diff --git a/nginx.conf b/nginx.conf index 76985be..2f0e743 100644 --- a/nginx.conf +++ b/nginx.conf @@ -23,7 +23,7 @@ http { root /usr/share/nginx/html; index index.html; - rewrite ^/(en|de)/(.*)$ /$2 last; + rewrite ^/(en|de|zh)/(.*)$ /$2 last; location / { try_files $uri $uri/ /index.html; diff --git a/public/locales/zh/common.json b/public/locales/zh/common.json new file mode 100644 index 0000000..c588ca9 --- /dev/null +++ b/public/locales/zh/common.json @@ -0,0 +1,275 @@ +{ + "nav": { + "home": "首页", + "about": "关于我们", + "contact": "联系我们", + "licensing": "许可", + "allTools": "所有工具", + "openMainMenu": "打开主菜单", + "language": "语言" + }, + "hero": { + "title": "专为隐私打造的", + "pdfToolkit": "PDF 工具箱", + "builtForPrivacy": " ", + "noSignups": "无需注册", + "unlimitedUse": "无限使用", + "worksOffline": "离线可用", + "startUsing": "立即开始" + }, + "usedBy": { + "title": "被众多公司和个人信赖,包括" + }, + "features": { + "title": "为什么选择", + "bentoPdf": "BentoPDF?", + "noSignup": { + "title": "无需注册", + "description": "即刻开始,无需账户或电子邮件。" + }, + "noUploads": { + "title": "无需上传", + "description": "100% 客户端处理,您的文件从未离开您的设备。" + }, + "foreverFree": { + "title": "永久免费", + "description": "所有工具免费,无试用期,无付费墙。" + }, + "noLimits": { + "title": "无限制", + "description": "随心使用,无任何隐形限制。" + }, + "batchProcessing": { + "title": "批量处理", + "description": "一次处理无限数量的 PDF 文件。" + }, + "lightningFast": { + "title": "极速处理", + "description": "瞬间处理 PDF,无需等待。" + } + }, + "tools": { + "title": "开始使用", + "toolsLabel": "工具", + "subtitle": "点击工具以打开文件上传", + "searchPlaceholder": "搜索工具 (例如 '合并', '分割'...)", + "backToTools": "返回工具列表" + }, + "upload": { + "clickToSelect": "点击选择文件", + "orDragAndDrop": "或将文件拖放到此处", + "pdfOrImages": "PDF 或图片", + "filesNeverLeave": "您的文件从未离开您的设备。", + "addMore": "添加更多文件", + "clearAll": "清空所有" + }, + "loader": { + "processing": "处理中..." + }, + "alert": { + "title": "提示", + "ok": "确定" + }, + "preview": { + "title": "文档预览", + "downloadAsPdf": "下载 PDF", + "close": "关闭" + }, + "settings": { + "title": "设置", + "shortcuts": "快捷键", + "preferences": "偏好设置", + "displayPreferences": "显示设置", + "searchShortcuts": "搜索快捷键...", + "shortcutsInfo": "按下并按住按键以设置快捷键。更改将自动保存。", + "shortcutsWarning": "⚠️ 避免使用通用的浏览器快捷键 (Cmd/Ctrl+W, Cmd/Ctrl+T, Cmd/Ctrl+N 等),因为它们可能无法稳定工作。", + "import": "导入", + "export": "导出", + "resetToDefaults": "恢复默认", + "fullWidthMode": "全宽模式", + "fullWidthDescription": "使用全屏宽度展示所有工具,而非居中显示", + "settingsAutoSaved": "设置已自动保存", + "clickToSet": "点击设置", + "pressKeys": "按下按键...", + "warnings": { + "alreadyInUse": "快捷键已被使用", + "assignedTo": "已分配给:", + "chooseDifferent": "请选择其他快捷键。", + "reserved": "保留快捷键警告", + "commonlyUsed": "通常用于:", + "unreliable": "此快捷键可能无法稳定工作,或与浏览器/系统快捷键冲突。", + "useAnyway": "仍要使用吗?", + "resetTitle": "重置快捷键", + "resetMessage": "确定要将所有快捷键重置为默认值吗?

此操作无法撤销。", + "importSuccessTitle": "导入成功", + "importSuccessMessage": "快捷键导入成功!", + "importFailTitle": "导入失败", + "importFailMessage": "导入快捷键失败。文件格式无效。" + } + }, + "warning": { + "title": "警告", + "cancel": "取消", + "proceed": "继续" + }, + "compliance": { + "title": "您的数据从未离开您的设备", + "weKeep": "我们会保持", + "yourInfoSafe": "您的信息安全", + "byFollowingStandards": ",遵循全球安全标准。", + "processingLocal": "所有处理都在您的设备上本地进行。", + "gdpr": { + "title": "GDPR 合规", + "description": "保护欧盟境内个人的个人数据和隐私。" + }, + "ccpa": { + "title": "CCPA 合规", + "description": "赋予加州居民对其个人信息的收集、使用和共享的权利。" + }, + "hipaa": { + "title": "HIPAA 合规", + "description": "制定美国医疗系统中处理敏感健康信息的保障措施。" + } + }, + "faq": { + "title": "常见", + "questions": "问题", + "isFree": { + "question": "BentoPDF 真的免费吗?", + "answer": "是的,完全免费。BentoPDF 上的所有工具均可 100% 免费使用,没有文件限制,无需注册,也没有水印。我们相信每个人都应该能够使用简单、强大的 PDF 工具,而无需通过付费墙。" + }, + "areFilesSecure": { + "question": "我的文件安全吗?它们在哪里处理?", + "answer": "您的文件非常安全,因为它们从未离开您的电脑。所有处理都直接在您的网络浏览器(客户端)中进行。我们从不将您的文件上传到服务器,因此您可以对文档保持完全的隐私和控制。" + }, + "platforms": { + "question": "它适用于 Mac、Windows 和手机吗?", + "answer": "是的!由于 BentoPDF 完全在您的浏览器中运行,因此它适用于任何带有现代网络浏览器的操作系统,包括 Windows、macOS、Linux、iOS 和 Android。" + }, + "gdprCompliant": { + "question": "BentoPDF 符合 GDPR 吗?", + "answer": "是的。BentoPDF 完全符合 GDPR。由于所有文件处理都在您的浏览器中本地进行,并且我们从不收集或将您的文件传输到任何服务器,因此我们无法访问您的数据。这确保您始终掌控您的文档。" + }, + "dataStorage": { + "question": "你们会存储或跟踪我的任何文件吗?", + "answer": "不。我们从不存储、跟踪或记录您的文件。您在 BentoPDF 上所做的所有操作都在您的浏览器内存中进行,并在您关闭页面后消失。没有上传,没有历史记录,也没有涉及服务器。" + }, + "different": { + "question": "BentoPDF 与其他 PDF 工具有何不同?", + "answer": "大多数 PDF 工具将您的文件上传到服务器进行处理。BentoPDF 从不这样做。我们使用安全、现代的网络技术直接在您的浏览器中处理您的文件。这意味着更快的性能、更强的隐私和完全的安心。" + }, + "browserBased": { + "question": "基于浏览器的处理如何保护我的安全?", + "answer": "通过完全在您的浏览器内部运行,BentoPDF 确保您的文件从未离开您的设备。这消除了服务器黑客攻击、数据泄露或未经授权访问的风险。您的文件始终属于您。" + }, + "analytics": { + "question": "你们使用 Cookie 或分析来跟踪我吗?", + "answer": "我们关心您的隐私。BentoPDF 不会跟踪个人信息。我们仅使用 Simple Analytics 查看匿名访问计数。这意味着我们可以知道有多少用户访问我们的网站,但我们永远不知道您是谁。Simple Analytics 完全符合 GDPR 并尊重您的隐私。" + } + }, + "testimonials": { + "title": "我们的", + "users": "用户", + "say": "评价" + }, + "support": { + "title": "喜欢这个项目?", + "description": "BentoPDF 是一个充满激情的项目,旨在为每个人提供免费、私密且强大的 PDF 工具箱。如果您觉得它有用,请考虑支持它的开发。每一杯咖啡都是莫大的支持!", + "buyMeCoffee": "请我喝杯咖啡" + }, + "footer": { + "copyright": "© 2025 BentoPDF. 保留所有权利。", + "version": "版本", + "company": "公司", + "aboutUs": "关于我们", + "faqLink": "常见问题", + "contactUs": "联系我们", + "legal": "法律", + "termsAndConditions": "服务条款", + "privacyPolicy": "隐私政策", + "followUs": "关注我们" + }, + "merge": { + "title": "合并 PDF", + "description": "合并整个文件,或选择特定页面合并到新文档中。", + "fileMode": "文件模式", + "pageMode": "页面模式", + "howItWorks": "使用说明:", + "fileModeInstructions": [ + "点击并拖动图标以更改文件的顺序。", + "在每个文件的 '页码' 框中,您可以指定范围(例如 '1-3, 5')以仅合并这些页面。", + "将 '页码' 框留空以包含该文件的所有页面。" + ], + "pageModeInstructions": [ + "您上传的 PDF 的所有页面显示在下方。", + "只需拖放单个页面缩略图,即可为您新文件对页面进行排序。" + ], + "mergePdfs": "合并 PDF" + }, + "common": { + "page": "页", + "pages": "页", + "of": " / ", + "download": "下载", + "cancel": "取消", + "save": "保存", + "delete": "删除", + "edit": "编辑", + "add": "添加", + "remove": "移除", + "loading": "加载中...", + "error": "错误", + "success": "成功", + "file": "文件", + "files": "文件" + }, + "about": { + "hero": { + "title": "我们相信 PDF 工具应该是", + "subtitle": "快速、私密且免费的。", + "noCompromises": "绝不妥协。" + }, + "mission": { + "title": "我们的使命", + "description": "提供最全面的 PDF 工具箱,尊重您的隐私,且永不收费。我们相信基本的文档工具应该对所有人、在任何地方都触手可及,没有任何障碍。" + }, + "philosophy": { + "label": "我们的核心理念", + "title": "隐私至上。始终如一。", + "description": "在数据被商品化的时代,我们采取不同的方式。BentoPDF 工具的所有处理都在您的浏览器本地进行。这意味着您的文件从未接触我们的服务器,我们从不查看您的文档,也不跟踪您的操作。您的文档保持绝对的私密性。这不仅是一项功能;这是我们的基石。" + }, + "whyBentopdf": { + "title": "为什么选择", + "speed": { + "title": "为速度而生", + "description": "无需等待上传或从服务器下载。通过使用 WebAssembly 等现代网络技术直接在您的浏览器中处理文件,我们为所有工具提供了无与伦比的速度。" + }, + "free": { + "title": "完全免费", + "description": "无试用,无订阅,无隐藏费用,也没有被锁定的 '高级' 功能。我们相信强大的 PDF 工具应该是一种公共设施,而不是盈利中心。" + }, + "noAccount": { + "title": "无需账户", + "description": "立即开始使用任何工具。我们不需要您的电子邮件、密码或任何个人信息。您的工作流程应该是无摩擦且匿名的。" + }, + "openSource": { + "title": "开源精神", + "description": "以透明度为核心构建。我们利用了像 PDF-lib 和 PDF.js 这样优秀的开源库,并相信社区驱动的力量能使强大的工具惠及每一个人。" + } + }, + "cta": { + "title": "准备好开始了吗?", + "description": "加入成千上万信任 BentoPDF 满足日常文档需求的用户。体验隐私和性能带来的不同。", + "button": "探索所有工具" + } + }, + "contact": { + "title": "联系我们", + "subtitle": "我们很乐意听到您的声音。无论您有问题、反馈还是功能请求,请随时联系我们。", + "email": "您可以直接通过电子邮件联系我们:" + }, + "licensing": { + "title": "许可适用", + "subtitle": "选择适合您需求的许可。" + } +} \ No newline at end of file diff --git a/public/locales/zh/tools.json b/public/locales/zh/tools.json new file mode 100644 index 0000000..a64ed0f --- /dev/null +++ b/public/locales/zh/tools.json @@ -0,0 +1,279 @@ +{ + "categories": { + "popularTools": "热门工具", + "editAnnotate": "编辑与注释", + "convertToPdf": "转换为 PDF", + "convertFromPdf": "从 PDF 转换", + "organizeManage": "组织与管理", + "optimizeRepair": "优化与修复", + "securePdf": "安全 PDF" + }, + "pdfMultiTool": { + "name": "PDF 多功能工具", + "subtitle": "在一个统一的界面中合并、分割、组织、删除、旋转、添加空白页、提取和复制。" + }, + "mergePdf": { + "name": "合并 PDF", + "subtitle": "将多个 PDF 合并为一个文件。保留书签。" + }, + "splitPdf": { + "name": "分割 PDF", + "subtitle": "将指定范围的页面提取到新 PDF 中。" + }, + "compressPdf": { + "name": "压缩 PDF", + "subtitle": "减小您的 PDF 文件大小。" + }, + "pdfEditor": { + "name": "PDF 编辑器", + "subtitle": "注释、高亮、涂黑、评论、添加形状/图片、搜索和查看 PDF。" + }, + "jpgToPdf": { + "name": "JPG 转 PDF", + "subtitle": "从一张或多张 JPG 图片创建 PDF。" + }, + "signPdf": { + "name": "签署 PDF", + "subtitle": "绘制、键入或上传您的签名。" + }, + "cropPdf": { + "name": "裁剪 PDF", + "subtitle": "修剪 PDF 中每一页的边距。" + }, + "extractPages": { + "name": "提取页面", + "subtitle": "将选定的页面保存为新文件。" + }, + "duplicateOrganize": { + "name": "复制与组织", + "subtitle": "复制、重新排序和删除页面。" + }, + "deletePages": { + "name": "删除页面", + "subtitle": "自您的文档中移除特定页面。" + }, + "editBookmarks": { + "name": "编辑书签", + "subtitle": "添加、编辑、导入、删除和提取 PDF 书签。" + }, + "tableOfContents": { + "name": "目录", + "subtitle": "根据 PDF 书签生成目录页。" + }, + "pageNumbers": { + "name": "页码", + "subtitle": "将页码插入到您的文档中。" + }, + "addWatermark": { + "name": "添加水印", + "subtitle": "在您的 PDF 页面上添加文字或图片水印。" + }, + "headerFooter": { + "name": "页眉和页脚", + "subtitle": "在页面顶部和底部添加文字。" + }, + "invertColors": { + "name": "反转颜色", + "subtitle": "创建您的 PDF 的“暗黑模式”版本。" + }, + "backgroundColor": { + "name": "背景颜色", + "subtitle": "更改您的 PDF 的背景颜色。" + }, + "changeTextColor": { + "name": "更改文本颜色", + "subtitle": "更改您 PDF 中文本的颜色。" + }, + "addStamps": { + "name": "添加印章", + "subtitle": "使用注释工具栏向您的 PDF 添加图片印章。" + }, + "removeAnnotations": { + "name": "移除注释", + "subtitle": "移除评论、高亮和链接。" + }, + "pdfFormFiller": { + "name": "PDF 表单填写器", + "subtitle": "直接在浏览器中填写表单。也支持 XFA 表单。" + }, + "createPdfForm": { + "name": "创建 PDF 表单", + "subtitle": "使用拖放文本字段创建可填写的 PDF 表单。" + }, + "removeBlankPages": { + "name": "移除空白页", + "subtitle": "自动检测并删除空白页。" + }, + "imageToPdf": { + "name": "图片转 PDF", + "subtitle": "将 JPG, PNG, WebP, BMP, TIFF, SVG, HEIC 转换为 PDF。" + }, + "pngToPdf": { + "name": "PNG 转 PDF", + "subtitle": "从一张或多张 PNG 图片创建 PDF。" + }, + "webpToPdf": { + "name": "WebP 转 PDF", + "subtitle": "从一张或多张 WebP 图片创建 PDF。" + }, + "svgToPdf": { + "name": "SVG 转 PDF", + "subtitle": "从一张或多张 SVG 图片创建 PDF。" + }, + "bmpToPdf": { + "name": "BMP 转 PDF", + "subtitle": "从一张或多张 BMP 图片创建 PDF。" + }, + "heicToPdf": { + "name": "HEIC 转 PDF", + "subtitle": "从一张或多张 HEIC 图片创建 PDF。" + }, + "tiffToPdf": { + "name": "TIFF 转 PDF", + "subtitle": "从一张或多张 TIFF 图片创建 PDF。" + }, + "textToPdf": { + "name": "文本转 PDF", + "subtitle": "将纯文本文件转换为 PDF。" + }, + "jsonToPdf": { + "name": "JSON 转 PDF", + "subtitle": "将 JSON 文件转换为 PDF 格式。" + }, + "pdfToJpg": { + "name": "PDF 转 JPG", + "subtitle": "将每一页 PDF 转换为 JPG 图片。" + }, + "pdfToPng": { + "name": "PDF 转 PNG", + "subtitle": "将每一页 PDF 转换为 PNG 图片。" + }, + "pdfToWebp": { + "name": "PDF 转 WebP", + "subtitle": "将每一页 PDF 转换为 WebP 图片。" + }, + "pdfToBmp": { + "name": "PDF 转 BMP", + "subtitle": "将每一页 PDF 转换为 BMP 图片。" + }, + "pdfToTiff": { + "name": "PDF 转 TIFF", + "subtitle": "将每一页 PDF 转换为 TIFF 图片。" + }, + "pdfToGreyscale": { + "name": "PDF 转 灰度", + "subtitle": "将所有颜色转换为黑白。" + }, + "pdfToJson": { + "name": "PDF 转 JSON", + "subtitle": "将 PDF 文件转换为 JSON 格式。" + }, + "ocrPdf": { + "name": "OCR PDF", + "subtitle": "使 PDF 可搜索和可复制。" + }, + "alternateMix": { + "name": "交替混合页面", + "subtitle": "通过交替每个 PDF 的页面来合并 PDF。保留书签。" + }, + "addAttachments": { + "name": "添加附件", + "subtitle": "将一个或多个文件嵌入到您的 PDF 中。" + }, + "extractAttachments": { + "name": "提取附件", + "subtitle": "从 PDF 中提取所有嵌入的文件为 ZIP。" + }, + "editAttachments": { + "name": "编辑附件", + "subtitle": "查看或移除 PDF 中的附件。" + }, + "dividePages": { + "name": "分割页面", + "subtitle": "水平或垂直分割页面。" + }, + "addBlankPage": { + "name": "添加空白页", + "subtitle": "在 PDF 的任意位置插入空白页。" + }, + "reversePages": { + "name": "反转页面", + "subtitle": "反转文档中所有页面的顺序。" + }, + "rotatePdf": { + "name": "旋转 PDF", + "subtitle": "以 90 度增量旋转页面。" + }, + "nUpPdf": { + "name": "N-Up PDF", + "subtitle": "将多页排列在单张纸上。" + }, + "combineToSinglePage": { + "name": "合并为单页", + "subtitle": "将所有页面拼接成一个连续的滚动页面。" + }, + "viewMetadata": { + "name": "查看元数据", + "subtitle": "检查 PDF 的隐藏属性。" + }, + "editMetadata": { + "name": "编辑元数据", + "subtitle": "更改作者、标题和其他属性。" + }, + "pdfsToZip": { + "name": "PDF 转 ZIP", + "subtitle": "将多个 PDF 文件打包成一个 ZIP 归档。" + }, + "comparePdfs": { + "name": "比较 PDF", + "subtitle": "并排比较两个 PDF。" + }, + "posterizePdf": { + "name": "海报化 PDF", + "subtitle": "将大页面分割成多个小页面。" + }, + "fixPageSize": { + "name": "修复页面尺寸", + "subtitle": "将所有页面标准化为统一尺寸。" + }, + "linearizePdf": { + "name": "线性化 PDF", + "subtitle": "优化 PDF 以便快速网络查看。" + }, + "pageDimensions": { + "name": "页面尺寸", + "subtitle": "分析页面大小、方向和单位。" + }, + "removeRestrictions": { + "name": "移除限制", + "subtitle": "移除与数字签名 PDF 文件相关的密码保护和安全限制。" + }, + "repairPdf": { + "name": "修复 PDF", + "subtitle": "从损坏的 PDF 文件中恢复数据。" + }, + "encryptPdf": { + "name": "加密 PDF", + "subtitle": "通过添加密码锁定您的 PDF。" + }, + "sanitizePdf": { + "name": "清理 PDF", + "subtitle": "移除元数据、注释、脚本等。" + }, + "decryptPdf": { + "name": "解密 PDF", + "subtitle": "通过移除密码保护解锁 PDF。" + }, + "flattenPdf": { + "name": "扁平化 PDF", + "subtitle": "使表单字段和注释不可编辑。" + }, + "removeMetadata": { + "name": "移除元数据", + "subtitle": "从 PDF 中剥离隐藏数据。" + }, + "changePermissions": { + "name": "更改权限", + "subtitle": "设置或更改 PDF 上的用户权限。" + } +} \ No newline at end of file diff --git a/src/js/i18n/i18n.ts b/src/js/i18n/i18n.ts index fe1c7c5..5fb9ed7 100644 --- a/src/js/i18n/i18n.ts +++ b/src/js/i18n/i18n.ts @@ -3,17 +3,18 @@ import LanguageDetector from 'i18next-browser-languagedetector'; import HttpBackend from 'i18next-http-backend'; // Supported languages -export const supportedLanguages = ['en', 'de'] as const; +export const supportedLanguages = ['en', 'de', 'zh'] as const; export type SupportedLanguage = (typeof supportedLanguages)[number]; export const languageNames: Record = { en: 'English', de: 'Deutsch', + zh: '中文', }; export const getLanguageFromUrl = (): SupportedLanguage => { const path = window.location.pathname; - const langMatch = path.match(/^\/(en|de)(?:\/|$)/); + const langMatch = path.match(/^\/(en|de|zh)(?:\/|$)/); if (langMatch && supportedLanguages.includes(langMatch[1] as SupportedLanguage)) { return langMatch[1] as SupportedLanguage; } @@ -69,9 +70,9 @@ export const changeLanguage = (lang: SupportedLanguage): void => { const currentLang = getLanguageFromUrl(); let newPath: string; - if (currentPath.match(/^\/(en|de)\//)) { - newPath = currentPath.replace(/^\/(en|de)\//, `/${lang}/`); - } else if (currentPath.match(/^\/(en|de)$/)) { + if (currentPath.match(/^\/(en|de|zh)\//)) { + newPath = currentPath.replace(/^\/(en|de|zh)\//, `/${lang}/`); + } else if (currentPath.match(/^\/(en|de|zh)$/)) { newPath = `/${lang}`; } else { newPath = `/${lang}${currentPath}`; @@ -133,7 +134,7 @@ export const rewriteLinks = (): void => { return; } - if (href.match(/^\/(en|de)\//)) { + if (href.match(/^\/(en|de|zh)\//)) { return; } let newHref: string; diff --git a/vite.config.ts b/vite.config.ts index e3a2b10..262383c 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -11,7 +11,7 @@ function pagesRewritePlugin(): Plugin { server.middlewares.use((req, res, next) => { const url = req.url?.split('?')[0] || ''; - const langMatch = url.match(/^\/(en|de)(\/.*)?$/); + const langMatch = url.match(/^\/(en|de|zh)(\/.*)?$/); if (langMatch) { const lang = langMatch[1]; const restOfPath = langMatch[2] || '/';