feat(i18n): add internationalization support with English and Chinese translations

This commit is contained in:
shuaiplus
2026-03-01 10:28:21 +08:00
committed by Shuai
parent 1810e0aa7a
commit bacf27b936
14 changed files with 1343 additions and 491 deletions
+716
View File
@@ -0,0 +1,716 @@
type Locale = 'en' | 'zh-CN';
const LOCALE_STORAGE_KEY = 'nodewarden.locale';
const messages: Record<Locale, Record<string, string>> = {
en: {
nav_account_settings: "Account Settings",
nav_admin_panel: "Admin Panel",
nav_device_management: "Device Management",
nav_my_vault: "My Vault",
nav_sends: "Sends",
nav_support_center: "Support Center",
support_title: "Support Center",
support_under_construction: "Under construction.",
txt_access_count: "Access Count",
txt_accessed_count_times: "Accessed {count} times",
txt_actions: "Actions",
txt_add: "Add",
txt_add_field: "Add Field",
txt_add_website: "Add Website",
txt_added: "Added",
txt_additional_options: "Additional Options",
txt_address: "Address",
txt_address_1: "Address 1",
txt_address_2: "Address 2",
txt_address_3: "Address 3",
txt_all_device_authorizations_revoked: "All device authorizations revoked",
txt_all_invites_deleted: "All invites deleted",
txt_all_items: "All Items",
txt_all_sends: "All Sends",
txt_android: "Android",
txt_are_you_sure_you_want_to_delete_count_selected_items: "Are you sure you want to delete {count} selected items?",
txt_are_you_sure_you_want_to_delete_this_item: "Are you sure you want to delete this item?",
txt_are_you_sure_you_want_to_log_out: "Are you sure you want to log out?",
txt_authenticator_key: "Authenticator Key",
txt_authorized_devices: "Authorized Devices",
txt_auto_copy_link_after_save: "Auto copy link after save",
txt_autofill_options: "Autofill Options",
txt_back_to_login: "Back To Login",
txt_ban: "Ban",
txt_boolean: "Boolean",
txt_brand: "Brand",
txt_bulk_delete_failed: "Bulk delete failed",
txt_bulk_delete_sends_failed: "Bulk delete sends failed",
txt_bulk_move_failed: "Bulk move failed",
txt_cancel: "Cancel",
txt_card: "Card",
txt_card_details: "Card Details",
txt_cardholder_name: "Cardholder Name",
txt_change_master_password: "Change Master Password",
txt_change_password: "Change Password",
txt_change_password_failed: "Change password failed",
txt_checked: "Checked",
txt_choose_destination_folder: "Choose destination folder.",
txt_chrome_browser: "Chrome Browser",
txt_chrome_extension: "Chrome Extension",
txt_city_town: "City / Town",
txt_code: "Code",
txt_company: "Company",
txt_configure_custom_field_values: "Configure custom field values.",
txt_confirm: "Confirm",
txt_confirm_master_password: "Confirm Master Password",
txt_confirm_password: "Confirm Password",
txt_copy: "Copy",
txt_copy_code: "Copy Code",
txt_copy_link: "Copy Link",
txt_copy_secret: "Copy Secret",
txt_country: "Country",
txt_create: "Create",
txt_create_account: "Create Account",
txt_create_folder: "Create Folder",
txt_create_folder_failed: "Create folder failed",
txt_create_item_failed: "Create item failed",
txt_create_send_failed: "Create send failed",
txt_create_timed_invite: "Create Timed Invite",
txt_created_value: "Created: {value}",
txt_current_new_password_is_required: "Current/new password is required",
txt_current_password: "Current Password",
txt_custom_fields: "Custom Fields",
txt_decrypt_failed: "(Decrypt failed)",
txt_decrypt_failed_2: "Decrypt failed",
txt_delete: "Delete",
txt_delete_all: "Delete All",
txt_delete_all_invite_codes_active_inactive: "Delete all invite codes (active/inactive)?",
txt_delete_all_invites: "Delete all invites",
txt_delete_item: "Delete Item",
txt_delete_item_failed: "Delete item failed",
txt_delete_selected: "Delete Selected",
txt_delete_selected_items: "Delete Selected Items",
txt_delete_send_failed: "Delete send failed",
txt_delete_this_user_and_all_user_data: "Delete this user and all user data?",
txt_delete_user: "Delete user",
txt_deleted_selected_items: "Deleted selected items",
txt_deleted_selected_sends: "Deleted selected sends",
txt_deletion_date: "Deletion Date",
txt_deletion_days: "Deletion Days",
txt_device: "Device",
txt_device_authorization_revoked: "Device authorization revoked",
txt_device_management: "Device Management",
txt_device_removed: "Device removed",
txt_disable_this_send: "Disable this send",
txt_disable_totp: "Disable TOTP",
txt_disable_totp_failed: "Disable TOTP failed",
txt_download: "Download",
txt_download_failed: "Download failed",
txt_edge_browser: "Edge Browser",
txt_edge_extension: "Edge Extension",
txt_edit: "Edit",
txt_edit_send: "Edit Send",
txt_email: "Email",
txt_email_password_and_recovery_code_are_required: "Email, password and recovery code are required",
txt_enable_totp: "Enable TOTP",
txt_enable_totp_failed: "Enable TOTP failed",
txt_enabled: "Enabled",
txt_encrypted_file: "Encrypted File",
txt_encrypted_file_2: "Encrypted file",
txt_enter_a_folder_name: "Enter a folder name.",
txt_enter_master_password_to_disable_two_step_verification: "Enter master password to disable two-step verification.",
txt_enter_master_password_to_view_this_item: "Enter master password to view this item.",
txt_expiration_date: "Expiration Date",
txt_expiration_days_0_never: "Expiration Days (0 = never)",
txt_expires_at: "Expires At",
txt_expires_at_value: "Expires at: {value}",
txt_expiry: "Expiry",
txt_expiry_month: "Expiry Month",
txt_expiry_year: "Expiry Year",
txt_failed_to_open_send: "Failed to open send",
txt_favorite: "Favorite",
txt_favorites: "Favorites",
txt_field: "Field",
txt_field_label: "Field Label",
txt_field_label_is_required: "Field label is required.",
txt_field_type: "Field Type",
txt_field_value: "Field Value",
txt_file: "File",
txt_file_name: "File Name",
txt_file_send: "File Send",
txt_file_size: "File Size",
txt_fingerprint: "Fingerprint",
txt_firefox_browser: "Firefox Browser",
txt_firefox_extension: "Firefox Extension",
txt_first_name: "First Name",
txt_folder: "Folder",
txt_folder_created: "Folder created",
txt_folder_name: "Folder Name",
txt_folder_name_is_required: "Folder name is required",
txt_folders: "Folders",
txt_hidden: "Hidden",
txt_hide: "Hide",
txt_identity: "Identity",
txt_identity_details: "Identity Details",
txt_ie_browser: "IE Browser",
txt_invite_code_optional: "Invite Code (Optional)",
txt_invite_created: "Invite created",
txt_invite_revoked: "Invite revoked",
txt_invite_validity_hours: "Invite validity (hours)",
txt_invites: "Invites",
txt_ios: "iOS",
txt_item: "Item",
txt_item_created: "Item created",
txt_item_deleted: "Item deleted",
txt_item_history: "Item History",
txt_item_name_is_required: "Item name is required.",
txt_item_updated: "Item updated",
txt_last_edited_value: "Last edited: {value}",
txt_last_name: "Last Name",
txt_last_seen: "Last Seen",
txt_license_number: "License Number",
txt_link_copied: "Link copied",
txt_linked: "Linked",
txt_linux_desktop: "Linux Desktop",
txt_loading: "Loading...",
txt_loading_nodewarden: "Loading NodeWarden...",
txt_log_in: "Log In",
txt_log_out: "Log Out",
txt_login: "Login",
txt_login_credentials: "Login Credentials",
txt_login_failed: "Login failed",
txt_login_success: "Login success",
txt_macos_desktop: "macOS Desktop",
txt_manage_authorized_devices_and_30_day_totp_trusted_sessions: "Manage authorized devices and 30-day TOTP trusted sessions.",
txt_master_password: "Master Password",
txt_master_password_changed_please_login_again: "Master password changed. Please login again.",
txt_master_password_is_required: "Master password is required",
txt_master_password_is_required_2: "Master password is required.",
txt_master_password_must_be_at_least_12_chars: "Master password must be at least 12 chars",
txt_master_password_reprompt: "Master password reprompt",
txt_master_password_reprompt_2: "Master Password Reprompt",
txt_max_access_count: "Max Access Count",
txt_middle_name: "Middle Name",
txt_move: "Move",
txt_move_selected_items: "Move Selected Items",
txt_moved_selected_items: "Moved selected items",
txt_name: "Name",
txt_name_is_required: "Name is required",
txt_new_password: "New Password",
txt_new_password_must_be_at_least_12_chars: "New password must be at least 12 chars",
txt_new_passwords_do_not_match: "New passwords do not match",
txt_new_send: "New Send",
txt_next: "Next",
txt_no: "No",
txt_no_devices_found: "No devices found.",
txt_no_folder: "No Folder",
txt_no_items: "No items",
txt_no_name: "(No Name)",
txt_no_sends: "No sends",
txt_nodewarden_send: "NodeWarden Send",
txt_not_trusted: "Not trusted",
txt_note: "Note",
txt_notes: "Notes",
txt_number: "Number",
txt_open: "Open",
txt_opera_browser: "Opera Browser",
txt_opera_extension: "Opera Extension",
txt_or: "or",
txt_options: "Options",
txt_passport_number: "Passport Number",
txt_password: "Password",
txt_password_is_already_verified: "Password is already verified.",
txt_passwords_do_not_match: "Passwords do not match",
txt_phone: "Phone",
txt_please_input_email_and_password: "Please input email and password",
txt_please_input_master_password: "Please input master password",
txt_please_input_totp_code: "Please input TOTP code",
txt_please_select_a_file: "Please select a file",
txt_postal_code: "Postal Code",
txt_prev: "Prev",
txt_private_key: "Private Key",
txt_profile: "Profile",
txt_profile_unavailable: "Profile unavailable",
txt_profile_updated: "Profile updated",
txt_public_key: "Public Key",
txt_recover_2fa_failed: "Recover 2FA failed",
txt_recover_two_step_login: "Recover Two-step Login",
txt_recovered_but_auto_login_failed_please_sign_in: "Recovered but auto-login failed, please sign in.",
txt_recovery_code: "Recovery Code",
txt_recovery_code_copied: "Recovery code copied",
txt_recovery_code_is_empty: "Recovery code is empty",
txt_recovery_code_loaded: "Recovery code loaded",
txt_refresh: "Refresh",
txt_refresh_in_seconds_s: "Refresh in {seconds}s",
txt_regenerate: "Regenerate",
txt_registration_succeeded_please_sign_in: "Registration succeeded. Please sign in.",
txt_remove: "Remove",
txt_remove_device: "Remove device",
txt_remove_device_2: "Remove Device",
txt_remove_device_name_and_clear_its_2fa_trust: "Remove device \"{name}\" and clear its 2FA trust?",
txt_reveal: "Reveal",
txt_revoke: "Revoke",
txt_revoke_30_day_totp_trust_for_name: "Revoke 30-day TOTP trust for \"{name}\"?",
txt_revoke_30_day_totp_trust_from_all_devices: "Revoke 30-day TOTP trust from all devices?",
txt_revoke_all_trusted: "Revoke All Trusted",
txt_revoke_all_trusted_devices: "Revoke all trusted devices",
txt_revoke_device_authorization: "Revoke device authorization",
txt_revoke_trust: "Revoke Trust",
txt_role: "Role",
txt_save: "Save",
txt_save_profile: "Save Profile",
txt_save_profile_failed: "Save profile failed",
txt_search_sends: "Search sends...",
txt_search_your_secure_vault: "Search your secure vault...",
txt_secret_and_code_are_required: "Secret and code are required",
txt_secret_copied: "Secret copied",
txt_secure_note: "Secure Note",
txt_security_code: "Security Code",
txt_security_code_cvv: "Security Code (CVV)",
txt_select_all: "Select All",
txt_select_an_item: "Select an item",
txt_send_created: "Send created",
txt_send_deleted: "Send deleted",
txt_send_details: "Send Details",
txt_send_file: "send-file",
txt_send_unavailable: "Send unavailable.",
txt_send_updated: "Send updated",
txt_sign_out: "Sign Out",
txt_ssh_key: "SSH Key",
txt_ssn: "SSN",
txt_state_province: "State / Province",
txt_status: "Status",
txt_submit: "Submit",
txt_sync: "Sync",
txt_sync_vault: "Sync Vault",
txt_dash: "-",
txt_text: "Text",
txt_text_2fa_recovered: "2FA recovered",
txt_text_2fa_recovered_new_recovery_code_code: "2FA recovered. New recovery code: {code}",
txt_text_3: "------",
txt_text_is_required: "Text is required",
txt_text_send: "Text Send",
txt_this_is_a_one_time_code_after_it_is_used_a_new_code_is_generated_automatically: "This is a one-time code. After it is used, a new code is generated automatically.",
txt_this_item_requires_master_password_every_time_before_viewing_details: "This item requires master password every time before viewing details.",
txt_this_link_is_missing_decryption_key: "This link is missing decryption key.",
txt_this_send_is_password_protected: "This send is password protected.",
txt_title: "Title",
txt_totp: "TOTP",
txt_totp_code: "TOTP Code",
txt_totp_disabled: "TOTP disabled",
txt_totp_enabled: "TOTP enabled",
txt_totp_is_enabled_for_this_account: "TOTP is enabled for this account.",
txt_totp_secret: "TOTP Secret",
txt_totp_verify_failed: "TOTP verify failed",
txt_trash: "Trash",
txt_trust_this_device_for_30_days: "Trust this device for 30 days",
txt_trusted_until: "Trusted Until",
txt_two_step_verification: "Two-step verification",
txt_type: "Type",
txt_type_type: "Type {type}",
txt_unban: "Unban",
txt_unchecked: "Unchecked",
txt_unknown_device: "Unknown device",
txt_unlock: "Unlock",
txt_unlock_details: "Unlock Details",
txt_unlock_failed: "Unlock failed",
txt_unlock_failed_master_password_is_incorrect: "Unlock failed. Master password is incorrect.",
txt_unlock_item: "Unlock Item",
txt_unlock_send: "Unlock Send",
txt_unlock_vault: "Unlock Vault",
txt_unlocked: "Unlocked",
txt_update_item_failed: "Update item failed",
txt_update_send_failed: "Update send failed",
txt_use_recovery_code: "Use Recovery Code",
txt_use_your_one_time_recovery_code_to_disable_two_step_verification: "Use your one-time recovery code to disable two-step verification.",
txt_user_deleted: "User deleted",
txt_user_status_updated: "User status updated",
txt_username: "Username",
txt_users: "Users",
txt_vault_synced: "Vault synced",
txt_verification_code: "Verification Code",
txt_verify: "Verify",
txt_view_recovery_code: "View Recovery Code",
txt_web: "Web",
txt_website: "Website",
txt_websites: "Websites",
txt_windows_desktop: "Windows Desktop",
txt_yes: "Yes",
},
'zh-CN': {},
};
const zhCNOverrides: Record<string, string> = {
nav_my_vault: '我的保险库',
nav_sends: 'Send',
nav_admin_panel: '管理面板',
nav_account_settings: '账户设置',
nav_device_management: '设备管理',
nav_support_center: '支持中心',
support_title: '支持中心',
support_under_construction: '正在搭建中。',
txt_sign_out: '退出登录',
txt_log_in: '登录',
txt_log_out: '退出',
txt_create_account: '创建账户',
txt_back_to_login: '返回登录',
txt_unlock: '解锁',
txt_unlock_vault: '解锁保险库',
txt_master_password: '主密码',
txt_email: '邮箱',
txt_name: '名称',
txt_password: '密码',
txt_confirm_password: '确认密码',
txt_confirm_master_password: '确认主密码',
txt_submit: '提交',
txt_cancel: '取消',
txt_yes: '是',
txt_no: '否',
txt_loading: '加载中...',
txt_loading_nodewarden: '正在加载 NodeWarden...',
txt_search_sends: '搜索发送...',
txt_search_your_secure_vault: '搜索你的保险库...',
txt_refresh: '刷新',
txt_sync: '同步',
txt_sync_vault: '同步保险库',
txt_add: '新增',
txt_edit: '编辑',
txt_delete: '删除',
txt_save: '保存',
txt_confirm: '确认',
txt_move: '移动',
txt_copy: '复制',
txt_copy_link: '复制链接',
txt_select_all: '全选',
txt_delete_selected: '删除所选',
txt_all_items: '所有项目',
txt_favorites: '收藏',
txt_trash: '回收站',
txt_folder: '文件夹',
txt_folders: '文件夹',
txt_no_folder: '无文件夹',
txt_no_items: '没有项目',
txt_no_sends: '没有发送',
txt_select_an_item: '请选择一个项目',
txt_login: '登录',
txt_card: '银行卡',
txt_identity: '身份',
txt_note: '笔记',
txt_secure_note: '安全笔记',
txt_ssh_key: 'SSH 密钥',
txt_login_credentials: '登录信息',
txt_card_details: '银行卡详情',
txt_identity_details: '身份详情',
txt_autofill_options: '自动填充选项',
txt_additional_options: '附加选项',
txt_custom_fields: '自定义字段',
txt_notes: '备注',
txt_item_history: '项目历史',
txt_last_edited_value: '最后编辑:{value}',
txt_created_value: '创建于:{value}',
txt_username: '用户名',
txt_website: '网站',
txt_websites: '网站',
txt_open: '打开',
txt_hide: '隐藏',
txt_reveal: '显示',
txt_favorite: '收藏',
txt_field: '字段',
txt_field_type: '字段类型',
txt_field_label: '字段标签',
txt_field_value: '字段值',
txt_add_field: '添加字段',
txt_remove: '移除',
txt_enabled: '已启用',
txt_checked: '已勾选',
txt_unchecked: '未勾选',
txt_profile: '资料',
txt_save_profile: '保存资料',
txt_change_master_password: '修改主密码',
txt_current_password: '当前密码',
txt_new_password: '新密码',
txt_change_password: '修改密码',
txt_totp: 'TOTP',
txt_enable_totp: '启用 TOTP',
txt_disable_totp: '停用 TOTP',
txt_totp_code: 'TOTP 验证码',
txt_totp_secret: 'TOTP 密钥',
txt_verification_code: '验证码',
txt_recovery_code: '恢复代码',
txt_view_recovery_code: '查看恢复代码',
txt_copy_code: '复制代码',
txt_device_management: '设备管理',
txt_authorized_devices: '已授权设备',
txt_device: '设备',
txt_last_seen: '最后在线',
txt_trusted_until: '信任至',
txt_revoke_trust: '撤销信任',
txt_remove_device_2: '移除设备',
txt_not_trusted: '未信任',
txt_unknown_device: '未知设备',
txt_users: '用户',
txt_invites: '邀请码',
txt_ban: '封禁',
txt_unban: '解封',
txt_create_timed_invite: '创建时效邀请码',
txt_invite_validity_hours: '邀请码有效期(小时)',
txt_delete_all: '全部删除',
txt_prev: '上一页',
txt_next: '下一页',
txt_send_details: '发送详情',
txt_new_send: '新建发送',
txt_edit_send: '编辑发送',
txt_file_send: '文件发送',
txt_text_send: '文本发送',
txt_file: '文件',
txt_text: '文本',
txt_file_name: '文件名',
txt_file_size: '文件大小',
txt_access_count: '访问次数',
txt_deletion_date: '删除日期',
txt_expiration_date: '过期日期',
txt_deletion_days: '删除天数',
txt_expiration_days_0_never: '过期天数(0 表示不过期)',
txt_max_access_count: '最大访问次数',
txt_options: '选项',
txt_disable_this_send: '禁用此发送',
txt_auto_copy_link_after_save: '保存后自动复制链接',
txt_unlock_send: '解锁发送',
txt_nodewarden_send: 'NodeWarden 发送',
txt_send_unavailable: '发送不可用。',
txt_download: '下载',
txt_expires_at: '过期时间',
txt_expires_at_value: '过期于:{value}',
txt_dash: '-',
txt_or: '或',
txt_no_name: '(无名称)',
txt_are_you_sure_you_want_to_log_out: '确认要退出登录吗?',
txt_delete_item: '删除项目',
txt_delete_selected_items: '删除所选项目',
txt_move_selected_items: '移动所选项目',
txt_create_folder: '创建文件夹',
txt_folder_name: '文件夹名称',
txt_unlock_item: '解锁项目',
txt_use_recovery_code: '使用恢复代码',
txt_two_step_verification: '两步验证',
txt_recover_two_step_login: '恢复两步登录',
txt_title: '称谓',
txt_first_name: '名',
txt_middle_name: '中间名',
txt_last_name: '姓',
txt_company: '公司',
txt_ssn: '社保号',
txt_passport_number: '护照号',
txt_license_number: '证件号',
txt_private_key: '私钥',
txt_public_key: '公钥',
txt_fingerprint: '指纹',
txt_master_password_reprompt: '主密码二次确认',
txt_master_password_reprompt_2: '主密码二次确认',
txt_configure_custom_field_values: '配置自定义字段值。',
txt_hidden: '隐藏',
txt_boolean: '布尔',
txt_regenerate: '重新生成',
txt_copy_secret: '复制密钥',
txt_this_is_a_one_time_code_after_it_is_used_a_new_code_is_generated_automatically: '这是一次性恢复代码,使用后将自动生成新的恢复代码。',
txt_manage_authorized_devices_and_30_day_totp_trusted_sessions: '管理已授权设备和 30 天 TOTP 受信会话。',
txt_role: '角色',
txt_status: '状态',
txt_actions: '操作',
txt_type: '类型',
txt_revoke_all_trusted: '撤销全部受信任设备',
txt_revoke_all_trusted_devices: '撤销所有受信任设备',
txt_revoke_30_day_totp_trust_from_all_devices: '确认撤销所有设备的 30 天 TOTP 信任吗?',
txt_revoke_30_day_totp_trust_for_name: '确认撤销“{name}”的 30 天 TOTP 信任吗?',
txt_remove_device_name_and_clear_its_2fa_trust: '确认移除设备“{name}”并清除其 2FA 信任吗?',
txt_role_admin: '管理员',
txt_role_user: '用户',
txt_status_active: '正常',
txt_status_banned: '已封禁',
txt_status_inactive: '未激活',
txt_accessed_count_times: '已访问 {count} 次',
txt_add_website: '添加网站',
txt_added: '已添加',
txt_address: '地址',
txt_address_1: '地址 1',
txt_address_2: '地址 2',
txt_address_3: '地址 3',
txt_all_device_authorizations_revoked: '已撤销所有设备授权',
txt_all_invites_deleted: '已删除所有邀请码',
txt_all_sends: '所有发送',
txt_android: '安卓',
txt_are_you_sure_you_want_to_delete_count_selected_items: '确认删除所选的 {count} 个项目?',
txt_are_you_sure_you_want_to_delete_this_item: '确认删除此项目?',
txt_authenticator_key: '验证器密钥',
txt_brand: '品牌',
txt_bulk_delete_failed: '批量删除失败',
txt_bulk_delete_sends_failed: '批量删除发送失败',
txt_bulk_move_failed: '批量移动失败',
txt_cardholder_name: '持卡人姓名',
txt_change_password_failed: '修改密码失败',
txt_choose_destination_folder: '选择目标文件夹。',
txt_chrome_browser: 'Chrome 浏览器',
txt_chrome_extension: 'Chrome 扩展',
txt_city_town: '城市 / 城镇',
txt_code: '代码',
txt_country: '国家',
txt_create: '创建',
txt_create_folder_failed: '创建文件夹失败',
txt_create_item_failed: '创建项目失败',
txt_create_send_failed: '创建发送失败',
txt_current_new_password_is_required: '需要输入当前密码和新密码',
txt_decrypt_failed: '(解密失败)',
txt_decrypt_failed_2: '解密失败',
txt_delete_all_invite_codes_active_inactive: '删除所有邀请码(有效/无效)?',
txt_delete_all_invites: '删除所有邀请码',
txt_delete_item_failed: '删除项目失败',
txt_delete_send_failed: '删除发送失败',
txt_delete_this_user_and_all_user_data: '删除此用户及其所有数据?',
txt_delete_user: '删除用户',
txt_deleted_selected_items: '已删除所选项目',
txt_deleted_selected_sends: '已删除所选发送',
txt_device_authorization_revoked: '已撤销设备授权',
txt_device_removed: '设备已移除',
txt_disable_totp_failed: '禁用 TOTP 失败',
txt_download_failed: '下载失败',
txt_edge_browser: 'Edge 浏览器',
txt_edge_extension: 'Edge 扩展',
txt_email_password_and_recovery_code_are_required: '需要输入邮箱、密码和恢复代码',
txt_enable_totp_failed: '启用 TOTP 失败',
txt_encrypted_file: '加密文件',
txt_encrypted_file_2: '加密文件',
txt_enter_a_folder_name: '请输入文件夹名称',
txt_enter_master_password_to_disable_two_step_verification: '输入主密码以禁用两步验证',
txt_enter_master_password_to_view_this_item: '输入主密码以查看此项目',
txt_expiry: '有效期',
txt_expiry_month: '有效期月',
txt_expiry_year: '有效期年',
txt_failed_to_open_send: '打开发送失败',
txt_field_label_is_required: '字段标签不能为空',
txt_firefox_browser: 'Firefox 浏览器',
txt_firefox_extension: 'Firefox 扩展',
txt_folder_created: '文件夹已创建',
txt_folder_name_is_required: '文件夹名称不能为空',
txt_ie_browser: 'IE 浏览器',
txt_invite_code_optional: '邀请码(可选)',
txt_invite_created: '邀请码已创建',
txt_invite_revoked: '邀请码已撤销',
txt_ios: 'iOS',
txt_item: '项目',
txt_item_created: '项目已创建',
txt_item_deleted: '项目已删除',
txt_item_name_is_required: '项目名称不能为空',
txt_item_updated: '项目已更新',
txt_link_copied: '链接已复制',
txt_linked: '已关联',
txt_linux_desktop: 'Linux 桌面端',
txt_login_failed: '登录失败',
txt_login_success: '登录成功',
txt_macos_desktop: 'macOS 桌面端',
txt_master_password_changed_please_login_again: '主密码已修改,请重新登录',
txt_master_password_is_required: '主密码不能为空',
txt_master_password_is_required_2: '请输入主密码',
txt_master_password_must_be_at_least_12_chars: '主密码至少需要 12 个字符',
txt_moved_selected_items: '已移动所选项目',
txt_name_is_required: '名称不能为空',
txt_new_password_must_be_at_least_12_chars: '新密码至少需要 12 个字符',
txt_new_passwords_do_not_match: '两次输入的新密码不一致',
txt_no_devices_found: '未找到设备',
txt_number: '数字',
txt_opera_browser: 'Opera 浏览器',
txt_opera_extension: 'Opera 扩展',
txt_password_is_already_verified: '密码已验证',
txt_passwords_do_not_match: '两次输入的密码不一致',
txt_phone: '电话',
txt_please_input_email_and_password: '请输入邮箱和密码',
txt_please_input_master_password: '请输入主密码',
txt_please_input_totp_code: '请输入 TOTP 验证码',
txt_please_select_a_file: '请选择文件',
txt_postal_code: '邮政编码',
txt_profile_unavailable: '资料不可用',
txt_profile_updated: '资料已更新',
txt_recover_2fa_failed: '恢复 2FA 失败',
txt_recovered_but_auto_login_failed_please_sign_in: '已恢复,但自动登录失败,请手动登录',
txt_recovery_code_copied: '恢复代码已复制',
txt_recovery_code_is_empty: '恢复代码为空',
txt_recovery_code_loaded: '恢复代码已加载',
txt_refresh_in_seconds_s: '{seconds} 秒后刷新',
txt_registration_succeeded_please_sign_in: '注册成功,请登录',
txt_remove_device: '移除设备',
txt_revoke: '撤销',
txt_revoke_device_authorization: '撤销设备授权',
txt_save_profile_failed: '保存资料失败',
txt_secret_and_code_are_required: '密钥和代码不能为空',
txt_secret_copied: '密钥已复制',
txt_security_code: '安全码',
txt_security_code_cvv: '安全码 (CVV)',
txt_send_created: '发送已创建',
txt_send_deleted: '发送已删除',
txt_send_file: '发送文件',
txt_send_updated: '发送已更新',
txt_state_province: '省 / 州',
txt_text_2fa_recovered: '2FA 已恢复',
txt_text_2fa_recovered_new_recovery_code_code: '2FA 已恢复,新的恢复代码:{code}',
txt_text_3: '------',
txt_text_is_required: '文本不能为空',
txt_this_item_requires_master_password_every_time_before_viewing_details: '每次查看详情前均需输入主密码',
txt_this_link_is_missing_decryption_key: '此链接缺少解密密钥',
txt_this_send_is_password_protected: '此发送受密码保护',
txt_totp_disabled: 'TOTP 已禁用',
txt_totp_enabled: 'TOTP 已启用',
txt_totp_is_enabled_for_this_account: '此账户已启用 TOTP。',
txt_totp_verify_failed: 'TOTP 验证失败',
txt_trust_this_device_for_30_days: '信任此设备 30 天',
txt_type_type: '类型 {type}',
txt_unlock_details: '解锁详情',
txt_unlock_failed: '解锁失败',
txt_unlock_failed_master_password_is_incorrect: '解锁失败,主密码不正确。',
txt_unlocked: '已解锁',
txt_update_item_failed: '更新项目失败',
txt_update_send_failed: '更新发送失败',
txt_use_your_one_time_recovery_code_to_disable_two_step_verification: '使用一次性恢复代码禁用两步验证。',
txt_user_deleted: '用户已删除',
txt_user_status_updated: '用户状态已更新',
txt_vault_synced: '保险库已同步',
txt_verify: '验证',
txt_web: '网页',
txt_windows_desktop: 'Windows 桌面端',
};
messages['zh-CN'] = { ...messages.en, ...zhCNOverrides };
function resolveInitialLocale(): Locale {
try {
const saved = localStorage.getItem(LOCALE_STORAGE_KEY);
if (saved === 'en' || saved === 'zh-CN') return saved;
} catch {
// ignore storage errors
}
if (typeof navigator !== 'undefined') {
const langs = Array.isArray(navigator.languages) ? navigator.languages : [navigator.language];
for (const lang of langs) {
if (String(lang || '').toLowerCase().startsWith('zh')) return 'zh-CN';
}
}
return 'en';
}
let locale: Locale = resolveInitialLocale();
export type I18nParams = Record<string, string | number | null | undefined>;
export function t(key: string, params?: I18nParams): string {
const template = messages[locale][key] ?? key;
if (!params) return template;
return template.replace(/\{(\w+)\}/g, (_, name: string) => String(params[name] ?? ''));
}
export function getLocale(): Locale {
return locale;
}
export function setLocale(next: Locale): void {
locale = next;
try {
localStorage.setItem(LOCALE_STORAGE_KEY, next);
} catch {
// ignore storage errors
}
}