feat: 前端新增中英文多语言支持
- 引入 vue-i18n,新增 locales/messages.ts 以中英对照方式维护词条 - 新增 LocaleSwitch 组件,在登录/注册页与主布局顶部栏提供切换入口 - 语言持久化到 localStorage 并同步 <html lang>,Naive UI 组件语言联动 - 各视图、表格列、弹窗与提示文案全部接入国际化 - 修复 confirmImport 缺失的 tagIds 类型定义
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
// 国际化入口:由对照消息构建各语言包,维护当前语言、持久化与 <html lang> 同步
|
||||
import { createI18n } from 'vue-i18n'
|
||||
import messages from './messages'
|
||||
|
||||
/** 支持的语言标识 */
|
||||
export type LocaleKey = 'zh-CN' | 'en-US'
|
||||
|
||||
/** 单条消息:同时包含中文与英文 */
|
||||
interface MessageLeaf {
|
||||
zh: string
|
||||
en: string
|
||||
}
|
||||
|
||||
// 语言偏好存储键
|
||||
const STORAGE_KEY = 'locale'
|
||||
// 支持的语言列表
|
||||
const SUPPORTED: LocaleKey[] = ['zh-CN', 'en-US']
|
||||
|
||||
/** 判断节点是否为消息叶子(同时具备 zh、en 字符串字段) */
|
||||
function isMessageLeaf(node: unknown): node is MessageLeaf {
|
||||
return (
|
||||
!!node &&
|
||||
typeof node === 'object' &&
|
||||
typeof (node as MessageLeaf).zh === 'string' &&
|
||||
typeof (node as MessageLeaf).en === 'string'
|
||||
)
|
||||
}
|
||||
|
||||
/** 递归将对照消息树拆分为指定语言的嵌套消息树 */
|
||||
function buildLocaleMessages(node: unknown, lang: 'zh' | 'en'): any {
|
||||
if (isMessageLeaf(node)) return node[lang]
|
||||
const result: Record<string, any> = {}
|
||||
for (const [key, value] of Object.entries(node as Record<string, unknown>)) {
|
||||
result[key] = buildLocaleMessages(value, lang)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/** 解析初始语言:localStorage > 浏览器语言 > 简体中文 */
|
||||
function resolveInitialLocale(): LocaleKey {
|
||||
const saved = localStorage.getItem(STORAGE_KEY)
|
||||
if (saved && SUPPORTED.includes(saved as LocaleKey)) {
|
||||
return saved as LocaleKey
|
||||
}
|
||||
if (navigator.language?.toLowerCase().startsWith('en')) {
|
||||
return 'en-US'
|
||||
}
|
||||
return 'zh-CN'
|
||||
}
|
||||
|
||||
const i18n = createI18n({
|
||||
legacy: false, // 使用 Composition API 模式
|
||||
globalInjection: true, // 模板中可直接使用 $t
|
||||
locale: resolveInitialLocale(),
|
||||
fallbackLocale: 'zh-CN',
|
||||
messages: {
|
||||
'zh-CN': buildLocaleMessages(messages, 'zh'),
|
||||
'en-US': buildLocaleMessages(messages, 'en'),
|
||||
},
|
||||
})
|
||||
|
||||
/** 获取当前语言标识 */
|
||||
export function getLocale(): LocaleKey {
|
||||
return i18n.global.locale.value as LocaleKey
|
||||
}
|
||||
|
||||
/** 切换语言:更新 i18n、持久化到 localStorage,并同步 <html lang> */
|
||||
export function setLocale(locale: LocaleKey) {
|
||||
i18n.global.locale.value = locale
|
||||
localStorage.setItem(STORAGE_KEY, locale)
|
||||
document.documentElement.lang = locale
|
||||
}
|
||||
|
||||
// 应用启动时同步 <html lang>
|
||||
document.documentElement.lang = getLocale()
|
||||
|
||||
export default i18n
|
||||
@@ -0,0 +1,302 @@
|
||||
// 多语言消息定义:每个 key 同时维护中文(zh)与英文(en),一一对应,便于对照维护
|
||||
export default {
|
||||
// 语言名称(用于切换器展示,始终以自身语言呈现)
|
||||
locale: {
|
||||
zhCN: { zh: '简体中文', en: '简体中文' },
|
||||
enUS: { zh: 'English', en: 'English' },
|
||||
},
|
||||
|
||||
// 通用文案与枚举
|
||||
common: {
|
||||
confirm: { zh: '确定', en: 'Confirm' },
|
||||
cancel: { zh: '取消', en: 'Cancel' },
|
||||
delete: { zh: '删除', en: 'Delete' },
|
||||
edit: { zh: '编辑', en: 'Edit' },
|
||||
operation: { zh: '操作', en: 'Actions' },
|
||||
name: { zh: '名称', en: 'Name' },
|
||||
type: { zh: '类型', en: 'Type' },
|
||||
sort: { zh: '排序', en: 'Order' },
|
||||
all: { zh: '全部', en: 'All' },
|
||||
min: { zh: '最小', en: 'Min' },
|
||||
max: { zh: '最大', en: 'Max' },
|
||||
reset: { zh: '重置', en: 'Reset' },
|
||||
loadFailed: { zh: '加载失败', en: 'Failed to load' },
|
||||
operationFailed: { zh: '操作失败', en: 'Operation failed' },
|
||||
createSuccess: { zh: '创建成功', en: 'Created successfully' },
|
||||
updateSuccess: { zh: '修改成功', en: 'Updated successfully' },
|
||||
deleteSuccess: { zh: '删除成功', en: 'Deleted successfully' },
|
||||
deleteFailed: { zh: '删除失败', en: 'Failed to delete' },
|
||||
confirmDelete: { zh: '确认删除', en: 'Confirm Deletion' },
|
||||
types: {
|
||||
expense: { zh: '支出', en: 'Expense' },
|
||||
income: { zh: '收入', en: 'Income' },
|
||||
},
|
||||
payment: {
|
||||
wechat: { zh: '微信', en: 'WeChat' },
|
||||
alipay: { zh: '支付宝', en: 'Alipay' },
|
||||
cash: { zh: '现金', en: 'Cash' },
|
||||
bank: { zh: '银行卡', en: 'Bank Card' },
|
||||
},
|
||||
},
|
||||
|
||||
// 登录页
|
||||
login: {
|
||||
title: { zh: '收支管理系统 - 登录', en: 'Finance Manager - Sign In' },
|
||||
username: { zh: '用户名', en: 'Username' },
|
||||
password: { zh: '密码', en: 'Password' },
|
||||
usernamePlaceholder: { zh: '请输入用户名', en: 'Enter your username' },
|
||||
passwordPlaceholder: { zh: '请输入密码', en: 'Enter your password' },
|
||||
submit: { zh: '登录', en: 'Sign In' },
|
||||
toRegister: { zh: '没有账号?去注册', en: "Don't have an account? Sign up" },
|
||||
fillRequired: { zh: '请填写用户名和密码', en: 'Please enter username and password' },
|
||||
success: { zh: '登录成功', en: 'Signed in successfully' },
|
||||
failed: { zh: '登录失败', en: 'Sign in failed' },
|
||||
},
|
||||
|
||||
// 注册页
|
||||
register: {
|
||||
title: { zh: '收支管理系统 - 注册', en: 'Finance Manager - Sign Up' },
|
||||
username: { zh: '用户名', en: 'Username' },
|
||||
nickname: { zh: '昵称', en: 'Nickname' },
|
||||
password: { zh: '密码', en: 'Password' },
|
||||
confirmPassword: { zh: '确认密码', en: 'Confirm Password' },
|
||||
usernamePlaceholder: { zh: '3-50个字符', en: '3-50 characters' },
|
||||
nicknamePlaceholder: { zh: '可选', en: 'Optional' },
|
||||
passwordPlaceholder: { zh: '至少6个字符', en: 'At least 6 characters' },
|
||||
confirmPasswordPlaceholder: { zh: '再次输入密码', en: 'Enter the password again' },
|
||||
submit: { zh: '注册', en: 'Sign Up' },
|
||||
toLogin: { zh: '已有账号?去登录', en: 'Already have an account? Sign in' },
|
||||
fillRequired: { zh: '请填写用户名和密码', en: 'Please enter username and password' },
|
||||
usernameMin: { zh: '用户名至少3个字符', en: 'Username must be at least 3 characters' },
|
||||
passwordMin: { zh: '密码至少6个字符', en: 'Password must be at least 6 characters' },
|
||||
passwordMismatch: { zh: '两次密码不一致', en: 'The two passwords do not match' },
|
||||
success: { zh: '注册成功,请登录', en: 'Registered successfully, please sign in' },
|
||||
failed: { zh: '注册失败', en: 'Registration failed' },
|
||||
},
|
||||
|
||||
// 主布局
|
||||
layout: {
|
||||
appTitle: { zh: '收支管理', en: 'Finance Manager' },
|
||||
dashboard: { zh: '统计面板', en: 'Dashboard' },
|
||||
transactions: { zh: '收支记录', en: 'Transactions' },
|
||||
categories: { zh: '分类管理', en: 'Categories' },
|
||||
tags: { zh: '标签管理', en: 'Tags' },
|
||||
user: { zh: '用户', en: 'User' },
|
||||
logout: { zh: '退出', en: 'Sign Out' },
|
||||
},
|
||||
|
||||
// 统计面板
|
||||
dashboard: {
|
||||
title: { zh: '统计面板', en: 'Dashboard' },
|
||||
range: {
|
||||
month: { zh: '本月', en: 'This Month' },
|
||||
'3month': { zh: '近3月', en: 'Last 3 Months' },
|
||||
'12month': { zh: '近12月', en: 'Last 12 Months' },
|
||||
custom: { zh: '自定义', en: 'Custom' },
|
||||
},
|
||||
granularity: {
|
||||
day: { zh: '按日', en: 'Daily' },
|
||||
week: { zh: '按周', en: 'Weekly' },
|
||||
month: { zh: '按月', en: 'Monthly' },
|
||||
quarter: { zh: '按季', en: 'Quarterly' },
|
||||
year: { zh: '按年', en: 'Yearly' },
|
||||
},
|
||||
filterType: { zh: '类型', en: 'Type' },
|
||||
filterCategory: { zh: '分类', en: 'Category' },
|
||||
filterPaymentMethod: { zh: '支付方式', en: 'Payment Method' },
|
||||
minAmount: { zh: '最小金额', en: 'Min Amount' },
|
||||
maxAmount: { zh: '最大金额', en: 'Max Amount' },
|
||||
remark: { zh: '备注搜索', en: 'Search Remark' },
|
||||
resetFilters: { zh: '重置筛选', en: 'Reset Filters' },
|
||||
totalIncome: { zh: '总收入', en: 'Total Income' },
|
||||
totalExpense: { zh: '总支出', en: 'Total Expense' },
|
||||
balance: { zh: '结余', en: 'Balance' },
|
||||
transactionCount: { zh: '交易笔数', en: 'Transactions' },
|
||||
avgDailyIncome: { zh: '日均收入', en: 'Avg. Daily Income' },
|
||||
avgDailyExpense: { zh: '日均支出', en: 'Avg. Daily Expense' },
|
||||
maxExpense: { zh: '最大单笔支出', en: 'Largest Expense' },
|
||||
avgExpense: { zh: '平均每笔支出', en: 'Avg. Expense' },
|
||||
trend: { zh: '收支趋势', en: 'Income & Expense Trend' },
|
||||
expenseCategoryPie: { zh: '支出分类占比', en: 'Expense by Category' },
|
||||
paymentPie: { zh: '支付方式分布', en: 'Payment Method Distribution' },
|
||||
uncategorized: { zh: '未分类', en: 'Uncategorized' },
|
||||
},
|
||||
|
||||
// 收支记录
|
||||
transaction: {
|
||||
title: { zh: '收支记录', en: 'Transactions' },
|
||||
sortLabel: { zh: '排序:', en: 'Sort:' },
|
||||
sort: {
|
||||
timeDesc: { zh: '交易时间(新→旧)', en: 'Time (Newest First)' },
|
||||
timeAsc: { zh: '交易时间(旧→新)', en: 'Time (Oldest First)' },
|
||||
amountDesc: { zh: '金额(高→低)', en: 'Amount (High to Low)' },
|
||||
amountAsc: { zh: '金额(低→高)', en: 'Amount (Low to High)' },
|
||||
},
|
||||
batchSet: { zh: '一键设置', en: 'Batch Set' },
|
||||
importBill: { zh: '导入账单', en: 'Import Bill' },
|
||||
exportExcel: { zh: '导出 Excel', en: 'Export Excel' },
|
||||
addRecord: { zh: '新增记录', en: 'Add Record' },
|
||||
moreFilter: { zh: '更多筛选', en: 'More Filters' },
|
||||
clear: { zh: '清空', en: 'Clear' },
|
||||
amountRange: { zh: '金额区间', en: 'Amount Range' },
|
||||
search: { zh: '查询', en: 'Search' },
|
||||
reset: { zh: '重置', en: 'Reset' },
|
||||
summary: { zh: '总计 {total} 条 · 第 {page} / {pages} 页 · 每页 {size} 条', en: 'Total {total} · Page {page} / {pages} · {size} per page' },
|
||||
pageExpense: { zh: '本页支出', en: 'Page Expense' },
|
||||
pageIncome: { zh: '本页收入', en: 'Page Income' },
|
||||
pageBalance: { zh: '本页结余', en: 'Page Balance' },
|
||||
column: {
|
||||
transactionTime: { zh: '交易时间', en: 'Time' },
|
||||
type: { zh: '类型', en: 'Type' },
|
||||
category: { zh: '分类', en: 'Category' },
|
||||
amount: { zh: '金额', en: 'Amount' },
|
||||
paymentMethod: { zh: '支付方式', en: 'Payment' },
|
||||
remark: { zh: '备注', en: 'Remark' },
|
||||
tags: { zh: '标签', en: 'Tags' },
|
||||
includeInStats: { zh: '计入统计', en: 'In Stats' },
|
||||
actions: { zh: '操作', en: 'Actions' },
|
||||
},
|
||||
notIncluded: { zh: '不计入', en: 'Excluded' },
|
||||
uncategorized: { zh: '未分类', en: 'Uncategorized' },
|
||||
remarkHidden: { zh: '备注已隐藏', en: 'Remark hidden' },
|
||||
remarkView: { zh: '查看', en: 'View' },
|
||||
remarkHide: { zh: '隐藏', en: 'Hide' },
|
||||
remarkCollapse: { zh: '收起', en: 'Collapse' },
|
||||
remarkUnhide: { zh: '取消隐藏', en: 'Unhide' },
|
||||
rawData: { zh: '原始数据', en: 'Raw Data' },
|
||||
rawDataTitle: { zh: '原始账单数据', en: 'Raw Bill Data' },
|
||||
createdTime: { zh: '创建时间:{time}', en: 'Created: {time}' },
|
||||
editRecord: { zh: '编辑记录', en: 'Edit Record' },
|
||||
addRecordTitle: { zh: '新增记录', en: 'Add Record' },
|
||||
batchTitle: { zh: '一键设置分类与统计', en: 'Batch Set Category & Stats' },
|
||||
batchScope: { zh: '作用范围', en: 'Scope' },
|
||||
batchScopeHint: { zh: '将对当前表格展示的 {count} 条记录设置分类与计入统计', en: 'Apply category and stats settings to the {count} records shown in the table' },
|
||||
expenseCategory: { zh: '支出分类', en: 'Expense Category' },
|
||||
incomeCategory: { zh: '收入分类', en: 'Income Category' },
|
||||
notSetExpense: { zh: '不设置支出分类', en: 'No expense category' },
|
||||
notSetIncome: { zh: '不设置收入分类', en: 'No income category' },
|
||||
addTag: { zh: '添加标签', en: 'Add Tags' },
|
||||
removeTag: { zh: '移除标签', en: 'Remove Tags' },
|
||||
notAddTag: { zh: '不添加标签', en: 'No tags to add' },
|
||||
notRemoveTag: { zh: '不移除标签', en: 'No tags to remove' },
|
||||
batchStats: {
|
||||
keep: { zh: '不修改', en: 'No Change' },
|
||||
include: { zh: '计入统计', en: 'Include in Stats' },
|
||||
exclude: { zh: '不计入统计', en: 'Exclude from Stats' },
|
||||
},
|
||||
includeInStats: { zh: '计入统计', en: 'In Stats' },
|
||||
includeInStatsHint: { zh: '关闭后不纳入月度统计(如借款、转账等)', en: 'When off, excluded from monthly stats (e.g. loans, transfers)' },
|
||||
deleteConfirm: { zh: '确定要删除这条记录吗?', en: 'Are you sure you want to delete this record?' },
|
||||
selectCategory: { zh: '请选择分类', en: 'Please select a category' },
|
||||
validAmount: { zh: '请输入有效金额', en: 'Please enter a valid amount' },
|
||||
selectCategoryPlaceholder: { zh: '请选择分类', en: 'Select a category' },
|
||||
amountPlaceholder: { zh: '请输入金额', en: 'Enter amount' },
|
||||
paymentPlaceholder: { zh: '选择支付方式', en: 'Select payment method' },
|
||||
remarkPlaceholder: { zh: '可选备注说明', en: 'Optional remark' },
|
||||
tagPlaceholder: { zh: '选择标签', en: 'Select tags' },
|
||||
noRawData: { zh: '该记录没有原始账单数据', en: 'This record has no raw bill data' },
|
||||
remarkHiddenSuccess: { zh: '已隐藏备注', en: 'Remark hidden' },
|
||||
remarkShownSuccess: { zh: '已取消隐藏', en: 'Remark unhidden' },
|
||||
statsIncluded: { zh: '已计入统计', en: 'Included in stats' },
|
||||
statsExcluded: { zh: '已排除统计', en: 'Excluded from stats' },
|
||||
noRecordsToSet: { zh: '当前表格没有可设置的记录', en: 'No records available in the current table' },
|
||||
batchNothingSelected: { zh: '请至少选择分类、计入统计或标签', en: 'Please select a category, stats option or tag' },
|
||||
batchUpdated: { zh: '已更新 {count} 条记录 | 已更新 {count} 条记录', en: 'Updated {count} record | Updated {count} records' },
|
||||
exportSuccess: { zh: '导出成功', en: 'Exported successfully' },
|
||||
exportFailed: { zh: '导出失败', en: 'Export failed' },
|
||||
exportFileName: { zh: '交易记录', en: 'transactions' },
|
||||
includeFilter: {
|
||||
yes: { zh: '计入', en: 'Included' },
|
||||
no: { zh: '不计入', en: 'Excluded' },
|
||||
},
|
||||
},
|
||||
|
||||
// 分类管理
|
||||
category: {
|
||||
title: { zh: '分类管理', en: 'Categories' },
|
||||
add: { zh: '新增分类', en: 'Add Category' },
|
||||
expenseSection: { zh: '支出分类', en: 'Expense Categories' },
|
||||
incomeSection: { zh: '收入分类', en: 'Income Categories' },
|
||||
editTitle: { zh: '编辑分类', en: 'Edit Category' },
|
||||
addTitle: { zh: '新增分类', en: 'Add Category' },
|
||||
name: { zh: '分类名称', en: 'Category Name' },
|
||||
namePlaceholder: { zh: '请输入分类名称', en: 'Enter category name' },
|
||||
type: { zh: '类型', en: 'Type' },
|
||||
icon: { zh: '图标', en: 'Icon' },
|
||||
iconPlaceholder: { zh: '可选,如 emoji', en: 'Optional, e.g. emoji' },
|
||||
sort: { zh: '排序', en: 'Order' },
|
||||
nameRequired: { zh: '请输入分类名称', en: 'Please enter a category name' },
|
||||
deleteConfirm: { zh: '确定要删除这个分类吗?', en: 'Are you sure you want to delete this category?' },
|
||||
},
|
||||
|
||||
// 标签管理
|
||||
tag: {
|
||||
title: { zh: '标签管理', en: 'Tags' },
|
||||
add: { zh: '新增标签', en: 'Add Tag' },
|
||||
editTitle: { zh: '编辑标签', en: 'Edit Tag' },
|
||||
addTitle: { zh: '新增标签', en: 'Add Tag' },
|
||||
name: { zh: '标签名称', en: 'Tag Name' },
|
||||
namePlaceholder: { zh: '请输入标签名称', en: 'Enter tag name' },
|
||||
label: { zh: '标签', en: 'Tag' },
|
||||
color: { zh: '颜色', en: 'Color' },
|
||||
sort: { zh: '排序', en: 'Order' },
|
||||
nameRequired: { zh: '请输入标签名称', en: 'Please enter a tag name' },
|
||||
deleteConfirm: { zh: '删除后将从所有交易记录中移除该标签,确定删除吗?', en: 'This tag will be removed from all transactions. Delete it?' },
|
||||
},
|
||||
|
||||
// 账单导入
|
||||
import: {
|
||||
title: { zh: '导入账单', en: 'Import Bill' },
|
||||
billType: { zh: '账单类型:', en: 'Bill type:' },
|
||||
billTypeALIPAY: { zh: '支付宝', en: 'Alipay' },
|
||||
billTypeWECHAT: { zh: '微信', en: 'WeChat' },
|
||||
billFile: { zh: '账单文件:', en: 'Bill file:' },
|
||||
dropText: { zh: '点击或拖拽文件到此处', en: 'Click or drag a file here' },
|
||||
fileHint: { zh: '仅支持{label}导出的账单文件({exts})', en: 'Only {label} bill files are supported ({exts})' },
|
||||
extSeparator: { zh: '、', en: ', ' },
|
||||
exportHintALIPAY: { zh: '导出路径:支付宝 App → 我的 → 账单 → 开具交易流水证明 / 账单导出,选择 CSV 格式。', en: 'Export path: Alipay App → Me → Bills → Issue Transaction Record / Export Bill, choose CSV format.' },
|
||||
exportHintWECHAT: { zh: '导出路径:微信 App → 我 → 服务 → 钱包 → 账单 → 常见问题 → 下载账单 → 用于个人对账,选择 xlsx 格式。', en: 'Export path: WeChat App → Me → Services → Wallet → Bills → FAQ → Download Bills → For personal reconciliation, choose xlsx format.' },
|
||||
parse: { zh: '解析', en: 'Parse' },
|
||||
expenseDefaultCategory: { zh: '支出默认分类(可不选):', en: 'Default expense category (optional):' },
|
||||
incomeDefaultCategory: { zh: '收入默认分类(可不选):', en: 'Default income category (optional):' },
|
||||
defaultTags: { zh: '默认标签(可不选):', en: 'Default tags (optional):' },
|
||||
notSetCategory: { zh: '未选则不计分类', en: 'No category if unselected' },
|
||||
notSetTag: { zh: '未选则不打标签', en: 'No tags if unselected' },
|
||||
selectAll: { zh: '全选', en: 'Select All' },
|
||||
previewSummary: { zh: '共 {total} 条,筛选后 {filtered} 条,已勾选 {checked} 条', en: 'Total {total}, {filtered} after filtering, {checked} selected' },
|
||||
searchPlaceholder: { zh: '搜索交易对方/商品/单号', en: 'Search counterparty / product / order no.' },
|
||||
typePlaceholder: { zh: '类型', en: 'Type' },
|
||||
statusPlaceholder: { zh: '状态', en: 'Status' },
|
||||
typeFilter: {
|
||||
income: { zh: '收入', en: 'Income' },
|
||||
expense: { zh: '支出', en: 'Expense' },
|
||||
neutral: { zh: '不计入', en: 'Excluded' },
|
||||
},
|
||||
statusFilter: {
|
||||
importable: { zh: '可导入', en: 'Importable' },
|
||||
duplicate: { zh: '已存在', en: 'Duplicate' },
|
||||
error: { zh: '不可导入', en: 'Not Importable' },
|
||||
},
|
||||
notIncluded: { zh: '不计入', en: 'Excluded' },
|
||||
notImportable: { zh: '不可导入', en: 'Not Importable' },
|
||||
prevStep: { zh: '上一步', en: 'Previous' },
|
||||
confirmImport: { zh: '确认导入({count})', en: 'Confirm Import ({count})' },
|
||||
resultSummary: { zh: '导入完成:成功 {imported} 条,跳过 {skipped} 条,失败 {failed} 条', en: 'Import complete: {imported} succeeded, {skipped} skipped, {failed} failed' },
|
||||
done: { zh: '完成', en: 'Done' },
|
||||
column: {
|
||||
transactionTime: { zh: '交易时间', en: 'Time' },
|
||||
type: { zh: '类型', en: 'Type' },
|
||||
amount: { zh: '金额', en: 'Amount' },
|
||||
counterparty: { zh: '交易对方', en: 'Counterparty' },
|
||||
product: { zh: '商品名称', en: 'Product' },
|
||||
status: { zh: '状态', en: 'Status' },
|
||||
},
|
||||
errorFileType: { zh: '账单类型「{label}」仅支持 {exts} 格式的文件', en: 'Bill type "{label}" only supports files in {exts} format' },
|
||||
selectFileFirst: { zh: '请先选择账单文件', en: 'Please select a bill file first' },
|
||||
parseFailed: { zh: '解析失败', en: 'Parse failed' },
|
||||
selectAtLeastOne: { zh: '请至少勾选一条记录', en: 'Please select at least one record' },
|
||||
importFailed: { zh: '导入失败', en: 'Import failed' },
|
||||
loadCategoriesFailed: { zh: '加载分类失败', en: 'Failed to load categories' },
|
||||
loadTagsFailed: { zh: '加载标签失败', en: 'Failed to load tags' },
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user