0
0

Refactoring of i18n (#3165)

Refactoring of i18n
This commit is contained in:
syuilo 2018-11-09 03:44:35 +09:00 committed by GitHub
parent 21303bd06a
commit 25a69ec1b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
211 changed files with 1825 additions and 1624 deletions

View File

@ -25,6 +25,7 @@ common:
application-authorization: "アプリの連携" application-authorization: "アプリの連携"
close: "閉じる" close: "閉じる"
do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。" do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
load-more: "もっと読み込む"
BSoD: BSoD:
fatal-error: ":( 致命的な問題が発生しました。" fatal-error: ":( 致命的な問題が発生しました。"
update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。" update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。"
@ -37,10 +38,7 @@ common:
got-it: "わかった" got-it: "わかった"
customization-tips: customization-tips:
title: "カスタマイズのヒント" title: "カスタマイズのヒント"
paragraph1: "ホームのカスタマイズでは、ウィジェットを追加/削除したり、ドラッグ&ドロップして並べ替えたりすることができます。" paragraph: "<p>ホームのカスタマイズでは、ウィジェットを追加/削除したり、ドラッグ&ドロップして並べ替えたりすることができます。</p><p>一部のウィジェットは、<strong><strong>右</strong>クリック</strong>することで表示を変更することができます。</p><p>ウィジェットを削除するには、ヘッダーの<strong>「ゴミ箱」</strong>と書かれたエリアにウィジェットをドラッグ&ドロップします。</p><p>カスタマイズを終了するには、右上の「完了」をクリックします。</p>"
paragraph2: "一部のウィジェットは、<strong><strong>右</strong>クリック</strong>することで表示を変更することができます。"
paragraph3: "ウィジェットを削除するには、ヘッダーの<strong>「ゴミ箱」</strong>と書かれたエリアにウィジェットをドラッグ&ドロップします。"
paragraph4: "カスタマイズを終了するには、右上の「完了」をクリックします。"
gotit: "Got it!" gotit: "Got it!"
notification: notification:
file-uploaded: "ファイルがアップロードされました" file-uploaded: "ファイルがアップロードされました"
@ -65,6 +63,7 @@ common:
trash: "ゴミ箱" trash: "ゴミ箱"
drive: "ドライブ" drive: "ドライブ"
messaging: "トーク"
weekday-short: weekday-short:
sunday: "日" sunday: "日"
@ -147,13 +146,13 @@ common:
drawn: "引き分け" drawn: "引き分け"
my-turn: "あなたのターンです" my-turn: "あなたのターンです"
opponent-turn: "相手のターンです" opponent-turn: "相手のターンです"
turn-of: "{}のターンです" turn-of: "{name}のターンです"
past-turn-of: "{}のターン" past-turn-of: "{name}のターン"
won: "{}の勝ち" won: "{name}の勝ち"
black: "黒" black: "黒"
white: "白" white: "白"
total: "合計" total: "合計"
this-turn: "{}ターン目" this-turn: "{count}ターン目"
widgets: widgets:
analog-clock: "アナログ時計" analog-clock: "アナログ時計"
@ -173,34 +172,12 @@ common:
users: "おすすめユーザー" users: "おすすめユーザー"
polls: "アンケート" polls: "アンケート"
post-form: "投稿フォーム" post-form: "投稿フォーム"
messaging: "メッセージ"
server: "サーバー情報" server: "サーバー情報"
donation: "寄付のお願い" donation: "寄付のお願い"
nav: "ナビゲーション" nav: "ナビゲーション"
tips: "ヒント" tips: "ヒント"
hashtags: "ハッシュタグ" hashtags: "ハッシュタグ"
deck:
widgets: "ウィジェット"
home: "ホーム"
local: "ローカル"
hybrid: "ソーシャル"
hashtag: "ハッシュタグ"
global: "グローバル"
mentions: "あなた宛て"
direct: "ダイレクト投稿"
notifications: "通知"
list: "リスト"
swap-left: "左に移動"
swap-right: "右に移動"
swap-up: "上に移動"
swap-down: "下に移動"
remove: "カラムを削除"
add-column: "カラムを追加"
rename: "名前を変更"
stack-left: "左に重ねる"
pop-right: "右に出す"
dev: "アプリの作成に失敗しました。再度お試しください。" dev: "アプリの作成に失敗しました。再度お試しください。"
ai-chan-kawaii: "藍ちゃかわいい" ai-chan-kawaii: "藍ちゃかわいい"
@ -354,7 +331,6 @@ common/views/components/messaging.vue:
common/views/components/messaging-room.vue: common/views/components/messaging-room.vue:
empty: "このユーザーと話したことはありません" empty: "このユーザーと話したことはありません"
more: "もっと読む"
no-history: "これより過去の履歴はありません" no-history: "これより過去の履歴はありません"
resize-form: "ドラッグしてフォームの広さを調整" resize-form: "ドラッグしてフォームの広さを調整"
new-message: "新しいメッセージがあります" new-message: "新しいメッセージがあります"
@ -604,13 +580,13 @@ desktop/views/components/activity.vue:
toggle: "表示を切り替え" toggle: "表示を切り替え"
desktop/views/components/calendar.vue: desktop/views/components/calendar.vue:
title: "{1}年 {2}月" title: "{year}年 {month}月"
prev: "前の月" prev: "前の月"
next: "次の月" next: "次の月"
go: "クリックして時間遡行" go: "クリックして時間遡行"
desktop/views/components/choose-file-from-drive-window.vue: desktop/views/components/choose-file-from-drive-window.vue:
choose-file: "ファイル選択中" chosen-files: "{count}ファイル選択中"
upload: "PCからドライブにファイルをアップロード" upload: "PCからドライブにファイルをアップロード"
cancel: "キャンセル" cancel: "キャンセル"
ok: "決定" ok: "決定"
@ -662,7 +638,6 @@ desktop/views/components/drive.folder.vue:
desktop/views/components/drive.vue: desktop/views/components/drive.vue:
search: "検索" search: "検索"
load-more: "もっと読み込む"
empty-draghover: "ドロップですか?いいですよ、ボクはカワイイですからね" empty-draghover: "ドロップですか?いいですよ、ボクはカワイイですからね"
empty-drive: "ドライブには何もありません。" empty-drive: "ドライブには何もありません。"
empty-drive-description: "右クリックして「ファイルをアップロード」を選んだり、ファイルをドラッグ&ドロップすることでもアップロードできます。" empty-drive-description: "右クリックして「ファイルをアップロード」を選んだり、ファイルをドラッグ&ドロップすることでもアップロードできます。"
@ -734,7 +709,6 @@ desktop/views/components/messaging-window.vue:
title: "メッセージ" title: "メッセージ"
desktop/views/components/note-detail.vue: desktop/views/components/note-detail.vue:
more: "会話をもっと読み込む"
private: "この投稿は非公開です" private: "この投稿は非公開です"
deleted: "この投稿は削除されました" deleted: "この投稿は削除されました"
reposted-by: "{}がRenote" reposted-by: "{}がRenote"
@ -754,10 +728,8 @@ desktop/views/components/note.vue:
desktop/views/components/notes.vue: desktop/views/components/notes.vue:
error: "読み込みに失敗しました。" error: "読み込みに失敗しました。"
retry: "リトライ" retry: "リトライ"
load-more: "もっと読み込む"
desktop/views/components/notifications.vue: desktop/views/components/notifications.vue:
more: "もっと見る"
empty: "ありません!" empty: "ありません!"
desktop/views/components/post-form.vue: desktop/views/components/post-form.vue:
@ -1019,7 +991,6 @@ desktop/views/components/ui.header.account.vue:
desktop/views/components/ui.header.nav.vue: desktop/views/components/ui.header.nav.vue:
home: "ホーム" home: "ホーム"
deck: "デッキ" deck: "デッキ"
messaging: "メッセージ"
game: "ゲーム" game: "ゲーム"
desktop/views/components/ui.header.notifications.vue: desktop/views/components/ui.header.notifications.vue:
@ -1049,7 +1020,6 @@ desktop/views/components/user-preview.vue:
desktop/views/components/users-list.vue: desktop/views/components/users-list.vue:
all: "すべて" all: "すべて"
iknow: "知り合い" iknow: "知り合い"
load-more: "もっと"
fetching: "読み込んでいます" fetching: "読み込んでいます"
desktop/views/components/users-list-item.vue: desktop/views/components/users-list-item.vue:
@ -1196,21 +1166,6 @@ admin/views/announcements.vue:
admin/views/hashtags.vue: admin/views/hashtags.vue:
hided-tags: "Hidden Tags" hided-tags: "Hidden Tags"
desktop/views/pages/deck/deck.tl-column.vue:
is-media-only: "メディア投稿のみ"
is-media-view: "メディアビュー"
edit: "オプション"
desktop/views/pages/deck/deck.user-column.vue:
posts: "投稿"
following: "フォロー"
followers: "フォロワー"
images: "画像"
activity: "アクティビティ"
timeline: "タイムライン"
pinned-notes: "ピン留めされた投稿"
push-to-a-list: "リストに追加"
desktop/views/pages/welcome.vue: desktop/views/pages/welcome.vue:
about: "詳しく..." about: "詳しく..."
gotit: "わかった" gotit: "わかった"
@ -1227,9 +1182,6 @@ desktop/views/pages/welcome.vue:
desktop/views/pages/drive.vue: desktop/views/pages/drive.vue:
title: "Misskey Drive" title: "Misskey Drive"
desktop/views/pages/favorites.vue:
more: "さらに読み込む"
desktop/views/pages/home-customize.vue: desktop/views/pages/home-customize.vue:
title: "ホームのカスタマイズ" title: "ホームのカスタマイズ"
@ -1245,13 +1197,13 @@ desktop/views/pages/selectdrive.vue:
desktop/views/pages/search.vue: desktop/views/pages/search.vue:
not-available: "検索機能はインスタンスの設定で無効になっています。" not-available: "検索機能はインスタンスの設定で無効になっています。"
not-found: "「{}」に関する投稿は見つかりませんでした。" not-found: "「{q}」に関する投稿は見つかりませんでした。"
desktop/views/pages/share.vue: desktop/views/pages/share.vue:
share-with: "{}で共有" share-with: "{name}で共有"
desktop/views/pages/tag.vue: desktop/views/pages/tag.vue:
no-posts-found: "ハッシュタグ「{}」が付けられた投稿は見つかりませんでした。" no-posts-found: "ハッシュタグ「{q}」が付けられた投稿は見つかりませんでした。"
desktop/views/pages/user-list.users.vue: desktop/views/pages/user-list.users.vue:
users: "ユーザー" users: "ユーザー"
@ -1268,10 +1220,6 @@ desktop/views/pages/user/user.friends.vue:
loading: "読み込み中" loading: "読み込み中"
no-users: "よく話すユーザーはいません" no-users: "よく話すユーザーはいません"
desktop/views/pages/user/user.vue:
is-suspended: "このユーザーは凍結されています。"
last-used-at: "最終アクセス"
desktop/views/pages/user/user.photos.vue: desktop/views/pages/user/user.photos.vue:
title: "フォト" title: "フォト"
loading: "読み込み中" loading: "読み込み中"
@ -1342,7 +1290,6 @@ mobile/views/components/drive.vue:
folder-count: "フォルダ" folder-count: "フォルダ"
count-separator: "、" count-separator: "、"
file-count: "ファイル" file-count: "ファイル"
load-more: "もっと読み込む"
nothing-in-drive: "ドライブには何もありません" nothing-in-drive: "ドライブには何もありません"
folder-is-empty: "このフォルダは空です" folder-is-empty: "このフォルダは空です"
prompt: "何をしますか?(数字を入力してください): <1 → ファイルをアップロード | 2 → ファイルをURLでアップロード | 3 → フォルダ作成 | 4 → このフォルダ名を変更 | 5 → このフォルダを移動 | 6 → このフォルダを削除>" prompt: "何をしますか?(数字を入力してください): <1 → ファイルをアップロード | 2 → ファイルをURLでアップロード | 3 → フォルダ作成 | 4 → このフォルダ名を変更 | 5 → このフォルダを移動 | 6 → このフォルダを削除>"
@ -1353,9 +1300,6 @@ mobile/views/components/drive.vue:
url-prompt: "アップロードしたいファイルのURL" url-prompt: "アップロードしたいファイルのURL"
uploading: "アップロードをリクエストしました。アップロードが完了するまで時間がかかる場合があります。" uploading: "アップロードをリクエストしました。アップロードが完了するまで時間がかかる場合があります。"
mobile/views/components/drive-file-detail.vue:
rename: "名前を変更"
mobile/views/components/drive-file-chooser.vue: mobile/views/components/drive-file-chooser.vue:
select-file: "ファイルを選択" select-file: "ファイルを選択"
@ -1421,12 +1365,7 @@ mobile/views/components/note-sub.vue:
bot: "bot" bot: "bot"
cat: "cat" cat: "cat"
mobile/views/components/notes.vue:
failed: "読み込みに失敗しました。"
retry: "リトライ"
mobile/views/components/notifications.vue: mobile/views/components/notifications.vue:
more: "もっと見る"
empty: "ありません!" empty: "ありません!"
mobile/views/components/post-form.vue: mobile/views/components/post-form.vue:
@ -1449,7 +1388,6 @@ mobile/views/components/sub-note-content.vue:
mobile/views/components/timeline.vue: mobile/views/components/timeline.vue:
empty: "投稿がありません" empty: "投稿がありません"
load-more: "もっと"
mobile/views/components/ui.header.vue: mobile/views/components/ui.header.vue:
welcome-back: "おかえりなさい、" welcome-back: "おかえりなさい、"
@ -1458,7 +1396,6 @@ mobile/views/components/ui.header.vue:
mobile/views/components/ui.nav.vue: mobile/views/components/ui.nav.vue:
timeline: "タイムライン" timeline: "タイムライン"
notifications: "通知" notifications: "通知"
messaging: "メッセージ"
follow-requests: "フォロー申請" follow-requests: "フォロー申請"
search: "検索" search: "検索"
favorites: "お気に入り" favorites: "お気に入り"
@ -1473,12 +1410,10 @@ mobile/views/components/ui.nav.vue:
mobile/views/components/user-timeline.vue: mobile/views/components/user-timeline.vue:
no-notes: "このユーザーは投稿していないようです。" no-notes: "このユーザーは投稿していないようです。"
no-notes-with-media: "メディア付き投稿はありません。" no-notes-with-media: "メディア付き投稿はありません。"
load-more: "もっと"
mobile/views/components/users-list.vue: mobile/views/components/users-list.vue:
all: "すべて" all: "すべて"
known: "知り合い" known: "知り合い"
load-more: "もっと"
mobile/views/pages/favorites.vue: mobile/views/pages/favorites.vue:
title: "お気に入り" title: "お気に入り"
@ -1487,17 +1422,14 @@ mobile/views/pages/user-lists.vue:
title: "リスト" title: "リスト"
enter-list-name: "リスト名を入力してください" enter-list-name: "リスト名を入力してください"
mobile/views/pages/drive.vue:
more: "もっと見る"
mobile/views/pages/signup.vue: mobile/views/pages/signup.vue:
lets-start: "📦 始めましょう" lets-start: "📦 始めましょう"
mobile/views/pages/followers.vue: mobile/views/pages/followers.vue:
followers-of: "{}のフォロワー" followers-of: "{name}のフォロワー"
mobile/views/pages/following.vue: mobile/views/pages/following.vue:
following-of: "{}のフォロー" following-of: "{name}のフォロー"
mobile/views/pages/home.vue: mobile/views/pages/home.vue:
home: "ホーム" home: "ホーム"
@ -1508,7 +1440,7 @@ mobile/views/pages/home.vue:
messages: "メッセージ" messages: "メッセージ"
mobile/views/pages/tag.vue: mobile/views/pages/tag.vue:
no-posts-found: "ハッシュタグ「{}」が付けられた投稿は見つかりませんでした。" no-posts-found: "ハッシュタグ「{q}」が付けられた投稿は見つかりませんでした。"
mobile/views/pages/welcome.vue: mobile/views/pages/welcome.vue:
signup: "新規登録" signup: "新規登録"
@ -1523,13 +1455,7 @@ mobile/views/pages/widgets/activity.vue:
activity: "アクティビティ" activity: "アクティビティ"
mobile/views/pages/share.vue: mobile/views/pages/share.vue:
share-with: "{}で共有" share-with: "{name}で共有"
mobile/views/pages/messaging.vue:
messaging: "メッセージ"
mobile/views/pages/messaging-room.vue:
messaging: "メッセージ"
mobile/views/pages/received-follow-requests.vue: mobile/views/pages/received-follow-requests.vue:
title: "フォロー申請" title: "フォロー申請"
@ -1550,8 +1476,7 @@ mobile/views/pages/games/reversi.vue:
mobile/views/pages/search.vue: mobile/views/pages/search.vue:
search: "検索" search: "検索"
empty: "「{}」に関する投稿は見つかりませんでした。" not-found: "「{q}」に関する投稿は見つかりませんでした。"
not-found: "「{}」に関する投稿は見つかりませんでした。"
mobile/views/pages/selectdrive.vue: mobile/views/pages/selectdrive.vue:
select-file: "ファイルを選択" select-file: "ファイルを選択"
@ -1637,21 +1562,53 @@ mobile/views/pages/user/home.vue:
last-used-at: "最終ログイン" last-used-at: "最終ログイン"
mobile/views/pages/user/home.followers-you-know.vue: mobile/views/pages/user/home.followers-you-know.vue:
loading: "読み込み中"
no-users: "知り合いのユーザーはいません" no-users: "知り合いのユーザーはいません"
mobile/views/pages/user/home.friends.vue: mobile/views/pages/user/home.friends.vue:
loading: "読み込み中"
no-users: "よく会話するユーザーはいません" no-users: "よく会話するユーザーはいません"
mobile/views/pages/user/home.notes.vue: mobile/views/pages/user/home.notes.vue:
loading: "読み込み中"
no-notes: "投稿はありません" no-notes: "投稿はありません"
mobile/views/pages/user/home.photos.vue: mobile/views/pages/user/home.photos.vue:
loading: "読み込み中"
no-photos: "写真はありません" no-photos: "写真はありません"
deck:
widgets: "ウィジェット"
home: "ホーム"
local: "ローカル"
hybrid: "ソーシャル"
hashtag: "ハッシュタグ"
global: "グローバル"
mentions: "あなた宛て"
direct: "ダイレクト投稿"
notifications: "通知"
list: "リスト"
swap-left: "左に移動"
swap-right: "右に移動"
swap-up: "上に移動"
swap-down: "下に移動"
remove: "カラムを削除"
add-column: "カラムを追加"
rename: "名前を変更"
stack-left: "左に重ねる"
pop-right: "右に出す"
deck/deck.tl-column.vue:
is-media-only: "メディア投稿のみ"
is-media-view: "メディアビュー"
edit: "オプション"
deck/deck.user-column.vue:
posts: "投稿"
following: "フォロー"
followers: "フォロワー"
images: "画像"
activity: "アクティビティ"
timeline: "タイムライン"
pinned-notes: "ピン留めされた投稿"
push-to-a-list: "リストに追加"
docs: docs:
edit-this-page-on-github: "間違いや改善点を見つけましたか?" edit-this-page-on-github: "間違いや改善点を見つけましたか?"
edit-this-page-on-github-link: "このページをGitHubで編集" edit-this-page-on-github-link: "このページをGitHubで編集"

View File

@ -1,30 +1,32 @@
<template> <template>
<div class="cdeuzmsthagexbkpofbmatmugjuvogfb"> <div class="cdeuzmsthagexbkpofbmatmugjuvogfb">
<ui-card> <ui-card>
<div slot="title"><fa icon="broadcast-tower"/> %i18n:@announcements%</div> <div slot="title"><fa icon="broadcast-tower"/> {{ $t('announcements') }}</div>
<section v-for="(announcement, i) in announcements" class="fit-top"> <section v-for="(announcement, i) in announcements" class="fit-top">
<ui-input v-model="announcement.title" @change="save"> <ui-input v-model="announcement.title" @change="save">
<span>%i18n:@title%</span> <span>{{ $t('title') }}</span>
</ui-input> </ui-input>
<ui-textarea v-model="announcement.text"> <ui-textarea v-model="announcement.text">
<span>%i18n:@text%</span> <span>{{ $t('text') }}</span>
</ui-textarea> </ui-textarea>
<ui-horizon-group> <ui-horizon-group>
<ui-button @click="save()"><fa :icon="['far', 'save']"/> %i18n:@save%</ui-button> <ui-button @click="save()"><fa :icon="['far', 'save']"/> {{ $t('save') }}</ui-button>
<ui-button @click="remove(i)"><fa :icon="['far', 'trash-alt']"/> %i18n:@remove%</ui-button> <ui-button @click="remove(i)"><fa :icon="['far', 'trash-alt']"/> {{ $t('remove') }}</ui-button>
</ui-horizon-group> </ui-horizon-group>
</section> </section>
<section> <section>
<ui-button @click="add"><fa icon="plus"/> %i18n:@add%</ui-button> <ui-button @click="add"><fa icon="plus"/> {{ $t('add') }}</ui-button>
</section> </section>
</ui-card> </ui-card>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from "vue"; import Vue from 'vue';
import i18n from '../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('admin/views/announcements.vue'),
data() { data() {
return { return {
announcements: [], announcements: [],
@ -48,7 +50,7 @@ export default Vue.extend({
remove(i) { remove(i) {
this.$swal({ this.$swal({
type: 'warning', type: 'warning',
text: '%i18n:@_remove.are-you-sure%'.replace('$1', this.announcements.find((_, j) => j == i).title), text: this.$t('_remove.are-you-sure').replace('$1', this.announcements.find((_, j) => j == i).title),
showCancelButton: true showCancelButton: true
}).then(res => { }).then(res => {
if (!res.value) return; if (!res.value) return;
@ -56,7 +58,7 @@ export default Vue.extend({
this.save(true); this.save(true);
this.$swal({ this.$swal({
type: 'success', type: 'success',
text: '%i18n:@_remove.removed%' text: this.$t('_remove.removed')
}); });
}); });
}, },
@ -68,7 +70,7 @@ export default Vue.extend({
if (!silent) { if (!silent) {
this.$swal({ this.$swal({
type: 'success', type: 'success',
text: '%i18n:@saved%' text: this.$t('saved')
}); });
} }
}).catch(e => { }).catch(e => {

View File

@ -1,36 +1,36 @@
<template> <template>
<div class="qvgidhudpqhjttdhxubzuyrhyzgslujw"> <div class="qvgidhudpqhjttdhxubzuyrhyzgslujw">
<header> <header>
<b><fa :icon="['far', 'chart-bar']"/> %i18n:@title%:</b> <b><fa :icon="['far', 'chart-bar']"/> {{ $t('title') }}:</b>
<select v-model="src"> <select v-model="src">
<optgroup label="%i18n:@federation%"> <optgroup :label="$t('label')">
<option value="federation-instances">%i18n:@charts.federation-instances%</option> <option value="federation-instances">{{ $t('charts.federation-instances') }}</option>
<option value="federation-instances-total">%i18n:@charts.federation-instances-total%</option> <option value="federation-instances-total">{{ $t('charts.federation-instances-total') }}</option>
</optgroup> </optgroup>
<optgroup label="%i18n:@users%"> <optgroup :label="$t('label')">
<option value="users">%i18n:@charts.users%</option> <option value="users">{{ $t('charts.users') }}</option>
<option value="users-total">%i18n:@charts.users-total%</option> <option value="users-total">{{ $t('charts.users-total') }}</option>
</optgroup> </optgroup>
<optgroup label="%i18n:@notes%"> <optgroup :label="$t('label')">
<option value="notes">%i18n:@charts.notes%</option> <option value="notes">{{ $t('charts.notes') }}</option>
<option value="local-notes">%i18n:@charts.local-notes%</option> <option value="local-notes">{{ $t('charts.local-notes') }}</option>
<option value="remote-notes">%i18n:@charts.remote-notes%</option> <option value="remote-notes">{{ $t('charts.remote-notes') }}</option>
<option value="notes-total">%i18n:@charts.notes-total%</option> <option value="notes-total">{{ $t('charts.notes-total') }}</option>
</optgroup> </optgroup>
<optgroup label="%i18n:@drive%"> <optgroup :label="$t('label')">
<option value="drive-files">%i18n:@charts.drive-files%</option> <option value="drive-files">{{ $t('charts.drive-files') }}</option>
<option value="drive-files-total">%i18n:@charts.drive-files-total%</option> <option value="drive-files-total">{{ $t('charts.drive-files-total') }}</option>
<option value="drive">%i18n:@charts.drive%</option> <option value="drive">{{ $t('charts.drive') }}</option>
<option value="drive-total">%i18n:@charts.drive-total%</option> <option value="drive-total">{{ $t('charts.drive-total') }}</option>
</optgroup> </optgroup>
<optgroup label="%i18n:@network%"> <optgroup :label="$t('label')">
<option value="network-requests">%i18n:@charts.network-requests%</option> <option value="network-requests">{{ $t('charts.network-requests') }}</option>
<option value="network-time">%i18n:@charts.network-time%</option> <option value="network-time">{{ $t('charts.network-time') }}</option>
<option value="network-usage">%i18n:@charts.network-usage%</option> <option value="network-usage">{{ $t('charts.network-usage') }}</option>
</optgroup> </optgroup>
</select> </select>
<div> <div>
<span @click="span = 'day'" :class="{ active: span == 'day' }">%i18n:@per-day%</span> | <span @click="span = 'hour'" :class="{ active: span == 'hour' }">%i18n:@per-hour%</span> <span @click="span = 'day'" :class="{ active: span == 'day' }">{{ $t('per-day') }}</span> | <span @click="span = 'hour'" :class="{ active: span == 'hour' }">{{ $t('per-hour') }}</span>
</div> </div>
</header> </header>
<div ref="chart"></div> <div ref="chart"></div>
@ -39,6 +39,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../i18n';
import * as tinycolor from 'tinycolor2'; import * as tinycolor from 'tinycolor2';
import * as ApexCharts from 'apexcharts'; import * as ApexCharts from 'apexcharts';
@ -48,6 +49,7 @@ const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b));
const negate = arr => arr.map(x => -x); const negate = arr => arr.map(x => -x);
export default Vue.extend({ export default Vue.extend({
i18n: i18n('admin/views/charts.vue'),
data() { data() {
return { return {
chart: null, chart: null,

View File

@ -5,7 +5,7 @@
<p><b>Machine</b><span>{{ meta.machine }}</span></p> <p><b>Machine</b><span>{{ meta.machine }}</span></p>
<p><b>OS</b><span>{{ meta.os }}</span></p> <p><b>OS</b><span>{{ meta.os }}</span></p>
<p><b>Node</b><span>{{ meta.node }}</span></p> <p><b>Node</b><span>{{ meta.node }}</span></p>
<p>%i18n:common.ai-chan-kawaii%</p> <p>{{ $t('@.ai-chan-kawaii') }}</p>
</header> </header>
<div v-if="stats" class="stats"> <div v-if="stats" class="stats">
@ -13,12 +13,12 @@
<div> <div>
<div><fa icon="user"/></div> <div><fa icon="user"/></div>
<div> <div>
<span>%i18n:@accounts%</span> <span>{{ $t('accounts') }}</span>
<b class="primary">{{ stats.originalUsersCount | number }}</b> <b class="primary">{{ stats.originalUsersCount | number }}</b>
</div> </div>
</div> </div>
<div> <div>
<span><fa icon="home"/> %i18n:@this-instance%</span> <span><fa icon="home"/> {{ $t('this-instance') }}</span>
<span @click="setChartSrc('users')"><fa :icon="['far', 'chart-bar']"/></span> <span @click="setChartSrc('users')"><fa :icon="['far', 'chart-bar']"/></span>
</div> </div>
</div> </div>
@ -26,12 +26,12 @@
<div> <div>
<div><fa icon="pencil-alt"/></div> <div><fa icon="pencil-alt"/></div>
<div> <div>
<span>%i18n:@notes%</span> <span>{{ $t('notes') }}</span>
<b class="primary">{{ stats.originalNotesCount | number }}</b> <b class="primary">{{ stats.originalNotesCount | number }}</b>
</div> </div>
</div> </div>
<div> <div>
<span><fa icon="home"/> %i18n:@this-instance%</span> <span><fa icon="home"/> {{ $t('this-instance') }}</span>
<span @click="setChartSrc('notes')"><fa :icon="['far', 'chart-bar']"/></span> <span @click="setChartSrc('notes')"><fa :icon="['far', 'chart-bar']"/></span>
</div> </div>
</div> </div>
@ -39,12 +39,12 @@
<div> <div>
<div><fa icon="database"/></div> <div><fa icon="database"/></div>
<div> <div>
<span>%i18n:@drive%</span> <span>{{ $t('drive') }}</span>
<b>{{ stats.driveUsageLocal | bytes }}</b> <b>{{ stats.driveUsageLocal | bytes }}</b>
</div> </div>
</div> </div>
<div> <div>
<span><fa icon="home"/> %i18n:@this-instance%</span> <span><fa icon="home"/> {{ $t('this-instance') }}</span>
<span @click="setChartSrc('drive')"><fa :icon="['far', 'chart-bar']"/></span> <span @click="setChartSrc('drive')"><fa :icon="['far', 'chart-bar']"/></span>
</div> </div>
</div> </div>
@ -52,12 +52,12 @@
<div> <div>
<div><fa :icon="['far', 'hdd']"/></div> <div><fa :icon="['far', 'hdd']"/></div>
<div> <div>
<span>%i18n:@instances%</span> <span>{{ $t('instances') }}</span>
<b>{{ stats.instances | number }}</b> <b>{{ stats.instances | number }}</b>
</div> </div>
</div> </div>
<div> <div>
<span><fa icon="globe"/> %i18n:@federated%</span> <span><fa icon="globe"/> {{ $t('federated') }}</span>
<span @click="setChartSrc('federation-instances-total')"><fa :icon="['far', 'chart-bar']"/></span> <span @click="setChartSrc('federation-instances-total')"><fa :icon="['far', 'chart-bar']"/></span>
</div> </div>
</div> </div>
@ -78,12 +78,14 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from "vue"; import Vue from 'vue';
import i18n from '../../i18n';
import XCpuMemory from "./cpu-memory.vue"; import XCpuMemory from "./cpu-memory.vue";
import XCharts from "./charts.vue"; import XCharts from "./charts.vue";
import XApLog from "./ap-log.vue"; import XApLog from "./ap-log.vue";
export default Vue.extend({ export default Vue.extend({
i18n: i18n('admin/views/dashboard.vue'),
components: { components: {
XCpuMemory, XCpuMemory,
XCharts, XCharts,

View File

@ -1,46 +1,46 @@
<template> <template>
<div class="tumhkfkmgtvzljezfvmgkeurkfncshbe"> <div class="tumhkfkmgtvzljezfvmgkeurkfncshbe">
<ui-card> <ui-card>
<div slot="title"><fa icon="plus"/> %i18n:@add-emoji.title%</div> <div slot="title"><fa icon="plus"/> {{ $t('add-emoji.title') }}</div>
<section class="fit-top"> <section class="fit-top">
<ui-horizon-group inputs> <ui-horizon-group inputs>
<ui-input v-model="name"> <ui-input v-model="name">
<span>%i18n:@add-emoji.name%</span> <span>{{ $t('add-emoji.name') }}</span>
<span slot="desc">%i18n:@add-emoji.name-desc%</span> <span slot="desc">{{ $t('add-emoji.name-desc') }}</span>
</ui-input> </ui-input>
<ui-input v-model="aliases"> <ui-input v-model="aliases">
<span>%i18n:@add-emoji.aliases%</span> <span>{{ $t('add-emoji.aliases') }}</span>
<span slot="desc">%i18n:@add-emoji.aliases-desc%</span> <span slot="desc">{{ $t('add-emoji.aliases-desc') }}</span>
</ui-input> </ui-input>
</ui-horizon-group> </ui-horizon-group>
<ui-input v-model="url"> <ui-input v-model="url">
<i slot="icon"><fa icon="link"/></i> <i slot="icon"><fa icon="link"/></i>
<span>%i18n:@add-emoji.url%</span> <span>{{ $t('add-emoji.url') }}</span>
</ui-input> </ui-input>
<ui-info>%i18n:@add-emoji.info%</ui-info> <ui-info>{{ $t('add-emoji.info') }}</ui-info>
<ui-button @click="add">%i18n:@add-emoji.add%</ui-button> <ui-button @click="add">{{ $t('add-emoji.add') }}</ui-button>
</section> </section>
</ui-card> </ui-card>
<ui-card> <ui-card>
<div slot="title"><fa :icon="['far', 'grin']"/> %i18n:@emojis.title%</div> <div slot="title"><fa :icon="['far', 'grin']"/> {{ $t('emojis.title') }}</div>
<section v-for="emoji in emojis"> <section v-for="emoji in emojis">
<img :src="emoji.url" :alt="emoji.name" style="width: 64px;"/> <img :src="emoji.url" :alt="emoji.name" style="width: 64px;"/>
<ui-horizon-group inputs> <ui-horizon-group inputs>
<ui-input v-model="emoji.name"> <ui-input v-model="emoji.name">
<span>%i18n:@add-emoji.name%</span> <span>{{ $t('add-emoji.name') }}</span>
</ui-input> </ui-input>
<ui-input v-model="emoji.aliases"> <ui-input v-model="emoji.aliases">
<span>%i18n:@add-emoji.aliases%</span> <span>{{ $t('add-emoji.aliases') }}</span>
</ui-input> </ui-input>
</ui-horizon-group> </ui-horizon-group>
<ui-input v-model="emoji.url"> <ui-input v-model="emoji.url">
<i slot="icon"><fa icon="link"/></i> <i slot="icon"><fa icon="link"/></i>
<span>%i18n:@add-emoji.url%</span> <span>{{ $t('add-emoji.url') }}</span>
</ui-input> </ui-input>
<ui-horizon-group> <ui-horizon-group>
<ui-button @click="updateEmoji(emoji)"><fa :icon="['far', 'save']"/> %i18n:@emojis.update%</ui-button> <ui-button @click="updateEmoji(emoji)"><fa :icon="['far', 'save']"/> {{ $t('emojis.update') }}</ui-button>
<ui-button @click="removeEmoji(emoji)"><fa :icon="['far', 'trash-alt']"/> %i18n:@emojis.remove%</ui-button> <ui-button @click="removeEmoji(emoji)"><fa :icon="['far', 'trash-alt']"/> {{ $t('emojis.remove') }}</ui-button>
</ui-horizon-group> </ui-horizon-group>
</section> </section>
</ui-card> </ui-card>
@ -48,9 +48,11 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from "vue"; import Vue from 'vue';
import i18n from '../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('admin/views/emoji.vue'),
data() { data() {
return { return {
name: '', name: '',
@ -73,7 +75,7 @@ export default Vue.extend({
}).then(() => { }).then(() => {
this.$swal({ this.$swal({
type: 'success', type: 'success',
text: '%i18n:@add-emoji.added%' text: this.$t('add-emoji.added')
}); });
this.fetchEmojis(); this.fetchEmojis();
}).catch(e => { }).catch(e => {
@ -101,7 +103,7 @@ export default Vue.extend({
}).then(() => { }).then(() => {
this.$swal({ this.$swal({
type: 'success', type: 'success',
text: '%i18n:@updated%' text: this.$t('updated')
}); });
}).catch(e => { }).catch(e => {
this.$swal({ this.$swal({
@ -114,7 +116,7 @@ export default Vue.extend({
removeEmoji(emoji) { removeEmoji(emoji) {
this.$swal({ this.$swal({
type: 'warning', type: 'warning',
text: '%i18n:@remove-emoji.are-you-sure%'.replace('$1', emoji.name), text: this.$t('remove-emoji.are-you-sure').replace('$1', emoji.name),
showCancelButton: true showCancelButton: true
}).then(res => { }).then(res => {
if (!res.value) return; if (!res.value) return;
@ -124,7 +126,7 @@ export default Vue.extend({
}).then(() => { }).then(() => {
this.$swal({ this.$swal({
type: 'success', type: 'success',
text: '%i18n:@remove-emoji.removed%' text: this.$t('remove-emoji.removed')
}); });
this.fetchEmojis(); this.fetchEmojis();
}).catch(e => { }).catch(e => {

View File

@ -1,19 +1,21 @@
<template> <template>
<div> <div>
<ui-card> <ui-card>
<div slot="title">%i18n:@hided-tags%</div> <div slot="title">{{ $t('hided-tags') }}</div>
<section> <section>
<textarea class="jdnqwkzlnxcfftthoybjxrebyolvoucw" v-model="hidedTags"></textarea> <textarea class="jdnqwkzlnxcfftthoybjxrebyolvoucw" v-model="hidedTags"></textarea>
<ui-button @click="save">%i18n:@save%</ui-button> <ui-button @click="save">{{ $t('save') }}</ui-button>
</section> </section>
</ui-card> </ui-card>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from "vue"; import Vue from 'vue';
import i18n from '../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('admin/views/hashtags.vue'),
data() { data() {
return { return {
hidedTags: '', hidedTags: '',

View File

@ -18,18 +18,18 @@
<p class="name">{{ $store.state.i | userName }}</p> <p class="name">{{ $store.state.i | userName }}</p>
</div> </div>
<ul> <ul>
<li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }"><fa icon="home" fixed-width/>%i18n:@dashboard%</li> <li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }"><fa icon="home" fixed-width/>{{ $t('dashboard') }}</li>
<li @click="nav('instance')" :class="{ active: page == 'instance' }"><fa icon="cog" fixed-width/>%i18n:@instance%</li> <li @click="nav('instance')" :class="{ active: page == 'instance' }"><fa icon="cog" fixed-width/>{{ $t('instance') }}</li>
<li @click="nav('users')" :class="{ active: page == 'users' }"><fa icon="users" fixed-width/>%i18n:@users%</li> <li @click="nav('users')" :class="{ active: page == 'users' }"><fa icon="users" fixed-width/>{{ $t('users') }}</li>
<li @click="nav('emoji')" :class="{ active: page == 'emoji' }"><fa :icon="['far', 'grin']" fixed-width/>%i18n:@emoji%</li> <li @click="nav('emoji')" :class="{ active: page == 'emoji' }"><fa :icon="['far', 'grin']" fixed-width/>{{ $t('emoji') }}</li>
<li @click="nav('announcements')" :class="{ active: page == 'announcements' }"><fa icon="broadcast-tower" fixed-width/>%i18n:@announcements%</li> <li @click="nav('announcements')" :class="{ active: page == 'announcements' }"><fa icon="broadcast-tower" fixed-width/>{{ $t('announcements') }}</li>
<li @click="nav('hashtags')" :class="{ active: page == 'hashtags' }"><fa icon="hashtag" fixed-width/>%i18n:@hashtags%</li> <li @click="nav('hashtags')" :class="{ active: page == 'hashtags' }"><fa icon="hashtag" fixed-width/>{{ $t('hashtags') }}</li>
<!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }"><fa icon="cloud" fixed-width/>%i18n:common.drive%</li> --> <!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }"><fa icon="cloud" fixed-width/>{{ $t('@.drive') }}</li> -->
<!-- <li @click="nav('update')" :class="{ active: page == 'update' }">%i18n:@update%</li> --> <!-- <li @click="nav('update')" :class="{ active: page == 'update' }">{{ $t('update') }}</li> -->
</ul> </ul>
<div class="back-to-misskey"> <div class="back-to-misskey">
<a href="/"><fa icon="arrow-left"/> %i18n:@back-to-misskey%</a> <a href="/"><fa icon="arrow-left"/> {{ $t('back-to-misskey') }}</a>
</div> </div>
<div class="version"> <div class="version">
<small>Misskey {{ version }}</small> <small>Misskey {{ version }}</small>
@ -49,7 +49,8 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from "vue"; import Vue from 'vue';
import i18n from '../../i18n';
import { version } from '../../config'; import { version } from '../../config';
import XDashboard from "./dashboard.vue"; import XDashboard from "./dashboard.vue";
import XInstance from "./instance.vue"; import XInstance from "./instance.vue";
@ -63,6 +64,7 @@ const ua = navigator.userAgent.toLowerCase();
const isMobile = /mobile|iphone|ipad|android/.test(ua); const isMobile = /mobile|iphone|ipad|android/.test(ua);
export default Vue.extend({ export default Vue.extend({
i18n: i18n('admin/views/index.vue'),
components: { components: {
XDashboard, XDashboard,
XInstance, XInstance,

View File

@ -1,87 +1,89 @@
<template> <template>
<div class="axbwjelsbymowqjyywpirzhdlszoncqs"> <div class="axbwjelsbymowqjyywpirzhdlszoncqs">
<ui-card> <ui-card>
<div slot="title"><fa icon="cog"/> %i18n:@instance%</div> <div slot="title"><fa icon="cog"/> {{ $t('instance') }}</div>
<section class="fit-top fit-bottom"> <section class="fit-top fit-bottom">
<ui-input v-model="name">%i18n:@instance-name%</ui-input> <ui-input v-model="name">{{ $t('instance-name') }}</ui-input>
<ui-textarea v-model="description">%i18n:@instance-description%</ui-textarea> <ui-textarea v-model="description">{{ $t('instance-description') }}</ui-textarea>
<ui-input v-model="bannerUrl"><i slot="icon"><fa icon="link"/></i>%i18n:@banner-url%</ui-input> <ui-input v-model="bannerUrl"><i slot="icon"><fa icon="link"/></i>{{ $t('banner-url') }}</ui-input>
<ui-input v-model="languages"><i slot="icon"><fa icon="language"/></i>%i18n:@languages%<span slot="desc">%i18n:@languages-desc%</span></ui-input> <ui-input v-model="languages"><i slot="icon"><fa icon="language"/></i>{{ $t('languages') }}<span slot="desc">{{ $t('languages-desc') }}</span></ui-input>
</section> </section>
<section class="fit-bottom"> <section class="fit-bottom">
<header><fa icon="headset"/> %i18n:@maintainer-config%</header> <header><fa icon="headset"/> {{ $t('maintainer-config') }}</header>
<ui-input v-model="maintainerName">%i18n:@maintainer-name%</ui-input> <ui-input v-model="maintainerName">{{ $t('maintainer-name') }}</ui-input>
<ui-input v-model="maintainerEmail" type="email"><i slot="icon"><fa :icon="['far', 'envelope']"/></i>%i18n:@maintainer-email%</ui-input> <ui-input v-model="maintainerEmail" type="email"><i slot="icon"><fa :icon="['far', 'envelope']"/></i>{{ $t('maintainer-email') }}</ui-input>
</section> </section>
<section class="fit-top fit-bottom"> <section class="fit-top fit-bottom">
<ui-input v-model="maxNoteTextLength">%i18n:@max-note-text-length%</ui-input> <ui-input v-model="maxNoteTextLength">{{ $t('max-note-text-length') }}</ui-input>
</section> </section>
<section class="fit-bottom"> <section class="fit-bottom">
<header><fa icon="cloud"/> %i18n:@drive-config%</header> <header><fa icon="cloud"/> {{ $t('drive-config') }}</header>
<ui-switch v-model="cacheRemoteFiles">%i18n:@cache-remote-files%<span slot="desc">%i18n:@cache-remote-files-desc%</span></ui-switch> <ui-switch v-model="cacheRemoteFiles">{{ $t('cache-remote-files') }}<span slot="desc">{{ $t('cache-remote-files-desc') }}</span></ui-switch>
<ui-input v-model="localDriveCapacityMb" type="number">%i18n:@local-drive-capacity-mb%<span slot="suffix">MB</span><span slot="desc">%i18n:@mb%</span></ui-input> <ui-input v-model="localDriveCapacityMb" type="number">{{ $t('local-drive-capacity-mb') }}<span slot="suffix">MB</span><span slot="desc">{{ $t('mb') }}</span></ui-input>
<ui-input v-model="remoteDriveCapacityMb" type="number" :disabled="!cacheRemoteFiles">%i18n:@remote-drive-capacity-mb%<span slot="suffix">MB</span><span slot="desc">%i18n:@mb%</span></ui-input> <ui-input v-model="remoteDriveCapacityMb" type="number" :disabled="!cacheRemoteFiles">{{ $t('remote-drive-capacity-mb') }}<span slot="suffix">MB</span><span slot="desc">{{ $t('mb') }}</span></ui-input>
</section> </section>
<section class="fit-bottom"> <section class="fit-bottom">
<header><fa icon="shield-alt"/> %i18n:@recaptcha-config%</header> <header><fa icon="shield-alt"/> {{ $t('recaptcha-config') }}</header>
<ui-switch v-model="enableRecaptcha">%i18n:@enable-recaptcha%</ui-switch> <ui-switch v-model="enableRecaptcha">{{ $t('enable-recaptcha') }}</ui-switch>
<ui-info>%i18n:@recaptcha-info%</ui-info> <ui-info>{{ $t('recaptcha-info') }}</ui-info>
<ui-input v-model="recaptchaSiteKey" :disabled="!enableRecaptcha"><i slot="icon"><fa icon="key"/></i>%i18n:@recaptcha-site-key%</ui-input> <ui-input v-model="recaptchaSiteKey" :disabled="!enableRecaptcha"><i slot="icon"><fa icon="key"/></i>{{ $t('recaptcha-site-key') }}</ui-input>
<ui-input v-model="recaptchaSecretKey" :disabled="!enableRecaptcha"><i slot="icon"><fa icon="key"/></i>%i18n:@recaptcha-secret-key%</ui-input> <ui-input v-model="recaptchaSecretKey" :disabled="!enableRecaptcha"><i slot="icon"><fa icon="key"/></i>{{ $t('recaptcha-secret-key') }}</ui-input>
</section> </section>
<section> <section>
<header><fa icon="ghost"/> %i18n:@proxy-account-config%</header> <header><fa icon="ghost"/> {{ $t('proxy-account-config') }}</header>
<ui-info>%i18n:@proxy-account-info%</ui-info> <ui-info>{{ $t('proxy-account-info') }}</ui-info>
<ui-input v-model="proxyAccount"><span slot="prefix">@</span>%i18n:@proxy-account-username%<span slot="desc">%i18n:@proxy-account-username-desc%</span></ui-input> <ui-input v-model="proxyAccount"><span slot="prefix">@</span>{{ $t('proxy-account-username') }}<span slot="desc">{{ $t('proxy-account-username-desc') }}</span></ui-input>
<ui-info warn>%i18n:@proxy-account-warn%</ui-info> <ui-info warn>{{ $t('proxy-account-warn') }}</ui-info>
</section> </section>
<section> <section>
<ui-switch v-model="disableRegistration">%i18n:@disable-registration%</ui-switch> <ui-switch v-model="disableRegistration">{{ $t('disable-registration') }}</ui-switch>
</section> </section>
<section> <section>
<ui-switch v-model="disableLocalTimeline">%i18n:@disable-local-timeline%</ui-switch> <ui-switch v-model="disableLocalTimeline">{{ $t('disable-local-timeline') }}</ui-switch>
</section> </section>
<section> <section>
<ui-button @click="updateMeta">%i18n:@save%</ui-button> <ui-button @click="updateMeta">{{ $t('save') }}</ui-button>
</section> </section>
</ui-card> </ui-card>
<ui-card> <ui-card>
<div slot="title">%i18n:@invite%</div> <div slot="title">{{ $t('invite') }}</div>
<section> <section>
<ui-button @click="invite">%i18n:@invite%</ui-button> <ui-button @click="invite">{{ $t('invite') }}</ui-button>
<p v-if="inviteCode">Code: <code>{{ inviteCode }}</code></p> <p v-if="inviteCode">Code: <code>{{ inviteCode }}</code></p>
</section> </section>
</ui-card> </ui-card>
<ui-card> <ui-card>
<div slot="title"><fa :icon="['fab', 'twitter']"/> %i18n:@twitter-integration-config%</div> <div slot="title"><fa :icon="['fab', 'twitter']"/> {{ $t('twitter-integration-config') }}</div>
<section> <section>
<ui-switch v-model="enableTwitterIntegration">%i18n:@enable-twitter-integration%</ui-switch> <ui-switch v-model="enableTwitterIntegration">{{ $t('enable-twitter-integration') }}</ui-switch>
<ui-info>%i18n:@twitter-integration-info%</ui-info> <ui-info>{{ $t('twitter-integration-info') }}</ui-info>
<ui-input v-model="twitterConsumerKey" :disabled="!enableTwitterIntegration"><i slot="icon"><fa icon="key"/></i>%i18n:@twitter-integration-consumer-key%</ui-input> <ui-input v-model="twitterConsumerKey" :disabled="!enableTwitterIntegration"><i slot="icon"><fa icon="key"/></i>{{ $t('twitter-integration-consumer-key') }}</ui-input>
<ui-input v-model="twitterConsumerSecret" :disabled="!enableTwitterIntegration"><i slot="icon"><fa icon="key"/></i>%i18n:@twitter-integration-consumer-secret%</ui-input> <ui-input v-model="twitterConsumerSecret" :disabled="!enableTwitterIntegration"><i slot="icon"><fa icon="key"/></i>{{ $t('twitter-integration-consumer-secret') }}</ui-input>
<ui-button @click="updateMeta">%i18n:@save%</ui-button> <ui-button @click="updateMeta">{{ $t('save') }}</ui-button>
</section> </section>
</ui-card> </ui-card>
<ui-card> <ui-card>
<div slot="title"><fa :icon="['fab', 'github']"/> %i18n:@github-integration-config%</div> <div slot="title"><fa :icon="['fab', 'github']"/> {{ $t('github-integration-config') }}</div>
<section> <section>
<ui-switch v-model="enableGithubIntegration">%i18n:@enable-github-integration%</ui-switch> <ui-switch v-model="enableGithubIntegration">{{ $t('enable-github-integration') }}</ui-switch>
<ui-info>%i18n:@github-integration-info%</ui-info> <ui-info>{{ $t('github-integration-info') }}</ui-info>
<ui-input v-model="githubClientId" :disabled="!enableGithubIntegration"><i slot="icon"><fa icon="key"/></i>%i18n:@github-integration-client-id%</ui-input> <ui-input v-model="githubClientId" :disabled="!enableGithubIntegration"><i slot="icon"><fa icon="key"/></i>{{ $t('github-integration-client-id') }}</ui-input>
<ui-input v-model="githubClientSecret" :disabled="!enableGithubIntegration"><i slot="icon"><fa icon="key"/></i>%i18n:@github-integration-client-secret%</ui-input> <ui-input v-model="githubClientSecret" :disabled="!enableGithubIntegration"><i slot="icon"><fa icon="key"/></i>{{ $t('github-integration-client-secret') }}</ui-input>
<ui-button @click="updateMeta">%i18n:@save%</ui-button> <ui-button @click="updateMeta">{{ $t('save') }}</ui-button>
</section> </section>
</ui-card> </ui-card>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from "vue"; import Vue from 'vue';
import i18n from '../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('admin/views/instance.vue'),
data() { data() {
return { return {
maintainerName: null, maintainerName: null,
@ -174,7 +176,7 @@ export default Vue.extend({
}).then(() => { }).then(() => {
this.$swal({ this.$swal({
type: 'success', type: 'success',
text: '%i18n:@saved%' text: this.$t('saved')
}); });
}).catch(e => { }).catch(e => {
this.$swal({ this.$swal({

View File

@ -1,52 +1,54 @@
<template> <template>
<div class="ucnffhbtogqgscfmqcymwmmupoknpfsw"> <div class="ucnffhbtogqgscfmqcymwmmupoknpfsw">
<ui-card> <ui-card>
<div slot="title">%i18n:@verify-user%</div> <div slot="title">{{ $t('verify-user') }}</div>
<section class="fit-top"> <section class="fit-top">
<ui-input v-model="verifyUsername" type="text"> <ui-input v-model="verifyUsername" type="text">
<span slot="prefix">@</span> <span slot="prefix">@</span>
</ui-input> </ui-input>
<ui-button @click="verifyUser" :disabled="verifying">%i18n:@verify%</ui-button> <ui-button @click="verifyUser" :disabled="verifying">{{ $t('verify') }}</ui-button>
</section> </section>
</ui-card> </ui-card>
<ui-card> <ui-card>
<div slot="title">%i18n:@unverify-user%</div> <div slot="title">{{ $t('unverify-user') }}</div>
<section class="fit-top"> <section class="fit-top">
<ui-input v-model="unverifyUsername" type="text"> <ui-input v-model="unverifyUsername" type="text">
<span slot="prefix">@</span> <span slot="prefix">@</span>
</ui-input> </ui-input>
<ui-button @click="unverifyUser" :disabled="unverifying">%i18n:@unverify%</ui-button> <ui-button @click="unverifyUser" :disabled="unverifying">{{ $t('unverify') }}</ui-button>
</section> </section>
</ui-card> </ui-card>
<ui-card> <ui-card>
<div slot="title">%i18n:@suspend-user%</div> <div slot="title">{{ $t('suspend-user') }}</div>
<section class="fit-top"> <section class="fit-top">
<ui-input v-model="suspendUsername" type="text"> <ui-input v-model="suspendUsername" type="text">
<span slot="prefix">@</span> <span slot="prefix">@</span>
</ui-input> </ui-input>
<ui-button @click="suspendUser" :disabled="suspending">%i18n:@suspend%</ui-button> <ui-button @click="suspendUser" :disabled="suspending">{{ $t('suspend') }}</ui-button>
</section> </section>
</ui-card> </ui-card>
<ui-card> <ui-card>
<div slot="title">%i18n:@unsuspend-user%</div> <div slot="title">{{ $t('unsuspend-user') }}</div>
<section class="fit-top"> <section class="fit-top">
<ui-input v-model="unsuspendUsername" type="text"> <ui-input v-model="unsuspendUsername" type="text">
<span slot="prefix">@</span> <span slot="prefix">@</span>
</ui-input> </ui-input>
<ui-button @click="unsuspendUser" :disabled="unsuspending">%i18n:@unsuspend%</ui-button> <ui-button @click="unsuspendUser" :disabled="unsuspending">{{ $t('unsuspend') }}</ui-button>
</section> </section>
</ui-card> </ui-card>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from "vue"; import Vue from 'vue';
import i18n from '../../i18n';
import parseAcct from "../../../../misc/acct/parse"; import parseAcct from "../../../../misc/acct/parse";
export default Vue.extend({ export default Vue.extend({
i18n: i18n('admin/views/users.vue'),
data() { data() {
return { return {
verifyUsername: null, verifyUsername: null,
@ -67,7 +69,7 @@ export default Vue.extend({
const process = async () => { const process = async () => {
const user = await (this as any).os.api('users/show', parseAcct(this.verifyUsername)); const user = await (this as any).os.api('users/show', parseAcct(this.verifyUsername));
await (this as any).os.api('admin/verify-user', { userId: user.id }); await (this as any).os.api('admin/verify-user', { userId: user.id });
//(this as any).os.apis.dialog({ text: '%i18n:@verified%' }); //(this as any).os.apis.dialog({ text: this.$t('verified') });
}; };
await process().catch(e => { await process().catch(e => {
@ -83,7 +85,7 @@ export default Vue.extend({
const process = async () => { const process = async () => {
const user = await (this as any).os.api('users/show', parseAcct(this.unverifyUsername)); const user = await (this as any).os.api('users/show', parseAcct(this.unverifyUsername));
await (this as any).os.api('admin/unverify-user', { userId: user.id }); await (this as any).os.api('admin/unverify-user', { userId: user.id });
//(this as any).os.apis.dialog({ text: '%i18n:@unverified%' }); //(this as any).os.apis.dialog({ text: this.$t('unverified') });
}; };
await process().catch(e => { await process().catch(e => {
@ -99,7 +101,7 @@ export default Vue.extend({
const process = async () => { const process = async () => {
const user = await (this as any).os.api('users/show', parseAcct(this.suspendUsername)); const user = await (this as any).os.api('users/show', parseAcct(this.suspendUsername));
await (this as any).os.api('admin/suspend-user', { userId: user.id }); await (this as any).os.api('admin/suspend-user', { userId: user.id });
//(this as any).os.apis.dialog({ text: '%i18n:@suspended%' }); //(this as any).os.apis.dialog({ text: this.$t('suspended') });
}; };
await process().catch(e => { await process().catch(e => {
@ -115,7 +117,7 @@ export default Vue.extend({
const process = async () => { const process = async () => {
const user = await (this as any).os.api('users/show', parseAcct(this.unsuspendUsername)); const user = await (this as any).os.api('users/show', parseAcct(this.unsuspendUsername));
await (this as any).os.api('admin/unsuspend-user', { userId: user.id }); await (this as any).os.api('admin/unsuspend-user', { userId: user.id });
//(this as any).os.apis.dialog({ text: '%i18n:@unsuspended%' }); //(this as any).os.apis.dialog({ text: this.$t('unsuspended') });
}; };
await process().catch(e => { await process().catch(e => {

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="form"> <div class="form">
<header> <header>
<h1>%i18n:@share-access%</h1> <h1>{{ $t('share-access') }}</h1>
<img :src="app.iconUrl"/> <img :src="app.iconUrl"/>
</header> </header>
<div class="app"> <div class="app">
@ -11,32 +11,35 @@
<p class="description">{{ app.description }}</p> <p class="description">{{ app.description }}</p>
</section> </section>
<section> <section>
<h2>%i18n:@permission-ask%</h2> <h2>{{ $t('permission-ask') }}</h2>
<ul> <ul>
<template v-for="p in app.permission"> <template v-for="p in app.permission">
<li v-if="p == 'account-read'">%i18n:@account-read%</li> <li v-if="p == 'account-read'">{{ $t('account-read') }}</li>
<li v-if="p == 'account-write'">%i18n:@account-write%</li> <li v-if="p == 'account-write'">{{ $t('account-write') }}</li>
<li v-if="p == 'note-write'">%i18n:@note-write%</li> <li v-if="p == 'note-write'">{{ $t('note-write') }}</li>
<li v-if="p == 'like-write'">%i18n:@like-write%</li> <li v-if="p == 'like-write'">{{ $t('like-write') }}</li>
<li v-if="p == 'following-write'">%i18n:@following-write%</li> <li v-if="p == 'following-write'">{{ $t('following-write') }}</li>
<li v-if="p == 'drive-read'">%i18n:@drive-read%</li> <li v-if="p == 'drive-read'">{{ $t('drive-read') }}</li>
<li v-if="p == 'drive-write'">%i18n:@drive-write%</li> <li v-if="p == 'drive-write'">{{ $t('drive-write') }}</li>
<li v-if="p == 'notification-read'">%i18n:@notification-read%</li> <li v-if="p == 'notification-read'">{{ $t('notification-read') }}</li>
<li v-if="p == 'notification-write'">%i18n:@notification-write%</li> <li v-if="p == 'notification-write'">{{ $t('notification-write') }}</li>
</template> </template>
</ul> </ul>
</section> </section>
</div> </div>
<div class="action"> <div class="action">
<button @click="cancel">%i18n:@cancel%</button> <button @click="cancel">{{ $t('cancel') }}</button>
<button @click="accept">%i18n:@accept%</button> <button @click="accept">{{ $t('accept') }}</button>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('auth/views/form.vue'),
props: ['session'], props: ['session'],
computed: { computed: {
app(): any { app(): any {

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="index"> <div class="index">
<main v-if="$store.getters.isSignedIn"> <main v-if="$store.getters.isSignedIn">
<p class="fetching" v-if="fetching">%i18n:@loading%<mk-ellipsis/></p> <p class="fetching" v-if="fetching">{{ $t('loading') }}<mk-ellipsis/></p>
<x-form <x-form
class="form" class="form"
ref="form" ref="form"
@ -11,20 +11,20 @@
@accepted="accepted" @accepted="accepted"
/> />
<div class="denied" v-if="state == 'denied'"> <div class="denied" v-if="state == 'denied'">
<h1>%i18n:@denied%</h1> <h1>{{ $t('denied') }}</h1>
<p>%i18n:@denied-paragraph%</p> <p>{{ $t('denied-paragraph') }}</p>
</div> </div>
<div class="accepted" v-if="state == 'accepted'"> <div class="accepted" v-if="state == 'accepted'">
<h1>{{ session.app.isAuthorized ? '%i18n:@already-authorized%' : '%i18n:@allowed%' }}</h1> <h1>{{ session.app.isAuthorized ? this.$t('already-authorized') : this.$t('allowed') }}</h1>
<p v-if="session.app.callbackUrl">%i18n:@callback-url%<mk-ellipsis/></p> <p v-if="session.app.callbackUrl">{{ $t('callback-url') }}<mk-ellipsis/></p>
<p v-if="!session.app.callbackUrl">%i18n:@please-go-back%</p> <p v-if="!session.app.callbackUrl">{{ $t('please-go-back') }}</p>
</div> </div>
<div class="error" v-if="state == 'fetch-session-error'"> <div class="error" v-if="state == 'fetch-session-error'">
<p>%i18n:@error%</p> <p>{{ $t('error') }}</p>
</div> </div>
</main> </main>
<main class="signin" v-if="!$store.getters.isSignedIn"> <main class="signin" v-if="!$store.getters.isSignedIn">
<h1>%i18n:@sign-in%</h1> <h1>{{ $t('sign-in') }}</h1>
<mk-signin/> <mk-signin/>
</main> </main>
<footer><img src="/assets/auth/icon.svg" alt="Misskey"/></footer> <footer><img src="/assets/auth/icon.svg" alt="Misskey"/></footer>
@ -33,9 +33,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../i18n';
import XForm from './form.vue'; import XForm from './form.vue';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('auth/views/index.vue'),
components: { components: {
XForm XForm
}, },

View File

@ -4,29 +4,29 @@
<section class="fit-top"> <section class="fit-top">
<ui-input :value="$store.state.i.token" readonly> <ui-input :value="$store.state.i.token" readonly>
<span>%i18n:@token%</span> <span>{{ $t('token') }}</span>
</ui-input> </ui-input>
<p>%i18n:@intro%</p> <p>{{ $t('intro') }}</p>
<ui-info warn>%i18n:@caution%</ui-info> <ui-info warn>{{ $t('caution') }}</ui-info>
<p>%i18n:@regeneration-of-token%</p> <p>{{ $t('regeneration-of-token') }}</p>
<ui-button @click="regenerateToken"><fa icon="sync-alt"/> %i18n:@regenerate-token%</ui-button> <ui-button @click="regenerateToken"><fa icon="sync-alt"/> {{ $t('regenerate-token') }}</ui-button>
</section> </section>
<section> <section>
<header><fa icon="terminal"/> %i18n:@console.title%</header> <header><fa icon="terminal"/> {{ $t('console.title') }}</header>
<ui-input v-model="endpoint"> <ui-input v-model="endpoint">
<span>%i18n:@console.endpoint%</span> <span>{{ $t('console.endpoint') }}</span>
</ui-input> </ui-input>
<ui-textarea v-model="body"> <ui-textarea v-model="body">
<span>%i18n:@console.parameter% (JSON or JSON5)</span> <span>{{ $t('console.parameter') }} (JSON or JSON5)</span>
<span slot="desc">%i18n:@console.credential-info%</span> <span slot="desc">{{ $t('console.credential-info') }}</span>
</ui-textarea> </ui-textarea>
<ui-button @click="send" :disabled="sending"> <ui-button @click="send" :disabled="sending">
<template v-if="sending">%i18n:@console.sending%</template> <template v-if="sending">{{ $t('console.sending') }}</template>
<template v-else><fa icon="paper-plane"/> %i18n:@console.send%</template> <template v-else><fa icon="paper-plane"/> {{ $t('console.send') }}</template>
</ui-button> </ui-button>
<ui-textarea v-if="res" v-model="res" readonly tall> <ui-textarea v-if="res" v-model="res" readonly tall>
<span>%i18n:@console.response%</span> <span>{{ $t('console.response') }}</span>
</ui-textarea> </ui-textarea>
</section> </section>
</ui-card> </ui-card>
@ -34,9 +34,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import * as JSON5 from 'json5'; import * as JSON5 from 'json5';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/api-settings.vue'),
data() { data() {
return { return {
endpoint: '', endpoint: '',
@ -49,7 +51,7 @@ export default Vue.extend({
methods: { methods: {
regenerateToken() { regenerateToken() {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:@enter-password%', title: this.$t('enter-password'),
type: 'password' type: 'password'
}).then(password => { }).then(password => {
(this as any).api('i/regenerate_token', { (this as any).api('i/regenerate_token', {

View File

@ -15,6 +15,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
export default Vue.extend({ export default Vue.extend({
props: { props: {
user: { user: {

View File

@ -1,47 +1,49 @@
<template> <template>
<div class="troubleshooter"> <div class="troubleshooter">
<div class="body"> <div class="body">
<h1><fa icon="wrench"/>%i18n:@title%</h1> <h1><fa icon="wrench"/>{{ $t('title') }}</h1>
<div> <div>
<p :data-wip="network == null"> <p :data-wip="network == null">
<template v-if="network != null"> <template v-if="network != null">
<template v-if="network"><fa icon="check"/></template> <template v-if="network"><fa icon="check"/></template>
<template v-if="!network"><fa icon="times"/></template> <template v-if="!network"><fa icon="times"/></template>
</template> </template>
{{ network == null ? '%i18n:@checking-network%' : '%i18n:@network%' }}<mk-ellipsis v-if="network == null"/> {{ network == null ? this.$t('checking-network') : this.$t('network') }}<mk-ellipsis v-if="network == null"/>
</p> </p>
<p v-if="network == true" :data-wip="internet == null"> <p v-if="network == true" :data-wip="internet == null">
<template v-if="internet != null"> <template v-if="internet != null">
<template v-if="internet"><fa icon="check"/></template> <template v-if="internet"><fa icon="check"/></template>
<template v-if="!internet"><fa icon="times"/></template> <template v-if="!internet"><fa icon="times"/></template>
</template> </template>
{{ internet == null ? '%i18n:@checking-internet%' : '%i18n:@internet%' }}<mk-ellipsis v-if="internet == null"/> {{ internet == null ? this.$t('checking-internet') : this.$t('internet') }}<mk-ellipsis v-if="internet == null"/>
</p> </p>
<p v-if="internet == true" :data-wip="server == null"> <p v-if="internet == true" :data-wip="server == null">
<template v-if="server != null"> <template v-if="server != null">
<template v-if="server"><fa icon="check"/></template> <template v-if="server"><fa icon="check"/></template>
<template v-if="!server"><fa icon="times"/></template> <template v-if="!server"><fa icon="times"/></template>
</template> </template>
{{ server == null ? '%i18n:@checking-server%' : '%i18n:@server%' }}<mk-ellipsis v-if="server == null"/> {{ server == null ? this.$t('checking-server') : this.$t('server') }}<mk-ellipsis v-if="server == null"/>
</p> </p>
</div> </div>
<p v-if="!end">%i18n:@finding%<mk-ellipsis/></p> <p v-if="!end">{{ $t('finding') }}<mk-ellipsis/></p>
<p v-if="network === false"><b><fa icon="exclamation-triangle"/>%i18n:@no-network%</b><br>%i18n:@no-network-desc%</p> <p v-if="network === false"><b><fa icon="exclamation-triangle"/>{{ $t('no-network') }}</b><br>{{ $t('no-network-desc') }}</p>
<p v-if="internet === false"><b><fa icon="exclamation-triangle"/>%i18n:@no-internet%</b><br>%i18n:@no-internet-desc%</p> <p v-if="internet === false"><b><fa icon="exclamation-triangle"/>{{ $t('no-internet') }}</b><br>{{ $t('no-internet-desc') }}</p>
<p v-if="server === false"><b><fa icon="exclamation-triangle"/>%i18n:@no-server%</b><br>%i18n:@no-server-desc%</p> <p v-if="server === false"><b><fa icon="exclamation-triangle"/>{{ $t('no-server') }}</b><br>{{ $t('no-server-desc') }}</p>
<p v-if="server === true" class="success"><b><fa icon="info-circle"/>%i18n:@success%</b><br>%i18n:@success-desc%</p> <p v-if="server === true" class="success"><b><fa icon="info-circle"/>{{ $t('success') }}</b><br>{{ $t('success-desc') }}</p>
</div> </div>
<footer> <footer>
<a href="/assets/flush.html">%i18n:@flush%</a> | <a href="/assets/version.html">%i18n:@set-version%</a> <a href="/assets/flush.html">{{ $t('flush') }}</a> | <a href="/assets/version.html">{{ $t('set-version') }}</a>
</footer> </footer>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import { apiUrl } from '../../../config'; import { apiUrl } from '../../../config';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/connect-failed.troubleshooter.vue'),
data() { data() {
return { return {
network: navigator.onLine, network: navigator.onLine,

View File

@ -1,23 +1,25 @@
<template> <template>
<div class="mk-connect-failed"> <div class="mk-connect-failed">
<img src="https://raw.githubusercontent.com/syuilo/misskey/develop/src/client/assets/error.jpg" alt=""/> <img src="https://raw.githubusercontent.com/syuilo/misskey/develop/src/client/assets/error.jpg" alt=""/>
<h1>%i18n:@title%</h1> <h1>{{ $t('title') }}</h1>
<p class="text"> <p class="text">
<span>{{ '%i18n:@description%'.substr(0, '%i18n:@description%'.indexOf('{')) }}</span> <span>{{ this.$t('description').substr(0, this.$t('description').indexOf('{')) }}</span>
<a @click="reload">{{ '%i18n:@description%'.match(/\{(.+?)\}/)[1] }}</a> <a @click="reload">{{ this.$t('description').match(/\{(.+?)\}/)[1] }}</a>
<span>{{ '%i18n:@description%'.substr('%i18n:@description%'.indexOf('}') + 1) }}</span> <span>{{ this.$t('description').substr(this.$t('description').indexOf('}') + 1) }}</span>
</p> </p>
<button v-if="!troubleshooting" @click="troubleshooting = true">%i18n:@troubleshoot%</button> <button v-if="!troubleshooting" @click="troubleshooting = true">{{ $t('troubleshoot') }}</button>
<x-troubleshooter v-if="troubleshooting"/> <x-troubleshooter v-if="troubleshooting"/>
<p class="thanks">%i18n:@thanks%</p> <p class="thanks">{{ $t('thanks') }}</p>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import XTroubleshooter from './connect-failed.troubleshooter.vue'; import XTroubleshooter from './connect-failed.troubleshooter.vue';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/connect-failed.vue'),
components: { components: {
XTroubleshooter XTroubleshooter
}, },

View File

@ -1,11 +1,13 @@
<template> <template>
<button class="nrvgflfuaxwgkxoynpnumyookecqrrvh" @click="toggle">{{ value ? '%i18n:@hide%' : '%i18n:@show%' }}</button> <button class="nrvgflfuaxwgkxoynpnumyookecqrrvh" @click="toggle">{{ value ? this.$t('hide') : this.$t('show') }}</button>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/cw-button.vue'),
props: { props: {
value: { value: {
type: Boolean, type: Boolean,

View File

@ -1,14 +1,14 @@
<template> <template>
<ui-card> <ui-card>
<div slot="title"><fa icon="cloud"/> %i18n:common.drive%</div> <div slot="title"><fa icon="cloud"/> {{ $t('@.drive') }}</div>
<section v-if="!fetching" class="juakhbxthdewydyreaphkepoxgxvfogn"> <section v-if="!fetching" class="juakhbxthdewydyreaphkepoxgxvfogn">
<div class="meter"><div :style="meterStyle"></div></div> <div class="meter"><div :style="meterStyle"></div></div>
<p>%i18n:@max%: <b>{{ capacity | bytes }}</b> %i18n:@in-use%: <b>{{ usage | bytes }}</b></p> <p>{{ $t('max') }}: <b>{{ capacity | bytes }}</b> {{ $t('in-use') }}: <b>{{ usage | bytes }}</b></p>
</section> </section>
<section> <section>
<header>%i18n:@stats%</header> <header>{{ $t('stats') }}</header>
<div ref="chart" style="margin-bottom: -16px; color: #000;"></div> <div ref="chart" style="margin-bottom: -16px; color: #000;"></div>
</section> </section>
</ui-card> </ui-card>
@ -16,10 +16,12 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import * as tinycolor from 'tinycolor2'; import * as tinycolor from 'tinycolor2';
import * as ApexCharts from 'apexcharts'; import * as ApexCharts from 'apexcharts';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/drive-settings.vue'),
data() { data() {
return { return {
fetching: true, fetching: true,

View File

@ -1,10 +1,19 @@
<template> <template>
<div class="wjqjnyhzogztorhrdgcpqlkxhkmuetgj"> <div class="wjqjnyhzogztorhrdgcpqlkxhkmuetgj">
<p><fa icon="exclamation-triangle"/> %i18n:common.error.title%</p> <p><fa icon="exclamation-triangle"/> {{ $t('@.error.title') }}</p>
<ui-button @click="() => $emit('retry')">%i18n:common.error.retry%</ui-button> <ui-button @click="() => $emit('retry')">{{ $t('@.error.retry') }}</ui-button>
</div> </div>
</template> </template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({
i18n: i18n()
});
</script>
<style lang="stylus" scoped> <style lang="stylus" scoped>
.wjqjnyhzogztorhrdgcpqlkxhkmuetgj .wjqjnyhzogztorhrdgcpqlkxhkmuetgj
max-width 350px max-width 350px

View File

@ -1,19 +1,19 @@
<template> <template>
<div class="xqnhankfuuilcwvhgsopeqncafzsquya"> <div class="xqnhankfuuilcwvhgsopeqncafzsquya">
<button class="go-index" v-if="selfNav" @click="goIndex"><fa icon="arrow-left"/></button> <button class="go-index" v-if="selfNav" @click="goIndex"><fa icon="arrow-left"/></button>
<header><b><router-link :to="blackUser | userPage">{{ blackUser | userName }}</router-link></b>(%i18n:common.reversi.black%) vs <b><router-link :to="whiteUser | userPage">{{ whiteUser | userName }}</router-link></b>(%i18n:common.reversi.white%)</header> <header><b><router-link :to="blackUser | userPage">{{ blackUser | userName }}</router-link></b>({{ $t('@.reversi.black') }}) vs <b><router-link :to="whiteUser | userPage">{{ whiteUser | userName }}</router-link></b>({{ $t('@.reversi.white') }})</header>
<div style="overflow: hidden; line-height: 28px;"> <div style="overflow: hidden; line-height: 28px;">
<p class="turn" v-if="!iAmPlayer && !game.isEnded">{{ '%i18n:common.reversi.turn-of%'.replace('{}', $options.filters.userName(turnUser)) }}<mk-ellipsis/></p> <p class="turn" v-if="!iAmPlayer && !game.isEnded">{{ $t('@.reversi.turn-of', { name: $options.filters.userName(turnUser) }) }}<mk-ellipsis/></p>
<p class="turn" v-if="logPos != logs.length">{{ '%i18n:common.reversi.past-turn-of%'.replace('{}', $options.filters.userName(turnUser)) }}</p> <p class="turn" v-if="logPos != logs.length">{{ $t('@.reversi.past-turn-of', { name: $options.filters.userName(turnUser) }) }}</p>
<p class="turn1" v-if="iAmPlayer && !game.isEnded && !isMyTurn">%i18n:common.reversi.opponent-turn%<mk-ellipsis/></p> <p class="turn1" v-if="iAmPlayer && !game.isEnded && !isMyTurn">{{ $t('@.reversi.opponent-turn') }}<mk-ellipsis/></p>
<p class="turn2" v-if="iAmPlayer && !game.isEnded && isMyTurn" v-animate-css="{ classes: 'tada', iteration: 'infinite' }">%i18n:common.reversi.my-turn%</p> <p class="turn2" v-if="iAmPlayer && !game.isEnded && isMyTurn" v-animate-css="{ classes: 'tada', iteration: 'infinite' }">{{ $t('@.reversi.my-turn') }}</p>
<p class="result" v-if="game.isEnded && logPos == logs.length"> <p class="result" v-if="game.isEnded && logPos == logs.length">
<template v-if="game.winner"> <template v-if="game.winner">
<span>{{ '%i18n:common.reversi.won%'.replace('{}', $options.filters.userName(game.winner)) }}</span> <span>{{ $t('@.reversi.won', { name: $options.filters.userName(game.winner) }) }}</span>
<span v-if="game.surrendered != null"> (%i18n:@surrendered%)</span> <span v-if="game.surrendered != null"> ({{ $t('surrendered') }})</span>
</template> </template>
<template v-else>%i18n:common.reversi.drawn%</template> <template v-else>{{ $t('@.reversi.drawn') }}</template>
</p> </p>
</div> </div>
@ -43,10 +43,10 @@
</div> </div>
</div> </div>
<p class="status"><b>{{ '%i18n:common.reversi.this-turn%'.split('{}')[0] }}{{ logPos }}{{ '%i18n:common.reversi.this-turn%'.split('{}')[1] }}</b> %i18n:common.reversi.black%:{{ o.blackCount }} %i18n:common.reversi.white%:{{ o.whiteCount }} %i18n:common.reversi.total%:{{ o.blackCount + o.whiteCount }}</p> <p class="status"><b>{{ $t('@.reversi.this-turn', { count: logPos }) }}</b> {{ $t('@.reversi.black') }}:{{ o.blackCount }} {{ $t('@.reversi.white') }}:{{ o.whiteCount }} {{ $t('@.reversi.total') }}:{{ o.blackCount + o.whiteCount }}</p>
<div class="actions" v-if="!game.isEnded && iAmPlayer"> <div class="actions" v-if="!game.isEnded && iAmPlayer">
<form-button @click="surrender">%i18n:@surrender%</form-button> <form-button @click="surrender">{{ $t('surrender') }}</form-button>
</div> </div>
<div class="player" v-if="game.isEnded"> <div class="player" v-if="game.isEnded">
@ -62,20 +62,22 @@
</div> </div>
<div class="info"> <div class="info">
<p v-if="game.settings.isLlotheo">%i18n:@is-llotheo%</p> <p v-if="game.settings.isLlotheo">{{ $t('is-llotheo') }}</p>
<p v-if="game.settings.loopedBoard">%i18n:@looped-map%</p> <p v-if="game.settings.loopedBoard">{{ $t('looped-map') }}</p>
<p v-if="game.settings.canPutEverywhere">%i18n:@can-put-everywhere%</p> <p v-if="game.settings.canPutEverywhere">{{ $t('can-put-everywhere') }}</p>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../../../i18n';
import * as CRC32 from 'crc-32'; import * as CRC32 from 'crc-32';
import Reversi, { Color } from '../../../../../../../games/reversi/core'; import Reversi, { Color } from '../../../../../../../games/reversi/core';
import { url } from '../../../../../config'; import { url } from '../../../../../config';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/games/reversi/reversi.game.vue'),
props: { props: {
initGame: { initGame: {
type: Object, type: Object,

View File

@ -7,10 +7,12 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../../../i18n';
import XGame from './reversi.game.vue'; import XGame from './reversi.game.vue';
import XRoom from './reversi.room.vue'; import XRoom from './reversi.room.vue';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/games/reversi/reversi.gameroom.vue'),
components: { components: {
XGame, XGame,
XRoom XRoom

View File

@ -1,22 +1,22 @@
<template> <template>
<div class="phgnkghfpyvkrvwiajkiuoxyrdaqpzcx"> <div class="phgnkghfpyvkrvwiajkiuoxyrdaqpzcx">
<h1>%i18n:@title%</h1> <h1>{{ $t('title') }}</h1>
<p>%i18n:@sub-title%</p> <p>{{ $t('sub-title') }}</p>
<div class="play"> <div class="play">
<form-button primary round @click="match">%i18n:@invite%</form-button> <form-button primary round @click="match">{{ $t('invite') }}</form-button>
<details> <details>
<summary>%i18n:@rule%</summary> <summary>{{ $t('rule') }}</summary>
<div> <div>
<p>%i18n:@rule-desc%</p> <p>{{ $t('rule-desc') }}</p>
<dl> <dl>
<dt><b>%i18n:@mode-invite%</b></dt> <dt><b>{{ $t('mode-invite') }}</b></dt>
<dd>%i18n:@mode-invite-desc%</dd> <dd>{{ $t('mode-invite-desc') }}</dd>
</dl> </dl>
</div> </div>
</details> </details>
</div> </div>
<section v-if="invitations.length > 0"> <section v-if="invitations.length > 0">
<h2>%i18n:@invitations%</h2> <h2>{{ $t('invitations') }}</h2>
<div class="invitation" v-for="i in invitations" tabindex="-1" @click="accept(i)"> <div class="invitation" v-for="i in invitations" tabindex="-1" @click="accept(i)">
<mk-avatar class="avatar" :user="i.parent"/> <mk-avatar class="avatar" :user="i.parent"/>
<span class="name"><b>{{ i.parent | userName }}</b></span> <span class="name"><b>{{ i.parent | userName }}</b></span>
@ -25,22 +25,22 @@
</div> </div>
</section> </section>
<section v-if="myGames.length > 0"> <section v-if="myGames.length > 0">
<h2>%i18n:@my-games%</h2> <h2>{{ $t('my-games') }}</h2>
<a class="game" v-for="g in myGames" tabindex="-1" @click.prevent="go(g)" :href="`/reversi/${g.id}`"> <a class="game" v-for="g in myGames" tabindex="-1" @click.prevent="go(g)" :href="`/reversi/${g.id}`">
<mk-avatar class="avatar" :user="g.user1"/> <mk-avatar class="avatar" :user="g.user1"/>
<mk-avatar class="avatar" :user="g.user2"/> <mk-avatar class="avatar" :user="g.user2"/>
<span><b>{{ g.user1 | userName }}</b> vs <b>{{ g.user2 | userName }}</b></span> <span><b>{{ g.user1 | userName }}</b> vs <b>{{ g.user2 | userName }}</b></span>
<span class="state">{{ g.isEnded ? '%i18n:@game-state.ended%' : '%i18n:@game-state.playing%' }}</span> <span class="state">{{ g.isEnded ? this.$t('game-state.ended') : this.$t('game-state.playing') }}</span>
<mk-time :time="g.createdAt" /> <mk-time :time="g.createdAt" />
</a> </a>
</section> </section>
<section v-if="games.length > 0"> <section v-if="games.length > 0">
<h2>%i18n:@all-games%</h2> <h2>{{ $t('all-games') }}</h2>
<a class="game" v-for="g in games" tabindex="-1" @click.prevent="go(g)" :href="`/reversi/${g.id}`"> <a class="game" v-for="g in games" tabindex="-1" @click.prevent="go(g)" :href="`/reversi/${g.id}`">
<mk-avatar class="avatar" :user="g.user1"/> <mk-avatar class="avatar" :user="g.user1"/>
<mk-avatar class="avatar" :user="g.user2"/> <mk-avatar class="avatar" :user="g.user2"/>
<span><b>{{ g.user1 | userName }}</b> vs <b>{{ g.user2 | userName }}</b></span> <span><b>{{ g.user1 | userName }}</b> vs <b>{{ g.user2 | userName }}</b></span>
<span class="state">{{ g.isEnded ? '%i18n:@game-state.ended%' : '%i18n:@game-state.playing%' }}</span> <span class="state">{{ g.isEnded ? this.$t('game-state.ended') : this.$t('game-state.playing') }}</span>
<mk-time :time="g.createdAt" /> <mk-time :time="g.createdAt" />
</a> </a>
</section> </section>
@ -49,8 +49,10 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/games/reversi/reversi.index.vue'),
data() { data() {
return { return {
games: [], games: [],
@ -99,7 +101,7 @@ export default Vue.extend({
match() { match() {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:@enter-username%' title: this.$t('enter-username')
}).then(username => { }).then(username => {
(this as any).api('users/show', { (this as any).api('users/show', {
username username

View File

@ -3,13 +3,13 @@
<header><b>{{ game.user1 | userName }}</b> vs <b>{{ game.user2 | userName }}</b></header> <header><b>{{ game.user1 | userName }}</b> vs <b>{{ game.user2 | userName }}</b></header>
<div> <div>
<p>%i18n:@settings-of-the-game%</p> <p>{{ $t('settings-of-the-game') }}</p>
<div class="card map"> <div class="card map">
<header> <header>
<select v-model="mapName" placeholder="%i18n:@choose-map%" @change="onMapChange"> <select v-model="mapName" :placeholder="$t('placeholder')" @change="onMapChange">
<option label="-Custom-" :value="mapName" v-if="mapName == '-Custom-'"/> <option label="-Custom-" :value="mapName" v-if="mapName == '-Custom-'"/>
<option label="%i18n:@random%" :value="null"/> <option :label="$t('label')" :value="null"/>
<optgroup v-for="c in mapCategories" :key="c" :label="c"> <optgroup v-for="c in mapCategories" :key="c" :label="c">
<option v-for="m in maps" v-if="m.category == c" :key="m.name" :label="m.name" :value="m.name">{{ m.name }}</option> <option v-for="m in maps" v-if="m.category == c" :key="m.name" :label="m.name" :value="m.name">{{ m.name }}</option>
</optgroup> </optgroup>
@ -31,31 +31,31 @@
<div class="card"> <div class="card">
<header> <header>
<span>%i18n:@black-or-white%</span> <span>{{ $t('black-or-white') }}</span>
</header> </header>
<div> <div>
<form-radio v-model="game.settings.bw" value="random" @change="updateSettings">%i18n:@random%</form-radio> <form-radio v-model="game.settings.bw" value="random" @change="updateSettings">{{ $t('random') }}</form-radio>
<form-radio v-model="game.settings.bw" :value="1" @change="updateSettings">{{ '%i18n:@black-is%'.split('{}')[0] }}<b>{{ game.user1 | userName }}</b>{{ '%i18n:@black-is%'.split('{}')[1] }}</form-radio> <form-radio v-model="game.settings.bw" :value="1" @change="updateSettings">{{ this.$t('black-is').split('{}')[0] }}<b>{{ game.user1 | userName }}</b>{{ this.$t('black-is').split('{}')[1] }}</form-radio>
<form-radio v-model="game.settings.bw" :value="2" @change="updateSettings">{{ '%i18n:@black-is%'.split('{}')[0] }}<b>{{ game.user2 | userName }}</b>{{ '%i18n:@black-is%'.split('{}')[1] }}</form-radio> <form-radio v-model="game.settings.bw" :value="2" @change="updateSettings">{{ this.$t('black-is').split('{}')[0] }}<b>{{ game.user2 | userName }}</b>{{ this.$t('black-is').split('{}')[1] }}</form-radio>
</div> </div>
</div> </div>
<div class="card"> <div class="card">
<header> <header>
<span>%i18n:@rules%</span> <span>{{ $t('rules') }}</span>
</header> </header>
<div> <div>
<ui-switch v-model="game.settings.isLlotheo" @change="updateSettings">%i18n:@is-llotheo%</ui-switch> <ui-switch v-model="game.settings.isLlotheo" @change="updateSettings">{{ $t('is-llotheo') }}</ui-switch>
<ui-switch v-model="game.settings.loopedBoard" @change="updateSettings">%i18n:@looped-map%</ui-switch> <ui-switch v-model="game.settings.loopedBoard" @change="updateSettings">{{ $t('looped-map') }}</ui-switch>
<ui-switch v-model="game.settings.canPutEverywhere" @change="updateSettings">%i18n:@can-put-everywhere%</ui-switch> <ui-switch v-model="game.settings.canPutEverywhere" @change="updateSettings">{{ $t('can-put-everywhere') }}</ui-switch>
</div> </div>
</div> </div>
<div class="card form" v-if="form"> <div class="card form" v-if="form">
<header> <header>
<span>%i18n:@settings-of-the-bot%</span> <span>{{ $t('settings-of-the-bot') }}</span>
</header> </header>
<div> <div>
@ -98,16 +98,16 @@
<footer> <footer>
<p class="status"> <p class="status">
<template v-if="isAccepted && isOpAccepted">%i18n:@this-game-is-started-soon%<mk-ellipsis/></template> <template v-if="isAccepted && isOpAccepted">{{ $t('this-game-is-started-soon') }}<mk-ellipsis/></template>
<template v-if="isAccepted && !isOpAccepted">%i18n:@waiting-for-other%<mk-ellipsis/></template> <template v-if="isAccepted && !isOpAccepted">{{ $t('waiting-for-other') }}<mk-ellipsis/></template>
<template v-if="!isAccepted && isOpAccepted">%i18n:@waiting-for-me%</template> <template v-if="!isAccepted && isOpAccepted">{{ $t('waiting-for-me') }}</template>
<template v-if="!isAccepted && !isOpAccepted">%i18n:@waiting-for-both%<mk-ellipsis/></template> <template v-if="!isAccepted && !isOpAccepted">{{ $t('waiting-for-both') }}<mk-ellipsis/></template>
</p> </p>
<div class="actions"> <div class="actions">
<form-button @click="exit">%i18n:@cancel%</form-button> <form-button @click="exit">{{ $t('cancel') }}</form-button>
<form-button primary @click="accept" v-if="!isAccepted">%i18n:@ready%</form-button> <form-button primary @click="accept" v-if="!isAccepted">{{ $t('ready') }}</form-button>
<form-button primary @click="cancel" v-if="isAccepted">%i18n:@cancel-ready%</form-button> <form-button primary @click="cancel" v-if="isAccepted">{{ $t('cancel-ready') }}</form-button>
</div> </div>
</footer> </footer>
</div> </div>
@ -115,9 +115,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../../../i18n';
import * as maps from '../../../../../../../games/reversi/maps'; import * as maps from '../../../../../../../games/reversi/maps';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/games/reversi/reversi.room.vue'),
props: ['game', 'connection'], props: ['game', 'connection'],
data() { data() {

View File

@ -4,9 +4,9 @@
<x-gameroom :game="game" :self-nav="selfNav" @go-index="goIndex"/> <x-gameroom :game="game" :self-nav="selfNav" @go-index="goIndex"/>
</div> </div>
<div class="matching" v-else-if="matching"> <div class="matching" v-else-if="matching">
<h1>{{ '%i18n:@matching.waiting-for%'.split('{}')[0] }}<b>{{ matching | userName }}</b>{{ '%i18n:@matching.waiting-for%'.split('{}')[1] }}<mk-ellipsis/></h1> <h1>{{ this.$t('matching.waiting-for').split('{}')[0] }}<b>{{ matching | userName }}</b>{{ this.$t('matching.waiting-for').split('{}')[1] }}<mk-ellipsis/></h1>
<div class="cancel"> <div class="cancel">
<form-button round @click="cancel">%i18n:@matching.cancel%</form-button> <form-button round @click="cancel">{{ $t('matching.cancel') }}</form-button>
</div> </div>
</div> </div>
<div v-else-if="gameId"> <div v-else-if="gameId">
@ -20,11 +20,13 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../../../i18n';
import XGameroom from './reversi.gameroom.vue'; import XGameroom from './reversi.gameroom.vue';
import XIndex from './reversi.index.vue'; import XIndex from './reversi.index.vue';
import Progress from '../../../../scripts/loading'; import Progress from '../../../../scripts/loading';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/games/reversi/reversi.vue'),
components: { components: {
XGameroom, XGameroom,
XIndex XIndex

View File

@ -1,11 +1,11 @@
<template> <template>
<div class="mk-github-setting"> <div class="mk-github-setting">
<p>%i18n:@description%<a :href="`${docsUrl}/link-to-github`" target="_blank">%i18n:@detail%</a></p> <p>{{ $t('description') }}<a :href="`${docsUrl}/link-to-github`" target="_blank">{{ $t('detail') }}</a></p>
<p class="account" v-if="$store.state.i.github" :title="`GitHub ID: ${$store.state.i.github.id}`">%i18n:@connected-to%: <a :href="`https://github.com/${$store.state.i.github.login}`" target="_blank">@{{ $store.state.i.github.login }}</a></p> <p class="account" v-if="$store.state.i.github" :title="`GitHub ID: ${$store.state.i.github.id}`">{{ $t('connected-to') }}: <a :href="`https://github.com/${$store.state.i.github.login}`" target="_blank">@{{ $store.state.i.github.login }}</a></p>
<p> <p>
<a :href="`${apiUrl}/connect/github`" target="_blank" @click.prevent="connect">{{ $store.state.i.github ? '%i18n:@reconnect%' : '%i18n:@connect%' }}</a> <a :href="`${apiUrl}/connect/github`" target="_blank" @click.prevent="connect">{{ $store.state.i.github ? this.$t('reconnect') : this.$t('connect') }}</a>
<span v-if="$store.state.i.github"> or </span> <span v-if="$store.state.i.github"> or </span>
<a :href="`${apiUrl}/disconnect/github`" target="_blank" v-if="$store.state.i.github" @click.prevent="disconnect">%i18n:@disconnect%</a> <a :href="`${apiUrl}/disconnect/github`" target="_blank" v-if="$store.state.i.github" @click.prevent="disconnect">{{ $t('disconnect') }}</a>
</p> </p>
<p class="id" v-if="$store.state.i.github">GitHub ID: {{ $store.state.i.github.id }}</p> <p class="id" v-if="$store.state.i.github">GitHub ID: {{ $store.state.i.github.id }}</p>
</div> </div>
@ -13,9 +13,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import { apiUrl, docsUrl } from '../../../config'; import { apiUrl, docsUrl } from '../../../config';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/github-setting.vue'),
data() { data() {
return { return {
form: null, form: null,

View File

@ -1,13 +1,16 @@
<template> <template>
<div class="mk-google"> <div class="mk-google">
<input type="search" v-model="query" :placeholder="q"> <input type="search" v-model="query" :placeholder="q">
<button @click="search"><fa icon="search"/> %i18n:common.search%</button> <button @click="search"><fa icon="search"/> {{ $t('@.search') }}</button>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n(),
props: ['q'], props: ['q'],
data() { data() {
return { return {

View File

@ -30,7 +30,6 @@ import time from './time.vue';
import timer from './timer.vue'; import timer from './timer.vue';
import mediaList from './media-list.vue'; import mediaList from './media-list.vue';
import uploader from './uploader.vue'; import uploader from './uploader.vue';
import specialMessage from './special-message.vue';
import streamIndicator from './stream-indicator.vue'; import streamIndicator from './stream-indicator.vue';
import ellipsis from './ellipsis.vue'; import ellipsis from './ellipsis.vue';
import messaging from './messaging.vue'; import messaging from './messaging.vue';
@ -84,7 +83,6 @@ Vue.component('mk-time', time);
Vue.component('mk-timer', timer); Vue.component('mk-timer', timer);
Vue.component('mk-media-list', mediaList); Vue.component('mk-media-list', mediaList);
Vue.component('mk-uploader', uploader); Vue.component('mk-uploader', uploader);
Vue.component('mk-special-message', specialMessage);
Vue.component('mk-stream-indicator', streamIndicator); Vue.component('mk-stream-indicator', streamIndicator);
Vue.component('mk-ellipsis', ellipsis); Vue.component('mk-ellipsis', ellipsis);
Vue.component('mk-messaging', messaging); Vue.component('mk-messaging', messaging);

View File

@ -3,15 +3,17 @@
<div class="banner" :style="{ backgroundImage: meta.bannerUrl ? `url(${meta.bannerUrl})` : null }"></div> <div class="banner" :style="{ backgroundImage: meta.bannerUrl ? `url(${meta.bannerUrl})` : null }"></div>
<h1>{{ meta.name }}</h1> <h1>{{ meta.name }}</h1>
<p v-html="meta.description || '%i18n:common.about%'"></p> <p v-html="meta.description || this.$t('@.about')"></p>
<router-link to="/">%i18n:@start%</router-link> <router-link to="/">{{ $t('start') }}</router-link>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/instance.vue'),
data() { data() {
return { return {
meta: null meta: null

View File

@ -2,8 +2,8 @@
<div class="mk-media-banner"> <div class="mk-media-banner">
<div class="sensitive" v-if="media.isSensitive && hide" @click="hide = false"> <div class="sensitive" v-if="media.isSensitive && hide" @click="hide = false">
<span class="icon"><fa icon="exclamation-triangle"/></span> <span class="icon"><fa icon="exclamation-triangle"/></span>
<b>%i18n:@sensitive%</b> <b>{{ $t('sensitive') }}</b>
<span>%i18n:@click-to-show%</span> <span>{{ $t('click-to-show') }}</span>
</div> </div>
<div class="audio" v-else-if="media.type.startsWith('audio')"> <div class="audio" v-else-if="media.type.startsWith('audio')">
<audio class="audio" <audio class="audio"
@ -26,8 +26,10 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/media-banner.vue'),
props: { props: {
media: { media: {
type: Object, type: Object,

View File

@ -8,18 +8,18 @@
ref="textarea" ref="textarea"
@keypress="onKeypress" @keypress="onKeypress"
@paste="onPaste" @paste="onPaste"
placeholder="%i18n:@input-message-here%" :placeholder="$t('placeholder')"
v-autocomplete="'text'" v-autocomplete="'text'"
></textarea> ></textarea>
<div class="file" @click="file = null" v-if="file">{{ file.name }}</div> <div class="file" @click="file = null" v-if="file">{{ file.name }}</div>
<mk-uploader ref="uploader" @uploaded="onUploaded"/> <mk-uploader ref="uploader" @uploaded="onUploaded"/>
<button class="send" @click="send" :disabled="!canSend || sending" title="%i18n:@send%"> <button class="send" @click="send" :disabled="!canSend || sending" :title="$t('send')">
<template v-if="!sending"><fa icon="paper-plane"/></template><template v-if="sending"><fa icon="spinner .spin"/></template> <template v-if="!sending"><fa icon="paper-plane"/></template><template v-if="sending"><fa icon="spinner .spin"/></template>
</button> </button>
<button class="attach-from-local" @click="chooseFile" title="%i18n:@attach-from-local%"> <button class="attach-from-local" @click="chooseFile" :title="$t('attach-from-local')">
<fa icon="upload"/> <fa icon="upload"/>
</button> </button>
<button class="attach-from-drive" @click="chooseFileFromDrive" title="%i18n:@attach-from-drive%"> <button class="attach-from-drive" @click="chooseFileFromDrive" :title="$t('attach-from-drive')">
<fa :icon="['far', 'folder-open']"/> <fa :icon="['far', 'folder-open']"/>
</button> </button>
<input ref="file" type="file" @change="onChangeFile"/> <input ref="file" type="file" @change="onChangeFile"/>
@ -28,9 +28,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import * as autosize from 'autosize'; import * as autosize from 'autosize';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/messaging-room.form.vue'),
props: ['user'], props: ['user'],
data() { data() {
return { return {

View File

@ -3,7 +3,7 @@
<mk-avatar class="avatar" :user="message.user" target="_blank"/> <mk-avatar class="avatar" :user="message.user" target="_blank"/>
<div class="content"> <div class="content">
<div class="balloon" :data-no-text="message.text == null"> <div class="balloon" :data-no-text="message.text == null">
<!-- <button class="delete-button" v-if="isMe" title="%i18n:common.delete%"> <!-- <button class="delete-button" v-if="isMe" :title="$t('@.delete')">
<img src="/assets/desktop/messaging/delete.png" alt="Delete"/> <img src="/assets/desktop/messaging/delete.png" alt="Delete"/>
</button> --> </button> -->
<div class="content" v-if="!message.isDeleted"> <div class="content" v-if="!message.isDeleted">
@ -16,13 +16,13 @@
</div> </div>
</div> </div>
<div class="content" v-if="message.isDeleted"> <div class="content" v-if="message.isDeleted">
<p class="is-deleted">%i18n:@deleted%</p> <p class="is-deleted">{{ $t('deleted') }}</p>
</div> </div>
</div> </div>
<div></div> <div></div>
<mk-url-preview v-for="url in urls" :url="url" :key="url"/> <mk-url-preview v-for="url in urls" :url="url" :key="url"/>
<footer> <footer>
<span class="read" v-if="isMe && message.isRead">%i18n:@is-read%</span> <span class="read" v-if="isMe && message.isRead">{{ $t('is-read') }}</span>
<mk-time :time="message.createdAt"/> <mk-time :time="message.createdAt"/>
<template v-if="message.is_edited"><fa icon="pencil-alt"/></template> <template v-if="message.is_edited"><fa icon="pencil-alt"/></template>
</footer> </footer>
@ -32,9 +32,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import parse from '../../../../../mfm/parse'; import parse from '../../../../../mfm/parse';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/messaging-room.message.vue'),
props: { props: {
message: { message: {
required: true required: true

View File

@ -4,11 +4,11 @@
@drop.prevent.stop="onDrop" @drop.prevent.stop="onDrop"
> >
<div class="body"> <div class="body">
<p class="init" v-if="init"><fa icon="spinner .spin"/>%i18n:common.loading%</p> <p class="init" v-if="init"><fa icon="spinner .spin"/>{{ $t('@.loading') }}</p>
<p class="empty" v-if="!init && messages.length == 0"><fa icon="info-circle"/>%i18n:@empty%</p> <p class="empty" v-if="!init && messages.length == 0"><fa icon="info-circle"/>{{ $t('empty') }}</p>
<p class="no-history" v-if="!init && messages.length > 0 && !existMoreMessages"><fa icon="flag"/>%i18n:@no-history%</p> <p class="no-history" v-if="!init && messages.length > 0 && !existMoreMessages"><fa icon="flag"/>{{ $t('no-history') }}</p>
<button class="more" :class="{ fetching: fetchingMoreMessages }" v-if="existMoreMessages" @click="fetchMoreMessages" :disabled="fetchingMoreMessages"> <button class="more" :class="{ fetching: fetchingMoreMessages }" v-if="existMoreMessages" @click="fetchMoreMessages" :disabled="fetchingMoreMessages">
<template v-if="fetchingMoreMessages"><fa icon="spinner .pulse" fixed-width/></template>{{ fetchingMoreMessages ? '%i18n:common.loading%' : '%i18n:@more%' }} <template v-if="fetchingMoreMessages"><fa icon="spinner .pulse" fixed-width/></template>{{ fetchingMoreMessages ? $t('@.loading') : $t('@.load-more') }}
</button> </button>
<template v-for="(message, i) in _messages"> <template v-for="(message, i) in _messages">
<x-message :message="message" :key="message.id"/> <x-message :message="message" :key="message.id"/>
@ -20,7 +20,7 @@
<footer> <footer>
<transition name="fade"> <transition name="fade">
<div class="new-message" v-show="showIndicator"> <div class="new-message" v-show="showIndicator">
<button @click="onIndicatorClick"><i><fa icon="arrow-circle-down"/></i>%i18n:@new-message%</button> <button @click="onIndicatorClick"><i><fa icon="arrow-circle-down"/></i>{{ $t('new-message') }}</button>
</div> </div>
</transition> </transition>
<x-form :user="user" ref="form"/> <x-form :user="user" ref="form"/>
@ -30,11 +30,13 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import XMessage from './messaging-room.message.vue'; import XMessage from './messaging-room.message.vue';
import XForm from './messaging-room.form.vue'; import XForm from './messaging-room.form.vue';
import { url } from '../../../config'; import { url } from '../../../config';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/messaging-room.vue'),
components: { components: {
XMessage, XMessage,
XForm XForm
@ -60,7 +62,7 @@ export default Vue.extend({
const date = new Date(message.createdAt).getDate(); const date = new Date(message.createdAt).getDate();
const month = new Date(message.createdAt).getMonth() + 1; const month = new Date(message.createdAt).getMonth() + 1;
message._date = date; message._date = date;
message._datetext = '%i18n:common.month-and-day%'.replace('{month}', month.toString()).replace('{day}', date.toString()); message._datetext = this.$t('@.month-and-day').replace('{month}', month.toString()).replace('{day}', date.toString());
return message; return message;
}); });
}, },
@ -120,7 +122,7 @@ export default Vue.extend({
this.form.upload(e.dataTransfer.files[0]); this.form.upload(e.dataTransfer.files[0]);
return; return;
} else if (e.dataTransfer.files.length > 1) { } else if (e.dataTransfer.files.length > 1) {
alert('%i18n:@only-one-file-attached%'); alert(this.$t('only-one-file-attached'));
return; return;
} }

View File

@ -3,7 +3,7 @@
<div class="search" v-if="!compact" :style="{ top: headerTop + 'px' }"> <div class="search" v-if="!compact" :style="{ top: headerTop + 'px' }">
<div class="form"> <div class="form">
<label for="search-input"><i><fa icon="search"/></i></label> <label for="search-input"><i><fa icon="search"/></i></label>
<input v-model="q" type="search" @input="search" @keydown="onSearchKeydown" placeholder="%i18n:@search-user%"/> <input v-model="q" type="search" @input="search" @keydown="onSearchKeydown" :placeholder="$t('placeholder')"/>
</div> </div>
<div class="result"> <div class="result">
<ol class="users" v-if="result.length > 0" ref="searchResult"> <ol class="users" v-if="result.length > 0" ref="searchResult">
@ -38,22 +38,24 @@
<mk-time :time="message.createdAt"/> <mk-time :time="message.createdAt"/>
</header> </header>
<div class="body"> <div class="body">
<p class="text"><span class="me" v-if="isMe(message)">%i18n:@you%:</span>{{ message.text }}</p> <p class="text"><span class="me" v-if="isMe(message)">{{ $t('you') }}:</span>{{ message.text }}</p>
</div> </div>
</div> </div>
</a> </a>
</template> </template>
</div> </div>
<p class="no-history" v-if="!fetching && messages.length == 0">%i18n:@no-history%</p> <p class="no-history" v-if="!fetching && messages.length == 0">{{ $t('no-history') }}</p>
<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p> <p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>{{ $t('@.loading') }}<mk-ellipsis/></p>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import getAcct from '../../../../../misc/acct/render'; import getAcct from '../../../../../misc/acct/render';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/messaging.vue'),
props: { props: {
compact: { compact: {
type: Boolean, type: Boolean,

View File

@ -1,10 +1,10 @@
<template> <template>
<ui-card> <ui-card>
<div slot="title"><fa icon="ban"/> %i18n:@mute-and-block%</div> <div slot="title"><fa icon="ban"/> {{ $t('mute-and-block') }}</div>
<section> <section>
<header>%i18n:@mute%</header> <header>{{ $t('mute') }}</header>
<ui-info v-if="!muteFetching && mute.length == 0">%i18n:@no-muted-users%</ui-info> <ui-info v-if="!muteFetching && mute.length == 0">{{ $t('no-muted-users') }}</ui-info>
<div class="users" v-if="mute.length != 0"> <div class="users" v-if="mute.length != 0">
<div v-for="user in mute" :key="user.id"> <div v-for="user in mute" :key="user.id">
<p><b>{{ user | userName }}</b> @{{ user | acct }}</p> <p><b>{{ user | userName }}</b> @{{ user | acct }}</p>
@ -13,8 +13,8 @@
</section> </section>
<section> <section>
<header>%i18n:@block%</header> <header>{{ $t('block') }}</header>
<ui-info v-if="!blockFetching && block.length == 0">%i18n:@no-blocked-users%</ui-info> <ui-info v-if="!blockFetching && block.length == 0">{{ $t('no-blocked-users') }}</ui-info>
<div class="users" v-if="block.length != 0"> <div class="users" v-if="block.length != 0">
<div v-for="user in block" :key="user.id"> <div v-for="user in block" :key="user.id">
<p><b>{{ user | userName }}</b> @{{ user | acct }}</p> <p><b>{{ user | userName }}</b> @{{ user | acct }}</p>
@ -26,8 +26,10 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/mute-and-block.vue'),
data() { data() {
return { return {
muteFetching: true, muteFetching: true,

View File

@ -1,20 +1,22 @@
<template> <template>
<span class="mk-nav"> <span class="mk-nav">
<a :href="aboutUrl">%i18n:@about%</a> <a :href="aboutUrl">{{ $t('about') }}</a>
<i></i> <i></i>
<a :href="repositoryUrl">%i18n:@repository%</a> <a :href="repositoryUrl">{{ $t('repository') }}</a>
<i></i> <i></i>
<a :href="feedbackUrl" target="_blank">%i18n:@feedback%</a> <a :href="feedbackUrl" target="_blank">{{ $t('feedback') }}</a>
<i></i> <i></i>
<a href="/dev">%i18n:@develop%</a> <a href="/dev">{{ $t('develop') }}</a>
</span> </span>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import { lang } from '../../../config'; import { lang } from '../../../config';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/nav.vue'),
data() { data() {
return { return {
aboutUrl: `/docs/${lang}/about`, aboutUrl: `/docs/${lang}/about`,

View File

@ -6,7 +6,7 @@
<span class="is-bot" v-if="note.user.isBot">bot</span> <span class="is-bot" v-if="note.user.isBot">bot</span>
<span class="is-cat" v-if="note.user.isCat">cat</span> <span class="is-cat" v-if="note.user.isCat">cat</span>
<span class="username"><mk-acct :user="note.user"/></span> <span class="username"><mk-acct :user="note.user"/></span>
<span class="is-verified" v-if="note.user.isVerified" title="%i18n:common.verified-user%"><fa icon="star"/></span> <span class="is-verified" v-if="note.user.isVerified" :title="$t('@.verified-user')"><fa icon="star"/></span>
<div class="info"> <div class="info">
<span class="app" v-if="note.app && !mini">via <b>{{ note.app.name }}</b></span> <span class="app" v-if="note.app && !mini">via <b>{{ note.app.name }}</b></span>
<span class="mobile" v-if="note.viaMobile"><fa icon="mobile-alt"/></span> <span class="mobile" v-if="note.viaMobile"><fa icon="mobile-alt"/></span>
@ -25,8 +25,10 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n(),
props: { props: {
note: { note: {
type: Object, type: Object,

View File

@ -6,28 +6,30 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import { url } from '../../../config'; import { url } from '../../../config';
import copyToClipboard from '../../../common/scripts/copy-to-clipboard'; import copyToClipboard from '../../../common/scripts/copy-to-clipboard';
import Ok from './ok.vue'; import Ok from './ok.vue';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/note-menu.vue'),
props: ['note', 'source', 'compact'], props: ['note', 'source', 'compact'],
computed: { computed: {
items() { items() {
const items = [{ const items = [{
icon: 'info-circle', icon: 'info-circle',
text: '%i18n:@detail%', text: this.$t('detail'),
action: this.detail action: this.detail
}, { }, {
icon: 'link', icon: 'link',
text: '%i18n:@copy-link%', text: this.$t('copy-link'),
action: this.copyLink action: this.copyLink
}]; }];
if (this.note.uri) { if (this.note.uri) {
items.push({ items.push({
icon: 'external-link-square-alt', icon: 'external-link-square-alt',
text: '%i18n:@remote%', text: this.$t('remote'),
action: () => { action: () => {
window.open(this.note.uri, '_blank'); window.open(this.note.uri, '_blank');
} }
@ -39,13 +41,13 @@ export default Vue.extend({
if (this.note.isFavorited) { if (this.note.isFavorited) {
items.push({ items.push({
icon: 'star', icon: 'star',
text: '%i18n:@unfavorite%', text: this.$t('unfavorite'),
action: this.unfavorite action: this.unfavorite
}); });
} else { } else {
items.push({ items.push({
icon: 'star', icon: 'star',
text: '%i18n:@favorite%', text: this.$t('favorite'),
action: this.favorite action: this.favorite
}); });
} }
@ -54,13 +56,13 @@ export default Vue.extend({
if ((this.$store.state.i.pinnedNoteIds || []).includes(this.note.id)) { if ((this.$store.state.i.pinnedNoteIds || []).includes(this.note.id)) {
items.push({ items.push({
icon: 'thumbtack', icon: 'thumbtack',
text: '%i18n:@unpin%', text: this.$t('unpin'),
action: this.unpin action: this.unpin
}); });
} else { } else {
items.push({ items.push({
icon: 'thumbtack', icon: 'thumbtack',
text: '%i18n:@pin%', text: this.$t('pin'),
action: this.pin action: this.pin
}); });
} }
@ -70,7 +72,7 @@ export default Vue.extend({
items.push(null); items.push(null);
items.push({ items.push({
icon: ['far', 'trash-alt'], icon: ['far', 'trash-alt'],
text: '%i18n:@delete%', text: this.$t('delete'),
action: this.del action: this.del
}); });
} }
@ -106,7 +108,7 @@ export default Vue.extend({
}, },
del() { del() {
if (!window.confirm('%i18n:@delete-confirm%')) return; if (!window.confirm(this.$t('delete-confirm'))) return;
(this as any).api('notes/delete', { (this as any).api('notes/delete', {
noteId: this.note.id noteId: this.note.id
}).then(() => { }).then(() => {

View File

@ -1,31 +1,33 @@
<template> <template>
<div> <div>
<ui-button @click="reset">%i18n:@reset%</ui-button> <ui-button @click="reset">{{ $t('reset') }}</ui-button>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/password-settings.vue'),
methods: { methods: {
reset() { reset() {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:@enter-current-password%', title: this.$t('enter-current-password'),
type: 'password' type: 'password'
}).then(currentPassword => { }).then(currentPassword => {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:@enter-new-password%', title: this.$t('enter-new-password'),
type: 'password' type: 'password'
}).then(newPassword => { }).then(newPassword => {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:@enter-new-password-again%', title: this.$t('enter-new-password-again'),
type: 'password' type: 'password'
}).then(newPassword2 => { }).then(newPassword2 => {
if (newPassword !== newPassword2) { if (newPassword !== newPassword2) {
(this as any).apis.dialog({ (this as any).apis.dialog({
title: null, title: null,
text: '%i18n:@not-match%', text: this.$t('not-match'),
actions: [{ actions: [{
text: 'OK' text: 'OK'
}] }]
@ -36,7 +38,7 @@ export default Vue.extend({
currentPasword: currentPassword, currentPasword: currentPassword,
newPassword: newPassword newPassword: newPassword
}).then(() => { }).then(() => {
(this as any).apis.notify('%i18n:@changed%'); (this as any).apis.notify(this.$t('changed'));
}); });
}); });
}); });

View File

@ -1,18 +1,18 @@
<template> <template>
<div class="mk-poll-editor"> <div class="mk-poll-editor">
<p class="caution" v-if="choices.length < 2"> <p class="caution" v-if="choices.length < 2">
<fa icon="exclamation-triangle"/>%i18n:@no-only-one-choice% <fa icon="exclamation-triangle"/>{{ $t('no-only-one-choice') }}
</p> </p>
<ul ref="choices"> <ul ref="choices">
<li v-for="(choice, i) in choices"> <li v-for="(choice, i) in choices">
<input :value="choice" @input="onInput(i, $event)" :placeholder="'%i18n:@choice-n%'.replace('{}', i + 1)"> <input :value="choice" @input="onInput(i, $event)" :placeholder="this.$t('choice-n').replace('{}', i + 1)">
<button @click="remove(i)" title="%i18n:@remove%"> <button @click="remove(i)" :title="$t('remove')">
<fa icon="times"/> <fa icon="times"/>
</button> </button>
</li> </li>
</ul> </ul>
<button class="add" v-if="choices.length < 10" @click="add">%i18n:@add%</button> <button class="add" v-if="choices.length < 10" @click="add">{{ $t('add') }}</button>
<button class="destroy" @click="destroy" title="%i18n:@destroy%"> <button class="destroy" @click="destroy" :title="$t('destroy')">
<fa icon="times"/> <fa icon="times"/>
</button> </button>
</div> </div>
@ -20,8 +20,10 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import { erase } from '../../../../../prelude/array'; import { erase } from '../../../../../prelude/array';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/poll-editor.vue'),
data() { data() {
return { return {
choices: ['', ''] choices: ['', '']

View File

@ -1,28 +1,30 @@
<template> <template>
<div class="mk-poll" :data-is-voted="isVoted"> <div class="mk-poll" :data-is-voted="isVoted">
<ul> <ul>
<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) : ''"> <li v-for="choice in poll.choices" :key="choice.id" @click="vote(choice.id)" :class="{ voted: choice.voted }" :title="!isVoted ? $t('vote-to').replace('{}', choice.text) : ''">
<div class="backdrop" :style="{ 'width': (showResult ? (choice.votes / total * 100) : 0) + '%' }"></div> <div class="backdrop" :style="{ 'width': (showResult ? (choice.votes / total * 100) : 0) + '%' }"></div>
<span> <span>
<template v-if="choice.isVoted"><fa icon="check"/></template> <template v-if="choice.isVoted"><fa icon="check"/></template>
<span>{{ choice.text }}</span> <span>{{ choice.text }}</span>
<span class="votes" v-if="showResult">({{ '%i18n:@vote-count%'.replace('{}', choice.votes) }})</span> <span class="votes" v-if="showResult">({{ $t('vote-count').replace('{}', choice.votes) }})</span>
</span> </span>
</li> </li>
</ul> </ul>
<p v-if="total > 0"> <p v-if="total > 0">
<span>{{ '%i18n:@total-users%'.replace('{}', total) }}</span> <span>{{ $t('total-users').replace('{}', total) }}</span>
<span></span> <span></span>
<a v-if="!isVoted" @click="toggleShowResult">{{ showResult ? '%i18n:@vote%' : '%i18n:@show-result%' }}</a> <a v-if="!isVoted" @click="toggleShowResult">{{ showResult ? $t('vote') : $t('show-result') }}</a>
<span v-if="isVoted">%i18n:@voted%</span> <span v-if="isVoted">{{ $t('voted') }}</span>
</p> </p>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import { sum } from '../../../../../prelude/array'; import { sum } from '../../../../../prelude/array';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/poll.vue'),
props: ['note'], props: ['note'],
data() { data() {
return { return {

View File

@ -1,65 +1,65 @@
<template> <template>
<ui-card> <ui-card>
<div slot="title"><fa icon="user"/> %i18n:@title%</div> <div slot="title"><fa icon="user"/> {{ $t('title') }}</div>
<section class="fit-top"> <section class="fit-top">
<ui-form :disabled="saving"> <ui-form :disabled="saving">
<ui-input v-model="name" :max="30"> <ui-input v-model="name" :max="30">
<span>%i18n:@name%</span> <span>{{ $t('name') }}</span>
</ui-input> </ui-input>
<ui-input v-model="username" readonly> <ui-input v-model="username" readonly>
<span>%i18n:@account%</span> <span>{{ $t('account') }}</span>
<span slot="prefix">@</span> <span slot="prefix">@</span>
<span slot="suffix">@{{ host }}</span> <span slot="suffix">@{{ host }}</span>
</ui-input> </ui-input>
<ui-input v-model="location"> <ui-input v-model="location">
<span>%i18n:@location%</span> <span>{{ $t('location') }}</span>
<span slot="prefix"><fa icon="map-marker-alt"/></span> <span slot="prefix"><fa icon="map-marker-alt"/></span>
</ui-input> </ui-input>
<ui-input v-model="birthday" type="date"> <ui-input v-model="birthday" type="date">
<span>%i18n:@birthday%</span> <span>{{ $t('birthday') }}</span>
<span slot="prefix"><fa icon="birthday-cake"/></span> <span slot="prefix"><fa icon="birthday-cake"/></span>
</ui-input> </ui-input>
<ui-textarea v-model="description" :max="500"> <ui-textarea v-model="description" :max="500">
<span>%i18n:@description%</span> <span>{{ $t('description') }}</span>
</ui-textarea> </ui-textarea>
<ui-input type="file" @change="onAvatarChange"> <ui-input type="file" @change="onAvatarChange">
<span>%i18n:@avatar%</span> <span>{{ $t('avatar') }}</span>
<span slot="icon"><fa icon="image"/></span> <span slot="icon"><fa icon="image"/></span>
<span slot="desc" v-if="avatarUploading">%i18n:@uploading%<mk-ellipsis/></span> <span slot="desc" v-if="avatarUploading">{{ $t('uploading') }}<mk-ellipsis/></span>
</ui-input> </ui-input>
<ui-input type="file" @change="onBannerChange"> <ui-input type="file" @change="onBannerChange">
<span>%i18n:@banner%</span> <span>{{ $t('banner') }}</span>
<span slot="icon"><fa icon="image"/></span> <span slot="icon"><fa icon="image"/></span>
<span slot="desc" v-if="bannerUploading">%i18n:@uploading%<mk-ellipsis/></span> <span slot="desc" v-if="bannerUploading">{{ $t('uploading') }}<mk-ellipsis/></span>
</ui-input> </ui-input>
<ui-button @click="save(true)">%i18n:@save%</ui-button> <ui-button @click="save(true)">{{ $t('save') }}</ui-button>
</ui-form> </ui-form>
</section> </section>
<section> <section>
<header>%i18n:@advanced%</header> <header>{{ $t('advanced') }}</header>
<div> <div>
<ui-switch v-model="isCat" @change="save(false)">%i18n:@is-cat%</ui-switch> <ui-switch v-model="isCat" @change="save(false)">{{ $t('is-cat') }}</ui-switch>
<ui-switch v-model="isBot" @change="save(false)">%i18n:@is-bot%</ui-switch> <ui-switch v-model="isBot" @change="save(false)">{{ $t('is-bot') }}</ui-switch>
<ui-switch v-model="alwaysMarkNsfw">%i18n:common.always-mark-nsfw%</ui-switch> <ui-switch v-model="alwaysMarkNsfw">{{ $t('@.always-mark-nsfw') }}</ui-switch>
</div> </div>
</section> </section>
<section> <section>
<header>%i18n:@privacy%</header> <header>{{ $t('privacy') }}</header>
<div> <div>
<ui-switch v-model="isLocked" @change="save(false)">%i18n:@is-locked%</ui-switch> <ui-switch v-model="isLocked" @change="save(false)">{{ $t('is-locked') }}</ui-switch>
<ui-switch v-model="carefulBot" @change="save(false)">%i18n:@careful-bot%</ui-switch> <ui-switch v-model="carefulBot" @change="save(false)">{{ $t('careful-bot') }}</ui-switch>
</div> </div>
</section> </section>
</ui-card> </ui-card>
@ -67,9 +67,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import { apiUrl, host } from '../../../config'; import { apiUrl, host } from '../../../config';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/profile-editor.vue'),
data() { data() {
return { return {
host, host,
@ -180,7 +182,7 @@ export default Vue.extend({
if (notify) { if (notify) {
this.$swal({ this.$swal({
type: 'success', type: 'success',
text: '%i18n:@saved%' text: this.$t('saved')
}); });
} }
}); });

View File

@ -1,24 +1,26 @@
<template> <template>
<span class="mk-reaction-icon"> <span class="mk-reaction-icon">
<img v-if="reaction == 'like'" src="https://twemoji.maxcdn.com/2/svg/1f44d.svg" alt="%i18n:common.reactions.like%"> <img v-if="reaction == 'like'" src="https://twemoji.maxcdn.com/2/svg/1f44d.svg" :alt="$t('@.reactions.like')">
<img v-if="reaction == 'love'" src="https://twemoji.maxcdn.com/2/svg/2764.svg" alt="%i18n:common.reactions.love%"> <img v-if="reaction == 'love'" src="https://twemoji.maxcdn.com/2/svg/2764.svg" :alt="$t('@.reactions.love')">
<img v-if="reaction == 'laugh'" src="https://twemoji.maxcdn.com/2/svg/1f606.svg" alt="%i18n:common.reactions.laugh%"> <img v-if="reaction == 'laugh'" src="https://twemoji.maxcdn.com/2/svg/1f606.svg" :alt="$t('@.reactions.laugh')">
<img v-if="reaction == 'hmm'" src="https://twemoji.maxcdn.com/2/svg/1f914.svg" alt="%i18n:common.reactions.hmm%"> <img v-if="reaction == 'hmm'" src="https://twemoji.maxcdn.com/2/svg/1f914.svg" :alt="$t('@.reactions.hmm')">
<img v-if="reaction == 'surprise'" src="https://twemoji.maxcdn.com/2/svg/1f62e.svg" alt="%i18n:common.reactions.surprise%"> <img v-if="reaction == 'surprise'" src="https://twemoji.maxcdn.com/2/svg/1f62e.svg" :alt="$t('@.reactions.surprise')">
<img v-if="reaction == 'congrats'" src="https://twemoji.maxcdn.com/2/svg/1f389.svg" alt="%i18n:common.reactions.congrats%"> <img v-if="reaction == 'congrats'" src="https://twemoji.maxcdn.com/2/svg/1f389.svg" :alt="$t('@.reactions.congrats')">
<img v-if="reaction == 'angry'" src="https://twemoji.maxcdn.com/2/svg/1f4a2.svg" alt="%i18n:common.reactions.angry%"> <img v-if="reaction == 'angry'" src="https://twemoji.maxcdn.com/2/svg/1f4a2.svg" :alt="$t('@.reactions.angry')">
<img v-if="reaction == 'confused'" src="https://twemoji.maxcdn.com/2/svg/1f625.svg" alt="%i18n:common.reactions.confused%"> <img v-if="reaction == 'confused'" src="https://twemoji.maxcdn.com/2/svg/1f625.svg" :alt="$t('@.reactions.confused')">
<img v-if="reaction == 'rip'" src="https://twemoji.maxcdn.com/2/svg/1f607.svg" alt="%i18n:common.reactions.rip%"> <img v-if="reaction == 'rip'" src="https://twemoji.maxcdn.com/2/svg/1f607.svg" :alt="$t('@.reactions.rip')">
<template v-if="reaction == 'pudding'"> <template v-if="reaction == 'pudding'">
<img v-if="$store.getters.isSignedIn && $store.state.settings.iLikeSushi" src="https://twemoji.maxcdn.com/2/svg/1f363.svg" alt="%i18n:common.reactions.pudding%"> <img v-if="$store.getters.isSignedIn && $store.state.settings.iLikeSushi" src="https://twemoji.maxcdn.com/2/svg/1f363.svg" :alt="$t('@.reactions.pudding')">
<img v-else src="https://twemoji.maxcdn.com/2/svg/1f36e.svg" alt="%i18n:common.reactions.pudding%"> <img v-else src="https://twemoji.maxcdn.com/2/svg/1f36e.svg" :alt="$t('@.reactions.pudding')">
</template> </template>
</span> </span>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n(),
props: ['reaction'] props: ['reaction']
}); });
</script> </script>

View File

@ -4,16 +4,16 @@
<div class="popover" :class="{ compact, big }" ref="popover"> <div class="popover" :class="{ compact, big }" ref="popover">
<p v-if="!compact">{{ title }}</p> <p v-if="!compact">{{ title }}</p>
<div ref="buttons" :class="{ showFocus }"> <div ref="buttons" :class="{ showFocus }">
<button @click="react('like')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="1" title="%i18n:common.reactions.like%"><mk-reaction-icon reaction='like'/></button> <button @click="react('like')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="1" :title="$t('@.reactions.like')"><mk-reaction-icon reaction='like'/></button>
<button @click="react('love')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="2" title="%i18n:common.reactions.love%"><mk-reaction-icon reaction='love'/></button> <button @click="react('love')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="2" :title="$t('@.reactions.love')"><mk-reaction-icon reaction='love'/></button>
<button @click="react('laugh')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="3" title="%i18n:common.reactions.laugh%"><mk-reaction-icon reaction='laugh'/></button> <button @click="react('laugh')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="3" :title="$t('@.reactions.laugh')"><mk-reaction-icon reaction='laugh'/></button>
<button @click="react('hmm')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="4" title="%i18n:common.reactions.hmm%"><mk-reaction-icon reaction='hmm'/></button> <button @click="react('hmm')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="4" :title="$t('@.reactions.hmm')"><mk-reaction-icon reaction='hmm'/></button>
<button @click="react('surprise')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="5" title="%i18n:common.reactions.surprise%"><mk-reaction-icon reaction='surprise'/></button> <button @click="react('surprise')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="5" :title="$t('@.reactions.surprise')"><mk-reaction-icon reaction='surprise'/></button>
<button @click="react('congrats')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="6" title="%i18n:common.reactions.congrats%"><mk-reaction-icon reaction='congrats'/></button> <button @click="react('congrats')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="6" :title="$t('@.reactions.congrats')"><mk-reaction-icon reaction='congrats'/></button>
<button @click="react('angry')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="7" title="%i18n:common.reactions.angry%"><mk-reaction-icon reaction='angry'/></button> <button @click="react('angry')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="7" :title="$t('@.reactions.angry')"><mk-reaction-icon reaction='angry'/></button>
<button @click="react('confused')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="8" title="%i18n:common.reactions.confused%"><mk-reaction-icon reaction='confused'/></button> <button @click="react('confused')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="8" :title="$t('@.reactions.confused')"><mk-reaction-icon reaction='confused'/></button>
<button @click="react('rip')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="9" title="%i18n:common.reactions.rip%"><mk-reaction-icon reaction='rip'/></button> <button @click="react('rip')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="9" :title="$t('@.reactions.rip')"><mk-reaction-icon reaction='rip'/></button>
<button @click="react('pudding')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="10" title="%i18n:common.reactions.pudding%"><mk-reaction-icon reaction='pudding'/></button> <button @click="react('pudding')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="10" :title="$t('@.reactions.pudding')"><mk-reaction-icon reaction='pudding'/></button>
</div> </div>
</div> </div>
</div> </div>
@ -21,11 +21,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import * as anime from 'animejs'; import * as anime from 'animejs';
const placeholder = '%i18n:@choose-reaction%';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/reaction-picker.vue'),
props: { props: {
note: { note: {
type: Object, type: Object,
@ -67,7 +67,7 @@ export default Vue.extend({
data() { data() {
return { return {
title: placeholder, title: this.$t('choose-reaction'),
focus: null focus: null
}; };
}, },
@ -160,7 +160,7 @@ export default Vue.extend({
}, },
onMouseout(e) { onMouseout(e) {
this.title = placeholder; this.title = this.$t('choose-reaction');
}, },
close() { close() {

View File

@ -17,6 +17,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
export default Vue.extend({ export default Vue.extend({
props: ['note'], props: ['note'],
computed: { computed: {

View File

@ -2,26 +2,28 @@
<form class="mk-signin" :class="{ signing }" @submit.prevent="onSubmit"> <form class="mk-signin" :class="{ signing }" @submit.prevent="onSubmit">
<div class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null }" v-show="withAvatar"></div> <div class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null }" v-show="withAvatar"></div>
<ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @input="onUsernameChange" styl="fill"> <ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @input="onUsernameChange" styl="fill">
<span>%i18n:@username%</span> <span>{{ $t('username') }}</span>
<span slot="prefix">@</span> <span slot="prefix">@</span>
<span slot="suffix">@{{ host }}</span> <span slot="suffix">@{{ host }}</span>
</ui-input> </ui-input>
<ui-input v-model="password" type="password" required styl="fill"> <ui-input v-model="password" type="password" required styl="fill">
<span>%i18n:@password%</span> <span>{{ $t('password') }}</span>
<span slot="prefix"><fa icon="lock"/></span> <span slot="prefix"><fa icon="lock"/></span>
</ui-input> </ui-input>
<ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" required styl="fill"/> <ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" required styl="fill"/>
<ui-button type="submit" :disabled="signing">{{ signing ? '%i18n:@signing-in%' : '%i18n:@signin%' }}</ui-button> <ui-button type="submit" :disabled="signing">{{ signing ? $t('signing-in') : $t('signin') }}</ui-button>
<p style="margin: 8px 0;">%i18n:@or% <a :href="`${apiUrl}/signin/twitter`">%i18n:@signin-with-twitter%</a></p> <p style="margin: 8px 0;"><a :href="`${apiUrl}/signin/twitter`">{{ $t('signin-with-twitter') }}</a></p>
<p style="margin: 8px 0;">%i18n:@or% <a :href="`${apiUrl}/signin/github`">%i18n:@signin-with-github%</a></p> <p style="margin: 8px 0;"><a :href="`${apiUrl}/signin/github`">{{ $t('signin-with-github') }}</a></p>
</form> </form>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import { apiUrl, host } from '../../../config'; import { apiUrl, host } from '../../../config';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/signin.vue'),
props: { props: {
withAvatar: { withAvatar: {
type: Boolean, type: Boolean,
@ -60,7 +62,7 @@ export default Vue.extend({
}, true).then(() => { }, true).then(() => {
location.reload(); location.reload();
}).catch(() => { }).catch(() => {
alert('%i18n:@login-failed%'); alert(this.$t('login-failed'));
this.signing = false; this.signing = false;
}); });
} }

View File

@ -2,51 +2,53 @@
<form class="mk-signup" @submit.prevent="onSubmit" :autocomplete="Math.random()"> <form class="mk-signup" @submit.prevent="onSubmit" :autocomplete="Math.random()">
<template v-if="meta"> <template v-if="meta">
<ui-input v-if="meta.disableRegistration" v-model="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required styl="fill"> <ui-input v-if="meta.disableRegistration" v-model="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required styl="fill">
<span>%i18n:@invitation-code%</span> <span>{{ $t('invitation-code') }}</span>
<span slot="prefix"><fa icon="id-card-alt"/></span> <span slot="prefix"><fa icon="id-card-alt"/></span>
<p slot="desc" v-html="'%i18n:@invitation-info%'.replace('{}', 'mailto:' + meta.maintainer.email)"></p> <p slot="desc" v-html="this.$t('invitation-info').replace('{}', 'mailto:' + meta.maintainer.email)"></p>
</ui-input> </ui-input>
<ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @input="onChangeUsername" styl="fill"> <ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @input="onChangeUsername" styl="fill">
<span>%i18n:@username%</span> <span>{{ $t('username') }}</span>
<span slot="prefix">@</span> <span slot="prefix">@</span>
<span slot="suffix">@{{ host }}</span> <span slot="suffix">@{{ host }}</span>
<p slot="desc" v-if="usernameState == 'wait'" style="color:#999"><fa icon="spinner .pulse" fixed-width/> %i18n:@checking%</p> <p slot="desc" v-if="usernameState == 'wait'" style="color:#999"><fa icon="spinner .pulse" fixed-width/> {{ $t('checking') }}</p>
<p slot="desc" v-if="usernameState == 'ok'" style="color:#3CB7B5"><fa icon="check" fixed-width/> %i18n:@available%</p> <p slot="desc" v-if="usernameState == 'ok'" style="color:#3CB7B5"><fa icon="check" fixed-width/> {{ $t('available') }}</p>
<p slot="desc" v-if="usernameState == 'unavailable'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@unavailable%</p> <p slot="desc" v-if="usernameState == 'unavailable'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> {{ $t('unavailable') }}</p>
<p slot="desc" v-if="usernameState == 'error'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@error%</p> <p slot="desc" v-if="usernameState == 'error'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> {{ $t('error') }}</p>
<p slot="desc" v-if="usernameState == 'invalid-format'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@invalid-format%</p> <p slot="desc" v-if="usernameState == 'invalid-format'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> {{ $t('invalid-format') }}</p>
<p slot="desc" v-if="usernameState == 'min-range'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@too-short%</p> <p slot="desc" v-if="usernameState == 'min-range'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> {{ $t('too-short') }}</p>
<p slot="desc" v-if="usernameState == 'max-range'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@too-long%</p> <p slot="desc" v-if="usernameState == 'max-range'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> {{ $t('too-long') }}</p>
</ui-input> </ui-input>
<ui-input v-model="password" type="password" :autocomplete="Math.random()" required @input="onChangePassword" :with-password-meter="true" styl="fill"> <ui-input v-model="password" type="password" :autocomplete="Math.random()" required @input="onChangePassword" :with-password-meter="true" styl="fill">
<span>%i18n:@password%</span> <span>{{ $t('password') }}</span>
<span slot="prefix"><fa icon="lock"/></span> <span slot="prefix"><fa icon="lock"/></span>
<div slot="desc"> <div slot="desc">
<p v-if="passwordStrength == 'low'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@weak-password%</p> <p v-if="passwordStrength == 'low'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> {{ $t('weak-password') }}</p>
<p v-if="passwordStrength == 'medium'" style="color:#3CB7B5"><fa icon="check" fixed-width/> %i18n:@normal-password%</p> <p v-if="passwordStrength == 'medium'" style="color:#3CB7B5"><fa icon="check" fixed-width/> {{ $t('normal-password') }}</p>
<p v-if="passwordStrength == 'high'" style="color:#3CB7B5"><fa icon="check" fixed-width/> %i18n:@strong-password%</p> <p v-if="passwordStrength == 'high'" style="color:#3CB7B5"><fa icon="check" fixed-width/> {{ $t('strong-password') }}</p>
</div> </div>
</ui-input> </ui-input>
<ui-input v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @input="onChangePasswordRetype" styl="fill"> <ui-input v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @input="onChangePasswordRetype" styl="fill">
<span>%i18n:@password% (%i18n:@retype%)</span> <span>{{ $t('password') }} ({{ $t('retype') }})</span>
<span slot="prefix"><fa icon="lock"/></span> <span slot="prefix"><fa icon="lock"/></span>
<div slot="desc"> <div slot="desc">
<p v-if="passwordRetypeState == 'match'" style="color:#3CB7B5"><fa icon="check" fixed-width/> %i18n:@password-matched%</p> <p v-if="passwordRetypeState == 'match'" style="color:#3CB7B5"><fa icon="check" fixed-width/> {{ $t('password-matched') }}</p>
<p v-if="passwordRetypeState == 'not-match'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@password-not-matched%</p> <p v-if="passwordRetypeState == 'not-match'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> {{ $t('password-not-matched') }}</p>
</div> </div>
</ui-input> </ui-input>
<div v-if="meta.enableRecaptcha" class="g-recaptcha" :data-sitekey="meta.recaptchaSiteKey" style="margin: 16px 0;"></div> <div v-if="meta.enableRecaptcha" class="g-recaptcha" :data-sitekey="meta.recaptchaSiteKey" style="margin: 16px 0;"></div>
<ui-button type="submit">%i18n:@create%</ui-button> <ui-button type="submit">{{ $t('create') }}</ui-button>
</template> </template>
</form> </form>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
const getPasswordStrength = require('syuilo-password-strength'); const getPasswordStrength = require('syuilo-password-strength');
import { host, url } from '../../../config'; import { host, url } from '../../../config';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/signup.vue'),
data() { data() {
return { return {
host, host,
@ -139,7 +141,7 @@ export default Vue.extend({
location.href = '/'; location.href = '/';
}); });
}).catch(() => { }).catch(() => {
alert('%i18n:@some-error%'); alert(this.$t('some-error'));
if (this.meta.enableRecaptcha) { if (this.meta.enableRecaptcha) {
(window as any).grecaptcha.reset(); (window as any).grecaptcha.reset();

View File

@ -1,42 +0,0 @@
<template>
<div class="mk-special-message">
<p v-if="m == 1 && d == 1">%i18n:@new-year%</p>
<p v-if="m == 12 && d == 25">%i18n:@christmas%</p>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
data() {
return {
now: new Date()
};
},
computed: {
d(): number {
return this.now.getDate();
},
m(): number {
return this.now.getMonth() + 1;
}
}
});
</script>
<style lang="stylus" scoped>
.mk-special-message
&:empty
display none
> p
margin 0
padding 4px
text-align center
font-size 14px
font-weight bold
text-transform uppercase
color #fff
background #ff1036
</style>

View File

@ -2,24 +2,26 @@
<div class="mk-stream-indicator"> <div class="mk-stream-indicator">
<p v-if="stream.state == 'initializing'"> <p v-if="stream.state == 'initializing'">
<fa icon="spinner .pulse"/> <fa icon="spinner .pulse"/>
<span>%i18n:@connecting%<mk-ellipsis/></span> <span>{{ $t('connecting') }}<mk-ellipsis/></span>
</p> </p>
<p v-if="stream.state == 'reconnecting'"> <p v-if="stream.state == 'reconnecting'">
<fa icon="spinner .pulse"/> <fa icon="spinner .pulse"/>
<span>%i18n:@reconnecting%<mk-ellipsis/></span> <span>{{ $t('reconnecting') }}<mk-ellipsis/></span>
</p> </p>
<p v-if="stream.state == 'connected'"> <p v-if="stream.state == 'connected'">
<fa icon="check"/> <fa icon="check"/>
<span>%i18n:@connected%</span> <span>{{ $t('connected') }}</span>
</p> </p>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import * as anime from 'animejs'; import * as anime from 'animejs';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/stream-indicator.vue'),
computed: { computed: {
stream() { stream() {
return (this as any).os.stream; return (this as any).os.stream;

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="jtivnzhfwquxpsfidertopbmwmchmnmo"> <div class="jtivnzhfwquxpsfidertopbmwmchmnmo">
<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p> <p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>{{ $t('@.loading') }}<mk-ellipsis/></p>
<p class="empty" v-else-if="tags.length == 0"><fa icon="exclamation-circle"/>%i18n:@empty%</p> <p class="empty" v-else-if="tags.length == 0"><fa icon="exclamation-circle"/>{{ $t('empty') }}</p>
<div v-else> <div v-else>
<vue-word-cloud <vue-word-cloud
:words="tags.slice(0, 20).map(x => [x.name, x.count])" :words="tags.slice(0, 20).map(x => [x.name, x.count])"
@ -19,9 +19,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import * as VueWordCloud from 'vuewordcloud'; import * as VueWordCloud from 'vuewordcloud';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/tag-cloud.vue'),
components: { components: {
[VueWordCloud.name]: VueWordCloud [VueWordCloud.name]: VueWordCloud
}, },

View File

@ -1,96 +1,96 @@
<template> <template>
<div class="nicnklzforebnpfgasiypmpdaaglujqm"> <div class="nicnklzforebnpfgasiypmpdaaglujqm">
<label> <label>
<span>%i18n:@light-theme%</span> <span>{{ $t('light-theme') }}</span>
<ui-select v-model="light" placeholder="%i18n:@light-theme%"> <ui-select v-model="light" :placeholder="$t('placeholder')">
<optgroup label="%i18n:@light-themes%"> <optgroup :label="$t('label')">
<option v-for="x in lightThemes" :value="x.id" :key="x.id">{{ x.name }}</option> <option v-for="x in lightThemes" :value="x.id" :key="x.id">{{ x.name }}</option>
</optgroup> </optgroup>
<optgroup label="%i18n:@dark-themes%"> <optgroup :label="$t('label')">
<option v-for="x in darkThemes" :value="x.id" :key="x.id">{{ x.name }}</option> <option v-for="x in darkThemes" :value="x.id" :key="x.id">{{ x.name }}</option>
</optgroup> </optgroup>
</ui-select> </ui-select>
</label> </label>
<label> <label>
<span>%i18n:@dark-theme%</span> <span>{{ $t('dark-theme') }}</span>
<ui-select v-model="dark" placeholder="%i18n:@dark-theme%"> <ui-select v-model="dark" :placeholder="$t('placeholder')">
<optgroup label="%i18n:@dark-themes%"> <optgroup :label="$t('label')">
<option v-for="x in darkThemes" :value="x.id" :key="x.id">{{ x.name }}</option> <option v-for="x in darkThemes" :value="x.id" :key="x.id">{{ x.name }}</option>
</optgroup> </optgroup>
<optgroup label="%i18n:@light-themes%"> <optgroup :label="$t('label')">
<option v-for="x in lightThemes" :value="x.id" :key="x.id">{{ x.name }}</option> <option v-for="x in lightThemes" :value="x.id" :key="x.id">{{ x.name }}</option>
</optgroup> </optgroup>
</ui-select> </ui-select>
</label> </label>
<details class="creator"> <details class="creator">
<summary><fa icon="palette"/> %i18n:@create-a-theme%</summary> <summary><fa icon="palette"/> {{ $t('create-a-theme') }}</summary>
<div> <div>
<span>%i18n:@base-theme%:</span> <span>{{ $t('base-theme') }}:</span>
<ui-radio v-model="myThemeBase" value="light">%i18n:@base-theme-light%</ui-radio> <ui-radio v-model="myThemeBase" value="light">{{ $t('base-theme-light') }}</ui-radio>
<ui-radio v-model="myThemeBase" value="dark">%i18n:@base-theme-dark%</ui-radio> <ui-radio v-model="myThemeBase" value="dark">{{ $t('base-theme-dark') }}</ui-radio>
</div> </div>
<div> <div>
<ui-input v-model="myThemeName"> <ui-input v-model="myThemeName">
<span>%i18n:@theme-name%</span> <span>{{ $t('theme-name') }}</span>
</ui-input> </ui-input>
<ui-textarea v-model="myThemeDesc"> <ui-textarea v-model="myThemeDesc">
<span>%i18n:@desc%</span> <span>{{ $t('desc') }}</span>
</ui-textarea> </ui-textarea>
</div> </div>
<div> <div>
<div style="padding-bottom:8px;">%i18n:@primary-color%:</div> <div style="padding-bottom:8px;">{{ $t('primary-color') }}:</div>
<color-picker v-model="myThemePrimary"/> <color-picker v-model="myThemePrimary"/>
</div> </div>
<div> <div>
<div style="padding-bottom:8px;">%i18n:@secondary-color%:</div> <div style="padding-bottom:8px;">{{ $t('secondary-color') }}:</div>
<color-picker v-model="myThemeSecondary"/> <color-picker v-model="myThemeSecondary"/>
</div> </div>
<div> <div>
<div style="padding-bottom:8px;">%i18n:@text-color%:</div> <div style="padding-bottom:8px;">{{ $t('text-color') }}:</div>
<color-picker v-model="myThemeText"/> <color-picker v-model="myThemeText"/>
</div> </div>
<ui-button @click="preview()"><fa icon="eye"/> %i18n:@preview-created-theme%</ui-button> <ui-button @click="preview()"><fa icon="eye"/> {{ $t('preview-created-theme') }}</ui-button>
<ui-button primary @click="gen()"><fa :icon="['far', 'save']"/> %i18n:@save-created-theme%</ui-button> <ui-button primary @click="gen()"><fa :icon="['far', 'save']"/> {{ $t('save-created-theme') }}</ui-button>
</details> </details>
<details> <details>
<summary><fa icon="download"/> %i18n:@install-a-theme%</summary> <summary><fa icon="download"/> {{ $t('install-a-theme') }}</summary>
<ui-button @click="import_()"><fa icon="file-import"/> %i18n:@import%</ui-button> <ui-button @click="import_()"><fa icon="file-import"/> {{ $t('import') }}</ui-button>
<input ref="file" type="file" accept=".misskeytheme" style="display:none;" @change="onUpdateImportFile"/> <input ref="file" type="file" accept=".misskeytheme" style="display:none;" @change="onUpdateImportFile"/>
<p>%i18n:@import-by-code%:</p> <p>{{ $t('import-by-code') }}:</p>
<ui-textarea v-model="installThemeCode"> <ui-textarea v-model="installThemeCode">
<span>%i18n:@theme-code%</span> <span>{{ $t('theme-code') }}</span>
</ui-textarea> </ui-textarea>
<ui-button @click="() => install(this.installThemeCode)"><fa icon="check"/> %i18n:@install%</ui-button> <ui-button @click="() => install(this.installThemeCode)"><fa icon="check"/> {{ $t('install') }}</ui-button>
</details> </details>
<details> <details>
<summary><fa icon="folder-open"/> %i18n:@manage-themes%</summary> <summary><fa icon="folder-open"/> {{ $t('manage-themes') }}</summary>
<ui-select v-model="selectedThemeId" placeholder="%i18n:@select-theme%"> <ui-select v-model="selectedThemeId" :placeholder="$t('placeholder')">
<optgroup label="%i18n:@builtin-themes%"> <optgroup :label="$t('label')">
<option v-for="x in builtinThemes" :value="x.id" :key="x.id">{{ x.name }}</option> <option v-for="x in builtinThemes" :value="x.id" :key="x.id">{{ x.name }}</option>
</optgroup> </optgroup>
<optgroup label="%i18n:@my-themes%"> <optgroup :label="$t('label')">
<option v-for="x in installedThemes.filter(t => t.author == this.$store.state.i.username)" :value="x.id" :key="x.id">{{ x.name }}</option> <option v-for="x in installedThemes.filter(t => t.author == this.$store.state.i.username)" :value="x.id" :key="x.id">{{ x.name }}</option>
</optgroup> </optgroup>
<optgroup label="%i18n:@installed-themes%"> <optgroup :label="$t('label')">
<option v-for="x in installedThemes.filter(t => t.author != this.$store.state.i.username)" :value="x.id" :key="x.id">{{ x.name }}</option> <option v-for="x in installedThemes.filter(t => t.author != this.$store.state.i.username)" :value="x.id" :key="x.id">{{ x.name }}</option>
</optgroup> </optgroup>
</ui-select> </ui-select>
<template v-if="selectedTheme"> <template v-if="selectedTheme">
<ui-input readonly :value="selectedTheme.author"> <ui-input readonly :value="selectedTheme.author">
<span>%i18n:@author%</span> <span>{{ $t('author') }}</span>
</ui-input> </ui-input>
<ui-textarea v-if="selectedTheme.desc" readonly :value="selectedTheme.desc"> <ui-textarea v-if="selectedTheme.desc" readonly :value="selectedTheme.desc">
<span>%i18n:@desc%</span> <span>{{ $t('desc') }}</span>
</ui-textarea> </ui-textarea>
<ui-textarea readonly :value="selectedThemeCode"> <ui-textarea readonly :value="selectedThemeCode">
<span>%i18n:@theme-code%</span> <span>{{ $t('theme-code') }}</span>
</ui-textarea> </ui-textarea>
<ui-button @click="export_()" link :download="`${selectedTheme.name}.misskeytheme`" ref="export"><fa icon="box"/> %i18n:@export%</ui-button> <ui-button @click="export_()" link :download="`${selectedTheme.name}.misskeytheme`" ref="export"><fa icon="box"/> {{ $t('export') }}</ui-button>
<ui-button @click="uninstall()" v-if="!builtinThemes.some(t => t.id == selectedTheme.id)"><fa :icon="['far', 'trash-alt']"/> %i18n:@uninstall%</ui-button> <ui-button @click="uninstall()" v-if="!builtinThemes.some(t => t.id == selectedTheme.id)"><fa :icon="['far', 'trash-alt']"/> {{ $t('uninstall') }}</ui-button>
</template> </template>
</details> </details>
</div> </div>
@ -98,6 +98,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import { lightTheme, darkTheme, builtinThemes, applyTheme, Theme } from '../../../theme'; import { lightTheme, darkTheme, builtinThemes, applyTheme, Theme } from '../../../theme';
import { Chrome } from 'vue-color'; import { Chrome } from 'vue-color';
import * as uuid from 'uuid'; import * as uuid from 'uuid';
@ -119,6 +120,7 @@ function convertOldThemedefinition(t) {
} }
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/theme.vue'),
components: { components: {
ColorPicker: Chrome ColorPicker: Chrome
}, },
@ -221,7 +223,7 @@ export default Vue.extend({
} catch (e) { } catch (e) {
this.$swal({ this.$swal({
type: 'error', type: 'error',
text: '%i18n:@invalid-theme%' text: this.$t('invalid-theme')
}); });
return; return;
} }
@ -234,7 +236,7 @@ export default Vue.extend({
if (theme.id == null) { if (theme.id == null) {
this.$swal({ this.$swal({
type: 'error', type: 'error',
text: '%i18n:@invalid-theme%' text: this.$t('invalid-theme')
}); });
return; return;
} }
@ -242,7 +244,7 @@ export default Vue.extend({
if (this.$store.state.device.themes.some(t => t.id == theme.id)) { if (this.$store.state.device.themes.some(t => t.id == theme.id)) {
this.$swal({ this.$swal({
type: 'info', type: 'info',
text: '%i18n:@already-installed%' text: this.$t('already-installed')
}); });
return; return;
} }
@ -254,7 +256,7 @@ export default Vue.extend({
this.$swal({ this.$swal({
type: 'success', type: 'success',
text: '%i18n:@installed%'.replace('{}', theme.name) text: this.$t('installed').replace('{}', theme.name)
}); });
}, },
@ -267,7 +269,7 @@ export default Vue.extend({
this.$swal({ this.$swal({
type: 'info', type: 'info',
text: '%i18n:@uninstalled%'.replace('{}', theme.name) text: this.$t('uninstalled').replace('{}', theme.name)
}); });
}, },
@ -304,7 +306,7 @@ export default Vue.extend({
if (theme.name == null || theme.name.trim() == '') { if (theme.name == null || theme.name.trim() == '') {
this.$swal({ this.$swal({
type: 'warning', type: 'warning',
text: '%i18n:@theme-name-required%' text: this.$t('theme-name-required')
}); });
return; return;
} }
@ -318,7 +320,7 @@ export default Vue.extend({
this.$swal({ this.$swal({
type: 'success', type: 'success',
text: '%i18n:@saved%' text: this.$t('saved')
}); });
} }
} }

View File

@ -8,8 +8,10 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n(),
props: { props: {
time: { time: {
type: [Date, String], type: [Date, String],
@ -44,16 +46,16 @@ export default Vue.extend({
const time = this._time; const time = this._time;
const ago = (this.now.getTime() - time.getTime()) / 1000/*ms*/; const ago = (this.now.getTime() - time.getTime()) / 1000/*ms*/;
return ( return (
ago >= 31536000 ? '%i18n:common.time.years_ago%' .replace('{}', (~~(ago / 31536000)).toString()) : ago >= 31536000 ? this.$t('@.time.years_ago') .replace('{}', (~~(ago / 31536000)).toString()) :
ago >= 2592000 ? '%i18n:common.time.months_ago%' .replace('{}', (~~(ago / 2592000)).toString()) : ago >= 2592000 ? this.$t('@.time.months_ago') .replace('{}', (~~(ago / 2592000)).toString()) :
ago >= 604800 ? '%i18n:common.time.weeks_ago%' .replace('{}', (~~(ago / 604800)).toString()) : ago >= 604800 ? this.$t('@.time.weeks_ago') .replace('{}', (~~(ago / 604800)).toString()) :
ago >= 86400 ? '%i18n:common.time.days_ago%' .replace('{}', (~~(ago / 86400)).toString()) : ago >= 86400 ? this.$t('@.time.days_ago') .replace('{}', (~~(ago / 86400)).toString()) :
ago >= 3600 ? '%i18n:common.time.hours_ago%' .replace('{}', (~~(ago / 3600)).toString()) : ago >= 3600 ? this.$t('@.time.hours_ago') .replace('{}', (~~(ago / 3600)).toString()) :
ago >= 60 ? '%i18n:common.time.minutes_ago%'.replace('{}', (~~(ago / 60)).toString()) : ago >= 60 ? this.$t('@.time.minutes_ago').replace('{}', (~~(ago / 60)).toString()) :
ago >= 10 ? '%i18n:common.time.seconds_ago%'.replace('{}', (~~(ago % 60)).toString()) : ago >= 10 ? this.$t('@.time.seconds_ago').replace('{}', (~~(ago % 60)).toString()) :
ago >= 0 ? '%i18n:common.time.just_now%' : ago >= 0 ? this.$t('@.time.just_now') :
ago < 0 ? '%i18n:common.time.future%' : ago < 0 ? this.$t('@.time.future') :
'%i18n:common.time.unknown%'); this.$t('@.time.unknown'));
} }
}, },
created() { created() {

View File

@ -1,13 +1,13 @@
<template> <template>
<div class="csqvmxybqbycalfhkxvyfrgbrdalkaoc"> <div class="csqvmxybqbycalfhkxvyfrgbrdalkaoc">
<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p> <p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>{{ $t('@.loading') }}<mk-ellipsis/></p>
<p class="empty" v-else-if="stats.length == 0"><fa icon="exclamation-circle"/>%i18n:@empty%</p> <p class="empty" v-else-if="stats.length == 0"><fa icon="exclamation-circle"/>{{ $t('empty') }}</p>
<!-- トランジションを有効にするとなぜかメモリリークする --> <!-- トランジションを有効にするとなぜかメモリリークする -->
<transition-group v-else tag="div" name="chart"> <transition-group v-else tag="div" name="chart">
<div v-for="stat in stats" :key="stat.tag"> <div v-for="stat in stats" :key="stat.tag">
<div class="tag"> <div class="tag">
<router-link :to="`/tags/${ encodeURIComponent(stat.tag) }`" :title="stat.tag">#{{ stat.tag }}</router-link> <router-link :to="`/tags/${ encodeURIComponent(stat.tag) }`" :title="stat.tag">#{{ stat.tag }}</router-link>
<p>{{ '%i18n:@count%'.replace('{}', stat.usersCount) }}</p> <p>{{ this.$t('count').replace('{}', stat.usersCount) }}</p>
</div> </div>
<x-chart class="chart" :src="stat.chart"/> <x-chart class="chart" :src="stat.chart"/>
</div> </div>
@ -17,9 +17,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import XChart from './trends.chart.vue'; import XChart from './trends.chart.vue';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/trends.vue'),
components: { components: {
XChart XChart
}, },

View File

@ -1,11 +1,11 @@
<template> <template>
<div class="mk-twitter-setting"> <div class="mk-twitter-setting">
<p>%i18n:@description%<a :href="`${docsUrl}/link-to-twitter`" target="_blank">%i18n:@detail%</a></p> <p>{{ $t('description') }}<a :href="`${docsUrl}/link-to-twitter`" target="_blank">{{ $t('detail') }}</a></p>
<p class="account" v-if="$store.state.i.twitter" :title="`Twitter ID: ${$store.state.i.twitter.userId}`">%i18n:@connected-to%: <a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p> <p class="account" v-if="$store.state.i.twitter" :title="`Twitter ID: ${$store.state.i.twitter.userId}`">{{ $t('connected-to') }}: <a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p>
<p> <p>
<a :href="`${apiUrl}/connect/twitter`" target="_blank" @click.prevent="connect">{{ $store.state.i.twitter ? '%i18n:@reconnect%' : '%i18n:@connect%' }}</a> <a :href="`${apiUrl}/connect/twitter`" target="_blank" @click.prevent="connect">{{ $store.state.i.twitter ? this.$t('reconnect') : this.$t('connect') }}</a>
<span v-if="$store.state.i.twitter"> or </span> <span v-if="$store.state.i.twitter"> or </span>
<a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="$store.state.i.twitter" @click.prevent="disconnect">%i18n:@disconnect%</a> <a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="$store.state.i.twitter" @click.prevent="disconnect">{{ $t('disconnect') }}</a>
</p> </p>
<p class="id" v-if="$store.state.i.twitter">Twitter ID: {{ $store.state.i.twitter.userId }}</p> <p class="id" v-if="$store.state.i.twitter">Twitter ID: {{ $store.state.i.twitter.userId }}</p>
</div> </div>
@ -13,9 +13,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import { apiUrl, docsUrl } from '../../../config'; import { apiUrl, docsUrl } from '../../../config';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/twitter-setting.vue'),
data() { data() {
return { return {
form: null, form: null,

View File

@ -19,7 +19,6 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
const getPasswordStrength = require('syuilo-password-strength');
export default Vue.extend({ export default Vue.extend({
props: { props: {

View File

@ -5,7 +5,7 @@
<div class="img" :style="{ backgroundImage: `url(${ ctx.img })` }"></div> <div class="img" :style="{ backgroundImage: `url(${ ctx.img })` }"></div>
<p class="name"><fa icon="spinner .pulse"/>{{ ctx.name }}</p> <p class="name"><fa icon="spinner .pulse"/>{{ ctx.name }}</p>
<p class="status"> <p class="status">
<span class="initing" v-if="ctx.progress == undefined">%i18n:@waiting%<mk-ellipsis/></span> <span class="initing" v-if="ctx.progress == undefined">{{ $t('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="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> <span class="percentage" v-if="ctx.progress != undefined">{{ Math.floor((ctx.progress.value / ctx.progress.max) * 100) }}</span>
</p> </p>
@ -19,10 +19,12 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import { apiUrl } from '../../../config'; import { apiUrl } from '../../../config';
import getMD5 from '../../scripts/get-md5'; import getMD5 from '../../scripts/get-md5';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/uploader.vue'),
data() { data() {
return { return {
uploads: [] uploads: []

View File

@ -13,6 +13,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import { toUnicode as decodePunycode } from 'punycode'; import { toUnicode as decodePunycode } from 'punycode';
export default Vue.extend({ export default Vue.extend({
props: ['url', 'target'], props: ['url', 'target'],
data() { data() {

View File

@ -5,34 +5,34 @@
<div @click="choose('public')" :class="{ active: v == 'public' }"> <div @click="choose('public')" :class="{ active: v == 'public' }">
<div><fa icon="globe"/></div> <div><fa icon="globe"/></div>
<div> <div>
<span>%i18n:@public%</span> <span>{{ $t('public') }}</span>
</div> </div>
</div> </div>
<div @click="choose('home')" :class="{ active: v == 'home' }"> <div @click="choose('home')" :class="{ active: v == 'home' }">
<div><fa icon="home"/></div> <div><fa icon="home"/></div>
<div> <div>
<span>%i18n:@home%</span> <span>{{ $t('home') }}</span>
<span>%i18n:@home-desc%</span> <span>{{ $t('home-desc') }}</span>
</div> </div>
</div> </div>
<div @click="choose('followers')" :class="{ active: v == 'followers' }"> <div @click="choose('followers')" :class="{ active: v == 'followers' }">
<div><fa icon="unlock"/></div> <div><fa icon="unlock"/></div>
<div> <div>
<span>%i18n:@followers%</span> <span>{{ $t('followers') }}</span>
<span>%i18n:@followers-desc%</span> <span>{{ $t('followers-desc') }}</span>
</div> </div>
</div> </div>
<div @click="choose('specified')" :class="{ active: v == 'specified' }"> <div @click="choose('specified')" :class="{ active: v == 'specified' }">
<div><fa icon="envelope"/></div> <div><fa icon="envelope"/></div>
<div> <div>
<span>%i18n:@specified%</span> <span>{{ $t('specified') }}</span>
<span>%i18n:@specified-desc%</span> <span>{{ $t('specified-desc') }}</span>
</div> </div>
</div> </div>
<div @click="choose('private')" :class="{ active: v == 'private' }"> <div @click="choose('private')" :class="{ active: v == 'private' }">
<div><fa icon="lock"/></div> <div><fa icon="lock"/></div>
<div> <div>
<span>%i18n:@private%</span> <span>{{ $t('private') }}</span>
</div> </div>
</div> </div>
</div> </div>
@ -41,9 +41,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import * as anime from 'animejs'; import * as anime from 'animejs';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/visibility-chooser.vue'),
props: ['source', 'compact'], props: ['source', 'compact'],
data() { data() {
return { return {

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="syxhndwprovvuqhmyvveewmbqayniwkv" v-if="!fetching"> <div class="syxhndwprovvuqhmyvveewmbqayniwkv" v-if="!fetching">
<div class="signed-in-as" v-html="'%i18n:@signed-in-as%'.replace('{}', `<b>${myName}`)"></div> <div class="signed-in-as" v-html="this.$t('signed-in-as').replace('{}', `<b>${myName}`)"></div>
<main> <main>
<div class="banner" :style="bannerStyle"></div> <div class="banner" :style="bannerStyle"></div>
@ -19,11 +19,11 @@
@click="onClick" @click="onClick"
:disabled="followWait"> :disabled="followWait">
<template v-if="!followWait"> <template v-if="!followWait">
<template v-if="user.hasPendingFollowRequestFromYou && user.isLocked"><fa icon="hourglass-half"/> %i18n:@request-pending%</template> <template v-if="user.hasPendingFollowRequestFromYou && user.isLocked"><fa icon="hourglass-half"/> {{ $t('request-pending') }}</template>
<template v-else-if="user.hasPendingFollowRequestFromYou && !user.isLocked"><fa icon="hourglass-start"/> %i18n:@follow-processing%</template> <template v-else-if="user.hasPendingFollowRequestFromYou && !user.isLocked"><fa icon="hourglass-start"/> {{ $t('follow-processing') }}</template>
<template v-else-if="user.isFollowing"><fa icon="minus"/> %i18n:@following%</template> <template v-else-if="user.isFollowing"><fa icon="minus"/> {{ $t('following') }}</template>
<template v-else-if="!user.isFollowing && user.isLocked"><fa icon="plus"/> %i18n:@follow-request%</template> <template v-else-if="!user.isFollowing && user.isLocked"><fa icon="plus"/> {{ $t('follow-request') }}</template>
<template v-else-if="!user.isFollowing && !user.isLocked"><fa icon="plus"/> %i18n:@follow%</template> <template v-else-if="!user.isFollowing && !user.isLocked"><fa icon="plus"/> {{ $t('follow') }}</template>
</template> </template>
<template v-else><fa icon="spinner .pulse" fixed-width/></template> <template v-else><fa icon="spinner .pulse" fixed-width/></template>
</button> </button>
@ -32,10 +32,12 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import parseAcct from '../../../../../misc/acct/parse'; import parseAcct from '../../../../../misc/acct/parse';
import Progress from '../../../common/scripts/loading'; import Progress from '../../../common/scripts/loading';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/pages/follow.vue'),
data() { data() {
return { return {
fetching: true, fetching: true,

View File

@ -15,13 +15,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> <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> </svg>
</div> </div>
<p class="fetching" v-if="fetching">%i18n:@fetching%<mk-ellipsis/></p> <p class="fetching" v-if="fetching">{{ $t('fetching') }}<mk-ellipsis/></p>
<h1 v-if="!fetching">{{ announcements.length == 0 ? '%i18n:@no-broadcasts%' : announcements[i].title }}</h1> <h1 v-if="!fetching">{{ announcements.length == 0 ? this.$t('no-broadcasts') : announcements[i].title }}</h1>
<p v-if="!fetching"> <p v-if="!fetching">
<span v-if="announcements.length != 0" v-html="announcements[i].text"></span> <span v-if="announcements.length != 0" v-html="announcements[i].text"></span>
<template v-if="announcements.length == 0">%i18n:@have-a-nice-day%</template> <template v-if="announcements.length == 0">{{ $t('have-a-nice-day') }}</template>
</p> </p>
<a v-if="announcements.length > 1" @click="next">%i18n:@next% &gt;&gt;</a> <a v-if="announcements.length > 1" @click="next">{{ $t('next') }} &gt;&gt;</a>
</div> </div>
</mk-widget-container> </mk-widget-container>
</div> </div>
@ -29,6 +29,7 @@
<script lang="ts"> <script lang="ts">
import define from '../../../common/define-widget'; import define from '../../../common/define-widget';
import i18n from '../../../i18n';
export default define({ export default define({
name: 'broadcast', name: 'broadcast',
@ -36,6 +37,7 @@ export default define({
design: 0 design: 0
}) })
}).extend({ }).extend({
i18n: i18n('common/views/widgets/broadcast.vue'),
data() { data() {
return { return {
i: 0, i: 0,

View File

@ -4,27 +4,27 @@
<div class="mkw-calendar--body"> <div class="mkw-calendar--body">
<div class="calendar" :data-is-holiday="isHoliday"> <div class="calendar" :data-is-holiday="isHoliday">
<p class="month-and-year"> <p class="month-and-year">
<span class="year">{{ '%i18n:@year%'.split('{}')[0] }}{{ year }}{{ '%i18n:@year%'.split('{}')[1] }}</span> <span class="year">{{ this.$t('year').split('{}')[0] }}{{ year }}{{ this.$t('year').split('{}')[1] }}</span>
<span class="month">{{ '%i18n:@month%'.split('{}')[0] }}{{ month }}{{ '%i18n:@month%'.split('{}')[1] }}</span> <span class="month">{{ this.$t('month').split('{}')[0] }}{{ month }}{{ this.$t('month').split('{}')[1] }}</span>
</p> </p>
<p class="day">{{ '%i18n:@day%'.split('{}')[0] }}{{ day }}{{ '%i18n:@day%'.split('{}')[1] }}</p> <p class="day">{{ this.$t('day').split('{}')[0] }}{{ day }}{{ this.$t('day').split('{}')[1] }}</p>
<p class="week-day">{{ weekDay }}</p> <p class="week-day">{{ weekDay }}</p>
</div> </div>
<div class="info"> <div class="info">
<div> <div>
<p>%i18n:@today%<b>{{ dayP.toFixed(1) }}%</b></p> <p>{{ $t('today') }}<b>{{ dayP.toFixed(1) }}%</b></p>
<div class="meter"> <div class="meter">
<div class="val" :style="{ width: `${dayP}%` }"></div> <div class="val" :style="{ width: `${dayP}%` }"></div>
</div> </div>
</div> </div>
<div> <div>
<p>%i18n:@this-month%<b>{{ monthP.toFixed(1) }}%</b></p> <p>{{ $t('this-month') }}<b>{{ monthP.toFixed(1) }}%</b></p>
<div class="meter"> <div class="meter">
<div class="val" :style="{ width: `${monthP}%` }"></div> <div class="val" :style="{ width: `${monthP}%` }"></div>
</div> </div>
</div> </div>
<div> <div>
<p>%i18n:@this-year%<b>{{ yearP.toFixed(1) }}%</b></p> <p>{{ $t('this-year') }}<b>{{ yearP.toFixed(1) }}%</b></p>
<div class="meter"> <div class="meter">
<div class="val" :style="{ width: `${yearP}%` }"></div> <div class="val" :style="{ width: `${yearP}%` }"></div>
</div> </div>
@ -37,12 +37,15 @@
<script lang="ts"> <script lang="ts">
import define from '../../../common/define-widget'; import define from '../../../common/define-widget';
import i18n from '../../../i18n';
export default define({ export default define({
name: 'calendar', name: 'calendar',
props: () => ({ props: () => ({
design: 0 design: 0
}) })
}).extend({ }).extend({
i18n: i18n('common/views/widgets/calendar.vue'),
data() { data() {
return { return {
now: new Date(), now: new Date(),
@ -85,13 +88,13 @@ export default define({
this.month = nm + 1; this.month = nm + 1;
this.day = nd; this.day = nd;
this.weekDay = [ this.weekDay = [
'%i18n:common.weekday.sunday%', this.$t('@.weekday.sunday'),
'%i18n:common.weekday.monday%', this.$t('@.weekday.monday'),
'%i18n:common.weekday.tuesday%', this.$t('@.weekday.tuesday'),
'%i18n:common.weekday.wednesday%', this.$t('@.weekday.wednesday'),
'%i18n:common.weekday.thursday%', this.$t('@.weekday.thursday'),
'%i18n:common.weekday.friday%', this.$t('@.weekday.friday'),
'%i18n:common.weekday.saturday%' this.$t('@.weekday.saturday')
][now.getDay()]; ][now.getDay()];
const dayNumer = now.getTime() - new Date(ny, nm, nd).getTime(); const dayNumer = now.getTime() - new Date(ny, nm, nd).getTime();

View File

@ -2,11 +2,11 @@
<div> <div>
<mk-widget-container :show-header="false"> <mk-widget-container :show-header="false">
<article class="dolfvtibguprpxxhfndqaosjitixjohx"> <article class="dolfvtibguprpxxhfndqaosjitixjohx">
<h1><fa icon="heart"/>%i18n:@title%</h1> <h1><fa icon="heart"/>{{ $t('title') }}</h1>
<p v-if="meta"> <p v-if="meta">
{{ '%i18n:@text%'.substr(0, '%i18n:@text%'.indexOf('{')) }} {{ this.$t('text').substr(0, this.$t('text').indexOf('{')) }}
<a :href="'mailto:' + meta.maintainer.email">{{ meta.maintainer.name }}</a> <a :href="'mailto:' + meta.maintainer.email">{{ meta.maintainer.name }}</a>
{{ '%i18n:@text%'.substr('%i18n:@text%'.indexOf('}') + 1) }} {{ this.$t('text').substr(this.$t('text').indexOf('}') + 1) }}
</p> </p>
</article> </article>
</mk-widget-container> </mk-widget-container>
@ -15,9 +15,12 @@
<script lang="ts"> <script lang="ts">
import define from '../../../common/define-widget'; import define from '../../../common/define-widget';
import i18n from '../../../i18n';
export default define({ export default define({
name: 'donation' name: 'donation'
}).extend({ }).extend({
i18n: i18n('common/views/widgets/donation.vue'),
data() { data() {
return { return {
meta: null meta: null

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="mkw-hashtags"> <div class="mkw-hashtags">
<mk-widget-container :show-header="!props.compact"> <mk-widget-container :show-header="!props.compact">
<template slot="header"><fa icon="hashtag"/>%i18n:@title%</template> <template slot="header"><fa icon="hashtag"/>{{ $t('title') }}</template>
<div class="mkw-hashtags--body" :data-mobile="platform == 'mobile'"> <div class="mkw-hashtags--body" :data-mobile="platform == 'mobile'">
<mk-trends/> <mk-trends/>
@ -12,6 +12,7 @@
<script lang="ts"> <script lang="ts">
import define from '../../../common/define-widget'; import define from '../../../common/define-widget';
import i18n from '../../../i18n';
export default define({ export default define({
name: 'hashtags', name: 'hashtags',
@ -19,6 +20,7 @@ export default define({
compact: false compact: false
}) })
}).extend({ }).extend({
i18n: i18n('common/views/widgets/hashtags.vue'),
methods: { methods: {
func() { func() {
this.props.compact = !this.props.compact; this.props.compact = !this.props.compact;

View File

@ -1,11 +1,11 @@
<template> <template>
<div class="mkw-memo"> <div class="mkw-memo">
<mk-widget-container :show-header="!props.compact"> <mk-widget-container :show-header="!props.compact">
<template slot="header"><fa :icon="['far', 'sticky-note']"/>%i18n:@title%</template> <template slot="header"><fa :icon="['far', 'sticky-note']"/>{{ $t('title') }}</template>
<div class="mkw-memo--body"> <div class="mkw-memo--body">
<textarea v-model="text" placeholder="%i18n:@memo%" @input="onChange"></textarea> <textarea v-model="text" :placeholder="$t('placeholder')" @input="onChange"></textarea>
<button @click="saveMemo" :disabled="!changed">%i18n:@save%</button> <button @click="saveMemo" :disabled="!changed">{{ $t('save') }}</button>
</div> </div>
</mk-widget-container> </mk-widget-container>
</div> </div>
@ -13,6 +13,7 @@
<script lang="ts"> <script lang="ts">
import define from '../../define-widget'; import define from '../../define-widget';
import i18n from '../../../i18n';
export default define({ export default define({
name: 'memo', name: 'memo',
@ -20,6 +21,7 @@ export default define({
compact: false compact: false
}) })
}).extend({ }).extend({
i18n: i18n('common/views/widgets/memo.vue'),
data() { data() {
return { return {
text: null, text: null,

View File

@ -1,25 +1,29 @@
<template> <template>
<div class="mkw-photo-stream" :class="$style.root" :data-melt="props.design == 2"> <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"> <mk-widget-container :show-header="props.design == 0" :naked="props.design == 2">
<template slot="header"><fa icon="camera"/>%i18n:@title%</template> <template slot="header"><fa icon="camera"/>{{ $t('title') }}</template>
<p :class="$style.fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p> <p :class="$style.fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>{{ $t('@.loading') }}<mk-ellipsis/></p>
<div :class="$style.stream" v-if="!fetching && images.length > 0"> <div :class="$style.stream" v-if="!fetching && images.length > 0">
<div v-for="image in images" :class="$style.img" :style="`background-image: url(${image.thumbnailUrl || image.url})`"></div> <div v-for="image in images" :class="$style.img" :style="`background-image: url(${image.thumbnailUrl || image.url})`"></div>
</div> </div>
<p :class="$style.empty" v-if="!fetching && images.length == 0">%i18n:@no-photos%</p> <p :class="$style.empty" v-if="!fetching && images.length == 0">{{ $t('no-photos') }}</p>
</mk-widget-container> </mk-widget-container>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import define from '../../../common/define-widget'; import define from '../../../common/define-widget';
import i18n from '../../../i18n';
export default define({ export default define({
name: 'photo-stream', name: 'photo-stream',
props: () => ({ props: () => ({
design: 0 design: 0
}) })
}).extend({ }).extend({
i18n: i18n('common/views/widgets/photo-stream.vue'),
data() { data() {
return { return {
images: [], images: [],

View File

@ -1,8 +1,8 @@
<template> <template>
<div class="mkw-posts-monitor"> <div class="mkw-posts-monitor">
<mk-widget-container :show-header="props.design == 0" :naked="props.design == 2"> <mk-widget-container :show-header="props.design == 0" :naked="props.design == 2">
<template slot="header"><fa icon="chart-line"/>%i18n:@title%</template> <template slot="header"><fa icon="chart-line"/>{{ $t('title') }}</template>
<button slot="func" @click="toggle" title="%i18n:@toggle%"><fa icon="sort"/></button> <button slot="func" @click="toggle" :title="$t('toggle')"><fa icon="sort"/></button>
<div class="qpdmibaztplkylerhdbllwcokyrfxeyj" :class="{ dual: props.view == 0 }"> <div class="qpdmibaztplkylerhdbllwcokyrfxeyj" :class="{ dual: props.view == 0 }">
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" v-show="props.view != 2"> <svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" v-show="props.view != 2">
@ -70,15 +70,18 @@
<script lang="ts"> <script lang="ts">
import define from '../../../common/define-widget'; import define from '../../../common/define-widget';
import i18n from '../../../i18n';
import * as uuid from 'uuid'; import * as uuid from 'uuid';
export default define({ export default define({
name: 'server', name: 'posts-monitor',
props: () => ({ props: () => ({
design: 0, design: 0,
view: 0 view: 0
}) })
}).extend({ }).extend({
i18n: i18n('common/views/widgets/posts-monitor.vue'),
data() { data() {
return { return {
connection: null, connection: null,

View File

@ -5,7 +5,7 @@
<button slot="func" title="設定" @click="setting"><fa icon="cog"/></button> <button slot="func" title="設定" @click="setting"><fa icon="cog"/></button>
<div class="mkw-rss--body" :data-mobile="platform == 'mobile'"> <div class="mkw-rss--body" :data-mobile="platform == 'mobile'">
<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p> <p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>{{ $t('@.loading') }}<mk-ellipsis/></p>
<div class="feed" v-else> <div class="feed" v-else>
<a v-for="item in items" :href="item.link" target="_blank">{{ item.title }}</a> <a v-for="item in items" :href="item.link" target="_blank">{{ item.title }}</a>
</div> </div>
@ -16,6 +16,8 @@
<script lang="ts"> <script lang="ts">
import define from '../../../common/define-widget'; import define from '../../../common/define-widget';
import i18n from '../../../i18n';
export default define({ export default define({
name: 'rss', name: 'rss',
props: () => ({ props: () => ({
@ -23,6 +25,7 @@ export default define({
url: 'http://news.yahoo.co.jp/pickup/rss.xml' url: 'http://news.yahoo.co.jp/pickup/rss.xml'
}) })
}).extend({ }).extend({
i18n: i18n(),
data() { data() {
return { return {
items: [], items: [],

View File

@ -1,10 +1,10 @@
<template> <template>
<div class="mkw-server"> <div class="mkw-server">
<mk-widget-container :show-header="props.design == 0" :naked="props.design == 2"> <mk-widget-container :show-header="props.design == 0" :naked="props.design == 2">
<template slot="header"><fa icon="server"/>%i18n:@title%</template> <template slot="header"><fa icon="server"/>{{ $t('title') }}</template>
<button slot="func" @click="toggle" title="%i18n:@toggle%"><fa icon="sort"/></button> <button slot="func" @click="toggle" :title="$t('toggle')"><fa icon="sort"/></button>
<p :class="$style.fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p> <p :class="$style.fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>{{ $t('@.loading') }}<mk-ellipsis/></p>
<template v-if="!fetching"> <template v-if="!fetching">
<x-cpu-memory v-show="props.view == 0" :connection="connection"/> <x-cpu-memory v-show="props.view == 0" :connection="connection"/>
<x-cpu v-show="props.view == 1" :connection="connection" :meta="meta"/> <x-cpu v-show="props.view == 1" :connection="connection" :meta="meta"/>
@ -19,6 +19,7 @@
<script lang="ts"> <script lang="ts">
import define from '../../../common/define-widget'; import define from '../../../common/define-widget';
import i18n from '../../../i18n';
import XCpuMemory from './server.cpu-memory.vue'; import XCpuMemory from './server.cpu-memory.vue';
import XCpu from './server.cpu.vue'; import XCpu from './server.cpu.vue';
import XMemory from './server.memory.vue'; import XMemory from './server.memory.vue';
@ -33,6 +34,8 @@ export default define({
view: 0 view: 0
}) })
}).extend({ }).extend({
i18n: i18n('common/views/widgets/server.vue'),
components: { components: {
XCpuMemory, XCpuMemory,
XCpu, XCpu,

View File

@ -2,10 +2,10 @@
<div class="mkw-slideshow" :data-mobile="platform == 'mobile'"> <div class="mkw-slideshow" :data-mobile="platform == 'mobile'">
<div @click="choose"> <div @click="choose">
<p v-if="props.folder === undefined"> <p v-if="props.folder === undefined">
<template v-if="isCustomizeMode">%i18n:@folder-customize-mode%</template> <template v-if="isCustomizeMode">{{ $t('folder-customize-mode') }}</template>
<template v-else>%i18n:@folder%</template> <template v-else>{{ $t('folder') }}</template>
</p> </p>
<p v-if="props.folder !== undefined && images.length == 0 && !fetching">%i18n:@no-image%</p> <p v-if="props.folder !== undefined && images.length == 0 && !fetching">{{ $t('no-image') }}</p>
<div ref="slideA" class="slide a"></div> <div ref="slideA" class="slide a"></div>
<div ref="slideB" class="slide b"></div> <div ref="slideB" class="slide b"></div>
</div> </div>
@ -15,6 +15,8 @@
<script lang="ts"> <script lang="ts">
import * as anime from 'animejs'; import * as anime from 'animejs';
import define from '../../../common/define-widget'; import define from '../../../common/define-widget';
import i18n from '../../../i18n';
export default define({ export default define({
name: 'slideshow', name: 'slideshow',
props: () => ({ props: () => ({
@ -22,6 +24,8 @@ export default define({
size: 0 size: 0
}) })
}).extend({ }).extend({
i18n: i18n('common/views/widgets/slideshow.vue'),
data() { data() {
return { return {
images: [], images: [],

View File

@ -7,35 +7,37 @@
<script lang="ts"> <script lang="ts">
import * as anime from 'animejs'; import * as anime from 'animejs';
import define from '../../../common/define-widget'; import define from '../../../common/define-widget';
import i18n from '../../../i18n';
const tips = [
'%i18n:@tips-line1%',
'%i18n:@tips-line2%',
'%i18n:@tips-line3%',
'%i18n:@tips-line4%',
'%i18n:@tips-line5%',
'%i18n:@tips-line6%',
'%i18n:@tips-line7%',
'%i18n:@tips-line8%',
'%i18n:@tips-line9%',
'%i18n:@tips-line10%',
'%i18n:@tips-line11%',
'%i18n:@tips-line13%',
'%i18n:@tips-line14%',
'%i18n:@tips-line17%',
'%i18n:@tips-line19%',
'%i18n:@tips-line20%',
'%i18n:@tips-line21%',
'%i18n:@tips-line23%',
'%i18n:@tips-line24%',
'%i18n:@tips-line25%'
]
export default define({ export default define({
name: 'tips' name: 'tips'
}).extend({ }).extend({
i18n: i18n('common/views/widgets/tips.vue'),
data() { data() {
return { return {
tips: [
this.$t('tips-line1'),
this.$t('tips-line2'),
this.$t('tips-line3'),
this.$t('tips-line4'),
this.$t('tips-line5'),
this.$t('tips-line6'),
this.$t('tips-line7'),
this.$t('tips-line8'),
this.$t('tips-line9'),
this.$t('tips-line10'),
this.$t('tips-line11'),
this.$t('tips-line13'),
this.$t('tips-line14'),
this.$t('tips-line17'),
this.$t('tips-line19'),
this.$t('tips-line20'),
this.$t('tips-line21'),
this.$t('tips-line23'),
this.$t('tips-line24'),
this.$t('tips-line25')
],
tip: null, tip: null,
clock: null clock: null
}; };

View File

@ -1,6 +1,6 @@
<template> <template>
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" @mousedown.prevent="onMousedown"> <svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" @mousedown.prevent="onMousedown">
<title>%i18n:@total%<br/>%i18n:@notes%<br/>%i18n:@replies%<br/>%i18n:@renotes%</title> <title>{{ $t('total') }}<br/>{{ $t('notes') }}<br/>{{ $t('replies') }}<br/>{{ $t('renotes') }}</title>
<polyline <polyline
:points="pointsNote" :points="pointsNote"
fill="none" fill="none"
@ -27,6 +27,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
function dragListen(fn) { function dragListen(fn) {
window.addEventListener('mousemove', fn); window.addEventListener('mousemove', fn);
@ -41,6 +42,7 @@ function dragClear(fn) {
} }
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/activity.chart.vue'),
props: ['data'], props: ['data'],
data() { data() {
return { return {

View File

@ -1,10 +1,10 @@
<template> <template>
<div class="mk-activity"> <div class="mk-activity">
<mk-widget-container :show-header="design == 0" :naked="design == 2"> <mk-widget-container :show-header="design == 0" :naked="design == 2">
<template slot="header"><fa icon="chart-bar"/>%i18n:@title%</template> <template slot="header"><fa icon="chart-bar"/>{{ $t('title') }}</template>
<button slot="func" title="%i18n:@toggle%" @click="toggle"><fa icon="sort"/></button> <button slot="func" :title="$t('toggle')" @click="toggle"><fa icon="sort"/></button>
<p :class="$style.fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p> <p :class="$style.fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>{{ $t('@.loading') }}<mk-ellipsis/></p>
<template v-else> <template v-else>
<x-calendar v-show="view == 0" :data="[].concat(activity)"/> <x-calendar v-show="view == 0" :data="[].concat(activity)"/>
<x-chart v-show="view == 1" :data="[].concat(activity)"/> <x-chart v-show="view == 1" :data="[].concat(activity)"/>
@ -15,10 +15,12 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import XCalendar from './activity.calendar.vue'; import XCalendar from './activity.calendar.vue';
import XChart from './activity.chart.vue'; import XChart from './activity.chart.vue';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/activity.vue'),
components: { components: {
XCalendar, XCalendar,
XChart XChart

View File

@ -1,9 +1,9 @@
<template> <template>
<div class="mk-calendar" :data-melt="design == 4 || design == 5"> <div class="mk-calendar" :data-melt="design == 4 || design == 5">
<template v-if="design == 0 || design == 1"> <template v-if="design == 0 || design == 1">
<button @click="prev" title="%i18n:@prev%"><fa icon="chevron-circle-left"/></button> <button @click="prev" :title="$t('prev')"><fa icon="chevron-circle-left"/></button>
<p class="title">{{ '%i18n:@title%'.replace('{1}', year).replace('{2}', month) }}</p> <p class="title">{{ $t('title', { year, month }) }}</p>
<button @click="next" title="%i18n:@next%"><fa icon="chevron-circle-right"/></button> <button @click="next" :title="$t('next')"><fa icon="chevron-circle-right"/></button>
</template> </template>
<div class="calendar"> <div class="calendar">
@ -21,7 +21,7 @@
:data-is-out-of-range="isOutOfRange(i + 1)" :data-is-out-of-range="isOutOfRange(i + 1)"
:data-is-donichi="isDonichi(i + 1)" :data-is-donichi="isDonichi(i + 1)"
@click="go(i + 1)" @click="go(i + 1)"
:title="isOutOfRange(i + 1) ? null : '%i18n:@go%'" :title="isOutOfRange(i + 1) ? null : $t('go')"
> >
<div>{{ i + 1 }}</div> <div>{{ i + 1 }}</div>
</div> </div>
@ -31,6 +31,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
const eachMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; const eachMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
@ -39,6 +40,7 @@ function isLeapYear(year) {
} }
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/calendar.vue'),
props: { props: {
design: { design: {
default: 0 default: 0
@ -55,13 +57,13 @@ export default Vue.extend({
month: new Date().getMonth() + 1, month: new Date().getMonth() + 1,
selected: new Date(), selected: new Date(),
weekdayText: [ weekdayText: [
'%i18n:common.weekday-short.sunday%', this.$t('@.weekday-short.sunday'),
'%i18n:common.weekday-short.monday%', this.$t('@.weekday-short.monday'),
'%i18n:common.weekday-short.tuesday%', this.$t('@.weekday-short.tuesday'),
'%i18n:common.weekday-short.wednesday%', this.$t('@.weekday-short.wednesday'),
'%i18n:common.weekday-short.thursday%', this.$t('@.weekday-short.thursday'),
'%i18n:common.weekday-short.friday%', this.$t('@.weekday-short.friday'),
'%i18n:common.weekday-short.saturday%' this.$t('@.weekday-short.saturday')
] ]
}; };
}, },

View File

@ -2,7 +2,7 @@
<mk-window ref="window" is-modal width="800px" height="500px" @closed="destroyDom"> <mk-window ref="window" is-modal width="800px" height="500px" @closed="destroyDom">
<span slot="header"> <span slot="header">
<span v-html="title" :class="$style.title"></span> <span v-html="title" :class="$style.title"></span>
<span :class="$style.count" v-if="multiple && files.length > 0">({{ files.length }}%i18n:@choose-file%)</span> <span :class="$style.count" v-if="multiple && files.length > 0">({{ $t('chosen-files', { count: files.length }) }})</span>
</span> </span>
<mk-drive <mk-drive
@ -13,22 +13,24 @@
@change-selection="onChangeSelection" @change-selection="onChangeSelection"
/> />
<div :class="$style.footer"> <div :class="$style.footer">
<button :class="$style.upload" title="%i18n:@upload%" @click="upload"><fa icon="upload"/></button> <button :class="$style.upload" :title="$t('title')" @click="upload"><fa icon="upload"/></button>
<button :class="$style.cancel" @click="cancel">%i18n:@cancel%</button> <button :class="$style.cancel" @click="cancel">{{ $t('cancel') }}</button>
<button :class="$style.ok" :disabled="multiple && files.length == 0" @click="ok">%i18n:@ok%</button> <button :class="$style.ok" :disabled="multiple && files.length == 0" @click="ok">{{ $t('ok') }}</button>
</div> </div>
</mk-window> </mk-window>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/choose-file-from-drive-window.vue'),
props: { props: {
multiple: { multiple: {
default: false default: false
}, },
title: { title: {
default: '<fa :icon="['far', 'file']"/>%i18n:@choose-prompt%' default: () => this.$t('choose-prompt')
} }
}, },
data() { data() {
@ -59,8 +61,6 @@ export default Vue.extend({
</script> </script>
<style lang="stylus" module> <style lang="stylus" module>
.title .title
> [data-icon] > [data-icon]
margin-right 4px margin-right 4px

View File

@ -10,18 +10,20 @@
:multiple="false" :multiple="false"
/> />
<div :class="$style.footer"> <div :class="$style.footer">
<button :class="$style.cancel" @click="cancel">%i18n:@cancel%</button> <button :class="$style.cancel" @click="cancel">{{ $t('cancel') }}</button>
<button :class="$style.ok" @click="ok">%i18n:@ok%</button> <button :class="$style.ok" @click="ok">{{ $t('ok') }}</button>
</div> </div>
</mk-window> </mk-window>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/choose-folder-from-drive-window.vue'),
props: { props: {
title: { title: {
default: '<fa :icon="['far', 'folder']"/>%i18n:@choose-prompt%' default: () => this.$t('choose-prompt')
} }
}, },
methods: { methods: {

View File

@ -10,18 +10,20 @@
/> />
</div> </div>
<div :class="$style.actions"> <div :class="$style.actions">
<button :class="$style.skip" @click="skip">%i18n:@skip%</button> <button :class="$style.skip" @click="skip">{{ $t('skip') }}</button>
<button :class="$style.cancel" @click="cancel">%i18n:@cancel%</button> <button :class="$style.cancel" @click="cancel">{{ $t('cancel') }}</button>
<button :class="$style.ok" @click="ok">%i18n:@ok%</button> <button :class="$style.ok" @click="ok">{{ $t('ok') }}</button>
</div> </div>
</mk-window> </mk-window>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import VueCropper from 'vue-cropperjs'; import VueCropper from 'vue-cropperjs';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/crop-window.vue'),
components: { components: {
VueCropper VueCropper
}, },

View File

@ -1,8 +1,8 @@
<template> <template>
<mk-window ref="window" @closed="destroyDom" width="800px" height="500px" :popout-url="popout"> <mk-window ref="window" @closed="destroyDom" width="800px" height="500px" :popout-url="popout">
<template slot="header"> <template slot="header">
<p v-if="usage" :class="$style.info"><b>{{ usage.toFixed(1) }}%</b> %i18n:@used%</p> <p v-if="usage" :class="$style.info"><b>{{ usage.toFixed(1) }}%</b> {{ $t('used') }}</p>
<span :class="$style.title"><fa icon="cloud"/>%i18n:common.drive%</span> <span :class="$style.title"><fa icon="cloud"/>{{ $t('@.drive') }}</span>
</template> </template>
<mk-drive :class="$style.browser" multiple :init-folder="folder" ref="browser"/> <mk-drive :class="$style.browser" multiple :init-folder="folder" ref="browser"/>
</mk-window> </mk-window>
@ -10,9 +10,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import { url } from '../../../config'; import { url } from '../../../config';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/drive-window.vue'),
props: ['folder'], props: ['folder'],
data() { data() {
return { return {

View File

@ -11,15 +11,15 @@
> >
<div class="label" v-if="$store.state.i.avatarId == file.id"> <div class="label" v-if="$store.state.i.avatarId == file.id">
<img src="/assets/label.svg"/> <img src="/assets/label.svg"/>
<p>%i18n:@avatar%</p> <p>{{ $t('avatar') }}</p>
</div> </div>
<div class="label" v-if="$store.state.i.bannerId == file.id"> <div class="label" v-if="$store.state.i.bannerId == file.id">
<img src="/assets/label.svg"/> <img src="/assets/label.svg"/>
<p>%i18n:@banner%</p> <p>{{ $t('banner') }}</p>
</div> </div>
<div class="label red" v-if="file.isSensitive"> <div class="label red" v-if="file.isSensitive">
<img src="/assets/label-red.svg"/> <img src="/assets/label-red.svg"/>
<p>%i18n:@nsfw%</p> <p>{{ $t('nsfw') }}</p>
</div> </div>
<div class="thumbnail" ref="thumbnail" :style="`background-color: ${ background }`"> <div class="thumbnail" ref="thumbnail" :style="`background-color: ${ background }`">
<img :src="file.thumbnailUrl" alt="" @load="onThumbnailLoaded"/> <img :src="file.thumbnailUrl" alt="" @load="onThumbnailLoaded"/>
@ -33,11 +33,13 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import * as anime from 'animejs'; import * as anime from 'animejs';
import contextmenu from '../../api/contextmenu'; import contextmenu from '../../api/contextmenu';
import copyToClipboard from '../../../common/scripts/copy-to-clipboard'; import copyToClipboard from '../../../common/scripts/copy-to-clipboard';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/drive.file.vue'),
props: ['file'], props: ['file'],
data() { data() {
return { return {
@ -70,44 +72,44 @@ export default Vue.extend({
this.isContextmenuShowing = true; this.isContextmenuShowing = true;
contextmenu((this as any).os)(e, [{ contextmenu((this as any).os)(e, [{
type: 'item', type: 'item',
text: '%i18n:@contextmenu.rename%', text: this.$t('contextmenu.rename'),
icon: 'i-cursor', icon: 'i-cursor',
action: this.rename action: this.rename
}, { }, {
type: 'item', type: 'item',
text: this.file.isSensitive ? '%i18n:@contextmenu.unmark-as-sensitive%' : '%i18n:@contextmenu.mark-as-sensitive%', text: this.file.isSensitive ? this.$t('contextmenu.unmark-as-sensitive') : this.$t('contextmenu.mark-as-sensitive'),
icon: this.file.isSensitive ? ['far', 'eye'] : ['far', 'eye-slash'], icon: this.file.isSensitive ? ['far', 'eye'] : ['far', 'eye-slash'],
action: this.toggleSensitive action: this.toggleSensitive
}, null, { }, null, {
type: 'item', type: 'item',
text: '%i18n:@contextmenu.copy-url%', text: this.$t('contextmenu.copy-url'),
icon: 'link', icon: 'link',
action: this.copyUrl action: this.copyUrl
}, { }, {
type: 'link', type: 'link',
href: `${this.file.url}?download`, href: `${this.file.url}?download`,
text: '%i18n:@contextmenu.download%', text: this.$t('contextmenu.download'),
icon: 'download', icon: 'download',
}, null, { }, null, {
type: 'item', type: 'item',
text: '%i18n:common.delete%', text: this.$t('@.delete'),
icon: ['far', 'trash-alt'], icon: ['far', 'trash-alt'],
action: this.deleteFile action: this.deleteFile
}, null, { }, null, {
type: 'nest', type: 'nest',
text: '%i18n:@contextmenu.else-files%', text: this.$t('contextmenu.else-files'),
menu: [{ menu: [{
type: 'item', type: 'item',
text: '%i18n:@contextmenu.set-as-avatar%', text: this.$t('contextmenu.set-as-avatar'),
action: this.setAsAvatar action: this.setAsAvatar
}, { }, {
type: 'item', type: 'item',
text: '%i18n:@contextmenu.set-as-banner%', text: this.$t('contextmenu.set-as-banner'),
action: this.setAsBanner action: this.setAsBanner
}] }]
}, /*{ }, /*{
type: 'nest', type: 'nest',
text: '%i18n:@contextmenu.open-in-app%', text: this.$t('contextmenu.open-in-app'),
menu: [{ menu: [{
type: 'item', type: 'item',
text: '%i18n:@contextmenu.add-app%...', text: '%i18n:@contextmenu.add-app%...',
@ -148,8 +150,8 @@ export default Vue.extend({
rename() { rename() {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:@contextmenu.rename-file%', title: this.$t('contextmenu.rename-file'),
placeholder: '%i18n:@contextmenu.input-new-file-name%', placeholder: this.$t('contextmenu.input-new-file-name'),
default: this.file.name, default: this.file.name,
allowEmpty: false allowEmpty: false
}).then(name => { }).then(name => {
@ -170,10 +172,10 @@ export default Vue.extend({
copyUrl() { copyUrl() {
copyToClipboard(this.file.url); copyToClipboard(this.file.url);
(this as any).apis.dialog({ (this as any).apis.dialog({
title: '<fa icon="check"/>%i18n:@contextmenu.copied%', title: this.$t('contextmenu.copied'),
text: '%i18n:@contextmenu.copied-url-to-clipboard%', text: this.$t('contextmenu.copied-url-to-clipboard'),
actions: [{ actions: [{
text: '%i18n:common.ok%' text: this.$t('@.ok')
}] }]
}); });
}, },

View File

@ -25,9 +25,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import contextmenu from '../../api/contextmenu'; import contextmenu from '../../api/contextmenu';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/drive.folder.vue'),
props: ['folder'], props: ['folder'],
data() { data() {
return { return {
@ -54,22 +56,22 @@ export default Vue.extend({
this.isContextmenuShowing = true; this.isContextmenuShowing = true;
contextmenu((this as any).os)(e, [{ contextmenu((this as any).os)(e, [{
type: 'item', type: 'item',
text: '%i18n:@contextmenu.move-to-this-folder%', text: this.$t('contextmenu.move-to-this-folder'),
icon: 'arrow-right', icon: 'arrow-right',
action: this.go action: this.go
}, { }, {
type: 'item', type: 'item',
text: '%i18n:@contextmenu.show-in-new-window%', text: this.$t('contextmenu.show-in-new-window'),
icon: ['far', 'window-restore'], icon: ['far', 'window-restore'],
action: this.newWindow action: this.newWindow
}, null, { }, null, {
type: 'item', type: 'item',
text: '%i18n:@contextmenu.rename%', text: this.$t('contextmenu.rename'),
icon: 'i-cursor', icon: 'i-cursor',
action: this.rename action: this.rename
}, null, { }, null, {
type: 'item', type: 'item',
text: '%i18n:common.delete%', text: this.$t('@.delete'),
icon: ['far', 'trash-alt'], icon: ['far', 'trash-alt'],
action: this.deleteFolder action: this.deleteFolder
}], { }], {
@ -155,15 +157,15 @@ export default Vue.extend({
switch (err) { switch (err) {
case 'detected-circular-definition': case 'detected-circular-definition':
(this as any).apis.dialog({ (this as any).apis.dialog({
title: '<fa icon="exclamation-triangle"/>%i18n:@unable-to-process%', title: this.$t('unable-to-process'),
text: '%i18n:@circular-reference-detected%', text: this.$t('circular-reference-detected'),
actions: [{ actions: [{
text: '%i18n:common.ok%' text: this.$t('@.ok')
}] }]
}); });
break; break;
default: default:
alert(`%i18n:@unhandled-error% ${err}`); alert(this.$t('unhandled-error'));
} }
}); });
} }
@ -195,8 +197,8 @@ export default Vue.extend({
rename() { rename() {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:@contextmenu.rename-folder%', title: this.$t('contextmenu.rename-folder'),
placeholder: '%i18n:@contextmenu.input-new-folder-name%', placeholder: this.$t('contextmenu.input-new-folder-name'),
default: this.folder.name default: this.folder.name
}).then(name => { }).then(name => {
(this as any).api('drive/folders/update', { (this as any).api('drive/folders/update', {

View File

@ -8,13 +8,15 @@
@drop.stop="onDrop" @drop.stop="onDrop"
> >
<i v-if="folder == null" class="cloud"><fa icon="cloud"/></i> <i v-if="folder == null" class="cloud"><fa icon="cloud"/></i>
<span>{{ folder == null ? '%i18n:common.drive%' : folder.name }}</span> <span>{{ folder == null ? $t('@.drive') : folder.name }}</span>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n(),
props: ['folder'], props: ['folder'],
data() { data() {
return { return {

View File

@ -30,18 +30,18 @@
<x-folder v-for="folder in folders" :key="folder.id" class="folder" :folder="folder"/> <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 --> <!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid -->
<div class="padding" v-for="n in 16"></div> <div class="padding" v-for="n in 16"></div>
<button v-if="moreFolders">%i18n:@load-more%</button> <button v-if="moreFolders">{{ $t('@.load-more') }}</button>
</div> </div>
<div class="files" ref="filesContainer" v-if="files.length > 0"> <div class="files" ref="filesContainer" v-if="files.length > 0">
<x-file v-for="file in files" :key="file.id" class="file" :file="file"/> <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 --> <!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid -->
<div class="padding" v-for="n in 16"></div> <div class="padding" v-for="n in 16"></div>
<button v-if="moreFiles" @click="fetchMoreFiles">%i18n:@load-more%</button> <button v-if="moreFiles" @click="fetchMoreFiles">{{ $t('@.load-more') }}</button>
</div> </div>
<div class="empty" v-if="files.length == 0 && folders.length == 0 && !fetching"> <div class="empty" v-if="files.length == 0 && folders.length == 0 && !fetching">
<p v-if="draghover">%i18n:@empty-draghover%</p> <p v-if="draghover">{{ $t('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"><strong>{{ $t('empty-drive') }}</strong><br/>{{ $t('empty-drive-description') }}</p>
<p v-if="!draghover && folder != null">%i18n:@empty-folder%</p> <p v-if="!draghover && folder != null">{{ $t('empty-folder') }}</p>
</div> </div>
</div> </div>
<div class="fetching" v-if="fetching"> <div class="fetching" v-if="fetching">
@ -59,6 +59,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import MkDriveWindow from './drive-window.vue'; import MkDriveWindow from './drive-window.vue';
import XNavFolder from './drive.nav-folder.vue'; import XNavFolder from './drive.nav-folder.vue';
import XFolder from './drive.folder.vue'; import XFolder from './drive.folder.vue';
@ -68,6 +69,7 @@ import contextmenu from '../../api/contextmenu';
import { url } from '../../../config'; import { url } from '../../../config';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/drive.vue'),
components: { components: {
XNavFolder, XNavFolder,
XFolder, XFolder,
@ -137,17 +139,17 @@ export default Vue.extend({
onContextmenu(e) { onContextmenu(e) {
contextmenu((this as any).os)(e, [{ contextmenu((this as any).os)(e, [{
type: 'item', type: 'item',
text: '%i18n:@contextmenu.create-folder%', text: this.$t('contextmenu.create-folder'),
icon: ['far', 'folder'], icon: ['far', 'folder'],
action: this.createFolder action: this.createFolder
}, { }, {
type: 'item', type: 'item',
text: '%i18n:@contextmenu.upload%', text: this.$t('contextmenu.upload'),
icon: 'upload', icon: 'upload',
action: this.selectLocalFile action: this.selectLocalFile
}, { }, {
type: 'item', type: 'item',
text: '%i18n:@contextmenu.url-upload%', text: this.$t('contextmenu.url-upload'),
icon: 'cloud-upload-alt', icon: 'cloud-upload-alt',
action: this.urlUpload action: this.urlUpload
}]); }]);
@ -313,10 +315,10 @@ export default Vue.extend({
switch (err) { switch (err) {
case 'detected-circular-definition': case 'detected-circular-definition':
(this as any).apis.dialog({ (this as any).apis.dialog({
title: '<fa icon="exclamation-triangle"/>%i18n:@unable-to-process%', title: this.$t('unable-to-process'),
text: '%i18n:@circular-reference-detected%', text: this.$t('circular-reference-detected'),
actions: [{ actions: [{
text: '%i18n:common.ok%' text: this.$t('@.ok')
}] }]
}); });
break; break;
@ -334,8 +336,8 @@ export default Vue.extend({
urlUpload() { urlUpload() {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:@url-upload%', title: this.$t('url-upload'),
placeholder: '%i18n:@url-of-file%' placeholder: this.$t('url-of-file')
}).then(url => { }).then(url => {
(this as any).api('drive/files/upload_from_url', { (this as any).api('drive/files/upload_from_url', {
url: url, url: url,
@ -343,10 +345,10 @@ export default Vue.extend({
}); });
(this as any).apis.dialog({ (this as any).apis.dialog({
title: '<fa icon="check"/>%i18n:@url-upload-requested%', title: this.$t('url-upload-requested'),
text: '%i18n:@may-take-time%', text: this.$t('may-take-time'),
actions: [{ actions: [{
text: '%i18n:common.ok%' text: this.$t('@.ok')
}] }]
}); });
}); });
@ -354,8 +356,8 @@ export default Vue.extend({
createFolder() { createFolder() {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:@create-folder%', title: this.$t('create-folder'),
placeholder: '%i18n:@folder-name%' placeholder: this.$t('folder-name')
}).then(name => { }).then(name => {
(this as any).api('drive/folders/create', { (this as any).api('drive/folders/create', {
name: name, name: name,

View File

@ -5,11 +5,11 @@
:disabled="wait" :disabled="wait"
> >
<template v-if="!wait"> <template v-if="!wait">
<template v-if="u.hasPendingFollowRequestFromYou && u.isLocked"><fa icon="hourglass-half"/><template v-if="size == 'big'"> %i18n:@request-pending%</template></template> <template v-if="u.hasPendingFollowRequestFromYou && u.isLocked"><fa icon="hourglass-half"/><template v-if="size == 'big'"> {{ $t('request-pending') }}</template></template>
<template v-else-if="u.hasPendingFollowRequestFromYou && !u.isLocked"><fa icon="hourglass-start"/><template v-if="size == 'big'"> %i18n:@follow-processing%</template></template> <template v-else-if="u.hasPendingFollowRequestFromYou && !u.isLocked"><fa icon="hourglass-start"/><template v-if="size == 'big'"> {{ $t('follow-processing') }}</template></template>
<template v-else-if="u.isFollowing"><fa icon="minus"/><template v-if="size == 'big'"> %i18n:@following%</template></template> <template v-else-if="u.isFollowing"><fa icon="minus"/><template v-if="size == 'big'"> {{ $t('following') }}</template></template>
<template v-else-if="!u.isFollowing && u.isLocked"><fa icon="plus"/><template v-if="size == 'big'"> %i18n:@follow-request%</template></template> <template v-else-if="!u.isFollowing && u.isLocked"><fa icon="plus"/><template v-if="size == 'big'"> {{ $t('follow-request') }}</template></template>
<template v-else-if="!u.isFollowing && !u.isLocked"><fa icon="plus"/><template v-if="size == 'big'"> %i18n:@follow%</template></template> <template v-else-if="!u.isFollowing && !u.isLocked"><fa icon="plus"/><template v-if="size == 'big'"> {{ $t('follow') }}</template></template>
</template> </template>
<template v-else><fa icon="spinner .pulse" fixed-width/></template> <template v-else><fa icon="spinner .pulse" fixed-width/></template>
</button> </button>
@ -17,8 +17,10 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/follow-button.vue'),
props: { props: {
user: { user: {
type: Object, type: Object,

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="mk-friends-maker"> <div class="mk-friends-maker">
<p class="title">%i18n:@title%</p> <p class="title">{{ $t('title') }}</p>
<div class="users" v-if="!fetching && users.length > 0"> <div class="users" v-if="!fetching && users.length > 0">
<div class="user" v-for="user in users" :key="user.id"> <div class="user" v-for="user in users" :key="user.id">
<mk-avatar class="avatar" :user="user" target="_blank"/> <mk-avatar class="avatar" :user="user" target="_blank"/>
@ -10,17 +10,19 @@
</div> </div>
</div> </div>
</div> </div>
<p class="empty" v-if="!fetching && users.length == 0">%i18n:@empty%</p> <p class="empty" v-if="!fetching && users.length == 0">{{ $t('empty') }}</p>
<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:@fetching%<mk-ellipsis/></p> <p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>{{ $t('fetching') }}<mk-ellipsis/></p>
<a class="refresh" @click="refresh">%i18n:@refresh%</a> <a class="refresh" @click="refresh">{{ $t('refresh') }}</a>
<button class="close" @click="destroyDom()" title="%i18n:@close%"><fa icon="times"/></button> <button class="close" @click="destroyDom()" :title="$t('title')"><fa icon="times"/></button>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/friends-maker.vue'),
data() { data() {
return { return {
users: [], users: [],

View File

@ -1,15 +1,17 @@
<template> <template>
<mk-window ref="window" width="500px" height="560px" :popout-url="popout" @closed="destroyDom"> <mk-window ref="window" width="500px" height="560px" :popout-url="popout" @closed="destroyDom">
<span slot="header" :class="$style.header"><fa icon="gamepad"/>%i18n:@game%</span> <span slot="header" :class="$style.header"><fa icon="gamepad"/>{{ $t('game') }}</span>
<x-reversi :class="$style.content" @gamed="g => game = g"/> <x-reversi :class="$style.content" @gamed="g => game = g"/>
</mk-window> </mk-window>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import { url } from '../../../config'; import { url } from '../../../config';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/game-window.vue'),
components: { components: {
XReversi: () => import('../../../common/views/components/games/reversi/reversi.vue') XReversi: () => import('../../../common/views/components/games/reversi/reversi.vue')
}, },

View File

@ -1,40 +1,40 @@
<template> <template>
<div class="mk-home" :data-customize="customize"> <div class="mk-home" :data-customize="customize">
<div class="customize" v-if="customize"> <div class="customize" v-if="customize">
<router-link to="/"><fa icon="check"/>%i18n:@done%</router-link> <router-link to="/"><fa icon="check"/>{{ $t('done') }}</router-link>
<div> <div>
<div class="adder"> <div class="adder">
<p>%i18n:@add-widget%</p> <p>{{ $t('add-widget') }}</p>
<select v-model="widgetAdderSelected"> <select v-model="widgetAdderSelected">
<option value="profile">%i18n:common.widgets.profile%</option> <option value="profile">{{ $t('@.widgets.profile') }}</option>
<option value="analog-clock">%i18n:common.widgets.analog-clock%</option> <option value="analog-clock">{{ $t('@.widgets.analog-clock') }}</option>
<option value="calendar">%i18n:common.widgets.calendar%</option> <option value="calendar">{{ $t('@.widgets.calendar') }}</option>
<option value="timemachine">%i18n:common.widgets.timemachine%</option> <option value="timemachine">{{ $t('@.widgets.timemachine') }}</option>
<option value="activity">%i18n:common.widgets.activity%</option> <option value="activity">{{ $t('@.widgets.activity') }}</option>
<option value="rss">%i18n:common.widgets.rss%</option> <option value="rss">{{ $t('@.widgets.rss') }}</option>
<option value="trends">%i18n:common.widgets.trends%</option> <option value="trends">{{ $t('@.widgets.trends') }}</option>
<option value="photo-stream">%i18n:common.widgets.photo-stream%</option> <option value="photo-stream">{{ $t('@.widgets.photo-stream') }}</option>
<option value="slideshow">%i18n:common.widgets.slideshow%</option> <option value="slideshow">{{ $t('@.widgets.slideshow') }}</option>
<option value="version">%i18n:common.widgets.version%</option> <option value="version">{{ $t('@.widgets.version') }}</option>
<option value="broadcast">%i18n:common.widgets.broadcast%</option> <option value="broadcast">{{ $t('@.widgets.broadcast') }}</option>
<option value="notifications">%i18n:common.widgets.notifications%</option> <option value="notifications">{{ $t('@.widgets.notifications') }}</option>
<option value="users">%i18n:common.widgets.users%</option> <option value="users">{{ $t('@.widgets.users') }}</option>
<option value="polls">%i18n:common.widgets.polls%</option> <option value="polls">{{ $t('@.widgets.polls') }}</option>
<option value="post-form">%i18n:common.widgets.post-form%</option> <option value="post-form">{{ $t('@.widgets.post-form') }}</option>
<option value="messaging">%i18n:common.widgets.messaging%</option> <option value="messaging">{{ $t('@.widgets.messaging') }}</option>
<option value="memo">%i18n:common.widgets.memo%</option> <option value="memo">{{ $t('@.widgets.memo') }}</option>
<option value="hashtags">%i18n:common.widgets.hashtags%</option> <option value="hashtags">{{ $t('@.widgets.hashtags') }}</option>
<option value="posts-monitor">%i18n:common.widgets.posts-monitor%</option> <option value="posts-monitor">{{ $t('@.widgets.posts-monitor') }}</option>
<option value="server">%i18n:common.widgets.server%</option> <option value="server">{{ $t('@.widgets.server') }}</option>
<option value="donation">%i18n:common.widgets.donation%</option> <option value="donation">{{ $t('@.widgets.donation') }}</option>
<option value="nav">%i18n:common.widgets.nav%</option> <option value="nav">{{ $t('@.widgets.nav') }}</option>
<option value="tips">%i18n:common.widgets.tips%</option> <option value="tips">{{ $t('@.widgets.tips') }}</option>
</select> </select>
<button @click="addWidget">%i18n:@add%</button> <button @click="addWidget">{{ $t('add') }}</button>
</div> </div>
<div class="trash"> <div class="trash">
<x-draggable v-model="trash" :options="{ group: 'x' }" @add="onTrash"></x-draggable> <x-draggable v-model="trash" :options="{ group: 'x' }" @add="onTrash"></x-draggable>
<p>%i18n:common.trash%</p> <p>{{ $t('@.trash') }}</p>
</div> </div>
</div> </div>
</div> </div>
@ -53,7 +53,7 @@
</div> </div>
</x-draggable> </x-draggable>
<div class="main"> <div class="main">
<a @click="hint">%i18n:common.customization-tips.title%</a> <a @click="hint">{{ $t('@.customization-tips.title') }}</a>
<div> <div>
<mk-post-form v-if="$store.state.settings.showPostFormOnTopOfTl"/> <mk-post-form v-if="$store.state.settings.showPostFormOnTopOfTl"/>
<mk-timeline ref="tl" @loaded="onTlLoaded"/> <mk-timeline ref="tl" @loaded="onTlLoaded"/>
@ -75,6 +75,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import * as XDraggable from 'vuedraggable'; import * as XDraggable from 'vuedraggable';
import * as uuid from 'uuid'; import * as uuid from 'uuid';
@ -123,6 +124,7 @@ defaultDesktopHomeWidgets.right.forEach(widget => {
//#endregion //#endregion
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/home.vue'),
components: { components: {
XDraggable XDraggable
}, },
@ -185,13 +187,10 @@ export default Vue.extend({
methods: { methods: {
hint() { hint() {
(this as any).apis.dialog({ (this as any).apis.dialog({
title: '<fa icon="info-circle"/>%i18n:common.customization-tips.title%', title: this.$t('@.customization-tips.title'),
text: '<p>%i18n:common.customization-tips.paragraph1%</p>' + text: this.$t('@.customization-tips.paragraph'),
'<p>%i18n:common.customization-tips.paragraph2%</p>' +
'<p>%i18n:common.customization-tips.paragraph3%</p>' +
'<p>%i18n:common.customization-tips.paragraph4%</p>',
actions: [{ actions: [{
text: '%i18n:common.customization-tips.gotit%' text: this.$t('@.customization-tips.gotit')
}] }]
}); });
}, },

View File

@ -8,15 +8,17 @@
<input ref="text" v-model="text" :type="type" @keydown="onKeydown" :placeholder="placeholder"/> <input ref="text" v-model="text" :type="type" @keydown="onKeydown" :placeholder="placeholder"/>
</div> </div>
<div :class="$style.actions"> <div :class="$style.actions">
<button :class="$style.cancel" @click="cancel">%i18n:@cancel%</button> <button :class="$style.cancel" @click="cancel">{{ $t('cancel') }}</button>
<button :class="$style.ok" :disabled="!allowEmpty && text.length == 0" @click="ok">%i18n:@ok%</button> <button :class="$style.ok" :disabled="!allowEmpty && text.length == 0" @click="ok">{{ $t('ok') }}</button>
</div> </div>
</mk-window> </mk-window>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/input-dialog.vue'),
props: { props: {
title: { title: {
type: String type: String

View File

@ -1,8 +1,8 @@
<template> <template>
<div class="ldwbgwstjsdgcjruamauqdrffetqudry" v-if="image.isSensitive && hide && !$store.state.device.alwaysShowNsfw" @click="hide = false"> <div class="ldwbgwstjsdgcjruamauqdrffetqudry" v-if="image.isSensitive && hide && !$store.state.device.alwaysShowNsfw" @click="hide = false">
<div> <div>
<b><fa icon="exclamation-triangle"/> %i18n:@sensitive%</b> <b><fa icon="exclamation-triangle"/> {{ $t('sensitive') }}</b>
<span>%i18n:@click-to-show%</span> <span>{{ $t('click-to-show') }}</span>
</div> </div>
</div> </div>
<a class="lcjomzwbohoelkxsnuqjiaccdbdfiazy" v-else <a class="lcjomzwbohoelkxsnuqjiaccdbdfiazy" v-else
@ -17,9 +17,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import ImageViewer from '../../../common/views/components/image-viewer.vue'; import ImageViewer from '../../../common/views/components/image-viewer.vue';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/media-image.vue'),
props: { props: {
image: { image: {
type: Object, type: Object,

View File

@ -1,8 +1,8 @@
<template> <template>
<div class="uofhebxjdgksfmltszlxurtjnjjsvioh" v-if="video.isSensitive && hide" @click="hide = false"> <div class="uofhebxjdgksfmltszlxurtjnjjsvioh" v-if="video.isSensitive && hide" @click="hide = false">
<div> <div>
<b><fa icon="exclamation-triangle"/> %i18n:@sensitive%</b> <b><fa icon="exclamation-triangle"/> {{ $t('sensitive') }}</b>
<span>%i18n:@click-to-show%</span> <span>{{ $t('click-to-show') }}</span>
</div> </div>
</div> </div>
<div class="vwxdhznewyashiknzolsoihtlpicqepe" v-else> <div class="vwxdhznewyashiknzolsoihtlpicqepe" v-else>
@ -19,9 +19,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import MkMediaVideoDialog from './media-video-dialog.vue'; import MkMediaVideoDialog from './media-video-dialog.vue';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/media-video.vue'),
props: { props: {
video: { video: {
type: Object, type: Object,

View File

@ -1,16 +1,18 @@
<template> <template>
<mk-window ref="window" width="500px" height="560px" :popout-url="popout" @closed="destroyDom"> <mk-window ref="window" width="500px" height="560px" :popout-url="popout" @closed="destroyDom">
<span slot="header" :class="$style.header"><fa icon="comments"/>%i18n:@title% {{ user | userName }}</span> <span slot="header" :class="$style.header"><fa icon="comments"/>{{ $t('title') }} {{ user | userName }}</span>
<mk-messaging-room :user="user" :class="$style.content"/> <mk-messaging-room :user="user" :class="$style.content"/>
</mk-window> </mk-window>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import { url } from '../../../config'; import { url } from '../../../config';
import getAcct from '../../../../../misc/acct/render'; import getAcct from '../../../../../misc/acct/render';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/messaging-room-window.vue'),
props: ['user'], props: ['user'],
computed: { computed: {
popout(): string { popout(): string {

View File

@ -1,15 +1,17 @@
<template> <template>
<mk-window ref="window" width="500px" height="560px" @closed="destroyDom"> <mk-window ref="window" width="500px" height="560px" @closed="destroyDom">
<span slot="header" :class="$style.header"><fa icon="comments"/>%i18n:@title%</span> <span slot="header" :class="$style.header"><fa icon="comments"/>{{ $t('title') }}</span>
<mk-messaging :class="$style.content" @navigate="navigate"/> <mk-messaging :class="$style.content" @navigate="navigate"/>
</mk-window> </mk-window>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import MkMessagingRoomWindow from './messaging-room-window.vue'; import MkMessagingRoomWindow from './messaging-room-window.vue';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/messaging-window.vue'),
methods: { methods: {
navigate(user) { navigate(user) {
(this as any).os.new(MkMessagingRoomWindow, { (this as any).os.new(MkMessagingRoomWindow, {

View File

@ -3,7 +3,7 @@
<button <button
class="read-more" class="read-more"
v-if="p.reply && p.reply.replyId && conversation.length == 0" v-if="p.reply && p.reply.replyId && conversation.length == 0"
title="%i18n:@more%" :title="$t('title')"
@click="fetchConversation" @click="fetchConversation"
:disabled="conversationFetching" :disabled="conversationFetching"
> >
@ -21,9 +21,9 @@
<mk-avatar class="avatar" :user="note.user"/> <mk-avatar class="avatar" :user="note.user"/>
<fa icon="retweet"/> <fa icon="retweet"/>
<router-link class="name" :href="note.user | userPage">{{ note.user | userName }}</router-link> <router-link class="name" :href="note.user | userPage">{{ note.user | userName }}</router-link>
<span>{{ '%i18n:@reposted-by%'.substr(0, '%i18n:@reposted-by%'.indexOf('{')) }}</span> <span>{{ this.$t('reposted-by').substr(0, this.$t('reposted-by').indexOf('{')) }}</span>
<a class="name" :href="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</a> <a class="name" :href="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</a>
<span>{{ '%i18n:@reposted-by%'.substr('%i18n:@reposted-by%'.indexOf('}') + 1) }}</span> <span>{{ this.$t('reposted-by').substr(this.$t('reposted-by').indexOf('}') + 1) }}</span>
<mk-time :time="note.createdAt"/> <mk-time :time="note.createdAt"/>
</p> </p>
</div> </div>
@ -43,8 +43,8 @@
</p> </p>
<div class="content" v-show="p.cw == null || showContent"> <div class="content" v-show="p.cw == null || showContent">
<div class="text"> <div class="text">
<span v-if="p.isHidden" style="opacity: 0.5">%i18n:@private%</span> <span v-if="p.isHidden" style="opacity: 0.5">{{ $t('private') }}</span>
<span v-if="p.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span> <span v-if="p.deletedAt" style="opacity: 0.5">{{ $t('deleted') }}</span>
<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i" :customEmojis="p.emojis" /> <misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i" :customEmojis="p.emojis" />
</div> </div>
<div class="files" v-if="p.files.length > 0"> <div class="files" v-if="p.files.length > 0">
@ -52,7 +52,7 @@
</div> </div>
<mk-poll v-if="p.poll" :note="p"/> <mk-poll v-if="p.poll" :note="p"/>
<mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="true"/> <mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="true"/>
<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank"><fa icon="map-marker-alt"/> %i18n:@location%</a> <a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank"><fa icon="map-marker-alt"/> {{ $t('location') }}</a>
<div class="map" v-if="p.geo" ref="map"></div> <div class="map" v-if="p.geo" ref="map"></div>
<div class="renote" v-if="p.renote"> <div class="renote" v-if="p.renote">
<mk-note-preview :note="p.renote"/> <mk-note-preview :note="p.renote"/>
@ -67,10 +67,10 @@
<template v-else><fa icon="reply"/></template> <template v-else><fa icon="reply"/></template>
<p class="count" v-if="p.repliesCount > 0">{{ p.repliesCount }}</p> <p class="count" v-if="p.repliesCount > 0">{{ p.repliesCount }}</p>
</button> </button>
<button class="renoteButton" @click="renote" title="%i18n:@renote%"> <button class="renoteButton" @click="renote" :title="$t('title')">
<fa icon="retweet"/><p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p> <fa icon="retweet"/><p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p>
</button> </button>
<button class="reactionButton" :class="{ reacted: p.myReaction != null }" @click="react" ref="reactButton" title="%i18n:@add-reaction%"> <button class="reactionButton" :class="{ reacted: p.myReaction != null }" @click="react" ref="reactButton" :title="$t('title')">
<fa icon="plus"/><p class="count" v-if="p.reactions_count > 0">{{ p.reactions_count }}</p> <fa icon="plus"/><p class="count" v-if="p.reactions_count > 0">{{ p.reactions_count }}</p>
</button> </button>
<button @click="menu" ref="menuButton"> <button @click="menu" ref="menuButton">
@ -86,6 +86,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import parse from '../../../../../mfm/parse'; import parse from '../../../../../mfm/parse';
import MkPostFormWindow from './post-form-window.vue'; import MkPostFormWindow from './post-form-window.vue';
@ -97,6 +98,7 @@ import { sum } from '../../../../../prelude/array';
import noteSubscriber from '../../../common/scripts/note-subscriber'; import noteSubscriber from '../../../common/scripts/note-subscriber';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/note-detail.vue'),
components: { components: {
XSub XSub
}, },

View File

@ -16,9 +16,9 @@
<div class="renote" v-if="isRenote"> <div class="renote" v-if="isRenote">
<mk-avatar class="avatar" :user="note.user"/> <mk-avatar class="avatar" :user="note.user"/>
<fa icon="retweet"/> <fa icon="retweet"/>
<span>{{ '%i18n:@reposted-by%'.substr(0, '%i18n:@reposted-by%'.indexOf('{')) }}</span> <span>{{ this.$t('reposted-by').substr(0, this.$t('reposted-by').indexOf('{')) }}</span>
<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link> <router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link>
<span>{{ '%i18n:@reposted-by%'.substr('%i18n:@reposted-by%'.indexOf('}') + 1) }}</span> <span>{{ this.$t('reposted-by').substr(this.$t('reposted-by').indexOf('}') + 1) }}</span>
<mk-time :time="note.createdAt"/> <mk-time :time="note.createdAt"/>
</div> </div>
<article> <article>
@ -32,7 +32,7 @@
</p> </p>
<div class="content" v-show="appearNote.cw == null || showContent"> <div class="content" v-show="appearNote.cw == null || showContent">
<div class="text"> <div class="text">
<span v-if="appearNote.isHidden" style="opacity: 0.5">%i18n:@private%</span> <span v-if="appearNote.isHidden" style="opacity: 0.5">{{ $t('private') }}</span>
<a class="reply" v-if="appearNote.reply"><fa icon="reply"/></a> <a class="reply" v-if="appearNote.reply"><fa icon="reply"/></a>
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text" :customEmojis="appearNote.emojis"/> <misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text" :customEmojis="appearNote.emojis"/>
<a class="rp" v-if="appearNote.renote">RN:</a> <a class="rp" v-if="appearNote.renote">RN:</a>
@ -49,15 +49,15 @@
<footer> <footer>
<span class="app" v-if="appearNote.app && mini">via <b>{{ appearNote.app.name }}</b></span> <span class="app" v-if="appearNote.app && mini">via <b>{{ appearNote.app.name }}</b></span>
<mk-reactions-viewer :note="appearNote" ref="reactionsViewer"/> <mk-reactions-viewer :note="appearNote" ref="reactionsViewer"/>
<button class="replyButton" @click="reply()" title="%i18n:@reply%"> <button class="replyButton" @click="reply()" :title="$t('reply')">
<template v-if="appearNote.reply"><fa icon="reply-all"/></template> <template v-if="appearNote.reply"><fa icon="reply-all"/></template>
<template v-else><fa icon="reply"/></template> <template v-else><fa icon="reply"/></template>
<p class="count" v-if="appearNote.repliesCount > 0">{{ appearNote.repliesCount }}</p> <p class="count" v-if="appearNote.repliesCount > 0">{{ appearNote.repliesCount }}</p>
</button> </button>
<button class="renoteButton" @click="renote()" title="%i18n:@renote%"> <button class="renoteButton" @click="renote()" :title="$t('renote')">
<fa icon="retweet"/><p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p> <fa icon="retweet"/><p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
</button> </button>
<button class="reactionButton" :class="{ reacted: appearNote.myReaction != null }" @click="react()" ref="reactButton" title="%i18n:@add-reaction%"> <button class="reactionButton" :class="{ reacted: appearNote.myReaction != null }" @click="react()" ref="reactButton" :title="$t('add-reaction')">
<fa icon="plus"/><p class="count" v-if="appearNote.reactions_count > 0">{{ appearNote.reactions_count }}</p> <fa icon="plus"/><p class="count" v-if="appearNote.reactions_count > 0">{{ appearNote.reactions_count }}</p>
</button> </button>
<button @click="menu()" ref="menuButton"> <button @click="menu()" ref="menuButton">
@ -74,12 +74,14 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import XSub from './note.sub.vue'; import XSub from './note.sub.vue';
import noteMixin from '../../../common/scripts/note-mixin'; import noteMixin from '../../../common/scripts/note-mixin';
import noteSubscriber from '../../../common/scripts/note-subscriber'; import noteSubscriber from '../../../common/scripts/note-subscriber';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/note.vue'),
components: { components: {
XSub XSub
}, },

View File

@ -25,7 +25,7 @@
<footer v-if="more"> <footer v-if="more">
<button @click="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }"> <button @click="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
<template v-if="!moreFetching">%i18n:@load-more%</template> <template v-if="!moreFetching">{{ $t('@.load-more') }}</template>
<template v-if="moreFetching"><fa icon="spinner .pulse" fixed-width/></template> <template v-if="moreFetching"><fa icon="spinner .pulse" fixed-width/></template>
</button> </button>
</footer> </footer>
@ -34,6 +34,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import * as config from '../../../config'; import * as config from '../../../config';
import XNote from './note.vue'; import XNote from './note.vue';
@ -41,6 +42,7 @@ import XNote from './note.vue';
const displayLimit = 30; const displayLimit = 30;
export default Vue.extend({ export default Vue.extend({
i18n: i18n(),
components: { components: {
XNote XNote
}, },
@ -68,7 +70,7 @@ export default Vue.extend({
const date = new Date(note.createdAt).getDate(); const date = new Date(note.createdAt).getDate();
const month = new Date(note.createdAt).getMonth() + 1; const month = new Date(note.createdAt).getMonth() + 1;
note._date = date; note._date = date;
note._datetext = '%i18n:common.month-and-day%'.replace('{month}', month.toString()).replace('{day}', date.toString()); note._datetext = this.$t('@.month-and-day').replace('{month}', month.toString()).replace('{day}', date.toString());
return note; return note;
}); });
} }

View File

@ -105,17 +105,19 @@
</component> </component>
</div> </div>
<button class="more" :class="{ fetching: fetchingMoreNotifications }" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications"> <button class="more" :class="{ fetching: fetchingMoreNotifications }" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications">
<template v-if="fetchingMoreNotifications"><fa icon="spinner .pulse" fixed-width/></template>{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }} <template v-if="fetchingMoreNotifications"><fa icon="spinner .pulse" fixed-width/></template>{{ fetchingMoreNotifications ? $t('@.loading') : $t('@.load-more') }}
</button> </button>
<p class="empty" v-if="notifications.length == 0 && !fetching">%i18n:@empty%</p> <p class="empty" v-if="notifications.length == 0 && !fetching">{{ $t('empty') }}</p>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import getNoteSummary from '../../../../../misc/get-note-summary'; import getNoteSummary from '../../../../../misc/get-note-summary';
export default Vue.extend({ export default Vue.extend({
i18n: i18n(),
data() { data() {
return { return {
fetching: true, fetching: true,
@ -133,7 +135,7 @@ export default Vue.extend({
const date = new Date(notification.createdAt).getDate(); const date = new Date(notification.createdAt).getDate();
const month = new Date(notification.createdAt).getMonth() + 1; const month = new Date(notification.createdAt).getMonth() + 1;
notification._date = date; notification._date = date;
notification._datetext = '%i18n:common.month-and-day%'.replace('{month}', month.toString()).replace('{day}', date.toString()); notification._datetext = this.$t('@.month-and-day').replace('{month}', month.toString()).replace('{day}', date.toString());
return notification; return notification;
}); });
} }

View File

@ -2,10 +2,10 @@
<mk-window class="mk-post-form-window" ref="window" is-modal @closed="onWindowClosed" :animation="animation"> <mk-window class="mk-post-form-window" ref="window" is-modal @closed="onWindowClosed" :animation="animation">
<span slot="header" class="mk-post-form-window--header"> <span slot="header" class="mk-post-form-window--header">
<span class="icon" v-if="geo"><fa icon="map-marker-alt"/></span> <span class="icon" v-if="geo"><fa icon="map-marker-alt"/></span>
<span v-if="!reply">%i18n:@note%</span> <span v-if="!reply">{{ $t('note') }}</span>
<span v-if="reply">%i18n:@reply%</span> <span v-if="reply">{{ $t('reply') }}</span>
<span class="count" v-if="files.length != 0">{{ '%i18n:@attaches%'.replace('{}', files.length) }}</span> <span class="count" v-if="files.length != 0">{{ this.$t('attaches').replace('{}', files.length) }}</span>
<span class="count" v-if="uploadings.length != 0">{{ '%i18n:@uploading-media%'.replace('{}', uploadings.length) }}<mk-ellipsis/></span> <span class="count" v-if="uploadings.length != 0">{{ this.$t('uploading-media').replace('{}', uploadings.length) }}<mk-ellipsis/></span>
</span> </span>
<div class="mk-post-form-window--body"> <div class="mk-post-form-window--body">
@ -23,8 +23,10 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/post-form-window.vue'),
props: { props: {
reply: { reply: {
type: Object, type: Object,

View File

@ -8,13 +8,13 @@
<div class="content"> <div class="content">
<div v-if="visibility == 'specified'" class="visibleUsers"> <div v-if="visibility == 'specified'" class="visibleUsers">
<span v-for="u in visibleUsers">{{ u | userName }}<a @click="removeVisibleUser(u)">[x]</a></span> <span v-for="u in visibleUsers">{{ u | userName }}<a @click="removeVisibleUser(u)">[x]</a></span>
<a @click="addVisibleUser">%i18n:@add-visible-user%</a> <a @click="addVisibleUser">{{ $t('add-visible-user') }}</a>
</div> </div>
<div class="hashtags" v-if="recentHashtags.length > 0 && $store.state.settings.suggestRecentHashtags"> <div class="hashtags" v-if="recentHashtags.length > 0 && $store.state.settings.suggestRecentHashtags">
<b>%i18n:@recent-tags%:</b> <b>{{ $t('recent-tags') }}:</b>
<a v-for="tag in recentHashtags.slice(0, 5)" @click="addTag(tag)" title="%i18n:@click-to-tagging%">#{{ tag }}</a> <a v-for="tag in recentHashtags.slice(0, 5)" @click="addTag(tag)" :title="$t('click-to-tagging')">#{{ tag }}</a>
</div> </div>
<input v-show="useCw" v-model="cw" placeholder="%i18n:@annotations%"> <input v-show="useCw" v-model="cw" :placeholder="$t('placeholder')">
<textarea :class="{ with: (files.length != 0 || poll) }" <textarea :class="{ with: (files.length != 0 || poll) }"
ref="text" v-model="text" :disabled="posting" ref="text" v-model="text" :disabled="posting"
@keydown="onKeydown" @paste="onPaste" :placeholder="placeholder" @keydown="onKeydown" @paste="onPaste" :placeholder="placeholder"
@ -24,7 +24,7 @@
<x-draggable :list="files" :options="{ animation: 150 }"> <x-draggable :list="files" :options="{ animation: 150 }">
<div v-for="file in files" :key="file.id"> <div v-for="file in files" :key="file.id">
<div class="img" :style="{ backgroundImage: `url(${file.thumbnailUrl})` }" :title="file.name"></div> <div class="img" :style="{ backgroundImage: `url(${file.thumbnailUrl})` }" :title="file.name"></div>
<img class="remove" @click="detachMedia(file.id)" src="/assets/desktop/remove.png" title="%i18n:@attach-cancel%" alt=""/> <img class="remove" @click="detachMedia(file.id)" src="/assets/desktop/remove.png" :title="$t('attach-cancel')" alt=""/>
</div> </div>
</x-draggable> </x-draggable>
<p class="remain">{{ 4 - files.length }}/4</p> <p class="remain">{{ 4 - files.length }}/4</p>
@ -32,13 +32,13 @@
<mk-poll-editor v-if="poll" ref="poll" @destroyed="poll = false" @updated="saveDraft()"/> <mk-poll-editor v-if="poll" ref="poll" @destroyed="poll = false" @updated="saveDraft()"/>
</div> </div>
<mk-uploader ref="uploader" @uploaded="attachMedia" @change="onChangeUploadings"/> <mk-uploader ref="uploader" @uploaded="attachMedia" @change="onChangeUploadings"/>
<button class="upload" title="%i18n:@attach-media-from-local%" @click="chooseFile"><fa icon="upload"/></button> <button class="upload" :title="$t('attach-media-from-local')" @click="chooseFile"><fa icon="upload"/></button>
<button class="drive" title="%i18n:@attach-media-from-drive%" @click="chooseFileFromDrive"><fa icon="cloud"/></button> <button class="drive" :title="$t('attach-media-from-drive')" @click="chooseFileFromDrive"><fa icon="cloud"/></button>
<button class="kao" title="%i18n:@insert-a-kao%" @click="kao"><fa :icon="['far', 'smile']"/></button> <button class="kao" :title="$t('insert-a-kao')" @click="kao"><fa :icon="['far', 'smile']"/></button>
<button class="poll" title="%i18n:@create-poll%" @click="poll = !poll"><fa icon="chart-pie"/></button> <button class="poll" :title="$t('create-poll')" @click="poll = !poll"><fa icon="chart-pie"/></button>
<button class="poll" title="%i18n:@hide-contents%" @click="useCw = !useCw"><fa icon="eye-slash"/></button> <button class="cw%" :title="$t('hide-contents%')" @click="useCw = !useCw"><fa icon="eye-slash"/></button>
<button class="geo" title="%i18n:@attach-location-information%" @click="geo ? removeGeo() : setGeo()"><fa icon="map-marker-alt"/></button> <button class="geo" :title="$t('attach-location-information')" @click="geo ? removeGeo() : setGeo()"><fa icon="map-marker-alt"/></button>
<button class="visibility" title="%i18n:@visibility%" @click="setVisibility" ref="visibilityButton"> <button class="visibility" :title="$t('visibility')" @click="setVisibility" ref="visibilityButton">
<span v-if="visibility === 'public'"><fa icon="globe"/></span> <span v-if="visibility === 'public'"><fa icon="globe"/></span>
<span v-if="visibility === 'home'"><fa icon="home"/></span> <span v-if="visibility === 'home'"><fa icon="home"/></span>
<span v-if="visibility === 'followers'"><fa icon="unlock"/></span> <span v-if="visibility === 'followers'"><fa icon="unlock"/></span>
@ -47,7 +47,7 @@
</button> </button>
<p class="text-count" :class="{ over: this.trimmedLength(text) > this.maxNoteTextLength }">{{ this.maxNoteTextLength - this.trimmedLength(text) }}</p> <p class="text-count" :class="{ over: this.trimmedLength(text) > this.maxNoteTextLength }">{{ this.maxNoteTextLength - this.trimmedLength(text) }}</p>
<button :class="{ posting }" class="submit" :disabled="!canPost" @click="post"> <button :class="{ posting }" class="submit" :disabled="!canPost" @click="post">
{{ posting ? '%i18n:@posting%' : submitText }}<mk-ellipsis v-if="posting"/> {{ posting ? this.$t('posting') : submitText }}<mk-ellipsis v-if="posting"/>
</button> </button>
<input ref="file" type="file" multiple="multiple" tabindex="-1" @change="onChangeFile"/> <input ref="file" type="file" multiple="multiple" tabindex="-1" @change="onChangeFile"/>
<div class="dropzone" v-if="draghover"></div> <div class="dropzone" v-if="draghover"></div>
@ -56,6 +56,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import insertTextAtCursor from 'insert-text-at-cursor'; import insertTextAtCursor from 'insert-text-at-cursor';
import * as XDraggable from 'vuedraggable'; import * as XDraggable from 'vuedraggable';
import getFace from '../../../common/scripts/get-face'; import getFace from '../../../common/scripts/get-face';
@ -68,6 +69,7 @@ import parseAcct from '../../../../../misc/acct/parse';
import { toASCII } from 'punycode'; import { toASCII } from 'punycode';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/post-form.vue'),
components: { components: {
XDraggable, XDraggable,
MkVisibilityChooser MkVisibilityChooser
@ -129,28 +131,28 @@ export default Vue.extend({
placeholder(): string { placeholder(): string {
const xs = [ const xs = [
'%i18n:common.note-placeholders.a%', this.$t('@.note-placeholders.a'),
'%i18n:common.note-placeholders.b%', this.$t('@.note-placeholders.b'),
'%i18n:common.note-placeholders.c%', this.$t('@.note-placeholders.c'),
'%i18n:common.note-placeholders.d%', this.$t('@.note-placeholders.d'),
'%i18n:common.note-placeholders.e%', this.$t('@.note-placeholders.e'),
'%i18n:common.note-placeholders.f%' this.$t('@.note-placeholders.f')
]; ];
const x = xs[Math.floor(Math.random() * xs.length)]; const x = xs[Math.floor(Math.random() * xs.length)];
return this.renote return this.renote
? '%i18n:@quote-placeholder%' ? this.$t('quote-placeholder')
: this.reply : this.reply
? '%i18n:@reply-placeholder%' ? this.$t('reply-placeholder')
: x; : x;
}, },
submitText(): string { submitText(): string {
return this.renote return this.renote
? '%i18n:@renote%' ? this.$t('renote')
: this.reply : this.reply
? '%i18n:@reply%' ? this.$t('reply')
: '%i18n:@submit%'; : this.$t('submit');
}, },
canPost(): boolean { canPost(): boolean {
@ -332,7 +334,7 @@ export default Vue.extend({
setGeo() { setGeo() {
if (navigator.geolocation == null) { if (navigator.geolocation == null) {
alert('%i18n:@geolocation-alert%'); alert(this.$t('geolocation-alert'));
return; return;
} }
@ -362,7 +364,7 @@ export default Vue.extend({
addVisibleUser() { addVisibleUser() {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:@enter-username%' title: this.$t('enter-username')
}).then(acct => { }).then(acct => {
if (acct.startsWith('@')) acct = acct.substr(1); if (acct.startsWith('@')) acct = acct.substr(1);
(this as any).api('users/show', parseAcct(acct)).then(user => { (this as any).api('users/show', parseAcct(acct)).then(user => {
@ -400,16 +402,16 @@ export default Vue.extend({
this.deleteDraft(); this.deleteDraft();
this.$emit('posted'); this.$emit('posted');
(this as any).apis.notify(this.renote (this as any).apis.notify(this.renote
? '%i18n:@reposted%' ? this.$t('reposted')
: this.reply : this.reply
? '%i18n:@replied%' ? this.$t('replied')
: '%i18n:@posted%'); : this.$t('posted'));
}).catch(err => { }).catch(err => {
(this as any).apis.notify(this.renote (this as any).apis.notify(this.renote
? '%i18n:@renote-failed%' ? this.$t('renote-failed')
: this.reply : this.reply
? '%i18n:@reply-failed%' ? this.$t('reply-failed')
: '%i18n:@note-failed%'); : this.$t('note-failed'));
}).then(() => { }).then(() => {
this.posting = false; this.posting = false;
}); });

View File

@ -2,7 +2,7 @@
<mk-window ref="window" :is-modal="false" :can-close="false" width="500px" @closed="destroyDom"> <mk-window ref="window" :is-modal="false" :can-close="false" width="500px" @closed="destroyDom">
<span slot="header">{{ title }}<mk-ellipsis/></span> <span slot="header">{{ title }}<mk-ellipsis/></span>
<div :class="$style.body"> <div :class="$style.body">
<p :class="$style.init" v-if="isNaN(value)">%i18n:@waiting%<mk-ellipsis/></p> <p :class="$style.init" v-if="isNaN(value)">{{ $t('waiting') }}<mk-ellipsis/></p>
<p :class="$style.percentage" v-if="!isNaN(value)">{{ Math.floor((value / max) * 100) }}</p> <p :class="$style.percentage" v-if="!isNaN(value)">{{ Math.floor((value / max) * 100) }}</p>
<progress :class="$style.progress" <progress :class="$style.progress"
v-if="!isNaN(value) && value < max" v-if="!isNaN(value) && value < max"
@ -16,7 +16,10 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/progress-dialog.vue'),
props: ['title', 'initValue', 'initMax'], props: ['title', 'initValue', 'initMax'],
data() { data() {
return { return {

View File

@ -1,12 +1,12 @@
<template> <template>
<mk-window ref="window" is-modal width="450px" height="500px" @closed="destroyDom"> <mk-window ref="window" is-modal width="450px" height="500px" @closed="destroyDom">
<span slot="header"><fa :icon="['far', 'envelope']"/> %i18n:@title%</span> <span slot="header"><fa :icon="['far', 'envelope']"/> {{ $t('title') }}</span>
<div class="slpqaxdoxhvglersgjukmvizkqbmbokc"> <div class="slpqaxdoxhvglersgjukmvizkqbmbokc">
<div v-for="req in requests"> <div v-for="req in requests">
<router-link :key="req.id" :to="req.follower | userPage">{{ req.follower | userName }}</router-link> <router-link :key="req.id" :to="req.follower | userPage">{{ req.follower | userName }}</router-link>
<span> <span>
<a @click="accept(req.follower)">%i18n:@accept%</a>|<a @click="reject(req.follower)">%i18n:@reject%</a> <a @click="accept(req.follower)">{{ $t('accept') }}</a>|<a @click="reject(req.follower)">{{ $t('reject') }}</a>
</span> </span>
</div> </div>
</div> </div>
@ -15,7 +15,10 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/received-follow-requests-window.vue'),
data() { data() {
return { return {
fetching: true, fetching: true,

View File

@ -1,14 +1,16 @@
<template> <template>
<mk-window ref="window" is-modal @closed="onWindowClosed" :animation="animation"> <mk-window ref="window" is-modal @closed="onWindowClosed" :animation="animation">
<span slot="header" :class="$style.header"><fa icon="retweet"/>%i18n:@title%</span> <span slot="header" :class="$style.header"><fa icon="retweet"/>{{ $t('title') }}</span>
<mk-renote-form ref="form" :note="note" @posted="onPosted" @canceled="onCanceled" v-hotkey.global="keymap"/> <mk-renote-form ref="form" :note="note" @posted="onPosted" @canceled="onCanceled" v-hotkey.global="keymap"/>
</mk-window> </mk-window>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/renote-form-window.vue'),
props: { props: {
note: { note: {
type: Object, type: Object,

View File

@ -3,9 +3,9 @@
<mk-note-preview class="preview" :note="note"/> <mk-note-preview class="preview" :note="note"/>
<template v-if="!quote"> <template v-if="!quote">
<footer> <footer>
<a class="quote" v-if="!quote" @click="onQuote">%i18n:@quote%</a> <a class="quote" v-if="!quote" @click="onQuote">{{ $t('quote') }}</a>
<ui-button class="button cancel" inline @click="cancel">%i18n:@cancel%</ui-button> <ui-button class="button cancel" inline @click="cancel">{{ $t('cancel') }}</ui-button>
<ui-button class="button ok" inline primary @click="ok" :disabled="wait">{{ wait ? '%i18n:@reposting%' : '%i18n:@renote%' }}</ui-button> <ui-button class="button ok" inline primary @click="ok" :disabled="wait">{{ wait ? this.$t('reposting') : this.$t('renote') }}</ui-button>
</footer> </footer>
</template> </template>
<template v-if="quote"> <template v-if="quote">
@ -16,8 +16,10 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/renote-form.vue'),
props: ['note'], props: ['note'],
data() { data() {
return { return {
@ -32,9 +34,9 @@ export default Vue.extend({
renoteId: this.note.id renoteId: this.note.id
}).then(data => { }).then(data => {
this.$emit('posted'); this.$emit('posted');
(this as any).apis.notify('%i18n:@success%'); (this as any).apis.notify(this.$t('success'));
}).catch(err => { }).catch(err => {
(this as any).apis.notify('%i18n:@failure%'); (this as any).apis.notify(this.$t('failure'));
}).then(() => { }).then(() => {
this.wait = false; this.wait = false;
}); });

View File

@ -1,13 +1,15 @@
<template> <template>
<mk-window ref="window" is-modal width="700px" height="550px" @closed="destroyDom"> <mk-window ref="window" is-modal width="700px" height="550px" @closed="destroyDom">
<span slot="header" :class="$style.header"><fa icon="cog"/>%i18n:@settings%</span> <span slot="header" :class="$style.header"><fa icon="cog"/>{{ $t('settings') }}</span>
<mk-settings :initial-page="initialPage" @done="close"/> <mk-settings :initial-page="initialPage" @done="close"/>
</mk-window> </mk-window>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/settings-window.vue'),
props: { props: {
initialPage: { initialPage: {
type: String, type: String,

View File

@ -1,30 +1,32 @@
<template> <template>
<div class="2fa"> <div class="2fa">
<p style="margin-top:0;">%i18n:@intro%<a href="%i18n:@url%" target="_blank">%i18n:@detail%</a></p> <p style="margin-top:0;">{{ $t('intro') }}<a :href="$t('href')" target="_blank">{{ $t('detail') }}</a></p>
<ui-info warn>%i18n:@caution%</ui-info> <ui-info warn>{{ $t('caution') }}</ui-info>
<p v-if="!data && !$store.state.i.twoFactorEnabled"><ui-button @click="register">%i18n:@register%</ui-button></p> <p v-if="!data && !$store.state.i.twoFactorEnabled"><ui-button @click="register">{{ $t('register') }}</ui-button></p>
<template v-if="$store.state.i.twoFactorEnabled"> <template v-if="$store.state.i.twoFactorEnabled">
<p>%i18n:@already-registered%</p> <p>{{ $t('already-registered') }}</p>
<ui-button @click="unregister">%i18n:@unregister%</ui-button> <ui-button @click="unregister">{{ $t('unregister') }}</ui-button>
</template> </template>
<div v-if="data"> <div v-if="data">
<ol> <ol>
<li>%i18n:@authenticator% <a href="https://support.google.com/accounts/answer/1066447" target="_blank">%i18n:@howtoinstall%</a></li> <li>{{ $t('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>{{ $t('scan') }}<br><img :src="data.qr"></li>
<li>%i18n:@done%<br> <li>{{ $t('done') }}<br>
<input type="number" v-model="token" class="ui"> <input type="number" v-model="token" class="ui">
<ui-button primary @click="submit">%i18n:@submit%</ui-button> <ui-button primary @click="submit">{{ $t('submit') }}</ui-button>
</li> </li>
</ol> </ol>
<div class="ui info"><p><fa icon="info-circle"/>%i18n:@info%</p></div> <div class="ui info"><p><fa icon="info-circle"/>{{ $t('info') }}</p></div>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/settings.2fa.vue'),
data() { data() {
return { return {
data: null, data: null,
@ -34,7 +36,7 @@ export default Vue.extend({
methods: { methods: {
register() { register() {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:@enter-password%', title: this.$t('enter-password'),
type: 'password' type: 'password'
}).then(password => { }).then(password => {
(this as any).api('i/2fa/register', { (this as any).api('i/2fa/register', {
@ -47,13 +49,13 @@ export default Vue.extend({
unregister() { unregister() {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:@enter-password%', title: this.$t('enter-password'),
type: 'password' type: 'password'
}).then(password => { }).then(password => {
(this as any).api('i/2fa/unregister', { (this as any).api('i/2fa/unregister', {
password: password password: password
}).then(() => { }).then(() => {
(this as any).apis.notify('%i18n:@unregistered%'); (this as any).apis.notify(this.$t('unregistered'));
this.$store.state.i.twoFactorEnabled = false; this.$store.state.i.twoFactorEnabled = false;
}); });
}); });
@ -63,10 +65,10 @@ export default Vue.extend({
(this as any).api('i/2fa/done', { (this as any).api('i/2fa/done', {
token: this.token token: this.token
}).then(() => { }).then(() => {
(this as any).apis.notify('%i18n:@success%'); (this as any).apis.notify(this.$t('success'));
this.$store.state.i.twoFactorEnabled = true; this.$store.state.i.twoFactorEnabled = true;
}).catch(() => { }).catch(() => {
(this as any).apis.notify('%i18n:@failed%'); (this as any).apis.notify(this.$t('failed'));
}); });
} }
} }

Some files were not shown because too many files have changed in this diff Show More