mirror of
https://github.com/keven1024/015.git
synced 2026-05-26 07:08:02 +00:00
feat(front): add i18n support with language switcher in Navbar and configure locales for English and Chinese
This commit is contained in:
@@ -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>
|
||||
|
||||
9
front/i18n/locales/en.json
Normal file
9
front/i18n/locales/en.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"navbar": {
|
||||
"file": "File",
|
||||
"text": "Text"
|
||||
},
|
||||
"i18n": {
|
||||
"switchLocale": "Switch Language"
|
||||
}
|
||||
}
|
||||
9
front/i18n/locales/zh-CN.json
Normal file
9
front/i18n/locales/zh-CN.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"navbar": {
|
||||
"file": "文件",
|
||||
"text": "文本"
|
||||
},
|
||||
"i18n": {
|
||||
"switchLocale": "切换语言"
|
||||
}
|
||||
}
|
||||
@@ -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()],
|
||||
},
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user