feat(i18n): add offline auto-translate plugin with 200+ common medical terms dictionary

This commit is contained in:
2026-06-25 16:02:35 +08:00
parent d8c5269ab9
commit 05a59f2884
3 changed files with 177 additions and 2 deletions

View File

@@ -0,0 +1,168 @@
/**
* 离线自动翻译插件
* 当 $t() 找不到翻译时,自动从预设字典中查找翻译
* 开发模式下标记未翻译文本
*/
import Cookies from 'js-cookie'
// 预设翻译字典 - 中文到各语言
const translationDict = {
'en': {
// 通用操作
'新增': 'Add', '编辑': 'Edit', '删除': 'Delete', '查询': 'Search', '重置': 'Reset',
'确定': 'Confirm', '取消': 'Cancel', '保存': 'Save', '提交': 'Submit', '关闭': 'Close',
'导出': 'Export', '导入': 'Import', '刷新': 'Refresh', '打印': 'Print', '复制': 'Copy',
'返回': 'Back', '下一步': 'Next', '上一步': 'Previous', '完成': 'Finish',
'查看': 'View', '详情': 'Detail', '操作': 'Action', '状态': 'Status',
'启用': 'Enabled', '停用': 'Disabled', '正常': 'Normal', '异常': 'Abnormal',
'是': 'Yes', '否': 'No', '有': 'Yes', '无': 'None',
'成功': 'Success', '失败': 'Failed', '警告': 'Warning', '提示': 'Tip', '错误': 'Error',
'加载中': 'Loading', '暂无数据': 'No Data', '请稍候': 'Please wait',
'请选择': 'Please select', '请输入': 'Please enter', '必填': 'Required',
'确认删除': 'Confirm Delete', '确认操作': 'Confirm Action',
'操作成功': 'Operation successful', '操作失败': 'Operation failed',
'保存成功': 'Saved successfully', '保存失败': 'Save failed',
'删除成功': 'Deleted successfully', '删除失败': 'Delete failed',
'新增成功': 'Added successfully', '新增失败': 'Add failed',
'修改成功': 'Modified successfully', '修改失败': 'Modification failed',
'提交成功': 'Submitted successfully', '提交失败': 'Submit failed',
'导出成功': 'Exported successfully', '导出失败': 'Export failed',
'导入成功': 'Imported successfully', '导入失败': 'Import failed',
'查询成功': 'Query successful', '查询失败': 'Query failed',
'登录成功': 'Login successful', '登录失败': 'Login failed',
'退出成功': 'Logged out', '注册成功': 'Registration successful',
// 表格通用
'序号': 'No.', '名称': 'Name', '编码': 'Code', '类型': 'Type', '级别': 'Level',
'描述': 'Description', '备注': 'Remark', '创建时间': 'Create Time', '更新时间': 'Update Time',
'创建人': 'Creator', '更新人': 'Updater', '排序': 'Sort', '显示': 'Display',
'隐藏': 'Hidden', '可见': 'Visible', '全部': 'All', '其他': 'Other',
'开始日期': 'Start Date', '结束日期': 'End Date', '开始时间': 'Start Time', '结束时间': 'End Time',
'日期': 'Date', '时间': 'Time', '年': 'Year', '月': 'Month', '日': 'Day',
'今天': 'Today', '昨天': 'Yesterday', '本周': 'This Week', '本月': 'This Month',
// 医疗通用
'患者': 'Patient', '患者姓名': 'Patient Name', '患者ID': 'Patient ID',
'性别': 'Gender', '男': 'Male', '女': 'Female', '年龄': 'Age',
'科室': 'Department', '医生': 'Doctor', '护士': 'Nurse',
'诊断': 'Diagnosis', '处方': 'Prescription', '医嘱': 'Order',
'药品': 'Drug', '剂量': 'Dosage', '用法': 'Usage', '频次': 'Frequency',
'住院号': 'Admission No.', '门诊号': 'Outpatient No.', '就诊卡号': 'Visit Card No.',
'身份证号': 'ID Card No.', '手机号': 'Phone No.', '地址': 'Address',
'入院日期': 'Admission Date', '出院日期': 'Discharge Date',
'主治医生': 'Attending Doctor', '责任护士': 'Responsible Nurse',
'费用': 'Fee', '金额': 'Amount', '单价': 'Unit Price', '数量': 'Quantity',
'合计': 'Total', '应收': 'Receivable', '实收': 'Actual', '找零': 'Change',
'支付方式': 'Payment Method', '现金': 'Cash', '微信': 'WeChat', '支付宝': 'Alipay',
'医保': 'Medical Insurance', '自费': 'Self Pay',
'已支付': 'Paid', '未支付': 'Unpaid', '已退款': 'Refunded',
'待处理': 'Pending', '处理中': 'Processing', '已完成': 'Completed', '已取消': 'Cancelled',
'已确认': 'Confirmed', '已审核': 'Reviewed', '已批准': 'Approved', '已拒绝': 'Rejected',
'待审核': 'Pending Review', '待批准': 'Pending Approval',
// 药房
'西药': 'Western Medicine', '中成药': 'Chinese Patent Medicine', '中草药': 'Chinese Herbal Medicine',
'库存': 'Stock', '入库': 'Inbound', '出库': 'Outbound', '盘点': 'Stocktaking',
'效期': 'Expiry Date', '批号': 'Batch No.', '规格': 'Specification', '单位': 'Unit',
'生产厂家': 'Manufacturer', '供应商': 'Supplier', '批准文号': 'Approval No.',
// 手术
'手术': 'Surgery', '手术名称': 'Surgery Name', '手术时间': 'Surgery Time',
'主刀医生': 'Surgeon', '麻醉医生': 'Anesthesiologist', '麻醉方式': 'Anesthesia Type',
'手术室': 'Operating Room', '手术台': 'Operating Table',
// 检验检查
'检验': 'Lab Test', '检查': 'Examination', '标本': 'Specimen',
'结果': 'Result', '参考范围': 'Reference Range', '正常值': 'Normal Value',
'报告': 'Report', '申请': 'Application',
// 病历
'病历': 'Medical Record', '病案': 'Case Record', '病程': 'Progress Notes',
'入院记录': 'Admission Record', '出院记录': 'Discharge Record',
'首次病程': 'First Progress Note', '日常病程': 'Daily Progress Note',
'手术记录': 'Surgery Record', '护理记录': 'Nursing Record',
// 系统
'系统': 'System', '设置': 'Settings', '配置': 'Configuration',
'权限': 'Permission', '角色': 'Role', '菜单': 'Menu', '字典': 'Dictionary',
'用户': 'User', '密码': 'Password', '验证码': 'Captcha',
'登录': 'Login', '退出': 'Logout', '注册': 'Register',
'首页': 'Home', '仪表盘': 'Dashboard', '个人中心': 'Profile',
'帮助': 'Help', '关于': 'About', '版本': 'Version',
'在线': 'Online', '离线': 'Offline', '已连接': 'Connected', '未连接': 'Disconnected',
'元': 'Yuan', '次': 'Times', '天': 'Days', '小时': 'Hours', '分钟': 'Minutes',
'条': 'Items', '个': 'Items', '项': 'Items', '次/分': 'Times/min',
},
'vi': {
'新增': 'Thêm', '编辑': 'Sửa', '删除': 'Xóa', '查询': 'Tìm kiếm', '重置': 'Đặt lại',
'确定': 'Xác nhận', '取消': 'Hủy', '保存': 'Lưu', '提交': 'Gửi', '关闭': 'Đóng',
'导出': 'Xuất', '导入': 'Nhập', '刷新': 'Làm mới', '打印': 'In', '复制': 'Sao chép',
'返回': 'Quay lại', '下一步': 'Tiếp theo', '上一步': 'Trước đó', '完成': 'Hoàn thành',
'查看': 'Xem', '详情': 'Chi tiết', '操作': 'Thao tác', '状态': 'Trạng thái',
'启用': 'Kích hoạt', '停用': 'Vô hiệu', '正常': 'Bình thường', '异常': 'Bất thường',
'是': 'Có', '否': 'Không', '有': 'Có', '无': 'Không',
'成功': 'Thành công', '失败': 'Thất bại', '警告': 'Cảnh báo', '提示': 'Thông báo', '错误': 'Lỗi',
'加载中': 'Đang tải', '暂无数据': 'Không có dữ liệu', '请稍候': 'Vui lòng đợi',
'请选择': 'Vui lòng chọn', '请输入': 'Vui lòng nhập', '必填': 'Bắt buộc',
'确认删除': 'Xác nhận xóa', '确认操作': 'Xác nhận thao tác',
'操作成功': 'Thao tác thành công', '操作失败': 'Thao tác thất bại',
'保存成功': 'Lưu thành công', '保存失败': 'Lưu thất bại',
'删除成功': 'Xóa thành công', '删除失败': 'Xóa thất bại',
'新增成功': 'Thêm thành công', '新增失败': 'Thêm thất bại',
'修改成功': 'Sửa thành công', '修改失败': 'Sửa thất bại',
'患者': 'Bệnh nhân', '患者姓名': 'Tên BN', '患者ID': 'Mã BN',
'性别': 'Giới tính', '男': 'Nam', '女': 'Nữ', '年龄': 'Tuổi',
'科室': 'Khoa', '医生': 'Bác sĩ', '护士': 'Điều dưỡng',
'诊断': 'Chẩn đoán', '处方': 'Đơn thuốc', '医嘱': 'Y lệnh',
'药品': 'Thuốc', '剂量': 'Liều lượng', '用法': 'Cách dùng', '频次': 'Tần suất',
'费用': 'Viện phí', '金额': 'Số tiền', '合计': 'Tổng cộng',
'待处理': 'Chờ xử lý', '处理中': 'Đang xử lý', '已完成': 'Hoàn thành', '已取消': 'Đã hủy',
'系统': 'Hệ thống', '设置': 'Cài đặt', '权限': 'Phân quyền', '角色': 'Vai trò',
'用户': 'Người dùng', '密码': 'Mật khẩu', '登录': 'Đăng nhập', '退出': 'Đăng xuất',
'首页': 'Trang chủ', '仪表盘': 'Bảng điều khiển',
'元': 'đồng', '次': 'lần', '天': 'ngày', 'giờ': 'giờ', 'phút': 'phút',
}
}
// 当前语言
function getCurrentLang() {
return Cookies.get('lang') || localStorage.getItem('lang') || 'zh-CN'
}
// 自动翻译函数
export function autoTranslate(chineseText) {
const lang = getCurrentLang()
if (lang === 'zh-CN') return chineseText
const langKey = lang === 'en' ? 'en' : lang === 'vi' ? 'vi' : null
if (!langKey) return chineseText
const dict = translationDict[langKey]
if (!dict) return chineseText
// 精确匹配
if (dict[chineseText]) return dict[chineseText]
// 尝试组合翻译(处理 "XX管理" 这类组合词)
let result = chineseText
for (const [zh, en] of Object.entries(dict)) {
result = result.replace(new RegExp(zh, 'g'), en)
}
return result
}
// Vue 插件安装
export const AutoTranslatePlugin = {
install(app) {
// 在开发模式下,给未翻译的文本添加标记
if (import.meta.env.DEV) {
const originalT = app.config.globalProperties.$t
if (originalT) {
app.config.globalProperties.$t = function(key, ...args) {
const result = originalT.call(this, key, ...args)
// 如果结果等于 key说明没找到翻译尝试自动翻译
if (result === key && /[\u4e00-\u9fff]/.test(key)) {
return autoTranslate(key)
}
return result
}
}
}
}
}
export default { autoTranslate, AutoTranslatePlugin }

View File

@@ -1,6 +1,6 @@
import { createI18n } from 'vue-i18n'
import Cookies from 'js-cookie'
import { ElMessageBox } from 'element-plus'
import { autoTranslate } from './autoTranslate'
const messages = {
'zh-CN': {},
@@ -64,5 +64,10 @@ export const changeLocale = async (newLocale) => {
export const t = (key, ...params) => {
if (!i18nInstance) return key
const { t: tFunc } = i18nInstance.global
return tFunc(key, ...params)
const result = tFunc(key, ...params)
// 如果翻译结果等于 key未找到翻译尝试自动翻译
if (result === key && /[\u4e00-\u9fff]/.test(key)) {
return autoTranslate(key)
}
return result
}

View File

@@ -84,6 +84,7 @@ console.error = (...args) => {
async function bootstrap() {
const {initI18n} = await import('@/i18n');
const {AutoTranslatePlugin} = await import('@/i18n/autoTranslate');
const i18n = await initI18n();
const app = createApp(App);
@@ -167,6 +168,7 @@ async function bootstrap() {
});
app.use(i18n);
app.use(AutoTranslatePlugin);
app.mount('#app');
}
bootstrap();