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:
Ayaka Rizumu 2022-11-28 14:58:29 +08:00 committed by GitHub
parent 443bd65c05
commit 871076f2d9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 170 additions and 16 deletions

View file

@ -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"
} }

View file

@ -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>

View file

@ -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>

View 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
View 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
View file

@ -0,0 +1,13 @@
{
"nav_side": {
"bookmarks": "书签",
"conversations": "私信",
"explore": "探索",
"favourites": "喜欢",
"federated": "跨站",
"home": "主页",
"local": "本地",
"notifications": "通知",
"profile": "个人资料"
}
}

View file

@ -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
View 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)
})

View file

@ -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: