summaryrefslogtreecommitdiff
path: root/packages/frontend/src/components
diff options
context:
space:
mode:
authorAcid Chicken (硫酸鶏) <root@acid-chicken.com>2024-01-20 08:11:59 +0900
committerGitHub <noreply@github.com>2024-01-20 08:11:59 +0900
commit7881f06be060dd955499a6beff3ad1967ed628f6 (patch)
tree7b91a1c5e0f1ef99d9f66e702c7d954a54958a56 /packages/frontend/src/components
parentfeat: reversi (diff)
downloadmisskey-7881f06be060dd955499a6beff3ad1967ed628f6.tar.gz
misskey-7881f06be060dd955499a6beff3ad1967ed628f6.tar.bz2
misskey-7881f06be060dd955499a6beff3ad1967ed628f6.zip
refactor: deprecate i18n.t (#13039)
* refactor: deprecate i18n.t * revert: deprecate i18n.t This reverts commit 7dbf873a2f745040ee723df5db659acacff84e12. * chore: reimpl
Diffstat (limited to 'packages/frontend/src/components')
-rw-r--r--packages/frontend/src/components/MkAnnouncementDialog.vue2
-rw-r--r--packages/frontend/src/components/MkCwButton.vue4
-rw-r--r--packages/frontend/src/components/MkDateSeparatedList.vue2
-rw-r--r--packages/frontend/src/components/MkDialog.vue4
-rw-r--r--packages/frontend/src/components/MkDrive.vue4
-rw-r--r--packages/frontend/src/components/MkFollowButton.vue2
-rw-r--r--packages/frontend/src/components/MkNote.vue2
-rw-r--r--packages/frontend/src/components/MkNoteDetailed.vue2
-rw-r--r--packages/frontend/src/components/MkNotification.vue4
-rw-r--r--packages/frontend/src/components/MkNotificationSelectWindow.vue2
-rw-r--r--packages/frontend/src/components/MkPoll.vue15
-rw-r--r--packages/frontend/src/components/MkPollEditor.vue2
-rw-r--r--packages/frontend/src/components/MkSignupDialog.form.vue2
-rw-r--r--packages/frontend/src/components/MkSignupDialog.rules.vue6
-rw-r--r--packages/frontend/src/components/MkSubNoteContent.vue2
-rw-r--r--packages/frontend/src/components/MkTokenGenerateWindow.vue4
-rw-r--r--packages/frontend/src/components/MkTutorialDialog.vue2
-rw-r--r--packages/frontend/src/components/MkUserAnnouncementEditDialog.vue2
-rw-r--r--packages/frontend/src/components/MkUserSetupDialog.Profile.vue2
-rw-r--r--packages/frontend/src/components/MkUserSetupDialog.vue4
-rw-r--r--packages/frontend/src/components/MkWidgets.vue4
-rw-r--r--packages/frontend/src/components/global/I18n.vue46
-rw-r--r--packages/frontend/src/components/global/MkTime.stories.impl.ts10
-rw-r--r--packages/frontend/src/components/global/MkTime.vue28
-rw-r--r--packages/frontend/src/components/global/i18n.ts29
-rw-r--r--packages/frontend/src/components/index.ts2
26 files changed, 103 insertions, 85 deletions
diff --git a/packages/frontend/src/components/MkAnnouncementDialog.vue b/packages/frontend/src/components/MkAnnouncementDialog.vue
index c649e69cd0..54cbbe18c2 100644
--- a/packages/frontend/src/components/MkAnnouncementDialog.vue
+++ b/packages/frontend/src/components/MkAnnouncementDialog.vue
@@ -44,7 +44,7 @@ async function ok() {
const confirm = await os.confirm({
type: 'question',
title: i18n.ts._announcement.readConfirmTitle,
- text: i18n.t('_announcement.readConfirmText', { title: props.announcement.title }),
+ text: i18n.tsx._announcement.readConfirmText({ title: props.announcement.title }),
});
if (confirm.canceled) return;
}
diff --git a/packages/frontend/src/components/MkCwButton.vue b/packages/frontend/src/components/MkCwButton.vue
index 4a6d2dfba2..ca19a2122d 100644
--- a/packages/frontend/src/components/MkCwButton.vue
+++ b/packages/frontend/src/components/MkCwButton.vue
@@ -41,9 +41,9 @@ const emit = defineEmits<{
const label = computed(() => {
return concat([
- props.text ? [i18n.t('_cw.chars', { count: props.text.length })] : [],
+ props.text ? [i18n.tsx._cw.chars({ count: props.text.length })] : [],
props.renote ? [i18n.ts.quote] : [],
- props.files.length !== 0 ? [i18n.t('_cw.files', { count: props.files.length })] : [],
+ props.files.length !== 0 ? [i18n.tsx._cw.files({ count: props.files.length })] : [],
props.poll != null ? [i18n.ts.poll] : [],
] as string[][]).join(' / ');
});
diff --git a/packages/frontend/src/components/MkDateSeparatedList.vue b/packages/frontend/src/components/MkDateSeparatedList.vue
index 0a71b689fe..7b9a052868 100644
--- a/packages/frontend/src/components/MkDateSeparatedList.vue
+++ b/packages/frontend/src/components/MkDateSeparatedList.vue
@@ -46,7 +46,7 @@ export default defineComponent({
function getDateText(time: string) {
const date = new Date(time).getDate();
const month = new Date(time).getMonth() + 1;
- return i18n.t('monthAndDay', {
+ return i18n.tsx.monthAndDay({
month: month.toString(),
day: date.toString(),
});
diff --git a/packages/frontend/src/components/MkDialog.vue b/packages/frontend/src/components/MkDialog.vue
index 3c1f83d335..3fc9f0e357 100644
--- a/packages/frontend/src/components/MkDialog.vue
+++ b/packages/frontend/src/components/MkDialog.vue
@@ -30,8 +30,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkInput v-if="input" v-model="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder || undefined" :autocomplete="input.autocomplete" @keydown="onInputKeydown">
<template v-if="input.type === 'password'" #prefix><i class="ti ti-lock"></i></template>
<template #caption>
- <span v-if="okButtonDisabledReason === 'charactersExceeded'" v-text="i18n.t('_dialog.charactersExceeded', { current: (inputValue as string).length, max: input.maxLength ?? 'NaN' })"/>
- <span v-else-if="okButtonDisabledReason === 'charactersBelow'" v-text="i18n.t('_dialog.charactersBelow', { current: (inputValue as string).length, min: input.minLength ?? 'NaN' })"/>
+ <span v-if="okButtonDisabledReason === 'charactersExceeded'" v-text="i18n.tsx._dialog.charactersExceeded({ current: (inputValue as string).length, max: input.maxLength ?? 'NaN' })"/>
+ <span v-else-if="okButtonDisabledReason === 'charactersBelow'" v-text="i18n.tsx._dialog.charactersBelow({ current: (inputValue as string).length, min: input.minLength ?? 'NaN' })"/>
</template>
</MkInput>
<MkSelect v-if="select" v-model="selectedValue" autofocus>
diff --git a/packages/frontend/src/components/MkDrive.vue b/packages/frontend/src/components/MkDrive.vue
index dbf98cd622..560d5502d4 100644
--- a/packages/frontend/src/components/MkDrive.vue
+++ b/packages/frontend/src/components/MkDrive.vue
@@ -82,8 +82,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton v-show="moreFiles" ref="loadMoreFiles" @click="fetchMoreFiles">{{ i18n.ts.loadMore }}</MkButton>
</div>
<div v-if="files.length == 0 && folders.length == 0 && !fetching" :class="$style.empty">
- <div v-if="draghover">{{ i18n.t('empty-draghover') }}</div>
- <div v-if="!draghover && folder == null"><strong>{{ i18n.ts.emptyDrive }}</strong><br/>{{ i18n.t('empty-drive-description') }}</div>
+ <div v-if="draghover">{{ i18n.ts['empty-draghover'] }}</div>
+ <div v-if="!draghover && folder == null"><strong>{{ i18n.ts.emptyDrive }}</strong><br/>{{ i18n.ts['empty-drive-description'] }}</div>
<div v-if="!draghover && folder != null">{{ i18n.ts.emptyFolder }}</div>
</div>
</div>
diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue
index 78c4fb3cd2..6bc96be1b9 100644
--- a/packages/frontend/src/components/MkFollowButton.vue
+++ b/packages/frontend/src/components/MkFollowButton.vue
@@ -84,7 +84,7 @@ async function onClick() {
if (isFollowing.value) {
const { canceled } = await os.confirm({
type: 'warning',
- text: i18n.t('unfollowConfirm', { name: props.user.name || props.user.username }),
+ text: i18n.tsx.unfollowConfirm({ name: props.user.name || props.user.username }),
});
if (canceled) return;
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue
index 9c4354ef5f..d7bb64661b 100644
--- a/packages/frontend/src/components/MkNote.vue
+++ b/packages/frontend/src/components/MkNote.vue
@@ -73,7 +73,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="translating || translation" :class="$style.translation">
<MkLoading v-if="translating" mini/>
<div v-else>
- <b>{{ i18n.t('translatedFrom', { x: translation.sourceLang }) }}: </b>
+ <b>{{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: </b>
<Mfm :text="translation.text" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis"/>
</div>
</div>
diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue
index e941827d74..1f5b283cfe 100644
--- a/packages/frontend/src/components/MkNoteDetailed.vue
+++ b/packages/frontend/src/components/MkNoteDetailed.vue
@@ -87,7 +87,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="translating || translation" :class="$style.translation">
<MkLoading v-if="translating" mini/>
<div v-else>
- <b>{{ i18n.t('translatedFrom', { x: translation.sourceLang }) }}: </b>
+ <b>{{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: </b>
<Mfm :text="translation.text" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis"/>
</div>
</div>
diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue
index ce8b054b39..92be20c6f6 100644
--- a/packages/frontend/src/components/MkNotification.vue
+++ b/packages/frontend/src/components/MkNotification.vue
@@ -56,8 +56,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<span v-else-if="notification.type === 'achievementEarned'">{{ i18n.ts._notification.achievementEarned }}</span>
<span v-else-if="notification.type === 'test'">{{ i18n.ts._notification.testNotification }}</span>
<MkA v-else-if="notification.user" v-user-preview="notification.user.id" :class="$style.headerName" :to="userPage(notification.user)"><MkUserName :user="notification.user"/></MkA>
- <span v-else-if="notification.type === 'reaction:grouped'">{{ i18n.t('_notification.reactedBySomeUsers', { n: notification.reactions.length }) }}</span>
- <span v-else-if="notification.type === 'renote:grouped'">{{ i18n.t('_notification.renotedBySomeUsers', { n: notification.users.length }) }}</span>
+ <span v-else-if="notification.type === 'reaction:grouped'">{{ i18n.tsx._notification.reactedBySomeUsers({ n: notification.reactions.length }) }}</span>
+ <span v-else-if="notification.type === 'renote:grouped'">{{ i18n.tsx._notification.renotedBySomeUsers({ n: notification.users.length }) }}</span>
<span v-else>{{ notification.header }}</span>
<MkTime v-if="withTime" :time="notification.createdAt" :class="$style.headerTime"/>
</header>
diff --git a/packages/frontend/src/components/MkNotificationSelectWindow.vue b/packages/frontend/src/components/MkNotificationSelectWindow.vue
index 6725776f43..0e77d2a6aa 100644
--- a/packages/frontend/src/components/MkNotificationSelectWindow.vue
+++ b/packages/frontend/src/components/MkNotificationSelectWindow.vue
@@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton inline @click="disableAll">{{ i18n.ts.disableAll }}</MkButton>
<MkButton inline @click="enableAll">{{ i18n.ts.enableAll }}</MkButton>
</div>
- <MkSwitch v-for="ntype in notificationTypes" :key="ntype" v-model="typesMap[ntype].value">{{ i18n.t(`_notification._types.${ntype}`) }}</MkSwitch>
+ <MkSwitch v-for="ntype in notificationTypes" :key="ntype" v-model="typesMap[ntype].value">{{ i18n.ts._notification._types[ntype] }}</MkSwitch>
</div>
</MkSpacer>
</MkModalWindow>
diff --git a/packages/frontend/src/components/MkPoll.vue b/packages/frontend/src/components/MkPoll.vue
index 4cac1fe9c3..7c58b58697 100644
--- a/packages/frontend/src/components/MkPoll.vue
+++ b/packages/frontend/src/components/MkPoll.vue
@@ -11,12 +11,12 @@ SPDX-License-Identifier: AGPL-3.0-only
<span :class="$style.fg">
<template v-if="choice.isVoted"><i class="ti ti-check" style="margin-right: 4px; color: var(--accent);"></i></template>
<Mfm :text="choice.text" :plain="true"/>
- <span v-if="showResult" style="margin-left: 4px; opacity: 0.7;">({{ i18n.t('_poll.votesCount', { n: choice.votes }) }})</span>
+ <span v-if="showResult" style="margin-left: 4px; opacity: 0.7;">({{ i18n.tsx._poll.votesCount({ n: choice.votes }) }})</span>
</span>
</li>
</ul>
<p v-if="!readOnly" :class="$style.info">
- <span>{{ i18n.t('_poll.totalVotes', { n: total }) }}</span>
+ <span>{{ i18n.tsx._poll.totalVotes({ n: total }) }}</span>
<span> · </span>
<a v-if="!closed && !isVoted" style="color: inherit;" @click="showResult = !showResult">{{ showResult ? i18n.ts._poll.vote : i18n.ts._poll.showResult }}</a>
<span v-if="isVoted">{{ i18n.ts._poll.voted }}</span>
@@ -47,10 +47,11 @@ const remaining = ref(-1);
const total = computed(() => sum(props.note.poll.choices.map(x => x.votes)));
const closed = computed(() => remaining.value === 0);
const isVoted = computed(() => !props.note.poll.multiple && props.note.poll.choices.some(c => c.isVoted));
-const timer = computed(() => i18n.t(
- remaining.value >= 86400 ? '_poll.remainingDays' :
- remaining.value >= 3600 ? '_poll.remainingHours' :
- remaining.value >= 60 ? '_poll.remainingMinutes' : '_poll.remainingSeconds', {
+const timer = computed(() => i18n.tsx._poll[
+ remaining.value >= 86400 ? 'remainingDays' :
+ remaining.value >= 3600 ? 'remainingHours' :
+ remaining.value >= 60 ? 'remainingMinutes' : 'remainingSeconds'
+ ]({
s: Math.floor(remaining.value % 60),
m: Math.floor(remaining.value / 60) % 60,
h: Math.floor(remaining.value / 3600) % 24,
@@ -81,7 +82,7 @@ const vote = async (id) => {
const { canceled } = await os.confirm({
type: 'question',
- text: i18n.t('voteConfirm', { choice: props.note.poll.choices[id].text }),
+ text: i18n.tsx.voteConfirm({ choice: props.note.poll.choices[id].text }),
});
if (canceled) return;
diff --git a/packages/frontend/src/components/MkPollEditor.vue b/packages/frontend/src/components/MkPollEditor.vue
index 43e576d1ab..34f6c72b6e 100644
--- a/packages/frontend/src/components/MkPollEditor.vue
+++ b/packages/frontend/src/components/MkPollEditor.vue
@@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</p>
<ul>
<li v-for="(choice, i) in choices" :key="i">
- <MkInput class="input" small :modelValue="choice" :placeholder="i18n.t('_poll.choiceN', { n: i + 1 })" @update:modelValue="onInput(i, $event)">
+ <MkInput class="input" small :modelValue="choice" :placeholder="i18n.tsx._poll.choiceN({ n: i + 1 })" @update:modelValue="onInput(i, $event)">
</MkInput>
<button class="_button" @click="remove(i)">
<i class="ti ti-x"></i>
diff --git a/packages/frontend/src/components/MkSignupDialog.form.vue b/packages/frontend/src/components/MkSignupDialog.form.vue
index 79e17c9aef..e27510fb34 100644
--- a/packages/frontend/src/components/MkSignupDialog.form.vue
+++ b/packages/frontend/src/components/MkSignupDialog.form.vue
@@ -263,7 +263,7 @@ async function onSubmit(): Promise<void> {
os.alert({
type: 'success',
title: i18n.ts._signup.almostThere,
- text: i18n.t('_signup.emailSent', { email: email.value }),
+ text: i18n.tsx._signup.emailSent({ email: email.value }),
});
emit('signupEmailPending');
} else {
diff --git a/packages/frontend/src/components/MkSignupDialog.rules.vue b/packages/frontend/src/components/MkSignupDialog.rules.vue
index 8cf7ce92ad..d42b496a34 100644
--- a/packages/frontend/src/components/MkSignupDialog.rules.vue
+++ b/packages/frontend/src/components/MkSignupDialog.rules.vue
@@ -105,7 +105,7 @@ async function updateAgreeServerRules(v: boolean) {
const confirm = await os.confirm({
type: 'question',
title: i18n.ts.doYouAgree,
- text: i18n.t('iHaveReadXCarefullyAndAgree', { x: i18n.ts.serverRules }),
+ text: i18n.tsx.iHaveReadXCarefullyAndAgree({ x: i18n.ts.serverRules }),
});
if (confirm.canceled) return;
agreeServerRules.value = true;
@@ -119,7 +119,7 @@ async function updateAgreeTosAndPrivacyPolicy(v: boolean) {
const confirm = await os.confirm({
type: 'question',
title: i18n.ts.doYouAgree,
- text: i18n.t('iHaveReadXCarefullyAndAgree', {
+ text: i18n.tsx.iHaveReadXCarefullyAndAgree({
x: tosPrivacyPolicyLabel.value,
}),
});
@@ -135,7 +135,7 @@ async function updateAgreeNote(v: boolean) {
const confirm = await os.confirm({
type: 'question',
title: i18n.ts.doYouAgree,
- text: i18n.t('iHaveReadXCarefullyAndAgree', { x: i18n.ts.basicNotesBeforeCreateAccount }),
+ text: i18n.tsx.iHaveReadXCarefullyAndAgree({ x: i18n.ts.basicNotesBeforeCreateAccount }),
});
if (confirm.canceled) return;
agreeNote.value = true;
diff --git a/packages/frontend/src/components/MkSubNoteContent.vue b/packages/frontend/src/components/MkSubNoteContent.vue
index 438140649e..13d0e6c2ca 100644
--- a/packages/frontend/src/components/MkSubNoteContent.vue
+++ b/packages/frontend/src/components/MkSubNoteContent.vue
@@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkA v-if="note.renoteId" :class="$style.rp" :to="`/notes/${note.renoteId}`">RN: ...</MkA>
</div>
<details v-if="note.files.length > 0">
- <summary>({{ i18n.t('withNFiles', { n: note.files.length }) }})</summary>
+ <summary>({{ i18n.tsx.withNFiles({ n: note.files.length }) }})</summary>
<MkMediaList :mediaList="note.files"/>
</details>
<details v-if="note.poll">
diff --git a/packages/frontend/src/components/MkTokenGenerateWindow.vue b/packages/frontend/src/components/MkTokenGenerateWindow.vue
index a42767e1b6..28f2f29b7d 100644
--- a/packages/frontend/src/components/MkTokenGenerateWindow.vue
+++ b/packages/frontend/src/components/MkTokenGenerateWindow.vue
@@ -33,12 +33,12 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton inline @click="enableAll">{{ i18n.ts.enableAll }}</MkButton>
</div>
<div class="_gaps_s">
- <MkSwitch v-for="kind in Object.keys(permissionSwitches)" :key="kind" v-model="permissionSwitches[kind]">{{ i18n.t(`_permissions.${kind}`) }}</MkSwitch>
+ <MkSwitch v-for="kind in Object.keys(permissionSwitches)" :key="kind" v-model="permissionSwitches[kind]">{{ i18n.ts._permissions[kind] }}</MkSwitch>
</div>
<div v-if="iAmAdmin" :class="$style.adminPermissions">
<div :class="$style.adminPermissionsHeader"><b>{{ i18n.ts.adminPermission }}</b></div>
<div class="_gaps_s">
- <MkSwitch v-for="kind in Object.keys(permissionSwitchesForAdmin)" :key="kind" v-model="permissionSwitchesForAdmin[kind]">{{ i18n.t(`_permissions.${kind}`) }}</MkSwitch>
+ <MkSwitch v-for="kind in Object.keys(permissionSwitchesForAdmin)" :key="kind" v-model="permissionSwitchesForAdmin[kind]">{{ i18n.ts._permissions[kind] }}</MkSwitch>
</div>
</div>
</div>
diff --git a/packages/frontend/src/components/MkTutorialDialog.vue b/packages/frontend/src/components/MkTutorialDialog.vue
index 963e78a1ff..9c3b46e133 100644
--- a/packages/frontend/src/components/MkTutorialDialog.vue
+++ b/packages/frontend/src/components/MkTutorialDialog.vue
@@ -133,7 +133,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<a href="https://misskey-hub.net/docs/for-users/" target="_blank" class="_link">{{ i18n.ts.help }}</a>
</template>
</I18n>
- <div>{{ i18n.t('_initialAccountSetting.haveFun', { name: instance.name ?? host }) }}</div>
+ <div>{{ i18n.tsx._initialAccountSetting.haveFun({ name: instance.name ?? host }) }}</div>
<div class="_buttonsCenter" style="margin-top: 16px;">
<MkButton v-if="initialPage !== 4" rounded @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton>
<MkButton rounded primary gradate @click="close(false)">{{ i18n.ts.close }}</MkButton>
diff --git a/packages/frontend/src/components/MkUserAnnouncementEditDialog.vue b/packages/frontend/src/components/MkUserAnnouncementEditDialog.vue
index af094a8e8c..9e3a78fe22 100644
--- a/packages/frontend/src/components/MkUserAnnouncementEditDialog.vue
+++ b/packages/frontend/src/components/MkUserAnnouncementEditDialog.vue
@@ -118,7 +118,7 @@ async function done() {
async function del() {
const { canceled } = await os.confirm({
type: 'warning',
- text: i18n.t('removeAreYouSure', { x: title.value }),
+ text: i18n.tsx.removeAreYouSure({ x: title.value }),
});
if (canceled) return;
diff --git a/packages/frontend/src/components/MkUserSetupDialog.Profile.vue b/packages/frontend/src/components/MkUserSetupDialog.Profile.vue
index 37aa677b44..f082833838 100644
--- a/packages/frontend/src/components/MkUserSetupDialog.Profile.vue
+++ b/packages/frontend/src/components/MkUserSetupDialog.Profile.vue
@@ -68,7 +68,7 @@ function setAvatar(ev) {
const { canceled } = await os.confirm({
type: 'question',
- text: i18n.t('cropImageAsk'),
+ text: i18n.ts.cropImageAsk,
okText: i18n.ts.cropYes,
cancelText: i18n.ts.cropNo,
});
diff --git a/packages/frontend/src/components/MkUserSetupDialog.vue b/packages/frontend/src/components/MkUserSetupDialog.vue
index 05b55f77a7..4b0c540829 100644
--- a/packages/frontend/src/components/MkUserSetupDialog.vue
+++ b/packages/frontend/src/components/MkUserSetupDialog.vue
@@ -93,7 +93,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps" style="text-align: center;">
<i class="ti ti-bell-ringing-2" style="display: block; margin: auto; font-size: 3em; color: var(--accent);"></i>
<div style="font-size: 120%;">{{ i18n.ts.pushNotification }}</div>
- <div style="padding: 0 16px;">{{ i18n.t('_initialAccountSetting.pushNotificationDescription', { name: instance.name ?? host }) }}</div>
+ <div style="padding: 0 16px;">{{ i18n.tsx._initialAccountSetting.pushNotificationDescription({ name: instance.name ?? host }) }}</div>
<MkPushNotificationAllowButton primary showOnlyToRegister style="margin: 0 auto;"/>
<div class="_buttonsCenter" style="margin-top: 16px;">
<MkButton rounded data-cy-user-setup-back @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton>
@@ -110,7 +110,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps" style="text-align: center;">
<i class="ti ti-check" style="display: block; margin: auto; font-size: 3em; color: var(--accent);"></i>
<div style="font-size: 120%;">{{ i18n.ts._initialAccountSetting.initialAccountSettingCompleted }}</div>
- <div>{{ i18n.t('_initialAccountSetting.youCanContinueTutorial', { name: instance.name ?? host }) }}</div>
+ <div>{{ i18n.tsx._initialAccountSetting.youCanContinueTutorial({ name: instance.name ?? host }) }}</div>
<div class="_buttonsCenter" style="margin-top: 16px;">
<MkButton rounded primary gradate data-cy-user-setup-continue @click="launchTutorial()">{{ i18n.ts._initialAccountSetting.startTutorial }} <i class="ti ti-arrow-right"></i></MkButton>
</div>
diff --git a/packages/frontend/src/components/MkWidgets.vue b/packages/frontend/src/components/MkWidgets.vue
index ee4e29dd8f..b8b253de06 100644
--- a/packages/frontend/src/components/MkWidgets.vue
+++ b/packages/frontend/src/components/MkWidgets.vue
@@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<header :class="$style.editHeader">
<MkSelect v-model="widgetAdderSelected" style="margin-bottom: var(--margin)" data-cy-widget-select>
<template #label>{{ i18n.ts.selectWidget }}</template>
- <option v-for="widget in widgetDefs" :key="widget" :value="widget">{{ i18n.t(`_widgets.${widget}`) }}</option>
+ <option v-for="widget in widgetDefs" :key="widget" :value="widget">{{ i18n.ts._widgets[widget] }}</option>
</MkSelect>
<MkButton inline primary data-cy-widget-add @click="addWidget"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton>
<MkButton inline @click="$emit('exit')">{{ i18n.ts.close }}</MkButton>
@@ -109,7 +109,7 @@ function onContextmenu(widget: Widget, ev: MouseEvent) {
os.contextMenu([{
type: 'label',
- text: i18n.t(`_widgets.${widget.name}`),
+ text: i18n.ts._widgets[widget.name],
}, {
icon: 'ti ti-settings',
text: i18n.ts.settings,
diff --git a/packages/frontend/src/components/global/I18n.vue b/packages/frontend/src/components/global/I18n.vue
new file mode 100644
index 0000000000..162aa2bcf8
--- /dev/null
+++ b/packages/frontend/src/components/global/I18n.vue
@@ -0,0 +1,46 @@
+<template>
+<render/>
+</template>
+
+<script setup lang="ts" generic="T extends string | ParameterizedString">
+import { computed, h } from 'vue';
+import type { ParameterizedString } from '../../../../../locales/index.js';
+
+const props = withDefaults(defineProps<{
+ src: T;
+ tag?: string;
+ // eslint-disable-next-line vue/require-default-prop
+ textTag?: string;
+}>(), {
+ tag: 'span',
+});
+
+const slots = defineSlots<T extends ParameterizedString<infer R> ? { [K in R]: () => unknown } : NonNullable<unknown>>();
+
+const parsed = computed(() => {
+ let str = props.src as string;
+ const value: (string | { arg: string; })[] = [];
+ for (;;) {
+ const nextBracketOpen = str.indexOf('{');
+ const nextBracketClose = str.indexOf('}');
+
+ if (nextBracketOpen === -1) {
+ value.push(str);
+ break;
+ } else {
+ if (nextBracketOpen > 0) value.push(str.substring(0, nextBracketOpen));
+ value.push({
+ arg: str.substring(nextBracketOpen + 1, nextBracketClose),
+ });
+ }
+
+ str = str.substring(nextBracketClose + 1);
+ }
+
+ return value;
+});
+
+const render = () => {
+ return h(props.tag, parsed.value.map(x => typeof x === 'string' ? (props.textTag ? h(props.textTag, x) : x) : slots[x.arg]()));
+};
+</script>
diff --git a/packages/frontend/src/components/global/MkTime.stories.impl.ts b/packages/frontend/src/components/global/MkTime.stories.impl.ts
index 0eeefa4859..0e7f6a9bdf 100644
--- a/packages/frontend/src/components/global/MkTime.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkTime.stories.impl.ts
@@ -123,7 +123,7 @@ export const DetailNow = {
export const RelativeOneHourAgo = {
...Empty,
async play({ canvasElement }) {
- await expect(canvasElement).toHaveTextContent(i18n.t('_ago.hoursAgo', { n: 1 }));
+ await expect(canvasElement).toHaveTextContent(i18n.tsx._ago.hoursAgo({ n: 1 }));
},
args: {
...Empty.args,
@@ -162,7 +162,7 @@ export const DetailOneHourAgo = {
export const RelativeOneDayAgo = {
...Empty,
async play({ canvasElement }) {
- await expect(canvasElement).toHaveTextContent(i18n.t('_ago.daysAgo', { n: 1 }));
+ await expect(canvasElement).toHaveTextContent(i18n.tsx._ago.daysAgo({ n: 1 }));
},
args: {
...Empty.args,
@@ -201,7 +201,7 @@ export const DetailOneDayAgo = {
export const RelativeOneWeekAgo = {
...Empty,
async play({ canvasElement }) {
- await expect(canvasElement).toHaveTextContent(i18n.t('_ago.weeksAgo', { n: 1 }));
+ await expect(canvasElement).toHaveTextContent(i18n.tsx._ago.weeksAgo({ n: 1 }));
},
args: {
...Empty.args,
@@ -240,7 +240,7 @@ export const DetailOneWeekAgo = {
export const RelativeOneMonthAgo = {
...Empty,
async play({ canvasElement }) {
- await expect(canvasElement).toHaveTextContent(i18n.t('_ago.monthsAgo', { n: 1 }));
+ await expect(canvasElement).toHaveTextContent(i18n.tsx._ago.monthsAgo({ n: 1 }));
},
args: {
...Empty.args,
@@ -279,7 +279,7 @@ export const DetailOneMonthAgo = {
export const RelativeOneYearAgo = {
...Empty,
async play({ canvasElement }) {
- await expect(canvasElement).toHaveTextContent(i18n.t('_ago.yearsAgo', { n: 1 }));
+ await expect(canvasElement).toHaveTextContent(i18n.tsx._ago.yearsAgo({ n: 1 }));
},
args: {
...Empty.args,
diff --git a/packages/frontend/src/components/global/MkTime.vue b/packages/frontend/src/components/global/MkTime.vue
index e11db9dc31..2b0bf246ad 100644
--- a/packages/frontend/src/components/global/MkTime.vue
+++ b/packages/frontend/src/components/global/MkTime.vue
@@ -55,21 +55,21 @@ const relative = computed<string>(() => {
if (invalid) return i18n.ts._ago.invalid;
return (
- ago.value >= 31536000 ? i18n.t('_ago.yearsAgo', { n: Math.round(ago.value / 31536000).toString() }) :
- ago.value >= 2592000 ? i18n.t('_ago.monthsAgo', { n: Math.round(ago.value / 2592000).toString() }) :
- ago.value >= 604800 ? i18n.t('_ago.weeksAgo', { n: Math.round(ago.value / 604800).toString() }) :
- ago.value >= 86400 ? i18n.t('_ago.daysAgo', { n: Math.round(ago.value / 86400).toString() }) :
- ago.value >= 3600 ? i18n.t('_ago.hoursAgo', { n: Math.round(ago.value / 3600).toString() }) :
- ago.value >= 60 ? i18n.t('_ago.minutesAgo', { n: (~~(ago.value / 60)).toString() }) :
- ago.value >= 10 ? i18n.t('_ago.secondsAgo', { n: (~~(ago.value % 60)).toString() }) :
+ ago.value >= 31536000 ? i18n.tsx._ago.yearsAgo({ n: Math.round(ago.value / 31536000).toString() }) :
+ ago.value >= 2592000 ? i18n.tsx._ago.monthsAgo({ n: Math.round(ago.value / 2592000).toString() }) :
+ ago.value >= 604800 ? i18n.tsx._ago.weeksAgo({ n: Math.round(ago.value / 604800).toString() }) :
+ ago.value >= 86400 ? i18n.tsx._ago.daysAgo({ n: Math.round(ago.value / 86400).toString() }) :
+ ago.value >= 3600 ? i18n.tsx._ago.hoursAgo({ n: Math.round(ago.value / 3600).toString() }) :
+ ago.value >= 60 ? i18n.tsx._ago.minutesAgo({ n: (~~(ago.value / 60)).toString() }) :
+ ago.value >= 10 ? i18n.tsx._ago.secondsAgo({ n: (~~(ago.value % 60)).toString() }) :
ago.value >= -3 ? i18n.ts._ago.justNow :
- ago.value < -31536000 ? i18n.t('_timeIn.years', { n: Math.round(-ago.value / 31536000).toString() }) :
- ago.value < -2592000 ? i18n.t('_timeIn.months', { n: Math.round(-ago.value / 2592000).toString() }) :
- ago.value < -604800 ? i18n.t('_timeIn.weeks', { n: Math.round(-ago.value / 604800).toString() }) :
- ago.value < -86400 ? i18n.t('_timeIn.days', { n: Math.round(-ago.value / 86400).toString() }) :
- ago.value < -3600 ? i18n.t('_timeIn.hours', { n: Math.round(-ago.value / 3600).toString() }) :
- ago.value < -60 ? i18n.t('_timeIn.minutes', { n: (~~(-ago.value / 60)).toString() }) :
- i18n.t('_timeIn.seconds', { n: (~~(-ago.value % 60)).toString() })
+ ago.value < -31536000 ? i18n.tsx._timeIn.years({ n: Math.round(-ago.value / 31536000).toString() }) :
+ ago.value < -2592000 ? i18n.tsx._timeIn.months({ n: Math.round(-ago.value / 2592000).toString() }) :
+ ago.value < -604800 ? i18n.tsx._timeIn.weeks({ n: Math.round(-ago.value / 604800).toString() }) :
+ ago.value < -86400 ? i18n.tsx._timeIn.days({ n: Math.round(-ago.value / 86400).toString() }) :
+ ago.value < -3600 ? i18n.tsx._timeIn.hours({ n: Math.round(-ago.value / 3600).toString() }) :
+ ago.value < -60 ? i18n.tsx._timeIn.minutes({ n: (~~(-ago.value / 60)).toString() }) :
+ i18n.tsx._timeIn.seconds({ n: (~~(-ago.value % 60)).toString() })
);
});
diff --git a/packages/frontend/src/components/global/i18n.ts b/packages/frontend/src/components/global/i18n.ts
deleted file mode 100644
index 2f4d7edabd..0000000000
--- a/packages/frontend/src/components/global/i18n.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and other misskey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { h } from 'vue';
-
-export default function(props: { src: string; tag?: string; textTag?: string; }, { slots }) {
- let str = props.src;
- const parsed = [] as (string | { arg: string; })[];
- while (true) {
- const nextBracketOpen = str.indexOf('{');
- const nextBracketClose = str.indexOf('}');
-
- if (nextBracketOpen === -1) {
- parsed.push(str);
- break;
- } else {
- if (nextBracketOpen > 0) parsed.push(str.substring(0, nextBracketOpen));
- parsed.push({
- arg: str.substring(nextBracketOpen + 1, nextBracketClose),
- });
- }
-
- str = str.substring(nextBracketClose + 1);
- }
-
- return h(props.tag ?? 'span', parsed.map(x => typeof x === 'string' ? (props.textTag ? h(props.textTag, x) : x) : slots[x.arg]()));
-}
diff --git a/packages/frontend/src/components/index.ts b/packages/frontend/src/components/index.ts
index a3e13c3a50..f3b476b15c 100644
--- a/packages/frontend/src/components/index.ts
+++ b/packages/frontend/src/components/index.ts
@@ -16,7 +16,7 @@ import MkUserName from './global/MkUserName.vue';
import MkEllipsis from './global/MkEllipsis.vue';
import MkTime from './global/MkTime.vue';
import MkUrl from './global/MkUrl.vue';
-import I18n from './global/i18n.js';
+import I18n from './global/I18n.vue';
import RouterView from './global/RouterView.vue';
import MkLoading from './global/MkLoading.vue';
import MkError from './global/MkError.vue';