feat: locale system
This commit is contained in:
11
bun.lock
11
bun.lock
@@ -19,6 +19,7 @@
|
||||
"reka-ui": "^2.8.0",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"vue": "^3.5.17",
|
||||
"vue-i18n": "11",
|
||||
"vue-router": "^4.5.1",
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -209,6 +210,12 @@
|
||||
|
||||
"@internationalized/number": ["@internationalized/number@3.6.5", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g=="],
|
||||
|
||||
"@intlify/core-base": ["@intlify/core-base@11.2.8", "", { "dependencies": { "@intlify/message-compiler": "11.2.8", "@intlify/shared": "11.2.8" } }, "sha512-nBq6Y1tVkjIUsLsdOjDSJj4AsjvD0UG3zsg9Fyc+OivwlA/oMHSKooUy9tpKj0HqZ+NWFifweHavdljlBLTwdA=="],
|
||||
|
||||
"@intlify/message-compiler": ["@intlify/message-compiler@11.2.8", "", { "dependencies": { "@intlify/shared": "11.2.8", "source-map-js": "^1.0.2" } }, "sha512-A5n33doOjmHsBtCN421386cG1tWp5rpOjOYPNsnpjIJbQ4POF0QY2ezhZR9kr0boKwaHjbOifvyQvHj2UTrDFQ=="],
|
||||
|
||||
"@intlify/shared": ["@intlify/shared@11.2.8", "", {}, "sha512-l6e4NZyUgv8VyXXH4DbuucFOBmxLF56C/mqh2tvApbzl2Hrhi1aTDcuv5TKdxzfHYmpO3UB0Cz04fgDT9vszfw=="],
|
||||
|
||||
"@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="],
|
||||
|
||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
||||
@@ -1149,6 +1156,8 @@
|
||||
|
||||
"vue-eslint-parser": ["vue-eslint-parser@10.2.0", "", { "dependencies": { "debug": "^4.4.0", "eslint-scope": "^8.2.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.6.0", "semver": "^7.6.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0" } }, "sha512-CydUvFOQKD928UzZhTp4pr2vWz1L+H99t7Pkln2QSPdvmURT0MoC4wUccfCnuEaihNsu9aYYyk+bep8rlfkUXw=="],
|
||||
|
||||
"vue-i18n": ["vue-i18n@11.2.8", "", { "dependencies": { "@intlify/core-base": "11.2.8", "@intlify/shared": "11.2.8", "@vue/devtools-api": "^6.5.0" }, "peerDependencies": { "vue": "^3.0.0" } }, "sha512-vJ123v/PXCZntd6Qj5Jumy7UBmIuE92VrtdX+AXr+1WzdBHojiBxnAxdfctUFL+/JIN+VQH4BhsfTtiGsvVObg=="],
|
||||
|
||||
"vue-router": ["vue-router@4.5.1", "", { "dependencies": { "@vue/devtools-api": "^6.6.4" }, "peerDependencies": { "vue": "^3.2.0" } }, "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw=="],
|
||||
|
||||
"vue-tsc": ["vue-tsc@2.2.12", "", { "dependencies": { "@volar/typescript": "2.4.15", "@vue/language-core": "2.2.12" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "./bin/vue-tsc.js" } }, "sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw=="],
|
||||
@@ -1237,6 +1246,8 @@
|
||||
|
||||
"vue-eslint-parser/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
||||
|
||||
"vue-i18n/@vue/devtools-api": ["@vue/devtools-api@6.6.4", "", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="],
|
||||
|
||||
"vue-router/@vue/devtools-api": ["@vue/devtools-api@6.6.4", "", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
"reka-ui": "^2.8.0",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"vue": "^3.5.17",
|
||||
"vue-i18n": "11",
|
||||
"vue-router": "^4.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
10
src/App.vue
10
src/App.vue
@@ -1,4 +1,12 @@
|
||||
<script lang="ts" setup></script>
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useLanguageStore } from "./stores/LanguageStore";
|
||||
|
||||
onMounted(() => {
|
||||
// 加载 i18n
|
||||
useI18n().locale.value = useLanguageStore().language;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { useGlobalLanguageHook } from "@/hooks/globalLanguageHook";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { changeGlobalLanguage, curGlobalLanguage, optionalLanguages } =
|
||||
useGlobalLanguageHook();
|
||||
|
||||
const { locale, t } = useI18n();
|
||||
|
||||
const onClickChangeLocal = (newLanguage: string) => {
|
||||
changeGlobalLanguage(newLanguage, locale);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -41,7 +48,7 @@ const { changeGlobalLanguage, curGlobalLanguage, optionalLanguages } =
|
||||
class="dropdown-content bg-base-200 text-base-content rounded-box top-px mt-14 w-56 overflow-y-auto border-[length:var(--border)] border-white/5 shadow-2xl outline-[length:var(--border)] outline-black/5"
|
||||
>
|
||||
<ul class="menu menu-sm w-full">
|
||||
<li class="menu-title text-xs">语言</li>
|
||||
<li class="menu-title text-xs">{{ t("nav.locale") }}</li>
|
||||
<li
|
||||
v-for="optionalLanguage in optionalLanguages"
|
||||
:key="optionalLanguage.label"
|
||||
@@ -50,7 +57,7 @@ const { changeGlobalLanguage, curGlobalLanguage, optionalLanguages } =
|
||||
:class="[
|
||||
curGlobalLanguage === optionalLanguage.label ? 'menu-active' : '',
|
||||
]"
|
||||
@click="changeGlobalLanguage(optionalLanguage.label)"
|
||||
@click="onClickChangeLocal(optionalLanguage.label)"
|
||||
>
|
||||
<span class="pe-4 font-mono font-bold opacity-40">
|
||||
{{ optionalLanguage.label }}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { useGlobalThemeHook } from "@/hooks/globalThemeHook";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const { changeGlobalTheme, curGlobalTheme, optionalThemes } =
|
||||
useGlobalThemeHook();
|
||||
@@ -31,7 +34,7 @@ const { changeGlobalTheme, curGlobalTheme, optionalThemes } =
|
||||
tabindex="-1"
|
||||
class="dropdown-content bg-base-300 rounded-box z-1 w-52 p-2 shadow-2xl max-h-84 overflow-auto mt-6"
|
||||
>
|
||||
<li class="menu-title text-xs my-1">主题</li>
|
||||
<li class="menu-title text-xs my-1">{{ t("nav.theme") }}</li>
|
||||
<li
|
||||
v-for="optionalTheme in optionalThemes"
|
||||
:key="optionalTheme"
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import ChangeLanguageDropdownButton from "@/components/button/ChangeLanguageDropdownButton.vue";
|
||||
import ChangeThemeDropdownButton from "@/components/button/ChangeThemeDropdownButton.vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -27,16 +30,24 @@ import ChangeThemeDropdownButton from "@/components/button/ChangeThemeDropdownBu
|
||||
tabindex="-1"
|
||||
class="menu dropdown-content bg-base-100 rounded-box z-1 mt-5 w-52 p-2 shadow"
|
||||
>
|
||||
<li><a>首页</a></li>
|
||||
<li><a>关于</a></li>
|
||||
<li>
|
||||
<a>{{ t("nav.home") }}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a>{{ t("nav.about") }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<a class="btn btn-ghost text-xl">daisyUI</a>
|
||||
<a class="btn btn-ghost text-xl">Hucky</a>
|
||||
</div>
|
||||
<div class="navbar-center hidden lg:flex">
|
||||
<ul class="menu menu-horizontal px-1">
|
||||
<li><a>首页</a></li>
|
||||
<li><a>关于</a></li>
|
||||
<li>
|
||||
<a>{{ t("nav.home") }}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a>{{ t("nav.about") }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="navbar-end">
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
GlobalLanguage,
|
||||
languageMap,
|
||||
} from "@/stores/LanguageStore";
|
||||
import { Locale } from "vue-i18n";
|
||||
|
||||
const languageStore = useLanguageStore();
|
||||
|
||||
@@ -16,8 +17,12 @@ export const optionalLanguages = Object.entries(languageMap).map(
|
||||
// 一定不要通过改变 curGlobalLanguage 来改变语言,而要通过 changeGlobalLanguage 来改变语言
|
||||
const curGlobalLanguage = computed(() => languageStore.language);
|
||||
|
||||
function changeGlobalLanguage(language: GlobalLanguage) {
|
||||
function changeGlobalLanguage(
|
||||
language: GlobalLanguage,
|
||||
locale: WritableComputedRef<string>,
|
||||
) {
|
||||
languageStore.setLanguage(language);
|
||||
locale.value = language;
|
||||
}
|
||||
|
||||
export const useGlobalLanguageHook = () => ({
|
||||
|
||||
10
src/i18n/en_US.ts
Normal file
10
src/i18n/en_US.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { messagesInterface } from ".";
|
||||
|
||||
export const en_USMessages: messagesInterface = {
|
||||
nav: {
|
||||
home: "Home",
|
||||
about: "About",
|
||||
theme: "Theme",
|
||||
locale: "Locale",
|
||||
},
|
||||
};
|
||||
24
src/i18n/index.ts
Normal file
24
src/i18n/index.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { createI18n } from "vue-i18n";
|
||||
import { zh_CNMessages } from "./zh_CN";
|
||||
import { en_USMessages } from "./en_US";
|
||||
|
||||
export interface messagesInterface {
|
||||
nav: {
|
||||
home: string;
|
||||
about: string;
|
||||
theme: string;
|
||||
locale: string;
|
||||
};
|
||||
}
|
||||
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: "ZH",
|
||||
fallbackLocale: "EN",
|
||||
messages: {
|
||||
ZH: zh_CNMessages,
|
||||
EN: en_USMessages,
|
||||
},
|
||||
});
|
||||
|
||||
export default i18n;
|
||||
10
src/i18n/zh_CN.ts
Normal file
10
src/i18n/zh_CN.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { messagesInterface } from ".";
|
||||
|
||||
export const zh_CNMessages: messagesInterface = {
|
||||
nav: {
|
||||
home: "首页",
|
||||
about: "关于",
|
||||
theme: "主题",
|
||||
locale: "语言",
|
||||
},
|
||||
};
|
||||
@@ -2,10 +2,11 @@ import { createApp } from "vue";
|
||||
import "./style.css";
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
import i18n from "./i18n";
|
||||
import { createPinia } from "pinia";
|
||||
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
|
||||
|
||||
const pinia = createPinia();
|
||||
pinia.use(piniaPluginPersistedstate);
|
||||
|
||||
createApp(App).use(router).use(pinia).mount("#app");
|
||||
createApp(App).use(router).use(pinia).use(i18n).mount("#app");
|
||||
|
||||
Reference in New Issue
Block a user