From 554570cb0964f9eca6eb3d645a0a2ca0550d4733 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 15 Apr 2018 01:04:40 +0900
Subject: [PATCH 01/12] wip

---
 src/build/i18n.ts                             | 15 ++++++-
 .../connect-failed.troubleshooter.vue         | 18 ++++-----
 .../views/components/connect-failed.vue       | 12 +++---
 .../app/common/views/components/forkit.vue    |  2 +-
 .../views/components/messaging-room.form.vue  |  4 +-
 .../components/messaging-room.message.vue     |  4 +-
 .../views/components/messaging-room.vue       |  8 ++--
 .../app/common/views/components/messaging.vue |  6 +--
 .../app/common/views/components/nav.vue       | 14 +++----
 .../app/common/views/components/note-menu.vue |  2 +-
 .../common/views/components/poll-editor.vue   | 10 ++---
 .../app/common/views/components/poll.vue      | 10 ++---
 .../views/components/reaction-picker.vue      |  2 +-
 .../app/common/views/components/signin.vue    |  8 ++--
 .../app/common/views/components/signup.vue    | 40 +++++++++----------
 .../views/components/special-message.vue      |  4 +-
 .../views/components/stream-indicator.vue     |  6 +--
 .../views/components/twitter-setting.vue      |  8 ++--
 .../app/common/views/components/uploader.vue  |  2 +-
 .../app/common/views/widgets/access-log.vue   |  2 +-
 .../app/common/views/widgets/broadcast.vue    |  8 ++--
 .../app/common/views/widgets/donation.vue     |  6 +--
 .../app/common/views/widgets/photo-stream.vue |  4 +-
 .../app/common/views/widgets/server.vue       |  4 +-
 .../app/desktop/views/components/activity.vue |  4 +-
 .../app/desktop/views/components/calendar.vue |  8 ++--
 .../desktop/views/components/drive-window.vue |  4 +-
 .../desktop/views/components/drive.file.vue   | 28 ++++++-------
 .../desktop/views/components/drive.folder.vue | 16 ++++----
 .../views/components/drive.nav-folder.vue     |  2 +-
 .../app/desktop/views/components/drive.vue    | 36 ++++++++---------
 .../desktop/views/components/notes.note.vue   | 12 +++---
 .../views/components/notifications.vue        |  2 +-
 .../views/components/post-form-window.vue     |  8 ++--
 .../desktop/views/components/post-form.vue    | 38 +++++++++---------
 .../views/components/renote-form-window.vue   |  2 +-
 .../desktop/views/components/renote-form.vue  | 10 ++---
 .../views/components/repost-form-window.vue   |  2 +-
 .../desktop/views/components/repost-form.vue  | 10 ++---
 .../desktop/views/components/settings.2fa.vue | 30 +++++++-------
 .../desktop/views/components/settings.api.vue | 10 ++---
 .../views/components/settings.mute.vue        |  2 +-
 .../views/components/settings.password.vue    | 12 +++---
 .../views/components/settings.profile.vue     | 14 +++----
 .../app/desktop/views/components/settings.vue | 22 +++++-----
 .../views/components/ui.header.account.vue    | 10 ++---
 .../views/components/ui.header.nav.vue        |  4 +-
 .../components/ui.header.notifications.vue    |  2 +-
 .../views/components/ui.header.post.vue       |  2 +-
 .../views/components/ui.header.search.vue     |  2 +-
 src/client/app/desktop/views/pages/note.vue   |  4 +-
 .../app/desktop/views/pages/selectdrive.vue   |  8 ++--
 .../pages/user/user.followers-you-know.vue    |  6 +--
 .../desktop/views/pages/user/user.friends.vue |  6 +--
 .../desktop/views/pages/user/user.home.vue    |  2 +-
 .../desktop/views/pages/user/user.photos.vue  |  6 +--
 .../desktop/views/pages/user/user.profile.vue |  6 +--
 .../app/desktop/views/widgets/channel.vue     |  6 +--
 .../app/desktop/views/widgets/messaging.vue   |  2 +-
 .../desktop/views/widgets/notifications.vue   |  4 +-
 .../app/desktop/views/widgets/polls.vue       |  6 +--
 .../app/desktop/views/widgets/post-form.vue   |  6 +--
 .../app/desktop/views/widgets/trends.vue      |  6 +--
 .../app/desktop/views/widgets/users.vue       |  6 +--
 .../views/components/drive-file-chooser.vue   |  2 +-
 .../views/components/drive-folder-chooser.vue |  2 +-
 .../views/components/drive.file-detail.vue    | 10 ++---
 .../app/mobile/views/components/drive.vue     | 18 ++++-----
 .../mobile/views/components/follow-button.vue |  2 +-
 .../mobile/views/components/note-detail.vue   |  4 +-
 .../app/mobile/views/components/note.vue      |  4 +-
 .../mobile/views/components/notifications.vue |  4 +-
 .../app/mobile/views/components/post-form.vue |  4 +-
 .../views/components/sub-note-content.vue     |  2 +-
 .../app/mobile/views/components/timeline.vue  |  4 +-
 .../app/mobile/views/components/ui.nav.vue    | 16 ++++----
 .../mobile/views/components/user-timeline.vue |  4 +-
 .../mobile/views/components/users-list.vue    |  6 +--
 src/client/app/mobile/views/pages/drive.vue   |  2 +-
 .../app/mobile/views/pages/followers.vue      |  6 +--
 .../app/mobile/views/pages/following.vue      |  6 +--
 .../app/mobile/views/pages/messaging-room.vue |  2 +-
 .../app/mobile/views/pages/messaging.vue      |  4 +-
 src/client/app/mobile/views/pages/note.vue    |  6 +--
 .../app/mobile/views/pages/notifications.vue  |  6 +--
 .../mobile/views/pages/profile-setting.vue    | 30 +++++++-------
 src/client/app/mobile/views/pages/search.vue  |  6 +--
 .../app/mobile/views/pages/selectdrive.vue    |  4 +-
 .../app/mobile/views/pages/settings.vue       | 16 ++++----
 src/client/app/mobile/views/pages/user.vue    | 14 +++----
 .../pages/user/home.followers-you-know.vue    |  4 +-
 .../mobile/views/pages/user/home.friends.vue  |  4 +-
 .../mobile/views/pages/user/home.notes.vue    |  4 +-
 .../mobile/views/pages/user/home.photos.vue   |  4 +-
 .../app/mobile/views/pages/user/home.vue      | 12 +++---
 webpack/loaders/replace.js                    |  5 ++-
 96 files changed, 398 insertions(+), 384 deletions(-)

diff --git a/src/build/i18n.ts b/src/build/i18n.ts
index b9b7403214..d9dacccd34 100644
--- a/src/build/i18n.ts
+++ b/src/build/i18n.ts
@@ -44,8 +44,19 @@ export default class Replacer {
 		}
 	}
 
