From c614f8b9cad705fa35cb56bba84dafe967a8f95d Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Thu, 5 Sep 2024 23:01:12 +0800 Subject: [PATCH] Perf: i18n change and captcha code. (#2625) * perf: send captcha check * perf: back router * perf: i18n init * perf: ui * i18n * perf: ui duration --- .vscode/settings.json | 2 +- .../zh-cn/docs/development/upgrading/4810.md | 61 +++--- .../service/common/vectorStore/pg/class.ts | 7 +- packages/web/hooks/useI18n.ts | 45 +++++ packages/web/i18n/en/app.json | 9 +- packages/web/i18n/en/chat.json | 4 +- packages/web/i18n/en/common.json | 110 +--------- packages/web/i18n/en/dataset.json | 4 +- packages/web/i18n/en/file.json | 2 +- packages/web/i18n/en/login.json | 13 ++ packages/web/i18n/en/publish.json | 5 +- packages/web/i18n/en/user.json | 27 +-- packages/web/i18n/en/workflow.json | 14 +- packages/web/i18n/zh/app.json | 9 +- packages/web/i18n/zh/chat.json | 4 +- packages/web/i18n/zh/common.json | 131 ++---------- packages/web/i18n/zh/dataset.json | 4 +- packages/web/i18n/zh/file.json | 2 +- packages/web/i18n/zh/login.json | 13 ++ packages/web/i18n/zh/publish.json | 5 +- packages/web/i18n/zh/user.json | 39 ++-- packages/web/i18n/zh/workflow.json | 14 +- packages/web/package.json | 8 +- packages/web/types/i18next.d.ts | 12 +- pnpm-lock.yaml | 29 ++- projects/app/next-i18next.config.js | 4 +- projects/app/package.json | 1 - projects/app/src/components/Layout/index.tsx | 7 + .../support/user/safe/SendCodeAuthModal.tsx | 2 +- projects/app/src/pages/_app.tsx | 1 + .../account/components/Individuation.tsx | 15 +- projects/app/src/pages/account/index.tsx | 14 +- .../app/detail/components/Plugin/Header.tsx | 9 +- .../app/detail/components/Workflow/Header.tsx | 9 +- .../src/pages/dataset/list/component/List.tsx | 6 +- .../login/components/LoginForm/LoginForm.tsx | 26 +-- projects/app/src/pages/login/index.tsx | 2 +- projects/app/src/web/common/utils/i18n.ts | 22 -- projects/app/src/web/context/useInitApp.ts | 15 -- scripts/i18n/delete-unused-keys.js | 188 ------------------ scripts/i18n/package.json | 15 -- scripts/i18n/query.js | 94 --------- scripts/i18n/query.ts | 49 ----- 43 files changed, 259 insertions(+), 793 deletions(-) create mode 100644 packages/web/hooks/useI18n.ts create mode 100644 packages/web/i18n/en/login.json create mode 100644 packages/web/i18n/zh/login.json delete mode 100644 scripts/i18n/delete-unused-keys.js delete mode 100644 scripts/i18n/package.json delete mode 100644 scripts/i18n/query.js delete mode 100644 scripts/i18n/query.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 30e2803d7fb9..4ae3704a067b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,7 +13,7 @@ "js", "ts" ], - "i18n-ally.keystyle": "nested", + "i18n-ally.keystyle": "flat", "i18n-ally.sortKeys": true, "i18n-ally.keepFulfilled": false, "i18n-ally.sourceLanguage": "zh", // 根据此语言文件翻译其他语言文件的变量和内容 diff --git a/docSite/content/zh-cn/docs/development/upgrading/4810.md b/docSite/content/zh-cn/docs/development/upgrading/4810.md index 39ce8cacd32c..98f317b55b55 100644 --- a/docSite/content/zh-cn/docs/development/upgrading/4810.md +++ b/docSite/content/zh-cn/docs/development/upgrading/4810.md @@ -56,32 +56,35 @@ curl --location --request POST 'https://{{host}}/api/admin/initv4810' \ 7. 新增 - 应用调用迁移成单独节点,同时可以传递全局变量和用户的文件。 8. 新增 - 插件增加使用说明配置。 9. 新增 - 工作流导出导入,支持直接导出和导入 JSON 文件,便于交流。 -10. 商业版新增 - 飞书机器人接入 -11. 商业版新增 - 公众号接入接入 -12. 商业版新增 - 自助开票申请 -13. 商业版新增 - SSO 定制 -14. 优化 - 工作流循环校验,避免 skip 循环空转。同时支持分支完全并发执行。 -15. 优化 - SSE 响应优化。 -16. 优化 - 无 SSL 证书情况下,优化复制。 -17. 优化 - 单选框打开后自动滚动到选中的位置。 -18. 优化 - 知识库集合禁用,目录禁用会递归修改其下所有 children 的禁用状态。 -19. 优化 - 节点选择,避免切换 tab 时候,path 加载报错。 -20. 优化 - 最新 React Markdown 组件,支持 Base64 图片。 -21. 优化 - 知识库列表 UI。 -22. 优化 - 知识库详情页 UI。 -23. 优化 - 支持无网络配置情况下运行。 -24. 优化 - 部分全局变量,增加数据类型约束。 -25. 优化 - 查看工作流详情,切换 tab 时,自动滚动到顶部。 -26. 修复 - 全局变量 key 可能重复。 -27. 修复 - Prompt 模式调用工具,stream=false 模式下,会携带 0: 开头标记。 -28. 修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情。 -29. 修复 - 选择 Milvus 部署时,无法导出知识库。 -30. 修复 - 创建 APP 副本,无法复制系统配置。 -31. 修复 - 图片识别模式下,自动解析图片链接正则不够严谨问题。 -32. 修复 - 内容提取的数据类型与输出数据类型未一致。 -33. 修复 - 工作流运行时间统计错误。 -34. 修复 - stream 模式下,工具调用有可能出现 undefined -35. 修复 - 全局变量在 API 中无法持久化。 -36. 修复 - OpenAPI,detail=false模式下,不应该返回 tool 调用结果,仅返回文字。(可解决 cow 不适配问题) -37. 修复 - 知识库标签重复加载。 -38. 修复 - Debug 模式下,循环调用边问题。 +10. 新增 - HTTP模块支持超时配置、支持更多的 Body 类型,params 和 headers 支持新的变量选择模式。 +11. 新增 - 发送验证码安全校验。 +12. 商业版新增 - 飞书机器人接入 +13. 商业版新增 - 公众号接入接入 +14. 商业版新增 - 自助开票申请 +15. 商业版新增 - SSO 定制 +16. 优化 - 工作流循环校验,避免 skip 循环空转。同时支持分支完全并发执行。 +17. 优化 - SSE 响应优化。 +18. 优化 - 无 SSL 证书情况下,优化复制。 +19. 优化 - 单选框打开后自动滚动到选中的位置。 +20. 优化 - 知识库集合禁用,目录禁用会递归修改其下所有 children 的禁用状态。 +21. 优化 - 节点选择,避免切换 tab 时候,path 加载报错。 +22. 优化 - 最新 React Markdown 组件,支持 Base64 图片。 +23. 优化 - 知识库列表 UI。 +24. 优化 - 知识库详情页 UI。 +25. 优化 - 支持无网络配置情况下运行。 +26. 优化 - 部分全局变量,增加数据类型约束。 +27. 优化 - 查看工作流详情,切换 tab 时,自动滚动到顶部。 +28. 优化 - 对话框性能问题。 +29. 修复 - 全局变量 key 可能重复。 +30. 修复 - Prompt 模式调用工具,stream=false 模式下,会携带 0: 开头标记。 +31. 修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情。 +32. 修复 - 选择 Milvus 部署时,无法导出知识库。 +33. 修复 - 创建 APP 副本,无法复制系统配置。 +34. 修复 - 图片识别模式下,自动解析图片链接正则不够严谨问题。 +35. 修复 - 内容提取的数据类型与输出数据类型未一致。 +36. 修复 - 工作流运行时间统计错误。 +37. 修复 - stream 模式下,工具调用有可能出现 undefined +38. 修复 - 全局变量在 API 中无法持久化。 +39. 修复 - OpenAPI,detail=false模式下,不应该返回 tool 调用结果,仅返回文字。(可解决 cow 不适配问题) +40. 修复 - 知识库标签重复加载。 +41. 修复 - Debug 模式下,循环调用边问题。 diff --git a/packages/service/common/vectorStore/pg/class.ts b/packages/service/common/vectorStore/pg/class.ts index cfd4ef386284..4a84a3d28dcb 100644 --- a/packages/service/common/vectorStore/pg/class.ts +++ b/packages/service/common/vectorStore/pg/class.ts @@ -48,7 +48,7 @@ export class PgVectorCtrl { const { teamId, datasetId, collectionId, vector, retry = 3 } = props; try { - const { rows } = await PgClient.insert(DatasetVectorTableName, { + const { rowCount, rows } = await PgClient.insert(DatasetVectorTableName, { values: [ [ { key: 'vector', value: `[${vector}]` }, @@ -58,6 +58,11 @@ export class PgVectorCtrl { ] ] }); + + if (rowCount === 0) { + return Promise.reject('insertDatasetData: no insert'); + } + return { insertId: rows[0].id }; diff --git a/packages/web/hooks/useI18n.ts b/packages/web/hooks/useI18n.ts new file mode 100644 index 000000000000..b0cdd27789d8 --- /dev/null +++ b/packages/web/hooks/useI18n.ts @@ -0,0 +1,45 @@ +import Cookies, { CookieAttributes } from 'js-cookie'; +import { useTranslation } from 'next-i18next'; + +const setCookie = (key: string, value: string, options?: CookieAttributes) => { + Cookies.set(key, value, options); +}; +const getCookie = (key: string) => { + return Cookies.get(key); +}; + +const LANG_KEY = 'NEXT_LOCALE'; + +export const useI18nLng = () => { + const { i18n } = useTranslation(); + + const onChangeLng = (lng: string) => { + setCookie(LANG_KEY, lng, { + expires: 30, + sameSite: 'None', + secure: true + }); + i18n?.changeLanguage(lng); + }; + + const setUserDefaultLng = () => { + if (!navigator || !localStorage) return; + if (getCookie(LANG_KEY)) return onChangeLng(getCookie(LANG_KEY) as string); + + const languageMap = { + zh: 'zh', + 'zh-CN': 'zh' + }; + + // @ts-ignore + const lang = languageMap[navigator.language] || 'en'; + + // currentLng not in userLang + return onChangeLng(lang); + }; + + return { + onChangeLng, + setUserDefaultLng + }; +}; diff --git a/packages/web/i18n/en/app.json b/packages/web/i18n/en/app.json index f1fd0aa28da2..b65b30487bcb 100644 --- a/packages/web/i18n/en/app.json +++ b/packages/web/i18n/en/app.json @@ -15,8 +15,7 @@ "version_initial_copy": "Duplicate - Original State", "version_name_tips": "Version name cannot be empty", "version_past": "Previously Published", - "version_publish_tips": "This version will be saved to the team cloud, synchronized with the entire team, and update the app version on all release channels.", - "version_save_tips": "This version will be saved to the team cloud, synchronized with the entire team." + "version_publish_tips": "This version will be saved to the team cloud, synchronized with the entire team, and update the app version on all release channels." }, "app_detail": "Application Details", "chat_debug": "Chat Preview", @@ -138,13 +137,11 @@ "Create plugin bot": "Create Plugin", "Create simple bot": "Create Simple App", "Create simple bot tip": "Create a simple AI app by filling out a form, suitable for beginners.", - "Create template tip": "Explore more features in the template market to help you understand and get started with various applications.", "Create workflow bot": "Create Workflow", "Create workflow tip": "Build complex multi-turn dialogue AI applications through low-code methods, recommended for advanced users.", "Http plugin": "HTTP Plugin", "Plugin": "Plugin", "Simple bot": "Simple App", - "Template": "Create via Template", "Workflow bot": "Workflow" }, "upload_file_max_amount": "Maximum File Quantity", @@ -169,8 +166,6 @@ "workflow": { "Input guide": "Input Guide", "file_url": "Document Link", - "option1": "Option 1", - "option2": "Option 2", "read_files": "Document Parsing", "read_files_result": "Document Parsing Result", "read_files_result_desc": "Original document text, consisting of file names and document content, separated by hyphens between multiple files.", @@ -187,4 +182,4 @@ "user_select": "User Selection", "user_select_tip": "This module can configure multiple options for selection during the dialogue. Different options can lead to different workflow branches." } -} +} \ No newline at end of file diff --git a/packages/web/i18n/en/chat.json b/packages/web/i18n/en/chat.json index d087c18649cd..9e902ff5bea4 100644 --- a/packages/web/i18n/en/chat.json +++ b/packages/web/i18n/en/chat.json @@ -24,12 +24,10 @@ "items": "Items", "module_runtime_and": "Total Module Runtime", "multiple_AI_conversations": "Multiple AI Conversations", - "new_chat": "New Conversation", "new_input_guide_lexicon": "New Lexicon", "no_workflow_response": "No workflow data", "plugins_output": "Plugin Output", "question_tip": "From top to bottom, the response order of each module", - "rearrangement": "Rearrangement of Retrieval Results", "response": { "node_inputs": "Node Inputs" }, @@ -38,4 +36,4 @@ "stream_output": "Stream Output", "view_citations": "View References", "web_site_sync": "Web Site Sync" -} +} \ No newline at end of file diff --git a/packages/web/i18n/en/common.json b/packages/web/i18n/en/common.json index e887c1e4c6d5..8718f3b6292c 100644 --- a/packages/web/i18n/en/common.json +++ b/packages/web/i18n/en/common.json @@ -6,10 +6,6 @@ "ai_point_expire_a": "Yes, they will expire. After the current package expires, the AI points will be reset to the new package's AI points. Annual package AI points are valid for one year, not monthly.", "ai_point_expire_q": "Do AI points expire?", "ai_point_q": "What are AI points?", - "auto_renew_a": "After the current package expires, the system will automatically renew according to the 'Future Package'. The system will attempt to deduct the fee from your account balance. Please ensure there is sufficient balance for automatic renewal.", - "auto_renew_q": "Will the subscription package renew automatically?", - "change_package_a": "If the current package price is higher than the new package, it cannot be switched immediately and will switch upon renewal after the current package expires.\nIf the current package price is lower than the new package, the system will calculate the remaining balance of the current package, and you can pay the difference to switch packages.", - "change_package_q": "Can I switch subscription packages?", "check_subscription_a": "Go to Account - Personal Information - Package Details - Usage. You can view the effective and expiration dates of your subscribed packages. After the paid package expires, it will automatically switch to the free version.", "check_subscription_q": "Where can I view my subscribed packages?", "dataset_compute_a": "1 Dataset storage equals 1 Dataset index. A piece of Dataset data can contain one or more Dataset indexes. In enhanced training, 1 piece of data generates 5 indexes.", @@ -27,7 +23,6 @@ "Login": "Login", "Move": "Move", "Name": "Name", - "Not_selected": "Not selected", "Rename": "Rename", "Resume": "Resume", "Running": "Running", @@ -146,7 +141,6 @@ "Exit": "Exit", "Exit Directly": "Exit Directly", "Expired Time": "Expiration Time", - "Field": "Field", "File": "File", "Finish": "Finish", "Import": "Import", @@ -212,7 +206,6 @@ "Update Failed": "Update Failed", "Update Success": "Updated Successfully", "Update Successful": "Updated Successfully", - "Upload File Failed": "File Upload Failed", "Username": "Username", "Waiting": "Waiting", "Warning": "Warning", @@ -225,7 +218,7 @@ "base_config": "Basic Configuration", "choosable": "Choosable", "confirm": { - "Common Tip": "Operation Confirmation" + "Common Tip": "Confirm" }, "copy_to_clipboard": "Copy to Clipboard", "course": { @@ -236,7 +229,6 @@ }, "error": { "Select avatar failed": "Avatar Selection Failed", - "too_many_request": "Too Many Requests, Please Try Again Later.", "unKnow": "An Unexpected Error Occurred" }, "export_to_json": "Export to JSON", @@ -278,7 +270,6 @@ }, "submit_success": "Submitted Successfully", "submitted": "Submitted", - "submitting": "Submitting", "support": "Support", "system": { "Commercial version function": "Please Upgrade to the Commercial Version to Use This Feature: https://fastgpt.in", @@ -335,8 +326,6 @@ "Max histories": "Number of Chat Histories", "Max tokens": "Response Limit", "Name and avatar": "Avatar & Name", - "Not saved": "Not Saved", - "Onclick to save": "Click to Save", "Publish": "Publish", "Publish Confirm": "Confirm to Publish App? This Will Immediately Update the App Status on All Publishing Channels.", "Publish app tip": "After Publishing the App, All Publishing Channels Will Immediately Use This Version", @@ -345,7 +334,6 @@ "Quote prompt": "Quote Template Prompt", "Quote templates": "Quote Content Templates", "Random": "Divergent", - "Saved time": "Saved: {{time}}", "Search team tags": "Search Tags", "Select TTS": "Select Voice Playback Mode", "Select app from template": "Select from Template", @@ -385,22 +373,12 @@ "Custom feedback": "Custom Feedback", "close custom feedback": "Close Feedback" }, - "have_publish": "Published", "have_saved": "Saved", - "loading": "Loading", "logs": { "Source And Time": "Source & Time" }, "more": "View More", - "navbar": { - "External": "External Use", - "Flow mode": "Advanced Orchestration", - "Publish": "Publish", - "Publish app": "Publish App", - "Simple mode": "Simple Configuration" - }, "no_app": "No Apps Yet, Create One Now!", - "not_published": "Not Published", "not_saved": "Not Saved", "outLink": { "Can Drag": "Icon Can Be Dragged", @@ -415,7 +393,6 @@ "Show History": "Show Chat History" }, "publish": { - "Fei Shu Bot Desc": "Integrate into Feishu Bot", "Fei shu bot": "Feishu", "Fei shu bot publish": "Publish to Feishu Bot" }, @@ -474,13 +451,11 @@ "Audio Not Support": "Device Does Not Support Voice Playback", "Audio Speech Error": "Voice Playback Error", "Cancel Speak": "Cancel Voice Input", - "Chat API is error or undefined": "Chat API Error or Undefined", "Confirm to clear history": "Confirm to Clear Online Chat History for This App? Share and API Call Records Will Not Be Cleared.", "Confirm to clear share chat history": "Confirm to Delete All Chat Records?", "Converting to text": "Converting to Text...", "Custom History Title": "Custom History Title", "Custom History Title Description": "If set to empty, it will automatically follow the chat record.", - "Debug test": "Debug Preview", "Exit Chat": "Exit Chat", "Failed to initialize chat": "Failed to Initialize Chat", "Feedback Failed": "Feedback Submission Failed", @@ -504,7 +479,6 @@ "Record": "Voice Input", "Restart": "Restart Chat", "Run test": "Run Preview", - "Select Image": "Select Image", "Select dataset": "Select Dataset", "Select dataset Desc": "Select a Dataset to store the expected answer", "Send Message": "Send", @@ -549,10 +523,8 @@ "response": { "Complete Response": "Complete Response", "Extension model": "Question Optimization Model", - "Plugin response detail": "Plugin Details", "Read complete response": "View Details", "Read complete response tips": "Click to View Detailed Process", - "Tool call response detail": "Tool Run Details", "Tool call tokens": "Tool Call Tokens Consumption", "context total length": "Total Context Length", "module cq": "Question Classification List", @@ -589,14 +561,11 @@ } }, "dataset": { - "All Dataset": "All Datasets", - "Avatar": "Dataset Avatar", "Choose Dataset": "Associate Dataset", "Collection": "Dataset", "Create dataset": "Create a {{name}}", "Dataset": "Dataset", "Dataset ID": "Dataset ID", - "Dataset Type": "Dataset Type", "Delete Confirm": "Confirm to Delete This Dataset? Data Cannot Be Recovered After Deletion, Please Confirm!", "Empty Dataset": "Empty Dataset", "Empty Dataset Tips": "No Dataset Yet, Create One Now!", @@ -605,7 +574,6 @@ "Intro Placeholder": "This Dataset Has No Introduction Yet", "Manual collection": "Manual Dataset", "My Dataset": "My Dataset", - "Name": "Dataset Name", "Query extension intro": "Enabling the question optimization function can improve the accuracy of Dataset searches during continuous conversations. After enabling this function, when performing Dataset searches, the AI will complete the missing information of the question based on the conversation history.", "Quote Length": "Quote Content Length", "Read Dataset": "View Dataset Details", @@ -629,7 +597,6 @@ "Chunk Size": "Chunk Size", "Createtime": "Creation Time", "Raw text length": "Raw Text Length", - "Read Metadata": "View Metadata", "Training Type": "Training Mode", "Updatetime": "Update Time", "Web page selector": "Web Page Selector", @@ -648,8 +615,7 @@ "success": "Sync Started" } }, - "training": { - } + "training": {} }, "data": { "Auxiliary Data": "Auxiliary Data", @@ -665,7 +631,6 @@ "Search data placeholder": "Search Related Data", "Too Long": "Total Length Exceeded", "Total Amount": "{{total}} Groups", - "empty_index": "No Custom Index", "group": "Group", "unit": "Items" }, @@ -673,7 +638,6 @@ "error": { "Data not found": "Data Not Found or Deleted", "Start Sync Failed": "Failed to Start Sync", - "Template does not exist": "Template Does Not Exist", "invalidVectorModelOrQAModel": "Invalid Vector Model or QA Model", "unAuthDataset": "Unauthorized to Operate This Dataset", "unAuthDatasetCollection": "Unauthorized to Operate This Dataset", @@ -814,7 +778,6 @@ "Add question type": "Add Question Type", "Add_option": "Add Option", "Can not connect self": "Cannot Connect to Itself", - "Confirm Delete Node": "Confirm to Delete This Node?", "Data Type": "Data Type", "Dataset quote": { "label": "Dataset Quote", @@ -859,19 +822,15 @@ }, "http": { "Add props": "Add Parameter", - "Add props_and_tips": "To add parameters, enter \"/\" to invoke the variable list", "AppId": "App ID", - "AppSecret": "AppSecret", "ChatId": "Current Chat ID", "Current time": "Current Time", "Histories": "History Records", "Key already exists": "Key Already Exists", "Key cannot be empty": "Parameter Name Cannot Be Empty", "Props name": "Parameter Name", - "Props name_and_tips": "Parameter name, enter \"/\" to call up the variable list", "Props tip": "You can set related parameters for the HTTP request\nYou can call global variables or external parameter inputs through {{key}}, currently available variables:\n{{variable}}", "Props value": "Parameter Value", - "Props value_and_tips": "Parameter value, enter \"/\" to invoke the variable list", "ResponseChatItemId": "AI Response ID", "Url and params have been split": "Path parameters have been automatically added to Params", "curl import": "cURL Import", @@ -923,14 +882,12 @@ "Query extension": "Question Optimization", "System Plugin": "System Plugin", "System input module": "System Input", - "Team Plugin": "Team Plugin", "Team app": "Team App", "Tool module": "Tool", "UnKnow Module": "Unknown Module", "ai_chat": "AI conversation", "ai_chat_intro": "AI large model dialogue", "config_params": "Can configure application system parameters", - "empty_app": "Blank application", "empty_plugin": "Blank plugin", "empty_workflow": "Blank workflow", "http body placeholder": "Same syntax as Apifox", @@ -959,9 +916,7 @@ "variable option is value is required": "Option Content Cannot Be Empty", "variable options": "Options" }, - "variable add option": "Add Option", - "variable_update": "Variable Update", - "variable_update_info": "Can update the output value of the specified node or update global variables" + "variable add option": "Add Option" }, "plugin": { "Custom headers": "Custom Request Headers", @@ -1009,7 +964,6 @@ "Reference": "Variable Reference", "custom": "Custom Variable", "dynamicTargetInput": "Dynamic External Data", - "file_link": "File Upload", "input": "Single Line Input Box", "number input": "Number Input Box", "select": "Single Select Box", @@ -1024,7 +978,6 @@ "OnRevert version confirm": "Confirm to Revert to This Version? The configuration of the editing version will be saved, and a new release version will be created for the reverted version.", "histories": "Release Records" }, - "run_test": "Run", "template": { "Interactive": "Interactive", "Multimodal": "Multimodal", @@ -1068,21 +1021,14 @@ "Select One Collection To Store": "Select a File to Store" }, "data": { - "Add Index": "Add Custom Index", "Can not edit": "No Edit Permission", "Custom Index Number": "Custom Index {{number}}", "Default Index": "Default Index", "Delete Tip": "Confirm to Delete This Data?", - "Index Edit": "Data Index", "Index Placeholder": "Enter Index Text Content", - "Input Data": "Import New Data", "Input Success Tip": "Data Imported Successfully", - "Update Data": "Update Data", "Update Success Tip": "Data Updated Successfully", "edit": { - "Content": "Data Content", - "Course": "Documentation", - "Delete": "Delete Data", "Index": "Data Index ({{amount}})", "divide_content": "Segment Content" }, @@ -1094,19 +1040,15 @@ "noResult": "No Search Results" } }, - "default_reply": "Default Reply", "error": { "Create failed": "Create failed", - "code_error": "Code error", "fileNotFound": "File not found~", "inheritPermissionError": "Inherit permission Error", "missingParams": "Insufficient parameters", - "team": { - "overSize": "Team Member Limit Exceeded" - }, "upload_file_error_filename": "{{name}} Upload Failed", "username_empty": "Account cannot be empty" }, + "error.code_error": "Verification code error", "extraction_results": "Extraction Results", "field_name": "Field Name", "free": "Free", @@ -1142,28 +1084,16 @@ }, "new_create": "Create New", "no": "No", - "no_data": "No Data Available", "no_laf_env": "System Not Configured with Laf Environment", "not_yet_introduced": "No Introduction Yet", "option": "Option", "pay": { "amount": "Amount", - "balance": "Account Balance", - "balance_notice": "Insufficient Account Balance", - "confirm_pay": "Confirm Payment", - "get_pay_QR": "Get Payment QR Code", - "need_pay": "Need to Pay", - "need_to_pay": "Actual Payment", - "new_package_price": "New Package Price", - "notice": "Please Do Not Close the Page", - "old_package_price": "Old Package Balance", - "other": "Other Amount, Please Use Whole Numbers", "package_tip": { "buy": "The package you purchased is lower than the current package. This package will take effect after the current package expires.\nYou can view the package usage in Account - Personal Information - Package Details.", "renewal": "You are renewing the package. You can view the package usage in Account - Personal Information - Package Details.", "upgrade": "The package you purchased is higher than the current package. This package will take effect immediately, and the current package will take effect later. You can view the package usage in Account - Personal Information - Package Details." }, - "to_recharge": "Insufficient Balance, Go to Recharge", "wechat": "Please Scan the QR Code with WeChat to Pay: {{price}} Yuan\nPlease Do Not Close the Page", "yuan": "{{amount}} Yuan" }, @@ -1218,7 +1148,6 @@ "go to laf": "Go to Write", "path": "Path" }, - "reply_now": "Reply Now", "required": "Required", "resume_failed": "Resume Failed", "select_reference_variable": "Select Reference Variable", @@ -1252,8 +1181,6 @@ }, "standard": { "AI Bonus Points": "AI Points", - "Expired Time": "End Time", - "Start Time": "Start Time", "due_date": "Due Date", "storage": "Storage", "type": "Type" @@ -1279,22 +1206,14 @@ "System message": "System Message" }, "login": { - "And": "and", "Email": "Email", - "Forget Password": "Forgot Password?", "Github": "GitHub Login", "Google": "Google Login", "Password": "Password", "Password login": "Password Login", "Phone": "Phone Login", "Phone number": "Phone Number", - "Policy tip": "By using, you agree to our", - "Privacy": "Privacy Policy", "Provider error": "Login Error, Please Try Again", - "Register": "Register Account", - "Root login": "Login with Root User", - "Root password placeholder": "Root password is the environment variable you set", - "Terms": "Terms of Service", "Username": "Username", "Wechat": "WeChat Login", "can_not_login": "Cannot Log In, Click to Contact", @@ -1314,12 +1233,9 @@ "wallet": { "Ai point every thousand tokens": "{{points}} Points/1K Tokens", "Amount": "Amount", - "Bills": "Bills and Invoices", "Buy": "Buy", - "Confirm pay": "Payment Confirmation", "Not sufficient": "Insufficient AI Points, Please Upgrade Your Package or Purchase Additional AI Points to Continue Using.", "Plan expired time": "Package Expiration Time", - "Plan reset time": "Package Reset Time", "Standard Plan Detail": "Package Details", "To read plan": "View Package", "amount_0": "Purchase Quantity Cannot Be 0", @@ -1356,7 +1272,6 @@ "company_address": "Company Address", "company_phone": "Company Phone", "email": "Email Address", - "in_valid": "There are empty fields or email format errors", "need_special_invoice": "Need Special Invoice", "organization_name": "Organization Name", "unit_code": "Unified Credit Code" @@ -1376,7 +1291,6 @@ "AI points usage": "AI Points Usage", "AI points usage tip": "Each time the AI model is called, a certain amount of AI points will be consumed. For specific calculation standards, please refer to the 'Pricing' above.", "Ai points": "AI Points Calculation Standards", - "Buy now": "Switch Package", "Current plan": "Current Package", "Extra ai points": "Extra AI Points", "Extra dataset size": "Extra Dataset Capacity", @@ -1385,10 +1299,7 @@ "FAQ": "FAQ", "Month amount": "Months", "Next plan": "Future Package", - "Nonsupport": "No Purchase Needed", "Stand plan level": "Subscription Package", - "Standard update fail": "Failed to Update Subscription Package", - "Standard update success": "Subscription Package Updated Successfully!", "Sub plan": "Subscription Package", "Sub plan tip": "Free to use {{title}} or upgrade to a higher package", "Team plan and usage": "Package and Usage", @@ -1454,8 +1365,7 @@ "Total points": "AI Points Consumption", "Usage Detail": "Usage Details", "Whisper": "Voice Input" - }, - "use_default": "Use Default Header" + } } }, "sync_link": "Sync Link", @@ -1492,28 +1402,23 @@ "Laf Account Setting": "Laf Account Configuration", "Language": "Language", "Member Name": "Nickname", - "Notice": "Notice", "Notification Receive": "Notification Receive", "Notification Receive Bind": "Please bind the notification receive method first", "Old password is error": "Old Password is Incorrect", "OpenAI Account Setting": "OpenAI Account Configuration", "Password": "Password", "Pay": "Recharge", - "Personal Information": "Profile", "Promotion": "Promotion", "Promotion Rate": "Cashback Rate", - "Promotion Record": "Promotion Record", "Promotion rate tip": "You will receive a balance reward when friends recharge", "Replace": "Replace", "Set OpenAI Account Failed": "Failed to Set OpenAI Account", - "Sign Out": "Sign Out", "Team": "Team", "Time": "Time", "Timezone": "Timezone", "Update Password": "Update Password", "Update password failed": "Failed to Update Password", "Update password successful": "Password Updated Successfully", - "Usage Record": "Usage Record", "apikey": { "key": "API Key" }, @@ -1568,8 +1473,7 @@ }, "role": { "Admin": "Admin", - "Owner": "Owner", - "Visitor": "Visitor" + "Owner": "Owner" } }, "type": "Type" @@ -1577,4 +1481,4 @@ "verification": "Verification", "xx_search_result": "{{key}} Search Results", "yes": "Yes" -} +} \ No newline at end of file diff --git a/packages/web/i18n/en/dataset.json b/packages/web/i18n/en/dataset.json index bc4cae8bb83e..1ce173579525 100644 --- a/packages/web/i18n/en/dataset.json +++ b/packages/web/i18n/en/dataset.json @@ -1,7 +1,5 @@ { - "Disabled": "Disabled", "Enable": "Enable", - "Enabled": "Enabled", "collection": { "Create update time": "Creation/Update Time", "Training type": "Training Mode" @@ -47,4 +45,4 @@ "the_knowledge_base_has_indexes_that_are_being_trained_or_being_rebuilt": "The Dataset has indexes that are being trained or rebuilt", "website_dataset": "Website Sync", "website_dataset_desc": "Website sync allows you to build a Dataset directly using a web link." -} +} \ No newline at end of file diff --git a/packages/web/i18n/en/file.json b/packages/web/i18n/en/file.json index cf32aab95e6c..2bd7a3061ce3 100644 --- a/packages/web/i18n/en/file.json +++ b/packages/web/i18n/en/file.json @@ -15,4 +15,4 @@ "upload_failed": "Upload Failed", "reached_max_file_count": "Maximum file count reached", "upload_error_description": "Only multiple files or a single folder can be uploaded at a time" -} +} \ No newline at end of file diff --git a/packages/web/i18n/en/login.json b/packages/web/i18n/en/login.json new file mode 100644 index 000000000000..a8297cf2f6e9 --- /dev/null +++ b/packages/web/i18n/en/login.json @@ -0,0 +1,13 @@ +{ + "Login": "Login", + "forget_password": "Find password", + "login_failed": "Login failed", + "login_success": "Login successful", + "password_condition": "Password maximum 60 characters", + "policy_tip": "By useing, you agree to our", + "privacy": "Privacy policy", + "register": "Register", + "root_password_placeholder": "The root user password is the value of the environment variable DEFAULT_ROOT_PSW", + "terms": "Terms", + "use_root_login": "Log in as root user" +} \ No newline at end of file diff --git a/packages/web/i18n/en/publish.json b/packages/web/i18n/en/publish.json index fa818da40167..03f0ebbe5035 100644 --- a/packages/web/i18n/en/publish.json +++ b/packages/web/i18n/en/publish.json @@ -4,20 +4,17 @@ "copy_link_hint": "Copy the link below to the specified location", "create_api_key": "Create New Key", "create_link": "Create Link", - "default_response": "Default Response", "edit_api_key": "Edit Key Details", "edit_feishu_bot": "Edit Feishu Bot", "edit_link": "Edit", "feishu_api": "Feishu API", "feishu_bot": "Feishu Bot", "feishu_bot_desc": "Connect to Feishu Bot directly via API", - "feishu_name": "Feishu", "key_alias": "Key alias, for display only", "key_tips": "You can use the API key to access specific interfaces (cannot access the application, use the in-app API key for that)", "link_name": "Share Link Name", "new_feishu_bot": "Add New Feishu Bot", "official_account": { - "api": "WeChat Official Account API", "create_modal_title": "Create WeChat Official Account Integration", "desc": "Connect to WeChat Official Account directly via API", "edit_modal_title": "Edit WeChat Official Account Integration", @@ -40,4 +37,4 @@ "edit_modal_title": "Edit WeCom Bot", "title": "Publish to WeCom Bot" } -} +} \ No newline at end of file diff --git a/packages/web/i18n/en/user.json b/packages/web/i18n/en/user.json index a191a2b8a8c1..314115dd5cce 100644 --- a/packages/web/i18n/en/user.json +++ b/packages/web/i18n/en/user.json @@ -2,7 +2,6 @@ "bill": { "balance": "Balance", "buy_plan": "Purchase Plan", - "buy_standard_plan_success": "Plan Purchase Successful", "contact_customer_service": "Contact Support", "conversion": "Conversion", "convert_error": "Conversion Failed", @@ -20,6 +19,7 @@ "you_can_convert": "You can convert", "yuan": "Yuan" }, + "bill_and_invoices": "Bill & Invoice", "bind_inform_account_error": "Failed to Bind Notification Account", "bind_inform_account_success": "Notification Account Bound Successfully", "delete": { @@ -27,28 +27,24 @@ "admin_success": "Admin Deleted Successfully" }, "has_chosen": "Selected", + "individuation": "Individuation", "login": { "error": "Login Error", - "failed": "Login Failed", - "login_account": "Login to {{account}} Account", - "login_error": "Incorrect Username or Password", "password_condition": "Password can be up to 60 characters", - "success": "Login Successful", - "to_register": "No account? Register" + "success": "Login Successful" }, "name": "Name", + "notice": "Notice", "notification": { "Bind Notification Pipe Hint": "Please bind a notification receiving account to ensure you receive notifications such as plan expiration reminders, ensuring your service runs smoothly.", "remind_owner_bind": "Please remind the creator to bind a notification account" }, "operations": "Actions", "password": { - "change_error": "Password Change Error", "code_required": "Verification Code Required", "code_send_error": "Failed to Send Verification Code", "code_sended": "Verification Code Sent", "confirm": "Confirm Password", - "email_phone": "Email/Phone Number", "email_phone_error": "Invalid Email/Phone Number Format", "email_phone_void": "Email/Phone Number Cannot Be Empty", "get_code": "Get Verification Code", @@ -80,19 +76,17 @@ "write": "In addition to readable resources, you can also create new resources" }, "permissions": "Permissions", - "promotion": { - "pay": "Friend Payment", - "register": "Friend Registration" - }, + "personal_information": "Me", + "personalization": "Personalization", + "promotion_records": "Promotion", "register": { "confirm": "Confirm Registration", - "error": "Registration Error", - "failed": "Registration Failed", "register_account": "Register {{account}} Account", "success": "Registration Successful", "to_login": "Already have an account? Login" }, "search_user": "Search Username", + "sign_out": "Sign out", "synchronization": { "button": "Sync Now", "placeholder": "Enter Sync Tag", @@ -109,5 +103,6 @@ "official_account": "Official Account", "share": "Share Link", "wecom": "WeCom" - } -} + }, + "usage_record": "Usages" +} \ No newline at end of file diff --git a/packages/web/i18n/en/workflow.json b/packages/web/i18n/en/workflow.json index ae36f34faba9..3e18c6038d61 100644 --- a/packages/web/i18n/en/workflow.json +++ b/packages/web/i18n/en/workflow.json @@ -1,11 +1,4 @@ { - " i18nT('workflow": { - "use_user_id'),\n required": { - "workflow": { - "use_user_id": "" - } - } - }, "Code": "Code", "about_xxx_question": "Question regarding xxx", "add_new_input": "Add New Input", @@ -122,15 +115,12 @@ "Custom outputs": "Custom Outputs", "Error": "Error", "Read file result": "Read File Result", - "User_select_description": "Description", - "User_select_result": "Selected Result", "read files": "Read Files" }, "select_an_application": "Select an Application", "select_another_application_to_call": "You can choose another application to call", "special_array_format": "Special array format, returns an empty array when the search result is empty.", "start_with": "Starts With", - "system_variables": "system variables", "target_fields_description": "A target field consists of 'description' and 'key'. Multiple target fields can be extracted.", "template": { "ai_chat": "AI Chat", @@ -156,11 +146,9 @@ "variable_picker_tips": "Type node name or variable name to search", "variable_update": "Variable Update", "workflow": { - "Back_to_current_version": "Back to Current Version", "My edit": "My Edit", - "Switch_failed": "Switch Failed", "Switch_success": "Switch Successful", "Team cloud": "Team Cloud", "exit_tips": "Your changes have not been saved. 'Exit directly' will not save your edits." } -} +} \ No newline at end of file diff --git a/packages/web/i18n/zh/app.json b/packages/web/i18n/zh/app.json index f647b7e4e693..2d29524aaa43 100644 --- a/packages/web/i18n/zh/app.json +++ b/packages/web/i18n/zh/app.json @@ -15,8 +15,7 @@ "version_initial_copy": "副本-初始状态", "version_name_tips": "版本名称不能为空", "version_past": "发布过", - "version_publish_tips": "该版本将被保存至团队云端,同步给整个团队,同时更新所有发布渠道的应用版本", - "version_save_tips": "该版本将被保存至团队云端,同步给整个团队" + "version_publish_tips": "该版本将被保存至团队云端,同步给整个团队,同时更新所有发布渠道的应用版本" }, "app_detail": "应用详情", "chat_debug": "调试预览", @@ -131,13 +130,11 @@ "Create plugin bot": "创建插件", "Create simple bot": "创建简易应用", "Create simple bot tip": "通过填表单形式,创建简单的 AI 应用,适合新手", - "Create template tip": "在模板市场探索更多玩法,带你理解并上手各种应用", "Create workflow bot": "创建工作流", "Create workflow tip": "通过低代码的方式,构建逻辑复杂的多轮对话 AI 应用,推荐高级玩家使用", "Http plugin": "HTTP 插件", "Plugin": "插件", "Simple bot": "简易应用", - "Template": "通过模板创建", "Workflow bot": "工作流" }, "upload_file_max_amount": "最大文件数量", @@ -162,8 +159,6 @@ "workflow": { "Input guide": "填写说明", "file_url": "文档链接", - "option1": "选项 1", - "option2": "选项 2", "read_files": "文档解析", "read_files_result": "文档解析结果", "read_files_result_desc": "文档原文,由文件名和文档内容组成,多个文件之间通过横线隔开。", @@ -187,4 +182,4 @@ "manage": "写权限基础上,可配置发布渠道、查看对话日志、分配该应用权限" } } -} +} \ No newline at end of file diff --git a/packages/web/i18n/zh/chat.json b/packages/web/i18n/zh/chat.json index 966d9c611cad..84a7a96f6bba 100644 --- a/packages/web/i18n/zh/chat.json +++ b/packages/web/i18n/zh/chat.json @@ -24,12 +24,10 @@ "items": "条", "module_runtime_and": "模块运行时间和", "multiple_AI_conversations": "多组 AI 对话", - "new_chat": "新对话", "new_input_guide_lexicon": "新词库", "no_workflow_response": "没有运行数据", "plugins_output": "插件输出", "question_tip": "从上到下,为各个模块的响应顺序", - "rearrangement": "检索结果重排", "response": { "node_inputs": "节点输入" }, @@ -38,4 +36,4 @@ "stream_output": "流输出", "view_citations": "查看引用", "web_site_sync": "Web站点同步" -} +} \ No newline at end of file diff --git a/packages/web/i18n/zh/common.json b/packages/web/i18n/zh/common.json index 65ef8b23ac0d..e78b9e31b498 100644 --- a/packages/web/i18n/zh/common.json +++ b/packages/web/i18n/zh/common.json @@ -6,10 +6,6 @@ "ai_point_expire_a": "会过期。当前套餐过期后,AI积分将会清空,并更新为新套餐的AI积分。年度套餐的AI积分时长为1年,而不是每个月。", "ai_point_expire_q": "AI积分会过期么?", "ai_point_q": "什么是AI积分?", - "auto_renew_a": "当前套餐过期后,系统会自动根据“未来套餐”进行续费,系统会尝试从账户余额进行扣费,如果您需要自动续费,请在账户余额中预留额度。", - "auto_renew_q": "订阅套餐会自动续费么?", - "change_package_a": "当前套餐价格大于新套餐时,无法立即切换,将会在当前套餐过期后以“续费”形式进行切换。\n当前套餐价格小于新套餐时,系统会自动计算当前套餐剩余余额,您可支付差价进行套餐切换。", - "change_package_q": "能否切换订阅套餐?", "check_subscription_a": "账号-个人信息-套餐详情-使用情况。您可以查看所拥有套餐的生效和到期时间。当付费套餐到期后将自动切换免费版。", "check_subscription_q": "在哪里查看已订阅的套餐?", "dataset_compute_a": "1条知识库存储等于1条知识库索引。一条知识库数据可以包含1条或多条知识库索引。增强训练中,1条数据会生成5条索引。", @@ -27,7 +23,6 @@ "Login": "登录", "Move": "移动", "Name": "名称", - "Not_selected": "未选择", "Rename": "重命名", "Resume": "恢复", "Running": "运行中", @@ -146,7 +141,6 @@ "Exit": "退出", "Exit Directly": "直接退出", "Expired Time": "过期时间", - "Field": "字段", "File": "文件", "Finish": "完成", "Import": "导入", @@ -212,7 +206,6 @@ "Update Failed": "更新异常", "Update Success": "更新成功", "Update Successful": "更新成功", - "Upload File Failed": "上传文件失败", "Username": "用户名", "Waiting": "等待中", "Warning": "警告", @@ -236,7 +229,6 @@ }, "error": { "Select avatar failed": "头像选择异常", - "too_many_request": "请求太频繁了,请稍后重试。", "unKnow": "出现了点意外~" }, "export_to_json": "导出为 JSON", @@ -278,7 +270,6 @@ }, "submit_success": "提交成功", "submitted": "已提交", - "submitting": "提交中", "support": "支持", "system": { "Commercial version function": "请升级商业版后使用该功能:https://fastgpt.in", @@ -335,8 +326,6 @@ "Max histories": "聊天记录数量", "Max tokens": "回复上限", "Name and avatar": "头像 & 名称", - "Not saved": "未保存", - "Onclick to save": "点击保存", "Publish": "发布", "Publish Confirm": "确认发布应用?会立即更新所有发布渠道的应用状态。", "Publish app tip": "发布应用后,所有发布渠道将会立即使用该版本", @@ -345,7 +334,6 @@ "Quote prompt": "引用模板提示词", "Quote templates": "引用内容模板", "Random": "发散", - "Saved time": "已保存:{{time}}", "Search team tags": "搜索标签", "Select TTS": "选择语音播放模式", "Select app from template": "从模板中选择", @@ -385,22 +373,12 @@ "Custom feedback": "自定义反馈", "close custom feedback": "关闭反馈" }, - "have_publish": "已发布", "have_saved": "已保存", - "loading": "加载中", "logs": { "Source And Time": "来源 & 时间" }, "more": "查看更多", - "navbar": { - "External": "外部使用", - "Flow mode": "高级编排", - "Publish": "发布", - "Publish app": "发布应用", - "Simple mode": "简易配置" - }, "no_app": "还没有应用,快去创建一个吧!", - "not_published": "未发布", "not_saved": "未保存", "outLink": { "Can Drag": "图标可拖拽", @@ -415,7 +393,6 @@ "Show History": "展示历史对话" }, "publish": { - "Fei Shu Bot Desc": "接入到飞书机器人中", "Fei shu bot": "飞书", "Fei shu bot publish": "发布到飞书机器人" }, @@ -474,13 +451,11 @@ "Audio Not Support": "设备不支持语音播放", "Audio Speech Error": "语音播报异常", "Cancel Speak": "取消语音输入", - "Chat API is error or undefined": "对话接口报错或返回为空", "Confirm to clear history": "确认清空该应用的在线聊天记录?分享和 API 调用的记录不会被清空。", "Confirm to clear share chat history": "确认删除所有聊天记录?", "Converting to text": "正在转换为文本...", "Custom History Title": "自定义历史记录标题", "Custom History Title Description": "如果设置为空,会自动跟随聊天记录。", - "Debug test": "调试预览", "Exit Chat": "退出聊天", "Failed to initialize chat": "初始化聊天失败", "Feedback Failed": "提交反馈异常", @@ -504,7 +479,6 @@ "Record": "语音输入", "Restart": "重开对话", "Run test": "运行预览", - "Select Image": "选择图片", "Select dataset": "选择知识库", "Select dataset Desc": "选择一个知识库存储预期答案", "Send Message": "发送", @@ -529,9 +503,9 @@ "logs": { "api": "API 调用", "feishu": "飞书", + "free_login": "免登录链接", "official_account": "公众号", "online": "在线使用", - "free_login": "免登录链接", "share": "外部链接调用", "team": "团队空间对话", "test": "测试", @@ -549,10 +523,8 @@ "response": { "Complete Response": "完整响应", "Extension model": "问题优化模型", - "Plugin response detail": "插件详情", "Read complete response": "查看详情", "Read complete response tips": "点击查看详细流程", - "Tool call response detail": "工具运行详情", "Tool call tokens": "工具调用 tokens 消耗", "context total length": "上下文总长度", "module cq": "问题分类列表", @@ -589,14 +561,11 @@ } }, "dataset": { - "All Dataset": "全部知识库", - "Avatar": "知识库头像", "Choose Dataset": "关联知识库", "Collection": "数据集", "Create dataset": "创建一个{{name}}", "Dataset": "知识库", "Dataset ID": "知识库 ID", - "Dataset Type": "知识库类型", "Delete Confirm": "确认删除该知识库?删除后数据无法恢复,请确认!", "Empty Dataset": "空数据集", "Empty Dataset Tips": "还没有知识库,快去创建一个吧!", @@ -605,7 +574,6 @@ "Intro Placeholder": "这个知识库还没有介绍~", "Manual collection": "手动数据集", "My Dataset": "我的知识库", - "Name": "知识库名称", "Query extension intro": "开启问题优化功能,可以提高提高连续对话时,知识库搜索的精度。开启该功能后,在进行知识库搜索时,会根据对话记录,利用 AI 补全问题缺失的信息。", "Quote Length": "引用内容长度", "Read Dataset": "查看知识库详情", @@ -629,7 +597,6 @@ "Chunk Size": "分割大小", "Createtime": "创建时间", "Raw text length": "原文长度", - "Read Metadata": "查看元数据", "Training Type": "训练模式", "Updatetime": "更新时间", "Web page selector": "网站选择器", @@ -664,7 +631,6 @@ "Search data placeholder": "搜索相关数据", "Too Long": "总长度超长了", "Total Amount": "{{total}} 组", - "empty_index": "无自定义索引", "group": "组", "unit": "条" }, @@ -672,7 +638,6 @@ "error": { "Data not found": "数据不存在或已被删除", "Start Sync Failed": "开始同步失败", - "Template does not exist": "模板不存在", "invalidVectorModelOrQAModel": "VectorModel 或 QA 模型错误", "unAuthDataset": "无权操作该知识库", "unAuthDatasetCollection": "无权操作该数据集", @@ -813,7 +778,6 @@ "Add question type": "添加问题类型", "Add_option": "添加选项", "Can not connect self": "不能连接自身", - "Confirm Delete Node": "确认删除该节点?", "Data Type": "数据类型", "Dataset quote": { "label": "知识库引用", @@ -858,19 +822,15 @@ }, "http": { "Add props": "添加参数", - "Add props_and_tips": "添加参数,输入“/”唤起变量列表", "AppId": "应用 ID", - "AppSecret": "AppSecret", "ChatId": "当前对话 ID", "Current time": "当前时间", "Histories": "历史记录", "Key already exists": "Key 已经存在", "Key cannot be empty": "参数名不能为空", "Props name": "参数名", - "Props name_and_tips": "参数名,输入”/“唤起变量列表", "Props tip": "可以设置 HTTP 请求的相关参数\n可通过输入 / 来调用变量,当前可使用变量:\n{{variable}}", "Props value": "参数值", - "Props value_and_tips": "参数值,输入“/”唤起变量列表", "ResponseChatItemId": "AI 回复的 ID", "Url and params have been split": "路径参数已被自动加入 Params 中", "curl import": "cURL 导入", @@ -922,22 +882,20 @@ "Query extension": "问题优化", "System Plugin": "系统插件", "System input module": "系统输入", - "Team Plugin": "团队插件", "Team app": "团队应用", "Tool module": "工具", "UnKnow Module": "未知模块", - "http body placeholder": "与 Apifox 相同的语法", - "empty_workflow": "空白工作流", - "empty_app": "空白应用", + "ai_chat": "AI 对话", + "ai_chat_intro": "AI 大模型对话", + "config_params": "可以配置应用的系统参数", "empty_plugin": "空白插件", - "system_config": "系统配置", - "system_config_info": "可以配置应用的系统参数", - "work_start": "流程开始", + "empty_workflow": "空白工作流", + "http body placeholder": "与 Apifox 相同的语法", "self_input": "自定义插件输入", "self_output": "自定义插件输出", - "config_params": "可以配置应用的系统参数", - "ai_chat": "AI 对话", - "ai_chat_intro": "AI 大模型对话" + "system_config": "系统配置", + "system_config_info": "可以配置应用的系统参数", + "work_start": "流程开始" }, "templates": { "Load plugin error": "加载插件失败" @@ -958,9 +916,7 @@ "variable option is value is required": "选项内容不能为空", "variable options": "选项" }, - "variable add option": "添加选项", - "variable_update": "变量更新", - "variable_update_info": "可以更新指定节点的输出值或更新全局变量" + "variable add option": "添加选项" }, "plugin": { "Custom headers": "自定义请求头", @@ -1008,7 +964,6 @@ "Reference": "变量引用", "custom": "自定义变量", "dynamicTargetInput": "动态外部数据", - "file_link": "文件上传", "input": "单行输入框", "number input": "数字输入框", "select": "单选框", @@ -1023,7 +978,6 @@ "OnRevert version confirm": "确认回退至该版本?会为您保存编辑中版本的配置,并为回退版本创建一个新的发布版本。", "histories": "发布记录" }, - "run_test": "运行", "template": { "Interactive": "交互", "Multimodal": "多模态", @@ -1067,21 +1021,14 @@ "Select One Collection To Store": "选择一个文件进行存储" }, "data": { - "Add Index": "新增自定义索引", "Can not edit": "无编辑权限", "Custom Index Number": "自定义索引{{number}}", "Default Index": "默认索引", "Delete Tip": "确认删除该条数据?", - "Index Edit": "数据索引", "Index Placeholder": "输入索引文本内容", - "Input Data": "导入新数据", "Input Success Tip": "导入数据成功", - "Update Data": "更新数据", "Update Success Tip": "更新数据成功", "edit": { - "Content": "数据内容", - "Course": "说明文档", - "Delete": "删除数据", "Index": "数据索引({{amount}})", "divide_content": "分块内容" }, @@ -1093,19 +1040,15 @@ "noResult": "搜索结果为空" } }, - "default_reply": "默认回复", "error": { "Create failed": "创建失败", - "code_error": "验证码错误", "fileNotFound": "文件找不到了~", "inheritPermissionError": "权限继承错误", "missingParams": "参数缺失", - "team": { - "overSize": "团队成员超出上限" - }, "upload_file_error_filename": "{{name}} 上传失败", "username_empty": "账号不能为空" }, + "error.code_error": "验证码错误", "extraction_results": "提取结果", "field_name": "字段名", "free": "免费", @@ -1141,28 +1084,16 @@ }, "new_create": "新建", "no": "否", - "no_data": "暂无数据", "no_laf_env": "系统未配置Laf环境", "not_yet_introduced": "暂无介绍", "option": "选项", "pay": { "amount": "金额", - "balance": "账号余额", - "balance_notice": "账号余额不足", - "confirm_pay": "确认支付", - "get_pay_QR": "获取充值二维码", - "need_pay": "需支付", - "need_to_pay": "实付", - "new_package_price": "新套餐价格", - "notice": "请勿关闭页面", - "old_package_price": "旧套餐余额", - "other": "其他金额,请取整数", "package_tip": { "buy": "您购买的套餐等级低于当前套餐,该套餐将在当前套餐过期后生效。\n您可在账号—个人信息—套餐详情里,查看套餐使用情况。", "renewal": "您正在续费套餐。您可在账号—个人信息—套餐详情里,查看套餐使用情况。", "upgrade": "您购买的套餐等级高于当前套餐,该套餐将即刻生效,当前套餐将延后生效。您可在账号—个人信息—套餐详情里,查看套餐使用情况。" }, - "to_recharge": "余额不足,去充值", "wechat": "请微信扫码支付: {{price}}元\n请勿关闭页面", "yuan": "{{amount}}元" }, @@ -1170,9 +1101,6 @@ "Collaborator": "协作者", "Default permission": "默认权限", "Manage": "管理", - "manager": "管理员", - "read": "读权限", - "write": "写权限", "No InheritPermission": "已限制权限,不再继承父级文件夹的权限,", "Not collaborator": "暂无协作者", "Owner": "创建者", @@ -1191,7 +1119,10 @@ "change_owner_placeholder": "输入用户名查找账号", "change_owner_success": "成功转移所有权", "change_owner_tip": "转移后您的权限不会保留", - "change_owner_to": "转移给" + "change_owner_to": "转移给", + "manager": "管理员", + "read": "读权限", + "write": "写权限" }, "plugin": { "App": "选择应用", @@ -1217,7 +1148,6 @@ "go to laf": "去编写", "path": "路径" }, - "reply_now": "立即回复", "required": "必须", "resume_failed": "恢复失败", "select_reference_variable": "选择引用变量", @@ -1251,8 +1181,6 @@ }, "standard": { "AI Bonus Points": "AI 积分", - "Expired Time": "结束时间", - "Start Time": "开始时间", "due_date": "到期时间", "storage": "存储量", "type": "类型" @@ -1278,22 +1206,14 @@ "System message": "系统消息" }, "login": { - "And": "和", "Email": "邮箱", - "Forget Password": "忘记密码?", "Github": "GitHub 登录", "Google": "Google 登录", "Password": "密码", "Password login": "密码登录", "Phone": "手机号登录", "Phone number": "手机号", - "Policy tip": "使用即代表你同意我们的", - "Privacy": "隐私政策", "Provider error": "登录异常,请重试", - "Register": "注册账号", - "Root login": "使用 root 用户登录", - "Root password placeholder": "root 密码为你设置的环境变量", - "Terms": "服务协议", "Username": "用户名", "Wechat": "微信登录", "can_not_login": "无法登录,点击联系", @@ -1313,12 +1233,9 @@ "wallet": { "Ai point every thousand tokens": "{{points}} 积分/1K tokens", "Amount": "金额", - "Bills": "账单与开票", "Buy": "购买", - "Confirm pay": "支付确认", "Not sufficient": "您的 AI 积分不足,请先升级套餐或购买额外 AI 积分后继续使用。", "Plan expired time": "套餐到期时间", - "Plan reset time": "套餐重置时间", "Standard Plan Detail": "套餐详情", "To read plan": "查看套餐", "amount_0": "购买数量不能为0", @@ -1355,7 +1272,6 @@ "company_address": "公司地址", "company_phone": "公司电话", "email": "邮箱地址", - "in_valid": "存在空字段或邮箱格式错误", "need_special_invoice": "是否需要专票", "organization_name": "组织名称", "unit_code": "统一信用代码" @@ -1375,7 +1291,6 @@ "AI points usage": "AI 积分使用量", "AI points usage tip": "每次调用 AI 模型时,都会消耗一定的 AI 积分。具体的计算标准可参考上方的“计费标准”", "Ai points": "AI 积分计算标准", - "Buy now": "切换套餐", "Current plan": "当前套餐", "Extra ai points": "额外 AI 积分", "Extra dataset size": "额外知识库容量", @@ -1384,10 +1299,7 @@ "FAQ": "常见问题", "Month amount": "月数", "Next plan": "未来套餐", - "Nonsupport": "无需购买", "Stand plan level": "订阅套餐", - "Standard update fail": "修改订阅套餐异常", - "Standard update success": "变更订阅套餐成功!", "Sub plan": "订阅套餐", "Sub plan tip": "免费使用 {{title}} 或升级更高的套餐", "Team plan and usage": "套餐与用量", @@ -1453,8 +1365,7 @@ "Total points": "AI 积分消耗", "Usage Detail": "使用详情", "Whisper": "语音输入" - }, - "use_default": "使用默认抬头" + } } }, "sync_link": "同步链接", @@ -1491,28 +1402,23 @@ "Laf Account Setting": "laf 账号配置", "Language": "语言", "Member Name": "昵称", - "Notice": "通知", "Notification Receive": "通知接收", "Notification Receive Bind": "请先绑定通知接收途径", "Old password is error": "旧密码错误", "OpenAI Account Setting": "OpenAI 账号配置", "Password": "密码", "Pay": "充值", - "Personal Information": "个人信息", "Promotion": "促销", "Promotion Rate": "返现比例", - "Promotion Record": "推广记录", "Promotion rate tip": "好友充值时你将获得一定比例的余额奖励", "Replace": "更换", "Set OpenAI Account Failed": "设置 OpenAI 账号异常", - "Sign Out": "登出", "Team": "团队", "Time": "时间", "Timezone": "时区", "Update Password": "修改密码", "Update password failed": "修改密码异常", "Update password successful": "修改密码成功", - "Usage Record": "使用记录", "apikey": { "key": "API 密钥" }, @@ -1567,8 +1473,7 @@ }, "role": { "Admin": "管理员", - "Owner": "创建者", - "Visitor": "访客" + "Owner": "创建者" } }, "type": "类型" @@ -1576,4 +1481,4 @@ "verification": "验证", "xx_search_result": "{{key}} 的搜索结果", "yes": "是" -} +} \ No newline at end of file diff --git a/packages/web/i18n/zh/dataset.json b/packages/web/i18n/zh/dataset.json index 32a06cb14e91..253d36e34e3e 100644 --- a/packages/web/i18n/zh/dataset.json +++ b/packages/web/i18n/zh/dataset.json @@ -1,7 +1,5 @@ { - "Disabled": "已禁用", "Enable": "启用", - "Enabled": "已启用", "collection": { "Create update time": "创建/更新时间", "Training type": "训练模式" @@ -47,4 +45,4 @@ "manage": "可管理整个知识库数据和信息" } } -} +} \ No newline at end of file diff --git a/packages/web/i18n/zh/file.json b/packages/web/i18n/zh/file.json index 700856fd3b1d..839fe4c828a6 100644 --- a/packages/web/i18n/zh/file.json +++ b/packages/web/i18n/zh/file.json @@ -15,4 +15,4 @@ "upload_failed": "上传异常", "reached_max_file_count": "已达到最大文件数量", "upload_error_description": "单次只支持上传多个文件或者一个文件夹" -} +} \ No newline at end of file diff --git a/packages/web/i18n/zh/login.json b/packages/web/i18n/zh/login.json new file mode 100644 index 000000000000..c66304e06c8c --- /dev/null +++ b/packages/web/i18n/zh/login.json @@ -0,0 +1,13 @@ +{ + "Login": "登录", + "forget_password": "忘记密码?", + "login_failed": "登录异常", + "login_success": "登录成功", + "password_condition": "密码最多 60 位", + "policy_tip": "使用即代表你同意我们的", + "privacy": "隐私协议", + "register": "注册账号", + "root_password_placeholder": "root 用户密码为环境变量 DEFAULT_ROOT_PSW 的值", + "terms": "服务协议", + "use_root_login": "使用 root 用户登录" +} \ No newline at end of file diff --git a/packages/web/i18n/zh/publish.json b/packages/web/i18n/zh/publish.json index 484bece90de0..be0a52555c33 100644 --- a/packages/web/i18n/zh/publish.json +++ b/packages/web/i18n/zh/publish.json @@ -4,20 +4,17 @@ "copy_link_hint": "将下面链接复制到指定位置", "create_api_key": "创建新 key", "create_link": "创建链接", - "default_response": "默认回复", "edit_api_key": "编辑 key 信息", "edit_feishu_bot": "编辑飞书机器人", "edit_link": "编辑", "feishu_api": "飞书接口", "feishu_bot": "飞书机器人", "feishu_bot_desc": "通过 API 直接接入飞书机器人", - "feishu_name": "飞书", "key_alias": "key 的别名,仅用于展示", "key_tips": "你可以使用 API 密钥访问一些特定的接口(无法访问应用,访问应用需使用应用内的 API key)", "link_name": "分享链接的名字", "new_feishu_bot": "新增飞书机器人", "official_account": { - "api": "微信公众号 API", "create_modal_title": "创建微信公众号接入", "desc": "通过 API 直接接入微信公众号", "edit_modal_title": "编辑微信公众号接入", @@ -40,4 +37,4 @@ "edit_modal_title": "编辑企微机器人", "title": "发布到企业微信机器人" } -} +} \ No newline at end of file diff --git a/packages/web/i18n/zh/user.json b/packages/web/i18n/zh/user.json index 1e4b43116cb4..ff3b50e079ae 100644 --- a/packages/web/i18n/zh/user.json +++ b/packages/web/i18n/zh/user.json @@ -2,13 +2,14 @@ "bill": { "balance": "余额", "buy_plan": "购买套餐", - "buy_standard_plan_success": "购买套餐成功", "contact_customer_service": "联系客服", "conversion": "兑换", "convert_error": "兑换失败", "convert_success": "兑换成功", + "current_token_price": "当前积分价格", "not_need_invoice": "余额支付,无法开票", "price": "价格", + "renew_plan": "续费套餐", "standard_valid_tip": "套餐使用规则:系统优先使用更高级的套餐,原未用完的套餐将延后生效", "token_expire_1year": "积分有效期一年", "tokens": "积分", @@ -16,14 +17,9 @@ "use_balance_hint": "由于系统升级,原“自动续费从余额扣款”模式取消,余额充值入口关闭。您的余额可用于购买积分", "valid_time": "生效时间", "you_can_convert": "您可兑换", - "renew_plan": "续费套餐", - "current_token_price": "当前积分价格", "yuan": "元" }, - "promotion": { - "register": "好友注册", - "pay": "好友充值" - }, + "bill_and_invoices": "账单 & 发票", "bind_inform_account_error": "绑定通知账号异常", "bind_inform_account_success": "绑定通知账号成功", "delete": { @@ -31,28 +27,24 @@ "admin_success": "删除管理员成功" }, "has_chosen": "已选择", + "individuation": "个性化", "login": { "error": "登录异常", - "failed": "登录失败", - "login_account": "登录 {{account}} 账号", - "login_error": "用户名或密码错误", "password_condition": "密码最多 60 位", - "success": "登录成功", - "to_register": "没有账号,去注册" + "success": "登录成功" }, "name": "名称", + "notice": "通知", "notification": { "Bind Notification Pipe Hint": "请绑定通知接收账号,以确保您能正常接收套餐过期提醒等通知,保障您的服务正常运行。", "remind_owner_bind": "请提醒创建者绑定通知账号" }, "operations": "操作", "password": { - "change_error": "修改密码异常", "code_required": "验证码不能为空", "code_send_error": "验证码发送异常", "code_sended": "验证码已发送", "confirm": "确认密码", - "email_phone": "邮箱/手机号", "email_phone_error": "邮箱/手机号格式错误", "email_phone_void": "邮箱/手机号不能为空", "get_code": "获取验证码", @@ -78,16 +70,23 @@ "team_read": "团队可访问", "team_write": "团队可编辑" }, + "permission_des": { + "manage": "可创建资源、邀请、删除成员", + "read": "成员仅可阅读相关资源,无法新建资源", + "write": "除了可读资源外,还可以新建新的资源" + }, "permissions": "权限", + "personal_information": "个人信息", + "personalization": "个性化", + "promotion_records": "推广记录", "register": { "confirm": "确认注册", - "error": "注册异常", - "failed": "注册失败", "register_account": "注册 {{account}} 账号", "success": "注册成功", "to_login": "已有账号,去登录" }, "search_user": "搜索用户名", + "sign_out": "登出", "synchronization": { "button": "立即同步", "placeholder": "请输入同步标签", @@ -105,9 +104,5 @@ "share": "分享链接", "wecom": "企业微信" }, - "permission_des": { - "read": "成员仅可阅读相关资源,无法新建资源", - "write": "除了可读资源外,还可以新建新的资源", - "manage": "可创建资源、邀请、删除成员" - } -} + "usage_record": "使用记录" +} \ No newline at end of file diff --git a/packages/web/i18n/zh/workflow.json b/packages/web/i18n/zh/workflow.json index 476823b2e973..53ac080ed1c1 100644 --- a/packages/web/i18n/zh/workflow.json +++ b/packages/web/i18n/zh/workflow.json @@ -1,11 +1,4 @@ { - " i18nT('workflow": { - "use_user_id'),\n required": { - "workflow": { - "use_user_id": "使用者 ID" - } - } - }, "Code": "代码", "about_xxx_question": "关于 xxx 的问题", "add_new_input": "新增输入", @@ -122,15 +115,12 @@ "Custom outputs": "自定义输出", "Error": "错误信息", "Read file result": "文档解析结果预览", - "User_select_description": "说明文字", - "User_select_result": "选择的结果", "read files": "解析的文档" }, "select_an_application": "选择一个应用", "select_another_application_to_call": "可以选择一个其他应用进行调用", "special_array_format": "特殊数组格式,搜索结果为空时,返回空数组。", "start_with": "开始为", - "system_variables": "系统变量", "target_fields_description": "由 '描述' 和 'key' 组成一个目标字段,可提取多个目标字段", "template": { "ai_chat": "AI 对话", @@ -156,11 +146,9 @@ "variable_picker_tips": "可输入节点名或变量名搜索", "variable_update": "变量更新", "workflow": { - "Back_to_current_version": "回到初始状态", "My edit": "我的编辑", - "Switch_failed": "切换失败", "Switch_success": "切换成功", "Team cloud": "团队云端", "exit_tips": "您的更改尚未保存,「直接退出」将不会保存您的编辑记录。" } -} +} \ No newline at end of file diff --git a/packages/web/package.json b/packages/web/package.json index d487c19216df..6fd345e57006 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -21,25 +21,27 @@ "ahooks": "^3.7.11", "date-fns": "2.30.0", "dayjs": "^1.11.7", + "i18next": "23.11.5", + "js-cookie": "^3.0.5", "lexical": "0.12.6", "lodash": "^4.17.21", - "i18next": "23.11.5", "next-i18next": "15.3.0", - "react-i18next": "14.1.2", "papaparse": "^5.4.1", "react": "18.3.1", "react-beautiful-dnd": "^13.1.1", "react-day-picker": "^8.7.1", "react-dom": "18.3.1", "react-hook-form": "7.43.1", + "react-i18next": "14.1.2", "react-photo-view": "^1.2.6", "use-context-selector": "^1.4.4" }, "devDependencies": { + "@types/js-cookie": "^3.0.5", "@types/lodash": "^4.14.191", "@types/papaparse": "^5.3.7", "@types/react": "18.3.1", "@types/react-beautiful-dnd": "^13.1.1", "@types/react-dom": "18.3.0" } -} \ No newline at end of file +} diff --git a/packages/web/types/i18next.d.ts b/packages/web/types/i18next.d.ts index 3d2b7b68e55b..9de5ca103ccc 100644 --- a/packages/web/types/i18next.d.ts +++ b/packages/web/types/i18next.d.ts @@ -7,6 +7,7 @@ import publish from '../i18n/zh/publish.json'; import workflow from '../i18n/zh/workflow.json'; import user from '../i18n/zh/user.json'; import chat from '../i18n/zh/chat.json'; +import login from '../i18n/zh/login.json'; export interface I18nNamespaces { common: typeof common; @@ -17,18 +18,11 @@ export interface I18nNamespaces { workflow: typeof workflow; user: typeof user; chat: typeof chat; + login: typeof login; } export type I18nNsType = (keyof I18nNamespaces)[]; -export type I18nCommonKey = NestedKeyOf; -export type I18nDataSetKey = NestedKeyOf; -export type I18nAppKey = NestedKeyOf; -export type I18nPublishKey = NestedKeyOf; -export type I18nWorkflowKey = NestedKeyOf; -export type I18nUserKey = NestedKeyOf; -export type I18nChatKey = NestedKeyOf; - export type NestedKeyOf = { [Key in keyof ObjectType & (string | number)]: ObjectType[Key] extends object ? `${Key}` | `${Key}.${NestedKeyOf}` @@ -46,7 +40,7 @@ export type I18nKeyFunction = { declare module 'i18next' { interface CustomTypeOptions { returnNull: false; - defaultNS: ['common', 'dataset', 'app', 'file', 'publish', 'workflow', 'user', 'chat']; + defaultNS: ['common', 'dataset', 'app', 'file', 'publish', 'workflow', 'user', 'chat', 'login']; resources: I18nNamespaces; } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 180d6b1018e9..5eefba80b138 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,7 +22,7 @@ importers: version: 13.3.0 next-i18next: specifier: 15.3.0 - version: 15.3.0(i18next@23.11.5)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-i18next@14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 15.3.0(i18next@23.11.5)(next@14.2.5(@babel/core@7.24.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-i18next@14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) prettier: specifier: 3.2.4 version: 3.2.4 @@ -250,7 +250,7 @@ importers: version: 2.1.1(@chakra-ui/system@2.6.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(react@18.3.1))(react@18.3.1) '@chakra-ui/next-js': specifier: 2.1.5 - version: 2.1.5(@chakra-ui/react@2.8.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react@18.3.1) + version: 2.1.5(@chakra-ui/react@2.8.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.5(@babel/core@7.24.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react@18.3.1) '@chakra-ui/react': specifier: 2.8.1 version: 2.8.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -302,6 +302,9 @@ importers: i18next: specifier: 23.11.5 version: 23.11.5 + js-cookie: + specifier: ^3.0.5 + version: 3.0.5 lexical: specifier: 0.12.6 version: 0.12.6 @@ -310,7 +313,7 @@ importers: version: 4.17.21 next-i18next: specifier: 15.3.0 - version: 15.3.0(i18next@23.11.5)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-i18next@14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 15.3.0(i18next@23.11.5)(next@14.2.5(@babel/core@7.24.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-i18next@14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) papaparse: specifier: ^5.4.1 version: 5.4.1 @@ -339,6 +342,9 @@ importers: specifier: ^1.4.4 version: 1.4.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) devDependencies: + '@types/js-cookie': + specifier: ^3.0.5 + version: 3.0.6 '@types/lodash': specifier: ^4.14.191 version: 4.17.7 @@ -368,7 +374,7 @@ importers: version: 2.1.1(@chakra-ui/system@2.6.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(react@18.3.1))(react@18.3.1) '@chakra-ui/next-js': specifier: 2.1.5 - version: 2.1.5(@chakra-ui/react@2.8.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react@18.3.1) + version: 2.1.5(@chakra-ui/react@2.8.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.5(@babel/core@7.24.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react@18.3.1) '@chakra-ui/react': specifier: 2.8.1 version: 2.8.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -464,7 +470,7 @@ importers: version: 14.2.5(@babel/core@7.24.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8) next-i18next: specifier: 15.3.0 - version: 15.3.0(i18next@23.11.5)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-i18next@14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 15.3.0(i18next@23.11.5)(next@14.2.5(@babel/core@7.24.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-i18next@14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) nextjs-node-loader: specifier: ^1.1.5 version: 1.1.5(webpack@5.92.1) @@ -529,9 +535,6 @@ importers: '@types/formidable': specifier: ^2.0.5 version: 2.0.6 - '@types/js-cookie': - specifier: ^3.0.3 - version: 3.0.6 '@types/js-yaml': specifier: ^4.0.9 version: 4.0.9 @@ -6015,6 +6018,10 @@ packages: js-cookie@2.2.1: resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} + js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -10024,7 +10031,7 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@chakra-ui/next-js@2.1.5(@chakra-ui/react@2.8.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react@18.3.1)': + '@chakra-ui/next-js@2.1.5(@chakra-ui/react@2.8.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.5(@babel/core@7.24.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react@18.3.1)': dependencies: '@chakra-ui/react': 2.8.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@emotion/cache': 11.11.0 @@ -15529,6 +15536,8 @@ snapshots: js-cookie@2.2.1: {} + js-cookie@3.0.5: {} + js-tokens@4.0.0: {} js-tokens@9.0.0: {} @@ -16625,7 +16634,7 @@ snapshots: neo-async@2.6.2: {} - next-i18next@15.3.0(i18next@23.11.5)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-i18next@14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): + next-i18next@15.3.0(i18next@23.11.5)(next@14.2.5(@babel/core@7.24.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-i18next@14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.24.8 '@types/hoist-non-react-statics': 3.3.5 diff --git a/projects/app/next-i18next.config.js b/projects/app/next-i18next.config.js index 5d84d7ecfdda..910a4bd3b2d0 100644 --- a/projects/app/next-i18next.config.js +++ b/projects/app/next-i18next.config.js @@ -5,11 +5,11 @@ module.exports = { i18n: { - defaultLocale: 'zh', + defaultLocale: 'en', locales: ['en', 'zh'], localeDetection: false }, localePath: typeof window === 'undefined' ? require('path').resolve('../../packages/web/i18n') : '/i18n', reloadOnPrerender: process.env.NODE_ENV === 'development' -} +}; diff --git a/projects/app/package.json b/projects/app/package.json index 055b9016babf..f46e6bf5b349 100644 --- a/projects/app/package.json +++ b/projects/app/package.json @@ -68,7 +68,6 @@ "devDependencies": { "@svgr/webpack": "^6.5.1", "@types/formidable": "^2.0.5", - "@types/js-cookie": "^3.0.3", "@types/js-yaml": "^4.0.9", "@types/jsonwebtoken": "^9.0.3", "@types/lodash": "^4.14.191", diff --git a/projects/app/src/components/Layout/index.tsx b/projects/app/src/components/Layout/index.tsx index 2d783cd5ebb5..1cd1ed0dc89a 100644 --- a/projects/app/src/components/Layout/index.tsx +++ b/projects/app/src/components/Layout/index.tsx @@ -7,9 +7,11 @@ import { useQuery } from '@tanstack/react-query'; import { useUserStore } from '@/web/support/user/useUserStore'; import { getUnreadCount } from '@/web/support/user/inform/api'; import dynamic from 'next/dynamic'; +import { useI18nLng } from '@fastgpt/web/hooks/useI18n'; import Auth from './auth'; import { useSystem } from '@fastgpt/web/hooks/useSystem'; +import { useMount } from 'ahooks'; const Navbar = dynamic(() => import('./navbar')); const NavbarPhone = dynamic(() => import('./navbarPhone')); const UpdateInviteModal = dynamic(() => import('@/components/support/user/team/UpdateInviteModal')); @@ -46,6 +48,7 @@ const Layout = ({ children }: { children: JSX.Element }) => { const { loading, feConfigs, isNotSufficientModal } = useSystemStore(); const { isPc } = useSystem(); const { userInfo } = useUserStore(); + const { setUserDefaultLng } = useI18nLng(); const isChatPage = useMemo( () => router.pathname === '/chat' && Object.values(router.query).join('').length !== 0, @@ -61,6 +64,10 @@ const Layout = ({ children }: { children: JSX.Element }) => { const isHideNavbar = !!pcUnShowLayoutRoute[router.pathname]; + useMount(() => { + setUserDefaultLng(); + }); + return ( <> diff --git a/projects/app/src/components/support/user/safe/SendCodeAuthModal.tsx b/projects/app/src/components/support/user/safe/SendCodeAuthModal.tsx index 2a6762f5a709..dc70ef8126ef 100644 --- a/projects/app/src/components/support/user/safe/SendCodeAuthModal.tsx +++ b/projects/app/src/components/support/user/safe/SendCodeAuthModal.tsx @@ -37,7 +37,7 @@ const SendCodeAuthModal = ({ { const { t, i18n } = useTranslation(); const { userInfo, updateUserInfo } = useUserStore(); const { toast } = useToast(); - const router = useRouter(); + const { onChangeLng } = useI18nLng(); const { reset } = useForm({ defaultValues: userInfo as UserType @@ -55,14 +57,7 @@ const Individuation = () => { }))} onchange={(val: any) => { const lang = val; - setLngStore(lang); - router.replace( - { - query: router.query - }, - router.asPath, - { locale: lang } - ); + onChangeLng(lang); }} /> diff --git a/projects/app/src/pages/account/index.tsx b/projects/app/src/pages/account/index.tsx index 8d191a3492d4..1352c490a842 100644 --- a/projects/app/src/pages/account/index.tsx +++ b/projects/app/src/pages/account/index.tsx @@ -40,14 +40,14 @@ const Account = ({ currentTab }: { currentTab: TabEnum }) => { const tabList = [ { icon: 'support/user/userLight', - label: t('common:user.Personal Information'), + label: t('user:personal_information'), value: TabEnum.info }, ...(feConfigs?.isPlus ? [ { icon: 'support/usage/usageRecordLight', - label: t('common:user.Usage Record'), + label: t('user:usage_record'), value: TabEnum.usage } ] @@ -57,7 +57,7 @@ const Account = ({ currentTab }: { currentTab: TabEnum }) => { ? [ { icon: 'support/bill/payRecordLight', - label: t('common:support.wallet.Bills'), + label: t('user:bill_and_invoices'), value: TabEnum.bill } ] @@ -67,7 +67,7 @@ const Account = ({ currentTab }: { currentTab: TabEnum }) => { ? [ { icon: 'support/account/promotionLight', - label: t('common:user.Promotion Record'), + label: t('user:promotion_records'), value: TabEnum.promotion } ] @@ -83,14 +83,14 @@ const Account = ({ currentTab }: { currentTab: TabEnum }) => { : []), { icon: 'support/user/individuation', - label: t('common:support.account.Individuation'), + label: t('user:personalization'), value: TabEnum.individuation }, ...(feConfigs.isPlus ? [ { icon: 'support/user/informLight', - label: t('common:user.Notice'), + label: t('user:notice'), value: TabEnum.inform } ] @@ -98,7 +98,7 @@ const Account = ({ currentTab }: { currentTab: TabEnum }) => { { icon: 'support/account/loginoutLight', - label: t('common:user.Sign Out'), + label: t('user:sign_out'), value: TabEnum.loginout } ]; diff --git a/projects/app/src/pages/app/detail/components/Plugin/Header.tsx b/projects/app/src/pages/app/detail/components/Plugin/Header.tsx index 920167330000..632625e24874 100644 --- a/projects/app/src/pages/app/detail/components/Plugin/Header.tsx +++ b/projects/app/src/pages/app/detail/components/Plugin/Header.tsx @@ -125,9 +125,14 @@ const Header = () => { try { localStorage.removeItem(`${appDetail._id}-past`); localStorage.removeItem(`${appDetail._id}-future`); - router.back(); + router.push({ + pathname: '/app/list', + query: { + parentId: appDetail.parentId + } + }); } catch (error) {} - }, [appDetail._id, router]); + }, [appDetail._id, appDetail.parentId, router]); const Render = useMemo(() => { return ( diff --git a/projects/app/src/pages/app/detail/components/Workflow/Header.tsx b/projects/app/src/pages/app/detail/components/Workflow/Header.tsx index 920167330000..632625e24874 100644 --- a/projects/app/src/pages/app/detail/components/Workflow/Header.tsx +++ b/projects/app/src/pages/app/detail/components/Workflow/Header.tsx @@ -125,9 +125,14 @@ const Header = () => { try { localStorage.removeItem(`${appDetail._id}-past`); localStorage.removeItem(`${appDetail._id}-future`); - router.back(); + router.push({ + pathname: '/app/list', + query: { + parentId: appDetail.parentId + } + }); } catch (error) {} - }, [appDetail._id, router]); + }, [appDetail._id, appDetail.parentId, router]); const Render = useMemo(() => { return ( diff --git a/projects/app/src/pages/dataset/list/component/List.tsx b/projects/app/src/pages/dataset/list/component/List.tsx index c153de80b5fc..07405ff2a571 100644 --- a/projects/app/src/pages/dataset/list/component/List.tsx +++ b/projects/app/src/pages/dataset/list/component/List.tsx @@ -272,7 +272,7 @@ function List() { {owner && ( - + {owner.memberName} @@ -288,7 +288,9 @@ function List() { {isPc && ( - {formatTimeToChatTime(dataset.updateTime)} + + {formatTimeToChatTime(dataset.updateTime)} + )} {dataset.permission.hasWritePer && ( diff --git a/projects/app/src/pages/login/components/LoginForm/LoginForm.tsx b/projects/app/src/pages/login/components/LoginForm/LoginForm.tsx index 7d4ad606c002..149f3d13628a 100644 --- a/projects/app/src/pages/login/components/LoginForm/LoginForm.tsx +++ b/projects/app/src/pages/login/components/LoginForm/LoginForm.tsx @@ -43,12 +43,12 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => { }) ); toast({ - title: t('user:login.success'), + title: t('login:login_success'), status: 'success' }); } catch (error: any) { toast({ - title: error.message || t('user:login.error'), + title: error.message || t('login:login_failed'), status: 'error' }); } @@ -61,7 +61,7 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => { const placeholder = (() => { if (isCommunityVersion) { - return t('common:support.user.login.Root login'); + return t('login:use_root_login'); } return [t('common:support.user.login.Username')] .concat( @@ -102,36 +102,36 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => { type={'password'} placeholder={ isCommunityVersion - ? t('common:support.user.login.Root password placeholder') + ? t('login:root_password_placeholder') : t('common:support.user.login.Password') } {...register('password', { required: true, maxLength: { value: 60, - message: t('user:login.password_condition') + message: t('login:password_condition') } })} > {feConfigs?.docUrl && ( - - {t('common:support.user.login.Policy tip')} + + {t('login:policy_tip')} - {t('common:support.user.login.Terms')} + {t('login:terms')} - {t('common:support.user.login.And')} + & - {t('common:support.user.login.Privacy')} + {t('login:privacy')} )} @@ -145,7 +145,7 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => { isLoading={requesting} onClick={handleSubmit(onclickLogin)} > - {t('common:Login')} + {t('login:Login')} @@ -156,7 +156,7 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => { onClick={() => setPageType('forgetPassword')} fontSize="sm" > - {t('common:support.user.login.Forget Password')} + {t('login:forget_password')} )} {feConfigs?.register_method && feConfigs.register_method.length > 0 && ( @@ -168,7 +168,7 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => { onClick={() => setPageType('register')} fontSize="sm" > - {t('common:support.user.login.Register')} + {t('login:register')} )} diff --git a/projects/app/src/pages/login/index.tsx b/projects/app/src/pages/login/index.tsx index e04326ffe70c..f719aeb6f6e7 100644 --- a/projects/app/src/pages/login/index.tsx +++ b/projects/app/src/pages/login/index.tsx @@ -129,7 +129,7 @@ const Login = () => { export async function getServerSideProps(context: any) { return { - props: { ...(await serviceSideProps(context, ['app', 'user'])) } + props: { ...(await serviceSideProps(context, ['app', 'user', 'login'])) } }; } diff --git a/projects/app/src/web/common/utils/i18n.ts b/projects/app/src/web/common/utils/i18n.ts index 506ad74c6cd9..3e2d2102ec65 100644 --- a/projects/app/src/web/common/utils/i18n.ts +++ b/projects/app/src/web/common/utils/i18n.ts @@ -1,7 +1,6 @@ import { I18nNsType } from '@fastgpt/web/types/i18next'; import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; -export const LANG_KEY = 'NEXT_LOCALE_LANG'; export enum LangEnum { 'zh' = 'zh', 'en' = 'en' @@ -20,24 +19,3 @@ export const langMap = { export const serviceSideProps = (content: any, ns: I18nNsType = []) => { return serverSideTranslations(content.locale, ['common', 'error', ...ns], null, content.locales); }; - -export const getLng = (lng: string) => { - return lng.split('-')[0]; -}; -export const change2DefaultLng = (currentLng: string) => { - if (!navigator || !localStorage) return; - if (localStorage.getItem(LANG_KEY)) return; - const userLang = navigator.language; - - if (userLang.includes(currentLng)) { - return; - } - - // currentLng not in userLang - return getLng(userLang); -}; - -export const setLngStore = (lng: string) => { - if (!localStorage) return; - localStorage.setItem(LANG_KEY, lng); -}; diff --git a/projects/app/src/web/context/useInitApp.ts b/projects/app/src/web/context/useInitApp.ts index c63597124c1a..340c40146a36 100644 --- a/projects/app/src/web/context/useInitApp.ts +++ b/projects/app/src/web/context/useInitApp.ts @@ -1,17 +1,14 @@ import { useEffect, useState } from 'react'; import { clientInitData } from '@/web/common/system/staticData'; -import { useTranslation } from 'next-i18next'; import { useRouter } from 'next/router'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import type { FastGPTFeConfigsType } from '@fastgpt/global/common/system/types/index.d'; -import { change2DefaultLng, LangEnum, setLngStore } from '@/web/common/utils/i18n'; import { useMemoizedFn, useMount } from 'ahooks'; import { TrackEventName } from '../common/system/constants'; export const useInitApp = () => { const router = useRouter(); const { hiId } = router.query as { hiId?: string }; - const { i18n } = useTranslation(); const { loadGitStar, setInitd, feConfigs } = useSystemStore(); const [scripts, setScripts] = useState([]); const [title, setTitle] = useState(process.env.SYSTEM_NAME || 'AI'); @@ -38,20 +35,8 @@ export const useInitApp = () => { setInitd(); }); - const initUserLanguage = useMemoizedFn(() => { - // get default language - - const targetLng = - change2DefaultLng(i18n.language) || - (['zh', 'zh-CN'].includes(navigator.language) ? 'zh' : 'en'); - - setLngStore(targetLng); - router.replace(router.asPath, undefined, { locale: targetLng }); - }); - useMount(() => { initFetch(); - initUserLanguage(); const errorTrack = (event: ErrorEvent) => { window.umami?.track(TrackEventName.windowError, { diff --git a/scripts/i18n/delete-unused-keys.js b/scripts/i18n/delete-unused-keys.js deleted file mode 100644 index a6b8b643b070..000000000000 --- a/scripts/i18n/delete-unused-keys.js +++ /dev/null @@ -1,188 +0,0 @@ -const fs = require('fs').promises -const path = require('path') - -// 配置项 -const CONFIG = { - i18nDirectory: path.join(__dirname, '../../packages/web/i18n'), - sourceDirectories: ['../../packages', '../../projects/app'].map(dir => path.join(__dirname, dir)), - fileExtensions: ['.ts', '.tsx', '.js', '.jsx'], - ignoreDirectories: ['node_modules', '.next', 'public', 'i18n'] -} - -// 从文件中加载 JSON -const loadJSON = async (filePath) => { - try { - const data = await fs.readFile(filePath, 'utf8') - return JSON.parse(data) - } catch (error) { - console.error(`读取 JSON 文件 ${filePath} 时出错:`, error) - return null - } -} - -// 递归提取 JSON 对象的所有键 -const extractKeysFromJSON = (obj, parentKey = '') => { - let keys = [] - for (const [key, value] of Object.entries(obj)) { - const fullKey = parentKey ? `${parentKey}.${key}` : key - if (typeof value === 'object' && value !== null) { - keys = keys.concat(extractKeysFromJSON(value, fullKey)) - } else { - keys.push(fullKey) - } - } - return keys -} - -// 递归获取文件夹中的所有 JSON 文件 -const getAllJSONFiles = async (dir) => { - let results = [] - const list = await fs.readdir(dir) - await Promise.all(list.map(async (file) => { - const filePath = path.join(dir, file) - const stat = await fs.stat(filePath) - if (stat.isDirectory()) { - if (!CONFIG.ignoreDirectories.includes(file)) { - results = results.concat(await getAllJSONFiles(filePath)) - } - } else if (filePath.endsWith('.json')) { - results.push(filePath) - } - })) - return results -} - -// 提取文件夹中所有 JSON 文件的键 -const extractKeysFromDirectory = async (dir) => { - let allKeys = new Set() - - const subDirs = await fs.readdir(dir) - await Promise.all(subDirs.map(async (subDir) => { - const subDirPath = path.join(dir, subDir) - const stat = await fs.stat(subDirPath) - if (stat.isDirectory() && !CONFIG.ignoreDirectories.includes(subDir)) { - const files = await getAllJSONFiles(subDirPath) - await Promise.all(files.map(async (file) => { - const jsonObject = await loadJSON(file) - if (jsonObject) { - const keys = extractKeysFromJSON(jsonObject) - keys.forEach(key => allKeys.add(key)) - } - })) - } - })) - - return Array.from(allKeys) -} - -// 检查键是否在内容中使用 -const isKeyUsedInContent = (content, key) => { - const regex = new RegExp(`\\b${key}\\b`, 'g') - return regex.test(content) -} - -// 递归在文件夹中搜索键 -const searchKeysInFiles = async (dir, keys, usedKeys) => { - const list = await fs.readdir(dir) - await Promise.all(list.map(async (file) => { - const filePath = path.join(dir, file) - const stat = await fs.stat(filePath) - if (stat.isDirectory()) { - if (!CONFIG.ignoreDirectories.includes(file)) { - await searchKeysInFiles(filePath, keys, usedKeys) - } - } else if (CONFIG.fileExtensions.includes(path.extname(file))) { - const data = await fs.readFile(filePath, 'utf8') - keys.forEach(key => { - if (isKeyUsedInContent(data, key)) { - usedKeys.add(key) - } - }) - } - })) -} - -// 从扁平键路径恢复嵌套对象 -const restoreNestedStructure = (keys) => { - const result = {} - keys.forEach(key => { - const parts = key.split('.') - let current = result - parts.forEach((part, index) => { - if (!current[part]) { - current[part] = index === parts.length - 1 ? null : {} - } - current = current[part] - }) - }) - return result -} - -// 递归删除未使用的键 -const removeUnusedKeys = (target, unusedKeys) => { - for (const [key, value] of Object.entries(unusedKeys)) { - if (value === null) { - delete target[key] - } else if (typeof target[key] === 'object' && target[key] !== null) { - removeUnusedKeys(target[key], value) - if (Object.keys(target[key]).length === 0) { - delete target[key] - } - } - } -} - -// 处理 JSON 文件 -const processJSONFile = async (filePath, unusedKeys) => { - try { - const jsonObject = await loadJSON(filePath) - if (jsonObject) { - removeUnusedKeys(jsonObject, unusedKeys) - await fs.writeFile(filePath, JSON.stringify(jsonObject, null, 2), 'utf8') - console.log(`已处理文件 ${filePath}`) - } - } catch (error) { - console.error(`处理文件 ${filePath} 时出错:`, error) - } -} - -// 递归处理目录中的所有 JSON 文件 -const processJSONFilesInDirectory = async (dir, unusedKeys) => { - const list = await fs.readdir(dir) - await Promise.all(list.map(async (file) => { - const filePath = path.join(dir, file) - const stat = await fs.stat(filePath) - if (stat.isDirectory() && !CONFIG.ignoreDirectories.includes(file)) { - await processJSONFilesInDirectory(filePath, unusedKeys) - } else if (stat.isFile() && file.endsWith('.json')) { - await processJSONFile(filePath, unusedKeys) - } - })) -} - -// 将 keys 写入 JSON 文件 -const writeKeysToFile = async (filePath, keys) => { - try { - await fs.writeFile(filePath, JSON.stringify(keys, null, 2), 'utf8') - console.log(`已将 keys 写入文件 ${filePath}`) - } catch (error) { - console.error(`写入文件 ${filePath} 时出错:`, error) - } -} - -// 主函数 -const main = async () => { - const allKeys = await extractKeysFromDirectory(CONFIG.i18nDirectory) - // await writeKeysToFile(path.join(__dirname, 'allKeys.json'), allKeys) - const usedKeys = new Set() - await Promise.all(CONFIG.sourceDirectories.map(dir => searchKeysInFiles(dir, allKeys, usedKeys))) - - const unusedKeys = allKeys.filter(key => !usedKeys.has(key)) - // await writeKeysToFile(path.join(__dirname, 'unusedKeys.json'), unusedKeys) - console.log(unusedKeys) - - const nestedUnusedKeys = restoreNestedStructure(unusedKeys) - await processJSONFilesInDirectory(CONFIG.i18nDirectory, nestedUnusedKeys) -} - -main().catch(err => console.error('执行过程中出错:', err)) \ No newline at end of file diff --git a/scripts/i18n/package.json b/scripts/i18n/package.json deleted file mode 100644 index 977df4ebce19..000000000000 --- a/scripts/i18n/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "i18n", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "keywords": [], - "author": "", - "license": "ISC", - "devDependencies": { - "@phenomnomnominal/tsquery": "^6.1.3" - } -} diff --git a/scripts/i18n/query.js b/scripts/i18n/query.js deleted file mode 100644 index 19b61eea8dfa..000000000000 --- a/scripts/i18n/query.js +++ /dev/null @@ -1,94 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (g && (g = 0, op[0] && (_ = 0)), _) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var tsquery_1 = require("@phenomnomnominal/tsquery"); -var path = require("path"); -var fs = require("fs"); -// -var root = path.join(__dirname, '../../'); -// get all files in the project recursively -function getAllFiles(dirPath, arrayOfFiles) { - if (arrayOfFiles === void 0) { arrayOfFiles = []; } - var files = fs.readdirSync(dirPath); - files.forEach(function (file) { - var filePath = path.join(dirPath, file); - if (fs.statSync(filePath).isDirectory()) { - arrayOfFiles = getAllFiles(filePath, arrayOfFiles); - } - else { - arrayOfFiles.push(filePath); - } - }); - return arrayOfFiles; -} -var allFiles = getAllFiles(root).filter(function (file) { return file.endsWith('.ts') || file.endsWith('.tsx'); }) - .filter(function (file) { return !file.includes('node_modules'); }) - .filter(function (file) { return !file.includes('jieba'); }); -function processFiles(allFiles) { - return __awaiter(this, void 0, void 0, function () { - var fileContents, error_1; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - _a.trys.push([0, 2, , 3]); - return [4 /*yield*/, Promise.all(allFiles.map(function (file) { return fs.readFileSync(file, 'utf-8'); }))]; - case 1: - fileContents = _a.sent(); - // 处理每个文件的内容 - fileContents.forEach(function (content, index) { - var astTree = (0, tsquery_1.ast)(content); - var res = (0, tsquery_1.query)(astTree, 'JsxText,StringLiteral'); - for (var _i = 0, res_1 = res; _i < res_1.length; _i++) { - var node = res_1[_i]; - var text = node.getText().trim(); - if (text.length > 0 && text.match(/[\u4e00-\u9fa5]/g)) { - console.log(allFiles[index], text); - } - } - }); - return [3 /*break*/, 3]; - case 2: - error_1 = _a.sent(); - console.error('Error processing files:', error_1); - return [3 /*break*/, 3]; - case 3: return [2 /*return*/]; - } - }); - }); -} -processFiles(allFiles); diff --git a/scripts/i18n/query.ts b/scripts/i18n/query.ts deleted file mode 100644 index 3665d8772d68..000000000000 --- a/scripts/i18n/query.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { ast, query } from '@phenomnomnominal/tsquery'; -import * as path from 'path'; -import * as fs from 'fs'; -// -const root = path.join(__dirname, '../../'); -// get all files in the project recursively - -function getAllFiles(dirPath: string, arrayOfFiles: string[] = []): string[] { - const files = fs.readdirSync(dirPath); - - files.forEach((file) => { - const filePath = path.join(dirPath, file); - if (fs.statSync(filePath).isDirectory()) { - arrayOfFiles = getAllFiles(filePath, arrayOfFiles); - } else { - arrayOfFiles.push(filePath); - } - }); - - return arrayOfFiles; -} - -const allFiles = getAllFiles(root) - .filter((file) => file.endsWith('.ts') || file.endsWith('.tsx')) - .filter((file) => !file.includes('node_modules')) - .filter((file) => !file.includes('jieba')); - -async function processFiles(allFiles: string[]) { - try { - // 并行读取所有文件内容 - const fileContents = await Promise.all(allFiles.map((file) => fs.readFileSync(file, 'utf-8'))); - - // 处理每个文件的内容 - fileContents.forEach((content, index) => { - const astTree = ast(content); - const res = query(astTree, 'JsxText,StringLiteral'); - for (const node of res) { - const text = node.getText().trim(); - if (text.length > 0 && text.match(/[\u4e00-\u9fa5]/g)) { - console.log(allFiles[index], text); - } - } - }); - } catch (error) { - console.error('Error processing files:', error); - } -} - -processFiles(allFiles);