From 30761b6dadf161f48d9962a600bb9b6d4ac6dc5f Mon Sep 17 00:00:00 2001 From: Ryan Date: Thu, 23 Oct 2025 01:43:48 -0400 Subject: [PATCH] feat(i18n,auth): add Simplified Chinese (zh-CN) and expose in User Panel --- CHANGELOG.md | 13 ++ README.md | 2 +- public/js/adminPanel.js | 2 +- public/js/authModals.js | 13 +- public/js/i18n.js | 280 +++++++++++++++++++++++++++++++++++++++- 5 files changed, 305 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 379af8a..367a811 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## Changes 10/23/2025 (v1.6.2) + +feat(i18n,auth): add Simplified Chinese (zh-CN) and expose in User Panel + +- Add zh-CN locale to i18n.js with full key set. +- Introduce chinese_simplified label key across locales. +- Added some missing labels +- Update language selector mapping to include zh-CN (English/Spanish/French/German/简体中文). +- Wire zh-CN into Auth/User Panel (authModals) language dropdown. +- Fallback-safe rendering for language names when a key is missing. + +--- + ## Changes 10/23/2025 (v1.6.1) feat(ui): unified zone toggle + polished interactions for sidebar/top cards diff --git a/README.md b/README.md index 14e888b..f4b198e 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ With drag-and-drop uploads, in-browser editing, secure user logins (SSO & TOTP 2 - 🎨 **Responsive UI (Dark/Light Mode):** Modern, mobile-friendly design with persistent preferences (theme, layout, last folder, etc.). -- 🌐 **Internationalization:** English, Spanish, French, and German available. Community translations welcome. +- 🌐 **Internationalization:** English, Spanish, French, German & Simplified Chinese available. Community translations welcome. - ⚙️ **Lightweight & Self-Contained:** Runs on PHP 8.3+, no external DB required. Single-folder or Docker deployment with minimal footprint, optimized for Unraid and self-hosting. diff --git a/public/js/adminPanel.js b/public/js/adminPanel.js index b9ffee7..e1db784 100644 --- a/public/js/adminPanel.js +++ b/public/js/adminPanel.js @@ -1141,7 +1141,7 @@ async function loadUserFlagsList() { ${t("read_only")} ${t("disable_upload")} ${t("can_share")} - bypassOwnership + ${t("bypass_ownership")} ${rows || `${t("no_users_found")}`} diff --git a/public/js/authModals.js b/public/js/authModals.js index 9c04d06..5393401 100644 --- a/public/js/authModals.js +++ b/public/js/authModals.js @@ -328,10 +328,19 @@ export async function openUserPanel() { const langSel = document.createElement('select'); langSel.id = 'languageSelector'; langSel.className = 'form-select'; - ['en', 'es', 'fr', 'de'].forEach(code => { + const languages = [ + { code: 'en', labelKey: 'english', fallback: 'English' }, + { code: 'es', labelKey: 'spanish', fallback: 'Español' }, + { code: 'fr', labelKey: 'french', fallback: 'Français' }, + { code: 'de', labelKey: 'german', fallback: 'Deutsch' }, + { code: 'zh-CN', labelKey: 'chinese_simplified', fallback: '简体中文' }, + ]; + + languages.forEach(({ code, labelKey, fallback }) => { const opt = document.createElement('option'); opt.value = code; - opt.textContent = t(code === 'en' ? 'english' : code === 'es' ? 'spanish' : code === 'fr' ? 'french' : 'german'); + // use i18n if available, otherwise fallback + opt.textContent = (typeof t === 'function' ? t(labelKey) : '') || fallback; langSel.appendChild(opt); }); langSel.value = localStorage.getItem('language') || 'en'; diff --git a/public/js/i18n.js b/public/js/i18n.js index f3ba762..b1eef29 100644 --- a/public/js/i18n.js +++ b/public/js/i18n.js @@ -216,6 +216,7 @@ const translations = { "spanish": "Spanish", "french": "French", "german": "German", + "chinese_simplified": "Chinese (Simplified)", "use_totp_code_instead": "Use TOTP Code instead", "submit_recovery_code": "Submit Recovery Code", "please_enter_recovery_code": "Please enter your recovery code.", @@ -275,7 +276,13 @@ const translations = { "newfile_placeholder": "New file name", "file_created_successfully": "File created successfully!", "error_creating_file": "Error creating file", - "file_created": "File created successfully!" + "file_created": "File created successfully!", + "no_access_to_resource": "You do not have access to this resource.", + "can_share": "Can Share", + "bypass_ownership": "Bypass Ownership", + "error_loading_user_grants": "Error loading user grants", + "click_to_edit": "Click to edit", + "folder_access": "Folder Access" }, es: { "please_log_in_to_continue": "Por favor, inicie sesión para continuar.", @@ -458,6 +465,7 @@ const translations = { "spanish": "Español", "french": "Francés", "german": "Alemán", + "chinese_simplified": "Chino (simplificado)", "use_totp_code_instead": "Usar código TOTP en su lugar", "submit_recovery_code": "Enviar código de recuperación", "please_enter_recovery_code": "Por favor, ingrese su código de recuperación.", @@ -686,6 +694,7 @@ const translations = { "spanish": "Espagnol", "french": "Français", "german": "Allemand", + "chinese_simplified": "Chinois (simplifié)", "use_totp_code_instead": "Utiliser le code TOTP à la place", "submit_recovery_code": "Soumettre le code de récupération", "please_enter_recovery_code": "Veuillez entrer votre code de récupération.", @@ -923,6 +932,7 @@ const translations = { "spanish": "Spanisch", "french": "Französisch", "german": "Deutsch", + "chinese_simplified": "Chinesisch (vereinfacht)", "use_totp_code_instead": "Stattdessen TOTP-Code verwenden", "submit_recovery_code": "Wiederherstellungscode absenden", "please_enter_recovery_code": "Bitte geben Sie Ihren Wiederherstellungscode ein.", @@ -972,7 +982,275 @@ const translations = { "show": "Zeige", "items_per_page": "elemente pro seite", "columns": "Spalten" + }, + "zh-CN": { + "please_log_in_to_continue": "请登录以继续。", + "no_files_selected": "未选择文件。", + "confirm_delete_files": "确定要删除所选的 {count} 个文件吗?", + "element_not_found": "未找到 ID 为 \"{id}\" 的元素。", + "search_placeholder": "搜索文件、标签和上传者…", + "search_placeholder_advanced": "高级搜索:文件、标签、上传者和内容…", + "basic_search_tooltip": "基础搜索:按文件名、标签和上传者搜索。", + "advanced_search_tooltip": "高级搜索:包括文件内容、文件名、标签和上传者。", + "file_name": "文件名", + "date_modified": "修改日期", + "upload_date": "上传日期", + "file_size": "文件大小", + "uploader": "上传者", + "enter_totp_code": "输入 TOTP 验证码", + "use_recovery_code_instead": "改用恢复代码", + "enter_recovery_code": "输入恢复代码", + "editing": "正在编辑", + "decrease_font": "A-", + "increase_font": "A+", + "save": "保存", + "close": "关闭", + "no_files_found": "未找到文件。", + "switch_to_table_view": "切换到表格视图", + "switch_to_gallery_view": "切换到图库视图", + "share_file": "分享文件", + "set_expiration": "设置到期时间:", + "password_optional": "密码(可选):", + "generate_share_link": "生成分享链接", + "shareable_link": "可分享链接:", + "copy_link": "复制链接", + "tag_file": "标记文件", + "tag_name": "标签名称:", + "tag_color": "标签颜色:", + "save_tag": "保存标签", + "light_mode": "浅色模式", + "dark_mode": "深色模式", + "upload_instruction": "将文件/文件夹拖到此处,或点击“选择文件”", + "no_files_selected_default": "未选择文件", + "choose_files": "选择文件", + "delete_selected": "删除所选", + "copy_selected": "复制所选", + "move_selected": "移动所选", + "tag_selected": "标记所选", + "download_zip": "下载 ZIP", + "extract_zip": "解压 ZIP", + "preview": "预览", + "edit": "编辑", + "rename": "重命名", + "trash_empty": "回收站为空。", + "no_trash_selected": "未选择要还原的回收站项目。", + + "title": "FileRise", + "header_title": "FileRise", + "header_title_text": "标题文本", + "logout": "退出登录", + "change_password": "更改密码", + "restore_text": "还原或", + "delete_text": "删除回收站项目", + "restore_selected": "还原所选", + "restore_all": "全部还原", + "delete_selected_trash": "删除所选", + "delete_all": "全部删除", + "upload_header": "上传文件/文件夹", + + "folder_navigation": "文件夹导航与管理", + "create_folder": "创建文件夹", + "create_folder_title": "创建文件夹", + "enter_folder_name": "输入文件夹名称", + "cancel": "取消", + "create": "创建", + "rename_folder": "重命名文件夹", + "rename_folder_title": "重命名文件夹", + "rename_folder_placeholder": "输入新的文件夹名称", + "delete_folder": "删除文件夹", + "delete_folder_title": "删除文件夹", + "delete_folder_message": "确定要删除此文件夹吗?", + "folder_help": "文件夹帮助", + "folder_help_item_1": "点击文件夹以查看其中的文件。", + "folder_help_item_2": "使用 [-] 折叠,使用 [+] 展开文件夹。", + "folder_help_item_3": "选择一个文件夹并点击“创建文件夹”以添加子文件夹。", + "folder_help_item_4": "要重命名或删除文件夹,请选择后点击相应按钮。", + + "actions": "操作", + "file_list_title": "文件列表(根目录)", + "files_in": "文件位于", + "delete_files": "删除文件", + "delete_selected_files_title": "删除所选文件", + "delete_files_message": "确定要删除所选文件吗?", + "copy_files": "复制文件", + "copy_files_title": "复制所选文件", + "copy_files_message": "选择目标文件夹以复制所选文件:", + "move_files": "移动文件", + "move_files_title": "移动所选文件", + "move_files_message": "选择目标文件夹以移动所选文件:", + "move": "移动", + "extract_zip_button": "解压 ZIP", + "download_zip_title": "将所选文件打包为 ZIP 下载", + "download_zip_prompt": "输入 ZIP 文件名:", + "zip_placeholder": "files.zip", + "share": "分享", + "total_files": "文件总数", + "total_size": "总大小", + "prev": "上一页", + "next": "下一页", + "page": "第", + "of": "页,共", + + "login": "登录", + "remember_me": "记住我", + "login_oidc": "使用 OIDC 登录", + "basic_http_login": "使用基本 HTTP 登录", + + "change_password_title": "更改密码", + "old_password": "旧密码", + "new_password": "新密码", + "confirm_new_password": "确认新密码", + + "create_new_user_title": "创建新用户", + "username": "用户名:", + "password": "密码:", + "enter_password": "密码", + "preparing_download": "正在准备下载…", + "download_file": "下载文件", + "confirm_or_change_filename": "确认或修改下载文件名:", + "filename": "文件名", + "download": "下载", + "grant_admin": "授予管理员权限", + "save_user": "保存用户", + + "remove_user_title": "删除用户", + "select_user_remove": "选择要删除的用户:", + "delete_user": "删除用户", + + "rename_file_title": "重命名文件", + "rename_file_placeholder": "输入新的文件名", + + "share_folder": "分享文件夹", + "allow_uploads": "允许上传", + "share_link_generated": "已生成分享链接", + "error_generating_share_link": "生成分享链接时出错", + "custom": "自定义", + "duration": "持续时间", + "seconds": "秒", + "minutes": "分钟", + "hours": "小时", + "days": "天", + "custom_duration_warning": "⚠️ 使用较长的到期时间可能存在安全风险,请谨慎使用。", + + "folder_share": "分享文件夹", + + "yes": "是", + "no": "否", + "unsaved_changes_confirm": "您有未保存的更改,确定要关闭而不保存吗?", + "delete": "删除", + "upload": "上传", + "copy": "复制", + "extract": "解压", + "user": "用户:", + "unknown_error": "未知错误", + "link_copied": "链接已复制到剪贴板", + "weeks": "周", + "months": "月", + + "dark_mode_toggle": "深色模式", + "light_mode_toggle": "浅色模式", + "switch_to_light_mode": "切换到浅色模式", + "switch_to_dark_mode": "切换到深色模式", + + "header_settings": "标题设置", + "shared_max_upload_size_bytes_title": "共享最大上传大小", + "shared_max_upload_size_bytes": "共享最大上传大小(字节)", + "max_bytes_shared_uploads_note": "请输入共享文件夹上传的最大允许字节数", + "manage_shared_links": "管理分享链接", + "folder_shares": "文件夹分享", + "file_shares": "文件分享", + "loading": "正在加载…", + "error_loading_share_links": "加载分享链接时出错", + "share_deleted_successfully": "分享已成功删除", + "error_deleting_share": "删除分享时出错", + "password_protected": "受密码保护", + "no_shared_links_available": "暂无可用的分享链接", + + "admin_panel": "管理员面板", + "user_panel": "用户面板", + "user_settings": "用户设置", + "save_profile_picture": "保存头像", + "please_select_picture": "请选择图片", + "profile_picture_updated": "头像已更新", + "error_updating_picture": "更新头像时出错", + "trash_restore_delete": "回收站恢复/删除", + "totp_settings": "TOTP 设置", + "enable_totp": "启用 TOTP", + "language": "语言", + "select_language": "选择语言", + "english": "英语", + "spanish": "西班牙语", + "french": "法语", + "german": "德语", + "chinese_simplified": "简体中文", + "use_totp_code_instead": "改用 TOTP 验证码", + "submit_recovery_code": "提交恢复代码", + "please_enter_recovery_code": "请输入您的恢复代码。", + "recovery_code_verification_failed": "恢复代码验证失败", + "error_verifying_recovery_code": "验证恢复代码时出错", + "totp_verification_failed": "TOTP 验证失败", + "error_verifying_totp_code": "验证 TOTP 代码时出错", + "totp_setup": "TOTP 设置", + "scan_qr_code": "请使用验证器应用扫描此二维码。", + "enter_totp_confirmation": "输入应用生成的 6 位验证码以确认设置:", + "confirm": "确认", + "please_enter_valid_code": "请输入有效的 6 位验证码。", + "totp_enabled_successfully": "TOTP 启用成功。", + "error_generating_recovery_code": "生成恢复代码时出错", + "error_loading_qr_code": "加载二维码时出错。", + "error_disabling_totp_setting": "禁用 TOTP 设置时出错", + "user_management": "用户管理", + "add_user": "添加用户", + "remove_user": "删除用户", + "user_permissions": "用户权限", + "oidc_configuration": "OIDC 配置", + "oidc_provider_url": "OIDC 提供者 URL", + "oidc_client_id": "OIDC 客户端 ID", + "oidc_client_secret": "OIDC 客户端密钥", + "oidc_redirect_uri": "OIDC 重定向 URI", + "global_totp_settings": "全局 TOTP 设置", + "global_otpauth_url": "全局 OTPAuth URL", + "login_options": "登录选项", + "disable_login_form": "禁用登录表单", + "disable_basic_http_auth": "禁用基本 HTTP 认证", + "disable_oidc_login": "禁用 OIDC 登录", + "save_settings": "保存设置", + "at_least_one_login_method": "至少保留一种登录方式。", + "settings_updated_successfully": "设置已成功更新。", + "error_updating_settings": "更新设置时出错", + "user_permissions_updated_successfully": "用户权限已成功更新。", + "error_updating_permissions": "更新权限时出错", + "no_users_found": "未找到用户。", + "user_folder_only": "仅限用户文件夹", + "read_only": "只读", + "disable_upload": "禁用上传", + "error_loading_users": "加载用户时出错", + "save_permissions": "保存权限", + "your_recovery_code": "您的恢复代码", + "please_save_recovery_code": "请妥善保存此代码。此代码仅显示一次且只能使用一次。", + "ok": "确定", + "show": "显示", + "items_per_page": "每页项目数", + "columns": "列", + "row_height": "行高", + "api_docs": "API 文档", + "show_folders_above_files": "在文件上方显示文件夹", + "display": "显示", + "create_file": "创建文件", + "create_new_file": "创建新文件", + "enter_file_name": "输入文件名", + "newfile_placeholder": "新文件名", + "file_created_successfully": "文件创建成功!", + "error_creating_file": "创建文件时出错", + "file_created": "文件创建成功!", + "no_access_to_resource": "您无权访问此资源。", + "can_share": "可分享", + "bypass_ownership": "绕过所有权限制", + "error_loading_user_grants": "加载用户授权时出错", + "click_to_edit": "点击编辑", + "folder_access": "文件夹访问" } + }; let currentLocale = 'en';