From 07a12141276172b8f52faeb9b60cf6967088911b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8?= Date: Sat, 9 May 2026 15:30:10 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=BF=E7=94=A8il8n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/i18n/index.ts | 18 ++++ src/i18n/locales/en-US/index.ts | 101 ++++++++++++++++++ src/i18n/locales/zh-CN/index.ts | 101 ++++++++++++++++++ src/main.ts | 6 ++ src/stores/modules/language.ts | 7 +- src/views/agent/user/default.vue | 65 +++++++----- src/views/profile/personalCenter/index.vue | 113 +++++++++++---------- 7 files changed, 330 insertions(+), 81 deletions(-) create mode 100644 src/i18n/index.ts create mode 100644 src/i18n/locales/en-US/index.ts create mode 100644 src/i18n/locales/zh-CN/index.ts diff --git a/src/i18n/index.ts b/src/i18n/index.ts new file mode 100644 index 0000000..a330980 --- /dev/null +++ b/src/i18n/index.ts @@ -0,0 +1,18 @@ +import { createI18n } from 'vue-i18n' +import zhCN from './locales/zh-CN/index' +import enUS from './locales/en-US/index' + +export type { LanguageType } from '@/stores/modules/language' + +// 创建 i18n 实例 +const i18n = createI18n({ + legacy: false, // 使用 Composition API 模式 + locale: localStorage.getItem('lang') || 'zh-CN', // 默认语言 + fallbackLocale: 'zh-CN', // 回退语言 + messages: { + 'zh-CN': zhCN, + 'en-US': enUS + } +}) + +export default i18n diff --git a/src/i18n/locales/en-US/index.ts b/src/i18n/locales/en-US/index.ts new file mode 100644 index 0000000..f6ba2ba --- /dev/null +++ b/src/i18n/locales/en-US/index.ts @@ -0,0 +1,101 @@ +// English translation file +export default { + // Common + common: { + loading: 'Loading...', + submit: 'Submit', + cancel: 'Cancel', + confirm: 'Confirm', + edit: 'Edit', + delete: 'Delete', + save: 'Save', + close: 'Close', + search: 'Search', + reset: 'Reset', + pleaseInput: 'Please enter', + pleaseSelect: 'Please select', + operation: 'Operation', + status: 'Status', + createTime: 'Create Time', + updateTime: 'Update Time', + remark: 'Remark', + success: 'Operation successful', + error: 'Operation failed', + warning: 'Warning', + info: 'Info' + }, + // Personal Center + personalCenter: { + pageTitle: 'Account Information', + username: 'Username', + email: 'Email', + mobile: 'Mobile', + password: 'Password', + language: 'Language', + languageDesc: 'Select your preferred communication language', + lastLogin: 'Last Login', + notSet: 'Not set', + notBound: 'Not bound', + bound: 'Bound', + goToBind: 'Go to bind', + bind: 'Bind', + modify: 'Modify', + bindEmail: 'Bind Email', + bindMobile: 'Bind Mobile', + rebindMobile: 'Rebind Mobile', + modifyUsername: 'Modify Username', + modifyPassword: 'Modify Password', + verifyMethod: 'Verification Method', + verifyAccount: 'Verification Account', + mobileVerify: 'Mobile Verification', + emailVerify: 'Email Verification', + newPassword: 'New Password', + confirmPassword: 'Confirm Password', + passwordPlaceholder: '6-12 characters, including uppercase, lowercase and special characters', + confirmPasswordPlaceholder: 'Please enter new password again', + // Validation messages + pleaseInputEmail: 'Please enter email', + emailFormatError: 'Email format is incorrect', + pleaseInputMobile: 'Please enter mobile number', + mobileFormatError: 'Mobile number format is incorrect', + pleaseInputUsername: 'Please enter username', + usernameLengthError: 'Username length must be 2-20 characters', + pleaseSelectVerifyMethod: 'Please select verification method', + pleaseInputNewPassword: 'Please enter new password', + passwordLengthError: 'Length must be 6-12 characters', + passwordComplexityError: 'Must include uppercase, lowercase and special characters', + pleaseConfirmNewPassword: 'Please confirm new password', + passwordMismatchError: 'Passwords do not match', + // Message prompts + pleaseBindMobileOrEmail: 'Please bind mobile or email first', + pleaseInputVerifyAccount: 'Please bind verification account first', + pleaseInputReceiverAccount: 'Please enter the account to receive verification code', + getUserInfoFailed: 'Failed to get user information', + languageChangeFailed: 'Failed to change language' + }, + // Agent User Detail + agentUser: { + phone: 'Phone', + accountBalance: 'Account Balance', + depositAmount: 'Deposit Amount', + email: 'Email', + registerTime: 'Register Time', + historyTradeAmount: 'History Trade Amount', + tradeAccount: 'Trade Account', + accountName: 'Account Name', + balance: 'Balance', + tradeLeverage: 'Trade Leverage', + historyTradeVolume: 'History Trade Volume', + addTime: 'Add Time', + loadDetailFailed: 'Failed to load detail', + operateAccount: 'Operate Account', + role: { + 1: 'Platform', + 2: 'Contractor', + 3: 'Special Market Maker', + 4: 'Ordinary Market Maker', + 5: 'Agent', + 6: 'User' + } + } +} diff --git a/src/i18n/locales/zh-CN/index.ts b/src/i18n/locales/zh-CN/index.ts new file mode 100644 index 0000000..c930a96 --- /dev/null +++ b/src/i18n/locales/zh-CN/index.ts @@ -0,0 +1,101 @@ +// 中文翻译文件 +export default { + // 通用 + common: { + loading: '加载中...', + submit: '提交', + cancel: '取消', + confirm: '确认', + edit: '修改', + delete: '删除', + save: '保存', + close: '关闭', + search: '搜索', + reset: '重置', + pleaseInput: '请输入', + pleaseSelect: '请选择', + operation: '操作', + status: '状态', + createTime: '创建时间', + updateTime: '更新时间', + remark: '备注', + success: '操作成功', + error: '操作失败', + warning: '警告', + info: '提示' + }, + // 个人中心 + personalCenter: { + pageTitle: '账户信息', + username: '用户名', + email: '邮箱', + mobile: '手机号', + password: '密码', + language: '语言', + languageDesc: '选择您偏好的通讯语言', + lastLogin: '最后登录', + notSet: '未设置', + notBound: '未绑定', + bound: '已绑定', + goToBind: '去绑定', + bind: '绑定', + modify: '修改', + bindEmail: '绑定邮箱', + bindMobile: '绑定手机号', + rebindMobile: '重新绑定手机号', + modifyUsername: '修改用户名', + modifyPassword: '修改密码', + verifyMethod: '验证方式', + verifyAccount: '验证账号', + mobileVerify: '手机验证', + emailVerify: '邮箱验证', + newPassword: '新密码', + confirmPassword: '确认密码', + passwordPlaceholder: '6-12位,含大小写+特殊字符', + confirmPasswordPlaceholder: '请再次输入新密码', + // 验证规则提示 + pleaseInputEmail: '请输入邮箱', + emailFormatError: '邮箱格式不正确', + pleaseInputMobile: '请输入手机号', + mobileFormatError: '手机号格式不正确', + pleaseInputUsername: '请输入用户名', + usernameLengthError: '用户名长度 2-20 位', + pleaseSelectVerifyMethod: '请选择验证方式', + pleaseInputNewPassword: '请输入新密码', + passwordLengthError: '长度 6-12 位', + passwordComplexityError: '必须包含大小写+特殊字符', + pleaseConfirmNewPassword: '请确认新密码', + passwordMismatchError: '两次密码不一致', + // 消息提示 + pleaseBindMobileOrEmail: '请先绑定手机或邮箱', + pleaseInputVerifyAccount: '请先绑定验证账号', + pleaseInputReceiverAccount: '请输入接收验证码的账号', + getUserInfoFailed: '获取用户信息失败', + languageChangeFailed: '语言切换失败' + }, + // 代理用户详情 + agentUser: { + phone: '手机号', + accountBalance: '账户余额', + depositAmount: '存款金额', + email: '邮箱', + registerTime: '注册时间', + historyTradeAmount: '历史交易金额', + tradeAccount: '交易账号', + accountName: '账户名称', + balance: '余额', + tradeLeverage: '交易杠杆', + historyTradeVolume: '历史交易量', + addTime: '添加时间', + loadDetailFailed: '加载详情失败', + operateAccount: '操作账户', + role: { + 1: '平台', + 2: '承包商', + 3: '特殊做市商', + 4: '普通做市商', + 5: '代理', + 6: '用户' + } + } +} diff --git a/src/main.ts b/src/main.ts index 1e4f87c..afa257f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -5,12 +5,14 @@ import 'element-plus/dist/index.css' //语言配置 import ElementPlus from 'element-plus' import zhCn from 'element-plus/dist/locale/zh-cn.mjs' +import en from 'element-plus/dist/locale/en.mjs' import { createApp } from 'vue' import { createPinia } from 'pinia' import App from './App.vue' import router from './router' +import i18n from './i18n' import {setupAuthDirective} from './directives/auth' import { setStorage } from '@/utils/storage' import '@imengyu/vue3-context-menu/lib/vue3-context-menu.css' @@ -22,9 +24,13 @@ const app = createApp(App) setupAuthDirective(app) app.use(createPinia()) app.use(router) +app.use(i18n) app.use(ContextMenu) app.use(ElementPlus, { locale: zhCn, }) app.mount('#app') + +// 导出 app 实例以便在其他地方使用 +export default app diff --git a/src/stores/modules/language.ts b/src/stores/modules/language.ts index af9fc6e..5e8085b 100644 --- a/src/stores/modules/language.ts +++ b/src/stores/modules/language.ts @@ -14,16 +14,11 @@ export const useLanguageStore = defineStore('language', () => { if (!getStorage('lang')) { setStorage('lang', initLang) } - // const setHtmlLang = (currentLang: LanguageType) => { - // document.documentElement.lang = langMap[currentLang] - // } - - // setHtmlLang(lang.value) const changeLang = (newLang: LanguageType) => { lang.value = newLang setStorage('lang', newLang) - // setHtmlLang(newLang) + // i18n 的 locale 会通过 watch 自动同步 } return { lang, changeLang } diff --git a/src/views/agent/user/default.vue b/src/views/agent/user/default.vue index 40088cb..13f3be6 100644 --- a/src/views/agent/user/default.vue +++ b/src/views/agent/user/default.vue @@ -23,7 +23,7 @@ - 手机号 + {{ t('agentUser.phone') }}
{{ userInfo.phone || '-' }}
@@ -32,7 +32,7 @@ - 账户余额 + {{ t('agentUser.accountBalance') }}
@@ -43,7 +43,7 @@ - 存款金额 + {{ t('agentUser.depositAmount') }}
@@ -54,7 +54,7 @@ - 邮箱 + {{ t('agentUser.email') }}
{{ userInfo.email || '-' }}
@@ -63,7 +63,7 @@ - 注册时间 + {{ t('agentUser.registerTime') }}
{{ userInfo.registerTime || '-' }}
@@ -72,7 +72,7 @@ - 历史交易金额 + {{ t('agentUser.historyTradeAmount') }}
@@ -98,9 +98,11 @@ defineOptions({ }) import { ref, watch, computed } from 'vue' import { ElAvatar, ElIcon, ElDrawer, ElButton, ElMessage } from 'element-plus' +import { useI18n } from 'vue-i18n' import { UserFilled, Phone, Message, Money, Wallet, Clock, CreditCard } from '@element-plus/icons-vue' import CustomerListTable from '@/components/common/Table.vue' import { getCustomerDetailApi } from '@/api/modules/agent/customerDetail' +import { useLanguageStore } from '@/stores/modules/language' import dayjs from 'dayjs' import AnimatedNumber from './AnimatedNumber.vue' @@ -115,14 +117,18 @@ import type { TableColumn } from '@/api/types/agent' -const roleMap: Record = { - 1: '平台', - 2: '承包商', - 3: '特殊做市商', - 4: '普通做市商', - 5: '代理', - 6: '用户', -} +const { t, locale } = useI18n() +const languageStore = useLanguageStore() + +// 使用 computed 动态生成角色映射,支持语言切换 +const roleMap = computed>(() => ({ + 1: t('agentUser.role.1'), + 2: t('agentUser.role.2'), + 3: t('agentUser.role.3'), + 4: t('agentUser.role.4'), + 5: t('agentUser.role.5'), + 6: t('agentUser.role.6'), +})) // 接收父组件传值 const props = defineProps<{ @@ -165,13 +171,15 @@ const userInfo = ref({ // 表格 const tableData = ref([]) -const tableColumnsOptions = ref([ - { label: '交易账号', prop: 'tradeAccount' }, - { label: '账户名称', prop: 'accountName' }, - { label: '余额', prop: 'balance', sortable: true }, - { label: '交易杠杆', prop: 'leverage' }, - { label: '历史交易量', prop: 'tradeVolume' }, - { label: '添加时间', prop: 'addTime', width: 180 } + +// 动态生成表格列配置,支持语言切换 +const tableColumnsOptions = computed(() => [ + { label: t('agentUser.tradeAccount'), prop: 'tradeAccount' }, + { label: t('agentUser.accountName'), prop: 'accountName' }, + { label: t('agentUser.balance'), prop: 'balance', sortable: true }, + { label: t('agentUser.tradeLeverage'), prop: 'leverage' }, + { label: t('agentUser.historyTradeVolume'), prop: 'tradeVolume' }, + { label: t('agentUser.addTime'), prop: 'addTime', width: 180 } ]) @@ -187,7 +195,7 @@ const loadDetailData = async (id: string | number) => { userInfo.value = { name: user.email || user.mobile || '-', id: user.id, - role: roleMap[user.role_id] || '-', + role: roleMap.value[user.role_id] || '-', phone: user.mobile || '-', email: user.email || '-', balance: Number(user.capital_amount) || 0, @@ -207,7 +215,7 @@ const loadDetailData = async (id: string | number) => { })) } catch (err) { console.error('加载详情失败:', err); - ElMessage.error('加载详情失败') + ElMessage.error(t('agentUser.loadDetailFailed')) } finally { loading.value = false tableLoading.value = false @@ -224,9 +232,18 @@ watch( { immediate: true } ) +// 监听语言切换,同步更新 i18n 的 locale +watch( + () => languageStore.lang, + (newLang) => { + locale.value = newLang + }, + { immediate: true } +) + // 账户操作 const handleAccount = (row: TableDataRow) => { - ElMessage.success('操作账户:' + row.tradeAccount) + ElMessage.success(t('agentUser.operateAccount') + ':' + row.tradeAccount) } diff --git a/src/views/profile/personalCenter/index.vue b/src/views/profile/personalCenter/index.vue index 623ecf0..9e36fa2 100644 --- a/src/views/profile/personalCenter/index.vue +++ b/src/views/profile/personalCenter/index.vue @@ -1,7 +1,7 @@