完善翻译

This commit is contained in:
Armamem0t 2025-07-01 23:27:03 +08:00
parent 7f8defeee2
commit 953a370233
Signed by: minglipro
GPG Key ID: 5F355A77B22AA93B
13 changed files with 195 additions and 52 deletions

View File

@ -25,12 +25,12 @@
"id": {
"type": "string",
"description": "语言ID",
"pattern": "^[a-z]{2}-[a-z]{2}$"
"pattern": "^[a-z]{2}-[A-Z]{2}$"
},
"file": {
"type": "string",
"description": "语言文件在language文件夹的位置",
"pattern": "^[A-Z]{2}_[A-Z]{2}\\.json$"
"pattern": "^[a-z]{2}-[A-Z]{2}\\.json$"
},
"icon": {
"type": "string",

View File

@ -1,7 +0,0 @@
{
"nav": {
"title": {
"home": "Home"
}
}
}

View File

@ -1,7 +0,0 @@
{
"nav": {
"title": {
"home": "主页"
}
}
}

View File

@ -3,16 +3,28 @@
"iconsUrl": "https://icones.js.org/collection/emojione-v1?category=Flags",
"languages": [
{
"title": "中国-汉语",
"id": "zh-cn",
"file": "ZH_CN.json",
"title": "zh-CN 简体中文",
"id": "zh-CN",
"file": "zh-CN.json",
"icon": "emojione-v1:flag-for-china"
},
{
"title": "US-English",
"id": "en-us",
"file": "EN_US.json",
"title": "zh-TW 简体中文",
"id": "zh-TW",
"file": "zh-TW.json",
"icon": "emojione-v1:flag-for-china"
},
{
"title": "en-US English",
"id": "en-US",
"file": "en-US.json",
"icon": "emojione-v1:flag-for-united-states"
},
{
"title": "ja-JP 日本語",
"id": "ja-JP",
"file": "ja-JP.json",
"icon": "emojione-v1:flag-for-japan"
}
]
}

View File

@ -0,0 +1,35 @@
{
"message": {
"login": {
"plaselogin": "Plase login."
}
},
"nav": {
"title": {
"api": "API",
"file": "file",
"home": "Home",
"setting": "setting",
"user": "user"
}
},
"setting": {
"language": {
"title": "language"
},
"theme": {
"auto": "auto",
"dark": "dark",
"light": "light",
"title": "theme"
},
"title": "setting"
},
"view": {
"login": {
"password": "password",
"title": "login",
"username": "username"
}
}
}

View File

@ -0,0 +1,35 @@
{
"message": {
"login": {
"plaselogin": "ログインしてください"
}
},
"nav": {
"title": {
"api": "API",
"file": "ファイル",
"home": "ホーム",
"setting": "設定",
"user": "ユーザー"
}
},
"setting": {
"language": {
"title": "言語設定"
},
"theme": {
"auto": "自動",
"dark": "ダークモード",
"light": "ライトモード",
"title": "テーマ設定"
},
"title": "設定"
},
"view": {
"login": {
"password": "パスワード",
"title": "ログイン",
"username": "ユーザー名"
}
}
}

View File

@ -0,0 +1,35 @@
{
"message": {
"login": {
"plaselogin": "请登陆"
}
},
"nav": {
"title": {
"api": "API",
"file": "文件",
"home": "主页",
"setting": "设置",
"user": "用户"
}
},
"setting": {
"language": {
"title": "语言配置"
},
"theme": {
"auto": "自动",
"dark": "暗色",
"light": "亮色",
"title": "主题配置"
},
"title": "设置"
},
"view": {
"login": {
"password": "密码",
"title": "登陆",
"username": "用户名"
}
}
}

View File

@ -0,0 +1,35 @@
{
"message": {
"login": {
"plaselogin": "請登入"
}
},
"nav": {
"title": {
"api": "API",
"file": "檔案",
"home": "首頁",
"setting": "設定",
"user": "使用者"
}
},
"setting": {
"language": {
"title": "語言設定"
},
"theme": {
"auto": "自動",
"dark": "深色",
"light": "淺色",
"title": "主題設定"
},
"title": "設定"
},
"view": {
"login": {
"password": "密碼",
"title": "登入",
"username": "使用者名稱"
}
}
}

View File

