From 7b33c63f78eb87ce80fe5ed29af62860384415d9 Mon Sep 17 00:00:00 2001
From: Aya Morisawa <AyaMorisawa4869@gmail.com>
Date: Thu, 2 Aug 2018 19:03:31 +0900
Subject: [PATCH] #332 (#2065)

---
 locales/en.yml                                | 52 ++++++++++++++++--
 locales/ja.yml                                | 53 ++++++++++++++++++-
 src/client/app/auth/script.ts                 |  2 +-
 src/client/app/auth/views/form.vue            | 26 ++++-----
 src/client/app/auth/views/index.vue           | 16 +++---
 .../common/scripts/compose-notification.ts    | 14 ++---
 .../app/common/scripts/date-stringify.ts      | 10 ++--
 .../app/common/scripts/fuck-ad-block.ts       |  4 +-
 src/client/app/common/views/pages/follow.vue  |  2 +-
 .../app/desktop/views/components/notes.vue    |  2 +-
 .../desktop/views/pages/home-customize.vue    |  2 +-
 src/client/app/desktop/views/pages/home.vue   |  2 +-
 src/client/app/desktop/views/pages/share.vue  |  4 +-
 .../app/desktop/views/pages/user/user.vue     |  2 +-
 .../app/desktop/views/pages/welcome.vue       |  4 +-
 src/client/app/dev/views/ui.vue               |  2 +-
 .../app/mobile/views/components/notes.vue     |  2 +-
 src/client/app/mobile/views/pages/drive.vue   |  8 +--
 .../app/mobile/views/pages/favorites.vue      |  2 +-
 .../app/mobile/views/pages/followers.vue      |  2 +-
 .../app/mobile/views/pages/following.vue      |  2 +-
 src/client/app/mobile/views/pages/home.vue    |  2 +-
 .../app/mobile/views/pages/messaging-room.vue |  2 +-
 .../app/mobile/views/pages/messaging.vue      |  2 +-
 src/client/app/mobile/views/pages/note.vue    |  2 +-
 .../app/mobile/views/pages/notifications.vue  |  2 +-
 .../views/pages/received-follow-requests.vue  |  2 +-
 src/client/app/mobile/views/pages/search.vue  |  2 +-
 .../app/mobile/views/pages/settings.vue       |  2 +-
 src/client/app/mobile/views/pages/share.vue   |  2 +-
 .../app/mobile/views/pages/user-lists.vue     |  2 +-
 src/client/app/mobile/views/pages/user.vue    |  2 +-
 src/client/app/mobile/views/pages/welcome.vue |  2 +-
 src/client/app/mobile/views/pages/widgets.vue |  4 +-
 34 files changed, 167 insertions(+), 74 deletions(-)

diff --git a/locales/en.yml b/locales/en.yml
index 650258e5cf..226d839938 100644
--- a/locales/en.yml
+++ b/locales/en.yml
@@ -6,6 +6,10 @@ common:
   misskey: "A ⭐ of the fediverse"
   about-title: "A ⭐ of the fediverse."
   about: "Thank you for finding Misskey. Misskey is a <b>decentralized microblogging platform</b> born on Earth. Since it exists within the Fediverse (a universe where various social media platforms are organized), it is mutually linked with other social media platforms. Why don't you take a short break from the hustle and bustle of the city, and dive into a new Internet?"
+  adblock:
+    detected: "Please disable ad blocker."
+    warning: "<strong>Misskey is not running ads</strong>, but some features may be unavailable or malfunctioning if ad blocking features are enabled."
+  application-authorization: "Application authorizations"
   customization-tips:
     title: "Customization tips"
     paragraph1: "Home customization allows you to add/delete, drag and drop and rearrange widgets."
@@ -13,6 +17,15 @@ common:
     paragraph3: "To delete a widget, <strong>drag and drop the widget onto the area labeled \"Trash\"</strong> in the header."
     paragraph4: "To finish the customization, click \"Finish\" in the upper right."
     gotit: "Got it!"
+  close: "Close"
+  notification:
+    file-uploaded: "File uploaded!"
+    message-from: "Message from {}:"
+    reversi-invited: "Invited to a game:"
+    reversi-invited-by: "By {}."
+    notified-by: "Notified by {}:"
+    reply-from: "Reply from {}:"
+    quoted-by: "Quoted by {}:"
   name: "Misskey"
   time:
     unknown: "unknown"
@@ -26,6 +39,12 @@ common:
     months_ago: "{}month(s) ago"
     years_ago: "{}year(s) ago"
   trash: "Trash"
+  date:
+    full-year: "Year"
+    month: "Month"
+    day: "Day"
+    hours: "Hours"
+    minutes: "Minutes"
   weekday-short:
     sunday: "S"
     monday: "M"
@@ -121,6 +140,30 @@ common:
     rename: "Rename"
     stack-left: "Stack to the left"
     pop-right: "Dock on the right"
