feat(front): add i18n support with language switcher in Navbar and configure locales for English and Chinese

This commit is contained in:
keven1024
2025-05-31 18:06:00 +08:00
parent 744dc614ce
commit be7db7d8a7
5 changed files with 115 additions and 28 deletions

View File

@@ -1,33 +1,91 @@
<template>
<div class="flex flex-row bg-white/50 backdrop-blur-xl p-2 rounded-full">
<div v-for="item in routes" :key="item.key" :class="cx('flex flex-row items-center gap-2 text-sm px-4 py-2 font-bold rounded-full relative select-none cursor-pointer',
item?.key !== type && 'hover:bg-black/5'
)" @click="() => {
router.push({
path: '/',
query: {
...route.query,
type: item.key
}
})
}">
<motion.div v-if="item?.key === type" layoutId="navbar-active"
class="absolute inset-0 rounded-full w-full h-full bg-black/10" />
<component :is="item.icon" />
{{ item.name }}
</div>
<div
class="flex flex-row bg-white/50 backdrop-blur-xl p-2 rounded-full gap-1"
>
<div
v-for="item in routes"
:key="item.key"
:class="
cx(
'flex flex-row items-center text-sm px-4 py-2 font-bold rounded-full relative select-none cursor-pointer',
!isActive(item) && 'hover:bg-black/5',
item?.name && 'gap-2',
item?.className,
)
"
@click="handleClick(item)"
>
<motion.div
v-if="isActive(item)"
layoutId="navbar-active"
class="absolute inset-0 rounded-full w-full h-full bg-black/10"
/>
<component :is="item.icon" />
<div class="hidden sm:block">{{ item.name }}</div>
</div>
</div>
</template>
<script setup lang="ts">
import { cx } from 'class-variance-authority'
import { LucideClipboardType, LucidePaperclip } from "#components"
import { motion } from "motion-v"
import { cx } from "class-variance-authority";
import { LucideClipboardType, LucidePaperclip } from "#components";
import { motion } from "motion-v";
import { LucideGlobe } from "lucide-vue-next";
import showDrawer from "@/lib/showDrawer";
import I18nSwitchDrawer from "./Drawer/I18nSwitchDrawer.vue";
const { t, ...r } = useI18n();
console.log("看看r", r);
const routes = [
{ name: '文件', key: 'file', icon: LucidePaperclip },
{ name: '文本', key: 'text', icon: LucideClipboardType }
]
const route = useRoute()
const router = useRouter()
const type = computed(() => route?.query?.type)
</script>
{
key: "about",
icon: () =>
h("img", {
class: "size-10 rounded-full border-2 border-white/50",
src: "/logo.png",
}),
onClick: () => {
router.push("/about");
},
isActive: (item: { key: string }) => route.path?.endsWith(item.key),
className: "!p-1.5",
},
{ name: t("navbar.file"), key: "file", icon: LucidePaperclip },
{ name: t("navbar.text"), key: "text", icon: LucideClipboardType },
{
key: "i18n",
icon: LucideGlobe,
onClick: () => {
showDrawer({
render: () => h(I18nSwitchDrawer),
});
},
className: "size-12 !p-1.5 justify-center items-center",
},
];
const route = useRoute();
const router = useRouter();
const type = computed(() => route?.query?.type);
const isActive = (item: {
key: string;
isActive?: (item: { key: string }) => boolean;
}) => {
const { key, isActive } = item || {};
return isActive ? isActive(item) : type.value === key;
};
const handleClick = (item: { key: string; onClick?: () => void }) => {
const { key, onClick } = item || {};
if (onClick) {
onClick();
return;
}
router.push({
path: "/",
query: {
...route.query,
type: key,
},
});
};
</script>

View File

@@ -0,0 +1,9 @@
{
"navbar": {
"file": "File",
"text": "Text"
},
"i18n": {
"switchLocale": "Switch Language"
}
}

View File

@@ -0,0 +1,9 @@
{
"navbar": {
"file": "文件",
"text": "文本"
},
"i18n": {
"switchLocale": "切换语言"
}
}

View File

@@ -5,15 +5,25 @@ export default defineNuxtConfig({
devtools: { enabled: true },
css: ["~/assets/css/main.css"],
modules: [
"@vueuse/nuxt", // '@serwist/nuxt',
// '@serwist/nuxt',
"@vueuse/nuxt",
"motion-v/nuxt",
"nuxt-lucide-icons",
"shadcn-nuxt",
"@vee-validate/nuxt",
"@pinia/nuxt",
"@nuxt/image",
"@nuxtjs/i18n",
],
// serwist: {},
i18n: {
strategy: "no_prefix",
defaultLocale: "en",
locales: [
{ code: "zh-CN", name: "中文(简体)", file: "zh-CN.json" },
{ code: "en", name: "English", file: "en.json" },
],
},
vite: {
plugins: [tailwindcss()],
},

View File

@@ -11,6 +11,7 @@
},
"dependencies": {
"@nuxt/image": "1.10.0",
"@nuxtjs/i18n": "9.5.5",
"@pinia/nuxt": "^0.11.0",
"@tailwindcss/postcss": "^4.1.3",
"@tailwindcss/vite": "^4.1.3",