@ -1,7 +1,7 @@
<template>
<nav class="navmain">
<router-link :to="{ name: 'home' }" c-c f style="color: inherit; height: 100%; text-decoration: none">
<img height="50" src="@/assets/index.svg" width="50" />
<img alt="@/assets/index.svg" height="50" src="@/assets/index.svg" width="50" />
<div>
<label style="font-size: 20px; margin-left: 10px; cursor: pointer">{{ useSettingStore.appName }}</label>
<label style="margin-left: 5px; font-size: 12px; cursor: pointer">V{{ useSettingStore.appVersion }}</label>
@ -26,7 +26,7 @@
}"
@click="openFile()">
<Icon icon="material-symbols:folder-rounded" />
文件
{{ t('nav.title.file') }}
<div class="after"></div>
</div>
<div
@ -36,7 +36,7 @@
}"
@click="router.push({ name: 'user' })">
<Icon icon="material-symbols:person-rounded" />
用户
{{ t('nav.title.user') }}
<div class="after"></div>
</div>
<div
@ -46,7 +46,7 @@
}"
@click="router.push({ name: 'api' })">
<icon icon="mdi:api" />
API
{{ t('nav.title.api') }}
<div class="after"></div>
</div>
<div
@ -55,23 +55,23 @@
}"
@click="activeSetting.on()">
<Icon icon="material-symbols:settings" />
设置
{{ t('nav.title.setting') }}
<div class="after"></div>
</div>
</div>
</nav>
<nav class="nav">
<n-drawer v-model:show="activeSetting.value" placement="right">
<n-drawer-content title="设置">
<n-divider>主题配置</n-divider>
<n-drawer v-model:show="activeSetting.value" placement="right" width="auto">
<n-drawer-content :title="t('setting.title')">
<n-divider>{{ t('setting.theme.title') }}</n-divider>
<div c-c f>
<n-radio-group v-model:value="useSettingStore.themeMode" name="team">
<n-radio-button value="light">亮色</n-radio-button>
<n-radio-button value="dark">暗色</n-radio-button>
<n-radio-button value="auto">自动</n-radio-button>
<n-radio-button value="light">{{ t('setting.theme.light') }}</n-radio-button>
<n-radio-button value="dark">{{ t('setting.theme.dark') }}</n-radio-button>
<n-radio-button value="auto">{{ t('setting.theme.auto') }}</n-radio-button>
</n-radio-group>
</div>
<n-divider>语言配置</n-divider>
<n-divider>{{ t('setting.language.title') }}</n-divider>
<n-select
:options="messageData"
:render-label="renderLabel"
@ -87,11 +87,11 @@
import Icon from '@/components/Icon.vue';
import { UseBoolRef } from '@/util';
import {
i18n,
type languageIndexItemValueType,
message,
messageData,
router,
t,
UseAuthStore,
UseSettingStore,
} from '@/plugin';
@ -156,15 +156,13 @@ function openFile() {
path: `/file/${useAuthStore.username}`,
});
} else {
message.error('请先登录');
message.error(() => t('message.login.plaselogin'));
router.push({
path: `/login`,
});
}
}
const t = i18n.global.t;
window.i18n = i18n;
console.log(t);
</script>
<style lang="scss" scoped>

View File

@ -4,7 +4,7 @@ import { ref } from 'vue';
export * from './type';
const languagedatas = import.meta.glob('@/language/*.json');
const languagedatas = import.meta.glob('@/language/**/*.json');
const loadIndexFile = async (): Promise<languageIndexType> => {
try {
@ -20,7 +20,9 @@ const loadIndexFile = async (): Promise<languageIndexType> => {
const loadLanguageFile = async (fileName: string): Promise<languageType> => {
try {
const module = (await languagedatas[`/language/${fileName}`]()) as { default: languageType };
const module = (await languagedatas[`/language/${fileName}`]()) as {
default: languageType;
};
return module.default;
} catch (error) {
console.error(`加载语言文件失败:${fileName}`, error);
@ -47,6 +49,10 @@ export async function installI18n() {
value: i.id,
icon: i.icon,
});
messages[i.id] = await loadLanguageFile(i.file);
messages[i.id] = await loadLanguageFile(`lang/${i.file}`);
}
}
export function t(d: string): string {
return i18n.global.t(d);
}

View File

@ -12,7 +12,7 @@ export const UseSettingStore = defineStore('setting', {
theme: state,
appName: '',
appVersion: '',
language: 'zh-cn',
language: 'zh-CN',
};
},
persist: {
@ -23,10 +23,12 @@ export const UseSettingStore = defineStore('setting', {
setLanguage(data: string | null) {
if (data == null) {
i18n.global.locale.value = this.language;
document.documentElement.lang = this.language;
return;
}
this.language = data;
i18n.global.locale.value = data;
document.documentElement.lang = data;
},
},
});

View File

@ -15,7 +15,4 @@ onMounted(() => {
});
});
</script>
<style scoped>
* {
}
</style>
<style scoped></style>

View File

@ -6,20 +6,22 @@
content: true,
footer: 'soft',
}"
style="width: 430px"
title="登录">
:title="t('view.login.title')"
style="width: 430px">
<n-form border label-align="right" label-placement="left" label-width="auto">
<n-form-item label="用户名">
<n-form-item :label="t('view.login.username')">
<n-input />
</n-form-item>
<n-form-item label="密码">
<n-form-item :label="t('view.login.password')">
<n-input />
</n-form-item>
</n-form>
<n-button block secondary strong type="primary">登录</n-button>
<n-button block secondary strong type="primary">{{ t('view.login.title') }}</n-button>
</n-card>
</n-spin>
</div>
</template>
<script lang="ts" setup></script>
<script lang="ts" setup>
import { t } from '@/plugin';
</script>
<style scoped></style>