+auth/views/form.vue: 
+  share-access: "Would you <b>allow</b> <i>{{app.name}}</i> to access your account?"
+  permission-ask: "This application requires the following permissions:"
+  account-read: "View account information."
+  account-write: "Modify account information."
+  note-write: "Post."
+  like-write: "React."
+  following-write: "Follow or unfollow."
+  drive-read: "Read your drive."
+  drive-write: "Upload/delete files in your drive."
+  notification-read: "Read your notifications."
+  notification-write: "Manage your notifications."
+  cancel: "Cancel"
+  accept: "Accept"
+auth/views/index.vue:
+  loading: "Loading..."
+  denied: "Application authorization is denied."
+  denied-paragraph: "This application will not access your account."
+  already-authorized: "This application is already authorized."
+  allowed: "Application authorization allowed."
+  callback-url: "Going back to the application."
+  please-go-back: "Please go back to the application."
+  error: "Session does not exist."
+  sign-in: "Please sign in."
 common/views/components/games/reversi/reversi.vue:
   title: "Misskey Reversi"
   sub-title: "Play reversi with your friends!"
@@ -751,10 +794,9 @@ desktop/views/pages/search.vue:
   not-available: "The search function can not be used."
   not-found: "No posts were found for '{}'"
 desktop/views/pages/share.vue:
-  share-with: "Share with Misskey"
-  close: "Close"
+  share-with: "Share with {}"
 desktop/views/pages/tag.vue:
-  no-posts-found: "ハッシュタグ「{}」が付けられた投稿は見つかりませんでした。"
+  no-posts-found: "No posts \"{}\" found."
 desktop/views/pages/user-list.users.vue:
   users: "User"
   add-user: "Add a user"
@@ -954,7 +996,7 @@ mobile/views/pages/home.vue:
   hybrid: "Social"
   global: "Global"
 mobile/views/pages/tag.vue:
-  no-posts-found: "ハッシュタグ「{}」が付けられた投稿は見つかりませんでした。"
+  no-posts-found: "No posts \"{}\" found."
 mobile/views/pages/welcome.vue:
   signup: "Sign up"
 mobile/views/pages/widgets.vue:
@@ -995,6 +1037,8 @@ mobile/views/pages/settings/settings.profile.vue:
 mobile/views/pages/search.vue:
   search: "Search"
   empty: "No posts were found for '{}'"
+mobile/views/pages/share.vue:
+  share-with: "Share with {}."
 mobile/views/pages/selectdrive.vue:
   select-file: "Choose files"
 mobile/views/pages/settings.vue:
diff --git a/locales/ja.yml b/locales/ja.yml
index 7e245d46a9..b3b50a5c8f 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -6,6 +6,11 @@ common:
   misskey: "A ⭐ of fediverse"
   about-title: "A ⭐ of fediverse."
   about: "Misskeyを見つけていただき、ありがとうございます。Misskeyは、地球で生まれた<b>分散マイクロブログSNS</b>です。Fediverse(様々なSNSで構成される宇宙)の中に存在するため、他のSNSと相互に繋がっています。暫し都会の喧騒から離れて、新しいインターネットにダイブしてみませんか。"
+  adblock:
+    detected: "広告ブロッカーを無効にしてください"
+    warning: "<strong>Misskeyは広告を掲載していません</strong>が、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。"
+  application-authorization: "アプリの連携"
+  close: "閉じる"
   customization-tips:
     title: "カスタマイズのヒント"
     paragraph1: "ホームのカスタマイズでは、ウィジェットを追加/削除したり、ドラッグ&ドロップして並べ替えたりすることができます。"
@@ -13,6 +18,14 @@ common:
     paragraph3: "ウィジェットを削除するには、ヘッダーの<strong>「ゴミ箱」</strong>と書かれたエリアにウィジェットをドラッグ&ドロップします。"
     paragraph4: "カスタマイズを終了するには、右上の「完了」をクリックします。"
     gotit: "Got it!"
+  notification:
+    file-uploaded: "ファイルがアップロードされました"
+    message-from: "{}さんからメッセージ:"
+    reversi-invited: "対局への招待があります"
+    reversi-invited-by: "{}さんから"
+    notified-by: "{}さんから"
+    reply-from: "{}さんから返信:"
+    quoted-by: "{}さんが引用:"
   name: "Misskey"
   time:
     unknown: "なぞのじかん"
@@ -28,6 +41,13 @@ common:
 
   trash: "ゴミ箱"
 
+  date:
+    full-year: "年"
+    month: "月"
+    day: "日"
+    hours: "時"
+    minutes: "分"
+  
   weekday-short:
     sunday: "日"
     monday: "月"
@@ -131,6 +151,32 @@ common:
     stack-left: "左に重ねる"
     pop-right: "右に出す"
 
