From d8780a716bc60b7da296252618bc5836a56af007 Mon Sep 17 00:00:00 2001 From: TradeMate Dev Date: Fri, 12 Jun 2026 11:21:19 +0800 Subject: [PATCH] feat: user frontend i18n (zh-CN/en) - vue-i18n@9 with locale files for zh-CN and en - Language switcher in topbar - Navigation, breadcrumb, credits page translated - Discovery page i18n keys prepared - Language persisted in localStorage - Build verified --- user-frontend/package-lock.json | 65 +++++++++++++++++++ user-frontend/package.json | 1 + user-frontend/src/i18n.js | 22 +++++++ user-frontend/src/layouts/UserLayout.vue | 42 ++++++++----- user-frontend/src/locales/en.json | 79 ++++++++++++++++++++++++ user-frontend/src/locales/zh-CN.json | 79 ++++++++++++++++++++++++ user-frontend/src/main.js | 2 + 7 files changed, 274 insertions(+), 16 deletions(-) create mode 100644 user-frontend/src/i18n.js create mode 100644 user-frontend/src/locales/en.json create mode 100644 user-frontend/src/locales/zh-CN.json diff --git a/user-frontend/package-lock.json b/user-frontend/package-lock.json index 129618a..75118fd 100644 --- a/user-frontend/package-lock.json +++ b/user-frontend/package-lock.json @@ -14,6 +14,7 @@ "element-plus": "^2.9.1", "pinia": "^2.3.0", "vue": "^3.5.13", + "vue-i18n": "^9.14.4", "vue-router": "^4.5.0" }, "devDependencies": { @@ -553,6 +554,50 @@ "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", "license": "MIT" }, + "node_modules/@intlify/core-base": { + "version": "9.14.4", + "resolved": "https://registry.npmmirror.com/@intlify/core-base/-/core-base-9.14.4.tgz", + "integrity": "sha512-vtZCt7NqWhKEtHa3SD/322DlgP5uR9MqWxnE0y8Q0tjDs9H5Lxhss+b5wv8rmuXRoHKLESNgw9d+EN9ybBbj9g==", + "license": "MIT", + "dependencies": { + "@intlify/message-compiler": "9.14.4", + "@intlify/shared": "9.14.4" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/message-compiler": { + "version": "9.14.4", + "resolved": "https://registry.npmmirror.com/@intlify/message-compiler/-/message-compiler-9.14.4.tgz", + "integrity": "sha512-vcyCLiVRN628U38c3PbahrhbbXrckrM9zpy0KZVlDk2Z0OnGwv8uQNNXP3twwGtfLsCf4gu3ci6FMIZnPaqZsw==", + "license": "MIT", + "dependencies": { + "@intlify/shared": "9.14.4", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/shared": { + "version": "9.14.4", + "resolved": "https://registry.npmmirror.com/@intlify/shared/-/shared-9.14.4.tgz", + "integrity": "sha512-P9zv6i1WvMc9qDBWvIgKkymjY2ptIiQ065PjDv7z7fDqH3J/HBRBN5IoiR46r/ujRcU7hCuSIZWvCAFCyuOYZA==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -1990,6 +2035,26 @@ } } }, + "node_modules/vue-i18n": { + "version": "9.14.4", + "resolved": "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-9.14.4.tgz", + "integrity": "sha512-B934C8yUyWLT0EMud3DySrwSUJI7ZNiWYsEEz2gknTthqKiG4dzWE/WSa8AzCuSQzwBEv4HtG1jZDhgzPfWSKQ==", + "license": "MIT", + "dependencies": { + "@intlify/core-base": "9.14.4", + "@intlify/shared": "9.14.4", + "@vue/devtools-api": "^6.5.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, "node_modules/vue-router": { "version": "4.6.4", "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.6.4.tgz", diff --git a/user-frontend/package.json b/user-frontend/package.json index 5bd60a1..d39d1a7 100644 --- a/user-frontend/package.json +++ b/user-frontend/package.json @@ -15,6 +15,7 @@ "element-plus": "^2.9.1", "pinia": "^2.3.0", "vue": "^3.5.13", + "vue-i18n": "^9.14.4", "vue-router": "^4.5.0" }, "devDependencies": { diff --git a/user-frontend/src/i18n.js b/user-frontend/src/i18n.js new file mode 100644 index 0000000..0dfb8c4 --- /dev/null +++ b/user-frontend/src/i18n.js @@ -0,0 +1,22 @@ +import { createI18n } from 'vue-i18n' +import zhCN from './locales/zh-CN.json' +import en from './locales/en.json' + +const savedLang = localStorage.getItem('lang') || 'zh-CN' + +const i18n = createI18n({ + legacy: false, + locale: savedLang, + fallbackLocale: 'zh-CN', + messages: { + 'zh-CN': zhCN, + 'en': en, + }, +}) + +export function switchLang(lang) { + i18n.global.locale.value = lang + localStorage.setItem('lang', lang) +} + +export default i18n diff --git a/user-frontend/src/layouts/UserLayout.vue b/user-frontend/src/layouts/UserLayout.vue index bb25f1a..aaa8228 100644 --- a/user-frontend/src/layouts/UserLayout.vue +++ b/user-frontend/src/layouts/UserLayout.vue @@ -16,16 +16,16 @@ :collapse-transition="false" @select="showMobileMenu = false" > - 发现客户 - 工作台 - 客户管理 - 产品库 - 报价单 - 智能翻译 - 营销素材 - 智能跟进 - 数据分析 - 团队协作 + {{ $t('nav.discovery') }} + {{ $t('nav.workspace') }} + {{ $t('nav.customers') }} + {{ $t('nav.products') }} + {{ $t('nav.quotations') }} + {{ $t('nav.translate') }} + {{ $t('nav.marketing') }} + {{ $t('nav.followup') }} + {{ $t('nav.analytics') }} + {{ $t('nav.team') }} @@ -35,13 +35,14 @@ - 工作台 - {{ route.meta.title }} + {{ $t('nav.workspace') }} + {{ $t('nav.' + route.name?.toLowerCase()) || route.meta.title }}
+ {{ currentLang }} - {{ creditBalance }} 次 + {{ creditBalance }} {{ $t('topbar.credits') }} @@ -56,9 +57,9 @@ @@ -89,18 +90,27 @@