-	public replacement(match, a, b, c) {
-		const key = a || b || c;
+	public replacement(ctx, match, a, b, c) {
+		const client = 'misskey/src/client/app/';
+		const name = ctx.src.substr(ctx.src.indexOf(client) + client.length);
+		if (name == '') return match;
+
+		let key = a || b || c;
+		if (key[0] == '@') {
+			const prefix = name.split('.')[0].replace(/\//g, '.') + '.';
+			//if (name.startsWith('app/desktop/views/')) prefix = 'desktop.views.';
+			//if (name.startsWith('app/mobile/views/')) prefix = 'mobile.views.';
+			key = prefix + key.substr(1);
+		}
+
 		if (match[0] == '"') {
 			return '"' + this.get(key).replace(/"/g, '\\"') + '"';
 		} else if (match[0] == "'") {
diff --git a/src/client/app/common/views/components/connect-failed.troubleshooter.vue b/src/client/app/common/views/components/connect-failed.troubleshooter.vue
index cadbd36ba4..b0a9c87e78 100644
--- a/src/client/app/common/views/components/connect-failed.troubleshooter.vue
+++ b/src/client/app/common/views/components/connect-failed.troubleshooter.vue
@@ -1,34 +1,34 @@
 <template>
 <div class="troubleshooter">
-	<h1>%fa:wrench%%i18n:common.tags.mk-error.troubleshooter.title%</h1>
+	<h1>%fa:wrench%%i18n:@title%</h1>
 	<div>
 		<p :data-wip="network == null">
 			<template v-if="network != null">
 				<template v-if="network">%fa:check%</template>
 				<template v-if="!network">%fa:times%</template>
 			</template>
-			{{ network == null ? '%i18n:common.tags.mk-error.troubleshooter.checking-network%' : '%i18n:common.tags.mk-error.troubleshooter.network%' }}<mk-ellipsis v-if="network == null"/>
+			{{ network == null ? '%i18n:@checking-network%' : '%i18n:@network%' }}<mk-ellipsis v-if="network == null"/>
 		</p>
 		<p v-if="network == true" :data-wip="internet == null">
 			<template v-if="internet != null">
 				<template v-if="internet">%fa:check%</template>
 				<template v-if="!internet">%fa:times%</template>
 			</template>
-			{{ internet == null ? '%i18n:common.tags.mk-error.troubleshooter.checking-internet%' : '%i18n:common.tags.mk-error.troubleshooter.internet%' }}<mk-ellipsis v-if="internet == null"/>
+			{{ internet == null ? '%i18n:@checking-internet%' : '%i18n:@internet%' }}<mk-ellipsis v-if="internet == null"/>
 		</p>
 		<p v-if="internet == true" :data-wip="server == null">
 			<template v-if="server != null">
 				<template v-if="server">%fa:check%</template>
 				<template v-if="!server">%fa:times%</template>
 			</template>
-			{{ server == null ? '%i18n:common.tags.mk-error.troubleshooter.checking-server%' : '%i18n:common.tags.mk-error.troubleshooter.server%' }}<mk-ellipsis v-if="server == null"/>
+			{{ server == null ? '%i18n:@checking-server%' : '%i18n:@server%' }}<mk-ellipsis v-if="server == null"/>
 		</p>
 	</div>
-	<p v-if="!end">%i18n:common.tags.mk-error.troubleshooter.finding%<mk-ellipsis/></p>
-	<p v-if="network === false"><b>%fa:exclamation-triangle%%i18n:common.tags.mk-error.troubleshooter.no-network%</b><br>%i18n:common.tags.mk-error.troubleshooter.no-network-desc%</p>
-	<p v-if="internet === false"><b>%fa:exclamation-triangle%%i18n:common.tags.mk-error.troubleshooter.no-internet%</b><br>%i18n:common.tags.mk-error.troubleshooter.no-internet-desc%</p>
-	<p v-if="server === false"><b>%fa:exclamation-triangle%%i18n:common.tags.mk-error.troubleshooter.no-server%</b><br>%i18n:common.tags.mk-error.troubleshooter.no-server-desc%</p>
-	<p v-if="server === true" class="success"><b>%fa:info-circle%%i18n:common.tags.mk-error.troubleshooter.success%</b><br>%i18n:common.tags.mk-error.troubleshooter.success-desc%</p>
+	<p v-if="!end">%i18n:@finding%<mk-ellipsis/></p>
+	<p v-if="network === false"><b>%fa:exclamation-triangle%%i18n:@no-network%</b><br>%i18n:@no-network-desc%</p>
+	<p v-if="internet === false"><b>%fa:exclamation-triangle%%i18n:@no-internet%</b><br>%i18n:@no-internet-desc%</p>
+	<p v-if="server === false"><b>%fa:exclamation-triangle%%i18n:@no-server%</b><br>%i18n:@no-server-desc%</p>
+	<p v-if="server === true" class="success"><b>%fa:info-circle%%i18n:@success%</b><br>%i18n:@success-desc%</p>
 </div>
 </template>
 
diff --git a/src/client/app/common/views/components/connect-failed.vue b/src/client/app/common/views/components/connect-failed.vue
index 185250dbd8..d90c8756b8 100644
--- a/src/client/app/common/views/components/connect-failed.vue
+++ b/src/client/app/common/views/components/connect-failed.vue
@@ -1,15 +1,15 @@
 <template>
 <div class="mk-connect-failed">
 	<img src="data:image/jpeg;base64,%base64:/assets/error.jpg%" alt=""/>
-	<h1>%i18n:common.tags.mk-error.title%</h1>
+	<h1>%i18n:@title%</h1>
 	<p class="text">
-		{{ '%i18n:common.tags.mk-error.description%'.substr(0, '%i18n:common.tags.mk-error.description%'.indexOf('{')) }}
-		<a @click="reload">{{ '%i18n:common.tags.mk-error.description%'.match(/\{(.+?)\}/)[1] }}</a>
-		{{ '%i18n:common.tags.mk-error.description%'.substr('%i18n:common.tags.mk-error.description%'.indexOf('}') + 1) }}
+		{{ '%i18n:@description%'.substr(0, '%i18n:@description%'.indexOf('{')) }}
+		<a @click="reload">{{ '%i18n:@description%'.match(/\{(.+?)\}/)[1] }}</a>
+		{{ '%i18n:@description%'.substr('%i18n:@description%'.indexOf('}') + 1) }}
 	</p>
-	<button v-if="!troubleshooting" @click="troubleshooting = true">%i18n:common.tags.mk-error.troubleshoot%</button>
+	<button v-if="!troubleshooting" @click="troubleshooting = true">%i18n:@troubleshoot%</button>
 	<x-troubleshooter v-if="troubleshooting"/>
-	<p class="thanks">%i18n:common.tags.mk-error.thanks%</p>
+	<p class="thanks">%i18n:@thanks%</p>
 </div>
 </template>
 
diff --git a/src/client/app/common/views/components/forkit.vue b/src/client/app/common/views/components/forkit.vue
index 6f334b965a..05971cbf15 100644
--- a/src/client/app/common/views/components/forkit.vue
+++ b/src/client/app/common/views/components/forkit.vue
@@ -1,5 +1,5 @@
 <template>
-<a class="a" href="https://github.com/syuilo/misskey" target="_blank" title="%i18n:common.tags.mk-forkit.open-github-link%" aria-label="%i18n:common.tags.mk-forkit.open-github-link%">
+<a class="a" href="https://github.com/syuilo/misskey" target="_blank" title="%i18n:@open-github-link%" aria-label="%i18n:@open-github-link%">
 	<svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="aria-hidden">
 		<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
 		<path class="octo-arm" d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor"></path>
diff --git a/src/client/app/common/views/components/messaging-room.form.vue b/src/client/app/common/views/components/messaging-room.form.vue
index 704f2016d8..1c7b68a266 100644
--- a/src/client/app/common/views/components/messaging-room.form.vue
+++ b/src/client/app/common/views/components/messaging-room.form.vue
@@ -16,10 +16,10 @@
 	<button class="send" @click="send" :disabled="!canSend || sending" title="%i18n:common.send%">
 		<template v-if="!sending">%fa:paper-plane%</template><template v-if="sending">%fa:spinner .spin%</template>
 	</button>
-	<button class="attach-from-local" @click="chooseFile" title="%i18n:common.tags.mk-messaging-form.attach-from-local%">
+	<button class="attach-from-local" @click="chooseFile" title="%i18n:@attach-from-local%">
 		%fa:upload%
 	</button>
-	<button class="attach-from-drive" @click="chooseFileFromDrive" title="%i18n:common.tags.mk-messaging-form.attach-from-drive%">
+	<button class="attach-from-drive" @click="chooseFileFromDrive" title="%i18n:@attach-from-drive%">
 		%fa:R folder-open%
 	</button>
 	<input ref="file" type="file" @change="onChangeFile"/>
diff --git a/src/client/app/common/views/components/messaging-room.message.vue b/src/client/app/common/views/components/messaging-room.message.vue
index 60e5258b63..afd700e777 100644
--- a/src/client/app/common/views/components/messaging-room.message.vue
+++ b/src/client/app/common/views/components/messaging-room.message.vue
@@ -5,7 +5,7 @@
 	</router-link>
 	<div class="content">
 		<div class="balloon" :data-no-text="message.text == null">
-			<p class="read" v-if="isMe && message.isRead">%i18n:common.tags.mk-messaging-message.is-read%</p>
+			<p class="read" v-if="isMe && message.isRead">%i18n:@is-read%</p>
 			<button class="delete-button" v-if="isMe" title="%i18n:common.delete%">
 				<img src="/assets/desktop/messaging/delete.png" alt="Delete"/>
 			</button>
@@ -19,7 +19,7 @@
 				</div>
 			</div>
 			<div class="content" v-if="message.isDeleted">
-				<p class="is-deleted">%i18n:common.tags.mk-messaging-message.deleted%</p>
+				<p class="is-deleted">%i18n:@deleted%</p>
 			</div>
 		</div>
 		<div></div>
diff --git a/src/client/app/common/views/components/messaging-room.vue b/src/client/app/common/views/components/messaging-room.vue
index e1b775c33a..ca5416a218 100644
--- a/src/client/app/common/views/components/messaging-room.vue
+++ b/src/client/app/common/views/components/messaging-room.vue
@@ -5,10 +5,10 @@
 >
 	<div class="stream">
 		<p class="init" v-if="init">%fa:spinner .spin%%i18n:common.loading%</p>
-		<p class="empty" v-if="!init && messages.length == 0">%fa:info-circle%%i18n:common.tags.mk-messaging-room.empty%</p>
-		<p class="no-history" v-if="!init && messages.length > 0 && !existMoreMessages">%fa:flag%%i18n:common.tags.mk-messaging-room.no-history%</p>
+		<p class="empty" v-if="!init && messages.length == 0">%fa:info-circle%%i18n:@empty%</p>
+		<p class="no-history" v-if="!init && messages.length > 0 && !existMoreMessages">%fa:flag%%i18n:@no-history%</p>
 		<button class="more" :class="{ fetching: fetchingMoreMessages }" v-if="existMoreMessages" @click="fetchMoreMessages" :disabled="fetchingMoreMessages">
-			<template v-if="fetchingMoreMessages">%fa:spinner .pulse .fw%</template>{{ fetchingMoreMessages ? '%i18n:common.loading%' : '%i18n:common.tags.mk-messaging-room.more%' }}
+			<template v-if="fetchingMoreMessages">%fa:spinner .pulse .fw%</template>{{ fetchingMoreMessages ? '%i18n:common.loading%' : '%i18n:@more%' }}
 		</button>
 		<template v-for="(message, i) in _messages">
 			<x-message :message="message" :key="message.id"/>
@@ -172,7 +172,7 @@ export default Vue.extend({
 				});
 			} else if (message.userId != (this as any).os.i.id) {
 				// Notify
-				this.notify('%i18n:common.tags.mk-messaging-room.new-message%');
+				this.notify('%i18n:@new-message%');
 			}
 		},
 
diff --git a/src/client/app/common/views/components/messaging.vue b/src/client/app/common/views/components/messaging.vue
index e6c32f80d8..f74d9643eb 100644
--- a/src/client/app/common/views/components/messaging.vue
+++ b/src/client/app/common/views/components/messaging.vue
@@ -3,7 +3,7 @@
 	<div class="search" v-if="!compact" :style="{ top: headerTop + 'px' }">
 		<div class="form">
 			<label for="search-input">%fa:search%</label>
-			<input v-model="q" type="search" @input="search" @keydown="onSearchKeydown" placeholder="%i18n:common.tags.mk-messaging.search-user%"/>
+			<input v-model="q" type="search" @input="search" @keydown="onSearchKeydown" placeholder="%i18n:@search-user%"/>
 		</div>
 		<div class="result">
 			<ol class="users" v-if="result.length > 0" ref="searchResult">
@@ -38,13 +38,13 @@
 						<mk-time :time="message.createdAt"/>
 					</header>
 					<div class="body">
-						<p class="text"><span class="me" v-if="isMe(message)">%i18n:common.tags.mk-messaging.you%:</span>{{ message.text }}</p>
+						<p class="text"><span class="me" v-if="isMe(message)">%i18n:@you%:</span>{{ message.text }}</p>
 					</div>
 				</div>
 			</a>
 		</template>
 	</div>
-	<p class="no-history" v-if="!fetching && messages.length == 0">%i18n:common.tags.mk-messaging.no-history%</p>
+	<p class="no-history" v-if="!fetching && messages.length == 0">%i18n:@no-history%</p>
 	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
 </div>
 </template>
diff --git a/src/client/app/common/views/components/nav.vue b/src/client/app/common/views/components/nav.vue
index 8ce75d3529..2295957928 100644
--- a/src/client/app/common/views/components/nav.vue
+++ b/src/client/app/common/views/components/nav.vue
@@ -1,18 +1,18 @@
 <template>
 <span class="mk-nav">
-	<a :href="aboutUrl">%i18n:common.tags.mk-nav-links.about%</a>
+	<a :href="aboutUrl">%i18n:@about%</a>
 	<i>・</i>
-	<a :href="statsUrl">%i18n:common.tags.mk-nav-links.stats%</a>
+	<a :href="statsUrl">%i18n:@stats%</a>
 	<i>・</i>
-	<a :href="statusUrl">%i18n:common.tags.mk-nav-links.status%</a>
+	<a :href="statusUrl">%i18n:@status%</a>
 	<i>・</i>
-	<a href="http://zawazawa.jp/misskey/">%i18n:common.tags.mk-nav-links.wiki%</a>
+	<a href="http://zawazawa.jp/misskey/">%i18n:@wiki%</a>
 	<i>・</i>
-	<a href="https://github.com/syuilo/misskey/blob/master/DONORS.md">%i18n:common.tags.mk-nav-links.donors%</a>
+	<a href="https://github.com/syuilo/misskey/blob/master/DONORS.md">%i18n:@donors%</a>
 	<i>・</i>
-	<a href="https://github.com/syuilo/misskey">%i18n:common.tags.mk-nav-links.repository%</a>
+	<a href="https://github.com/syuilo/misskey">%i18n:@repository%</a>
 	<i>・</i>
-	<a :href="devUrl">%i18n:common.tags.mk-nav-links.develop%</a>
+	<a :href="devUrl">%i18n:@develop%</a>
 	<i>・</i>
 	<a href="https://twitter.com/misskey_xyz" target="_blank">Follow us on %fa:B twitter%</a>
 </span>
diff --git a/src/client/app/common/views/components/note-menu.vue b/src/client/app/common/views/components/note-menu.vue
index d053748728..06fe0dfd0c 100644
--- a/src/client/app/common/views/components/note-menu.vue
+++ b/src/client/app/common/views/components/note-menu.vue
@@ -2,7 +2,7 @@
 <div class="mk-note-menu">
 	<div class="backdrop" ref="backdrop" @click="close"></div>
 	<div class="popover" :class="{ compact }" ref="popover">
-		<button v-if="note.userId == os.i.id" @click="pin">%i18n:common.tags.mk-note-menu.pin%</button>
+		<button v-if="note.userId == os.i.id" @click="pin">%i18n:@pin%</button>
 	</div>
 </div>
 </template>
diff --git a/src/client/app/common/views/components/poll-editor.vue b/src/client/app/common/views/components/poll-editor.vue
index 47d901d7b1..fa1897f435 100644
--- a/src/client/app/common/views/components/poll-editor.vue
+++ b/src/client/app/common/views/components/poll-editor.vue
@@ -1,18 +1,18 @@
 <template>
 <div class="mk-poll-editor">
 	<p class="caution" v-if="choices.length < 2">
-		%fa:exclamation-triangle%%i18n:common.tags.mk-poll-editor.no-only-one-choice%
+		%fa:exclamation-triangle%%i18n:@no-only-one-choice%
 	</p>
 	<ul ref="choices">
 		<li v-for="(choice, i) in choices">
-			<input :value="choice" @input="onInput(i, $event)" :placeholder="'%i18n:common.tags.mk-poll-editor.choice-n%'.replace('{}', i + 1)">
-			<button @click="remove(i)" title="%i18n:common.tags.mk-poll-editor.remove%">
+			<input :value="choice" @input="onInput(i, $event)" :placeholder="'%i18n:@choice-n%'.replace('{}', i + 1)">
+			<button @click="remove(i)" title="%i18n:@remove%">
 				%fa:times%
 			</button>
 		</li>
 	</ul>
-	<button class="add" v-if="choices.length < 10" @click="add">%i18n:common.tags.mk-poll-editor.add%</button>
-	<button class="destroy" @click="destroy" title="%i18n:common.tags.mk-poll-editor.destroy%">
+	<button class="add" v-if="choices.length < 10" @click="add">%i18n:@add%</button>
+	<button class="destroy" @click="destroy" title="%i18n:@destroy%">
 		%fa:times%
 	</button>
 </div>
diff --git a/src/client/app/common/views/components/poll.vue b/src/client/app/common/views/components/poll.vue
index eb29aa8837..fd0ebc4656 100644
--- a/src/client/app/common/views/components/poll.vue
+++ b/src/client/app/common/views/components/poll.vue
@@ -1,20 +1,20 @@
 <template>
 <div class="mk-poll" :data-is-voted="isVoted">
 	<ul>
-		<li v-for="choice in poll.choices" :key="choice.id" @click="vote(choice.id)" :class="{ voted: choice.voted }" :title="!isVoted ? '%i18n:common.tags.mk-poll.vote-to%'.replace('{}', choice.text) : ''">
+		<li v-for="choice in poll.choices" :key="choice.id" @click="vote(choice.id)" :class="{ voted: choice.voted }" :title="!isVoted ? '%i18n:@vote-to%'.replace('{}', choice.text) : ''">
 			<div class="backdrop" :style="{ 'width': (showResult ? (choice.votes / total * 100) : 0) + '%' }"></div>
 			<span>
 				<template v-if="choice.isVoted">%fa:check%</template>
 				<span>{{ choice.text }}</span>
-				<span class="votes" v-if="showResult">({{ '%i18n:common.tags.mk-poll.vote-count%'.replace('{}', choice.votes) }})</span>
+				<span class="votes" v-if="showResult">({{ '%i18n:@vote-count%'.replace('{}', choice.votes) }})</span>
 			</span>
 		</li>
 	</ul>
 	<p v-if="total > 0">
-		<span>{{ '%i18n:common.tags.mk-poll.total-users%'.replace('{}', total) }}</span>
+		<span>{{ '%i18n:@total-users%'.replace('{}', total) }}</span>
 		<span>・</span>
-		<a v-if="!isVoted" @click="toggleShowResult">{{ showResult ? '%i18n:common.tags.mk-poll.vote%' : '%i18n:common.tags.mk-poll.show-result%' }}</a>
-		<span v-if="isVoted">%i18n:common.tags.mk-poll.voted%</span>
+		<a v-if="!isVoted" @click="toggleShowResult">{{ showResult ? '%i18n:@vote%' : '%i18n:@show-result%' }}</a>
+		<span v-if="isVoted">%i18n:@voted%</span>
 	</p>
 </div>
 </template>
diff --git a/src/client/app/common/views/components/reaction-picker.vue b/src/client/app/common/views/components/reaction-picker.vue
index fa1998dca9..631ed13133 100644
--- a/src/client/app/common/views/components/reaction-picker.vue
+++ b/src/client/app/common/views/components/reaction-picker.vue
@@ -22,7 +22,7 @@
 import Vue from 'vue';
 import * as anime from 'animejs';
 
-const placeholder = '%i18n:common.tags.mk-reaction-picker.choose-reaction%';
+const placeholder = '%i18n:@choose-reaction%';
 
 export default Vue.extend({
 	props: ['note', 'source', 'compact', 'cb'],
diff --git a/src/client/app/common/views/components/signin.vue b/src/client/app/common/views/components/signin.vue
index da7472b8c7..4b114eb750 100644
--- a/src/client/app/common/views/components/signin.vue
+++ b/src/client/app/common/views/components/signin.vue
@@ -1,15 +1,15 @@
 <template>
 <form class="mk-signin" :class="{ signing }" @submit.prevent="onSubmit">
 	<label class="user-name">
-		<input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" placeholder="%i18n:common.tags.mk-signin.username%" autofocus required @change="onUsernameChange"/>%fa:at%
+		<input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" placeholder="%i18n:@username%" autofocus required @change="onUsernameChange"/>%fa:at%
 	</label>
 	<label class="password">
-		<input v-model="password" type="password" placeholder="%i18n:common.tags.mk-signin.password%" required/>%fa:lock%
+		<input v-model="password" type="password" placeholder="%i18n:@password%" required/>%fa:lock%
 	</label>
 	<label class="token" v-if="user && user.twoFactorEnabled">
-		<input v-model="token" type="number" placeholder="%i18n:common.tags.mk-signin.token%" required/>%fa:lock%
+		<input v-model="token" type="number" placeholder="%i18n:@token%" required/>%fa:lock%
 	</label>
-	<button type="submit" :disabled="signing">{{ signing ? '%i18n:common.tags.mk-signin.signing-in%' : '%i18n:common.tags.mk-signin.signin%' }}</button>
+	<button type="submit" :disabled="signing">{{ signing ? '%i18n:@signing-in%' : '%i18n:@signin%' }}</button>
 	もしくは <a :href="`${apiUrl}/signin/twitter`">Twitterでログイン</a>
 </form>
 </template>
diff --git a/src/client/app/common/views/components/signup.vue b/src/client/app/common/views/components/signup.vue
index 40262b54d3..b998e6f42a 100644
--- a/src/client/app/common/views/components/signup.vue
+++ b/src/client/app/common/views/components/signup.vue
@@ -1,42 +1,42 @@
 <template>
 <form class="mk-signup" @submit.prevent="onSubmit" autocomplete="off">
 	<label class="username">
-		<p class="caption">%fa:at%%i18n:common.tags.mk-signup.username%</p>
+		<p class="caption">%fa:at%%i18n:@username%</p>
 		<input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" placeholder="a~z、A~Z、0~9、-" autocomplete="off" required @input="onChangeUsername"/>
 		<p class="profile-page-url-preview" v-if="shouldShowProfileUrl">{{ `${url}/@${username}` }}</p>
-		<p class="info" v-if="usernameState == 'wait'" style="color:#999">%fa:spinner .pulse .fw%%i18n:common.tags.mk-signup.checking%</p>
-		<p class="info" v-if="usernameState == 'ok'" style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.available%</p>
-		<p class="info" v-if="usernameState == 'unavailable'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.unavailable%</p>
-		<p class="info" v-if="usernameState == 'error'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.error%</p>
-		<p class="info" v-if="usernameState == 'invalid-format'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.invalid-format%</p>
-		<p class="info" v-if="usernameState == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.too-short%</p>
-		<p class="info" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.too-long%</p>
+		<p class="info" v-if="usernameState == 'wait'" style="color:#999">%fa:spinner .pulse .fw%%i18n:@checking%</p>
+		<p class="info" v-if="usernameState == 'ok'" style="color:#3CB7B5">%fa:check .fw%%i18n:@available%</p>
+		<p class="info" v-if="usernameState == 'unavailable'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@unavailable%</p>
+		<p class="info" v-if="usernameState == 'error'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@error%</p>
+		<p class="info" v-if="usernameState == 'invalid-format'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@invalid-format%</p>
+		<p class="info" v-if="usernameState == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@too-short%</p>
+		<p class="info" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@too-long%</p>
 	</label>
 	<label class="password">
-		<p class="caption">%fa:lock%%i18n:common.tags.mk-signup.password%</p>
-		<input v-model="password" type="password" placeholder="%i18n:common.tags.mk-signup.password-placeholder%" autocomplete="off" required @input="onChangePassword"/>
+		<p class="caption">%fa:lock%%i18n:@password%</p>
+		<input v-model="password" type="password" placeholder="%i18n:@password-placeholder%" autocomplete="off" required @input="onChangePassword"/>
 		<div class="meter" v-show="passwordStrength != ''" :data-strength="passwordStrength">
 			<div class="value" ref="passwordMetar"></div>
 		</div>
-		<p class="info" v-if="passwordStrength == 'low'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.weak-password%</p>
-		<p class="info" v-if="passwordStrength == 'medium'" style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.normal-password%</p>
-		<p class="info" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.strong-password%</p>
+		<p class="info" v-if="passwordStrength == 'low'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@weak-password%</p>
+		<p class="info" v-if="passwordStrength == 'medium'" style="color:#3CB7B5">%fa:check .fw%%i18n:@normal-password%</p>
+		<p class="info" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw%%i18n:@strong-password%</p>
 	</label>
 	<label class="retype-password">
-		<p class="caption">%fa:lock%%i18n:common.tags.mk-signup.password%(%i18n:common.tags.mk-signup.retype%)</p>
-		<input v-model="retypedPassword" type="password" placeholder="%i18n:common.tags.mk-signup.retype-placeholder%" autocomplete="off" required @input="onChangePasswordRetype"/>
-		<p class="info" v-if="passwordRetypeState == 'match'" style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.password-matched%</p>
-		<p class="info" v-if="passwordRetypeState == 'not-match'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.password-not-matched%</p>
+		<p class="caption">%fa:lock%%i18n:@password%(%i18n:@retype%)</p>
+		<input v-model="retypedPassword" type="password" placeholder="%i18n:@retype-placeholder%" autocomplete="off" required @input="onChangePasswordRetype"/>
+		<p class="info" v-if="passwordRetypeState == 'match'" style="color:#3CB7B5">%fa:check .fw%%i18n:@password-matched%</p>
+		<p class="info" v-if="passwordRetypeState == 'not-match'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@password-not-matched%</p>
 	</label>
 	<label class="recaptcha">
-		<p class="caption"><template v-if="recaptchaed">%fa:toggle-on%</template><template v-if="!recaptchaed">%fa:toggle-off%</template>%i18n:common.tags.mk-signup.recaptcha%</p>
+		<p class="caption"><template v-if="recaptchaed">%fa:toggle-on%</template><template v-if="!recaptchaed">%fa:toggle-off%</template>%i18n:@recaptcha%</p>
 		<div class="g-recaptcha" data-callback="onRecaptchaed" data-expired-callback="onRecaptchaExpired" :data-sitekey="recaptchaSitekey"></div>
 	</label>
 	<label class="agree-tou">
 		<input name="agree-tou" type="checkbox" autocomplete="off" required/>
 		<p><a :href="touUrl" target="_blank">利用規約</a>に同意する</p>
 	</label>
-	<button type="submit">%i18n:common.tags.mk-signup.create%</button>
+	<button type="submit">%i18n:@create%</button>
 </form>
 </template>
 
@@ -127,7 +127,7 @@ export default Vue.extend({
 					location.href = '/';
 				});
 			}).catch(() => {
-				alert('%i18n:common.tags.mk-signup.some-error%');
+				alert('%i18n:@some-error%');
 
 				(window as any).grecaptcha.reset();
 				this.recaptchaed = false;
diff --git a/src/client/app/common/views/components/special-message.vue b/src/client/app/common/views/components/special-message.vue
index 2fd4d6515e..deac757c5b 100644
--- a/src/client/app/common/views/components/special-message.vue
+++ b/src/client/app/common/views/components/special-message.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="mk-special-message">
-	<p v-if="m == 1 && d == 1">%i18n:common.tags.mk-special-message.new-year%</p>
-	<p v-if="m == 12 && d == 25">%i18n:common.tags.mk-special-message.christmas%</p>
+	<p v-if="m == 1 && d == 1">%i18n:@new-year%</p>
+	<p v-if="m == 12 && d == 25">%i18n:@christmas%</p>
 </div>
 </template>
 
diff --git a/src/client/app/common/views/components/stream-indicator.vue b/src/client/app/common/views/components/stream-indicator.vue
index 1f18fa76ed..93758102de 100644
--- a/src/client/app/common/views/components/stream-indicator.vue
+++ b/src/client/app/common/views/components/stream-indicator.vue
@@ -2,15 +2,15 @@
 <div class="mk-stream-indicator">
 	<p v-if=" stream.state == 'initializing' ">
 		%fa:spinner .pulse%
-		<span>%i18n:common.tags.mk-stream-indicator.connecting%<mk-ellipsis/></span>
+		<span>%i18n:@connecting%<mk-ellipsis/></span>
 	</p>
 	<p v-if=" stream.state == 'reconnecting' ">
 		%fa:spinner .pulse%
-		<span>%i18n:common.tags.mk-stream-indicator.reconnecting%<mk-ellipsis/></span>
+		<span>%i18n:@reconnecting%<mk-ellipsis/></span>
 	</p>
 	<p v-if=" stream.state == 'connected' ">
 		%fa:check%
-		<span>%i18n:common.tags.mk-stream-indicator.connected%</span>
+		<span>%i18n:@connected%</span>
 	</p>
 </div>
 </template>
diff --git a/src/client/app/common/views/components/twitter-setting.vue b/src/client/app/common/views/components/twitter-setting.vue
index 00669cd833..77788290f6 100644
--- a/src/client/app/common/views/components/twitter-setting.vue
+++ b/src/client/app/common/views/components/twitter-setting.vue
@@ -1,11 +1,11 @@
 <template>
 <div class="mk-twitter-setting">
-	<p>%i18n:common.tags.mk-twitter-setting.description%<a :href="`${docsUrl}/link-to-twitter`" target="_blank">%i18n:common.tags.mk-twitter-setting.detail%</a></p>
-	<p class="account" v-if="os.i.twitter" :title="`Twitter ID: ${os.i.twitter.userId}`">%i18n:common.tags.mk-twitter-setting.connected-to%: <a :href="`https://twitter.com/${os.i.twitter.screenName}`" target="_blank">@{{ os.i.twitter.screenName }}</a></p>
+	<p>%i18n:@description%<a :href="`${docsUrl}/link-to-twitter`" target="_blank">%i18n:@detail%</a></p>
+	<p class="account" v-if="os.i.twitter" :title="`Twitter ID: ${os.i.twitter.userId}`">%i18n:@connected-to%: <a :href="`https://twitter.com/${os.i.twitter.screenName}`" target="_blank">@{{ os.i.twitter.screenName }}</a></p>
 	<p>
-		<a :href="`${apiUrl}/connect/twitter`" target="_blank" @click.prevent="connect">{{ os.i.twitter ? '%i18n:common.tags.mk-twitter-setting.reconnect%' : '%i18n:common.tags.mk-twitter-setting.connect%' }}</a>
+		<a :href="`${apiUrl}/connect/twitter`" target="_blank" @click.prevent="connect">{{ os.i.twitter ? '%i18n:@reconnect%' : '%i18n:@connect%' }}</a>
 		<span v-if="os.i.twitter"> or </span>
-		<a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="os.i.twitter" @click.prevent="disconnect">%i18n:common.tags.mk-twitter-setting.disconnect%</a>
+		<a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="os.i.twitter" @click.prevent="disconnect">%i18n:@disconnect%</a>
 	</p>
 	<p class="id" v-if="os.i.twitter">Twitter ID: {{ os.i.twitter.userId }}</p>
 </div>
diff --git a/src/client/app/common/views/components/uploader.vue b/src/client/app/common/views/components/uploader.vue
index ccad50dc37..a6caa80f3c 100644
--- a/src/client/app/common/views/components/uploader.vue
+++ b/src/client/app/common/views/components/uploader.vue
@@ -5,7 +5,7 @@
 			<div class="img" :style="{ backgroundImage: `url(${ ctx.img })` }"></div>
 			<p class="name">%fa:spinner .pulse%{{ ctx.name }}</p>
 			<p class="status">
-				<span class="initing" v-if="ctx.progress == undefined">%i18n:common.tags.mk-uploader.waiting%<mk-ellipsis/></span>
+				<span class="initing" v-if="ctx.progress == undefined">%i18n:@waiting%<mk-ellipsis/></span>
 				<span class="kb" v-if="ctx.progress != undefined">{{ String(Math.floor(ctx.progress.value / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}<i>KB</i> / {{ String(Math.floor(ctx.progress.max / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}<i>KB</i></span>
 				<span class="percentage" v-if="ctx.progress != undefined">{{ Math.floor((ctx.progress.value / ctx.progress.max) * 100) }}</span>
 			</p>
diff --git a/src/client/app/common/views/widgets/access-log.vue b/src/client/app/common/views/widgets/access-log.vue
index f7bb17d833..637ba328c6 100644
--- a/src/client/app/common/views/widgets/access-log.vue
+++ b/src/client/app/common/views/widgets/access-log.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="mkw-access-log">
 	<mk-widget-container :show-header="props.design == 0">
-		<template slot="header">%fa:server%%i18n:desktop.tags.mk-access-log-home-widget.title%</template>
+		<template slot="header">%fa:server%%i18n:@title%</template>
 
 		<div :class="$style.logs" ref="log">
 			<p v-for="req in requests">
diff --git a/src/client/app/common/views/widgets/broadcast.vue b/src/client/app/common/views/widgets/broadcast.vue
index bf41a5fc67..6e11ec29e3 100644
--- a/src/client/app/common/views/widgets/broadcast.vue
+++ b/src/client/app/common/views/widgets/broadcast.vue
@@ -13,13 +13,13 @@
 			<path class="wave d" d="M29.18,1.06c-0.479-0.502-1.273-0.522-1.775-0.044c-0.016,0.015-0.029,0.029-0.045,0.044c-0.5,0.52-0.5,1.36,0,1.88 c1.361,1.4,2.041,3.24,2.041,5.08s-0.68,3.66-2.041,5.08c-0.5,0.52-0.5,1.36,0,1.88c0.509,0.508,1.332,0.508,1.841,0 c1.86-1.92,2.8-4.44,2.8-6.96C31.99,5.424,30.98,2.931,29.18,1.06z"></path>
 		</svg>
 	</div>
-	<p class="fetching" v-if="fetching">%i18n:desktop.tags.mk-broadcast-home-widget.fetching%<mk-ellipsis/></p>
-	<h1 v-if="!fetching">{{ broadcasts.length == 0 ? '%i18n:desktop.tags.mk-broadcast-home-widget.no-broadcasts%' : broadcasts[i].title }}</h1>
+	<p class="fetching" v-if="fetching">%i18n:@fetching%<mk-ellipsis/></p>
+	<h1 v-if="!fetching">{{ broadcasts.length == 0 ? '%i18n:@no-broadcasts%' : broadcasts[i].title }}</h1>
 	<p v-if="!fetching">
 		<span v-if="broadcasts.length != 0" v-html="broadcasts[i].text"></span>
-		<template v-if="broadcasts.length == 0">%i18n:desktop.tags.mk-broadcast-home-widget.have-a-nice-day%</template>
+		<template v-if="broadcasts.length == 0">%i18n:@have-a-nice-day%</template>
 	</p>
-	<a v-if="broadcasts.length > 1" @click="next">%i18n:desktop.tags.mk-broadcast-home-widget.next% &gt;&gt;</a>
+	<a v-if="broadcasts.length > 1" @click="next">%i18n:@next% &gt;&gt;</a>
 </div>
 </template>
 
diff --git a/src/client/app/common/views/widgets/donation.vue b/src/client/app/common/views/widgets/donation.vue
index e218df06e1..0b0145fa0b 100644
--- a/src/client/app/common/views/widgets/donation.vue
+++ b/src/client/app/common/views/widgets/donation.vue
@@ -1,11 +1,11 @@
 <template>
 <div class="mkw-donation" :data-mobile="isMobile">
 	<article>
-		<h1>%fa:heart%%i18n:desktop.tags.mk-donation-home-widget.title%</h1>
+		<h1>%fa:heart%%i18n:@title%</h1>
 		<p>
-			{{ '%i18n:desktop.tags.mk-donation-home-widget.text%'.substr(0, '%i18n:desktop.tags.mk-donation-home-widget.text%'.indexOf('{')) }}
+			{{ '%i18n:@text%'.substr(0, '%i18n:@text%'.indexOf('{')) }}
 			<a href="https://syuilo.com">@syuilo</a>
-			{{ '%i18n:desktop.tags.mk-donation-home-widget.text%'.substr('%i18n:desktop.tags.mk-donation-home-widget.text%'.indexOf('}') + 1) }}
+			{{ '%i18n:@text%'.substr('%i18n:@text%'.indexOf('}') + 1) }}
 		</p>
 	</article>
 </div>
diff --git a/src/client/app/common/views/widgets/photo-stream.vue b/src/client/app/common/views/widgets/photo-stream.vue
index baafd40662..c51d932bd1 100644
--- a/src/client/app/common/views/widgets/photo-stream.vue
+++ b/src/client/app/common/views/widgets/photo-stream.vue
@@ -1,13 +1,13 @@
 <template>
 <div class="mkw-photo-stream" :class="$style.root" :data-melt="props.design == 2">
 	<mk-widget-container :show-header="props.design == 0" :naked="props.design == 2">
-		<template slot="header">%fa:camera%%i18n:desktop.tags.mk-photo-stream-home-widget.title%</template>
+		<template slot="header">%fa:camera%%i18n:@title%</template>
 
 		<p :class="$style.fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
 		<div :class="$style.stream" v-if="!fetching && images.length > 0">
 			<div v-for="image in images" :class="$style.img" :style="`background-image: url(${image.url}?thumbnail&size=256)`"></div>
 		</div>
-		<p :class="$style.empty" v-if="!fetching && images.length == 0">%i18n:desktop.tags.mk-photo-stream-home-widget.no-photos%</p>
+		<p :class="$style.empty" v-if="!fetching && images.length == 0">%i18n:@no-photos%</p>
 	</mk-widget-container>
 </div>
 </template>
diff --git a/src/client/app/common/views/widgets/server.vue b/src/client/app/common/views/widgets/server.vue
index 3d5248998f..2fbc07adf0 100644
--- a/src/client/app/common/views/widgets/server.vue
+++ b/src/client/app/common/views/widgets/server.vue
@@ -1,8 +1,8 @@
 <template>
 <div class="mkw-server">
 	<mk-widget-container :show-header="props.design == 0" :naked="props.design == 2">
-		<template slot="header">%fa:server%%i18n:desktop.tags.mk-server-home-widget.title%</template>
-		<button slot="func" @click="toggle" title="%i18n:desktop.tags.mk-server-home-widget.toggle%">%fa:sort%</button>
+		<template slot="header">%fa:server%%i18n:@title%</template>
+		<button slot="func" @click="toggle" title="%i18n:@toggle%">%fa:sort%</button>
 
 		<p :class="$style.fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
 		<template v-if="!fetching">
diff --git a/src/client/app/desktop/views/components/activity.vue b/src/client/app/desktop/views/components/activity.vue
index 480b956ecc..ea33bf9ff6 100644
--- a/src/client/app/desktop/views/components/activity.vue
+++ b/src/client/app/desktop/views/components/activity.vue
@@ -1,8 +1,8 @@
 <template>
 <div class="mk-activity" :data-melt="design == 2">
 	<template v-if="design == 0">
-		<p class="title">%fa:chart-bar%%i18n:desktop.tags.mk-activity-widget.title%</p>
-		<button @click="toggle" title="%i18n:desktop.tags.mk-activity-widget.toggle%">%fa:sort%</button>
+		<p class="title">%fa:chart-bar%%i18n:@title%</p>
+		<button @click="toggle" title="%i18n:@toggle%">%fa:sort%</button>
 	</template>
 	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
 	<template v-else>
diff --git a/src/client/app/desktop/views/components/calendar.vue b/src/client/app/desktop/views/components/calendar.vue
index 71aab2e8a5..7f0052af5c 100644
--- a/src/client/app/desktop/views/components/calendar.vue
+++ b/src/client/app/desktop/views/components/calendar.vue
@@ -1,9 +1,9 @@
 <template>
 <div class="mk-calendar" :data-melt="design == 4 || design == 5">
 	<template v-if="design == 0 || design == 1">
-		<button @click="prev" title="%i18n:desktop.tags.mk-calendar-widget.prev%">%fa:chevron-circle-left%</button>
-		<p class="title">{{ '%i18n:desktop.tags.mk-calendar-widget.title%'.replace('{1}', year).replace('{2}', month) }}</p>
-		<button @click="next" title="%i18n:desktop.tags.mk-calendar-widget.next%">%fa:chevron-circle-right%</button>
+		<button @click="prev" title="%i18n:@prev%">%fa:chevron-circle-left%</button>
+		<p class="title">{{ '%i18n:@title%'.replace('{1}', year).replace('{2}', month) }}</p>
+		<button @click="next" title="%i18n:@next%">%fa:chevron-circle-right%</button>
 	</template>
 
 	<div class="calendar">
@@ -21,7 +21,7 @@
 			:data-is-out-of-range="isOutOfRange(i + 1)"
 			:data-is-donichi="isDonichi(i + 1)"
 			@click="go(i + 1)"
-			:title="isOutOfRange(i + 1) ? null : '%i18n:desktop.tags.mk-calendar-widget.go%'"
+			:title="isOutOfRange(i + 1) ? null : '%i18n:@go%'"
 		>
 			<div>{{ i + 1 }}</div>
 		</div>
diff --git a/src/client/app/desktop/views/components/drive-window.vue b/src/client/app/desktop/views/components/drive-window.vue
index 3a072f4794..1f45b64324 100644
--- a/src/client/app/desktop/views/components/drive-window.vue
+++ b/src/client/app/desktop/views/components/drive-window.vue
@@ -1,8 +1,8 @@
 <template>
 <mk-window ref="window" @closed="$destroy" width="800px" height="500px" :popout-url="popout">
 	<template slot="header">
-		<p v-if="usage" :class="$style.info"><b>{{ usage.toFixed(1) }}%</b> %i18n:desktop.tags.mk-drive-browser-window.used%</p>
-		<span :class="$style.title">%fa:cloud%%i18n:desktop.tags.mk-drive-browser-window.drive%</span>
+		<p v-if="usage" :class="$style.info"><b>{{ usage.toFixed(1) }}%</b> %i18n:@used%</p>
+		<span :class="$style.title">%fa:cloud%%i18n:@drive%</span>
 	</template>
 	<mk-drive :class="$style.browser" multiple :init-folder="folder" ref="browser"/>
 </mk-window>
diff --git a/src/client/app/desktop/views/components/drive.file.vue b/src/client/app/desktop/views/components/drive.file.vue
index 85f8361c9f..5ad81322bf 100644
--- a/src/client/app/desktop/views/components/drive.file.vue
+++ b/src/client/app/desktop/views/components/drive.file.vue
@@ -10,10 +10,10 @@
 	:title="title"
 >
 	<div class="label" v-if="os.i.avatarId == file.id"><img src="/assets/label.svg"/>
-		<p>%i18n:desktop.tags.mk-drive-browser-file.avatar%</p>
+		<p>%i18n:@avatar%</p>
 	</div>
 	<div class="label" v-if="os.i.bannerId == file.id"><img src="/assets/label.svg"/>
-		<p>%i18n:desktop.tags.mk-drive-browser-file.banner%</p>
+		<p>%i18n:@banner%</p>
 	</div>
 	<div class="thumbnail" ref="thumbnail" :style="`background-color: ${ background }`">
 		<img :src="`${file.url}?thumbnail&size=128`" alt="" @load="onThumbnailLoaded"/>
@@ -64,18 +64,18 @@ export default Vue.extend({
 			this.isContextmenuShowing = true;
 			contextmenu(e, [{
 				type: 'item',
-				text: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.rename%',
+				text: '%i18n:@contextmenu.rename%',
 				icon: '%fa:i-cursor%',
 				onClick: this.rename
 			}, {
 				type: 'item',
-				text: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.copy-url%',
+				text: '%i18n:@contextmenu.copy-url%',
 				icon: '%fa:link%',
 				onClick: this.copyUrl
 			}, {
 				type: 'link',
 				href: `${this.file.url}?download`,
-				text: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.download%',
+				text: '%i18n:@contextmenu.download%',
 				icon: '%fa:download%',
 			}, {
 				type: 'divider',
@@ -88,22 +88,22 @@ export default Vue.extend({
 				type: 'divider',
 			}, {
 				type: 'nest',
-				text: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.else-files%',
+				text: '%i18n:@contextmenu.else-files%',
 				menu: [{
 					type: 'item',
-					text: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.set-as-avatar%',
+					text: '%i18n:@contextmenu.set-as-avatar%',
 					onClick: this.setAsAvatar
 				}, {
 					type: 'item',
-					text: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.set-as-banner%',
+					text: '%i18n:@contextmenu.set-as-banner%',
 					onClick: this.setAsBanner
 				}]
 			}, {
 				type: 'nest',
-				text: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.open-in-app%',
+				text: '%i18n:@contextmenu.open-in-app%',
 				menu: [{
 					type: 'item',
-					text: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.add-app%...',
+					text: '%i18n:@contextmenu.add-app%...',
 					onClick: this.addApp
 				}]
 			}], {
@@ -141,8 +141,8 @@ export default Vue.extend({
 
 		rename() {
 			(this as any).apis.input({
-				title: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.rename-file%',
-				placeholder: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.input-new-file-name%',
+				title: '%i18n:@contextmenu.rename-file%',
+				placeholder: '%i18n:@contextmenu.input-new-file-name%',
 				default: this.file.name,
 				allowEmpty: false
 			}).then(name => {
@@ -156,8 +156,8 @@ export default Vue.extend({
 		copyUrl() {
 			copyToClipboard(this.file.url);
 			(this as any).apis.dialog({
-				title: '%fa:check%%i18n:desktop.tags.mk-drive-browser-file-contextmenu.copied%',
-				text: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.copied-url-to-clipboard%',
+				title: '%fa:check%%i18n:@contextmenu.copied%',
+				text: '%i18n:@contextmenu.copied-url-to-clipboard%',
 				actions: [{
 					text: '%i18n:common.ok%'
 				}]
diff --git a/src/client/app/desktop/views/components/drive.folder.vue b/src/client/app/desktop/views/components/drive.folder.vue
index a926bf47b2..16f474f4e0 100644
--- a/src/client/app/desktop/views/components/drive.folder.vue
+++ b/src/client/app/desktop/views/components/drive.folder.vue
@@ -54,19 +54,19 @@ export default Vue.extend({
 			this.isContextmenuShowing = true;
 			contextmenu(e, [{
 				type: 'item',
-				text: '%i18n:desktop.tags.mk-drive-browser-folder-contextmenu.move-to-this-folder%',
+				text: '%i18n:@contextmenu.move-to-this-folder%',
 				icon: '%fa:arrow-right%',
 				onClick: this.go
 			}, {
 				type: 'item',
-				text: '%i18n:desktop.tags.mk-drive-browser-folder-contextmenu.show-in-new-window%',
+				text: '%i18n:@contextmenu.show-in-new-window%',
 				icon: '%fa:R window-restore%',
 				onClick: this.newWindow
 			}, {
 				type: 'divider',
 			}, {
 				type: 'item',
-				text: '%i18n:desktop.tags.mk-drive-browser-folder-contextmenu.rename%',
+				text: '%i18n:@contextmenu.rename%',
 				icon: '%fa:i-cursor%',
 				onClick: this.rename
 			}, {
@@ -159,15 +159,15 @@ export default Vue.extend({
 					switch (err) {
 						case 'detected-circular-definition':
 							(this as any).apis.dialog({
-								title: '%fa:exclamation-triangle%%i18n:desktop.tags.mk-drive-browser-folder.unable-to-process%',
-								text: '%i18n:desktop.tags.mk-drive-browser-folder.circular-reference-detected%',
+								title: '%fa:exclamation-triangle%%i18n:@unable-to-process%',
+								text: '%i18n:@circular-reference-detected%',
 								actions: [{
 									text: '%i18n:common.ok%'
 								}]
 							});
 							break;
 						default:
-							alert('%i18n:desktop.tags.mk-drive-browser-folder.unhandled-error% ' + err);
+							alert('%i18n:@unhandled-error% ' + err);
 					}
 				});
 			}
@@ -199,8 +199,8 @@ export default Vue.extend({
 
 		rename() {
 			(this as any).apis.input({
-				title: '%i18n:desktop.tags.mk-drive-browser-folder-contextmenu.rename-folder%',
-				placeholder: '%i18n:desktop.tags.mk-drive-browser-folder-contextmenu.input-new-folder-name%',
+				title: '%i18n:@contextmenu.rename-folder%',
+				placeholder: '%i18n:@contextmenu.input-new-folder-name%',
 				default: this.folder.name
 			}).then(name => {
 				(this as any).api('drive/folders/update', {
diff --git a/src/client/app/desktop/views/components/drive.nav-folder.vue b/src/client/app/desktop/views/components/drive.nav-folder.vue
index d885a72f7f..e910cdbae7 100644
--- a/src/client/app/desktop/views/components/drive.nav-folder.vue
+++ b/src/client/app/desktop/views/components/drive.nav-folder.vue
@@ -8,7 +8,7 @@
 	@drop.stop="onDrop"
 >
 	<template v-if="folder == null">%fa:cloud%</template>
-	<span>{{ folder == null ? '%i18n:desktop.tags.mk-drive-browser-nav-folder.drive%' : folder.name }}</span>
+	<span>{{ folder == null ? '%i18n:@drive%' : folder.name }}</span>
 </div>
 </template>
 
diff --git a/src/client/app/desktop/views/components/drive.vue b/src/client/app/desktop/views/components/drive.vue
index c766dfec12..abdf1338b4 100644
--- a/src/client/app/desktop/views/components/drive.vue
+++ b/src/client/app/desktop/views/components/drive.vue
@@ -10,7 +10,7 @@
 			<span class="separator" v-if="folder != null">%fa:angle-right%</span>
 			<span class="folder current" v-if="folder != null">{{ folder.name }}</span>
 		</div>
-		<input class="search" type="search" placeholder="&#xf002; %i18n:desktop.tags.mk-drive-browser.search%"/>
+		<input class="search" type="search" placeholder="&#xf002; %i18n:@search%"/>
 	</nav>
 	<div class="main" :class="{ uploading: uploadings.length > 0, fetching }"
 		ref="main"
@@ -27,18 +27,18 @@
 				<x-folder v-for="folder in folders" :key="folder.id" class="folder" :folder="folder"/>
 				<!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid -->
 				<div class="padding" v-for="n in 16"></div>
-				<button v-if="moreFolders">%i18n:desktop.tags.mk-drive-browser.load-more%</button>
+				<button v-if="moreFolders">%i18n:@load-more%</button>
 			</div>
 			<div class="files" ref="filesContainer" v-if="files.length > 0">
 				<x-file v-for="file in files" :key="file.id" class="file" :file="file"/>
 				<!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid -->
 				<div class="padding" v-for="n in 16"></div>
-				<button v-if="moreFiles" @click="fetchMoreFiles">%i18n:desktop.tags.mk-drive-browser.load-more%</button>
+				<button v-if="moreFiles" @click="fetchMoreFiles">%i18n:@load-more%</button>
 			</div>
 			<div class="empty" v-if="files.length == 0 && folders.length == 0 && !fetching">
-				<p v-if="draghover">%i18n:desktop.tags.mk-drive-browser.empty-draghover%</p>
-				<p v-if="!draghover && folder == null"><strong>%i18n:desktop.tags.mk-drive-browser.empty-drive%</strong><br/>%i18n:desktop.tags.mk-drive-browser.empty-drive-description%</p>
-				<p v-if="!draghover && folder != null">%i18n:desktop.tags.mk-drive-browser.empty-folder%</p>
+				<p v-if="draghover">%i18n:@empty-draghover%</p>
+				<p v-if="!draghover && folder == null"><strong>%i18n:@empty-drive%</strong><br/>%i18n:@empty-drive-description%</p>
+				<p v-if="!draghover && folder != null">%i18n:@empty-folder%</p>
 			</div>
 		</div>
 		<div class="fetching" v-if="fetching">
@@ -138,17 +138,17 @@ export default Vue.extend({
 		onContextmenu(e) {
 			contextmenu(e, [{
 				type: 'item',
-				text: '%i18n:desktop.tags.mk-drive-browser-base-contextmenu.create-folder%',
+				text: '%i18n:@contextmenu.create-folder%',
 				icon: '%fa:R folder%',
 				onClick: this.createFolder
 			}, {
 				type: 'item',
-				text: '%i18n:desktop.tags.mk-drive-browser-base-contextmenu.upload%',
+				text: '%i18n:@contextmenu.upload%',
 				icon: '%fa:upload%',
 				onClick: this.selectLocalFile
 			}, {
 				type: 'item',
-				text: '%i18n:desktop.tags.mk-drive-browser-base-contextmenu.url-upload%',
+				text: '%i18n:@contextmenu.url-upload%',
 				icon: '%fa:cloud-upload-alt%',
 				onClick: this.urlUpload
 			}]);
@@ -306,15 +306,15 @@ export default Vue.extend({
 					switch (err) {
 						case 'detected-circular-definition':
 							(this as any).apis.dialog({
-								title: '%fa:exclamation-triangle%%i18n:desktop.tags.mk-drive-browser.unable-to-process%',
-								text: '%i18n:desktop.tags.mk-drive-browser.circular-reference-detected%',
+								title: '%fa:exclamation-triangle%%i18n:@unable-to-process%',
+								text: '%i18n:@circular-reference-detected%',
 								actions: [{
 									text: '%i18n:common.ok%'
 								}]
 							});
 							break;
 						default:
-							alert('%i18n:desktop.tags.mk-drive-browser.unhandled-error% ' + err);
+							alert('%i18n:@unhandled-error% ' + err);
 					}
 				});
 			}
@@ -327,8 +327,8 @@ export default Vue.extend({
 
 		urlUpload() {
 			(this as any).apis.input({
-				title: '%i18n:desktop.tags.mk-drive-browser.url-upload%',
-				placeholder: '%i18n:desktop.tags.mk-drive-browser.url-of-file%'
+				title: '%i18n:@url-upload%',
+				placeholder: '%i18n:@url-of-file%'
 			}).then(url => {
 				(this as any).api('drive/files/upload_from_url', {
 					url: url,
@@ -336,8 +336,8 @@ export default Vue.extend({
 				});
 
 				(this as any).apis.dialog({
-					title: '%fa:check%%i18n:desktop.tags.mk-drive-browser.url-upload-requested%',
-					text: '%i18n:desktop.tags.mk-drive-browser.may-take-time%',
+					title: '%fa:check%%i18n:@url-upload-requested%',
+					text: '%i18n:@may-take-time%',
 					actions: [{
 						text: '%i18n:common.ok%'
 					}]
@@ -347,8 +347,8 @@ export default Vue.extend({
 
 		createFolder() {
 			(this as any).apis.input({
-				title: '%i18n:desktop.tags.mk-drive-browser.create-folder%',
-				placeholder: '%i18n:desktop.tags.mk-drive-browser.folder-name%'
+				title: '%i18n:@create-folder%',
+				placeholder: '%i18n:@folder-name%'
 			}).then(name => {
 				(this as any).api('drive/folders/create', {
 					name: name,
diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue
index 8561643c9c..90f9e98a5c 100644
--- a/src/client/app/desktop/views/components/notes.note.vue
+++ b/src/client/app/desktop/views/components/notes.note.vue
@@ -9,9 +9,9 @@
 				<img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=32`" alt="avatar"/>
 			</router-link>
 			%fa:retweet%
-			<span>{{ '%i18n:desktop.tags.mk-timeline-note.reposted-by%'.substr(0, '%i18n:desktop.tags.mk-timeline-note.reposted-by%'.indexOf('{')) }}</span>
+			<span>{{ '%i18n:@reposted-by%'.substr(0, '%i18n:@reposted-by%'.indexOf('{')) }}</span>
 			<a class="name" :href="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</a>
-			<span>{{ '%i18n:desktop.tags.mk-timeline-note.reposted-by%'.substr('%i18n:desktop.tags.mk-timeline-note.reposted-by%'.indexOf('}') + 1) }}</span>
+			<span>{{ '%i18n:@reposted-by%'.substr('%i18n:@reposted-by%'.indexOf('}') + 1) }}</span>
 		</p>
 		<mk-time :time="note.createdAt"/>
 	</div>
@@ -57,19 +57,19 @@
 			</div>
 			<footer>
 				<mk-reactions-viewer :note="p" ref="reactionsViewer"/>
-				<button @click="reply" title="%i18n:desktop.tags.mk-timeline-note.reply%">
+				<button @click="reply" title="%i18n:@reply%">
 					%fa:reply%<p class="count" v-if="p.repliesCount > 0">{{ p.repliesCount }}</p>
 				</button>
-				<button @click="renote" title="%i18n:desktop.tags.mk-timeline-note.renote%">
+				<button @click="renote" title="%i18n:@renote%">
 					%fa:retweet%<p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p>
 				</button>
-				<button :class="{ reacted: p.myReaction != null }" @click="react" ref="reactButton" title="%i18n:desktop.tags.mk-timeline-note.add-reaction%">
+				<button :class="{ reacted: p.myReaction != null }" @click="react" ref="reactButton" title="%i18n:@add-reaction%">
 					%fa:plus%<p class="count" v-if="p.reactions_count > 0">{{ p.reactions_count }}</p>
 				</button>
 				<button @click="menu" ref="menuButton">
 					%fa:ellipsis-h%
 				</button>
-				<button title="%i18n:desktop.tags.mk-timeline-note.detail">
+				<button title="%i18n:@detail">
 					<template v-if="!isDetailOpened">%fa:caret-down%</template>
 					<template v-if="isDetailOpened">%fa:caret-up%</template>
 				</button>
diff --git a/src/client/app/desktop/views/components/notifications.vue b/src/client/app/desktop/views/components/notifications.vue
index 598c2ad2fa..9b1a66dde5 100644
--- a/src/client/app/desktop/views/components/notifications.vue
+++ b/src/client/app/desktop/views/components/notifications.vue
@@ -93,7 +93,7 @@
 		</template>
 	</div>
 	<button class="more" :class="{ fetching: fetchingMoreNotifications }" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications">
-		<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:desktop.tags.mk-notifications.more%' }}
+		<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }}
 	</button>
 	<p class="empty" v-if="notifications.length == 0 && !fetching">ありません!</p>
 	<p class="loading" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
diff --git a/src/client/app/desktop/views/components/post-form-window.vue b/src/client/app/desktop/views/components/post-form-window.vue
index c890592a5e..18bb39f9bc 100644
--- a/src/client/app/desktop/views/components/post-form-window.vue
+++ b/src/client/app/desktop/views/components/post-form-window.vue
@@ -2,10 +2,10 @@
 <mk-window ref="window" is-modal @closed="$destroy">
 	<span slot="header">
 		<span :class="$style.icon" v-if="geo">%fa:map-marker-alt%</span>
-		<span v-if="!reply">%i18n:desktop.tags.mk-post-form-window.note%</span>
-		<span v-if="reply">%i18n:desktop.tags.mk-post-form-window.reply%</span>
-		<span :class="$style.count" v-if="media.length != 0">{{ '%i18n:desktop.tags.mk-post-form-window.attaches%'.replace('{}', media.length) }}</span>
-		<span :class="$style.count" v-if="uploadings.length != 0">{{ '%i18n:desktop.tags.mk-post-form-window.uploading-media%'.replace('{}', uploadings.length) }}<mk-ellipsis/></span>
+		<span v-if="!reply">%i18n:@note%</span>
+		<span v-if="reply">%i18n:@reply%</span>
+		<span :class="$style.count" v-if="media.length != 0">{{ '%i18n:@attaches%'.replace('{}', media.length) }}</span>
+		<span :class="$style.count" v-if="uploadings.length != 0">{{ '%i18n:@uploading-media%'.replace('{}', uploadings.length) }}<mk-ellipsis/></span>
 	</span>
 
 	<mk-note-preview v-if="reply" :class="$style.notePreview" :note="reply"/>
diff --git a/src/client/app/desktop/views/components/post-form.vue b/src/client/app/desktop/views/components/post-form.vue
index 8e3ec24bc8..6071bbe31f 100644
--- a/src/client/app/desktop/views/components/post-form.vue
+++ b/src/client/app/desktop/views/components/post-form.vue
@@ -15,7 +15,7 @@
 			<x-draggable :list="files" :options="{ animation: 150 }">
 				<div v-for="file in files" :key="file.id">
 					<div class="img" :style="{ backgroundImage: `url(${file.url}?thumbnail&size=64)` }" :title="file.name"></div>
-					<img class="remove" @click="detachMedia(file.id)" src="/assets/desktop/remove.png" title="%i18n:desktop.tags.mk-post-form.attach-cancel%" alt=""/>
+					<img class="remove" @click="detachMedia(file.id)" src="/assets/desktop/remove.png" title="%i18n:@attach-cancel%" alt=""/>
 				</div>
 			</x-draggable>
 			<p class="remain">{{ 4 - files.length }}/4</p>
@@ -23,14 +23,14 @@
 		<mk-poll-editor v-if="poll" ref="poll" @destroyed="poll = false" @updated="saveDraft()"/>
 	</div>
 	<mk-uploader ref="uploader" @uploaded="attachMedia" @change="onChangeUploadings"/>
-	<button class="upload" title="%i18n:desktop.tags.mk-post-form.attach-media-from-local%" @click="chooseFile">%fa:upload%</button>
-	<button class="drive" title="%i18n:desktop.tags.mk-post-form.attach-media-from-drive%" @click="chooseFileFromDrive">%fa:cloud%</button>
-	<button class="kao" title="%i18n:desktop.tags.mk-post-form.insert-a-kao%" @click="kao">%fa:R smile%</button>
-	<button class="poll" title="%i18n:desktop.tags.mk-post-form.create-poll%" @click="poll = true">%fa:chart-pie%</button>
+	<button class="upload" title="%i18n:@attach-media-from-local%" @click="chooseFile">%fa:upload%</button>
+	<button class="drive" title="%i18n:@attach-media-from-drive%" @click="chooseFileFromDrive">%fa:cloud%</button>
+	<button class="kao" title="%i18n:@insert-a-kao%" @click="kao">%fa:R smile%</button>
+	<button class="poll" title="%i18n:@create-poll%" @click="poll = true">%fa:chart-pie%</button>
 	<button class="geo" title="位置情報を添付する" @click="geo ? removeGeo() : setGeo()">%fa:map-marker-alt%</button>
-	<p class="text-count" :class="{ over: text.length > 1000 }">{{ '%i18n:desktop.tags.mk-post-form.text-remain%'.replace('{}', 1000 - text.length) }}</p>
+	<p class="text-count" :class="{ over: text.length > 1000 }">{{ '%i18n:@text-remain%'.replace('{}', 1000 - text.length) }}</p>
 	<button :class="{ posting }" class="submit" :disabled="!canPost" @click="post">
-		{{ posting ? '%i18n:desktop.tags.mk-post-form.posting%' : submitText }}<mk-ellipsis v-if="posting"/>
+		{{ posting ? '%i18n:@posting%' : submitText }}<mk-ellipsis v-if="posting"/>
 	</button>
 	<input ref="file" type="file" accept="image/*" multiple="multiple" tabindex="-1" @change="onChangeFile"/>
 	<div class="dropzone" v-if="draghover"></div>
@@ -69,17 +69,17 @@ export default Vue.extend({
 		},
 		placeholder(): string {
 			return this.renote
-				? '%i18n:desktop.tags.mk-post-form.quote-placeholder%'
+				? '%i18n:@quote-placeholder%'
 				: this.reply
-					? '%i18n:desktop.tags.mk-post-form.reply-placeholder%'
-					: '%i18n:desktop.tags.mk-post-form.note-placeholder%';
+					? '%i18n:@reply-placeholder%'
+					: '%i18n:@note-placeholder%';
 		},
 		submitText(): string {
 			return this.renote
-				? '%i18n:desktop.tags.mk-post-form.renote%'
+				? '%i18n:@renote%'
 				: this.reply
-					? '%i18n:desktop.tags.mk-post-form.reply%'
-					: '%i18n:desktop.tags.mk-post-form.note%';
+					? '%i18n:@reply%'
+					: '%i18n:@note%';
 		},
 		canPost(): boolean {
 			return !this.posting && (this.text.length != 0 || this.files.length != 0 || this.poll || this.renote);
@@ -236,16 +236,16 @@ export default Vue.extend({
 				this.deleteDraft();
 				this.$emit('posted');
 				(this as any).apis.notify(this.renote
-					? '%i18n:desktop.tags.mk-post-form.reposted%'
+					? '%i18n:@reposted%'
 					: this.reply
-						? '%i18n:desktop.tags.mk-post-form.replied%'
-						: '%i18n:desktop.tags.mk-post-form.posted%');
+						? '%i18n:@replied%'
+						: '%i18n:@posted%');
 			}).catch(err => {
 				(this as any).apis.notify(this.renote
-					? '%i18n:desktop.tags.mk-post-form.renote-failed%'
+					? '%i18n:@renote-failed%'
 					: this.reply
-						? '%i18n:desktop.tags.mk-post-form.reply-failed%'
-						: '%i18n:desktop.tags.mk-post-form.note-failed%');
+						? '%i18n:@reply-failed%'
+						: '%i18n:@note-failed%');
 			}).then(() => {
 				this.posting = false;
 			});
diff --git a/src/client/app/desktop/views/components/renote-form-window.vue b/src/client/app/desktop/views/components/renote-form-window.vue
index 09176b5ba7..df9d2f7fc7 100644
--- a/src/client/app/desktop/views/components/renote-form-window.vue
+++ b/src/client/app/desktop/views/components/renote-form-window.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-window ref="window" is-modal @closed="$destroy">
-	<span slot="header" :class="$style.header">%fa:retweet%%i18n:desktop.tags.mk-renote-form-window.title%</span>
+	<span slot="header" :class="$style.header">%fa:retweet%%i18n:@title%</span>
 	<mk-renote-form ref="form" :note="note" @posted="onPosted" @canceled="onCanceled"/>
 </mk-window>
 </template>
diff --git a/src/client/app/desktop/views/components/renote-form.vue b/src/client/app/desktop/views/components/renote-form.vue
index c6b9074156..1f947a71de 100644
--- a/src/client/app/desktop/views/components/renote-form.vue
+++ b/src/client/app/desktop/views/components/renote-form.vue
@@ -3,9 +3,9 @@
 	<mk-note-preview :note="note"/>
 	<template v-if="!quote">
 		<footer>
-			<a class="quote" v-if="!quote" @click="onQuote">%i18n:desktop.tags.mk-renote-form.quote%</a>
-			<button class="cancel" @click="cancel">%i18n:desktop.tags.mk-renote-form.cancel%</button>
-			<button class="ok" @click="ok" :disabled="wait">{{ wait ? '%i18n:desktop.tags.mk-renote-form.reposting%' : '%i18n:desktop.tags.mk-renote-form.renote%' }}</button>
+			<a class="quote" v-if="!quote" @click="onQuote">%i18n:@quote%</a>
+			<button class="cancel" @click="cancel">%i18n:@cancel%</button>
+			<button class="ok" @click="ok" :disabled="wait">{{ wait ? '%i18n:@reposting%' : '%i18n:@renote%' }}</button>
 		</footer>
 	</template>
 	<template v-if="quote">
@@ -32,9 +32,9 @@ export default Vue.extend({
 				renoteId: this.note.id
 			}).then(data => {
 				this.$emit('posted');
-				(this as any).apis.notify('%i18n:desktop.tags.mk-renote-form.success%');
+				(this as any).apis.notify('%i18n:@success%');
 			}).catch(err => {
-				(this as any).apis.notify('%i18n:desktop.tags.mk-renote-form.failure%');
+				(this as any).apis.notify('%i18n:@failure%');
 			}).then(() => {
 				this.wait = false;
 			});
diff --git a/src/client/app/desktop/views/components/repost-form-window.vue b/src/client/app/desktop/views/components/repost-form-window.vue
index 09176b5ba7..df9d2f7fc7 100644
--- a/src/client/app/desktop/views/components/repost-form-window.vue
+++ b/src/client/app/desktop/views/components/repost-form-window.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-window ref="window" is-modal @closed="$destroy">
-	<span slot="header" :class="$style.header">%fa:retweet%%i18n:desktop.tags.mk-renote-form-window.title%</span>
+	<span slot="header" :class="$style.header">%fa:retweet%%i18n:@title%</span>
 	<mk-renote-form ref="form" :note="note" @posted="onPosted" @canceled="onCanceled"/>
 </mk-window>
 </template>
diff --git a/src/client/app/desktop/views/components/repost-form.vue b/src/client/app/desktop/views/components/repost-form.vue
index c6b9074156..1f947a71de 100644
--- a/src/client/app/desktop/views/components/repost-form.vue
+++ b/src/client/app/desktop/views/components/repost-form.vue
@@ -3,9 +3,9 @@
 	<mk-note-preview :note="note"/>
 	<template v-if="!quote">
 		<footer>
-			<a class="quote" v-if="!quote" @click="onQuote">%i18n:desktop.tags.mk-renote-form.quote%</a>
-			<button class="cancel" @click="cancel">%i18n:desktop.tags.mk-renote-form.cancel%</button>
-			<button class="ok" @click="ok" :disabled="wait">{{ wait ? '%i18n:desktop.tags.mk-renote-form.reposting%' : '%i18n:desktop.tags.mk-renote-form.renote%' }}</button>
+			<a class="quote" v-if="!quote" @click="onQuote">%i18n:@quote%</a>
+			<button class="cancel" @click="cancel">%i18n:@cancel%</button>
+			<button class="ok" @click="ok" :disabled="wait">{{ wait ? '%i18n:@reposting%' : '%i18n:@renote%' }}</button>
 		</footer>
 	</template>
 	<template v-if="quote">
@@ -32,9 +32,9 @@ export default Vue.extend({
 				renoteId: this.note.id
 			}).then(data => {
 				this.$emit('posted');
-				(this as any).apis.notify('%i18n:desktop.tags.mk-renote-form.success%');
+				(this as any).apis.notify('%i18n:@success%');
 			}).catch(err => {
-				(this as any).apis.notify('%i18n:desktop.tags.mk-renote-form.failure%');
+				(this as any).apis.notify('%i18n:@failure%');
 			}).then(() => {
 				this.wait = false;
 			});
diff --git a/src/client/app/desktop/views/components/settings.2fa.vue b/src/client/app/desktop/views/components/settings.2fa.vue
index fb2dc30f2a..0809dd798c 100644
--- a/src/client/app/desktop/views/components/settings.2fa.vue
+++ b/src/client/app/desktop/views/components/settings.2fa.vue
@@ -1,22 +1,22 @@
 <template>
 <div class="2fa">
-	<p>%i18n:desktop.tags.mk-2fa-setting.intro%<a href="%i18n:desktop.tags.mk-2fa-setting.url%" target="_blank">%i18n:desktop.tags.mk-2fa-setting.detail%</a></p>
-	<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:desktop.tags.mk-2fa-setting.caution%</p></div>
-	<p v-if="!data && !os.i.twoFactorEnabled"><button @click="register" class="ui primary">%i18n:desktop.tags.mk-2fa-setting.register%</button></p>
+	<p>%i18n:@intro%<a href="%i18n:@url%" target="_blank">%i18n:@detail%</a></p>
+	<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:@caution%</p></div>
+	<p v-if="!data && !os.i.twoFactorEnabled"><button @click="register" class="ui primary">%i18n:@register%</button></p>
 	<template v-if="os.i.twoFactorEnabled">
-		<p>%i18n:desktop.tags.mk-2fa-setting.already-registered%</p>
-		<button @click="unregister" class="ui">%i18n:desktop.tags.mk-2fa-setting.unregister%</button>
+		<p>%i18n:@already-registered%</p>
+		<button @click="unregister" class="ui">%i18n:@unregister%</button>
 	</template>
 	<div v-if="data">
 		<ol>
-			<li>%i18n:desktop.tags.mk-2fa-setting.authenticator% <a href="https://support.google.com/accounts/answer/1066447" target="_blank">%i18n:desktop.tags.mk-2fa-setting.howtoinstall%</a></li>
-			<li>%i18n:desktop.tags.mk-2fa-setting.scan%<br><img :src="data.qr"></li>
-			<li>%i18n:desktop.tags.mk-2fa-setting.done%<br>
+			<li>%i18n:@authenticator% <a href="https://support.google.com/accounts/answer/1066447" target="_blank">%i18n:@howtoinstall%</a></li>
+			<li>%i18n:@scan%<br><img :src="data.qr"></li>
+			<li>%i18n:@done%<br>
 				<input type="number" v-model="token" class="ui">
-				<button @click="submit" class="ui primary">%i18n:desktop.tags.mk-2fa-setting.submit%</button>
+				<button @click="submit" class="ui primary">%i18n:@submit%</button>
 			</li>
 		</ol>
-		<div class="ui info"><p>%fa:info-circle%%i18n:desktop.tags.mk-2fa-setting.info%</p></div>
+		<div class="ui info"><p>%fa:info-circle%%i18n:@info%</p></div>
 	</div>
 </div>
 </template>
@@ -34,7 +34,7 @@ export default Vue.extend({
 	methods: {
 		register() {
 			(this as any).apis.input({
-				title: '%i18n:desktop.tags.mk-2fa-setting.enter-password%',
+				title: '%i18n:@enter-password%',
 				type: 'password'
 			}).then(password => {
 				(this as any).api('i/2fa/register', {
@@ -47,13 +47,13 @@ export default Vue.extend({
 
 		unregister() {
 			(this as any).apis.input({
-				title: '%i18n:desktop.tags.mk-2fa-setting.enter-password%',
+				title: '%i18n:@enter-password%',
 				type: 'password'
 			}).then(password => {
 				(this as any).api('i/2fa/unregister', {
 					password: password
 				}).then(() => {
-					(this as any).apis.notify('%i18n:desktop.tags.mk-2fa-setting.unregistered%');
+					(this as any).apis.notify('%i18n:@unregistered%');
 					(this as any).os.i.twoFactorEnabled = false;
 				});
 			});
@@ -63,10 +63,10 @@ export default Vue.extend({
 			(this as any).api('i/2fa/done', {
 				token: this.token
 			}).then(() => {
-				(this as any).apis.notify('%i18n:desktop.tags.mk-2fa-setting.success%');
+				(this as any).apis.notify('%i18n:@success%');
 				(this as any).os.i.twoFactorEnabled = true;
 			}).catch(() => {
-				(this as any).apis.notify('%i18n:desktop.tags.mk-2fa-setting.failed%');
+				(this as any).apis.notify('%i18n:@failed%');
 			});
 		}
 	}
diff --git a/src/client/app/desktop/views/components/settings.api.vue b/src/client/app/desktop/views/components/settings.api.vue
index 5831f82075..6ae29cb58a 100644
--- a/src/client/app/desktop/views/components/settings.api.vue
+++ b/src/client/app/desktop/views/components/settings.api.vue
@@ -1,10 +1,10 @@
 <template>
 <div class="root api">
 	<p>Token: <code>{{ os.i.token }}</code></p>
-	<p>%i18n:desktop.tags.mk-api-info.intro%</p>
-	<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:desktop.tags.mk-api-info.caution%</p></div>
-	<p>%i18n:desktop.tags.mk-api-info.regeneration-of-token%</p>
-	<button class="ui" @click="regenerateToken">%i18n:desktop.tags.mk-api-info.regenerate-token%</button>
+	<p>%i18n:@intro%</p>
+	<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:@caution%</p></div>
+	<p>%i18n:@regeneration-of-token%</p>
+	<button class="ui" @click="regenerateToken">%i18n:@regenerate-token%</button>
 </div>
 </template>
 
@@ -15,7 +15,7 @@ export default Vue.extend({
 	methods: {
 		regenerateToken() {
 			(this as any).apis.input({
-				title: '%i18n:desktop.tags.mk-api-info.enter-password%',
+				title: '%i18n:@enter-password%',
 				type: 'password'
 			}).then(password => {
 				(this as any).api('i/regenerate_token', {
diff --git a/src/client/app/desktop/views/components/settings.mute.vue b/src/client/app/desktop/views/components/settings.mute.vue
index 94492ad262..792afa923f 100644
--- a/src/client/app/desktop/views/components/settings.mute.vue
+++ b/src/client/app/desktop/views/components/settings.mute.vue
@@ -1,7 +1,7 @@
 <template>
 <div>
 	<div class="none ui info" v-if="!fetching && users.length == 0">
-		<p>%fa:info-circle%%i18n:desktop.tags.mk-mute-setting.no-users%</p>
+		<p>%fa:info-circle%%i18n:@no-users%</p>
 	</div>
 	<div class="users" v-if="users.length != 0">
 		<div v-for="user in users" :key="user.id">
diff --git a/src/client/app/desktop/views/components/settings.password.vue b/src/client/app/desktop/views/components/settings.password.vue
index f883b54065..39896daf67 100644
--- a/src/client/app/desktop/views/components/settings.password.vue
+++ b/src/client/app/desktop/views/components/settings.password.vue
@@ -1,6 +1,6 @@
 <template>
 <div>
-	<button @click="reset" class="ui primary">%i18n:desktop.tags.mk-password-setting.reset%</button>
+	<button @click="reset" class="ui primary">%i18n:@reset%</button>
 </div>
 </template>
 
@@ -11,21 +11,21 @@ export default Vue.extend({
 	methods: {
 		reset() {
 			(this as any).apis.input({
-				title: '%i18n:desktop.tags.mk-password-setting.enter-current-password%',
+				title: '%i18n:@enter-current-password%',
 				type: 'password'
 			}).then(currentPassword => {
 				(this as any).apis.input({
-					title: '%i18n:desktop.tags.mk-password-setting.enter-new-password%',
+					title: '%i18n:@enter-new-password%',
 					type: 'password'
 				}).then(newPassword => {
 					(this as any).apis.input({
-						title: '%i18n:desktop.tags.mk-password-setting.enter-new-password-again%',
+						title: '%i18n:@enter-new-password-again%',
 						type: 'password'
 					}).then(newPassword2 => {
 						if (newPassword !== newPassword2) {
 							(this as any).apis.dialog({
 								title: null,
-								text: '%i18n:desktop.tags.mk-password-setting.not-match%',
+								text: '%i18n:@not-match%',
 								actions: [{
 									text: 'OK'
 								}]
@@ -36,7 +36,7 @@ export default Vue.extend({
 							currentPasword: currentPassword,
 							newPassword: newPassword
 						}).then(() => {
-							(this as any).apis.notify('%i18n:desktop.tags.mk-password-setting.changed%');
+							(this as any).apis.notify('%i18n:@changed%');
 						});
 					});
 				});
diff --git a/src/client/app/desktop/views/components/settings.profile.vue b/src/client/app/desktop/views/components/settings.profile.vue
index 324a939f95..84b09eb988 100644
--- a/src/client/app/desktop/views/components/settings.profile.vue
+++ b/src/client/app/desktop/views/components/settings.profile.vue
@@ -1,27 +1,27 @@
 <template>
 <div class="profile">
 	<label class="avatar ui from group">
-		<p>%i18n:desktop.tags.mk-profile-setting.avatar%</p>
+		<p>%i18n:@avatar%</p>
 		<img class="avatar" :src="`${os.i.avatarUrl}?thumbnail&size=64`" alt="avatar"/>
-		<button class="ui" @click="updateAvatar">%i18n:desktop.tags.mk-profile-setting.choice-avatar%</button>
+		<button class="ui" @click="updateAvatar">%i18n:@choice-avatar%</button>
 	</label>
 	<label class="ui from group">
-		<p>%i18n:desktop.tags.mk-profile-setting.name%</p>
+		<p>%i18n:@name%</p>
 		<input v-model="name" type="text" class="ui"/>
 	</label>
 	<label class="ui from group">
-		<p>%i18n:desktop.tags.mk-profile-setting.location%</p>
+		<p>%i18n:@location%</p>
 		<input v-model="location" type="text" class="ui"/>
 	</label>
 	<label class="ui from group">
-		<p>%i18n:desktop.tags.mk-profile-setting.description%</p>
+		<p>%i18n:@description%</p>
 		<textarea v-model="description" class="ui"></textarea>
 	</label>
 	<label class="ui from group">
-		<p>%i18n:desktop.tags.mk-profile-setting.birthday%</p>
+		<p>%i18n:@birthday%</p>
 		<el-date-picker v-model="birthday" type="date" value-format="yyyy-MM-dd"/>
 	</label>
-	<button class="ui primary" @click="save">%i18n:desktop.tags.mk-profile-setting.save%</button>
+	<button class="ui primary" @click="save">%i18n:@save%</button>
 	<section>
 		<h2>その他</h2>
 		<mk-switch v-model="os.i.isBot" @change="onChangeIsBot" text="このアカウントはbotです"/>
diff --git a/src/client/app/desktop/views/components/settings.vue b/src/client/app/desktop/views/components/settings.vue
index 9d074165e5..335d780523 100644
--- a/src/client/app/desktop/views/components/settings.vue
+++ b/src/client/app/desktop/views/components/settings.vue
@@ -1,20 +1,20 @@
 <template>
 <div class="mk-settings">
 	<div class="nav">
-		<p :class="{ active: page == 'profile' }" @mousedown="page = 'profile'">%fa:user .fw%%i18n:desktop.tags.mk-settings.profile%</p>
+		<p :class="{ active: page == 'profile' }" @mousedown="page = 'profile'">%fa:user .fw%%i18n:@profile%</p>
 		<p :class="{ active: page == 'web' }" @mousedown="page = 'web'">%fa:desktop .fw%Web</p>
 		<p :class="{ active: page == 'notification' }" @mousedown="page = 'notification'">%fa:R bell .fw%通知</p>
-		<p :class="{ active: page == 'drive' }" @mousedown="page = 'drive'">%fa:cloud .fw%%i18n:desktop.tags.mk-settings.drive%</p>
-		<p :class="{ active: page == 'mute' }" @mousedown="page = 'mute'">%fa:ban .fw%%i18n:desktop.tags.mk-settings.mute%</p>
+		<p :class="{ active: page == 'drive' }" @mousedown="page = 'drive'">%fa:cloud .fw%%i18n:@drive%</p>
+		<p :class="{ active: page == 'mute' }" @mousedown="page = 'mute'">%fa:ban .fw%%i18n:@mute%</p>
 		<p :class="{ active: page == 'apps' }" @mousedown="page = 'apps'">%fa:puzzle-piece .fw%アプリ</p>
 		<p :class="{ active: page == 'twitter' }" @mousedown="page = 'twitter'">%fa:B twitter .fw%Twitter</p>
-		<p :class="{ active: page == 'security' }" @mousedown="page = 'security'">%fa:unlock-alt .fw%%i18n:desktop.tags.mk-settings.security%</p>
+		<p :class="{ active: page == 'security' }" @mousedown="page = 'security'">%fa:unlock-alt .fw%%i18n:@security%</p>
 		<p :class="{ active: page == 'api' }" @mousedown="page = 'api'">%fa:key .fw%API</p>
-		<p :class="{ active: page == 'other' }" @mousedown="page = 'other'">%fa:cogs .fw%%i18n:desktop.tags.mk-settings.other%</p>
+		<p :class="{ active: page == 'other' }" @mousedown="page = 'other'">%fa:cogs .fw%%i18n:@other%</p>
 	</div>
 	<div class="pages">
 		<section class="profile" v-show="page == 'profile'">
-			<h1>%i18n:desktop.tags.mk-settings.profile%</h1>
+			<h1>%i18n:@profile%</h1>
 			<x-profile/>
 		</section>
 
@@ -98,12 +98,12 @@
 		</section>
 
 		<section class="drive" v-show="page == 'drive'">
-			<h1>%i18n:desktop.tags.mk-settings.drive%</h1>
+			<h1>%i18n:@drive%</h1>
 			<x-drive/>
 		</section>
 
 		<section class="mute" v-show="page == 'mute'">
-			<h1>%i18n:desktop.tags.mk-settings.mute%</h1>
+			<h1>%i18n:@mute%</h1>
 			<x-mute/>
 		</section>
 
@@ -118,12 +118,12 @@
 		</section>
 
 		<section class="password" v-show="page == 'security'">
-			<h1>%i18n:desktop.tags.mk-settings.password%</h1>
+			<h1>%i18n:@password%</h1>
 			<x-password/>
 		</section>
 
 		<section class="2fa" v-show="page == 'security'">
-			<h1>%i18n:desktop.tags.mk-settings.2fa%</h1>
+			<h1>%i18n:@2fa%</h1>
 			<x-2fa/>
 		</section>
 
@@ -186,7 +186,7 @@
 		</section>
 
 		<section class="other" v-show="page == 'other'">
-			<h1>%i18n:desktop.tags.mk-settings.license%</h1>
+			<h1>%i18n:@license%</h1>
 			<div v-html="license"></div>
 			<a :href="licenseUrl" target="_blank">サードパーティ</a>
 		</section>
diff --git a/src/client/app/desktop/views/components/ui.header.account.vue b/src/client/app/desktop/views/components/ui.header.account.vue
index 61c3019294..5fd32a4cef 100644
--- a/src/client/app/desktop/views/components/ui.header.account.vue
+++ b/src/client/app/desktop/views/components/ui.header.account.vue
@@ -8,13 +8,13 @@
 		<div class="menu" v-if="isOpen">
 			<ul>
 				<li>
-					<router-link :to="`/@${ os.i.username }`">%fa:user%%i18n:desktop.tags.mk-ui-header-account.profile%%fa:angle-right%</router-link>
+					<router-link :to="`/@${ os.i.username }`">%fa:user%%i18n:@profile%%fa:angle-right%</router-link>
 				</li>
 				<li @click="drive">
-					<p>%fa:cloud%%i18n:desktop.tags.mk-ui-header-account.drive%%fa:angle-right%</p>
+					<p>%fa:cloud%%i18n:@drive%%fa:angle-right%</p>
 				</li>
 				<li>
-					<a href="/i/mentions">%fa:at%%i18n:desktop.tags.mk-ui-header-account.mentions%%fa:angle-right%</a>
+					<a href="/i/mentions">%fa:at%%i18n:@mentions%%fa:angle-right%</a>
 				</li>
 			</ul>
 			<ul>
@@ -22,12 +22,12 @@
 					<a href="/i/customize-home">%fa:wrench%カスタマイズ%fa:angle-right%</a>
 				</li>
 				<li @click="settings">
-					<p>%fa:cog%%i18n:desktop.tags.mk-ui-header-account.settings%%fa:angle-right%</p>
+					<p>%fa:cog%%i18n:@settings%%fa:angle-right%</p>
 				</li>
 			</ul>
 			<ul>
 				<li @click="signout">
-					<p>%fa:power-off%%i18n:desktop.tags.mk-ui-header-account.signout%%fa:angle-right%</p>
+					<p>%fa:power-off%%i18n:@signout%%fa:angle-right%</p>
 				</li>
 			</ul>
 		</div>
diff --git a/src/client/app/desktop/views/components/ui.header.nav.vue b/src/client/app/desktop/views/components/ui.header.nav.vue
index 5d7ae0a4e6..b4f83d8abf 100644
--- a/src/client/app/desktop/views/components/ui.header.nav.vue
+++ b/src/client/app/desktop/views/components/ui.header.nav.vue
@@ -5,13 +5,13 @@
 			<li class="home" :class="{ active: $route.name == 'index' }">
 				<router-link to="/">
 					%fa:home%
-					<p>%i18n:desktop.tags.mk-ui-header-nav.home%</p>
+					<p>%i18n:@home%</p>
 				</router-link>
 			</li>
 			<li class="messaging">
 				<a @click="messaging">
 					%fa:comments%
-					<p>%i18n:desktop.tags.mk-ui-header-nav.messaging%</p>
+					<p>%i18n:@messaging%</p>
 					<template v-if="hasUnreadMessagingMessages">%fa:circle%</template>
 				</a>
 			</li>
diff --git a/src/client/app/desktop/views/components/ui.header.notifications.vue b/src/client/app/desktop/views/components/ui.header.notifications.vue
index e829418d18..e9a6b9b04f 100644
--- a/src/client/app/desktop/views/components/ui.header.notifications.vue
+++ b/src/client/app/desktop/views/components/ui.header.notifications.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="notifications">
-	<button :data-active="isOpen" @click="toggle" title="%i18n:desktop.tags.mk-ui-header-notifications.title%">
+	<button :data-active="isOpen" @click="toggle" title="%i18n:@title%">
 		%fa:R bell%<template v-if="hasUnreadNotifications">%fa:circle%</template>
 	</button>
 	<div class="pop" v-if="isOpen">
diff --git a/src/client/app/desktop/views/components/ui.header.post.vue b/src/client/app/desktop/views/components/ui.header.post.vue
index 5c1756b756..01329c7c83 100644
--- a/src/client/app/desktop/views/components/ui.header.post.vue
+++ b/src/client/app/desktop/views/components/ui.header.post.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="note">
-	<button @click="post" title="%i18n:desktop.tags.mk-ui-header-note-button.note%">%fa:pencil-alt%</button>
+	<button @click="post" title="%i18n:@note%">%fa:pencil-alt%</button>
 </div>
 </template>
 
diff --git a/src/client/app/desktop/views/components/ui.header.search.vue b/src/client/app/desktop/views/components/ui.header.search.vue
index 86215556ad..3167aab8ab 100644
--- a/src/client/app/desktop/views/components/ui.header.search.vue
+++ b/src/client/app/desktop/views/components/ui.header.search.vue
@@ -1,7 +1,7 @@
 <template>
 <form class="search" @submit.prevent="onSubmit">
 	%fa:search%
-	<input v-model="q" type="search" placeholder="%i18n:desktop.tags.mk-ui-header-search.placeholder%"/>
+	<input v-model="q" type="search" placeholder="%i18n:@placeholder%"/>
 	<div class="result"></div>
 </form>
 </template>
diff --git a/src/client/app/desktop/views/pages/note.vue b/src/client/app/desktop/views/pages/note.vue
index 17c2b1e954..e92b0ff105 100644
--- a/src/client/app/desktop/views/pages/note.vue
+++ b/src/client/app/desktop/views/pages/note.vue
@@ -1,9 +1,9 @@
 <template>
 <mk-ui>
 	<main v-if="!fetching">
-		<a v-if="note.next" :href="note.next">%fa:angle-up%%i18n:desktop.tags.mk-note-page.next%</a>
+		<a v-if="note.next" :href="note.next">%fa:angle-up%%i18n:@next%</a>
 		<mk-note-detail :note="note"/>
-		<a v-if="note.prev" :href="note.prev">%fa:angle-down%%i18n:desktop.tags.mk-note-page.prev%</a>
+		<a v-if="note.prev" :href="note.prev">%fa:angle-down%%i18n:@prev%</a>
 	</main>
 </mk-ui>
 </template>
diff --git a/src/client/app/desktop/views/pages/selectdrive.vue b/src/client/app/desktop/views/pages/selectdrive.vue
index 4f0b86014b..c846f2418f 100644
--- a/src/client/app/desktop/views/pages/selectdrive.vue
+++ b/src/client/app/desktop/views/pages/selectdrive.vue
@@ -6,9 +6,9 @@
 		@change-selection="onChangeSelection"
 	/>
 	<footer>
-		<button class="upload" title="%i18n:desktop.tags.mk-selectdrive-page.upload%" @click="upload">%fa:upload%</button>
-		<button class="cancel" @click="close">%i18n:desktop.tags.mk-selectdrive-page.cancel%</button>
-		<button class="ok" @click="ok">%i18n:desktop.tags.mk-selectdrive-page.ok%</button>
+		<button class="upload" title="%i18n:@upload%" @click="upload">%fa:upload%</button>
+		<button class="cancel" @click="close">%i18n:@cancel%</button>
+		<button class="ok" @click="ok">%i18n:@ok%</button>
 	</footer>
 </div>
 </template>
@@ -29,7 +29,7 @@ export default Vue.extend({
 		}
 	},
 	mounted() {
-		document.title = '%i18n:desktop.tags.mk-selectdrive-page.title%';
+		document.title = '%i18n:@title%';
 	},
 	methods: {
 		onSelected(file) {
diff --git a/src/client/app/desktop/views/pages/user/user.followers-you-know.vue b/src/client/app/desktop/views/pages/user/user.followers-you-know.vue
index 4113ef13ab..e50f62d968 100644
--- a/src/client/app/desktop/views/pages/user/user.followers-you-know.vue
+++ b/src/client/app/desktop/views/pages/user/user.followers-you-know.vue
@@ -1,13 +1,13 @@
 <template>
 <div class="followers-you-know">
-	<p class="title">%fa:users%%i18n:desktop.tags.mk-user.followers-you-know.title%</p>
-	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:desktop.tags.mk-user.followers-you-know.loading%<mk-ellipsis/></p>
+	<p class="title">%fa:users%%i18n:@followers-you-know.title%</p>
+	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@followers-you-know.loading%<mk-ellipsis/></p>
 	<div v-if="!fetching && users.length > 0">
 	<router-link v-for="user in users" :to="user | userPage" :key="user.id">
 		<img :src="`${user.avatarUrl}?thumbnail&size=64`" :alt="user | userName" v-user-preview="user.id"/>
 	</router-link>
 	</div>
-	<p class="empty" v-if="!fetching && users.length == 0">%i18n:desktop.tags.mk-user.followers-you-know.no-users%</p>
+	<p class="empty" v-if="!fetching && users.length == 0">%i18n:@followers-you-know.no-users%</p>
 </div>
 </template>
 
diff --git a/src/client/app/desktop/views/pages/user/user.friends.vue b/src/client/app/desktop/views/pages/user/user.friends.vue
index 4b5ec88d52..12426a26c5 100644
--- a/src/client/app/desktop/views/pages/user/user.friends.vue
+++ b/src/client/app/desktop/views/pages/user/user.friends.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="friends">
-	<p class="title">%fa:users%%i18n:desktop.tags.mk-user.frequently-replied-users.title%</p>
-	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:desktop.tags.mk-user.frequently-replied-users.loading%<mk-ellipsis/></p>
+	<p class="title">%fa:users%%i18n:@frequently-replied-users.title%</p>
+	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@frequently-replied-users.loading%<mk-ellipsis/></p>
 	<template v-if="!fetching && users.length != 0">
 		<div class="user" v-for="friend in users">
 			<router-link class="avatar-anchor" :to="friend | userPage">
@@ -14,7 +14,7 @@
 			<mk-follow-button :user="friend"/>
 		</div>
 	</template>
-	<p class="empty" v-if="!fetching && users.length == 0">%i18n:desktop.tags.mk-user.frequently-replied-users.no-users%</p>
+	<p class="empty" v-if="!fetching && users.length == 0">%i18n:@frequently-replied-users.no-users%</p>
 </div>
 </template>
 
diff --git a/src/client/app/desktop/views/pages/user/user.home.vue b/src/client/app/desktop/views/pages/user/user.home.vue
index c254a320ce..7ca520ea7f 100644
--- a/src/client/app/desktop/views/pages/user/user.home.vue
+++ b/src/client/app/desktop/views/pages/user/user.home.vue
@@ -5,7 +5,7 @@
 			<x-profile :user="user"/>
 			<x-photos :user="user"/>
 			<x-followers-you-know v-if="os.isSignedIn && os.i.id != user.id" :user="user"/>
-			<p v-if="user.host === null">%i18n:desktop.tags.mk-user.last-used-at%: <b><mk-time :time="user.lastUsedAt"/></b></p>
+			<p v-if="user.host === null">%i18n:@last-used-at%: <b><mk-time :time="user.lastUsedAt"/></b></p>
 		</div>
 	</div>
 	<main>
diff --git a/src/client/app/desktop/views/pages/user/user.photos.vue b/src/client/app/desktop/views/pages/user/user.photos.vue
index 99a1a8d707..d1dfac9d7a 100644
--- a/src/client/app/desktop/views/pages/user/user.photos.vue
+++ b/src/client/app/desktop/views/pages/user/user.photos.vue
@@ -1,13 +1,13 @@
 <template>
 <div class="photos">
-	<p class="title">%fa:camera%%i18n:desktop.tags.mk-user.photos.title%</p>
-	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:desktop.tags.mk-user.photos.loading%<mk-ellipsis/></p>
+	<p class="title">%fa:camera%%i18n:@photos.title%</p>
+	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@photos.loading%<mk-ellipsis/></p>
 	<div class="stream" v-if="!fetching && images.length > 0">
 		<div v-for="image in images" class="img"
 			:style="`background-image: url(${image.url}?thumbnail&size=256)`"
 		></div>
 	</div>
-	<p class="empty" v-if="!fetching && images.length == 0">%i18n:desktop.tags.mk-user.photos.no-photos%</p>
+	<p class="empty" v-if="!fetching && images.length == 0">%i18n:@photos.no-photos%</p>
 </div>
 </template>
 
diff --git a/src/client/app/desktop/views/pages/user/user.profile.vue b/src/client/app/desktop/views/pages/user/user.profile.vue
index 44f20c2bc0..72750e1b3d 100644
--- a/src/client/app/desktop/views/pages/user/user.profile.vue
+++ b/src/client/app/desktop/views/pages/user/user.profile.vue
@@ -2,9 +2,9 @@
 <div class="profile">
 	<div class="friend-form" v-if="os.isSignedIn && os.i.id != user.id">
 		<mk-follow-button :user="user" size="big"/>
-		<p class="followed" v-if="user.isFollowed">%i18n:desktop.tags.mk-user.follows-you%</p>
-		<p v-if="user.isMuted">%i18n:desktop.tags.mk-user.muted% <a @click="unmute">%i18n:desktop.tags.mk-user.unmute%</a></p>
-		<p v-if="!user.isMuted"><a @click="mute">%i18n:desktop.tags.mk-user.mute%</a></p>
+		<p class="followed" v-if="user.isFollowed">%i18n:@follows-you%</p>
+		<p v-if="user.isMuted">%i18n:@muted% <a @click="unmute">%i18n:@unmute%</a></p>
+		<p v-if="!user.isMuted"><a @click="mute">%i18n:@mute%</a></p>
 	</div>
 	<div class="description" v-if="user.description">{{ user.description }}</div>
 	<div class="birthday" v-if="user.host === null && user.profile.birthday">
diff --git a/src/client/app/desktop/views/widgets/channel.vue b/src/client/app/desktop/views/widgets/channel.vue
index c9b62dfeab..975058b0e2 100644
--- a/src/client/app/desktop/views/widgets/channel.vue
+++ b/src/client/app/desktop/views/widgets/channel.vue
@@ -1,10 +1,10 @@
 <template>
 <div class="mkw-channel">
 	<template v-if="!props.compact">
-		<p class="title">%fa:tv%{{ channel ? channel.title : '%i18n:desktop.tags.mk-channel-home-widget.title%' }}</p>
-		<button @click="settings" title="%i18n:desktop.tags.mk-channel-home-widget.settings%">%fa:cog%</button>
+		<p class="title">%fa:tv%{{ channel ? channel.title : '%i18n:@title%' }}</p>
+		<button @click="settings" title="%i18n:@settings%">%fa:cog%</button>
 	</template>
-	<p class="get-started" v-if="props.channel == null">%i18n:desktop.tags.mk-channel-home-widget.get-started%</p>
+	<p class="get-started" v-if="props.channel == null">%i18n:@get-started%</p>
 	<x-channel class="channel" :channel="channel" v-if="channel != null"/>
 </div>
 </template>
diff --git a/src/client/app/desktop/views/widgets/messaging.vue b/src/client/app/desktop/views/widgets/messaging.vue
index 2c9f473bd1..0f197fb2d7 100644
--- a/src/client/app/desktop/views/widgets/messaging.vue
+++ b/src/client/app/desktop/views/widgets/messaging.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="mkw-messaging">
-	<p class="title" v-if="props.design == 0">%fa:comments%%i18n:desktop.tags.mk-messaging-home-widget.title%</p>
+	<p class="title" v-if="props.design == 0">%fa:comments%%i18n:@title%</p>
 	<mk-messaging ref="index" compact @navigate="navigate"/>
 </div>
 </template>
diff --git a/src/client/app/desktop/views/widgets/notifications.vue b/src/client/app/desktop/views/widgets/notifications.vue
index 1a2b3d3f89..0c2fa0434d 100644
--- a/src/client/app/desktop/views/widgets/notifications.vue
+++ b/src/client/app/desktop/views/widgets/notifications.vue
@@ -1,8 +1,8 @@
 <template>
 <div class="mkw-notifications">
 	<template v-if="!props.compact">
-		<p class="title">%fa:R bell%%i18n:desktop.tags.mk-notifications-home-widget.title%</p>
-		<button @click="settings" title="%i18n:desktop.tags.mk-notifications-home-widget.settings%">%fa:cog%</button>
+		<p class="title">%fa:R bell%%i18n:@title%</p>
+		<button @click="settings" title="%i18n:@settings%">%fa:cog%</button>
 	</template>
 	<mk-notifications/>
 </div>
diff --git a/src/client/app/desktop/views/widgets/polls.vue b/src/client/app/desktop/views/widgets/polls.vue
index 6ce980821a..6cb1192c24 100644
--- a/src/client/app/desktop/views/widgets/polls.vue
+++ b/src/client/app/desktop/views/widgets/polls.vue
@@ -1,15 +1,15 @@
 <template>
 <div class="mkw-polls">
 	<template v-if="!props.compact">
-		<p class="title">%fa:chart-pie%%i18n:desktop.tags.mk-recommended-polls-home-widget.title%</p>
-		<button @click="fetch" title="%i18n:desktop.tags.mk-recommended-polls-home-widget.refresh%">%fa:sync%</button>
+		<p class="title">%fa:chart-pie%%i18n:@title%</p>
+		<button @click="fetch" title="%i18n:@refresh%">%fa:sync%</button>
 	</template>
 	<div class="poll" v-if="!fetching && poll != null">
 		<p v-if="poll.text"><router-link to="poll | notePage">{{ poll.text }}</router-link></p>
 		<p v-if="!poll.text"><router-link to="poll | notePage">%fa:link%</router-link></p>
 		<mk-poll :note="poll"/>
 	</div>
-	<p class="empty" v-if="!fetching && poll == null">%i18n:desktop.tags.mk-recommended-polls-home-widget.nothing%</p>
+	<p class="empty" v-if="!fetching && poll == null">%i18n:@nothing%</p>
 	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
 </div>
 </template>
diff --git a/src/client/app/desktop/views/widgets/post-form.vue b/src/client/app/desktop/views/widgets/post-form.vue
index 5e59582a0f..627943588f 100644
--- a/src/client/app/desktop/views/widgets/post-form.vue
+++ b/src/client/app/desktop/views/widgets/post-form.vue
@@ -1,10 +1,10 @@
 <template>
 <div class="mkw-post-form">
 	<template v-if="props.design == 0">
-		<p class="title">%fa:pencil-alt%%i18n:desktop.tags.mk-post-form-home-widget.title%</p>
+		<p class="title">%fa:pencil-alt%%i18n:@title%</p>
 	</template>
-	<textarea :disabled="posting" v-model="text" @keydown="onKeydown" placeholder="%i18n:desktop.tags.mk-post-form-home-widget.placeholder%"></textarea>
-	<button @click="post" :disabled="posting">%i18n:desktop.tags.mk-post-form-home-widget.note%</button>
+	<textarea :disabled="posting" v-model="text" @keydown="onKeydown" placeholder="%i18n:@placeholder%"></textarea>
+	<button @click="post" :disabled="posting">%i18n:@note%</button>
 </div>
 </template>
 
diff --git a/src/client/app/desktop/views/widgets/trends.vue b/src/client/app/desktop/views/widgets/trends.vue
index 20e298730f..fccda3f9d0 100644
--- a/src/client/app/desktop/views/widgets/trends.vue
+++ b/src/client/app/desktop/views/widgets/trends.vue
@@ -1,15 +1,15 @@
 <template>
 <div class="mkw-trends">
 	<template v-if="!props.compact">
-		<p class="title">%fa:fire%%i18n:desktop.tags.mk-trends-home-widget.title%</p>
-		<button @click="fetch" title="%i18n:desktop.tags.mk-trends-home-widget.refresh%">%fa:sync%</button>
+		<p class="title">%fa:fire%%i18n:@title%</p>
+		<button @click="fetch" title="%i18n:@refresh%">%fa:sync%</button>
 	</template>
 	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
 	<div class="note" v-else-if="note != null">
 		<p class="text"><router-link :to="note | notePage">{{ note.text }}</router-link></p>
 		<p class="author">―<router-link :to="note.user | userPage">@{{ note.user | acct }}</router-link></p>
 	</div>
-	<p class="empty" v-else>%i18n:desktop.tags.mk-trends-home-widget.nothing%</p>
+	<p class="empty" v-else>%i18n:@nothing%</p>
 </div>
 </template>
 
diff --git a/src/client/app/desktop/views/widgets/users.vue b/src/client/app/desktop/views/widgets/users.vue
index c7075d9a57..0955ebbd71 100644
--- a/src/client/app/desktop/views/widgets/users.vue
+++ b/src/client/app/desktop/views/widgets/users.vue
@@ -1,8 +1,8 @@
 <template>
 <div class="mkw-users">
 	<template v-if="!props.compact">
-		<p class="title">%fa:users%%i18n:desktop.tags.mk-user-recommendation-home-widget.title%</p>
-		<button @click="refresh" title="%i18n:desktop.tags.mk-user-recommendation-home-widget.refresh%">%fa:sync%</button>
+		<p class="title">%fa:users%%i18n:@title%</p>
+		<button @click="refresh" title="%i18n:@refresh%">%fa:sync%</button>
 	</template>
 	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
 	<template v-else-if="users.length != 0">
@@ -17,7 +17,7 @@
 			<mk-follow-button :user="_user"/>
 		</div>
 	</template>
-	<p class="empty" v-else>%i18n:desktop.tags.mk-user-recommendation-home-widget.no-one%</p>
+	<p class="empty" v-else>%i18n:@no-one%</p>
 </div>
 </template>
 
diff --git a/src/client/app/mobile/views/components/drive-file-chooser.vue b/src/client/app/mobile/views/components/drive-file-chooser.vue
index 6806af0f1e..41536afbd4 100644
--- a/src/client/app/mobile/views/components/drive-file-chooser.vue
+++ b/src/client/app/mobile/views/components/drive-file-chooser.vue
@@ -2,7 +2,7 @@
 <div class="mk-drive-file-chooser">
 	<div class="body">
 		<header>
-			<h1>%i18n:mobile.tags.mk-drive-selector.select-file%<span class="count" v-if="files.length > 0">({{ files.length }})</span></h1>
+			<h1>%i18n:@select-file%<span class="count" v-if="files.length > 0">({{ files.length }})</span></h1>
 			<button class="close" @click="cancel">%fa:times%</button>
 			<button v-if="multiple" class="ok" @click="ok">%fa:check%</button>
 		</header>
diff --git a/src/client/app/mobile/views/components/drive-folder-chooser.vue b/src/client/app/mobile/views/components/drive-folder-chooser.vue
index 853078664f..bfd8fbda6f 100644
--- a/src/client/app/mobile/views/components/drive-folder-chooser.vue
+++ b/src/client/app/mobile/views/components/drive-folder-chooser.vue
@@ -2,7 +2,7 @@
 <div class="mk-drive-folder-chooser">
 	<div class="body">
 		<header>
-			<h1>%i18n:mobile.tags.mk-drive-folder-selector.select-folder%</h1>
+			<h1>%i18n:@select-folder%</h1>
 			<button class="close" @click="cancel">%fa:times%</button>
 			<button class="ok" @click="ok">%fa:check%</button>
 		</header>
diff --git a/src/client/app/mobile/views/components/drive.file-detail.vue b/src/client/app/mobile/views/components/drive.file-detail.vue
index f3274f677f..c7be7d1879 100644
--- a/src/client/app/mobile/views/components/drive.file-detail.vue
+++ b/src/client/app/mobile/views/components/drive.file-detail.vue
@@ -35,20 +35,20 @@
 	<div class="menu">
 		<div>
 			<a :href="`${file.url}?download`" :download="file.name">
-				%fa:download%%i18n:mobile.tags.mk-drive-file-viewer.download%
+				%fa:download%%i18n:@download%
 			</a>
 			<button @click="rename">
-				%fa:pencil-alt%%i18n:mobile.tags.mk-drive-file-viewer.rename%
+				%fa:pencil-alt%%i18n:@rename%
 			</button>
 			<button @click="move">
-				%fa:R folder-open%%i18n:mobile.tags.mk-drive-file-viewer.move%
+				%fa:R folder-open%%i18n:@move%
 			</button>
 		</div>
 	</div>
 	<div class="exif" v-show="exif">
 		<div>
 			<p>
-				%fa:camera%%i18n:mobile.tags.mk-drive-file-viewer.exif%
+				%fa:camera%%i18n:@exif%
 			</p>
 			<pre ref="exif" class="json">{{ exif ? JSON.stringify(exif, null, 2) : '' }}</pre>
 		</div>
@@ -56,7 +56,7 @@
 	<div class="hash">
 		<div>
 			<p>
-				%fa:hashtag%%i18n:mobile.tags.mk-drive-file-viewer.hash%
+				%fa:hashtag%%i18n:@hash%
 			</p>
 			<code>{{ file.md5 }}</code>
 		</div>
diff --git a/src/client/app/mobile/views/components/drive.vue b/src/client/app/mobile/views/components/drive.vue
index ff5366a0ad..ec1b983d0b 100644
--- a/src/client/app/mobile/views/components/drive.vue
+++ b/src/client/app/mobile/views/components/drive.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="mk-drive">
 	<nav ref="nav">
-		<a @click.prevent="goRoot()" href="/i/drive">%fa:cloud%%i18n:mobile.tags.mk-drive.drive%</a>
+		<a @click.prevent="goRoot()" href="/i/drive">%fa:cloud%%i18n:@drive%</a>
 		<template v-for="folder in hierarchyFolders">
 			<span :key="folder.id + '>'">%fa:angle-right%</span>
 			<a :key="folder.id" @click.prevent="cd(folder)" :href="`/i/drive/folder/${folder.id}`">{{ folder.name }}</a>
@@ -18,26 +18,26 @@
 	<mk-uploader ref="uploader"/>
 	<div class="browser" :class="{ fetching }" v-if="file == null">
 		<div class="info" v-if="info">
-			<p v-if="folder == null">{{ (info.usage / info.capacity * 100).toFixed(1) }}% %i18n:mobile.tags.mk-drive.used%</p>
+			<p v-if="folder == null">{{ (info.usage / info.capacity * 100).toFixed(1) }}% %i18n:@used%</p>
 			<p v-if="folder != null && (folder.foldersCount > 0 || folder.filesCount > 0)">
-				<template v-if="folder.foldersCount > 0">{{ folder.foldersCount }} %i18n:mobile.tags.mk-drive.folder-count%</template>
-				<template v-if="folder.foldersCount > 0 && folder.filesCount > 0">%i18n:mobile.tags.mk-drive.count-separator%</template>
-				<template v-if="folder.filesCount > 0">{{ folder.filesCount }} %i18n:mobile.tags.mk-drive.file-count%</template>
+				<template v-if="folder.foldersCount > 0">{{ folder.foldersCount }} %i18n:@folder-count%</template>
+				<template v-if="folder.foldersCount > 0 && folder.filesCount > 0">%i18n:@count-separator%</template>
+				<template v-if="folder.filesCount > 0">{{ folder.filesCount }} %i18n:@file-count%</template>
 			</p>
 		</div>
 		<div class="folders" v-if="folders.length > 0">
 			<x-folder v-for="folder in folders" :key="folder.id" :folder="folder"/>
-			<p v-if="moreFolders">%i18n:mobile.tags.mk-drive.load-more%</p>
+			<p v-if="moreFolders">%i18n:@load-more%</p>
 		</div>
 		<div class="files" v-if="files.length > 0">
 			<x-file v-for="file in files" :key="file.id" :file="file"/>
 			<button class="more" v-if="moreFiles" @click="fetchMoreFiles">
-				{{ fetchingMoreFiles ? '%i18n:common.loading%' : '%i18n:mobile.tags.mk-drive.load-more%' }}
+				{{ fetchingMoreFiles ? '%i18n:common.loading%' : '%i18n:@load-more%' }}
 			</button>
 		</div>
 		<div class="empty" v-if="files.length == 0 && folders.length == 0 && !fetching">
-			<p v-if="folder == null">%i18n:mobile.tags.mk-drive.nothing-in-drive%</p>
-			<p v-if="folder != null">%i18n:mobile.tags.mk-drive.folder-is-empty%</p>
+			<p v-if="folder == null">%i18n:@nothing-in-drive%</p>
+			<p v-if="folder != null">%i18n:@folder-is-empty%</p>
 		</div>
 	</div>
 	<div class="fetching" v-if="fetching && file == null && files.length == 0 && folders.length == 0">
diff --git a/src/client/app/mobile/views/components/follow-button.vue b/src/client/app/mobile/views/components/follow-button.vue
index 43c69d4e02..a6b5cf0556 100644
--- a/src/client/app/mobile/views/components/follow-button.vue
+++ b/src/client/app/mobile/views/components/follow-button.vue
@@ -7,7 +7,7 @@
 	<template v-if="!wait && user.isFollowing">%fa:minus%</template>
 	<template v-if="!wait && !user.isFollowing">%fa:plus%</template>
 	<template v-if="wait">%fa:spinner .pulse .fw%</template>
-	{{ user.isFollowing ? '%i18n:mobile.tags.mk-follow-button.unfollow%' : '%i18n:mobile.tags.mk-follow-button.follow%' }}
+	{{ user.isFollowing ? '%i18n:@unfollow%' : '%i18n:@follow%' }}
 </button>
 </template>
 
diff --git a/src/client/app/mobile/views/components/note-detail.vue b/src/client/app/mobile/views/components/note-detail.vue
index 63e28b7f54..c29e46e454 100644
--- a/src/client/app/mobile/views/components/note-detail.vue
+++ b/src/client/app/mobile/views/components/note-detail.vue
@@ -54,13 +54,13 @@
 		</router-link>
 		<footer>
 			<mk-reactions-viewer :note="p"/>
-			<button @click="reply" title="%i18n:mobile.tags.mk-note-detail.reply%">
+			<button @click="reply" title="%i18n:@reply%">
 				%fa:reply%<p class="count" v-if="p.repliesCount > 0">{{ p.repliesCount }}</p>
 			</button>
 			<button @click="renote" title="Renote">
 				%fa:retweet%<p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p>
 			</button>
-			<button :class="{ reacted: p.myReaction != null }" @click="react" ref="reactButton" title="%i18n:mobile.tags.mk-note-detail.reaction%">
+			<button :class="{ reacted: p.myReaction != null }" @click="react" ref="reactButton" title="%i18n:@reaction%">
 				%fa:plus%<p class="count" v-if="p.reactions_count > 0">{{ p.reactions_count }}</p>
 			</button>
 			<button @click="menu" ref="menuButton">
diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue
index 033de4f429..cde8b6c2ce 100644
--- a/src/client/app/mobile/views/components/note.vue
+++ b/src/client/app/mobile/views/components/note.vue
@@ -9,9 +9,9 @@
 				<img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/>
 			</router-link>
 			%fa:retweet%
-			<span>{{ '%i18n:mobile.tags.mk-timeline-note.reposted-by%'.substr(0, '%i18n:mobile.tags.mk-timeline-note.reposted-by%'.indexOf('{')) }}</span>
+			<span>{{ '%i18n:@reposted-by%'.substr(0, '%i18n:@reposted-by%'.indexOf('{')) }}</span>
 			<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link>
-			<span>{{ '%i18n:mobile.tags.mk-timeline-note.reposted-by%'.substr('%i18n:mobile.tags.mk-timeline-note.reposted-by%'.indexOf('}') + 1) }}</span>
+			<span>{{ '%i18n:@reposted-by%'.substr('%i18n:@reposted-by%'.indexOf('}') + 1) }}</span>
 		</p>
 		<mk-time :time="note.createdAt"/>
 	</div>
diff --git a/src/client/app/mobile/views/components/notifications.vue b/src/client/app/mobile/views/components/notifications.vue
index d68b990dfa..231ce2c1be 100644
--- a/src/client/app/mobile/views/components/notifications.vue
+++ b/src/client/app/mobile/views/components/notifications.vue
@@ -11,9 +11,9 @@
 	</div>
 	<button class="more" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications">
 		<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>
-		{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:mobile.tags.mk-notifications.more%' }}
+		{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }}
 	</button>
-	<p class="empty" v-if="notifications.length == 0 && !fetching">%i18n:mobile.tags.mk-notifications.empty%</p>
+	<p class="empty" v-if="notifications.length == 0 && !fetching">%i18n:@empty%</p>
 	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
 </div>
 </template>
diff --git a/src/client/app/mobile/views/components/post-form.vue b/src/client/app/mobile/views/components/post-form.vue
index 70be6db7b2..4b038fd2b6 100644
--- a/src/client/app/mobile/views/components/post-form.vue
+++ b/src/client/app/mobile/views/components/post-form.vue
@@ -5,12 +5,12 @@
 		<div>
 			<span class="text-count" :class="{ over: text.length > 1000 }">{{ 1000 - text.length }}</span>
 			<span class="geo" v-if="geo">%fa:map-marker-alt%</span>
-			<button class="submit" :disabled="posting" @click="post">{{ reply ? '返信' : '%i18n:mobile.tags.mk-post-form.submit%' }}</button>
+			<button class="submit" :disabled="posting" @click="post">{{ reply ? '返信' : '%i18n:@submit%' }}</button>
 		</div>
 	</header>
 	<div class="form">
 		<mk-note-preview v-if="reply" :note="reply"/>
-		<textarea v-model="text" ref="text" :disabled="posting" :placeholder="reply ? '%i18n:mobile.tags.mk-post-form.reply-placeholder%' : '%i18n:mobile.tags.mk-post-form.note-placeholder%'"></textarea>
+		<textarea v-model="text" ref="text" :disabled="posting" :placeholder="reply ? '%i18n:@reply-placeholder%' : '%i18n:@note-placeholder%'"></textarea>
 		<div class="attaches" v-show="files.length != 0">
 			<x-draggable class="files" :list="files" :options="{ animation: 150 }">
 				<div class="file" v-for="file in files" :key="file.id">
diff --git a/src/client/app/mobile/views/components/sub-note-content.vue b/src/client/app/mobile/views/components/sub-note-content.vue
index 22e6ebe3f1..54cc74f7f5 100644
--- a/src/client/app/mobile/views/components/sub-note-content.vue
+++ b/src/client/app/mobile/views/components/sub-note-content.vue
@@ -10,7 +10,7 @@
 		<mk-media-list :media-list="note.media"/>
 	</details>
 	<details v-if="note.poll">
-		<summary>%i18n:mobile.tags.mk-sub-note-content.poll%</summary>
+		<summary>%i18n:@poll%</summary>
 		<mk-poll :note="note"/>
 	</details>
 </div>
diff --git a/src/client/app/mobile/views/components/timeline.vue b/src/client/app/mobile/views/components/timeline.vue
index 4d6abcd167..6bc12096cd 100644
--- a/src/client/app/mobile/views/components/timeline.vue
+++ b/src/client/app/mobile/views/components/timeline.vue
@@ -7,10 +7,10 @@
 		</div>
 		<div class="empty" v-if="!fetching && notes.length == 0">
 			%fa:R comments%
-			%i18n:mobile.tags.mk-home-timeline.empty-timeline%
+			%i18n:@empty-timeline%
 		</div>
 		<button v-if="!fetching && existMore" @click="more" :disabled="moreFetching" slot="tail">
-			<span v-if="!moreFetching">%i18n:mobile.tags.mk-timeline.load-more%</span>
+			<span v-if="!moreFetching">%i18n:@load-more%</span>
 			<span v-if="moreFetching">%i18n:common.loading%<mk-ellipsis/></span>
 		</button>
 	</mk-notes>
diff --git a/src/client/app/mobile/views/components/ui.nav.vue b/src/client/app/mobile/views/components/ui.nav.vue
index f96e285407..2bab5fc7b1 100644
--- a/src/client/app/mobile/views/components/ui.nav.vue
+++ b/src/client/app/mobile/views/components/ui.nav.vue
@@ -15,22 +15,22 @@
 			</router-link>
 			<div class="links">
 				<ul>
-					<li><router-link to="/">%fa:home%%i18n:mobile.tags.mk-ui-nav.home%%fa:angle-right%</router-link></li>
-					<li><router-link to="/i/notifications">%fa:R bell%%i18n:mobile.tags.mk-ui-nav.notifications%<template v-if="hasUnreadNotifications">%fa:circle%</template>%fa:angle-right%</router-link></li>
-					<li><router-link to="/i/messaging">%fa:R comments%%i18n:mobile.tags.mk-ui-nav.messaging%<template v-if="hasUnreadMessagingMessages">%fa:circle%</template>%fa:angle-right%</router-link></li>
+					<li><router-link to="/">%fa:home%%i18n:@home%%fa:angle-right%</router-link></li>
+					<li><router-link to="/i/notifications">%fa:R bell%%i18n:@notifications%<template v-if="hasUnreadNotifications">%fa:circle%</template>%fa:angle-right%</router-link></li>
+					<li><router-link to="/i/messaging">%fa:R comments%%i18n:@messaging%<template v-if="hasUnreadMessagingMessages">%fa:circle%</template>%fa:angle-right%</router-link></li>
 					<li><router-link to="/othello">%fa:gamepad%ゲーム<template v-if="hasGameInvitations">%fa:circle%</template>%fa:angle-right%</router-link></li>
 				</ul>
 				<ul>
-					<li><router-link to="/i/drive">%fa:cloud%%i18n:mobile.tags.mk-ui-nav.drive%%fa:angle-right%</router-link></li>
+					<li><router-link to="/i/drive">%fa:cloud%%i18n:@drive%%fa:angle-right%</router-link></li>
 				</ul>
 				<ul>
-					<li><a @click="search">%fa:search%%i18n:mobile.tags.mk-ui-nav.search%%fa:angle-right%</a></li>
+					<li><a @click="search">%fa:search%%i18n:@search%%fa:angle-right%</a></li>
 				</ul>
 				<ul>
-					<li><router-link to="/i/settings">%fa:cog%%i18n:mobile.tags.mk-ui-nav.settings%%fa:angle-right%</router-link></li>
+					<li><router-link to="/i/settings">%fa:cog%%i18n:@settings%%fa:angle-right%</router-link></li>
 				</ul>
 			</div>
-			<a :href="aboutUrl"><p class="about">%i18n:mobile.tags.mk-ui-nav.about%</p></a>
+			<a :href="aboutUrl"><p class="about">%i18n:@about%</p></a>
 		</div>
 	</transition>
 </div>
@@ -92,7 +92,7 @@ export default Vue.extend({
 	},
 	methods: {
 		search() {
-			const query = window.prompt('%i18n:mobile.tags.mk-ui-nav.search%');
+			const query = window.prompt('%i18n:@search%');
 			if (query == null || query == '') return;
 			this.$router.push('/search?q=' + encodeURIComponent(query));
 		},
diff --git a/src/client/app/mobile/views/components/user-timeline.vue b/src/client/app/mobile/views/components/user-timeline.vue
index 7a04441f76..7cca6a55ac 100644
--- a/src/client/app/mobile/views/components/user-timeline.vue
+++ b/src/client/app/mobile/views/components/user-timeline.vue
@@ -6,10 +6,10 @@
 		</div>
 		<div class="empty" v-if="!fetching && notes.length == 0">
 			%fa:R comments%
-			{{ withMedia ? '%i18n:mobile.tags.mk-user-timeline.no-notes-with-media%' : '%i18n:mobile.tags.mk-user-timeline.no-notes%' }}
+			{{ withMedia ? '%i18n:@no-notes-with-media%' : '%i18n:@no-notes%' }}
 		</div>
 		<button v-if="!fetching && existMore" @click="more" :disabled="moreFetching" slot="tail">
-			<span v-if="!moreFetching">%i18n:mobile.tags.mk-user-timeline.load-more%</span>
+			<span v-if="!moreFetching">%i18n:@load-more%</span>
 			<span v-if="moreFetching">%i18n:common.loading%<mk-ellipsis/></span>
 		</button>
 	</mk-notes>
diff --git a/src/client/app/mobile/views/components/users-list.vue b/src/client/app/mobile/views/components/users-list.vue
index b11e4549d6..8fa7a9cbe6 100644
--- a/src/client/app/mobile/views/components/users-list.vue
+++ b/src/client/app/mobile/views/components/users-list.vue
@@ -1,14 +1,14 @@
 <template>
 <div class="mk-users-list">
 	<nav>
-		<span :data-is-active="mode == 'all'" @click="mode = 'all'">%i18n:mobile.tags.mk-users-list.all%<span>{{ count }}</span></span>
-		<span v-if="os.isSignedIn && youKnowCount" :data-is-active="mode == 'iknow'" @click="mode = 'iknow'">%i18n:mobile.tags.mk-users-list.known%<span>{{ youKnowCount }}</span></span>
+		<span :data-is-active="mode == 'all'" @click="mode = 'all'">%i18n:@all%<span>{{ count }}</span></span>
+		<span v-if="os.isSignedIn && youKnowCount" :data-is-active="mode == 'iknow'" @click="mode = 'iknow'">%i18n:@known%<span>{{ youKnowCount }}</span></span>
 	</nav>
 	<div class="users" v-if="!fetching && users.length != 0">
 		<mk-user-preview v-for="u in users" :user="u" :key="u.id"/>
 	</div>
 	<button class="more" v-if="!fetching && next != null" @click="more" :disabled="moreFetching">
-		<span v-if="!moreFetching">%i18n:mobile.tags.mk-users-list.load-more%</span>
+		<span v-if="!moreFetching">%i18n:@load-more%</span>
 		<span v-if="moreFetching">%i18n:common.loading%<mk-ellipsis/></span>
 	</button>
 	<p class="no" v-if="!fetching && users.length == 0">
diff --git a/src/client/app/mobile/views/pages/drive.vue b/src/client/app/mobile/views/pages/drive.vue
index 200379f222..2cf3f510a2 100644
--- a/src/client/app/mobile/views/pages/drive.vue
+++ b/src/client/app/mobile/views/pages/drive.vue
@@ -3,7 +3,7 @@
 	<span slot="header">
 		<template v-if="folder">%fa:R folder-open%{{ folder.name }}</template>
 		<template v-if="file"><mk-file-type-icon data-icon :type="file.type"/>{{ file.name }}</template>
-		<template v-if="!folder && !file">%fa:cloud%%i18n:mobile.tags.mk-drive-page.drive%</template>
+		<template v-if="!folder && !file">%fa:cloud%%i18n:@drive%</template>
 	</span>
 	<template slot="func"><button @click="fn">%fa:ellipsis-h%</button></template>
 	<mk-drive
diff --git a/src/client/app/mobile/views/pages/followers.vue b/src/client/app/mobile/views/pages/followers.vue
index f4225d556d..b1543b7cda 100644
--- a/src/client/app/mobile/views/pages/followers.vue
+++ b/src/client/app/mobile/views/pages/followers.vue
@@ -2,7 +2,7 @@
 <mk-ui>
 	<template slot="header" v-if="!fetching">
 		<img :src="`${user.avatarUrl}?thumbnail&size=64`" alt="">
-		{{ '%i18n:mobile.tags.mk-user-followers-page.followers-of%'.replace('{}', name) }}
+		{{ '%i18n:@followers-of%'.replace('{}', name) }}
 	</template>
 	<mk-users-list
 		v-if="!fetching"
@@ -11,7 +11,7 @@
 		:you-know-count="user.followersYouKnowCount"
 		@loaded="onLoaded"
 	>
-		%i18n:mobile.tags.mk-user-followers.no-users%
+		%i18n:@no-users%
 	</mk-users-list>
 </mk-ui>
 </template>
@@ -52,7 +52,7 @@ export default Vue.extend({
 				this.user = user;
 				this.fetching = false;
 
-				document.title = '%i18n:mobile.tags.mk-user-followers-page.followers-of%'.replace('{}', this.name) + ' | Misskey';
+				document.title = '%i18n:@followers-of%'.replace('{}', this.name) + ' | Misskey';
 			});
 		},
 		onLoaded() {
diff --git a/src/client/app/mobile/views/pages/following.vue b/src/client/app/mobile/views/pages/following.vue
index d0dcc117c2..8dbdd5dba4 100644
--- a/src/client/app/mobile/views/pages/following.vue
+++ b/src/client/app/mobile/views/pages/following.vue
@@ -2,7 +2,7 @@
 <mk-ui>
 	<template slot="header" v-if="!fetching">
 		<img :src="`${user.avatarUrl}?thumbnail&size=64`" alt="">
-		{{ '%i18n:mobile.tags.mk-user-following-page.following-of%'.replace('{}', name) }}
+		{{ '%i18n:@following-of%'.replace('{}', name) }}
 	</template>
 	<mk-users-list
 		v-if="!fetching"
@@ -11,7 +11,7 @@
 		:you-know-count="user.followingYouKnowCount"
 		@loaded="onLoaded"
 	>
-		%i18n:mobile.tags.mk-user-following.no-users%
+		%i18n:@no-users%
 	</mk-users-list>
 </mk-ui>
 </template>
@@ -51,7 +51,7 @@ export default Vue.extend({
 				this.user = user;
 				this.fetching = false;
 
-				document.title = '%i18n:mobile.tags.mk-user-followers-page.followers-of%'.replace('{}', this.name) + ' | Misskey';
+				document.title = '%i18n:@followers-of%'.replace('{}', this.name) + ' | Misskey';
 			});
 		},
 		onLoaded() {
diff --git a/src/client/app/mobile/views/pages/messaging-room.vue b/src/client/app/mobile/views/pages/messaging-room.vue
index 3b6fb11db5..d436960f2c 100644
--- a/src/client/app/mobile/views/pages/messaging-room.vue
+++ b/src/client/app/mobile/views/pages/messaging-room.vue
@@ -33,7 +33,7 @@ export default Vue.extend({
 				this.user = user;
 				this.fetching = false;
 
-				document.title = `%i18n:mobile.tags.mk-messaging-room-page.message%: ${Vue.filter('userName')(this.user)} | Misskey`;
+				document.title = `%i18n:@message%: ${Vue.filter('userName')(this.user)} | Misskey`;
 			});
 		}
 	}
diff --git a/src/client/app/mobile/views/pages/messaging.vue b/src/client/app/mobile/views/pages/messaging.vue
index fa735a2530..b52df7d3cf 100644
--- a/src/client/app/mobile/views/pages/messaging.vue
+++ b/src/client/app/mobile/views/pages/messaging.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-ui>
-	<span slot="header">%fa:R comments%%i18n:mobile.tags.mk-messaging-page.message%</span>
+	<span slot="header">%fa:R comments%%i18n:@message%</span>
 	<mk-messaging @navigate="navigate" :header-top="48"/>
 </mk-ui>
 </template>
@@ -11,7 +11,7 @@ import getAcct from '../../../../../acct/render';
 
 export default Vue.extend({
 	mounted() {
-		document.title = 'Misskey %i18n:mobile.tags.mk-messaging-page.message%';
+		document.title = 'Misskey %i18n:@message%';
 		document.documentElement.style.background = '#fff';
 	},
 	methods: {
diff --git a/src/client/app/mobile/views/pages/note.vue b/src/client/app/mobile/views/pages/note.vue
index 89b8c776f2..c866be8a14 100644
--- a/src/client/app/mobile/views/pages/note.vue
+++ b/src/client/app/mobile/views/pages/note.vue
@@ -1,12 +1,12 @@
 <template>
 <mk-ui>
-	<span slot="header">%fa:R sticky-note%%i18n:mobile.tags.mk-note-page.title%</span>
+	<span slot="header">%fa:R sticky-note%%i18n:@title%</span>
 	<main v-if="!fetching">
-		<a v-if="note.next" :href="note.next">%fa:angle-up%%i18n:mobile.tags.mk-note-page.next%</a>
+		<a v-if="note.next" :href="note.next">%fa:angle-up%%i18n:@next%</a>
 		<div>
 			<mk-note-detail :note="note"/>
 		</div>
-		<a v-if="note.prev" :href="note.prev">%fa:angle-down%%i18n:mobile.tags.mk-note-page.prev%</a>
+		<a v-if="note.prev" :href="note.prev">%fa:angle-down%%i18n:@prev%</a>
 	</main>
 </mk-ui>
 </template>
diff --git a/src/client/app/mobile/views/pages/notifications.vue b/src/client/app/mobile/views/pages/notifications.vue
index 6d45e22a9c..5ae94590cc 100644
--- a/src/client/app/mobile/views/pages/notifications.vue
+++ b/src/client/app/mobile/views/pages/notifications.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-ui>
-	<span slot="header">%fa:R bell%%i18n:mobile.tags.mk-notifications-page.notifications%</span>
+	<span slot="header">%fa:R bell%%i18n:@notifications%</span>
 	<template slot="func"><button @click="fn">%fa:check%</button></template>
 	<mk-notifications @fetched="onFetched"/>
 </mk-ui>
@@ -12,14 +12,14 @@ import Progress from '../../../common/scripts/loading';
 
 export default Vue.extend({
 	mounted() {
-		document.title = 'Misskey | %i18n:mobile.tags.mk-notifications-page.notifications%';
+		document.title = 'Misskey | %i18n:@notifications%';
 		document.documentElement.style.background = '#313a42';
 
 		Progress.start();
 	},
 	methods: {
 		fn() {
-			const ok = window.confirm('%i18n:mobile.tags.mk-notifications-page.read-all%');
+			const ok = window.confirm('%i18n:@read-all%');
 			if (!ok) return;
 
 			(this as any).api('notifications/markAsRead_all');
diff --git a/src/client/app/mobile/views/pages/profile-setting.vue b/src/client/app/mobile/views/pages/profile-setting.vue
index 7f0ff5aad7..846be59951 100644
--- a/src/client/app/mobile/views/pages/profile-setting.vue
+++ b/src/client/app/mobile/views/pages/profile-setting.vue
@@ -1,38 +1,38 @@
 <template>
 <mk-ui>
-	<span slot="header">%fa:user%%i18n:mobile.tags.mk-profile-setting-page.title%</span>
+	<span slot="header">%fa:user%%i18n:@title%</span>
 	<div :class="$style.content">
-		<p>%fa:info-circle%%i18n:mobile.tags.mk-profile-setting.will-be-published%</p>
+		<p>%fa:info-circle%%i18n:@will-be-published%</p>
 		<div :class="$style.form">
 			<div :style="os.i.bannerUrl ? `background-image: url(${os.i.bannerUrl}?thumbnail&size=1024)` : ''" @click="setBanner">
 				<img :src="`${os.i.avatarUrl}?thumbnail&size=200`" alt="avatar" @click="setAvatar"/>
 			</div>
 			<label>
-				<p>%i18n:mobile.tags.mk-profile-setting.name%</p>
+				<p>%i18n:@name%</p>
 				<input v-model="name" type="text"/>
 			</label>
 			<label>
-				<p>%i18n:mobile.tags.mk-profile-setting.location%</p>
+				<p>%i18n:@location%</p>
 				<input v-model="location" type="text"/>
 			</label>
 			<label>
-				<p>%i18n:mobile.tags.mk-profile-setting.description%</p>
+				<p>%i18n:@description%</p>
 				<textarea v-model="description"></textarea>
 			</label>
 			<label>
-				<p>%i18n:mobile.tags.mk-profile-setting.birthday%</p>
+				<p>%i18n:@birthday%</p>
 				<input v-model="birthday" type="date"/>
 			</label>
 			<label>
-				<p>%i18n:mobile.tags.mk-profile-setting.avatar%</p>
-				<button @click="setAvatar" :disabled="avatarSaving">%i18n:mobile.tags.mk-profile-setting.set-avatar%</button>
+				<p>%i18n:@avatar%</p>
+				<button @click="setAvatar" :disabled="avatarSaving">%i18n:@set-avatar%</button>
 			</label>
 			<label>
-				<p>%i18n:mobile.tags.mk-profile-setting.banner%</p>
-				<button @click="setBanner" :disabled="bannerSaving">%i18n:mobile.tags.mk-profile-setting.set-banner%</button>
+				<p>%i18n:@banner%</p>
+				<button @click="setBanner" :disabled="bannerSaving">%i18n:@set-banner%</button>
 			</label>
 		</div>
-		<button :class="$style.save" @click="save" :disabled="saving">%fa:check%%i18n:mobile.tags.mk-profile-setting.save%</button>
+		<button :class="$style.save" @click="save" :disabled="saving">%fa:check%%i18n:@save%</button>
 	</div>
 </mk-ui>
 </template>
@@ -58,7 +58,7 @@ export default Vue.extend({
 		this.birthday = (this as any).os.i.profile.birthday;
 	},
 	mounted() {
-		document.title = 'Misskey | %i18n:mobile.tags.mk-profile-setting-page.title%';
+		document.title = 'Misskey | %i18n:@title%';
 		document.documentElement.style.background = '#313a42';
 	},
 	methods: {
@@ -72,7 +72,7 @@ export default Vue.extend({
 					avatarId: file.id
 				}).then(() => {
 					this.avatarSaving = false;
-					alert('%i18n:mobile.tags.mk-profile-setting.avatar-saved%');
+					alert('%i18n:@avatar-saved%');
 				});
 			});
 		},
@@ -86,7 +86,7 @@ export default Vue.extend({
 					bannerId: file.id
 				}).then(() => {
 					this.bannerSaving = false;
-					alert('%i18n:mobile.tags.mk-profile-setting.banner-saved%');
+					alert('%i18n:@banner-saved%');
 				});
 			});
 		},
@@ -100,7 +100,7 @@ export default Vue.extend({
 				birthday: this.birthday || null
 			}).then(() => {
 				this.saving = false;
-				alert('%i18n:mobile.tags.mk-profile-setting.saved%');
+				alert('%i18n:@saved%');
 			});
 		}
 	}
diff --git a/src/client/app/mobile/views/pages/search.vue b/src/client/app/mobile/views/pages/search.vue
index a96832beec..2ea2c73384 100644
--- a/src/client/app/mobile/views/pages/search.vue
+++ b/src/client/app/mobile/views/pages/search.vue
@@ -3,9 +3,9 @@
 	<span slot="header">%fa:search% {{ q }}</span>
 	<main v-if="!fetching">
 		<mk-notes :class="$style.notes" :notes="notes">
-			<span v-if="notes.length == 0">{{ '%i18n:mobile.tags.mk-search-notes.empty%'.replace('{}', q) }}</span>
+			<span v-if="notes.length == 0">{{ '%i18n:@empty%'.replace('{}', q) }}</span>
 			<button v-if="existMore" @click="more" :disabled="fetching" slot="tail">
-				<span v-if="!fetching">%i18n:mobile.tags.mk-timeline.load-more%</span>
+				<span v-if="!fetching">%i18n:@load-more%</span>
 				<span v-if="fetching">%i18n:common.loading%<mk-ellipsis/></span>
 			</button>
 		</mk-notes>
@@ -38,7 +38,7 @@ export default Vue.extend({
 		}
 	},
 	mounted() {
-		document.title = `%i18n:mobile.tags.mk-search-page.search%: ${this.q} | Misskey`;
+		document.title = `%i18n:@search%: ${this.q} | Misskey`;
 		document.documentElement.style.background = '#313a42';
 
 		this.fetch();
diff --git a/src/client/app/mobile/views/pages/selectdrive.vue b/src/client/app/mobile/views/pages/selectdrive.vue
index 3480a0d103..e8e256cae8 100644
--- a/src/client/app/mobile/views/pages/selectdrive.vue
+++ b/src/client/app/mobile/views/pages/selectdrive.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="mk-selectdrive">
 	<header>
-		<h1>%i18n:mobile.tags.mk-selectdrive-page.select-file%<span class="count" v-if="files.length > 0">({{ files.length }})</span></h1>
+		<h1>%i18n:@select-file%<span class="count" v-if="files.length > 0">({{ files.length }})</span></h1>
 		<button class="upload" @click="upload">%fa:upload%</button>
 		<button v-if="multiple" class="ok" @click="ok">%fa:check%</button>
 	</header>
@@ -25,7 +25,7 @@ export default Vue.extend({
 		}
 	},
 	mounted() {
-		document.title = '%i18n:desktop.tags.mk-selectdrive-page.title%';
+		document.title = '%i18n:@title%';
 	},
 	methods: {
 		onSelected(file) {
diff --git a/src/client/app/mobile/views/pages/settings.vue b/src/client/app/mobile/views/pages/settings.vue
index 8d248f5cbf..d48c69b067 100644
--- a/src/client/app/mobile/views/pages/settings.vue
+++ b/src/client/app/mobile/views/pages/settings.vue
@@ -1,16 +1,16 @@
 <template>
 <mk-ui>
-	<span slot="header">%fa:cog%%i18n:mobile.tags.mk-settings-page.settings%</span>
+	<span slot="header">%fa:cog%%i18n:@settings%</span>
 	<div :class="$style.content">
-		<p v-html="'%i18n:mobile.tags.mk-settings.signed-in-as%'.replace('{}', '<b>' + name + '</b>')"></p>
+		<p v-html="'%i18n:@signed-in-as%'.replace('{}', '<b>' + name + '</b>')"></p>
 		<ul>
-			<li><router-link to="./settings/profile">%fa:user%%i18n:mobile.tags.mk-settings-page.profile%%fa:angle-right%</router-link></li>
-			<li><router-link to="./settings/authorized-apps">%fa:puzzle-piece%%i18n:mobile.tags.mk-settings-page.applications%%fa:angle-right%</router-link></li>
-			<li><router-link to="./settings/twitter">%fa:B twitter%%i18n:mobile.tags.mk-settings-page.twitter-integration%%fa:angle-right%</router-link></li>
-			<li><router-link to="./settings/signin-history">%fa:sign-in-alt%%i18n:mobile.tags.mk-settings-page.signin-history%%fa:angle-right%</router-link></li>
+			<li><router-link to="./settings/profile">%fa:user%%i18n:@profile%%fa:angle-right%</router-link></li>
+			<li><router-link to="./settings/authorized-apps">%fa:puzzle-piece%%i18n:@applications%%fa:angle-right%</router-link></li>
+			<li><router-link to="./settings/twitter">%fa:B twitter%%i18n:@twitter-integration%%fa:angle-right%</router-link></li>
+			<li><router-link to="./settings/signin-history">%fa:sign-in-alt%%i18n:@signin-history%%fa:angle-right%</router-link></li>
 		</ul>
 		<ul>
-			<li><a @click="signout">%fa:power-off%%i18n:mobile.tags.mk-settings-page.signout%</a></li>
+			<li><a @click="signout">%fa:power-off%%i18n:@signout%</a></li>
 		</ul>
 		<p><small>ver {{ version }} ({{ codename }})</small></p>
 	</div>
@@ -34,7 +34,7 @@ export default Vue.extend({
 		}
 	},
 	mounted() {
-		document.title = 'Misskey | %i18n:mobile.tags.mk-settings-page.settings%';
+		document.title = 'Misskey | %i18n:@settings%';
 		document.documentElement.style.background = '#313a42';
 	},
 	methods: {
diff --git a/src/client/app/mobile/views/pages/user.vue b/src/client/app/mobile/views/pages/user.vue
index 3d9fbda942..ea384308e9 100644
--- a/src/client/app/mobile/views/pages/user.vue
+++ b/src/client/app/mobile/views/pages/user.vue
@@ -14,7 +14,7 @@
 				<div class="title">
 					<h1>{{ user | userName }}</h1>
 					<span class="username">@{{ user | acct }}</span>
-					<span class="followed" v-if="user.isFollowed">%i18n:mobile.tags.mk-user.follows-you%</span>
+					<span class="followed" v-if="user.isFollowed">%i18n:@follows-you%</span>
 				</div>
 				<div class="description">{{ user.description }}</div>
 				<div class="info">
@@ -28,24 +28,24 @@
 				<div class="status">
 					<a>
 						<b>{{ user.notesCount | number }}</b>
-						<i>%i18n:mobile.tags.mk-user.notes%</i>
+						<i>%i18n:@notes%</i>
 					</a>
 					<a :href="user | userPage('following')">
 						<b>{{ user.followingCount | number }}</b>
-						<i>%i18n:mobile.tags.mk-user.following%</i>
+						<i>%i18n:@following%</i>
 					</a>
 					<a :href="user | userPage('followers')">
 						<b>{{ user.followersCount | number }}</b>
-						<i>%i18n:mobile.tags.mk-user.followers%</i>
+						<i>%i18n:@followers%</i>
 					</a>
 				</div>
 			</div>
 		</header>
 		<nav>
 			<div class="nav-container">
-				<a :data-is-active=" page == 'home' " @click="page = 'home'">%i18n:mobile.tags.mk-user.overview%</a>
-				<a :data-is-active=" page == 'notes' " @click="page = 'notes'">%i18n:mobile.tags.mk-user.timeline%</a>
-				<a :data-is-active=" page == 'media' " @click="page = 'media'">%i18n:mobile.tags.mk-user.media%</a>
+				<a :data-is-active=" page == 'home' " @click="page = 'home'">%i18n:@overview%</a>
+				<a :data-is-active=" page == 'notes' " @click="page = 'notes'">%i18n:@timeline%</a>
+				<a :data-is-active=" page == 'media' " @click="page = 'media'">%i18n:@media%</a>
 			</div>
 		</nav>
 		<div class="body">
diff --git a/src/client/app/mobile/views/pages/user/home.followers-you-know.vue b/src/client/app/mobile/views/pages/user/home.followers-you-know.vue
index 2841c0d63a..6f809d889e 100644
--- a/src/client/app/mobile/views/pages/user/home.followers-you-know.vue
+++ b/src/client/app/mobile/views/pages/user/home.followers-you-know.vue
@@ -1,12 +1,12 @@
 <template>
 <div class="root followers-you-know">
-	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:mobile.tags.mk-user-overview-followers-you-know.loading%<mk-ellipsis/></p>
+	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@loading%<mk-ellipsis/></p>
 	<div v-if="!fetching && users.length > 0">
 		<a v-for="user in users" :key="user.id" :href="user | userPage">
 			<img :src="`${user.avatarUrl}?thumbnail&size=64`" :alt="user | userName"/>
 		</a>
 	</div>
-	<p class="empty" v-if="!fetching && users.length == 0">%i18n:mobile.tags.mk-user-overview-followers-you-know.no-users%</p>
+	<p class="empty" v-if="!fetching && users.length == 0">%i18n:@no-users%</p>
 </div>
 </template>
 
diff --git a/src/client/app/mobile/views/pages/user/home.friends.vue b/src/client/app/mobile/views/pages/user/home.friends.vue
index 469781abb9..cf257b1243 100644
--- a/src/client/app/mobile/views/pages/user/home.friends.vue
+++ b/src/client/app/mobile/views/pages/user/home.friends.vue
@@ -1,10 +1,10 @@
 <template>
 <div class="root friends">
-	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:mobile.tags.mk-user-overview-frequently-replied-users.loading%<mk-ellipsis/></p>
+	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@loading%<mk-ellipsis/></p>
 	<div v-if="!fetching && users.length > 0">
 		<mk-user-card v-for="user in users" :key="user.id" :user="user"/>
 	</div>
-	<p class="empty" v-if="!fetching && users.length == 0">%i18n:mobile.tags.mk-user-overview-frequently-replied-users.no-users%</p>
+	<p class="empty" v-if="!fetching && users.length == 0">%i18n:@no-users%</p>
 </div>
 </template>
 
diff --git a/src/client/app/mobile/views/pages/user/home.notes.vue b/src/client/app/mobile/views/pages/user/home.notes.vue
index 02afed9b88..6483402a56 100644
--- a/src/client/app/mobile/views/pages/user/home.notes.vue
+++ b/src/client/app/mobile/views/pages/user/home.notes.vue
@@ -1,10 +1,10 @@
 <template>
 <div class="root notes">
-	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:mobile.tags.mk-user-overview-notes.loading%<mk-ellipsis/></p>
+	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@loading%<mk-ellipsis/></p>
 	<div v-if="!fetching && notes.length > 0">
 		<mk-note-card v-for="note in notes" :key="note.id" :note="note"/>
 	</div>
-	<p class="empty" v-if="!fetching && notes.length == 0">%i18n:mobile.tags.mk-user-overview-notes.no-notes%</p>
+	<p class="empty" v-if="!fetching && notes.length == 0">%i18n:@no-notes%</p>
 </div>
 </template>
 
diff --git a/src/client/app/mobile/views/pages/user/home.photos.vue b/src/client/app/mobile/views/pages/user/home.photos.vue
index 0e0d6926a1..bfd2aa8332 100644
--- a/src/client/app/mobile/views/pages/user/home.photos.vue
+++ b/src/client/app/mobile/views/pages/user/home.photos.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="root photos">
-	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:mobile.tags.mk-user-overview-photos.loading%<mk-ellipsis/></p>
+	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@loading%<mk-ellipsis/></p>
 	<div class="stream" v-if="!fetching && images.length > 0">
 		<a v-for="image in images"
 			class="img"
@@ -8,7 +8,7 @@
 			:href="image.note | notePage"
 		></a>
 	</div>
-	<p class="empty" v-if="!fetching && images.length == 0">%i18n:mobile.tags.mk-user-overview-photos.no-photos%</p>
+	<p class="empty" v-if="!fetching && images.length == 0">%i18n:@no-photos%</p>
 </div>
 </template>
 
diff --git a/src/client/app/mobile/views/pages/user/home.vue b/src/client/app/mobile/views/pages/user/home.vue
index c0cd9b8da8..4ba2ffd1df 100644
--- a/src/client/app/mobile/views/pages/user/home.vue
+++ b/src/client/app/mobile/views/pages/user/home.vue
@@ -2,36 +2,36 @@
 <div class="root home">
 	<mk-note-detail v-if="user.pinnedNote" :note="user.pinnedNote" :compact="true"/>
 	<section class="recent-notes">
-		<h2>%fa:R comments%%i18n:mobile.tags.mk-user-overview.recent-notes%</h2>
+		<h2>%fa:R comments%%i18n:@recent-notes%</h2>
 		<div>
 			<x-notes :user="user"/>
 		</div>
 	</section>
 	<section class="images">
-		<h2>%fa:image%%i18n:mobile.tags.mk-user-overview.images%</h2>
+		<h2>%fa:image%%i18n:@images%</h2>
 		<div>
 			<x-photos :user="user"/>
 		</div>
 	</section>
 	<section class="activity">
-		<h2>%fa:chart-bar%%i18n:mobile.tags.mk-user-overview.activity%</h2>
+		<h2>%fa:chart-bar%%i18n:@activity%</h2>
 		<div>
 			<mk-activity :user="user"/>
 		</div>
 	</section>
 	<section class="frequently-replied-users">
-		<h2>%fa:users%%i18n:mobile.tags.mk-user-overview.frequently-replied-users%</h2>
+		<h2>%fa:users%%i18n:@frequently-replied-users%</h2>
 		<div>
 			<x-friends :user="user"/>
 		</div>
 	</section>
 	<section class="followers-you-know" v-if="os.isSignedIn && os.i.id !== user.id">
-		<h2>%fa:users%%i18n:mobile.tags.mk-user-overview.followers-you-know%</h2>
+		<h2>%fa:users%%i18n:@followers-you-know%</h2>
 		<div>
 			<x-followers-you-know :user="user"/>
 		</div>
 	</section>
-	<p v-if="user.host === null">%i18n:mobile.tags.mk-user-overview.last-used-at%: <b><mk-time :time="user.lastUsedAt"/></b></p>
+	<p v-if="user.host === null">%i18n:@last-used-at%: <b><mk-time :time="user.lastUsedAt"/></b></p>
 </div>
 </template>
 
diff --git a/webpack/loaders/replace.js b/webpack/loaders/replace.js
index 03cf1fcd78..8018e9cec2 100644
--- a/webpack/loaders/replace.js
+++ b/webpack/loaders/replace.js
@@ -9,7 +9,10 @@ module.exports = function(src) {
 	const options = loaderUtils.getOptions(this);
 	const search = options.search;
 	const g = search[search.length - 1] == 'g';
-	const replace = global[options.replace];
+	const file = this.resourcePath.replace(/\\/g, '/');
+	const replace = global[options.replace].bind(null, {
+		src: file
+	});
 	if (typeof search != 'string' || search.length == 0) console.error('invalid search');
 	if (typeof replace != 'function') console.error('invalid replacer:', replace, this.request);
 	src = src.replace(new RegExp(trim(search, g), g ? 'g' : ''), replace);

From a16dffbd7573f724ea0d7b104d0618a319b0fa17 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 15 Apr 2018 01:20:46 +0900
Subject: [PATCH 02/12] wip

---
 src/build/i18n.ts | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/src/build/i18n.ts b/src/build/i18n.ts
index d9dacccd34..1fb43a13c9 100644
--- a/src/build/i18n.ts
+++ b/src/build/i18n.ts
@@ -16,7 +16,7 @@ export default class Replacer {
 		this.replacement = this.replacement.bind(this);
 	}
 
-	private get(key: string) {
+	private get(path: string, key: string) {
 		const texts = locale[this.lang];
 
 		if (texts == null) {
@@ -26,6 +26,15 @@ export default class Replacer {
 
 		let text = texts;
 
+		if (path) {
+			if (text.hasOwnProperty(path)) {
+				text = text[path];
+			} else {
+				console.warn(`path '${path}' not found in '${this.lang}'`);
+				return key; // Fallback
+			}
+		}
+
 		// Check the key existance
 		const error = key.split('.').some(k => {
 			if (text.hasOwnProperty(k)) {
@@ -37,7 +46,7 @@ export default class Replacer {
 		});
 
 		if (error) {
-			console.warn(`key '${key}' not found in '${this.lang}'`);
+			console.warn(`key '${key}' not found in '${path}' of '${this.lang}'`);
 			return key; // Fallback
 		} else {
 			return text;
@@ -51,18 +60,17 @@ export default class Replacer {
 
 		let key = a || b || c;
 		if (key[0] == '@') {
-			const prefix = name.split('.')[0].replace(/\//g, '.') + '.';
 			//if (name.startsWith('app/desktop/views/')) prefix = 'desktop.views.';
 			//if (name.startsWith('app/mobile/views/')) prefix = 'mobile.views.';
-			key = prefix + key.substr(1);
+			key = key.substr(1);
 		}
 
 		if (match[0] == '"') {
-			return '"' + this.get(key).replace(/"/g, '\\"') + '"';
+			return '"' + this.get(name, key).replace(/"/g, '\\"') + '"';
 		} else if (match[0] == "'") {
-			return '\'' + this.get(key).replace(/'/g, '\\\'') + '\'';
+			return '\'' + this.get(name, key).replace(/'/g, '\\\'') + '\'';
 		} else {
-			return this.get(key);
+			return this.get(name, key);
 		}
 	}
 }

From 298e4fe566e77ee45754d1fa065b452ef23b65ad Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 15 Apr 2018 01:36:16 +0900
Subject: [PATCH 03/12] wip

---
 locales/ja.yml                                | 381 +++++++++---------
 .../app/common/views/components/forkit.vue    |   2 +-
 2 files changed, 186 insertions(+), 197 deletions(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index 4d4c853625..547a367d09 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -1,5 +1,95 @@
+common/views/connect-failed.vue:
+  title: "サーバーに接続できません"
+  description: "インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから{再度お試し}ください。"
+  thanks: "いつもMisskeyをご利用いただきありがとうございます。"
+  troubleshoot: "トラブルシュート"
+
+common/views/connect-failed.troubleshooter.vue:
+  title: "トラブルシューティング"
+  network: "ネットワーク接続"
+  checking-network: "ネットワーク接続を確認中"
+  internet: "インターネット接続"
+  checking-internet: "インターネット接続を確認中"
+  server: "サーバー接続"
+  checking-server: "サーバー接続を確認中"
+  finding: "問題を調べています"
+  no-network: "ネットワークに接続されていません"
+  no-network-desc: "お使いのPCのネットワーク接続が正常か確認してください。"
+  no-internet: "インターネットに接続されていません"
+  no-internet-desc: "ネットワークには接続されていますが、インターネットには接続されていないようです。お使いのPCのインターネット接続が正常か確認してください。"
+  no-server: "Misskeyのサーバーに接続できません"
+  no-server-desc: "お使いのPCのインターネット接続は正常ですが、Misskeyのサーバーには接続できませんでした。サーバーがダウンまたはメンテナンスしている可能性があるので、しばらくしてから再度御アクセスください。"
+  success: "Misskeyのサーバーに接続できました"
+  success-desc: "正常に接続できるようです。ページを再度読み込みしてください。"
+
+common/views/components/messaging.vue:
+  search-user: "ユーザーを探す"
+  you: "あなた"
+  no-history: "履歴はありません"
+
+common/views/components/messaging-room.vue:
+  empty: "このユーザーと話したことはありません"
+  more: "もっと読む"
+  no-history: "これより過去の履歴はありません"
+  resize-form: "ドラッグしてフォームの広さを調整"
+  new-message: "新しいメッセージがあります"
+
+common/views/components/messaging-room.form.vue:
+  attach-from-local: "PCからファイルを添付する"
+  attach-from-drive: "ドライブからファイルを添付する"
+
+common/views/components/messaging-room.message.vue:
+  is-read: "既読"
+  deleted: "このメッセージは削除されました"
+
+common/views/components/nav.vue:
+  about: "Misskeyについて"
+  stats: "統計"
+  status: "ステータス"
+  wiki: "Wiki"
+  donors: "ドナー"
+  repository: "リポジトリ"
+  develop: "開発者"
+
+common/views/components/note-menu.vue:
+  pin: "ピン留め"
+
+common/views/components/poll.vue:
+  vote-to: "「{}」に投票する"
+  vote-count: "{}票"
+  total-users: "{}人が投票"
+  vote: "投票する"
+  show-result: "結果を見る"
+  voted: "投票済み"
+
+common/views/components/poll-editor.vue:
+  no-only-one-choice: "投票には、選択肢が最低2つ必要です"
+  choice-n: "選択肢{}"
+  remove: "この選択肢を削除"
+  add: "+選択肢を追加"
+  destroy: "投票を破棄"
+
+common/views/components/reaction-picker.vue:
+  choose-reaction: "リアクションを選択"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 common:
-  misskey: "Misskeyに何でも投稿して皆と共有しましょう。"
+  misskey: "Misskeyで皆と共有しよう。"
 
   time:
     unknown: "なぞのじかん"
@@ -33,14 +123,6 @@ common:
     confused: "こまこまのこまり"
     pudding: "Pudding"
 
-  note_categories:
-    music: "音楽"
-    game: "ゲーム"
-    anime: "アニメ"
-    it: "IT"
-    gadgets: "ガジェット"
-    photography: "写真"
-
   input-message-here: "ここにメッセージを入力"
   send: "送信"
   delete: "削除"
@@ -50,98 +132,18 @@ common:
   my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
 
   tags:
-    mk-nav-links:
-      about: "Misskeyについて"
-      stats: "統計"
-      status: "ステータス"
-      wiki: "Wiki"
-      donors: "ドナー"
-      repository: "リポジトリ"
-      develop: "開発者"
 
-    mk-messaging-form:
-      attach-from-local: "PCからファイルを添付する"
-      attach-from-drive: "ドライブからファイルを添付する"
-
-    mk-messaging:
-      search-user: "ユーザーを探す"
-      you: "あなた"
-      no-history: "履歴はありません"
-
-    mk-messaging-message:
-      is-read: "既読"
-      deleted: "このメッセージは削除されました"
-
-    mk-messaging-room:
-      empty: "このユーザーと話したことはありません"
-      more: "もっと読む"
-      no-history: "これより過去の履歴はありません"
-      resize-form: "ドラッグしてフォームの広さを調整"
-      new-message: "新しいメッセージがあります"
-
-    mk-authorized-apps:
+    authorized-apps:
       no-apps: "連携しているアプリケーションはありません"
 
-    mk-error:
-      title: "サーバーに接続できません"
-      description: "インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから{再度お試し}ください。"
-      thanks: "いつもMisskeyをご利用いただきありがとうございます。"
-      troubleshoot: "トラブルシュート"
-
-      troubleshooter:
-        title: "トラブルシューティング"
-        network: "ネットワーク接続"
-        checking-network: "ネットワーク接続を確認中"
-        internet: "インターネット接続"
-        checking-internet: "インターネット接続を確認中"
-        server: "サーバー接続"
-        checking-server: "サーバー接続を確認中"
-        finding: "問題を調べています"
-        no-network: "ネットワークに接続されていません"
-        no-network-desc: "お使いのPCのネットワーク接続が正常か確認してください。"
-        no-internet: "インターネットに接続されていません"
-        no-internet-desc: "ネットワークには接続されていますが、インターネットには接続されていないようです。お使いのPCのインターネット接続が正常か確認してください。"
-        no-server: "Misskeyのサーバーに接続できません"
-        no-server-desc: "お使いのPCのインターネット接続は正常ですが、Misskeyのサーバーには接続できませんでした。サーバーがダウンまたはメンテナンスしている可能性があるので、しばらくしてから再度御アクセスください。"
-        success: "Misskeyのサーバーに接続できました"
-        success-desc: "正常に接続できるようです。ページを再度読み込みしてください。"
-
-    mk-forkit:
-      open-github-link: "View source on Github"
-
-    mk-poll-editor:
-      no-only-one-choice: "投票には、選択肢が最低2つ必要です"
-      choice-n: "選択肢{}"
-      remove: "この選択肢を削除"
-      add: "+選択肢を追加"
-      destroy: "投票を破棄"
-
-    mk-poll:
-      vote-to: "「{}」に投票する"
-      vote-count: "{}票"
-      total-users: "{}人が投票"
-      vote: "投票する"
-      show-result: "結果を見る"
-      voted: "投票済み"
-
-    mk-note-menu:
-      pin: "ピン留め"
-      pinned: "ピン留めしました"
-      select: "カテゴリを選択"
-      categorize: "決定"
-      categorized: "カテゴリを報告しました。これによりMisskeyが賢くなり、投稿の自動カテゴライズに役立てられます。ご協力ありがとうございました。"
-
-    mk-reaction-picker:
-      choose-reaction: "リアクションを選択"
-
-    mk-signin:
+    signin:
       username: "ユーザー名"
       password: "パスワード"
       token: "トークン"
       signing-in: "やってます..."
       signin: "サインイン"
 
-    mk-signup:
+    signup:
       username: "ユーザー名"
       checking: "確認しています..."
       available: "利用できます"
@@ -163,16 +165,16 @@ common:
       create: "アカウント作成"
       some-error: "何らかの原因によりアカウントの作成に失敗しました。再度お試しください。"
 
-    mk-special-message:
+    special-message:
       new-year: "Happy New Year!"
       christmas: "Merry Christmas!"
 
-    mk-stream-indicator:
+    stream-indicator:
       connecting: "接続中"
       reconnecting: "再接続中"
       connected: "接続完了"
 
-    mk-twitter-setting:
+    twitter-setting:
       description: "お使いのTwitterアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでTwitterアカウント情報が表示されるようになったり、Twitterを用いた便利なサインインを利用できるようになります。"
       connected-to: "次のTwitterアカウントに接続されています"
       detail: "詳細..."
@@ -180,7 +182,7 @@ common:
       connect: "Twitterと接続する"
       disconnect: "切断する"
 
-    mk-uploader:
+    uploader:
       waiting: "待機中"
 
 docs:
@@ -201,38 +203,25 @@ docs:
       yes: "はい"
       no: "いいえ"
 
-ch:
-  tags:
-    mk-index:
-      new: "チャンネルを作成"
-      channel-title: "チャンネルのタイトル"
-
-    mk-channel-form:
-      textarea: "書いて"
-      upload: "アップロード"
-      drive: "ドライブ"
-      note: "やる"
-      posting: "やってます"
-
 desktop:
   tags:
-    mk-api-info:
+    api-info:
       intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
       caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
       regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
       regenerate-token: "トークンを再生成"
       enter-password: "パスワードを入力してください"
 
-    mk-drive-browser-base-contextmenu:
+    drive-browser-base-contextmenu:
       create-folder: "フォルダーを作成"
       upload: "ファイルをアップロード"
       url-upload: "URLからアップロード"
 
-    mk-drive-browser-window:
+    drive-browser-window:
       used: "使用中"
       drive: "ドライブ"
 
-    mk-drive-browser:
+    drive-browser:
       search: "検索"
       load-more: "もっと読み込む"
       empty-draghover: "ドロップですか?いいですよ、ボクはカワイイですからね"
@@ -249,7 +238,7 @@ desktop:
       create-folder: "フォルダー作成"
       folder-name: "フォルダー名"
 
-    mk-drive-browser-file-contextmenu:
+    drive-browser-file-contextmenu:
       rename: "名前を変更"
       copy-url: "URLをコピー"
       download: "ダウンロード"
@@ -263,54 +252,54 @@ desktop:
       copied: "コピー完了"
       copied-url-to-clipboard: "URLをクリップボードにコピーしました"
 
-    mk-drive-browser-file:
+    drive-browser-file:
       avatar: "アバター"
       banner: "バナー"
 
-    mk-drive-browser-folder-contextmenu:
+    drive-browser-folder-contextmenu:
       move-to-this-folder: "このフォルダへ移動"
       show-in-new-window: "新しいウィンドウで表示"
       rename: "名前を変更"
       rename-folder: "フォルダ名の変更"
       input-new-folder-name: "新しいフォルダ名を入力してください"
 
-    mk-drive-browser-folder:
+    drive-browser-folder:
       unable-to-process: "操作を完了できません"
       circular-reference-detected: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。"
       unhandled-error: "不明なエラー"
 
-    mk-drive-browser-nav-folder:
+    drive-browser-nav-folder:
       drive: "ドライブ"
 
-    mk-selectdrive-page:
+    selectdrive-page:
       title: "ファイルを選択してください"
       ok: "決定"
       cancel: "キャンセル"
       upload: "PCからドライブにファイルをアップロード"
 
-    mk-ui-header-nav:
+    ui-header-nav:
       home: "ホーム"
       messaging: "メッセージ"
       ch: "チャンネル"
       info: "お知らせ"
 
-    mk-ui-header-search:
+    ui-header-search:
       placeholder: "検索"
 
-    mk-ui-header-account:
+    ui-header-account:
       profile: "プロフィール"
       drive: "ドライブ"
       mentions: "あなた宛て"
       settings: "設定"
       signout: "サインアウト"
 
-    mk-ui-header-note-button:
+    ui-header-note-button:
       note: "新規投稿"
 
-    mk-ui-header-notifications:
+    ui-header-notifications:
       title: "通知"
 
-    mk-profile-setting:
+    profile-setting:
       avatar: "アバター"
       choice-avatar: "画像を選択"
       name: "名前"
@@ -319,7 +308,7 @@ desktop:
       birthday: "誕生日"
       save: "保存"
 
-    mk-password-setting:
+    password-setting:
       reset: "パスワードを変更する"
       enter-current-password: "現在のパスワードを入力してください"
       enter-new-password: "新しいパスワードを入力してください"
@@ -327,7 +316,7 @@ desktop:
       not-match: "新しいパスワードが一致しません"
       changed: "パスワードを変更しました"
 
-    mk-2fa-setting:
+    2fa-setting:
       intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
       detail: "詳細..."
       url: "https://www.google.co.jp/intl/ja/landing/2step/"
@@ -346,10 +335,10 @@ desktop:
       failed: "設定に失敗しました。トークンに誤りがないかご確認ください。"
       info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。"
 
-    mk-mute-setting:
+    mute-setting:
       no-users: "ミュートしているユーザーはいません"
 
-    mk-post-form:
+    post-form:
       note-placeholder: "いまどうしてる?"
       reply-placeholder: "この投稿への返信..."
       quote-placeholder: "この投稿を引用..."
@@ -370,17 +359,17 @@ desktop:
       create-poll: "投票を作成"
       text-remain: "のこり{}文字"
 
-    mk-post-form-window:
+    post-form-window:
       note: "新規投稿"
       reply: "返信"
       attaches: "添付: {}メディア"
       uploading-media: "{}個のメディアをアップロード中"
 
-    mk-note-page:
+    note-page:
       prev: "前の投稿"
       next: "次の投稿"
 
-    mk-settings:
+    settings:
       profile: "プロフィール"
       mute: "ミュート"
       drive: "ドライブ"
@@ -390,80 +379,80 @@ desktop:
       other: "その他"
       license: "ライセンス"
 
-    mk-timeline-note:
+    timeline-note:
       reposted-by: "{}がRenote"
       reply: "返信"
       renote: "Renote"
       add-reaction: "リアクション"
       detail: "詳細"
 
-    mk-notifications:
+    notifications:
       more: "もっと見る"
 
-    mk-notifications-home-widget:
+    notifications-home-widget:
       title: "通知"
       settings: "通知の設定"
 
-    mk-server-home-widget:
+    server-home-widget:
       title: "サーバー情報"
       toggle: "表示を切り替え"
 
-    mk-activity-widget:
+    activity-widget:
       title: "アクティビティ"
       toggle: "表示を切り替え"
 
-    mk-user-recommendation-home-widget:
+    user-recommendation-home-widget:
       title: "おすすめユーザー"
       refresh: "他を見る"
       no-one: "いません!"
 
-    mk-recommended-polls-home-widget:
+    recommended-polls-home-widget:
       title: "投票"
       refresh: "他を見る"
       nothing: "ありません!"
 
-    mk-trends-home-widget:
+    trends-home-widget:
       title: "トレンド"
       refresh: "他を見る"
       nothing: "ありません!"
 
-    mk-photo-stream-home-widget:
+    photo-stream-home-widget:
       title: "フォトストリーム"
       no-photos: "写真はありません"
 
-    mk-donation-home-widget:
+    donation-home-widget:
       title: "寄付のお願い"
       text: "Misskeyの運営にはドメイン、サーバー等のコストが掛かります。Misskeyは広告を掲載したりしないため、収入を皆様からの寄付に頼っています。もしご興味があれば、{}までご連絡ください。ご協力ありがとうございます。"
 
-    mk-channel-home-widget:
+    channel-home-widget:
       title: "チャンネル"
       settings: "ウィジェットの設定"
       get-started: "右上の歯車をクリックして受信するチャンネルを指定してください"
 
-    mk-calendar-widget:
+    calendar-widget:
       title: "{1}年 {2}月"
       prev: "前の月"
       next: "次の月"
       go: "クリックして時間遡行"
 
-    mk-post-form-home-widget:
+    post-form-home-widget:
       title: "投稿"
       note: "投稿"
       placeholder: "いまどうしてる?"
 
-    mk-access-log-home-widget:
+    access-log-home-widget:
       title: "アクセスログ"
 
-    mk-messaging-home-widget:
+    messaging-home-widget:
       title: "メッセージ"
 
-    mk-broadcast-home-widget:
+    broadcast-home-widget:
       fetching: "確認中"
       no-broadcasts: "お知らせはありません"
       have-a-nice-day: "良い一日を!"
       next: "次"
 
-    mk-renote-form:
+    renote-form:
       quote: "引用する..."
       cancel: "キャンセル"
       renote: "Renote"
@@ -471,10 +460,10 @@ desktop:
       success: "Renoteしました!"
       failure: "Renoteに失敗しました"
 
-    mk-renote-form-window:
+    renote-form-window:
       title: "この投稿をRenoteしますか?"
 
-    mk-user:
+    user:
       last-used-at: "最終アクセス"
 
       follows-you: "フォローされています"
@@ -499,60 +488,60 @@ desktop:
 
 mobile:
   tags:
-    mk-selectdrive-page:
+    selectdrive-page:
       select-file: "ファイルを選択"
 
-    mk-drive-file-viewer:
+    drive-file-viewer:
       download: "ダウンロード"
       rename: "名前を変更"
       move: "移動"
       hash: "ハッシュ (md5)"
       exif: "EXIF"
 
-    mk-entrance-signin:
+    entrance-signin:
       signup: "新規登録"
       about: "Misskeyについて"
 
-    mk-entrance-signup:
+    entrance-signup:
       cancel: "キャンセル"
 
-    mk-authorized-apps-page:
+    authorized-apps-page:
       application: "アプリケーション"
 
-    mk-signin-history-page:
+    signin-history-page:
       signin-history: "ログイン履歴"
 
-    mk-twitter-setting-page:
+    twitter-setting-page:
       twitter-integration: "Twitter連携"
 
-    mk-drive-page:
+    drive-page:
       drive: "ドライブ"
 
-    mk-home:
+    home:
       home: "ホーム"
 
-    mk-messaging-room-page:
+    messaging-room-page:
       message: "メッセージ"
 
-    mk-messaging-page:
+    messaging-page:
       message: "メッセージ"
 
-    mk-notifications-page:
+    notifications-page:
       notifications: "通知"
       read-all: "すべての通知を既読にしますか?"
 
-    mk-note-page:
+    note-page:
       title: "投稿"
       prev: "前の投稿"
       next: "次の投稿"
 
-    mk-search-page:
+    search-page:
       search: "検索"
 
-    mk-settings:
+    settings:
       signed-in-as: "{}としてサインイン中"
 
-    mk-settings-page:
+    settings-page:
       profile: "プロフィール"
       applications: "アプリケーション"
       twitter-integration: "Twitter連携"
@@ -561,10 +550,10 @@ mobile:
       settings: "設定"
       signout: "サインアウト"
 
-    mk-profile-setting-page:
+    profile-setting-page:
       title: "プロフィール設定"
 
-    mk-profile-setting:
+    profile-setting:
       will-be-published: "これらのプロフィールは公開されます。"
       name: "名前"
       location: "場所"
@@ -579,19 +568,19 @@ mobile:
       save: "保存"
       saved: "プロフィールを保存しました"
 
-    mk-user-followers-page:
+    user-followers-page:
       followers-of: "{}のフォロワー"
 
-    mk-user-following-page:
+    user-following-page:
       following-of: "{}のフォロー"
 
-    mk-drive-folder-selector:
+    drive-folder-selector:
       select-folder: "フォルダーを選択"
 
-    mk-drive-selector:
+    drive-selector:
       select-file: "ファイルを選択"
 
-    mk-drive:
+    drive:
       drive: "ドライブ"
       used: "使用中"
       folder-count: "フォルダ"
@@ -601,41 +590,41 @@ mobile:
       nothing-in-drive: "ドライブには何もありません"
       folder-is-empty: "このフォルダは空です"
 
-    mk-follow-button:
+    follow-button:
       follow: "フォロー"
       unfollow: "フォロー解除"
 
-    mk-home-timeline:
+    home-timeline:
       empty-timeline: "表示する投稿がありません。誰かしらをフォローするなどしましょう。"
 
-    mk-notifications:
+    notifications:
       more: "もっと見る"
       empty: "ありません!"
 
-    mk-note-detail:
+    note-detail:
       reply: "返信"
       reaction: "リアクション"
 
-    mk-post-form:
+    post-form:
       submit: "投稿"
       reply-placeholder: "この投稿への返信..."
       note-placeholder: "いまどうしてる?"
 
-    mk-search-notes:
+    search-notes:
       empty: "「{}」に関する投稿は見つかりませんでした。"
 
-    mk-sub-note-content:
+    sub-note-content:
       media-count: "{}個のメディア"
       poll: "投票"
 
-    mk-timeline-note:
+    timeline-note:
       reposted-by: "{}がRenote"
 
-    mk-timeline:
+    timeline:
       empty: "表示するものがありません"
       load-more: "もっとみる"
 
-    mk-ui-nav:
+    ui-nav:
       home: "ホーム"
       notifications: "通知"
       messaging: "メッセージ"
@@ -645,18 +634,18 @@ mobile:
       settings: "設定"
       about: "Misskeyについて"
 
-    mk-user-followers:
+    user-followers:
       no-users: "フォロワーはいないようです。"
 
-    mk-user-following:
+    user-following:
       no-users: "フォロー中のユーザーはいないようです。"
 
-    mk-user-timeline:
+    user-timeline:
       no-notes: "このユーザーはまだ投稿していないようです。"
       no-notes-with-media: "メディア付き投稿はありません。"
       load-more: "もっとみる"
 
-    mk-user:
+    user:
       follows-you: "フォローされています"
       following: "フォロー"
       followers: "フォロワー"
@@ -665,7 +654,7 @@ mobile:
       timeline: "タイムライン"
       media: "メディア"
 
-    mk-user-overview:
+    user-overview:
       recent-notes: "最近の投稿"
       images: "画像"
       activity: "アクティビティ"
@@ -675,29 +664,29 @@ mobile:
       followers-you-know: "知り合いのフォロワー"
       last-used-at: "最終ログイン"
 
-    mk-user-overview-notes:
+    user-overview-notes:
       loading: "読み込み中"
       no-notes: "投稿はありません"
 
-    mk-user-overview-photos:
+    user-overview-photos:
       loading: "読み込み中"
       no-photos: "写真はありません"
 
-    mk-user-overview-keywords:
+    user-overview-keywords:
       no-keywords: "キーワードはありません(十分な数の投稿をしていない可能性があります)"
 
-    mk-user-overview-domains:
+    user-overview-domains:
       no-domains: "よく表れるドメインは検出されませんでした"
 
-    mk-user-overview-frequently-replied-users:
+    user-overview-frequently-replied-users:
       loading: "読み込み中"
       no-users: "よく会話するユーザーはいません"
 
-    mk-user-overview-followers-you-know:
+    user-overview-followers-you-know:
       loading: "読み込み中"
       no-users: "知り合いのユーザーはいません"
 
-    mk-users-list:
+    users-list:
       all: "すべて"
       known: "知り合い"
       load-more: "もっと"
diff --git a/src/client/app/common/views/components/forkit.vue b/src/client/app/common/views/components/forkit.vue
index 05971cbf15..2a463ebfd7 100644
--- a/src/client/app/common/views/components/forkit.vue
+++ b/src/client/app/common/views/components/forkit.vue
@@ -1,5 +1,5 @@
 <template>
-<a class="a" href="https://github.com/syuilo/misskey" target="_blank" title="%i18n:@open-github-link%" aria-label="%i18n:@open-github-link%">
+<a class="a" href="https://github.com/syuilo/misskey" target="_blank" title="View source on Github">
 	<svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="aria-hidden">
 		<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
 		<path class="octo-arm" d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor"></path>

From 6805cf58edb6d989aa18dc19c00438addfee5d39 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 15 Apr 2018 01:51:02 +0900
Subject: [PATCH 04/12] wip

---
 locales/ja.yml | 259 ++++++++++++++++++++++++-------------------------
 1 file changed, 129 insertions(+), 130 deletions(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index 547a367d09..36acc55b76 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -72,9 +72,138 @@ common/views/components/poll-editor.vue:
 common/views/components/reaction-picker.vue:
   choose-reaction: "リアクションを選択"
 
+common/views/components/signin.vue:
+  username: "ユーザー名"
+  password: "パスワード"
+  token: "トークン"
+  signing-in: "やってます..."
+  signin: "サインイン"
 
+common/views/components/signup.vue:
+  username: "ユーザー名"
+  checking: "確認しています..."
+  available: "利用できます"
+  unavailable: "既に利用されています"
+  error: "通信エラー"
+  invalid-format: "a~z、A~Z、0~9、_が使えます"
+  too-short: "1文字以上でお願いします!"
+  too-long: "20文字以内でお願いします"
+  password: "パスワード"
+  password-placeholder: "8文字以上を推奨します"
+  weak-password: "弱いパスワード"
+  normal-password: "まあまあのパスワード"
+  strong-password: "強いパスワード"
+  retype: "再入力"
+  retype-placeholder: "確認のため再入力してください"
+  password-matched: "確認されました"
+  password-not-matched: "一致していません"
+  recaptcha: "認証"
+  create: "アカウント作成"
+  some-error: "何らかの原因によりアカウントの作成に失敗しました。再度お試しください。"
 
+common/views/components/special-message.vue:
+  new-year: "Happy New Year!"
+  christmas: "Merry Christmas!"
 
+common/views/components/stream-indicator.vue:
+  connecting: "接続中"
+  reconnecting: "再接続中"
+  connected: "接続完了"
+
+common/views/components/twitter-setting.vue:
+  description: "お使いのTwitterアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでTwitterアカウント情報が表示されるようになったり、Twitterを用いた便利なサインインを利用できるようになります。"
+  connected-to: "次のTwitterアカウントに接続されています"
+  detail: "詳細..."
+  reconnect: "再接続する"
+  connect: "Twitterと接続する"
+  disconnect: "切断する"
+
+common/views/components/uploader.vue:
+  waiting: "待機中"
+
+common/views/widgets/broadcast.vue:
+  fetching: "確認中"
+  no-broadcasts: "お知らせはありません"
+  have-a-nice-day: "良い一日を!"
+  next: "次"
+
+common/views/widgets/donation.vue:
+  title: "寄付のお願い"
+  text: "Misskeyの運営にはドメイン、サーバー等のコストが掛かります。Misskeyは広告を掲載したりしないため、収入を皆様からの寄付に頼っています。もしご興味があれば、{}までご連絡ください。ご協力ありがとうございます。"
+
+common/views/widgets/photo-stream.vue:
+  title: "フォトストリーム"
+  no-photos: "写真はありません"
+
+common/views/widgets/server.vue:
+  title: "サーバー情報"
+  toggle: "表示を切り替え"
+
+common/views/widgets/activity.vue:
+  title: "アクティビティ"
+  toggle: "表示を切り替え"
+
+desktop/views/widgets/calendar.vue:
+  title: "{1}年 {2}月"
+  prev: "前の月"
+  next: "次の月"
+  go: "クリックして時間遡行"
+
+desktop/views/components/drive-window.vue:
+  used: "使用中"
+  drive: "ドライブ"
+
+desktop/views/components/drive.file.vue:
+  avatar: "アバター"
+  banner: "バナー"
+  contextmenu:
+    rename: "名前を変更"
+    copy-url: "URLをコピー"
+    download: "ダウンロード"
+    else-files: "その他..."
+    set-as-avatar: "アバターに設定"
+    set-as-banner: "バナーに設定"
+    open-in-app: "アプリで開く"
+    add-app: "アプリを追加"
+    rename-file: "ファイル名の変更"
+    input-new-file-name: "新しいファイル名を入力してください"
+    copied: "コピー完了"
+    copied-url-to-clipboard: "URLをクリップボードにコピーしました"
+
+desktop/views/components/drive.folder.vue:
+  unable-to-process: "操作を完了できません"
+  circular-reference-detected: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。"
+  unhandled-error: "不明なエラー"
+  contextmenu:
+    move-to-this-folder: "このフォルダへ移動"
+    show-in-new-window: "新しいウィンドウで表示"
+    rename: "名前を変更"
+    rename-folder: "フォルダ名の変更"
+    input-new-folder-name: "新しいフォルダ名を入力してください"
+
+desktop/views/components/drive.nav-folder.vue:
+  drive: "ドライブ"
+
+desktop/views/components/drive.vue:
+  search: "検索"
+  load-more: "もっと読み込む"
+  empty-draghover: "ドロップですか?いいですよ、ボクはカワイイですからね"
+  empty-drive: "ドライブには何もありません。"
+  empty-drive-description: "右クリックして「ファイルをアップロード」を選んだり、ファイルをドラッグ&ドロップすることでもアップロードできます。"
+  empty-folder: "このフォルダーは空です"
+  unable-to-process: "操作を完了できません"
+  circular-reference-detected: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。"
+  unhandled-error: "不明なエラー"
+  url-upload: "URLアップロード"
+  url-of-file: "アップロードしたいファイルのURL"
+  url-upload-requested: "アップロードをリクエストしました"
+  may-take-time: "アップロードが完了するまで時間がかかる場合があります。"
+  create-folder: "フォルダー作成"
+  folder-name: "フォルダー名"
+  contextmenu:
+    create-folder: "フォルダーを作成"
+    upload: "ファイルをアップロード"
+    url-upload: "URLからアップロード"
 
 
 
@@ -136,54 +265,11 @@ common:
     authorized-apps:
       no-apps: "連携しているアプリケーションはありません"
 
-    signin:
-      username: "ユーザー名"
-      password: "パスワード"
-      token: "トークン"
-      signing-in: "やってます..."
-      signin: "サインイン"
 
-    signup:
-      username: "ユーザー名"
-      checking: "確認しています..."
-      available: "利用できます"
-      unavailable: "既に利用されています"
-      error: "通信エラー"
-      invalid-format: "a~z、A~Z、0~9、_が使えます"
-      too-short: "1文字以上でお願いします!"
-      too-long: "20文字以内でお願いします"
-      password: "パスワード"
-      password-placeholder: "8文字以上を推奨します"
-      weak-password: "弱いパスワード"
-      normal-password: "まあまあのパスワード"
-      strong-password: "強いパスワード"
-      retype: "再入力"
-      retype-placeholder: "確認のため再入力してください"
-      password-matched: "確認されました"
-      password-not-matched: "一致していません"
-      recaptcha: "認証"
-      create: "アカウント作成"
-      some-error: "何らかの原因によりアカウントの作成に失敗しました。再度お試しください。"
 
-    special-message:
-      new-year: "Happy New Year!"
-      christmas: "Merry Christmas!"
 
-    stream-indicator:
-      connecting: "接続中"
-      reconnecting: "再接続中"
-      connected: "接続完了"
 
-    twitter-setting:
-      description: "お使いのTwitterアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでTwitterアカウント情報が表示されるようになったり、Twitterを用いた便利なサインインを利用できるようになります。"
-      connected-to: "次のTwitterアカウントに接続されています"
-      detail: "詳細..."
-      reconnect: "再接続する"
-      connect: "Twitterと接続する"
-      disconnect: "切断する"
 
-    uploader:
-      waiting: "待機中"
 
 docs:
   edit-this-page-on-github: "間違いや改善点を見つけましたか?"
@@ -212,65 +298,6 @@ desktop:
       regenerate-token: "トークンを再生成"
       enter-password: "パスワードを入力してください"
 
-    drive-browser-base-contextmenu:
-      create-folder: "フォルダーを作成"
-      upload: "ファイルをアップロード"
-      url-upload: "URLからアップロード"
-
-    drive-browser-window:
-      used: "使用中"
-      drive: "ドライブ"
-
-    drive-browser:
-      search: "検索"
-      load-more: "もっと読み込む"
-      empty-draghover: "ドロップですか?いいですよ、ボクはカワイイですからね"
-      empty-drive: "ドライブには何もありません。"
-      empty-drive-description: "右クリックして「ファイルをアップロード」を選んだり、ファイルをドラッグ&ドロップすることでもアップロードできます。"
-      empty-folder: "このフォルダーは空です"
-      unable-to-process: "操作を完了できません"
-      circular-reference-detected: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。"
-      unhandled-error: "不明なエラー"
-      url-upload: "URLアップロード"
-      url-of-file: "アップロードしたいファイルのURL"
-      url-upload-requested: "アップロードをリクエストしました"
-      may-take-time: "アップロードが完了するまで時間がかかる場合があります。"
-      create-folder: "フォルダー作成"
-      folder-name: "フォルダー名"
-
-    drive-browser-file-contextmenu:
-      rename: "名前を変更"
-      copy-url: "URLをコピー"
-      download: "ダウンロード"
-      else-files: "その他..."
-      set-as-avatar: "アバターに設定"
-      set-as-banner: "バナーに設定"
-      open-in-app: "アプリで開く"
-      add-app: "アプリを追加"
-      rename-file: "ファイル名の変更"
-      input-new-file-name: "新しいファイル名を入力してください"
-      copied: "コピー完了"
-      copied-url-to-clipboard: "URLをクリップボードにコピーしました"
-
-    drive-browser-file:
-      avatar: "アバター"
-      banner: "バナー"
-
-    drive-browser-folder-contextmenu:
-      move-to-this-folder: "このフォルダへ移動"
-      show-in-new-window: "新しいウィンドウで表示"
-      rename: "名前を変更"
-      rename-folder: "フォルダ名の変更"
-      input-new-folder-name: "新しいフォルダ名を入力してください"
-
-    drive-browser-folder:
-      unable-to-process: "操作を完了できません"
-      circular-reference-detected: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。"
-      unhandled-error: "不明なエラー"
-
-    drive-browser-nav-folder:
-      drive: "ドライブ"
-
     selectdrive-page:
       title: "ファイルを選択してください"
       ok: "決定"
@@ -393,14 +420,6 @@ desktop:
       title: "通知"
       settings: "通知の設定"
 
-    server-home-widget:
-      title: "サーバー情報"
-      toggle: "表示を切り替え"
-
-    activity-widget:
-      title: "アクティビティ"
-      toggle: "表示を切り替え"
-
     user-recommendation-home-widget:
       title: "おすすめユーザー"
       refresh: "他を見る"
@@ -416,25 +435,11 @@ desktop:
       refresh: "他を見る"
       nothing: "ありません!"
 
-    photo-stream-home-widget:
-      title: "フォトストリーム"
-      no-photos: "写真はありません"
-
-    donation-home-widget:
-      title: "寄付のお願い"
-      text: "Misskeyの運営にはドメイン、サーバー等のコストが掛かります。Misskeyは広告を掲載したりしないため、収入を皆様からの寄付に頼っています。もしご興味があれば、{}までご連絡ください。ご協力ありがとうございます。"
-
     channel-home-widget:
       title: "チャンネル"
       settings: "ウィジェットの設定"
       get-started: "右上の歯車をクリックして受信するチャンネルを指定してください"
 
-    calendar-widget:
-      title: "{1}年 {2}月"
-      prev: "前の月"
-      next: "次の月"
-      go: "クリックして時間遡行"
-
     post-form-home-widget:
       title: "投稿"
       note: "投稿"
@@ -446,12 +451,6 @@ desktop:
     messaging-home-widget:
       title: "メッセージ"
 
-    broadcast-home-widget:
-      fetching: "確認中"
-      no-broadcasts: "お知らせはありません"
-      have-a-nice-day: "良い一日を!"
-      next: "次"
-
     renote-form:
       quote: "引用する..."
       cancel: "キャンセル"

From 27d5079c7e6df0e98aeef2c032ef3d7ed00a9afe Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 15 Apr 2018 02:03:36 +0900
Subject: [PATCH 05/12] wip

---
 locales/ja.yml                                | 236 +++++++++---------
 .../views/components/repost-form-window.vue   |  42 ----
 .../desktop/views/components/repost-form.vue  | 131 ----------
 .../views/components/ui.header.account.vue    |   2 +-
 .../views/components/ui.header.nav.vue        |   2 +-
 5 files changed, 117 insertions(+), 296 deletions(-)
 delete mode 100644 src/client/app/desktop/views/components/repost-form-window.vue
 delete mode 100644 src/client/app/desktop/views/components/repost-form.vue

diff --git a/locales/ja.yml b/locales/ja.yml
index 36acc55b76..6e8cd50ea2 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -154,14 +154,14 @@ desktop/views/components/drive-window.vue:
   drive: "ドライブ"
 
 desktop/views/components/drive.file.vue:
-  avatar: "アバター"
+  avatar: "アイコン"
   banner: "バナー"
   contextmenu:
     rename: "名前を変更"
     copy-url: "URLをコピー"
     download: "ダウンロード"
     else-files: "その他..."
-    set-as-avatar: "アバターに設定"
+    set-as-avatar: "アイコンに設定"
     set-as-banner: "バナーに設定"
     open-in-app: "アプリで開く"
     add-app: "アプリを追加"
@@ -205,11 +205,121 @@ desktop/views/components/drive.vue:
     upload: "ファイルをアップロード"
     url-upload: "URLからアップロード"
 
+desktop/views/components/notes.note.vue:
+  reposted-by: "{}がRenote"
+  reply: "返信"
+  renote: "Renote"
+  add-reaction: "リアクション"
+  detail: "詳細"
 
+desktop/views/components/notifications.vue:
+  more: "もっと見る"
 
+desktop/views/components/post-form.vue:
+  note-placeholder: "いまどうしてる?"
+  reply-placeholder: "この投稿への返信..."
+  quote-placeholder: "この投稿を引用..."
+  note: "投稿"
+  reply: "返信"
+  renote: "Renote"
+  posted: "投稿しました!"
+  replied: "返信しました!"
+  reposted: "Renoteしました!"
+  note-failed: "投稿に失敗しました"
+  reply-failed: "返信に失敗しました"
+  renote-failed: "Renoteに失敗しました"
+  posting: "投稿中"
+  attach-media-from-local: "PCからメディアを添付"
+  attach-media-from-drive: "ドライブからメディアを添付"
+  attach-cancel: "添付取り消し"
+  insert-a-kao: "v(‘ω’)v"
+  create-poll: "投票を作成"
+  text-remain: "残り{}文字"
 
+desktop/views/components/post-form-window.vue:
+  note: "新規投稿"
+  reply: "返信"
+  attaches: "添付: {}メディア"
+  uploading-media: "{}個のメディアをアップロード中"
 
+desktop/views/components/renote-form.vue:
+  quote: "引用する..."
+  cancel: "キャンセル"
+  renote: "Renote"
+  reposting: "しています..."
+  success: "Renoteしました!"
+  failure: "Renoteに失敗しました"
 
+desktop/views/components/renote-form-window.vue:
+  title: "この投稿をRenoteしますか?"
+
+desktop/views/components/settings.vue:
+  profile: "プロフィール"
+  mute: "ミュート"
+  drive: "ドライブ"
+  security: "セキュリティ"
+  password: "パスワード"
+  2fa: "二段階認証"
+  other: "その他"
+
+desktop/views/components/settings.2fa.vue:
+  intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
+  detail: "詳細..."
+  url: "https://www.google.co.jp/intl/ja/landing/2step/"
+  caution: "登録したデバイスを紛失するなどした場合、Misskeyにサインインできなくなりますのでご注意ください。"
+  register: "デバイスを登録する"
+  already-registered: "既に設定は完了しています。"
+  unregister: "設定を解除"
+  unregistered: "二段階認証が無効になりました。"
+  enter-password: "パスワードを入力してください"
+  authenticator: "まず、Google Authenticatorをお使いのデバイスにインストールします:"
+  howtoinstall: "インストール方法はこちら"
+  scan: "次に、表示されているQRコードをスキャンします:"
+  done: "お使いのデバイスに表示されているトークンを入力して完了します:"
+  submit: "完了"
+  success: "設定が完了しました!"
+  failed: "設定に失敗しました。トークンに誤りがないかご確認ください。"
+  info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。"
+
+desktop/views/components/settings.api.vue:
+  intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
+  caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
+  regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
+  regenerate-token: "トークンを再生成"
+  enter-password: "パスワードを入力してください"
+
+desktop/views/components/settings.mute.vue:
+  no-users: "ミュートしているユーザーはいません"
+
+desktop/views/components/settings.password.vue:
+  reset: "パスワードを変更する"
+  enter-current-password: "現在のパスワードを入力してください"
+  enter-new-password: "新しいパスワードを入力してください"
+  enter-new-password-again: "もう一度新しいパスワードを入力してください"
+  not-match: "新しいパスワードが一致しません"
+  changed: "パスワードを変更しました"
+
+desktop/views/components/settings.profile.vue:
+  avatar: "アイコン"
+  choice-avatar: "画像を選択"
+  name: "名前"
+  location: "場所"
+  description: "自己紹介"
+  birthday: "誕生日"
+  save: "保存"
+
+desktop/views/components/ui.header.account.vue:
+  profile: "プロフィール"
+  drive: "ドライブ"
+  mentions: "あなた宛て"
+  customize: "カスタマイズ"
+  settings: "設定"
+  signout: "サインアウト"
+
+desktop/views/components/ui.header.nav.vue:
+  home: "ホーム"
+  messaging: "メッセージ"
+  game: "ゲーム"
 
 
 
@@ -291,12 +401,6 @@ docs:
 
 desktop:
   tags:
-    api-info:
-      intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
-      caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
-      regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
-      regenerate-token: "トークンを再生成"
-      enter-password: "パスワードを入力してください"
 
     selectdrive-page:
       title: "ファイルを選択してください"
@@ -304,118 +408,19 @@ desktop:
       cancel: "キャンセル"
       upload: "PCからドライブにファイルをアップロード"
 
-    ui-header-nav:
-      home: "ホーム"
-      messaging: "メッセージ"
-      ch: "チャンネル"
-      info: "お知らせ"
-
     ui-header-search:
       placeholder: "検索"
 
-    ui-header-account:
-      profile: "プロフィール"
-      drive: "ドライブ"
-      mentions: "あなた宛て"
-      settings: "設定"
-      signout: "サインアウト"
-
     ui-header-note-button:
       note: "新規投稿"
 
     ui-header-notifications:
       title: "通知"
 
-    profile-setting:
-      avatar: "アバター"
-      choice-avatar: "画像を選択"
-      name: "名前"
-      location: "場所"
-      description: "自己紹介"
-      birthday: "誕生日"
-      save: "保存"
-
-    password-setting:
-      reset: "パスワードを変更する"
-      enter-current-password: "現在のパスワードを入力してください"
-      enter-new-password: "新しいパスワードを入力してください"
-      enter-new-password-again: "もう一度新しいパスワードを入力してください"
-      not-match: "新しいパスワードが一致しません"
-      changed: "パスワードを変更しました"
-
-    2fa-setting:
-      intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
-      detail: "詳細..."
-      url: "https://www.google.co.jp/intl/ja/landing/2step/"
-      caution: "登録したデバイスを紛失するなどした場合、Misskeyにサインインできなくなりますのでご注意ください。"
-      register: "デバイスを登録する"
-      already-registered: "既に設定は完了しています。"
-      unregister: "設定を解除"
-      unregistered: "二段階認証が無効になりました。"
-      enter-password: "パスワードを入力してください"
-      authenticator: "まず、Google Authenticatorをお使いのデバイスにインストールします:"
-      howtoinstall: "インストール方法はこちら"
-      scan: "次に、表示されているQRコードをスキャンします:"
-      done: "お使いのデバイスに表示されているトークンを入力して完了します:"
-      submit: "完了"
-      success: "設定が完了しました!"
-      failed: "設定に失敗しました。トークンに誤りがないかご確認ください。"
-      info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。"
-
-    mute-setting:
-      no-users: "ミュートしているユーザーはいません"
-
-    post-form:
-      note-placeholder: "いまどうしてる?"
-      reply-placeholder: "この投稿への返信..."
-      quote-placeholder: "この投稿を引用..."
-      note: "投稿"
-      reply: "返信"
-      renote: "Renote"
-      posted: "投稿しました!"
-      replied: "返信しました!"
-      reposted: "Renoteしました!"
-      note-failed: "投稿に失敗しました"
-      reply-failed: "返信に失敗しました"
-      renote-failed: "Renoteに失敗しました"
-      posting: "投稿中"
-      attach-media-from-local: "PCからメディアを添付"
-      attach-media-from-drive: "ドライブからメディアを添付"
-      attach-cancel: "添付取り消し"
-      insert-a-kao: "v(‘ω’)v"
-      create-poll: "投票を作成"
-      text-remain: "のこり{}文字"
-
-    post-form-window:
-      note: "新規投稿"
-      reply: "返信"
-      attaches: "添付: {}メディア"
-      uploading-media: "{}個のメディアをアップロード中"
-
     note-page:
       prev: "前の投稿"
       next: "次の投稿"
 
-    settings:
-      profile: "プロフィール"
-      mute: "ミュート"
-      drive: "ドライブ"
-      security: "セキュリティ"
-      password: "パスワード"
-      2fa: "二段階認証"
-      other: "その他"
-      license: "ライセンス"
-
-    timeline-note:
-      reposted-by: "{}がRenote"
-      reply: "返信"
-      renote: "Renote"
-      add-reaction: "リアクション"
-      detail: "詳細"
-
-    notifications:
-      more: "もっと見る"
-
     notifications-home-widget:
       title: "通知"
       settings: "通知の設定"
@@ -451,17 +456,6 @@ desktop:
     messaging-home-widget:
       title: "メッセージ"
 
-    renote-form:
-      quote: "引用する..."
-      cancel: "キャンセル"
-      renote: "Renote"
-      reposting: "しています..."
-      success: "Renoteしました!"
-      failure: "Renoteに失敗しました"
-
-    renote-form-window:
-      title: "この投稿をRenoteしますか?"
-
     user:
       last-used-at: "最終アクセス"
 
@@ -558,11 +552,11 @@ mobile:
       location: "場所"
       description: "自己紹介"
       birthday: "誕生日"
-      avatar: "アバター"
+      avatar: "アイコン"
       banner: "バナー"
-      avatar-saved: "アバターを保存しました"
+      avatar-saved: "アイコンを保存しました"
       banner-saved: "バナーを保存しました"
-      set-avatar: "アバターを選択する"
+      set-avatar: "アイコンを選択する"
       set-banner: "バナーを選択する"
       save: "保存"
       saved: "プロフィールを保存しました"
diff --git a/src/client/app/desktop/views/components/repost-form-window.vue b/src/client/app/desktop/views/components/repost-form-window.vue
deleted file mode 100644
index df9d2f7fc7..0000000000
--- a/src/client/app/desktop/views/components/repost-form-window.vue
+++ /dev/null
@@ -1,42 +0,0 @@
-<template>
-<mk-window ref="window" is-modal @closed="$destroy">
-	<span slot="header" :class="$style.header">%fa:retweet%%i18n:@title%</span>
-	<mk-renote-form ref="form" :note="note" @posted="onPosted" @canceled="onCanceled"/>
-</mk-window>
-</template>
-
-<script lang="ts">
-import Vue from 'vue';
-
-export default Vue.extend({
-	props: ['note'],
-	mounted() {
-		document.addEventListener('keydown', this.onDocumentKeydown);
-	},
-	beforeDestroy() {
-		document.removeEventListener('keydown', this.onDocumentKeydown);
-	},
-	methods: {
-		onDocumentKeydown(e) {
-			if (e.target.tagName != 'INPUT' && e.target.tagName != 'TEXTAREA') {
-				if (e.which == 27) { // Esc
-					(this.$refs.window as any).close();
-				}
-			}
-		},
-		onPosted() {
-			(this.$refs.window as any).close();
-		},
-		onCanceled() {
-			(this.$refs.window as any).close();
-		}
-	}
-});
-</script>
-
-<style lang="stylus" module>
-.header
-	> [data-fa]
-		margin-right 4px
-
-</style>
diff --git a/src/client/app/desktop/views/components/repost-form.vue b/src/client/app/desktop/views/components/repost-form.vue
deleted file mode 100644
index 1f947a71de..0000000000
--- a/src/client/app/desktop/views/components/repost-form.vue
+++ /dev/null
@@ -1,131 +0,0 @@
-<template>
-<div class="mk-renote-form">
-	<mk-note-preview :note="note"/>
-	<template v-if="!quote">
-		<footer>
-			<a class="quote" v-if="!quote" @click="onQuote">%i18n:@quote%</a>
-			<button class="cancel" @click="cancel">%i18n:@cancel%</button>
-			<button class="ok" @click="ok" :disabled="wait">{{ wait ? '%i18n:@reposting%' : '%i18n:@renote%' }}</button>
-		</footer>
-	</template>
-	<template v-if="quote">
-		<mk-post-form ref="form" :renote="note" @posted="onChildFormPosted"/>
-	</template>
-</div>
-</template>
-
-<script lang="ts">
-import Vue from 'vue';
-
-export default Vue.extend({
-	props: ['note'],
-	data() {
-		return {
-			wait: false,
-			quote: false
-		};
-	},
-	methods: {
-		ok() {
-			this.wait = true;
-			(this as any).api('notes/create', {
-				renoteId: this.note.id
-			}).then(data => {
-				this.$emit('posted');
-				(this as any).apis.notify('%i18n:@success%');
-			}).catch(err => {
-				(this as any).apis.notify('%i18n:@failure%');
-			}).then(() => {
-				this.wait = false;
-			});
-		},
-		cancel() {
-			this.$emit('canceled');
-		},
-		onQuote() {
-			this.quote = true;
-
-			this.$nextTick(() => {
-				(this.$refs.form as any).focus();
-			});
-		},
-		onChildFormPosted() {
-			this.$emit('posted');
-		}
-	}
-});
-</script>
-
-<style lang="stylus" scoped>
-@import '~const.styl'
-
-.mk-renote-form
-
-	> .mk-note-preview
-		margin 16px 22px
-
-	> footer
-		height 72px
-		background lighten($theme-color, 95%)
-
-		> .quote
-			position absolute
-			bottom 16px
-			left 28px
-			line-height 40px
-
-		button
-			display block
-			position absolute
-			bottom 16px
-			cursor pointer
-			padding 0
-			margin 0
-			width 120px
-			height 40px
-			font-size 1em
-			outline none
-			border-radius 4px
-
-			&:focus
-				&:after
-					content ""
-					pointer-events none
-					position absolute
-					top -5px
-					right -5px
-					bottom -5px
-					left -5px
-					border 2px solid rgba($theme-color, 0.3)
-					border-radius 8px
-
-		> .cancel
-			right 148px
-			color #888
-			background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%)
-			border solid 1px #e2e2e2
-
-			&:hover
-				background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%)
-				border-color #dcdcdc
-
-			&:active
-				background #ececec
-				border-color #dcdcdc
-
-		> .ok
-			right 16px
-			font-weight bold
-			color $theme-color-foreground
-			background linear-gradient(to bottom, lighten($theme-color, 25%) 0%, lighten($theme-color, 10%) 100%)
-			border solid 1px lighten($theme-color, 15%)
-
-			&:hover
-				background linear-gradient(to bottom, lighten($theme-color, 8%) 0%, darken($theme-color, 8%) 100%)
-				border-color $theme-color
-
-			&:active
-				background $theme-color
-				border-color $theme-color
-
-</style>
diff --git a/src/client/app/desktop/views/components/ui.header.account.vue b/src/client/app/desktop/views/components/ui.header.account.vue
index 5fd32a4cef..558aaa6dc8 100644
--- a/src/client/app/desktop/views/components/ui.header.account.vue
+++ b/src/client/app/desktop/views/components/ui.header.account.vue
@@ -19,7 +19,7 @@
 			</ul>
 			<ul>
 				<li>
-					<a href="/i/customize-home">%fa:wrench%カスタマイズ%fa:angle-right%</a>
+					<a href="/i/customize-home">%fa:wrench%%i18n:@customize%%fa:angle-right%</a>
 				</li>
 				<li @click="settings">
 					<p>%fa:cog%%i18n:@settings%%fa:angle-right%</p>
diff --git a/src/client/app/desktop/views/components/ui.header.nav.vue b/src/client/app/desktop/views/components/ui.header.nav.vue
index b4f83d8abf..19f72a86d7 100644
--- a/src/client/app/desktop/views/components/ui.header.nav.vue
+++ b/src/client/app/desktop/views/components/ui.header.nav.vue
@@ -18,7 +18,7 @@
 			<li class="game">
 				<a @click="game">
 					%fa:gamepad%
-					<p>ゲーム</p>
+					<p>%i18n:@game%</p>
 					<template v-if="hasGameInvitations">%fa:circle%</template>
 				</a>
 			</li>

From 1464df57fa430d7269c4baf71b8b3475e74ca2f0 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 15 Apr 2018 02:36:01 +0900
Subject: [PATCH 06/12] wip

---
 locales/ja.yml                                | 600 ++++++++----------
 .../views/components/ui.header.post.vue       |   2 +-
 .../app/mobile/views/pages/messaging-room.vue |   2 +-
 .../app/mobile/views/pages/messaging.vue      |   4 +-
 .../app/mobile/views/pages/settings.vue       |   2 +-
 5 files changed, 267 insertions(+), 343 deletions(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index 6e8cd50ea2..8787aaad20 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -1,3 +1,46 @@
+common:
+  misskey: "Misskeyで皆と共有しよう。"
+
+  time:
+    unknown: "なぞのじかん"
+    future: "未来"
+    just_now: "たった今"
+    seconds_ago: "{}秒前"
+    minutes_ago: "{}分前"
+    hours_ago: "{}時間前"
+    days_ago: "{}日前"
+    weeks_ago: "{}週間前"
+    months_ago: "{}ヶ月前"
+    years_ago: "{}年前"
+
+  weekday-short:
+    sunday: "日"
+    monday: "月"
+    tuesday: "火"
+    wednesday: "水"
+    thursday: "木"
+    friday: "金"
+    satruday: "土"
+
+  reactions:
+    like: "いいね"
+    love: "しゅき"
+    laugh: "笑"
+    hmm: "ふぅ~む"
+    surprise: "わお"
+    congrats: "おめでとう"
+    angry: "おこ"
+    confused: "こまこまのこまり"
+    pudding: "Pudding"
+
+  input-message-here: "ここにメッセージを入力"
+  send: "送信"
+  delete: "削除"
+  loading: "読み込み中"
+  ok: "わかった"
+  update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
+  my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
+
 common/views/connect-failed.vue:
   title: "サーバーに接続できません"
   description: "インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから{再度お試し}ください。"
@@ -321,65 +364,239 @@ desktop/views/components/ui.header.nav.vue:
   messaging: "メッセージ"
   game: "ゲーム"
 
+desktop/views/components/ui.header.notifications.vue:
+  title: "通知"
 
+desktop/views/components/ui.header.post.vue:
+  post: "新規投稿"
 
+desktop/views/components/ui.header.search.vue:
+  placeholder: "検索"
 
+desktop/views/pages/note.vue:
+  prev: "前の投稿"
+  next: "次の投稿"
 
+desktop/views/pages/selectdrive.vue:
+  title: "ファイルを選択してください"
+  ok: "決定"
+  cancel: "キャンセル"
+  upload: "PCからドライブにファイルをアップロード"
 
-
-common:
-  misskey: "Misskeyで皆と共有しよう。"
-
-  time:
-    unknown: "なぞのじかん"
-    future: "未来"
-    just_now: "たった今"
-    seconds_ago: "{}秒前"
-    minutes_ago: "{}分前"
-    hours_ago: "{}時間前"
-    days_ago: "{}日前"
-    weeks_ago: "{}週間前"
-    months_ago: "{}ヶ月前"
-    years_ago: "{}年前"
-
-  weekday-short:
-    sunday: "日"
-    monday: "月"
-    tuesday: "火"
-    wednesday: "水"
-    thursday: "木"
-    friday: "金"
-    satruday: "土"
-
-  reactions:
-    like: "いいね"
-    love: "しゅき"
-    laugh: "笑"
-    hmm: "ふぅ~む"
-    surprise: "わお"
-    congrats: "おめでとう"
-    angry: "おこ"
-    confused: "こまこまのこまり"
-    pudding: "Pudding"
-
-  input-message-here: "ここにメッセージを入力"
-  send: "送信"
-  delete: "削除"
+desktop/views/pages/user/user.followers-you-know.vue:
+  title: "知り合いのフォロワー"
   loading: "読み込み中"
-  ok: "わかった"
-  update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
-  my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
+  no-users: "知り合いのフォロワーはいません"
 
-  tags:
+desktop/views/pages/user/user.friends.vue:
+  title: "よく話すユーザー"
+  loading: "読み込み中"
+  no-users: "よく話すユーザーはいません"
 
-    authorized-apps:
-      no-apps: "連携しているアプリケーションはありません"
+desktop/views/pages/user/user.home.vue:
+  last-used-at: "最終アクセス"
 
+desktop/views/pages/user/user.photos.vue:
+  title: "フォト"
+  loading: "読み込み中"
+  no-photos: "写真はありません"
 
+desktop/views/pages/user/user.profile.vue:
+  follows-you: "フォローされています"
+  mute: "ミュートする"
+  muted: "ミュートしています"
+  unmute: "ミュート解除"
 
+desktop/views/widgets/messaging.vue:
+  title: "メッセージ"
 
+desktop/views/widgets/notifications.vue:
+  title: "通知"
+  settings: "通知の設定"
 
+desktop/views/widgets/polls.vue:
+  title: "投票"
+  refresh: "他を見る"
+  nothing: "ありません!"
 
+desktop/views/widgets/post-form.vue:
+  title: "投稿"
+  note: "投稿"
+  placeholder: "いまどうしてる?"
+
+desktop/views/widgets/trends.vue:
+  title: "トレンド"
+  refresh: "他を見る"
+  nothing: "ありません!"
+
+desktop/views/widgets/users.vue:
+  title: "おすすめユーザー"
+  refresh: "他を見る"
+  no-one: "いません!"
+
+desktop/views/widgets/channel.vue:
+  title: "チャンネル"
+  settings: "ウィジェットの設定"
+  get-started: "右上の歯車をクリックして受信するチャンネルを指定してください"
+
+mobile/views/components/drive.vue:
+  drive: "ドライブ"
+  used: "使用中"
+  folder-count: "フォルダ"
+  count-separator: "、"
+  file-count: "ファイル"
+  load-more: "もっと読み込む"
+  nothing-in-drive: "ドライブには何もありません"
+  folder-is-empty: "このフォルダは空です"
+
+mobile/views/components/drive-file-chooser.vue:
+  select-file: "ファイルを選択"
+
+mobile/views/components/drive-folder-chooser.vue:
+  select-folder: "フォルダーを選択"
+
+mobile/views/components/drive.file-detail.vue:
+  download: "ダウンロード"
+  rename: "名前を変更"
+  move: "移動"
+  hash: "ハッシュ (md5)"
+  exif: "EXIF"
+
+mobile/views/components/follow-button.vue:
+  follow: "フォロー"
+  unfollow: "フォロー解除"
+
+mobile/views/components/note.vue:
+  reposted-by: "{}がRenote"
+
+mobile/views/components/note-detail.vue:
+  reply: "返信"
+  reaction: "リアクション"
+
+mobile/views/components/notifications.vue:
+  more: "もっと見る"
+  empty: "ありません!"
+
+mobile/views/components/post-form.vue:
+  submit: "投稿"
+  reply-placeholder: "この投稿への返信..."
+  note-placeholder: "いまどうしてる?"
+
+mobile/views/components/sub-note-content.vue:
+  media-count: "{}個のメディア"
+  poll: "投票"
+
+mobile/views/components/timeline.vue:
+  empty: "投稿がありません"
+  load-more: "もっと"
+
+mobile/views/components/ui.nav.vue:
+  home: "ホーム"
+  notifications: "通知"
+  messaging: "メッセージ"
+  search: "検索"
+  drive: "ドライブ"
+  settings: "設定"
+  about: "Misskeyについて"
+
+mobile/views/components/user-timeline.vue:
+  no-notes: "このユーザーは投稿していないようです。"
+  no-notes-with-media: "メディア付き投稿はありません。"
+  load-more: "もっと"
+
+mobile/views/components/users-list.vue:
+  all: "すべて"
+  known: "知り合い"
+  load-more: "もっと"
+
+mobile/views/pages/drive.vue:
+  drive: "ドライブ"
+
+mobile/views/pages/followers.vue:
+  followers-of: "{}のフォロワー"
+
+mobile/views/pages/following.vue:
+  following-of: "{}のフォロー"
+
+mobile/views/pages/messaging.vue:
+  messaging: "メッセージ"
+
+mobile/views/pages/messaging-room.vue:
+  messaging: "メッセージ"
+
+mobile/views/pages/note.vue:
+  title: "投稿"
+  prev: "前の投稿"
+  next: "次の投稿"
+
+mobile/views/pages/notifications.vue:
+  notifications: "通知"
+  read-all: "すべての通知を既読にしますか?"
+
+mobile/views/pages/profile-setting.vue:
+  title: "プロフィール設定"
+  will-be-published: "これらのプロフィールは公開されます。"
+  name: "名前"
+  location: "場所"
+  description: "自己紹介"
+  birthday: "誕生日"
+  avatar: "アイコン"
+  banner: "バナー"
+  avatar-saved: "アイコンを保存しました"
+  banner-saved: "バナーを保存しました"
+  set-avatar: "アイコンを選択する"
+  set-banner: "バナーを選択する"
+  save: "保存"
+  saved: "プロフィールを保存しました"
+
+mobile/views/pages/search.vue:
+  search: "検索"
+  empty: "「{}」に関する投稿は見つかりませんでした。"
+
+mobile/views/pages/selectdrive.vue:
+  select-file: "ファイルを選択"
+
+mobile/views/pages/settings.vue:
+  profile: "プロフィール"
+  twitter: "Twitter連携"
+  signin-history: "サインイン履歴"
+  settings: "設定"
+  signout: "サインアウト"
+
+mobile/views/pages/user.vue:
+  follows-you: "フォローされています"
+  following: "フォロー"
+  followers: "フォロワー"
+  notes: "投稿"
+  overview: "概要"
+  timeline: "タイムライン"
+  media: "メディア"
+
+mobile/views/pages/user/home.vue:
+  recent-notes: "最近の投稿"
+  images: "画像"
+  activity: "アクティビティ"
+  keywords: "キーワード"
+  domains: "頻出ドメイン"
+  frequently-replied-users: "よく会話するユーザー"
+  followers-you-know: "知り合いのフォロワー"
+  last-used-at: "最終ログイン"
+
+mobile/views/pages/user/home.followers-you-know.vue:
+  loading: "読み込み中"
+  no-users: "知り合いのユーザーはいません"
+
+mobile/views/pages/user/home.friends.vue:
+  loading: "読み込み中"
+  no-users: "よく会話するユーザーはいません"
+
+mobile/views/pages/user/home.notes.vue:
+  loading: "読み込み中"
+  no-notes: "投稿はありません"
+
+mobile/views/pages/user/home.photos.vue:
+  loading: "読み込み中"
+  no-photos: "写真はありません"
 
 docs:
   edit-this-page-on-github: "間違いや改善点を見つけましたか?"
@@ -398,296 +615,3 @@ docs:
       description: "説明"
       yes: "はい"
       no: "いいえ"
-
-desktop:
-  tags:
-
-    selectdrive-page:
-      title: "ファイルを選択してください"
-      ok: "決定"
-      cancel: "キャンセル"
-      upload: "PCからドライブにファイルをアップロード"
-
-    ui-header-search:
-      placeholder: "検索"
-
-    ui-header-note-button:
-      note: "新規投稿"
-
-    ui-header-notifications:
-      title: "通知"
-
-    note-page:
-      prev: "前の投稿"
-      next: "次の投稿"
-
-    notifications-home-widget:
-      title: "通知"
-      settings: "通知の設定"
-
-    user-recommendation-home-widget:
-      title: "おすすめユーザー"
-      refresh: "他を見る"
-      no-one: "いません!"
-
-    recommended-polls-home-widget:
-      title: "投票"
-      refresh: "他を見る"
-      nothing: "ありません!"
-
-    trends-home-widget:
-      title: "トレンド"
-      refresh: "他を見る"
-      nothing: "ありません!"
-
-    channel-home-widget:
-      title: "チャンネル"
-      settings: "ウィジェットの設定"
-      get-started: "右上の歯車をクリックして受信するチャンネルを指定してください"
-
-    post-form-home-widget:
-      title: "投稿"
-      note: "投稿"
-      placeholder: "いまどうしてる?"
-
-    access-log-home-widget:
-      title: "アクセスログ"
-
-    messaging-home-widget:
-      title: "メッセージ"
-
-    user:
-      last-used-at: "最終アクセス"
-
-      follows-you: "フォローされています"
-      mute: "ミュートする"
-      muted: "ミュートしています"
-      unmute: "ミュート解除"
-
-      photos:
-        title: "フォト"
-        loading: "読み込み中"
-        no-photos: "写真はありません"
-
-      frequently-replied-users:
-        title: "よく話すユーザー"
-        loading: "読み込み中"
-        no-users: "よく話すユーザーはいません"
-
-      followers-you-know:
-        title: "知り合いのフォロワー"
-        loading: "読み込み中"
-        no-users: "知り合いのフォロワーはいません"
-
-mobile:
-  tags:
-    selectdrive-page:
-      select-file: "ファイルを選択"
-
-    drive-file-viewer:
-      download: "ダウンロード"
-      rename: "名前を変更"
-      move: "移動"
-      hash: "ハッシュ (md5)"
-      exif: "EXIF"
-
-    entrance-signin:
-      signup: "新規登録"
-      about: "Misskeyについて"
-
-    entrance-signup:
-      cancel: "キャンセル"
-
-    authorized-apps-page:
-      application: "アプリケーション"
-
-    signin-history-page:
-      signin-history: "ログイン履歴"
-
-    twitter-setting-page:
-      twitter-integration: "Twitter連携"
-
-    drive-page:
-      drive: "ドライブ"
-
-    home:
-      home: "ホーム"
-
-    messaging-room-page:
-      message: "メッセージ"
-
-    messaging-page:
-      message: "メッセージ"
-
-    notifications-page:
-      notifications: "通知"
-      read-all: "すべての通知を既読にしますか?"
-
-    note-page:
-      title: "投稿"
-      prev: "前の投稿"
-      next: "次の投稿"
-
-    search-page:
-      search: "検索"
-
-    settings:
-      signed-in-as: "{}としてサインイン中"
-
-    settings-page:
-      profile: "プロフィール"
-      applications: "アプリケーション"
-      twitter-integration: "Twitter連携"
-      signin-history: "サインイン履歴"
-      link: "Misskeyリンク"
-      settings: "設定"
-      signout: "サインアウト"
-
-    profile-setting-page:
-      title: "プロフィール設定"
-
-    profile-setting:
-      will-be-published: "これらのプロフィールは公開されます。"
-      name: "名前"
-      location: "場所"
-      description: "自己紹介"
-      birthday: "誕生日"
-      avatar: "アイコン"
-      banner: "バナー"
-      avatar-saved: "アイコンを保存しました"
-      banner-saved: "バナーを保存しました"
-      set-avatar: "アイコンを選択する"
-      set-banner: "バナーを選択する"
-      save: "保存"
-      saved: "プロフィールを保存しました"
-
-    user-followers-page:
-      followers-of: "{}のフォロワー"
-
-    user-following-page:
-      following-of: "{}のフォロー"
-
-    drive-folder-selector:
-      select-folder: "フォルダーを選択"
-
-    drive-selector:
-      select-file: "ファイルを選択"
-
-    drive:
-      drive: "ドライブ"
-      used: "使用中"
-      folder-count: "フォルダ"
-      count-separator: "、"
-      file-count: "ファイル"
-      load-more: "もっと読み込む"
-      nothing-in-drive: "ドライブには何もありません"
-      folder-is-empty: "このフォルダは空です"
-
-    follow-button:
-      follow: "フォロー"
-      unfollow: "フォロー解除"
-
-    home-timeline:
-      empty-timeline: "表示する投稿がありません。誰かしらをフォローするなどしましょう。"
-
-    notifications:
-      more: "もっと見る"
-      empty: "ありません!"
-
-    note-detail:
-      reply: "返信"
-      reaction: "リアクション"
-
-    post-form:
-      submit: "投稿"
-      reply-placeholder: "この投稿への返信..."
-      note-placeholder: "いまどうしてる?"
-
-    search-notes:
-      empty: "「{}」に関する投稿は見つかりませんでした。"
-
-    sub-note-content:
-      media-count: "{}個のメディア"
-      poll: "投票"
-
-    timeline-note:
-      reposted-by: "{}がRenote"
-
-    timeline:
-      empty: "表示するものがありません"
-      load-more: "もっとみる"
-
-    ui-nav:
-      home: "ホーム"
-      notifications: "通知"
-      messaging: "メッセージ"
-      ch: "チャンネル"
-      search: "検索"
-      drive: "ドライブ"
-      settings: "設定"
-      about: "Misskeyについて"
-
-    user-followers:
-      no-users: "フォロワーはいないようです。"
-
-    user-following:
-      no-users: "フォロー中のユーザーはいないようです。"
-
-    user-timeline:
-      no-notes: "このユーザーはまだ投稿していないようです。"
-      no-notes-with-media: "メディア付き投稿はありません。"
-      load-more: "もっとみる"
-
-    user:
-      follows-you: "フォローされています"
-      following: "フォロー"
-      followers: "フォロワー"
-      notes: "投稿"
-      overview: "概要"
-      timeline: "タイムライン"
-      media: "メディア"
-
-    user-overview:
-      recent-notes: "最近の投稿"
-      images: "画像"
-      activity: "アクティビティ"
-      keywords: "キーワード"
-      domains: "頻出ドメイン"
-      frequently-replied-users: "よく会話するユーザー"
-      followers-you-know: "知り合いのフォロワー"
-      last-used-at: "最終ログイン"
-
-    user-overview-notes:
-      loading: "読み込み中"
-      no-notes: "投稿はありません"
-
-    user-overview-photos:
-      loading: "読み込み中"
-      no-photos: "写真はありません"
-
-    user-overview-keywords:
-      no-keywords: "キーワードはありません(十分な数の投稿をしていない可能性があります)"
-
-    user-overview-domains:
-      no-domains: "よく表れるドメインは検出されませんでした"
-
-    user-overview-frequently-replied-users:
-      loading: "読み込み中"
-      no-users: "よく会話するユーザーはいません"
-
-    user-overview-followers-you-know:
-      loading: "読み込み中"
-      no-users: "知り合いのユーザーはいません"
-
-    users-list:
-      all: "すべて"
-      known: "知り合い"
-      load-more: "もっと"
-
-stats:
-  notes-count: "投稿の数"
-  users-count: "アカウントの数"
-
-status:
-  all-systems-maybe-operational: "すべてのシステムがたぶん正常に作動しています"
-  what-is-this-site: ""
diff --git a/src/client/app/desktop/views/components/ui.header.post.vue b/src/client/app/desktop/views/components/ui.header.post.vue
index 01329c7c83..3665488542 100644
--- a/src/client/app/desktop/views/components/ui.header.post.vue
+++ b/src/client/app/desktop/views/components/ui.header.post.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="note">
-	<button @click="post" title="%i18n:@note%">%fa:pencil-alt%</button>
+	<button @click="post" title="%i18n:@post%">%fa:pencil-alt%</button>
 </div>
 </template>
 
diff --git a/src/client/app/mobile/views/pages/messaging-room.vue b/src/client/app/mobile/views/pages/messaging-room.vue
index d436960f2c..c26a9b735e 100644
--- a/src/client/app/mobile/views/pages/messaging-room.vue
+++ b/src/client/app/mobile/views/pages/messaging-room.vue
@@ -33,7 +33,7 @@ export default Vue.extend({
 				this.user = user;
 				this.fetching = false;
 
-				document.title = `%i18n:@message%: ${Vue.filter('userName')(this.user)} | Misskey`;
+				document.title = `%i18n:@messaging%: ${Vue.filter('userName')(this.user)} | Misskey`;
 			});
 		}
 	}
diff --git a/src/client/app/mobile/views/pages/messaging.vue b/src/client/app/mobile/views/pages/messaging.vue
index b52df7d3cf..cc328e5a1c 100644
--- a/src/client/app/mobile/views/pages/messaging.vue
+++ b/src/client/app/mobile/views/pages/messaging.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-ui>
-	<span slot="header">%fa:R comments%%i18n:@message%</span>
+	<span slot="header">%fa:R comments%%i18n:@messaging%</span>
 	<mk-messaging @navigate="navigate" :header-top="48"/>
 </mk-ui>
 </template>
@@ -11,7 +11,7 @@ import getAcct from '../../../../../acct/render';
 
 export default Vue.extend({
 	mounted() {
-		document.title = 'Misskey %i18n:@message%';
+		document.title = 'Misskey %i18n:@messaging%';
 		document.documentElement.style.background = '#fff';
 	},
 	methods: {
diff --git a/src/client/app/mobile/views/pages/settings.vue b/src/client/app/mobile/views/pages/settings.vue
index d48c69b067..a294bf12a0 100644
--- a/src/client/app/mobile/views/pages/settings.vue
+++ b/src/client/app/mobile/views/pages/settings.vue
@@ -6,7 +6,7 @@
 		<ul>
 			<li><router-link to="./settings/profile">%fa:user%%i18n:@profile%%fa:angle-right%</router-link></li>
 			<li><router-link to="./settings/authorized-apps">%fa:puzzle-piece%%i18n:@applications%%fa:angle-right%</router-link></li>
-			<li><router-link to="./settings/twitter">%fa:B twitter%%i18n:@twitter-integration%%fa:angle-right%</router-link></li>
+			<li><router-link to="./settings/twitter">%fa:B twitter%%i18n:@twitter%%fa:angle-right%</router-link></li>
 			<li><router-link to="./settings/signin-history">%fa:sign-in-alt%%i18n:@signin-history%%fa:angle-right%</router-link></li>
 		</ul>
 		<ul>

From 986780a39a1ae83cdcae1874ae0d29e7d2cd0cdc Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 15 Apr 2018 02:51:29 +0900
Subject: [PATCH 07/12] wip

---
 src/build/fa.ts            | 2 +-
 webpack.config.ts          | 6 ++++--
 webpack/loaders/replace.js | 4 ++--
 3 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/build/fa.ts b/src/build/fa.ts
index 0c21be9504..f6f2427d0a 100644
--- a/src/build/fa.ts
+++ b/src/build/fa.ts
@@ -14,7 +14,7 @@ fontawesome.library.add(brands);
 
 export const pattern = /%fa:(.+?)%/g;
 
-export const replacement = (_, key) => {
+export const replacement = (match, key) => {
 	const args = key.split(' ');
 	let prefix = 'fas';
 	const classes = [];
diff --git a/webpack.config.ts b/webpack.config.ts
index 60dbfd2ff7..b0b06c7392 100644
--- a/webpack.config.ts
+++ b/webpack.config.ts
@@ -143,7 +143,8 @@ module.exports = entries.map(x => {
 					loader: 'replace',
 					query: {
 						search: i18nReplacer.pattern.toString(),
-						replace: 'i18nReplacement'
+						replace: 'i18nReplacement',
+						i18n: true
 					}
 				}, {
 					loader: 'replace',
@@ -214,7 +215,8 @@ module.exports = entries.map(x => {
 					loader: 'replace',
 					query: {
 						search: i18nReplacer.pattern.toString(),
-						replace: 'i18nReplacement'
+						replace: 'i18nReplacement',
+						i18n: true
 					}
 				}, {
 					loader: 'replace',
diff --git a/webpack/loaders/replace.js b/webpack/loaders/replace.js
index 8018e9cec2..9897fe37d5 100644
--- a/webpack/loaders/replace.js
+++ b/webpack/loaders/replace.js
@@ -10,9 +10,9 @@ module.exports = function(src) {
 	const search = options.search;
 	const g = search[search.length - 1] == 'g';
 	const file = this.resourcePath.replace(/\\/g, '/');
-	const replace = global[options.replace].bind(null, {
+	const replace = options.i18n ? global[options.replace].bind(null, {
 		src: file
-	});
+	}) : global[options.replace];
 	if (typeof search != 'string' || search.length == 0) console.error('invalid search');
 	if (typeof replace != 'function') console.error('invalid replacer:', replace, this.request);
 	src = src.replace(new RegExp(trim(search, g), g ? 'g' : ''), replace);

From 5a49d142464f42b87e8538579f34795d6a546036 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 15 Apr 2018 02:58:49 +0900
Subject: [PATCH 08/12] wip

---
 src/build/i18n.ts               | 3 +--
 src/client/docs/api/gulpfile.ts | 4 ++--
 src/client/docs/gulpfile.ts     | 2 +-
 3 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/src/build/i18n.ts b/src/build/i18n.ts
index 1fb43a13c9..57d6a20fd0 100644
--- a/src/build/i18n.ts
+++ b/src/build/i18n.ts
@@ -55,8 +55,7 @@ export default class Replacer {
 
 	public replacement(ctx, match, a, b, c) {
 		const client = 'misskey/src/client/app/';
-		const name = ctx.src.substr(ctx.src.indexOf(client) + client.length);
-		if (name == '') return match;
+		const name = ctx ? ctx.src.substr(ctx.src.indexOf(client) + client.length) : null;
 
 		let key = a || b || c;
 		if (key[0] == '@') {
diff --git a/src/client/docs/api/gulpfile.ts b/src/client/docs/api/gulpfile.ts
index 9980ede231..31027c0be3 100644
--- a/src/client/docs/api/gulpfile.ts
+++ b/src/client/docs/api/gulpfile.ts
@@ -127,7 +127,7 @@ gulp.task('doc:api:endpoints', async () => {
 						return;
 					}
 					const i18n = new I18nReplacer(lang);
-					html = html.replace(i18n.pattern, i18n.replacement);
+					html = html.replace(i18n.pattern, i18n.replacement.bind(null, null));
 					html = fa(html);
 					const htmlPath = `./built/client/docs/${lang}/api/endpoints/${ep.endpoint}.html`;
 					mkdirp(path.dirname(htmlPath), (mkdirErr) => {
@@ -171,7 +171,7 @@ gulp.task('doc:api:entities', async () => {
 						return;
 					}
 					const i18n = new I18nReplacer(lang);
-					html = html.replace(i18n.pattern, i18n.replacement);
+					html = html.replace(i18n.pattern, i18n.replacement.bind(null, null));
 					html = fa(html);
 					const htmlPath = `./built/client/docs/${lang}/api/entities/${kebab(entity.name)}.html`;
 					mkdirp(path.dirname(htmlPath), (mkdirErr) => {
diff --git a/src/client/docs/gulpfile.ts b/src/client/docs/gulpfile.ts
index 56bf6188c8..5e81d6d3b5 100644
--- a/src/client/docs/gulpfile.ts
+++ b/src/client/docs/gulpfile.ts
@@ -53,7 +53,7 @@ gulp.task('doc:docs', async () => {
 						return;
 					}
 					const i18n = new I18nReplacer(lang);
-					html = html.replace(i18n.pattern, i18n.replacement);
+					html = html.replace(i18n.pattern, i18n.replacement.bind(null, null));
 					html = fa(html);
 					const htmlPath = `./built/client/docs/${lang}/${name}.html`;
 					mkdirp(path.dirname(htmlPath), (mkdirErr) => {

From f78ae399f2a49379e0790ee07d2d8b8988ea01ef Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 15 Apr 2018 05:22:16 +0900
Subject: [PATCH 09/12] wip

---
 locales/ja.yml                                      | 13 +++++++++----
 src/build/i18n.ts                                   |  5 ++---
 .../app/desktop/views/components/settings.apps.vue  |  2 +-
 .../views/pages/user/user.followers-you-know.vue    |  6 +++---
 .../app/desktop/views/pages/user/user.friends.vue   |  6 +++---
 .../app/desktop/views/pages/user/user.photos.vue    |  6 +++---
 src/client/app/mobile/views/components/timeline.vue |  5 +++--
 src/client/app/mobile/views/pages/settings.vue      |  1 -
 8 files changed, 24 insertions(+), 20 deletions(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index 8787aaad20..597b0f47ec 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -41,13 +41,13 @@ common:
   update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
   my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
 
-common/views/connect-failed.vue:
+common/views/components/connect-failed.vue:
   title: "サーバーに接続できません"
   description: "インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから{再度お試し}ください。"
   thanks: "いつもMisskeyをご利用いただきありがとうございます。"
   troubleshoot: "トラブルシュート"
 
-common/views/connect-failed.troubleshooter.vue:
+common/views/components/connect-failed.troubleshooter.vue:
   title: "トラブルシューティング"
   network: "ネットワーク接続"
   checking-network: "ネットワーク接続を確認中"
@@ -182,11 +182,11 @@ common/views/widgets/server.vue:
   title: "サーバー情報"
   toggle: "表示を切り替え"
 
-common/views/widgets/activity.vue:
+desktop/views/components/activity.vue:
   title: "アクティビティ"
   toggle: "表示を切り替え"
 
-desktop/views/widgets/calendar.vue:
+desktop/views/components/calendar.vue:
   title: "{1}年 {2}月"
   prev: "前の月"
   next: "次の月"
@@ -304,6 +304,7 @@ desktop/views/components/settings.vue:
   password: "パスワード"
   2fa: "二段階認証"
   other: "その他"
+  license: "ライセンス"
 
 desktop/views/components/settings.2fa.vue:
   intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
@@ -331,6 +332,9 @@ desktop/views/components/settings.api.vue:
   regenerate-token: "トークンを再生成"
   enter-password: "パスワードを入力してください"
 
+desktop/views/components/settings.app.vue:
+  no-apps: "連携しているアプリケーションはありません"
+
 desktop/views/components/settings.mute.vue:
   no-users: "ミュートしているユーザーはいません"
 
@@ -557,6 +561,7 @@ mobile/views/pages/selectdrive.vue:
   select-file: "ファイルを選択"
 
 mobile/views/pages/settings.vue:
+  signed-in-as: "{}としてサインイン中"
   profile: "プロフィール"
   twitter: "Twitter連携"
   signin-history: "サインイン履歴"
diff --git a/src/build/i18n.ts b/src/build/i18n.ts
index 57d6a20fd0..35204c34a4 100644
--- a/src/build/i18n.ts
+++ b/src/build/i18n.ts
@@ -55,12 +55,11 @@ export default class Replacer {
 
 	public replacement(ctx, match, a, b, c) {
 		const client = 'misskey/src/client/app/';
-		const name = ctx ? ctx.src.substr(ctx.src.indexOf(client) + client.length) : null;
+		let name = null;
 
 		let key = a || b || c;
 		if (key[0] == '@') {
-			//if (name.startsWith('app/desktop/views/')) prefix = 'desktop.views.';
-			//if (name.startsWith('app/mobile/views/')) prefix = 'mobile.views.';
+			name = ctx.src.substr(ctx.src.indexOf(client) + client.length);
 			key = key.substr(1);
 		}
 
diff --git a/src/client/app/desktop/views/components/settings.apps.vue b/src/client/app/desktop/views/components/settings.apps.vue
index 0503b03abd..7d562f9c11 100644
--- a/src/client/app/desktop/views/components/settings.apps.vue
+++ b/src/client/app/desktop/views/components/settings.apps.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="root">
 	<div class="none ui info" v-if="!fetching && apps.length == 0">
-		<p>%fa:info-circle%%i18n:common.tags.mk-authorized-apps.no-apps%</p>
+		<p>%fa:info-circle%%i18n:@no-apps%</p>
 	</div>
 	<div class="apps" v-if="apps.length != 0">
 		<div v-for="app in apps">
diff --git a/src/client/app/desktop/views/pages/user/user.followers-you-know.vue b/src/client/app/desktop/views/pages/user/user.followers-you-know.vue
index e50f62d968..9ccbc7a310 100644
--- a/src/client/app/desktop/views/pages/user/user.followers-you-know.vue
+++ b/src/client/app/desktop/views/pages/user/user.followers-you-know.vue
@@ -1,13 +1,13 @@
 <template>
 <div class="followers-you-know">
-	<p class="title">%fa:users%%i18n:@followers-you-know.title%</p>
-	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@followers-you-know.loading%<mk-ellipsis/></p>
+	<p class="title">%fa:users%%i18n:@title%</p>
+	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@loading%<mk-ellipsis/></p>
 	<div v-if="!fetching && users.length > 0">
 	<router-link v-for="user in users" :to="user | userPage" :key="user.id">
 		<img :src="`${user.avatarUrl}?thumbnail&size=64`" :alt="user | userName" v-user-preview="user.id"/>
 	</router-link>
 	</div>
-	<p class="empty" v-if="!fetching && users.length == 0">%i18n:@followers-you-know.no-users%</p>
+	<p class="empty" v-if="!fetching && users.length == 0">%i18n:@no-users%</p>
 </div>
 </template>
 
diff --git a/src/client/app/desktop/views/pages/user/user.friends.vue b/src/client/app/desktop/views/pages/user/user.friends.vue
index 12426a26c5..203f936478 100644
--- a/src/client/app/desktop/views/pages/user/user.friends.vue
+++ b/src/client/app/desktop/views/pages/user/user.friends.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="friends">
-	<p class="title">%fa:users%%i18n:@frequently-replied-users.title%</p>
-	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@frequently-replied-users.loading%<mk-ellipsis/></p>
+	<p class="title">%fa:users%%i18n:@title%</p>
+	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@loading%<mk-ellipsis/></p>
 	<template v-if="!fetching && users.length != 0">
 		<div class="user" v-for="friend in users">
 			<router-link class="avatar-anchor" :to="friend | userPage">
@@ -14,7 +14,7 @@
 			<mk-follow-button :user="friend"/>
 		</div>
 	</template>
-	<p class="empty" v-if="!fetching && users.length == 0">%i18n:@frequently-replied-users.no-users%</p>
+	<p class="empty" v-if="!fetching && users.length == 0">%i18n:@no-users%</p>
 </div>
 </template>
 
diff --git a/src/client/app/desktop/views/pages/user/user.photos.vue b/src/client/app/desktop/views/pages/user/user.photos.vue
index d1dfac9d7a..9f749d5cc9 100644
--- a/src/client/app/desktop/views/pages/user/user.photos.vue
+++ b/src/client/app/desktop/views/pages/user/user.photos.vue
@@ -1,13 +1,13 @@
 <template>
 <div class="photos">
-	<p class="title">%fa:camera%%i18n:@photos.title%</p>
-	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@photos.loading%<mk-ellipsis/></p>
+	<p class="title">%fa:camera%%i18n:@title%</p>
+	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@loading%<mk-ellipsis/></p>
 	<div class="stream" v-if="!fetching && images.length > 0">
 		<div v-for="image in images" class="img"
 			:style="`background-image: url(${image.url}?thumbnail&size=256)`"
 		></div>
 	</div>
-	<p class="empty" v-if="!fetching && images.length == 0">%i18n:@photos.no-photos%</p>
+	<p class="empty" v-if="!fetching && images.length == 0">%i18n:@no-photos%</p>
 </div>
 </template>
 
diff --git a/src/client/app/mobile/views/components/timeline.vue b/src/client/app/mobile/views/components/timeline.vue
index 6bc12096cd..12cc7fcf19 100644
--- a/src/client/app/mobile/views/components/timeline.vue
+++ b/src/client/app/mobile/views/components/timeline.vue
@@ -7,7 +7,7 @@
 		</div>
 		<div class="empty" v-if="!fetching && notes.length == 0">
 			%fa:R comments%
-			%i18n:@empty-timeline%
+			%i18n:@empty%
 		</div>
 		<button v-if="!fetching && existMore" @click="more" :disabled="moreFetching" slot="tail">
 			<span v-if="!moreFetching">%i18n:@load-more%</span>
@@ -26,7 +26,8 @@ export default Vue.extend({
 	props: {
 		date: {
 			type: Date,
-			required: false
+			required: false,
+			default: null
 		}
 	},
 	data() {
diff --git a/src/client/app/mobile/views/pages/settings.vue b/src/client/app/mobile/views/pages/settings.vue
index a294bf12a0..36f7f09b84 100644
--- a/src/client/app/mobile/views/pages/settings.vue
+++ b/src/client/app/mobile/views/pages/settings.vue
@@ -5,7 +5,6 @@
 		<p v-html="'%i18n:@signed-in-as%'.replace('{}', '<b>' + name + '</b>')"></p>
 		<ul>
 			<li><router-link to="./settings/profile">%fa:user%%i18n:@profile%%fa:angle-right%</router-link></li>
-			<li><router-link to="./settings/authorized-apps">%fa:puzzle-piece%%i18n:@applications%%fa:angle-right%</router-link></li>
 			<li><router-link to="./settings/twitter">%fa:B twitter%%i18n:@twitter%%fa:angle-right%</router-link></li>
 			<li><router-link to="./settings/signin-history">%fa:sign-in-alt%%i18n:@signin-history%%fa:angle-right%</router-link></li>
 		</ul>

From d3b3a7fc4e54180f4efde00dd06abc474eb0b8ad Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 15 Apr 2018 05:57:30 +0900
Subject: [PATCH 10/12] wip

---
 locales/en.yml                                | 1181 ++++++++---------
 locales/index.ts                              |    2 +-
 locales/ja.yml                                |    4 +-
 .../views/components/messaging-room.form.vue  |    4 +-
 4 files changed, 551 insertions(+), 640 deletions(-)

diff --git a/locales/en.yml b/locales/en.yml
index 900571124f..f24d403652 100644
--- a/locales/en.yml
+++ b/locales/en.yml
@@ -1,5 +1,5 @@
 common:
-  misskey: "Note everything and share it others using Misskey."
+  misskey: "Share everything others using Misskey."
 
   time:
     unknown: "unknown"
@@ -33,155 +33,575 @@ common:
     confused: "Confused"
     pudding: "Pudding"
 
-  note_categories:
-    music: "Music"
-    game: "Video Game"
-    anime: "Anime"
-    it: "IT"
-    gadgets: "Gadgets"
-    photography: "Photography"
-
-  input-message-here: "Enter message here"
-  send: "Send"
   delete: "Delete"
   loading: "Loading"
   ok: "OK"
   update-available: "New version of Misskey is now available({newer}, current is {current}). Reload page to apply update."
   my-token-regenerated: "Your token is just regenerated, so you will signout."
 
-  tags:
-    mk-nav-links:
-      about: "About"
-      stats: "Stats"
-      status: "Status"
-      wiki: "Wiki"
-      donors: "Donors"
-      repository: "Repository"
-      develop: "Developers"
+common/views/components/connect-failed.vue:
+  title: "Unable to connect to the server"
+  description: "There is a problem with Internet connection, or the server may be down or maintaining. Please {try again} later."
+  thanks: "Thank you for using Misskey."
+  troubleshoot: "Troubleshoot"
 
-    mk-messaging-form:
-      attach-from-local: "Attach file from your pc"
-      attach-from-drive: "Attach file from the drive"
+common/views/components/connect-failed.troubleshooter.vue:
+  title: "TroubleShooting"
+  network: "Network connection"
+  checking-network: "Checking network connection"
+  internet: "Internet connection"
+  checking-internet: "Checking internet connection"
+  server: "Server connection"
+  checking-server: "Checking server connection"
+  finding: "Finding a problem"
+  no-network: "There is no Network connection"
+  no-network-desc: "Please make sure you are connected to the Network."
+  no-internet: "There is no Internet connection"
+  no-internet-desc: "Please make sure you are connected to the Internet."
+  no-server: "Unable to connect to the server"
+  no-server-desc: "The network connection of your PC is normal, but you could not connect to Misskey's server. There is a possibility that the server is down or maintaining, please try to access it again after a while."
+  success: "Successfully connect to the Misskey's server"
+  success-desc: "It seems to be able to connect normally. Please reload the page."
 
-    mk-messaging:
-      search-user: "Find a user"
-      you: "You"
-      no-history: "No history"
+common/views/components/messaging.vue:
+  search-user: "Find a user"
+  you: "You"
+  no-history: "No history"
 
-    mk-messaging-message:
-      is-read: "Read"
-      deleted: "This message has been deleted"
+common/views/components/messaging-room.vue:
+  empty: "No conversations"
+  more: "More"
+  no-history: "There is no more history"
+  resize-form: "Drag to resize"
+  new-message: "New message"
 
-    mk-messaging-room:
-      empty: "No conversations"
-      more: "More"
-      no-history: "There is no more history"
-      resize-form: "Drag to resize"
-      new-message: "New message"
+common/views/components/messaging-room.form.vue:
+  input-message-here: "Enter message here"
+  send: "Send"
+  attach-from-local: "Attach file from your pc"
+  attach-from-drive: "Attach file from the drive"
 
-    mk-authorized-apps:
-      no-apps: "No apps"
+common/views/components/messaging-room.message.vue:
+  is-read: "Read"
+  deleted: "This message has been deleted"
 
-    mk-error:
-      title: "Unable to connect to the server"
-      description: "There is a problem with Internet connection, or the server may be down or maintaining. Please {try again} later."
-      thanks: "Thank you for using Misskey."
-      troubleshoot: "Troubleshoot"
+common/views/components/nav.vue:
+  about: "About"
+  stats: "Stats"
+  status: "Status"
+  wiki: "Wiki"
+  donors: "Donors"
+  repository: "Repository"
+  develop: "Developers"
 
-      troubleshooter:
-        title: "TroubleShooting"
-        network: "Network connection"
-        checking-network: "Checking network connection"
-        internet: "Internet connection"
-        checking-internet: "Checking internet connection"
-        server: "Server connection"
-        checking-server: "Checking server connection"
-        finding: "Finding a problem"
-        no-network: "There is no Network connection"
-        no-network-desc: "Please make sure you are connected to the Network."
-        no-internet: "There is no Internet connection"
-        no-internet-desc: "Please make sure you are connected to the Internet."
-        no-server: "Unable to connect to the server"
-        no-server-desc: "The network connection of your PC is normal, but you could not connect to Misskey's server. There is a possibility that the server is down or maintaining, please try to access it again after a while."
-        success: "Successfully connect to the Misskey's server"
-        success-desc: "It seems to be able to connect normally. Please reload the page."
+common/views/components/note-menu.vue:
+  pin: "Pin to profile page"
 
-    mk-forkit:
-      open-github-link: "View source on Github"
+common/views/components/poll.vue:
+  vote-to: "Vote to 「{}」"
+  vote-count: "{} votes"
+  total-users: "{} users voted"
+  vote: "Vote"
+  show-result: "Show result"
+  voted: "Voted"
 
-    mk-poll-editor:
-      no-only-one-choice: "You need to enter two or more choice."
-      choice-n: "Choice {}"
-      remove: "Remove this choice"
-      add: "+ Add a choice"
-      destroy: "Destroy this poll"
+common/views/components/poll-editor.vue:
+  no-only-one-choice: "You need to enter two or more choice."
+  choice-n: "Choice {}"
+  remove: "Remove this choice"
+  add: "+ Add a choice"
+  destroy: "Destroy this poll"
 
-    mk-poll:
-      vote-to: "Vote to 「{}」"
-      vote-count: "{} votes"
-      total-users: "{} users voted"
-      vote: "Vote"
-      show-result: "Show result"
-      voted: "Voted"
+common/views/components/reaction-picker.vue:
+  choose-reaction: "Pick your reaction"
 
-    mk-note-menu:
-      pin: "Pin"
-      pinned: "Pinned"
-      select: "Select category"
-      categorize: "Accept"
-      categorized: "Category reported. Thank you!"
+common/views/components/signin.vue:
+  username: "Username"
+  password: "Password"
+  token: "Token"
+  signing-in: "Signing in..."
+  signin: "Sign in"
 
-    mk-reaction-picker:
-      choose-reaction: "Pick your reaction"
+common/views/components/signup.vue:
+  username: "Username"
+  checking: "Checking..."
+  available: "Available"
+  unavailable: "Unavailable"
+  error: "Network error"
+  invalid-format: "Only use letters, numbers and -."
+  too-short: "Please enter at least 1 letters!"
+  too-long: "Please enter within 20 letters."
+  password: "Password"
+  password-placeholder: "We recommend more than 8 letters."
+  weak-password: "Weak"
+  normal-password: "So so"
+  strong-password: "Strong"
+  retype: "Type again"
+  retype-placeholder: "Confirm your password"
+  password-matched: "OK"
+  password-not-matched: "Not matched"
+  recaptcha: "Verify"
+  create: "Create an Account"
+  some-error: "Account creation failed for some reason. Please try again."
 
-    mk-signin:
-      username: "Username"
-      password: "Password"
-      token: "Token"
-      signing-in: "Signing in..."
-      signin: "Sign in"
+common/views/components/special-message.vue:
+  new-year: "Happy New Year!"
+  christmas: "Merry Christmas!"
 
-    mk-signup:
-      username: "Username"
-      checking: "Checking..."
-      available: "Available"
-      unavailable: "Unavailable"
-      error: "Network error"
-      invalid-format: "Only use letters, numbers and -."
-      too-short: "Please enter at least 3 letters!"
-      too-long: "Please enter within 20 letters."
-      password: "Password"
-      password-placeholder: "We recommend more than 8 letters."
-      weak-password: "Weak"
-      normal-password: "So so"
-      strong-password: "Strong"
-      retype: "Type again"
-      retype-placeholder: "Confirm your password"
-      password-matched: "OK"
-      password-not-matched: "Not matched"
-      recaptcha: "Verify"
-      create: "Create an Account"
-      some-error: "Account creation failed for some reason. Please try again."
+common/views/components/stream-indicator.vue:
+  connecting: "Connecting"
+  reconnecting: "Reconnecting"
+  connected: "Connected"
 
-    mk-special-message:
-      new-year: "Happy New Year!"
-      christmas: "Merry Christmas!"
+common/views/components/twitter-setting.vue:
+  description: "お使いのTwitterアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでTwitterアカウント情報が表示されるようになったり、Twitterを用いた便利なサインインを利用できるようになります。"
+  connected-to: "You to connected this Twitter account"
+  detail: "Detail..."
+  reconnect: "Reconnect"
+  connect: "Connect to Twitter"
+  disconnect: "Disconnect"
 
-    mk-stream-indicator:
-      connecting: "Connecting"
-      reconnecting: "Reconnecting"
-      connected: "Connected"
+common/views/components/uploader.vue:
+  waiting: "Waiting"
 
-    mk-twitter-setting:
-      description: "お使いのTwitterアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでTwitterアカウント情報が表示されるようになったり、Twitterを用いた便利なサインインを利用できるようになります。"
-      connected-to: "You to connected this Twitter account"
-      detail: "Detail..."
-      reconnect: "Reconnect"
-      connect: "Connect to Twitter"
-      disconnect: "Disconnect"
+common/views/widgets/broadcast.vue:
+  fetching: "Fetching"
+  no-broadcasts: "No broadcasts"
+  have-a-nice-day: "Have a nice day!"
+  next: "Next"
 
-    mk-uploader:
-      waiting: "Waiting"
+common/views/widgets/donation.vue:
+  title: "Donation"
+  text: "To manage Misskey we spend money for our domain server etc.. There's no incomes for us so we need your tip. If you're interested contact {}. Thank you for your contribution!"
+
+common/views/widgets/photo-stream.vue:
+  title: "Photostream"
+  no-photos: "No photos"
+
+common/views/widgets/server.vue:
+  title: "Server info"
+  toggle: "Toggle views"
+
+desktop/views/components/activity.vue:
+  title: "Activity"
+  toggle: "Toggle views"
+
+desktop/views/components/calendar.vue:
+  title: "{1} / {2}"
+  prev: "Previous month"
+  next: "Next month"
+  go: "Click to travel"
+
+desktop/views/components/drive-window.vue:
+  used: "used"
+  drive: "Drive"
+
+desktop/views/components/drive.file.vue:
+  avatar: "Avatar"
+  banner: "Banner"
+  contextmenu:
+    rename: "Rename"
+    copy-url: "Copy URL"
+    download: "Download"
+    else-files: "その他..."
+    set-as-avatar: "Set as avatar"
+    set-as-banner: "Set as banner"
+    open-in-app: "Open in app"
+    add-app: "Add app"
+    rename-file: "Rename file"
+    input-new-file-name: "Enter new name"
+    copied: "Copied"
+    copied-url-to-clipboard: "Copied URL to clipboard"
+
+desktop/views/components/drive.folder.vue:
+  unable-to-process: "操作を完了できません"
+  circular-reference-detected: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。"
+  unhandled-error: "Unknown error"
+  contextmenu:
+    move-to-this-folder: "Move to this folder"
+    show-in-new-window: "Open in new window"
+    rename: "Rename"
+    rename-folder: "Rename folder"
+    input-new-folder-name: "Enter new name"
+
+desktop/views/components/drive.nav-folder.vue:
+  drive: "Drive"
+
+desktop/views/components/drive.vue:
+  search: "Search"
+  load-more: "Load more"
+  empty-draghover: "Drop Welcome!"
+  empty-drive: "Your drive is empty"
+  empty-drive-description: "右クリックして「ファイルをアップロード」を選んだり、ファイルをドラッグ&ドロップすることでもアップロードできます。"
+  empty-folder: "This folder is empty"
+  unable-to-process: "操作を完了できません"
+  circular-reference-detected: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。"
+  unhandled-error: "Unknown error"
+  url-upload: "Upload from a URL"
+  url-of-file: "URL of file you want to upload"
+  url-upload-requested: "Upload requested"
+  may-take-time: "アップロードが完了するまで時間がかかる場合があります。"
+  create-folder: "Create a folder"
+  folder-name: "Folder name"
+  contextmenu:
+    create-folder: "Create a folder"
+    upload: "Upload a file"
+    url-upload: "Upload from a URL"
+
+desktop/views/components/notes.note.vue:
+  reposted-by: "Reposted by {}"
+  reply: "Reply"
+  renote: "Renote"
+  add-reaction: "Add your reaction"
+  detail: "Show detail"
+
+desktop/views/components/notifications.vue:
+  more: "More"
+
+desktop/views/components/post-form.vue:
+  note-placeholder: "What's happening?"
+  reply-placeholder: "Reply to this note..."
+  quote-placeholder: "Quote this note..."
+  note: "Post"
+  reply: "Reply"
+  renote: "Renote"
+  posted: "Posted!"
+  replied: "Replied!"
+  reposted: "Reposted!"
+  note-failed: "Failed to note"
+  reply-failed: "Failed to reply"
+  renote-failed: "Failed to renote"
+  posting: "Posting"
+  attach-media-from-local: "Attach media from your pc"
+  attach-media-from-drive: "Attach media from the drive"
+  attach-cancel: "Cancel attachment"
+  insert-a-kao: "v(‘ω’)v"
+  create-poll: "Create a poll"
+  text-remain: "{} chars remaining"
+
+desktop/views/components/post-form-window.vue:
+  note: "New note"
+  reply: "Reply"
+  attaches: "{} media attached"
+  uploading-media: "Uploading {} media"
+
+desktop/views/components/renote-form.vue:
+  quote: "Quote..."
+  cancel: "Cancel"
+  renote: "Renote"
+  reposting: "Reposting..."
+  success: "Reposted!"
+  failure: "Failed to Renote"
+
+desktop/views/components/renote-form-window.vue:
+  title: "Are you sure you want to renote this note?"
+
+desktop/views/components/settings.vue:
+  profile: "Profile"
+  mute: "Mute"
+  drive: "Drive"
+  security: "Security"
+  password: "Password"
+  2fa: "Two-factor authentication"
+  other: "Other"
+  license: "License"
+
+desktop/views/components/settings.2fa.vue:
+  intro: "If you set up 2-step verification, you will need not only a password at sign-in but also a pre-registered physical device (such as your smartphone), which will improve security. "
+  detail: "See details..."
+  url: "https://www.google.com/landing/2step/"
+  caution: "As a caveat, security improves, but you can not sign in to Misskey if you lose a registered device, etc."
+  register: "Register a device"
+  already-registered: "The setting has already been completed."
+  unregister: "Disable"
+  unregistered: "Two-step authentication has been disabled."
+  enter-password: "Enter the password"
+  authenticator: "First, you need install Google Authenticator to your device:"
+  howtoinstall: "How to install"
+  scan: "Next, please scan displayed QR code:"
+  done: "Please enter the token displaying in your device:"
+  submit: "Submit"
+  success: "Setup completed successfully!"
+  failed: "Failed to setup. please ensure that the token is correct."
+  info: "From the next sign in, enter the token that is displayed on the device in addition to the password."
+
+desktop/views/components/settings.api.vue:
+  intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
+  caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
+  regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
+  regenerate-token: "Regenerate the token"
+  enter-password: "Please enter the password"
+
+desktop/views/components/settings.app.vue:
+  no-apps: "No authorized apps"
+
+desktop/views/components/settings.mute.vue:
+  no-users: "No muted users"
+
+desktop/views/components/settings.password.vue:
+  reset: "Change your password"
+  enter-current-password: "Enter the current password"
+  enter-new-password: "Enter the new password"
+  enter-new-password-again: "Enter the new password again"
+  not-match: "New password not matched"
+  changed: "Password updated successfully"
+
+desktop/views/components/settings.profile.vue:
+  avatar: "Avatar"
+  choice-avatar: "Choice an image"
+  name: "Name"
+  location: "Location"
+  description: "Description"
+  birthday: "Birthday"
+  save: "Update profile"
+
+desktop/views/components/ui.header.account.vue:
+  profile: "Your profile"
+  drive: "Drive"
+  mentions: "Mentions"
+  customize: "Customize"
+  settings: "Settings"
+  signout: "Sign out"
+
+desktop/views/components/ui.header.nav.vue:
+  home: "Home"
+  messaging: "Messages"
+  game: "Game"
+
+desktop/views/components/ui.header.notifications.vue:
+  title: "Notifications"
+
+desktop/views/components/ui.header.post.vue:
+  post: "Compose new Post"
+
+desktop/views/components/ui.header.search.vue:
+  placeholder: "Search"
+
+desktop/views/pages/note.vue:
+  prev: "Previous note"
+  next: "Next note"
+
+desktop/views/pages/selectdrive.vue:
+  title: "Choose a file(s)"
+  ok: "OK"
+  cancel: "Cancel"
+  upload: "Upload a file(s) from you PC"
+
+desktop/views/pages/user/user.followers-you-know.vue:
+  title: "Followers you know"
+  loading: "Loading"
+  no-users: "No users"
+
+desktop/views/pages/user/user.friends.vue:
+  title: "Frequently replied"
+  loading: "Loading"
+  no-users: "No users"
+
+desktop/views/pages/user/user.home.vue:
+  last-used-at: "Last used at"
+
+desktop/views/pages/user/user.photos.vue:
+  title: "Photos"
+  loading: "Loading"
+  no-photos: "No photos"
+
+desktop/views/pages/user/user.profile.vue:
+  follows-you: "Follows you"
+  mute: "Mute"
+  muted: "Muting"
+  unmute: "Unmute"
+
+desktop/views/widgets/messaging.vue:
+  title: "Messaging"
+
+desktop/views/widgets/notifications.vue:
+  title: "Notifications"
+  settings: "Settings"
+
+desktop/views/widgets/polls.vue:
+  title: "Polls"
+  refresh: "Show others"
+  nothing: "Nothing"
+
+desktop/views/widgets/post-form.vue:
+  title: "Post"
+  note: "Post"
+  placeholder: "What's happening?"
+
+desktop/views/widgets/trends.vue:
+  title: "Trend"
+  refresh: "Show others"
+  nothing: "Nothing"
+
+desktop/views/widgets/users.vue:
+  title: "Recommended users"
+  refresh: "Show others"
+  no-one: "No one"
+
+desktop/views/widgets/channel.vue:
+  title: "Channel"
+  settings: "Widget settings"
+  get-started: "Please click the cog in the upper right to specify the channel to receive"
+
+mobile/views/components/drive.vue:
+  drive: "Drive"
+  used: "used"
+  folder-count: "Folder(s)"
+  count-separator: ", "
+  file-count: "File(s)"
+  load-more: "Load more"
+  nothing-in-drive: "Nothing"
+  folder-is-empty: "This folder is empty"
+
+mobile/views/components/drive-file-chooser.vue:
+  select-file: "Choose a file"
+
+mobile/views/components/drive-folder-chooser.vue:
+  select-folder: "Choose a folder"
+
+mobile/views/components/drive.file-detail.vue:
+  download: "Download"
+  rename: "Rename"
+  move: "Move"
+  hash: "Hash (md5)"
+  exif: "EXIF"
+
+mobile/views/components/follow-button.vue:
+  follow: "Follow"
+  unfollow: "Unfollow"
+
+mobile/views/components/note.vue:
+  reposted-by: "Renoted by {}"
+
+mobile/views/components/note-detail.vue:
+  reply: "Reply"
+  reaction: "Reaction"
+
+mobile/views/components/notifications.vue:
+  more: "More"
+  empty: "No notifications"
+
+mobile/views/components/post-form.vue:
+  submit: "Post"
+  reply-placeholder: "Reply to this note..."
+  note-placeholder: "What's happening?"
+
+mobile/views/components/sub-note-content.vue:
+  media-count: "{} media"
+  poll: "Poll"
+
+mobile/views/components/timeline.vue:
+  empty: "No notes"
+  load-more: "More"
+
+mobile/views/components/ui.nav.vue:
+  home: "Home"
+  notifications: "Notifications"
+  messaging: "Messages"
+  drive: "Drive"
+  settings: "Settings"
+  about: "About Misskey"
+  search: "Search"
+
+mobile/views/components/user-timeline.vue:
+  no-notes: "This user seems never note"
+  no-notes-with-media: "There is no notes with media"
+  load-more: "More"
+
+mobile/views/components/users-list.vue:
+  all: "All"
+  known: "You know"
+  load-more: "More"
+
+mobile/views/pages/drive.vue:
+  drive: "Drive"
+
+mobile/views/pages/followers.vue:
+  followers-of: "Followers of {}"
+
+mobile/views/pages/following.vue:
+  following-of: "Following of {}"
+
+mobile/views/pages/messaging.vue:
+  messaging: "Messaging"
+
+mobile/views/pages/messaging-room.vue:
+  messaging: "Messaging"
+
+mobile/views/pages/note.vue:
+  title: "Post"
+  prev: "Previous note"
+  next: "Next note"
+
+mobile/views/pages/notifications.vue:
+  notifications: "Notifications"
+  read-all: "Are you sure you want to mark all unread notifications as read?"
+
+mobile/views/pages/profile-setting.vue:
+  title: "Profile settings"
+  will-be-published: "These profiles will be published."
+  name: "Name"
+  location: "Location"
+  description: "Description"
+  birthday: "Birthday"
+  avatar: "Avatar"
+  banner: "Banner"
+  avatar-saved: "Avatar updated successfully"
+  banner-saved: "Banner updated successfully"
+  set-avatar: "Choose an avatar"
+  set-banner: "Choose a banner"
+  save: "Save"
+  saved: "Profile updated successfully"
+
+mobile/views/pages/search.vue:
+  search: "Search"
+  empty: "「{}」に関する投稿は見つかりませんでした。"
+
+mobile/views/pages/selectdrive.vue:
+  select-file: "Choose a file"
+
+mobile/views/pages/settings.vue:
+  signed-in-as: "Signed in as {}"
+  profile: "Profile"
+  twitter-integration: "Twitter integration"
+  signin-history: "Sign in history"
+  settings: "Settings"
+  signout: "Sign out"
+
+mobile/views/pages/user.vue:
+  follows-you: "Follows you"
+  following: "Following"
+  followers: "Followers"
+  notes: "Posts"
+  overview: "Overview"
+  timeline: "Timeline"
+  media: "Media"
+
+mobile/views/pages/user/home.vue:
+  recent-notes: "Recent notes"
+  images: "Images"
+  activity: "Activity"
+  keywords: "Keywords"
+  domains: "Domains"
+  frequently-replied-users: "Frequently talking users"
+  followers-you-know: "Followers you know"
+  last-used-at: "Last used at"
+
+mobile/views/pages/user/home.followers-you-know.vue:
+  loading: "Loading"
+  no-users: "No users"
+
+mobile/views/pages/user/home.friends.vue:
+  loading: "Loading"
+  no-users: "No users"
+
+mobile/views/pages/user/home.notes.vue:
+  loading: "Loading"
+  no-notes: "No notes"
+
+mobile/views/pages/user/home.photos.vue:
+  loading: "Loading"
+  no-photos: "No photos"
 
 docs:
   edit-this-page-on-github: "Caught a mistake or want to contribute to the documentation? "
@@ -200,512 +620,3 @@ docs:
       description: "Description"
       yes: "Yes"
       no: "No"
-
-ch:
-  tags:
-    mk-index:
-      new: "Create new channel"
-      channel-title: "Channel title"
-
-    mk-channel-form:
-      textarea: "Write here"
-      upload: "Upload"
-      drive: "Drive"
-      note: "Do"
-      posting: "Doing"
-
-desktop:
-  tags:
-    mk-api-info:
-      intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
-      caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
-      regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
-      regenerate-token: "Regenerate the token"
-      enter-password: "Please enter the password"
-
-    mk-drive-browser-base-contextmenu:
-      create-folder: "Create a folder"
-      upload: "Upload a file"
-      url-upload: "Upload from a URL"
-
-    mk-drive-browser-window:
-      used: "used"
-      drive: "Drive"
-
-    mk-drive-browser:
-      search: "Search"
-      load-more: "Load more"
-      empty-draghover: "Drop Welcome!"
-      empty-drive: "Your drive is empty"
-      empty-drive-description: "右クリックして「ファイルをアップロード」を選んだり、ファイルをドラッグ&ドロップすることでもアップロードできます。"
-      empty-folder: "This folder is empty"
-      unable-to-process: "操作を完了できません"
-      circular-reference-detected: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。"
-      unhandled-error: "Unknown error"
-      url-upload: "Upload from a URL"
-      url-of-file: "URL of file you want to upload"
-      url-upload-requested: "Upload requested"
-      may-take-time: "アップロードが完了するまで時間がかかる場合があります。"
-      create-folder: "Create a folder"
-      folder-name: "Folder name"
-
-    mk-drive-browser-file-contextmenu:
-      rename: "Rename"
-      copy-url: "Copy URL"
-      download: "Download"
-      else-files: "その他..."
-      set-as-avatar: "Set as avatar"
-      set-as-banner: "Set as banner"
-      open-in-app: "Open in app"
-      add-app: "Add app"
-      rename-file: "Rename file"
-      input-new-file-name: "Enter new name"
-      copied: "Copied"
-      copied-url-to-clipboard: "Copied URL to clipboard"
-
-    mk-drive-browser-file:
-      avatar: "Avatar"
-      banner: "Banner"
-
-    mk-drive-browser-folder-contextmenu:
-      move-to-this-folder: "Move to this folder"
-      show-in-new-window: "Open in new window"
-      rename: "Rename"
-      rename-folder: "Rename folder"
-      input-new-folder-name: "Enter new name"
-
-    mk-drive-browser-folder:
-      unable-to-process: "操作を完了できません"
-      circular-reference-detected: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。"
-      unhandled-error: "Unknown error"
-
-    mk-drive-browser-nav-folder:
-      drive: "Drive"
-
-    mk-selectdrive-page:
-      title: "Choose a file(s)"
-      ok: "OK"
-      cancel: "Cancel"
-      upload: "Upload a file(s) from you PC"
-
-    mk-ui-header-nav:
-      home: "Home"
-      messaging: "Messages"
-      ch: "Channels"
-      info: "News"
-
-    mk-ui-header-search:
-      placeholder: "Search"
-
-    mk-ui-header-account:
-      profile: "Your profile"
-      drive: "Drive"
-      mentions: "Mentions"
-      settings: "Settings"
-      signout: "Sign out"
-
-    mk-ui-header-note-button:
-      note: "Compose new Post"
-
-    mk-ui-header-notifications:
-      title: "Notifications"
-
-    mk-profile-setting:
-      avatar: "Avatar"
-      choice-avatar: "Choice an image"
-      name: "Name"
-      location: "Location"
-      description: "Description"
-      birthday: "Birthday"
-      save: "Update profile"
-
-    mk-password-setting:
-      reset: "Change your password"
-      enter-current-password: "Enter the current password"
-      enter-new-password: "Enter the new password"
-      enter-new-password-again: "Enter the new password again"
-      not-match: "New password not matched"
-      changed: "Password updated successfully"
-
-    mk-2fa-setting:
-      intro: "If you set up 2-step verification, you will need not only a password at sign-in but also a pre-registered physical device (such as your smartphone), which will improve security. "
-      detail: "See details..."
-      url: "https://www.google.com/landing/2step/"
-      caution: "As a caveat, security improves, but you can not sign in to Misskey if you lose a registered device, etc."
-      register: "Register a device"
-      already-registered: "The setting has already been completed."
-      unregister: "Disable"
-      unregistered: "Two-step authentication has been disabled."
-      enter-password: "Enter the password"
-      authenticator: "First, you need install Google Authenticator to your device:"
-      howtoinstall: "How to install"
-      scan: "Next, please scan displayed QR code:"
-      done: "Please enter the token displaying in your device:"
-      submit: "Submit"
-      success: "Setup completed successfully!"
-      failed: "Failed to setup. please ensure that the token is correct."
-      info: "From the next sign in, enter the token that is displayed on the device in addition to the password."
-
-    mk-mute-setting:
-      no-users: "No muted users"
-
-    mk-post-form:
-      note-placeholder: "What's happening?"
-      reply-placeholder: "Reply to this note..."
-      quote-placeholder: "Quote this note..."
-      note: "Post"
-      reply: "Reply"
-      renote: "Renote"
-      posted: "Posted!"
-      replied: "Replied!"
-      reposted: "Reposted!"
-      note-failed: "Failed to note"
-      reply-failed: "Failed to reply"
-      renote-failed: "Failed to renote"
-      posting: "Posting"
-      attach-media-from-local: "Attach media from your pc"
-      attach-media-from-drive: "Attach media from the drive"
-      attach-cancel: "Cancel attachment"
-      insert-a-kao: "v(‘ω’)v"
-      create-poll: "Create a poll"
-      text-remain: "{} chars remaining"
-
-    mk-post-form-window:
-      note: "New note"
-      reply: "Reply"
-      attaches: "{} media attached"
-      uploading-media: "Uploading {} media"
-
-    mk-note-page:
-      prev: "Previous note"
-      next: "Next note"
-
-    mk-settings:
-      profile: "Profile"
-      mute: "Mute"
-      drive: "Drive"
-      security: "Security"
-      password: "Password"
-      2fa: "Two-factor authentication"
-      other: "Other"
-      license: "License"
-
-    mk-timeline-note:
-      reposted-by: "Reposted by {}"
-      reply: "Reply"
-      renote: "Renote"
-      add-reaction: "Add your reaction"
-      detail: "Show detail"
-
-    mk-notifications:
-      more: "More"
-
-    mk-notifications-home-widget:
-      title: "Notifications"
-      settings: "Notification settings"
-
-    mk-server-home-widget:
-      title: "Server info"
-      toggle: "Toggle views"
-
-    mk-activity-widget:
-      title: "Activity"
-      toggle: "Toggle views"
-
-    mk-user-recommendation-home-widget:
-      title: "Recommended users"
-      refresh: "Show others"
-      no-one: "No one"
-
-    mk-recommended-polls-home-widget:
-      title: "Polls"
-      refresh: "Show others"
-      nothing: "Nothing"
-
-    mk-trends-home-widget:
-      title: "Trend"
-      refresh: "Show others"
-      nothing: "Nothing"
-
-    mk-photo-stream-home-widget:
-      title: "Photostream"
-      no-photos: "No photos"
-
-    mk-donation-home-widget:
-      title: "Donation"
-      text: "To manage Misskey we spend money for our domain server etc.. There's no incomes for us so we need your tip. If you're interested contact {}. Thank you for your contribution!"
-
-    mk-channel-home-widget:
-      title: "Channel"
-      settings: "Widget settings"
-      get-started: "Please click the cog in the upper right to specify the channel to receive"
-
-    mk-calendar-widget:
-      title: "{1} / {2}"
-      prev: "Previous month"
-      next: "Next month"
-      go: "Click to travel"
-
-    mk-post-form-home-widget:
-      title: "Post"
-      note: "Post"
-      placeholder: "What's happening?"
-
-    mk-access-log-home-widget:
-      title: "Access log"
-
-    mk-messaging-home-widget:
-      title: "Messaging"
-
-    mk-broadcast-home-widget:
-      fetching: "Fetching"
-      no-broadcasts: "No broadcasts"
-      have-a-nice-day: "Have a nice day!"
-      next: "Next"
-
-    mk-renote-form:
-      quote: "Quote..."
-      cancel: "Cancel"
-      renote: "Renote"
-      reposting: "Reposting..."
-      success: "Reposted!"
-      failure: "Failed to Renote"
-
-    mk-renote-form-window:
-      title: "Are you sure you want to renote this note?"
-
-    mk-user:
-      last-used-at: "Last used at"
-
-      follows-you: "Follows you"
-      mute: "Mute"
-      muted: "Muting"
-      unmute: "Unmute"
-
-      photos:
-        title: "Photos"
-        loading: "Loading"
-        no-photos: "No photos"
-
-      frequently-replied-users:
-        title: "Frequently replied"
-        loading: "Loading"
-        no-users: "No users"
-
-      followers-you-know:
-        title: "Followers you know"
-        loading: "Loading"
-        no-users: "No users"
-
-mobile:
-  tags:
-    mk-selectdrive-page:
-      select-file: "Select file(s)"
-
-    mk-drive-file-viewer:
-      download: "Download"
-      rename: "Rename"
-      move: "Move"
-      hash: "Hash (md5)"
-      exif: "EXIF"
-
-    mk-entrance-signin:
-      signup: "Sign up"
-      about: "About Misskey"
-
-    mk-entrance-signup:
-      cancel: "Cancel"
-
-    mk-authorized-apps-page:
-      application: "Applications"
-
-    mk-signin-history-page:
-      signin-history: "Sign in history"
-
-    mk-twitter-setting-page:
-      twitter-integration: "Twitter integration"
-
-    mk-drive-page:
-      drive: "Drive"
-
-    mk-home:
-      home: "Home"
-
-    mk-messaging-room-page:
-      message: "Messaging"
-
-    mk-messaging-page:
-      message: "Messaging"
-
-    mk-notifications-page:
-      notifications: "Notifications"
-      read-all: "Are you sure you want to mark all unread notifications as read?"
-
-    mk-note-page:
-      title: "Post"
-      prev: "Previous note"
-      next: "Next note"
-
-    mk-search-page:
-      search: "Search"
-
-    mk-settings:
-      signed-in-as: "Signed in as {}"
-
-    mk-settings-page:
-      profile: "Profile"
-      applications: "Applications"
-      twitter-integration: "Twitter integration"
-      signin-history: "Sign in history"
-      link: "MisskeyLink"
-      settings: "Settings"
-      signout: "Sign out"
-
-    mk-profile-setting-page:
-      title: "Profile Settings"
-
-    mk-profile-setting:
-      will-be-published: "These profiles will be published."
-      name: "Name"
-      location: "Location"
-      description: "Description"
-      birthday: "Birthday"
-      avatar: "Avatar"
-      banner: "Banner"
-      avatar-saved: "Avatar updated successfully"
-      banner-saved: "Banner updated successfully"
-      set-avatar: "Choose an avatar"
-      set-banner: "Choose a banner"
-      save: "Save"
-      saved: "Profile updated successfully"
-
-    mk-user-followers-page:
-      followers-of: "Followers of {}"
-
-    mk-user-following-page:
-      following-of: "Following of {}"
-
-    mk-drive-folder-selector:
-      select-folder: "Choose a folder"
-
-    mk-drive-selector:
-      select-file: "Choose a file"
-
-    mk-drive:
-      drive: "Drive"
-      used: "used"
-      folder-count: "Folder(s)"
-      count-separator: ", "
-      file-count: "File(s)"
-      load-more: "Load more"
-      nothing-in-drive: "Nothing"
-      folder-is-empty: "This folder is empty"
-
-    mk-follow-button:
-      follow: "Follow"
-      unfollow: "Unfollow"
-
-    mk-home-timeline:
-      empty-timeline: "There is no notes"
-
-    mk-notifications:
-      more: "More"
-      empty: "No notifications"
-
-    mk-note-detail:
-      reply: "Reply"
-      reaction: "Reaction"
-
-    mk-post-form:
-      submit: "Post"
-      reply-placeholder: "Reply to this note..."
-      note-placeholder: "What's happening?"
-
-    mk-search-notes:
-      empty: "There is no note related to the 「{}」"
-
-    mk-sub-note-content:
-      media-count: "{} media"
-      poll: "Poll"
-
-    mk-timeline-note:
-      reposted-by: "Reposted by {}"
-
-    mk-timeline:
-      empty: "No notes"
-      load-more: "More"
-
-    mk-ui-nav:
-      home: "Home"
-      notifications: "Notifications"
-      messaging: "Messages"
-      ch: "Channels"
-      drive: "Drive"
-      settings: "Settings"
-      about: "About Misskey"
-      search: "Search"
-
-    mk-user-followers:
-      no-users: "No followers."
-
-    mk-user-following:
-      no-users: "No following."
-
-    mk-user-timeline:
-      no-notes: "This user seems never note"
-      no-notes-with-media: "There is no notes with media"
-      load-more: "More"
-
-    mk-user:
-      follows-you: "Follows you"
-      following: "Following"
-      followers: "Followers"
-      notes: "Posts"
-      overview: "Overview"
-      timeline: "Timeline"
-      media: "Media"
-
-    mk-user-overview:
-      recent-notes: "Recent notes"
-      images: "Images"
-      activity: "Activity"
-      keywords: "Keywords"
-      domains: "Domains"
-      frequently-replied-users: "Frequently talking users"
-      followers-you-know: "Followers you know"
-      last-used-at: "Last used at"
-
-    mk-user-overview-notes:
-      loading: "Loading"
-      no-notes: "No notes"
-
-    mk-user-overview-photos:
-      loading: "Loading"
-      no-photos: "No photos"
-
-    mk-user-overview-keywords:
-      no-keywords: "No keywords"
-
-    mk-user-overview-domains:
-      no-domains: "No domains"
-
-    mk-user-overview-frequently-replied-users:
-      loading: "Loading"
-      no-users: "No users"
-
-    mk-user-overview-followers-you-know:
-      loading: "Loading"
-      no-users: "No users"
-
-    mk-users-list:
-      all: "All"
-      known: "You know"
-      load-more: "More"
-
-stats:
-  notes-count: "Number of all notes"
-  users-count: "Number of all users"
-
-status:
-  all-systems-maybe-operational: "All systems maybe operational"
-  what-is-this-site: ""
diff --git a/locales/index.ts b/locales/index.ts
index ced3b4cb32..0593af366c 100644
--- a/locales/index.ts
+++ b/locales/index.ts
@@ -11,7 +11,7 @@ const loadLang = lang => yaml.safeLoad(
 const native = loadLang('ja');
 
 const langs = {
-	//'en': loadLang('en'),
+	'en': loadLang('en'),
 	'ja': native
 };
 
diff --git a/locales/ja.yml b/locales/ja.yml
index 597b0f47ec..7e253d3688 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -33,8 +33,6 @@ common:
     confused: "こまこまのこまり"
     pudding: "Pudding"
 
-  input-message-here: "ここにメッセージを入力"
-  send: "送信"
   delete: "削除"
   loading: "読み込み中"
   ok: "わかった"
@@ -78,6 +76,8 @@ common/views/components/messaging-room.vue:
   new-message: "新しいメッセージがあります"
 
 common/views/components/messaging-room.form.vue:
+  input-message-here: "ここにメッセージを入力"
+  send: "送信"
   attach-from-local: "PCからファイルを添付する"
   attach-from-drive: "ドライブからファイルを添付する"
 
diff --git a/src/client/app/common/views/components/messaging-room.form.vue b/src/client/app/common/views/components/messaging-room.form.vue
index 1c7b68a266..32a43ace57 100644
--- a/src/client/app/common/views/components/messaging-room.form.vue
+++ b/src/client/app/common/views/components/messaging-room.form.vue
@@ -8,12 +8,12 @@
 		ref="textarea"
 		@keypress="onKeypress"
 		@paste="onPaste"
-		placeholder="%i18n:common.input-message-here%"
+		placeholder="%i18n:@input-message-here%"
 		v-autocomplete="'text'"
 	></textarea>
 	<div class="file" @click="file = null" v-if="file">{{ file.name }}</div>
 	<mk-uploader ref="uploader" @uploaded="onUploaded"/>
-	<button class="send" @click="send" :disabled="!canSend || sending" title="%i18n:common.send%">
+	<button class="send" @click="send" :disabled="!canSend || sending" title="%i18n:@send%">
 		<template v-if="!sending">%fa:paper-plane%</template><template v-if="sending">%fa:spinner .spin%</template>
 	</button>
 	<button class="attach-from-local" @click="chooseFile" title="%i18n:@attach-from-local%">

From a53746e9d07a7089947480b1893eb829c0560a28 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 15 Apr 2018 06:16:50 +0900
Subject: [PATCH 11/12] :v:

---
 src/build/i18n.ts          | 2 ++
 src/client/app/boot.js     | 8 +++-----
 webpack.config.ts          | 8 +++++---
 webpack/loaders/replace.js | 3 ++-
 4 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/src/build/i18n.ts b/src/build/i18n.ts
index 35204c34a4..2790191191 100644
--- a/src/build/i18n.ts
+++ b/src/build/i18n.ts
@@ -63,6 +63,8 @@ export default class Replacer {
 			key = key.substr(1);
 		}
 
+		if (ctx && ctx.lang) this.lang = ctx.lang;
+
 		if (match[0] == '"') {
 			return '"' + this.get(name, key).replace(/"/g, '\\"') + '"';
 		} else if (match[0] == "'") {
diff --git a/src/client/app/boot.js b/src/client/app/boot.js
index 2675fa233a..12b0d220a9 100644
--- a/src/client/app/boot.js
+++ b/src/client/app/boot.js
@@ -31,11 +31,9 @@
 
 	// Detect the user language
 	// Note: The default language is Japanese
-	//let lang = navigator.language.split('-')[0];
-	//if (!/^(en|ja)$/.test(lang)) lang = 'ja';
-	//if (localStorage.getItem('lang')) lang = localStorage.getItem('lang');
-	//if (ENV != 'production') lang = 'ja';
-	const lang = 'ja';
+	let lang = navigator.language.split('-')[0];
+	if (!/^(en|ja)$/.test(lang)) lang = 'ja';
+	if (localStorage.getItem('lang')) lang = localStorage.getItem('lang');
 
 	// Detect the user agent
 	const ua = navigator.userAgent.toLowerCase();
diff --git a/webpack.config.ts b/webpack.config.ts
index b0b06c7392..bc876e067d 100644
--- a/webpack.config.ts
+++ b/webpack.config.ts
@@ -42,7 +42,7 @@ const langs = Object.keys(locales);
 
 const entries = process.env.NODE_ENV == 'production'
 	? langs.map(l => [l, false]).concat(langs.map(l => [l, true]))
-	: [['ja', false]];
+	: langs.map(l => [l, false]);
 
 module.exports = entries.map(x => {
 	const [lang, isProduction] = x;
@@ -144,7 +144,8 @@ module.exports = entries.map(x => {
 					query: {
 						search: i18nReplacer.pattern.toString(),
 						replace: 'i18nReplacement',
-						i18n: true
+						i18n: true,
+						lang
 					}
 				}, {
 					loader: 'replace',
@@ -216,7 +217,8 @@ module.exports = entries.map(x => {
 					query: {
 						search: i18nReplacer.pattern.toString(),
 						replace: 'i18nReplacement',
-						i18n: true
+						i18n: true,
+						lang
 					}
 				}, {
 					loader: 'replace',
diff --git a/webpack/loaders/replace.js b/webpack/loaders/replace.js
index 9897fe37d5..0326dcdab3 100644
--- a/webpack/loaders/replace.js
+++ b/webpack/loaders/replace.js
@@ -11,7 +11,8 @@ module.exports = function(src) {
 	const g = search[search.length - 1] == 'g';
 	const file = this.resourcePath.replace(/\\/g, '/');
 	const replace = options.i18n ? global[options.replace].bind(null, {
-		src: file
+		src: file,
+		lang: options.lang
 	}) : global[options.replace];
 	if (typeof search != 'string' || search.length == 0) console.error('invalid search');
 	if (typeof replace != 'function') console.error('invalid replacer:', replace, this.request);

From 7ced7db866851e62956d397b87f793f6d048a426 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 15 Apr 2018 06:21:19 +0900
Subject: [PATCH 12/12] :pizza:

---
 locales/en.yml                                            | 1 +
 locales/ja.yml                                            | 1 +
 src/client/app/desktop/views/components/notifications.vue | 2 +-
 3 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/locales/en.yml b/locales/en.yml
index f24d403652..94c5e8ec3a 100644
--- a/locales/en.yml
+++ b/locales/en.yml
@@ -257,6 +257,7 @@ desktop/views/components/notes.note.vue:
 
 desktop/views/components/notifications.vue:
   more: "More"
+  empty: "No notifications"
 
 desktop/views/components/post-form.vue:
   note-placeholder: "What's happening?"
diff --git a/locales/ja.yml b/locales/ja.yml
index 7e253d3688..e7c03f9ddf 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -257,6 +257,7 @@ desktop/views/components/notes.note.vue:
 
 desktop/views/components/notifications.vue:
   more: "もっと見る"
+  empty: "ありません!"
 
 desktop/views/components/post-form.vue:
   note-placeholder: "いまどうしてる?"
diff --git a/src/client/app/desktop/views/components/notifications.vue b/src/client/app/desktop/views/components/notifications.vue
index 9b1a66dde5..c1d4c561e8 100644
--- a/src/client/app/desktop/views/components/notifications.vue
+++ b/src/client/app/desktop/views/components/notifications.vue
@@ -95,7 +95,7 @@
 	<button class="more" :class="{ fetching: fetchingMoreNotifications }" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications">
 		<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }}
 	</button>
-	<p class="empty" v-if="notifications.length == 0 && !fetching">ありません!</p>
+	<p class="empty" v-if="notifications.length == 0 && !fetching">%i18n:@empty%</p>
 	<p class="loading" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
 </div>
 </template>