+auth/views/form.vue: 
+  share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
+  permission-ask: "このアプリは次の権限を要求しています:"
+  account-read: "アカウントの情報を見る。"
+  account-write: "アカウントの情報を操作する。"
+  note-write: "投稿する。"
+  like-write: "いいねしたりいいね解除する。"
+  following-write: "フォローしたりフォロー解除する。"
+  drive-read: "ドライブを見る。"
+  drive-write: "ドライブを操作する。"
+  notification-read: "通知を見る。"
+  notification-write: "通知を操作する。"
+  cancel: "キャンセル"
+  accept: "アクセスを許可"
+  
+auth/views/index.vue:
+  loading: "読み込み中"
+  denied: "アプリケーションの連携をキャンセルしました。"
+  denied-paragraph: "このアプリがあなたのアカウントにアクセスすることはありません。"
+  already-authorized: "このアプリは既に連携済みです"
+  allowed: "アプリケーションの連携を許可しました"
+  callback-url: "アプリケーションに戻っています"
+  please-go-back: "アプリケーションに戻って、やっていってください。"
+  error: "セッションが存在しません。"
+  sign-in: "サインインしてください"
+  
 common/views/components/games/reversi/reversi.vue:
   title: "Misskey Reversi"
   sub-title: "他のMisskeyユーザーとリバーシで対戦しよう"
@@ -870,8 +916,7 @@ desktop/views/pages/search.vue:
   not-found: "「{}」に関する投稿は見つかりませんでした。"
 
 desktop/views/pages/share.vue:
-  share-with: "Misskeyで共有"
-  close: "閉じる"
+  share-with: "{}で共有"
 
 desktop/views/pages/tag.vue:
   no-posts-found: "ハッシュタグ「{}」が付けられた投稿は見つかりませんでした。"
@@ -1127,10 +1172,14 @@ mobile/views/pages/welcome.vue:
 
 mobile/views/pages/widgets.vue:
   dashboard: "ダッシュボード"
+  widgets-hints: "ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。"
 
 mobile/views/pages/widgets/activity.vue:
   activity: "アクティビティ"
 
+mobile/views/pages/share.vue:
+  share-with: "{}で共有"
+  
 mobile/views/pages/messaging.vue:
   messaging: "メッセージ"
 
