diff --git a/src/hooks/useI18n.js b/src/hooks/useI18n.js new file mode 100644 index 0000000..ef0f6fa --- /dev/null +++ b/src/hooks/useI18n.js @@ -0,0 +1,16 @@ +import { useI18n as useVueI18n } from 'vue-i18n' +import { useI18nStore } from '@/stores/modules/i18n' + +export function useI18n() { + const { t, locale, availableLocales } = useVueI18n() + const i18nStore = useI18nStore() + + return { + t, + locale, + availableLocales, + setLocale: i18nStore.setLocale, + currentLocale: i18nStore.currentLocale, + localeLabel: i18nStore.localeLabel + } +} diff --git a/src/i18n/index.js b/src/i18n/index.js new file mode 100644 index 0000000..686b68a --- /dev/null +++ b/src/i18n/index.js @@ -0,0 +1,15 @@ +import { createI18n } from 'vue-i18n' +import zh from './locales/zh-CN' +import en from './locales/en-US' + +const i18n = createI18n({ + legacy: false, + locale: 'zh-CN', + fallbackLocale: 'en-US', + messages: { + 'zh-CN': zh, + 'en-US': en + } +}) + +export default i18n diff --git a/src/i18n/locales/en-US.js b/src/i18n/locales/en-US.js new file mode 100644 index 0000000..0a1ef77 --- /dev/null +++ b/src/i18n/locales/en-US.js @@ -0,0 +1,103 @@ +export default { + common: { + welcome: 'Welcome', + login: 'Login', + logout: 'Logout', + register: 'Register', + username: 'Username', + password: 'Password', + confirmPassword: 'Confirm Password', + email: 'Email', + phone: 'Phone', + rememberMe: 'Remember Me', + forgotPassword: 'Forgot Password?', + submit: 'Submit', + cancel: 'Cancel', + save: 'Save', + edit: 'Edit', + delete: 'Delete', + add: 'Add', + search: 'Search', + reset: 'Reset', + confirm: 'Confirm', + back: 'Back', + next: 'Next', + previous: 'Previous', + refresh: 'Refresh', + export: 'Export', + import: 'Import', + download: 'Download', + upload: 'Upload', + view: 'View', + detail: 'Detail', + settings: 'Settings', + profile: 'Profile', + language: 'Language', + theme: 'Theme', + dark: 'Dark', + light: 'Light', + loading: 'Loading...', + noData: 'No Data', + success: 'Operation Successful', + error: 'Operation Failed', + warning: 'Warning', + info: 'Info', + confirmDelete: 'Are you sure you want to delete?', + confirmLogout: 'Are you sure you want to logout?', + required: 'This field is required', + operation: 'Operation', + time: 'Time', + status: 'Status', + enabled: 'Enabled', + disabled: 'Disabled', + yes: 'Yes', + no: 'No' + }, + menu: { + dashboard: 'Dashboard', + userManagement: 'User Management', + roleManagement: 'Role Management', + permissionManagement: 'Permission Management', + systemSettings: 'System Settings', + logManagement: 'Log Management' + }, + login: { + title: 'User Login', + subtitle: 'Welcome back, please login to your account', + loginButton: 'Login', + loginSuccess: 'Login Successful', + loginFailed: 'Login Failed', + usernamePlaceholder: 'Please enter username', + passwordPlaceholder: 'Please enter password', + noAccount: "Don't have an account?", + registerNow: 'Register Now' + }, + layout: { + toggleSidebar: 'Toggle Sidebar', + collapse: 'Collapse', + expand: 'Expand', + logout: 'Logout' + }, + table: { + total: 'Total {total} items', + selected: '{selected} items selected', + actions: 'Actions', + noData: 'No Data', + sort: 'Sort', + filter: 'Filter' + }, + pagination: { + goTo: 'Go to', + page: 'Page', + total: 'Total {total} items', + itemsPerPage: '{size} items per page' + }, + form: { + required: 'This field is required', + invalidEmail: 'Please enter a valid email address', + invalidPhone: 'Please enter a valid phone number', + passwordMismatch: 'Passwords do not match', + minLength: 'Minimum {min} characters required', + maxLength: 'Maximum {max} characters allowed' + } +} diff --git a/src/i18n/locales/zh-CN.js b/src/i18n/locales/zh-CN.js new file mode 100644 index 0000000..c86871d --- /dev/null +++ b/src/i18n/locales/zh-CN.js @@ -0,0 +1,103 @@ +export default { + common: { + welcome: '欢迎使用', + login: '登录', + logout: '退出登录', + register: '注册', + username: '用户名', + password: '密码', + confirmPassword: '确认密码', + email: '邮箱', + phone: '手机号', + rememberMe: '记住我', + forgotPassword: '忘记密码?', + submit: '提交', + cancel: '取消', + save: '保存', + edit: '编辑', + delete: '删除', + add: '添加', + search: '搜索', + reset: '重置', + confirm: '确认', + back: '返回', + next: '下一步', + previous: '上一步', + refresh: '刷新', + export: '导出', + import: '导入', + download: '下载', + upload: '上传', + view: '查看', + detail: '详情', + settings: '设置', + profile: '个人资料', + language: '语言', + theme: '主题', + dark: '暗色', + light: '亮色', + loading: '加载中...', + noData: '暂无数据', + success: '操作成功', + error: '操作失败', + warning: '警告', + info: '提示', + confirmDelete: '确定要删除吗?', + confirmLogout: '确定要退出登录吗?', + required: '此项为必填项', + operation: '操作', + time: '时间', + status: '状态', + enabled: '启用', + disabled: '禁用', + yes: '是', + no: '否' + }, + menu: { + dashboard: '仪表板', + userManagement: '用户管理', + roleManagement: '角色管理', + permissionManagement: '权限管理', + systemSettings: '系统设置', + logManagement: '日志管理' + }, + login: { + title: '用户登录', + subtitle: '欢迎回来,请登录您的账户', + loginButton: '登录', + loginSuccess: '登录成功', + loginFailed: '登录失败', + usernamePlaceholder: '请输入用户名', + passwordPlaceholder: '请输入密码', + noAccount: '还没有账户?', + registerNow: '立即注册' + }, + layout: { + toggleSidebar: '切换侧边栏', + collapse: '折叠', + expand: '展开', + logout: '退出登录' + }, + table: { + total: '共 {total} 条', + selected: '已选择 {selected} 项', + actions: '操作', + noData: '暂无数据', + sort: '排序', + filter: '筛选' + }, + pagination: { + goTo: '前往', + page: '页', + total: '共 {total} 条', + itemsPerPage: '每页 {size} 条' + }, + form: { + required: '此项为必填项', + invalidEmail: '请输入有效的邮箱地址', + invalidPhone: '请输入有效的手机号', + passwordMismatch: '两次输入的密码不一致', + minLength: '最少需要 {min} 个字符', + maxLength: '最多允许 {max} 个字符' + } +} diff --git a/src/layouts/components/LanguageSwitcher.vue b/src/layouts/components/LanguageSwitcher.vue new file mode 100644 index 0000000..698ad93 --- /dev/null +++ b/src/layouts/components/LanguageSwitcher.vue @@ -0,0 +1,91 @@ + + + + + + {{ i18nStore.localeLabel }} + + + + + + + {{ locale.label }} + + + + + + diff --git a/src/main.js b/src/main.js index c934821..1082a3a 100644 --- a/src/main.js +++ b/src/main.js @@ -3,10 +3,17 @@ import { createApp } from 'vue' import App from './App.vue' import router from './router' import pinia from './stores' +import i18n from './i18n' +import { useI18nStore } from './stores/modules/i18n' const app = createApp(App) app.use(router) app.use(pinia) +app.use(i18n) + +// 初始化 i18n store,从 localStorage 读取保存的语言设置 +const i18nStore = useI18nStore() +i18nStore.initLocale() app.mount('#app') diff --git a/src/pages/login/index.vue b/src/pages/login/index.vue index 5160d2c..6fdef84 100644 --- a/src/pages/login/index.vue +++ b/src/pages/login/index.vue @@ -1,5 +1,9 @@ + + + - 用户登录 - 欢迎回来,请登录您的账户 + {{ t('login.title') }} + {{ t('login.subtitle') }} - 用户名 - + {{ t('common.username') }} + - 密码 - + {{ t('common.password') }} + - 记住我 + {{ t('common.rememberMe') }} - 忘记密码? + {{ t('common.forgotPassword') }} - 登录 - 登录中... + {{ t('login.loginButton') }} + {{ t('common.loading') }} @@ -73,6 +82,13 @@ const handleLogin = () => { overflow: hidden; } +.language-switcher-wrapper { + position: absolute; + top: 20px; + right: 20px; + z-index: 10; +} + /* 网格背景 */ .login-container::before { content: ''; diff --git a/src/stores/modules/i18n.js b/src/stores/modules/i18n.js new file mode 100644 index 0000000..41e2a8d --- /dev/null +++ b/src/stores/modules/i18n.js @@ -0,0 +1,34 @@ +import { defineStore } from 'pinia' +import i18n from '@/i18n' + +export const useI18nStore = defineStore('i18n', { + state: () => ({ + currentLocale: 'zh-CN', + availableLocales: [ + { label: '简体中文', value: 'zh-CN' }, + { label: 'English', value: 'en-US' } + ] + }), + + getters: { + localeLabel: (state) => { + const locale = state.availableLocales.find((item) => item.value === state.currentLocale) + return locale ? locale.label : '' + } + }, + + actions: { + setLocale(locale) { + this.currentLocale = locale + i18n.global.locale.value = locale + localStorage.setItem('locale', locale) + }, + + initLocale() { + const savedLocale = localStorage.getItem('locale') + if (savedLocale && this.availableLocales.some((item) => item.value === savedLocale)) { + this.setLocale(savedLocale) + } + } + } +}) diff --git a/vite.config.js b/vite.config.js index 4217010..f7317b4 100644 --- a/vite.config.js +++ b/vite.config.js @@ -6,13 +6,13 @@ import vueDevTools from 'vite-plugin-vue-devtools' // https://vite.dev/config/ export default defineConfig({ - plugins: [ - vue(), - vueDevTools(), - ], - resolve: { - alias: { - '@': fileURLToPath(new URL('./src', import.meta.url)) - }, - }, + plugins: [ + vue(), + vueDevTools(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + }, + }, })
欢迎回来,请登录您的账户
{{ t('login.subtitle') }}