feat: dynamic language change

This commit is contained in:
2026-02-18 01:56:07 +08:00
parent 1a8afd9573
commit 6153c7e87e
7 changed files with 62 additions and 10 deletions

2
components.d.ts vendored
View File

@@ -13,6 +13,7 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
AnimatePresence: typeof import('motion-v')['AnimatePresence']
AnimText: typeof import('./src/components/special/AnimText.vue')['default']
AuthDialog: typeof import('./src/components/dialog/AuthDialog.vue')['default']
Button: typeof import('./src/components/ui/button/Button.vue')['default']
Calendar: typeof import('./src/components/ui/calendar/Calendar.vue')['default']
@@ -52,6 +53,7 @@ declare module 'vue' {
// For TSX support
declare global {
const AnimatePresence: typeof import('motion-v')['AnimatePresence']
const AnimText: typeof import('./src/components/special/AnimText.vue')['default']
const AuthDialog: typeof import('./src/components/dialog/AuthDialog.vue')['default']
const Button: typeof import('./src/components/ui/button/Button.vue')['default']
const Calendar: typeof import('./src/components/ui/calendar/Calendar.vue')['default']

View File

@@ -0,0 +1,27 @@
<script setup lang="ts">
import { motion, useAnimate } from "motion-v";
import { useI18n } from "vue-i18n";
import { languageChangeBus } from "@/hooks/bus/languageChangeBus";
import type { Key, ResourceKeys } from "vue-i18n";
const { t } = useI18n();
const props = defineProps<{
text: Key | ResourceKeys;
}>();
const [scope, animate] = useAnimate();
languageChangeBus.on(async () => {
await animate(scope.current, { opacity: 0, y: "-20px" });
await animate(scope.current, { opacity: 1, y: "0" });
});
</script>
<template>
<motion.span ref="scope">
{{ t(props.text) }}
</motion.span>
</template>
<style scoped></style>

4
src/hooks/bus/index.ts Normal file
View File

@@ -0,0 +1,4 @@
export const keys = {
user: "user",
language: "language",
};

View File

@@ -0,0 +1,4 @@
import { useEventBus } from "@vueuse/core";
import { keys } from "./index";
export const languageChangeBus = useEventBus<string>(keys.language);

View File

@@ -3,6 +3,7 @@ import {
GlobalLanguage,
languageMap,
} from "@/stores/LanguageStore";
import { languageChangeBus } from "./bus/languageChangeBus";
const languageStore = useLanguageStore();
@@ -20,8 +21,13 @@ function changeGlobalLanguage(
language: GlobalLanguage,
locale: WritableComputedRef<string>,
) {
languageStore.setLanguage(language);
locale.value = language;
// 延迟切换先通知其他组件播放动画
languageChangeBus.emit("language changed");
setTimeout(() => {
languageStore.setLanguage(language);
locale.value = language;
}, 300);
}
export const useGlobalLanguageHook = () => ({

View File

@@ -3,6 +3,7 @@ import DatePickerDisplayCard from "@/components/card/DatePickerDisplayCard.vue";
import DevelopProgressCard from "@/components/card/DevelopProgressCard.vue";
import FooterBar from "@/components/layout/FooterBar.vue";
import NavBar from "@/components/menu/NavBar.vue";
import AnimText from "@/components/special/AnimText.vue";
import { navigateTo } from "@/utils/navigator";
const progress = ref([
@@ -46,17 +47,24 @@ const progress = ref([
<div class="hero flex-1">
<div class="hero-content text-center">
<div class="max-w-md">
<h1 class="text-5xl font-bold">{{ $t("home.welcome") }}</h1>
<p class="py-6">
{{ $t("home.intro_line1") }}<br />
<!-- <h1 class="text-5xl font-bold">{{ $t("home.welcome") }}</h1> -->
<h1 class="text-5xl font-bold">
<AnimText text="home.welcome" />
</h1>
<div class="py-6">
<!-- {{ $t("home.intro_line1") }}<br />
{{ $t("home.intro_line2") }}<br />
{{ $t("home.intro_line3") }}
</p>
{{ $t("home.intro_line3") }} -->
<AnimText text="home.intro_line1" /><br />
<AnimText text="home.intro_line2" /><br />
<AnimText text="home.intro_line3" />
</div>
<button
class="btn btn-primary"
@click="navigateTo('http://localhost:5174')"
>
{{ $t("home.read_doc") }}
<!-- {{ $t("home.read_doc") }} -->
<AnimText text="home.read_doc" />
</button>
</div>
</div>

View File

@@ -9,8 +9,9 @@
@plugin "daisyui/theme" {
name: "light";
--color-primary: blue;
--color-secondary: teal;
--color-primary: #5092d4;
--color-secondary: #bfd7f1;
--color-accent: #76b9ef;
}
/* Custom Scrollbar Styles */