diff --git a/src/client/app/auth/script.ts b/src/client/app/auth/script.ts
index fd985c46ad..bdfdf70be3 100644
--- a/src/client/app/auth/script.ts
+++ b/src/client/app/auth/script.ts
@@ -15,7 +15,7 @@ import Index from './views/index.vue';
  * init
  */
 init(launch => {
-	document.title = 'Misskey | アプリの連携';
+	document.title = '%i18n:common.name% | %i18n:common.application-authorization%';
 
 	// Init router
 	const router = new VueRouter({
diff --git a/src/client/app/auth/views/form.vue b/src/client/app/auth/views/form.vue
index 80086e3861..2d1e6d3e82 100644
--- a/src/client/app/auth/views/form.vue
+++ b/src/client/app/auth/views/form.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="form">
 	<header>
-		<h1><i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?</h1>
+		<h1>%i18n:@share-access%</h1>
 		<img :src="app.iconUrl"/>
 	</header>
 	<div class="app">
@@ -11,25 +11,25 @@
 			<p class="description">{{ app.description }}</p>
 		</section>
 		<section>
-			<h2>このアプリは次の権限を要求しています:</h2>
+			<h2>%i18n:@permission-ask%</h2>
 			<ul>
 				<template v-for="p in app.permission">
-					<li v-if="p == 'account-read'">アカウントの情報を見る。</li>
-					<li v-if="p == 'account-write'">アカウントの情報を操作する。</li>
-					<li v-if="p == 'note-write'">投稿する。</li>
-					<li v-if="p == 'like-write'">いいねしたりいいね解除する。</li>
-					<li v-if="p == 'following-write'">フォローしたりフォロー解除する。</li>
-					<li v-if="p == 'drive-read'">ドライブを見る。</li>
-					<li v-if="p == 'drive-write'">ドライブを操作する。</li>
-					<li v-if="p == 'notification-read'">通知を見る。</li>
-					<li v-if="p == 'notification-write'">通知を操作する。</li>
+					<li v-if="p == 'account-read'">%i18n:@account-read%</li>
+					<li v-if="p == 'account-write'">%i18n:@account-write%</li>
+					<li v-if="p == 'note-write'">%i18n:@note-write%</li>
+					<li v-if="p == 'like-write'">%i18n:@like-write%</li>
+					<li v-if="p == 'following-write'">%i18n:@following-write%</li>
+					<li v-if="p == 'drive-read'">%i18n:@drive-read%</li>
+					<li v-if="p == 'drive-write'">%i18n:@drive-write%</li>
+					<li v-if="p == 'notification-read'">%i18n:@notification-read%</li>
+					<li v-if="p == 'notification-write'">%i18n:@notification-write%</li>
 				</template>
 			</ul>
 		</section>
 	</div>
 	<div class="action">
-		<button @click="cancel">キャンセル</button>
-		<button @click="accept">アクセスを許可</button>
+		<button @click="cancel">%i18n:@cancel%</button>
+		<button @click="accept">%i18n:@accept%</button>
 	</div>
 </div>
 </template>
diff --git a/src/client/app/auth/views/index.vue b/src/client/app/auth/views/index.vue
index 6d0ba3cda3..609e758994 100644
--- a/src/client/app/auth/views/index.vue
+++ b/src/client/app/auth/views/index.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="index">
 	<main v-if="$store.getters.isSignedIn">
-		<p class="fetching" v-if="fetching">読み込み中<mk-ellipsis/></p>
+		<p class="fetching" v-if="fetching">%i18n:@loading%<mk-ellipsis/></p>
 		<x-form
 			class="form"
 			ref="form"
@@ -11,20 +11,20 @@
 			@accepted="accepted"
 		/>
 		<div class="denied" v-if="state == 'denied'">
-			<h1>アプリケーションの連携をキャンセルしました。</h1>
-			<p>このアプリがあなたのアカウントにアクセスすることはありません。</p>
+			<h1>%i18n:@denied%</h1>
+			<p>%i18n:@denied-paragraph%</p>
 		</div>
 		<div class="accepted" v-if="state == 'accepted'">
-			<h1>{{ session.app.isAuthorized ? 'このアプリは既に連携済みです' : 'アプリケーションの連携を許可しました' }}</h1>
-			<p v-if="session.app.callbackUrl">アプリケーションに戻っています<mk-ellipsis/></p>
-			<p v-if="!session.app.callbackUrl">アプリケーションに戻って、やっていってください。</p>
+			<h1>{{ session.app.isAuthorized ? '%i18n:@already-authorized%' : '%i18n:@allowed%' }}</h1>
+			<p v-if="session.app.callbackUrl">%i18n:@callback-url%<mk-ellipsis/></p>
+			<p v-if="!session.app.callbackUrl">%i18n:@please-go-back%</p>
 		</div>
 		<div class="error" v-if="state == 'fetch-session-error'">
-			<p>セッションが存在しません。</p>
+			<p>%i18n:@error%</p>
 		</div>
 	</main>
 	<main class="signin" v-if="!$store.getters.isSignedIn">
-		<h1>サインインしてください</h1>
+		<h1>%i18n:@sign-in%</h1>
 		<mk-signin/>
 	</main>
 	<footer><img src="/assets/auth/icon.svg" alt="Misskey"/></footer>
diff --git a/src/client/app/common/scripts/compose-notification.ts b/src/client/app/common/scripts/compose-notification.ts
index c93609bc59..4fb0610fd7 100644
--- a/src/client/app/common/scripts/compose-notification.ts
+++ b/src/client/app/common/scripts/compose-notification.ts
@@ -15,22 +15,22 @@ export default function(type, data): Notification {
 	switch (type) {
 		case 'drive_file_created':
 			return {
-				title: 'ファイルがアップロードされました',
+				title: '%i18n:common.notification.file-uploaded%',
 				body: data.name,
 				icon: data.url
 			};
 
 		case 'unread_messaging_message':
 			return {
-				title: `${getUserName(data.user)}さんからメッセージ:`,
+				title: '%i18n:common.notification.message-from%'.split("{}")[0] + `${getUserName(data.user)}` + '%i18n:common.notification.message-from%'.split("{}")[1] ,
 				body: data.text, // TODO: getMessagingMessageSummary(data),
 				icon: data.user.avatarUrl
 			};
 
 		case 'reversi_invited':
 			return {
-				title: '対局への招待があります',
-				body: `${getUserName(data.parent)}さんから`,
+				title: '%i18n:common.notification.reversi-invited%',
+				body: '%i18n:common.notification.reversi-invited-by%'.split("{}")[0] + `${getUserName(data.parent)}` + '%i18n:common.notification.reversi-invited-by%'.split("{}")[1],
 				icon: data.parent.avatarUrl
 			};
 
@@ -38,21 +38,21 @@ export default function(type, data): Notification {
 			switch (data.type) {
 				case 'mention':
 					return {
-						title: `${getUserName(data.user)}さんから:`,
+						title: '%i18n:common.notification.notified-by%'.split("{}")[0] + `${getUserName(data.user)}さんから:` + '%i18n:common.notification.notified-by%'.split("{}")[1],
 						body: getNoteSummary(data),
 						icon: data.user.avatarUrl
 					};
 
 				case 'reply':
 					return {
-						title: `${getUserName(data.user)}さんから返信:`,
+						title: '%i18n:common.notification.reply-from%'.split("{}")[0] + `${getUserName(data.user)}` + '%i18n:common.notification.reply-from%'.split("{}")[1],
 						body: getNoteSummary(data),
 						icon: data.user.avatarUrl
 					};
 
 				case 'quote':
 					return {
-						title: `${getUserName(data.user)}さんが引用:`,
+						title: '%i18n:common.notification.quoted-by%'.split("{}")[0] + `${getUserName(data.user)}` + '%i18n:common.notification.quoted-by%'.split("{}")[1],
 						body: getNoteSummary(data),
 						icon: data.user.avatarUrl
 					};
diff --git a/src/client/app/common/scripts/date-stringify.ts b/src/client/app/common/scripts/date-stringify.ts
index e51de8833d..2b8e525567 100644
--- a/src/client/app/common/scripts/date-stringify.ts
+++ b/src/client/app/common/scripts/date-stringify.ts
@@ -1,12 +1,12 @@
 export default date => {
 	if (typeof date == 'string') date = new Date(date);
 	return (
-		date.getFullYear()    + '年' +
-		(date.getMonth() + 1) + '月' +
-		date.getDate()        + '日' +
+		date.getFullYear()    + '%i18n:common.date.full-year%' +
+		(date.getMonth() + 1) + '%i18n:common.date.month%' +
+		date.getDate()        + '%i18n:common.date.day%' +
 		' ' +
-		date.getHours()       + '時' +
-		date.getMinutes()     + '分' +
+		date.getHours()       + '%i18n:common.date.hours%' +
+		date.getMinutes()     + '%i18n:common.date.minutes%' +
 		' ' +
 		`(${['日', '月', '火', '水', '木', '金', '土'][date.getDay()]})`
 	);
diff --git a/src/client/app/common/scripts/fuck-ad-block.ts b/src/client/app/common/scripts/fuck-ad-block.ts
index 9bcf7deeff..ed0904aeb3 100644
--- a/src/client/app/common/scripts/fuck-ad-block.ts
+++ b/src/client/app/common/scripts/fuck-ad-block.ts
@@ -5,8 +5,8 @@ declare const fuckAdBlock: any;
 export default (os) => {
 	function adBlockDetected() {
 		os.apis.dialog({
-			title: '%fa:exclamation-triangle%広告ブロッカーを無効にしてください',
-			text: '<strong>Misskeyは広告を掲載していません</strong>が、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。',
+			title: '%fa:exclamation-triangle%%i18n:common.adblock.detected%',
+			text: '%i18n:common.adblock.warning%',
 			actins: [{
 				text: 'OK'
 			}]
diff --git a/src/client/app/common/views/pages/follow.vue b/src/client/app/common/views/pages/follow.vue
index 4b8c2d3b7c..e1b5b1f120 100644
--- a/src/client/app/common/views/pages/follow.vue
+++ b/src/client/app/common/views/pages/follow.vue
@@ -71,7 +71,7 @@ export default Vue.extend({
 				this.user = user;
 				this.fetching = false;
 				Progress.done();
-				document.title = getUserName(this.user) + ' | Misskey';
+				document.title = getUserName(this.user) + ' | %i18n:common.name%';
 			});
 		},
 
diff --git a/src/client/app/desktop/views/components/notes.vue b/src/client/app/desktop/views/components/notes.vue
index c959508020..0ec2f16dbc 100644
--- a/src/client/app/desktop/views/components/notes.vue
+++ b/src/client/app/desktop/views/components/notes.vue
@@ -187,7 +187,7 @@ export default Vue.extend({
 
 		clearNotification() {
 			this.unreadCount = 0;
-			document.title = 'Misskey';
+			document.title = '%i18n:common.name%';
 		},
 
 		onVisibilitychange() {
diff --git a/src/client/app/desktop/views/pages/home-customize.vue b/src/client/app/desktop/views/pages/home-customize.vue
index da5f15bb69..ffdcf39fe2 100644
--- a/src/client/app/desktop/views/pages/home-customize.vue
+++ b/src/client/app/desktop/views/pages/home-customize.vue
@@ -6,7 +6,7 @@
 import Vue from 'vue';
 export default Vue.extend({
 	mounted() {
-		document.title = 'Misskey - %i18n:@title%';
+		document.title = '%i18n:common.name% - %i18n:@title%';
 	}
 });
 </script>
diff --git a/src/client/app/desktop/views/pages/home.vue b/src/client/app/desktop/views/pages/home.vue
index 60b257edb7..0c42e42bd2 100644
--- a/src/client/app/desktop/views/pages/home.vue
+++ b/src/client/app/desktop/views/pages/home.vue
@@ -16,7 +16,7 @@ export default Vue.extend({
 		}
 	},
 	mounted() {
-		document.title = 'Misskey';
+		document.title = '%i18n:common.name%';
 
 		Progress.start();
 	},
diff --git a/src/client/app/desktop/views/pages/share.vue b/src/client/app/desktop/views/pages/share.vue
index b1317f93e5..f5f5c4e184 100644
--- a/src/client/app/desktop/views/pages/share.vue
+++ b/src/client/app/desktop/views/pages/share.vue
@@ -1,12 +1,12 @@
 <template>
 <div class="pptjhabgjtt7kwskbfv4y3uml6fpuhmr">
-	<h1>%i18n:@share-with%</h1>
+	<h1>{{'%i18n:@share-with%'.split("{}")[0] + '%i18n:common.name%' + '%i18n:@share-with%'.split("{}")[1]}}</h1>
 	<div>
 		<mk-signin v-if="!$store.getters.isSignedIn"/>
 		<mk-post-form v-else-if="!posted" :initial-text="text" :instant="true" @posted="posted = true"/>
 		<p v-if="posted" class="posted">%fa:check%</p>
 	</div>
-	<button v-if="posted" class="ui button" @click="close">%i18n:@close%</button>
+	<button v-if="posted" class="ui button" @click="close">%i18n:common.close%</button>
 </div>
 </template>
 
diff --git a/src/client/app/desktop/views/pages/user/user.vue b/src/client/app/desktop/views/pages/user/user.vue
index 64a4eaa872..1a83f81342 100644
--- a/src/client/app/desktop/views/pages/user/user.vue
+++ b/src/client/app/desktop/views/pages/user/user.vue
@@ -68,7 +68,7 @@ export default Vue.extend({
 				this.user = user;
 				this.fetching = false;
 				Progress.done();
-				document.title = getUserName(this.user) + ' | Misskey';
+				document.title = getUserName(this.user) + ' | %i18n:common.name%';
 			});
 		},
 
diff --git a/src/client/app/desktop/views/pages/welcome.vue b/src/client/app/desktop/views/pages/welcome.vue
index 7449a3e5a4..9543a55b9a 100644
--- a/src/client/app/desktop/views/pages/welcome.vue
+++ b/src/client/app/desktop/views/pages/welcome.vue
@@ -17,7 +17,7 @@
 			<main>
 				<div class="about">
 					<h1 v-if="name">{{ name }}</h1>
-					<h1 v-else><img :src="$store.state.device.darkmode ? 'assets/title.dark.svg' : 'assets/title.light.svg'" alt="Misskey"></h1>
+					<h1 v-else><img :src="$store.state.device.darkmode ? 'assets/title.dark.svg' : 'assets/title.light.svg'" alt="%i18n:common.name%"></h1>
 					<p class="powerd-by" v-if="name">%i18n:@powered-by-misskey%</p>
 					<p class="desc" v-html="description || '%i18n:common.about%'"></p>
 					<a ref="signup" @click="signup">📦 %i18n:@signup%</a>
@@ -32,7 +32,7 @@
 			<mk-nav class="nav"/>
 		</div>
 		<mk-forkit class="forkit"/>
-		<img src="assets/title.dark.svg" alt="Misskey">
+		<img src="assets/title.dark.svg" alt="%i18n:common.name%">
 	</div>
 	<div class="tl">
 		<mk-welcome-timeline :max="20"/>
diff --git a/src/client/app/dev/views/ui.vue b/src/client/app/dev/views/ui.vue
index 4a0fcee635..0a1cdf829b 100644
--- a/src/client/app/dev/views/ui.vue
+++ b/src/client/app/dev/views/ui.vue
@@ -1,7 +1,7 @@
 <template>
 <div>
 	<b-navbar toggleable="md" type="dark" variant="info">
-		<b-navbar-brand>Misskey Developers</b-navbar-brand>
+		<b-navbar-brand>%i18n:common.name% Developers</b-navbar-brand>
 		<b-navbar-nav>
 			<b-nav-item to="/">Home</b-nav-item>
 			<b-nav-item to="/apps">Apps</b-nav-item>
diff --git a/src/client/app/mobile/views/components/notes.vue b/src/client/app/mobile/views/components/notes.vue
index 01f3d76c74..cba8ef1804 100644
--- a/src/client/app/mobile/views/components/notes.vue
+++ b/src/client/app/mobile/views/components/notes.vue
@@ -183,7 +183,7 @@ export default Vue.extend({
 
 		clearNotification() {
 			this.unreadCount = 0;
-			document.title = 'Misskey';
+			document.title = '%i18n:common.name%';
 		},
 
 		onVisibilitychange() {
diff --git a/src/client/app/mobile/views/pages/drive.vue b/src/client/app/mobile/views/pages/drive.vue
index 2cf3f510a2..9c635be05b 100644
--- a/src/client/app/mobile/views/pages/drive.vue
+++ b/src/client/app/mobile/views/pages/drive.vue
@@ -43,7 +43,7 @@ export default Vue.extend({
 		window.addEventListener('popstate', this.onPopState);
 	},
 	mounted() {
-		document.title = 'Misskey Drive';
+		document.title = '%i18n:common.name% Drive';
 		document.documentElement.style.background = '#fff';
 	},
 	beforeDestroy() {
@@ -63,7 +63,7 @@ export default Vue.extend({
 			(this.$refs as any).browser.openContextMenu();
 		},
 		onMoveRoot(silent) {
-			const title = 'Misskey Drive';
+			const title = '%i18n:common.name% Drive';
 
 			if (!silent) {
 				// Rewrite URL
@@ -76,7 +76,7 @@ export default Vue.extend({
 			this.folder = null;
 		},
 		onOpenFolder(folder, silent) {
-			const title = folder.name + ' | Misskey Drive';
+			const title = folder.name + ' | %i18n:common.name% Drive';
 
 			if (!silent) {
 				// Rewrite URL
@@ -89,7 +89,7 @@ export default Vue.extend({
 			this.folder = folder;
 		},
 		onOpenFile(file, silent) {
-			const title = file.name + ' | Misskey Drive';
+			const title = file.name + ' | %i18n:common.name% Drive';
 
 			if (!silent) {
 				// Rewrite URL
diff --git a/src/client/app/mobile/views/pages/favorites.vue b/src/client/app/mobile/views/pages/favorites.vue
index 1cccf169b0..88a84bd8a2 100644
--- a/src/client/app/mobile/views/pages/favorites.vue
+++ b/src/client/app/mobile/views/pages/favorites.vue
@@ -28,7 +28,7 @@ export default Vue.extend({
 		this.fetch();
 	},
 	mounted() {
-		document.title = 'Misskey | %i18n:@notifications%';
+		document.title = '%i18n:common.name% | %i18n:@notifications%';
 	},
 	methods: {
 		fetch() {
diff --git a/src/client/app/mobile/views/pages/followers.vue b/src/client/app/mobile/views/pages/followers.vue
index 7dc72a7c30..4956eb1b94 100644
--- a/src/client/app/mobile/views/pages/followers.vue
+++ b/src/client/app/mobile/views/pages/followers.vue
@@ -49,7 +49,7 @@ export default Vue.extend({
 				this.user = user;
 				this.fetching = false;
 
-				document.title = '%i18n:@followers-of%'.replace('{}', this.name) + ' | Misskey';
+				document.title = '%i18n:@followers-of%'.replace('{}', this.name) + ' | %i18n:common.name%';
 			});
 		},
 		onLoaded() {
diff --git a/src/client/app/mobile/views/pages/following.vue b/src/client/app/mobile/views/pages/following.vue
index 6895a76d53..fa6807a245 100644
--- a/src/client/app/mobile/views/pages/following.vue
+++ b/src/client/app/mobile/views/pages/following.vue
@@ -48,7 +48,7 @@ export default Vue.extend({
 				this.user = user;
 				this.fetching = false;
 
-				document.title = '%i18n:@followers-of%'.replace('{}', this.name) + ' | Misskey';
+				document.title = '%i18n:@followers-of%'.replace('{}', this.name) + ' | %i18n:common.name%';
 			});
 		},
 		onLoaded() {
diff --git a/src/client/app/mobile/views/pages/home.vue b/src/client/app/mobile/views/pages/home.vue
index 2f57e422a3..7b14c7ee98 100644
--- a/src/client/app/mobile/views/pages/home.vue
+++ b/src/client/app/mobile/views/pages/home.vue
@@ -96,7 +96,7 @@ export default Vue.extend({
 	},
 
 	mounted() {
-		document.title = 'Misskey';
+		document.title = '%i18n:common.name%';
 
 		Progress.start();
 
diff --git a/src/client/app/mobile/views/pages/messaging-room.vue b/src/client/app/mobile/views/pages/messaging-room.vue
index 35ae506761..24ffc658a3 100644
--- a/src/client/app/mobile/views/pages/messaging-room.vue
+++ b/src/client/app/mobile/views/pages/messaging-room.vue
@@ -47,7 +47,7 @@ export default Vue.extend({
 				this.user = user;
 				this.fetching = false;
 
-				document.title = `%i18n:@messaging%: ${Vue.filter('userName')(this.user)} | Misskey`;
+				document.title = `%i18n:@messaging%: ${Vue.filter('userName')(this.user)} | %i18n:common.name%`;
 			});
 		}
 	}
diff --git a/src/client/app/mobile/views/pages/messaging.vue b/src/client/app/mobile/views/pages/messaging.vue
index 8dcbc5d6c5..b5a4f405fb 100644
--- a/src/client/app/mobile/views/pages/messaging.vue
+++ b/src/client/app/mobile/views/pages/messaging.vue
@@ -11,7 +11,7 @@ import getAcct from '../../../../../misc/acct/render';
 
 export default Vue.extend({
 	mounted() {
-		document.title = 'Misskey %i18n:@messaging%';
+		document.title = '%i18n:common.name% %i18n:@messaging%';
 	},
 	methods: {
 		navigate(user) {
diff --git a/src/client/app/mobile/views/pages/note.vue b/src/client/app/mobile/views/pages/note.vue
index 146d89d22b..64d46f051b 100644
--- a/src/client/app/mobile/views/pages/note.vue
+++ b/src/client/app/mobile/views/pages/note.vue
@@ -31,7 +31,7 @@ export default Vue.extend({
 		this.fetch();
 	},
 	mounted() {
-		document.title = 'Misskey';
+		document.title = '%i18n:common.name%';
 	},
 	methods: {
 		fetch() {
diff --git a/src/client/app/mobile/views/pages/notifications.vue b/src/client/app/mobile/views/pages/notifications.vue
index fcd930997b..3688721613 100644
--- a/src/client/app/mobile/views/pages/notifications.vue
+++ b/src/client/app/mobile/views/pages/notifications.vue
@@ -15,7 +15,7 @@ import Progress from '../../../common/scripts/loading';
 
 export default Vue.extend({
 	mounted() {
-		document.title = 'Misskey | %i18n:@notifications%';
+		document.title = '%i18n:common.name% | %i18n:@notifications%';
 
 		Progress.start();
 	},
diff --git a/src/client/app/mobile/views/pages/received-follow-requests.vue b/src/client/app/mobile/views/pages/received-follow-requests.vue
index bf26a84ff9..fff2fdea56 100644
--- a/src/client/app/mobile/views/pages/received-follow-requests.vue
+++ b/src/client/app/mobile/views/pages/received-follow-requests.vue
@@ -25,7 +25,7 @@ export default Vue.extend({
 		};
 	},
 	mounted() {
-		document.title = 'Misskey | %i18n:@title%';
+		document.title = '%i18n:common.name% | %i18n:@title%';
 
 		Progress.start();
 
diff --git a/src/client/app/mobile/views/pages/search.vue b/src/client/app/mobile/views/pages/search.vue
index 2559922efb..7801068c1a 100644
--- a/src/client/app/mobile/views/pages/search.vue
+++ b/src/client/app/mobile/views/pages/search.vue
@@ -34,7 +34,7 @@ export default Vue.extend({
 		}
 	},
 	mounted() {
-		document.title = `%i18n:@search%: ${this.q} | Misskey`;
+		document.title = `%i18n:@search%: ${this.q} | %i18n:common.name%`;
 
 		this.fetch();
 	},
diff --git a/src/client/app/mobile/views/pages/settings.vue b/src/client/app/mobile/views/pages/settings.vue
index f4645b1837..73bff55e44 100644
--- a/src/client/app/mobile/views/pages/settings.vue
+++ b/src/client/app/mobile/views/pages/settings.vue
@@ -142,7 +142,7 @@ export default Vue.extend({
 	},
 
 	mounted() {
-		document.title = 'Misskey | %i18n:@settings%';
+		document.title = '%i18n:common.name% | %i18n:@settings%';
 	},
 
 	methods: {
diff --git a/src/client/app/mobile/views/pages/share.vue b/src/client/app/mobile/views/pages/share.vue
index c69498007d..3e33e32732 100644
--- a/src/client/app/mobile/views/pages/share.vue
+++ b/src/client/app/mobile/views/pages/share.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="azibmfpleajagva420swmu4c3r7ni7iw">
-	<h1>Misskeyで共有</h1>
+	<h1>{{'%i18n:@share-with%'.split("{}")[0] + '%i18n:common.name%' + '%i18n:@share-with%'.split("{}")[1]}}</h1>
 	<div>
 		<mk-signin v-if="!$store.getters.isSignedIn"/>
 		<mk-post-form v-else-if="!posted" :initial-text="text" :instant="true" @posted="posted = true"/>
diff --git a/src/client/app/mobile/views/pages/user-lists.vue b/src/client/app/mobile/views/pages/user-lists.vue
index 288295677e..1cce3e9bdd 100644
--- a/src/client/app/mobile/views/pages/user-lists.vue
+++ b/src/client/app/mobile/views/pages/user-lists.vue
@@ -23,7 +23,7 @@ export default Vue.extend({
 		};
 	},
 	mounted() {
-		document.title = 'Misskey | %i18n:@title%';
+		document.title = '%i18n:common.name% | %i18n:@title%';
 
 		Progress.start();
 
diff --git a/src/client/app/mobile/views/pages/user.vue b/src/client/app/mobile/views/pages/user.vue
index 2bc89b81be..d016345717 100644
--- a/src/client/app/mobile/views/pages/user.vue
+++ b/src/client/app/mobile/views/pages/user.vue
@@ -106,7 +106,7 @@ export default Vue.extend({
 				this.fetching = false;
 
 				Progress.done();
-				document.title = Vue.filter('userName')(this.user) + ' | Misskey';
+				document.title = Vue.filter('userName')(this.user) + ' | %i18n:common.name%';
 			});
 		}
 	}
diff --git a/src/client/app/mobile/views/pages/welcome.vue b/src/client/app/mobile/views/pages/welcome.vue
index d7c874af9a..acc8e2c490 100644
--- a/src/client/app/mobile/views/pages/welcome.vue
+++ b/src/client/app/mobile/views/pages/welcome.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="welcome">
 	<div>
-		<img :src="$store.state.device.darkmode ? 'assets/title.dark.svg' : 'assets/title.light.svg'" alt="Misskey">
+		<img :src="$store.state.device.darkmode ? 'assets/title.dark.svg' : 'assets/title.light.svg'" alt="%i18n:common.name%">
 		<p class="host">{{ host }}</p>
 		<div class="about">
 			<h2>{{ name || 'unidentified' }}</h2>
diff --git a/src/client/app/mobile/views/pages/widgets.vue b/src/client/app/mobile/views/pages/widgets.vue
index 0724cd03fa..4400132bf2 100644
--- a/src/client/app/mobile/views/pages/widgets.vue
+++ b/src/client/app/mobile/views/pages/widgets.vue
@@ -102,12 +102,12 @@ export default Vue.extend({
 	},
 
 	mounted() {
-		document.title = 'Misskey';
+		document.title = '%i18n:common.name%';
 	},
 
 	methods: {
 		hint() {
-			alert('ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。');
+			alert('%i18n:@widgets-hints%');
 		},
 
 		widgetFunc(id) {