feat: install and configure i18n features (#177)
Co-authored-by: Shinigami <chrissi92@hotmail.de> Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe> Co-authored-by: Daniel Roe <daniel@roe.dev>
This commit is contained in:
parent
443bd65c05
commit
871076f2d9
7
.vscode/settings.json
vendored
7
.vscode/settings.json
vendored
|
@ -10,5 +10,10 @@
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"masto",
|
"masto",
|
||||||
"Nuxtodon"
|
"Nuxtodon"
|
||||||
]
|
],
|
||||||
|
"i18n-ally.localesPaths": [
|
||||||
|
"locales"
|
||||||
|
],
|
||||||
|
"i18n-ally.keystyle": "nested",
|
||||||
|
"i18n-ally.sourceLanguage": "en-US"
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,17 +5,20 @@ const buildTimeAgo = useTimeAgo(buildTime)
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<footer p4 text-sm text-secondary-light flex="~ col">
|
<footer p4 text-sm text-secondary-light flex="~ col">
|
||||||
<div flex="~ gap2">
|
<div flex="~ gap2" items-center mb4>
|
||||||
<button i-ri-sun-line dark:i-ri-moon-line text-lg mb4 @click="toggleDark()" />
|
<button i-ri-sun-line dark:i-ri-moon-line text-lg @click="toggleDark()" />
|
||||||
<button
|
<button
|
||||||
text-lg mb4
|
text-lg
|
||||||
:class="isZenMode ? 'i-ri:layout-right-2-line' : 'i-ri:layout-right-line'"
|
:class="isZenMode ? 'i-ri:layout-right-2-line' : 'i-ri:layout-right-line'"
|
||||||
@click="toggleZenMode()"
|
@click="toggleZenMode()"
|
||||||
/>
|
/>
|
||||||
|
<NavSelectLanguage />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button cursor-pointer hover:underline @click="openPreviewHelp">
|
||||||
|
Show intro
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button cursor-pointer hover:underline @click="openPreviewHelp">
|
|
||||||
Show intro
|
|
||||||
</button>
|
|
||||||
<div>A Mastodon client made with 🧡</div>
|
<div>A Mastodon client made with 🧡</div>
|
||||||
<div>Built <time :datetime="buildTime" :title="buildTime">{{ buildTimeAgo }}</time> · <a href="https://github.com/elk-zone/elk" target="_blank">GitHub</a></div>
|
<div>Built <time :datetime="buildTime" :title="buildTime">{{ buildTimeAgo }}</time> · <a href="https://github.com/elk-zone/elk" target="_blank">GitHub</a></div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
@ -1,21 +1,27 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<nav px3 py4 flex="~ col gap2" text-lg>
|
<nav px3 py4 flex="~ col gap2" text-lg>
|
||||||
<template v-if="currentUser">
|
<template v-if="currentUser">
|
||||||
<NavSideItem text="Home" to="/home" icon="i-ri:home-5-line" />
|
<NavSideItem :text="t('nav_side.home')" to="/home" icon="i-ri:home-5-line" />
|
||||||
<NavSideItem text="Notifications" to="/notifications" icon="i-ri:notification-4-line" />
|
<NavSideItem :text="t('nav_side.notifications')" to="/notifications" icon="i-ri:notification-4-line" />
|
||||||
</template>
|
</template>
|
||||||
<NavSideItem text="Explore" to="/explore" icon="i-ri:hashtag" />
|
<NavSideItem :text="t('nav_side.explore')" to="/explore" icon="i-ri:hashtag" />
|
||||||
<NavSideItem text="Local" to="/public/local" icon="i-ri:group-2-line " />
|
<NavSideItem :text="t('nav_side.local')" to="/public/local" icon="i-ri:group-2-line " />
|
||||||
<NavSideItem text="Federated" to="/public" icon="i-ri:earth-line" />
|
<NavSideItem :text="t('nav_side.federated')" to="/public" icon="i-ri:earth-line" />
|
||||||
<template v-if="currentUser">
|
<template v-if="currentUser">
|
||||||
<NavSideItem text="Conversations" to="/conversations" icon="i-ri:at-line" />
|
<NavSideItem :text="t('nav_side.conversations')" to="/conversations" icon="i-ri:at-line" />
|
||||||
<NavSideItem text="Favourites" to="/favourites" icon="i-ri:heart-3-line" />
|
<NavSideItem :text="t('nav_side.favourites')" to="/favourites" icon="i-ri:heart-3-line" />
|
||||||
<NavSideItem text="Bookmarks" to="/bookmarks" icon="i-ri:bookmark-line " />
|
<NavSideItem :text="t('nav_side.bookmarks')" to="/bookmarks" icon="i-ri:bookmark-line " />
|
||||||
<NavSideItem :to="getAccountPath(currentUser.account)" icon="i-ri:list-check-2-line">
|
<NavSideItem :to="getAccountPath(currentUser.account)" icon="i-ri:list-check-2-line">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<AccountAvatar :account="currentUser.account" h="1.2em" />
|
<AccountAvatar :account="currentUser.account" h="1.2em" />
|
||||||
</template>
|
</template>
|
||||||
<ContentRich :content="getDisplayName(currentUser.account, { rich: true })" :emojis="currentUser.account.emojis" />
|
<ContentRich :content="getDisplayName(currentUser.account, { rich: true }) || t('nav_side.profile')" :emojis="currentUser.account.emojis" />
|
||||||
</NavSideItem>
|
</NavSideItem>
|
||||||
</template>
|
</template>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
36
components/nav/SelectLanguage.vue
Normal file
36
components/nav/SelectLanguage.vue
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
const { locale } = useI18n()
|
||||||
|
const languageList = [
|
||||||
|
{
|
||||||
|
value: 'en-US',
|
||||||
|
label: 'English',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'zh-CN',
|
||||||
|
label: '简体中文',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<CommonTooltip placement="bottom" content="Select Language">
|
||||||
|
<CommonDropdown>
|
||||||
|
<button align-top>
|
||||||
|
<div i-ri:earth-line text-lg />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<template #popper>
|
||||||
|
<CommonDropdownItem
|
||||||
|
v-for="item in languageList"
|
||||||
|
:key="item.value"
|
||||||
|
:checked="item.value === locale"
|
||||||
|
@click="locale = item.value"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</CommonDropdownItem>
|
||||||
|
</template>
|
||||||
|
</CommonDropdown>
|
||||||
|
</CommonTooltip>
|
||||||
|
</template>
|
13
locales/en-US.json
Normal file
13
locales/en-US.json
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"nav_side": {
|
||||||
|
"home": "Home",
|
||||||
|
"notifications": "Notifications",
|
||||||
|
"explore": "Explore",
|
||||||
|
"local": "Local",
|
||||||
|
"federated": "Federated",
|
||||||
|
"conversations": "Conversations",
|
||||||
|
"favourites": "Favourites",
|
||||||
|
"bookmarks": "Bookmarks",
|
||||||
|
"profile": "Profile"
|
||||||
|
}
|
||||||
|
}
|
13
locales/zh-CN.json
Normal file
13
locales/zh-CN.json
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"nav_side": {
|
||||||
|
"bookmarks": "书签",
|
||||||
|
"conversations": "私信",
|
||||||
|
"explore": "探索",
|
||||||
|
"favourites": "喜欢",
|
||||||
|
"federated": "跨站",
|
||||||
|
"home": "主页",
|
||||||
|
"local": "本地",
|
||||||
|
"notifications": "通知",
|
||||||
|
"profile": "个人资料"
|
||||||
|
}
|
||||||
|
}
|
|
@ -67,6 +67,7 @@
|
||||||
"unplugin-auto-import": "^0.12.0",
|
"unplugin-auto-import": "^0.12.0",
|
||||||
"vite-plugin-inspect": "^0.7.9",
|
"vite-plugin-inspect": "^0.7.9",
|
||||||
"vitest": "^0.25.3",
|
"vitest": "^0.25.3",
|
||||||
|
"vue-i18n": "^9.2.2",
|
||||||
"vue-safe-teleport": "^0.1.1",
|
"vue-safe-teleport": "^0.1.1",
|
||||||
"vue-virtual-scroller": "2.0.0-beta.3"
|
"vue-virtual-scroller": "2.0.0-beta.3"
|
||||||
}
|
}
|
||||||
|
|
25
plugins/i18n.ts
Normal file
25
plugins/i18n.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import { createI18n } from 'vue-i18n'
|
||||||
|
import enUS from '../locales/en-US.json'
|
||||||
|
import zhCn from '../locales/zh-CN.json'
|
||||||
|
|
||||||
|
/** Default language environment */
|
||||||
|
export const defaultLocale = 'en-US'
|
||||||
|
|
||||||
|
export const messages = {
|
||||||
|
'en-US': enUS,
|
||||||
|
'zh-CN': zhCn,
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Language Environment List */
|
||||||
|
export const localeList = Object.keys(messages)
|
||||||
|
|
||||||
|
export default defineNuxtPlugin(({ vueApp }) => {
|
||||||
|
const i18n = createI18n({
|
||||||
|
legacy: false,
|
||||||
|
globalInjection: true,
|
||||||
|
locale: defaultLocale,
|
||||||
|
messages,
|
||||||
|
})
|
||||||
|
|
||||||
|
vueApp.use(i18n)
|
||||||
|
})
|
|
@ -52,6 +52,7 @@ specifiers:
|
||||||
unplugin-auto-import: ^0.12.0
|
unplugin-auto-import: ^0.12.0
|
||||||
vite-plugin-inspect: ^0.7.9
|
vite-plugin-inspect: ^0.7.9
|
||||||
vitest: ^0.25.3
|
vitest: ^0.25.3
|
||||||
|
vue-i18n: ^9.2.2
|
||||||
vue-safe-teleport: ^0.1.1
|
vue-safe-teleport: ^0.1.1
|
||||||
vue-virtual-scroller: 2.0.0-beta.3
|
vue-virtual-scroller: 2.0.0-beta.3
|
||||||
|
|
||||||
|
@ -107,6 +108,7 @@ devDependencies:
|
||||||
unplugin-auto-import: 0.12.0
|
unplugin-auto-import: 0.12.0
|
||||||
vite-plugin-inspect: 0.7.9
|
vite-plugin-inspect: 0.7.9
|
||||||
vitest: 0.25.3
|
vitest: 0.25.3
|
||||||
|
vue-i18n: 9.2.2
|
||||||
vue-safe-teleport: 0.1.1
|
vue-safe-teleport: 0.1.1
|
||||||
vue-virtual-scroller: 2.0.0-beta.3
|
vue-virtual-scroller: 2.0.0-beta.3
|
||||||
|
|
||||||
|
@ -655,6 +657,44 @@ packages:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@intlify/core-base/9.2.2:
|
||||||
|
resolution: {integrity: sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==}
|
||||||
|
engines: {node: '>= 14'}
|
||||||
|
dependencies:
|
||||||
|
'@intlify/devtools-if': 9.2.2
|
||||||
|
'@intlify/message-compiler': 9.2.2
|
||||||
|
'@intlify/shared': 9.2.2
|
||||||
|
'@intlify/vue-devtools': 9.2.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@intlify/devtools-if/9.2.2:
|
||||||
|
resolution: {integrity: sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==}
|
||||||
|
engines: {node: '>= 14'}
|
||||||
|
dependencies:
|
||||||
|
'@intlify/shared': 9.2.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@intlify/message-compiler/9.2.2:
|
||||||
|
resolution: {integrity: sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==}
|
||||||
|
engines: {node: '>= 14'}
|
||||||
|
dependencies:
|
||||||
|
'@intlify/shared': 9.2.2
|
||||||
|
source-map: 0.6.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@intlify/shared/9.2.2:
|
||||||
|
resolution: {integrity: sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==}
|
||||||
|
engines: {node: '>= 14'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@intlify/vue-devtools/9.2.2:
|
||||||
|
resolution: {integrity: sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==}
|
||||||
|
engines: {node: '>= 14'}
|
||||||
|
dependencies:
|
||||||
|
'@intlify/core-base': 9.2.2
|
||||||
|
'@intlify/shared': 9.2.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@ioredis/commands/1.2.0:
|
/@ioredis/commands/1.2.0:
|
||||||
resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==}
|
resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -7865,6 +7905,18 @@ packages:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/vue-i18n/9.2.2:
|
||||||
|
resolution: {integrity: sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==}
|
||||||
|
engines: {node: '>= 14'}
|
||||||
|
peerDependencies:
|
||||||
|
vue: ^3.0.0
|
||||||
|
dependencies:
|
||||||
|
'@intlify/core-base': 9.2.2
|
||||||
|
'@intlify/shared': 9.2.2
|
||||||
|
'@intlify/vue-devtools': 9.2.2
|
||||||
|
'@vue/devtools-api': 6.4.5
|
||||||
|
dev: true
|
||||||
|
|
||||||
/vue-observe-visibility/2.0.0-alpha.1:
|
/vue-observe-visibility/2.0.0-alpha.1:
|
||||||
resolution: {integrity: sha512-flFbp/gs9pZniXR6fans8smv1kDScJ8RS7rEpMjhVabiKeq7Qz3D9+eGsypncjfIyyU84saU88XZ0zjbD6Gq/g==}
|
resolution: {integrity: sha512-flFbp/gs9pZniXR6fans8smv1kDScJ8RS7rEpMjhVabiKeq7Qz3D9+eGsypncjfIyyU84saU88XZ0zjbD6Gq/g==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
Loading…
Reference in a new issue