From 3b1ee769ebdbdb518f49fcff2ace7ac06717c4ce Mon Sep 17 00:00:00 2001 From: chanx <1243304602@qq.com> Date: Fri, 5 Sep 2025 09:57:15 +0800 Subject: [PATCH] fix: Optimize internationalization configuration #3221 (#9924) ### What problem does this PR solve? fix: Optimize internationalization configuration - Update multi-language options, adding general translations for functions like Select All and Clear - Add internationalization support for modules like Chat, Search, and Datasets ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue) --- .../components/cross-language-form-field.tsx | 7 ++++- web/src/components/delimiter-form-field.tsx | 1 + .../indented-tree/indented-tree.tsx | 6 ++-- web/src/components/knowledge-base-item.tsx | 4 ++- .../list-filter-bar/filter-popover.tsx | 5 +-- .../max-token-number-from-field.tsx | 1 + web/src/components/message-input/next.tsx | 3 +- .../raptor-form-fields.tsx | 4 ++- web/src/components/ui/form.tsx | 4 ++- web/src/components/ui/multi-select.tsx | 9 +++--- web/src/locales/en.ts | 29 ++++++++++++++++- web/src/locales/zh.ts | 31 +++++++++++++++++-- web/src/pages/agent/index.tsx | 2 +- web/src/pages/agents/index.tsx | 2 +- web/src/pages/agents/template-sidebar.tsx | 26 ++++++++++++---- .../components/chunk-creating-modal/index.tsx | 4 +-- .../components/chunk-result-bar/index.tsx | 5 ++- .../setting/configuration/common-item.tsx | 2 ++ web/src/pages/dataset/setting/utils.ts | 1 + .../pages/dataset/testing/testing-form.tsx | 2 +- web/src/pages/datasets/dataset-card.tsx | 6 +++- web/src/pages/datasets/index.tsx | 2 +- web/src/pages/files/index.tsx | 6 +++- web/src/pages/home/applications.tsx | 4 +-- web/src/pages/home/datasets.tsx | 2 +- .../chat/app-settings/chat-basic-settings.tsx | 13 ++++++-- .../chat/app-settings/chat-prompt-engine.tsx | 3 +- .../chat/chat-box/multiple-chat-box.tsx | 3 +- web/src/pages/next-chats/chat/index.tsx | 6 ++-- web/src/pages/next-chats/chat/sessions.tsx | 2 +- web/src/pages/next-chats/index.tsx | 2 +- web/src/pages/next-search/index.tsx | 2 +- web/src/pages/next-search/search-setting.tsx | 14 ++++++--- web/src/pages/next-search/search-view.tsx | 2 +- web/src/pages/next-searches/index.tsx | 2 +- web/tailwind.config.js | 9 ++++++ 36 files changed, 175 insertions(+), 51 deletions(-) diff --git a/web/src/components/cross-language-form-field.tsx b/web/src/components/cross-language-form-field.tsx index ec10736b45..9f7dc9a05f 100644 --- a/web/src/components/cross-language-form-field.tsx +++ b/web/src/components/cross-language-form-field.tsx @@ -6,6 +6,8 @@ import { } from '@/components/ui/form'; import { MultiSelect } from '@/components/ui/multi-select'; import { cn } from '@/lib/utils'; +import { t } from 'i18next'; +import { toLower } from 'lodash'; import { useFormContext } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; @@ -20,7 +22,10 @@ const Languages = [ 'Vietnamese', ]; -const options = Languages.map((x) => ({ label: x, value: x })); +const options = Languages.map((x) => ({ + label: t('language.' + toLower(x)), + value: x, +})); type CrossLanguageItemProps = { name?: string; diff --git a/web/src/components/delimiter-form-field.tsx b/web/src/components/delimiter-form-field.tsx index 7374945e30..2ca5d09a35 100644 --- a/web/src/components/delimiter-form-field.tsx +++ b/web/src/components/delimiter-form-field.tsx @@ -52,6 +52,7 @@ export function DelimiterFormField() {
diff --git a/web/src/components/indented-tree/indented-tree.tsx b/web/src/components/indented-tree/indented-tree.tsx index 91ee361b22..cb9583ccae 100644 --- a/web/src/components/indented-tree/indented-tree.tsx +++ b/web/src/components/indented-tree/indented-tree.tsx @@ -18,6 +18,7 @@ import { TreeData } from '@antv/g6/lib/types'; import isEmpty from 'lodash/isEmpty'; import React, { useCallback, useEffect, useRef } from 'react'; import { ErrorBoundary, FallbackProps } from 'react-error-boundary'; +import { useIsDarkTheme } from '../theme-provider'; const rootId = 'root'; @@ -322,7 +323,7 @@ const IndentedTree = ({ data, show, style = {} }: IProps) => { node.children.forEach((child, idx) => assignIds(child, node.id, idx)); } }, []); - + const isDark = useIsDarkTheme(); const render = useCallback( async (data: TreeData) => { const graph: Graph = new Graph({ @@ -335,7 +336,8 @@ const IndentedTree = ({ data, show, style = {} }: IProps) => { labelBackground: (datum) => datum.id === rootId, labelBackgroundRadius: 0, labelBackgroundFill: '#576286', - labelFill: (datum) => (datum.id === rootId ? '#fff' : '#666'), + labelFill: isDark ? '#fff' : '#333', + // labelFill: (datum) => (datum.id === rootId ? '#fff' : '#666'), labelText: (d) => d.style?.labelText || d.id, labelTextAlign: (datum) => datum.id === rootId ? 'center' : 'left', diff --git a/web/src/components/knowledge-base-item.tsx b/web/src/components/knowledge-base-item.tsx index b2ec7117ef..cb907df561 100644 --- a/web/src/components/knowledge-base-item.tsx +++ b/web/src/components/knowledge-base-item.tsx @@ -134,7 +134,9 @@ export function KnowledgeBaseFormField({ name="kb_ids" render={({ field }) => ( - {t('chat.knowledgeBases')} + + {t('chat.knowledgeBases')} + - Clear + {t('common.clear')}
diff --git a/web/src/components/max-token-number-from-field.tsx b/web/src/components/max-token-number-from-field.tsx index f1762c1a83..b01598d934 100644 --- a/web/src/components/max-token-number-from-field.tsx +++ b/web/src/components/max-token-number-from-field.tsx @@ -14,6 +14,7 @@ export function MaxTokenNumberFormField({ max = 2048, initialValue }: IProps) { { tooltip={t('useRaptorTip')} className="text-sm text-muted-foreground w-1/4 whitespace-break-spaces" > - {t('useRaptor')} +
+ {t('useRaptor')} +
diff --git a/web/src/components/ui/form.tsx b/web/src/components/ui/form.tsx index 8ce3a37cba..a350305420 100644 --- a/web/src/components/ui/form.tsx +++ b/web/src/components/ui/form.tsx @@ -94,8 +94,9 @@ const FormLabel = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { tooltip?: React.ReactNode; + required?: boolean; } ->(({ className, tooltip, ...props }, ref) => { +>(({ className, tooltip, required = false, ...props }, ref) => { const { error, formItemId } = useFormField(); return ( @@ -105,6 +106,7 @@ const FormLabel = React.forwardRef< htmlFor={formItemId} {...props} > + {required && *} {props.children} {tooltip && } diff --git a/web/src/components/ui/multi-select.tsx b/web/src/components/ui/multi-select.tsx index 252eb855cb..fbdff98f54 100644 --- a/web/src/components/ui/multi-select.tsx +++ b/web/src/components/ui/multi-select.tsx @@ -29,6 +29,7 @@ import { } from '@/components/ui/popover'; import { Separator } from '@/components/ui/separator'; import { cn } from '@/lib/utils'; +import { t } from 'i18next'; import { isEmpty } from 'lodash'; export type MultiSelectOptionType = { @@ -193,7 +194,7 @@ export const MultiSelect = React.forwardRef< onValueChange, variant, defaultValue = [], - placeholder = 'Select options', + placeholder = t('common.selectPlaceholder'), animation = 0, maxCount = 3, modalPopover = false, @@ -379,7 +380,7 @@ export const MultiSelect = React.forwardRef< > @@ -401,7 +402,7 @@ export const MultiSelect = React.forwardRef< >
- (Select All) + ({t('common.selectAll')}) )} {!options.some((x) => 'options' in x) && @@ -457,7 +458,7 @@ export const MultiSelect = React.forwardRef< onSelect={() => setIsPopoverOpen(false)} className="flex-1 justify-center cursor-pointer max-w-full" > - Close + {t('common.close')} diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 18ce603c05..2edf2404cb 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -3,6 +3,7 @@ export default { common: { noResults: 'No results.', selectPlaceholder: 'select value', + selectAll: 'Select All', delete: 'Delete', deleteModalTitle: 'Are you sure to delete this item?', ok: 'Yes', @@ -37,6 +38,7 @@ export default { pleaseSelect: 'Please select', pleaseInput: 'Please input', submit: 'Submit', + clear: 'Clear', embedIntoSite: 'Embed into webpage', previousPage: 'Previous', nextPage: 'Next', @@ -145,7 +147,8 @@ export default { vectorSimilarityWeightTip: 'This sets the weight of keyword similarity in the combined similarity score, either used with vector cosine similarity or with reranking score. The total of the two weights must equal 1.0.', keywordSimilarityWeight: 'Keyword similarity weight', - keywordSimilarityWeightTip: '', + keywordSimilarityWeightTip: + 'This sets the weight of keyword similarity in the combined similarity score, either used with vector cosine similarity or with reranking score. The total of the two weights must equal 1.0.', testText: 'Test text', testTextPlaceholder: 'Input your question here!', testingLabel: 'Testing', @@ -441,6 +444,12 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s delete: 'Delete', }, chat: { + messagePlaceholder: 'Type your message here...', + exit: 'Exit', + multipleModels: 'Multiple Models', + applyModelConfigs: 'Apply model configs', + conversations: 'Conversations', + chatApps: 'Chat Apps', newConversation: 'New conversation', createAssistant: 'Create an Assistant', assistantSetting: 'Assistant settings', @@ -839,6 +848,7 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s hint: 'hint', }, fileManager: { + files: 'Files', name: 'Name', uploadDate: 'Upload Date', knowledgeBase: 'Dataset', @@ -864,6 +874,12 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s pleaseUploadAtLeastOneFile: 'Please upload at least one file', }, flow: { + recommended: 'Recommended', + customerSupport: 'Customer Support', + marketing: 'Marketing', + consumerApp: 'Consumer App', + other: 'Other', + agents: 'Agents', days: 'Days', beginInput: 'Begin Input', ref: 'Variable', @@ -1527,6 +1543,7 @@ This delimiter is used to split the input text into several text pieces echo of editMCP: 'Edit MCP', }, search: { + searchApps: 'Search Apps', createSearch: 'Create Search', searchGreeting: 'How can I help you today ?', profile: 'Hide Profile', @@ -1551,5 +1568,15 @@ This delimiter is used to split the input text into several text pieces echo of okText: 'Save', cancelText: 'Cancel', }, + language: { + english: 'English', + chinese: 'Chinese', + spanish: 'Spanish', + french: 'French', + german: 'German', + japanese: 'Japanese', + korean: 'Korean', + vietnamese: 'Vietnamese', + }, }, }; diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index fec9c34283..973a9ac9a1 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -3,6 +3,7 @@ export default { common: { noResults: '无结果。', selectPlaceholder: '请选择', + selectAll: '全选', delete: '删除', deleteModalTitle: '确定删除吗?', ok: '是', @@ -36,6 +37,7 @@ export default { pleaseSelect: '请选择', pleaseInput: '请输入', submit: '提交', + clear: '清空', embedIntoSite: '嵌入网站', previousPage: '上一页', nextPage: '下一页', @@ -105,7 +107,7 @@ export default { testing: '检索测试', configuration: '配置', knowledgeGraph: '知识图谱', - files: '文件', + files: '个文件', name: '名称', namePlaceholder: '请输入名称', doc: '文档', @@ -136,7 +138,8 @@ export default { vectorSimilarityWeightTip: '我们使用混合相似性评分来评估两行文本之间的距离。它是加权关键字相似性和矢量余弦相似性或rerank得分(0〜1)。两个权重的总和为1.0。', keywordSimilarityWeight: '关键词相似度权重', - keywordSimilarityWeightTip: '', + keywordSimilarityWeightTip: + '我们使用混合相似性评分来评估两行文本之间的距离。它是加权关键字相似性和矢量余弦相似性或rerank得分(0〜1)。两个权重的总和为1.0。', testText: '测试文本', testTextPlaceholder: '请输入您的问题!', testingLabel: '测试', @@ -440,6 +443,12 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 delete: '删除', }, chat: { + messagePlaceholder: '请输入消息...', + exit: '退出', + multipleModels: '多模型', + applyModelConfigs: '应用模型配置', + conversations: '会话', + chatApps: '聊天', createChat: '创建聊天', newConversation: '新会话', createAssistant: '新建助理', @@ -798,6 +807,7 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 hint: '提示', }, fileManager: { + files: '文件', name: '名称', uploadDate: '上传日期', knowledgeBase: '知识库', @@ -822,6 +832,12 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 pleaseUploadAtLeastOneFile: '请上传至少一个文件', }, flow: { + recommended: '推荐', + customerSupport: '客户支持', + marketing: '营销', + consumerApp: '消费者应用', + other: '其他', + agents: '智能体', beginInput: '开始输入', seconds: '秒', ref: '引用变量', @@ -1441,6 +1457,7 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 cancelText: '取消', }, search: { + searchApps: '搜索', createSearch: '创建查询', searchGreeting: '今天我能为你做些什么?', profile: '隐藏个人资料', @@ -1465,5 +1482,15 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 okText: '保存', cancelText: '返回', }, + language: { + english: '英语', + chinese: '中文', + spanish: '西班牙语', + french: '法语', + german: '德语', + japanese: '日语', + korean: '韩语', + vietnamese: '越南语', + }, }, }; diff --git a/web/src/pages/agent/index.tsx b/web/src/pages/agent/index.tsx index c2ef597b77..b356a93195 100644 --- a/web/src/pages/agent/index.tsx +++ b/web/src/pages/agent/index.tsx @@ -114,7 +114,7 @@ export default function Agent() { - Agent + {t('header.flow')} diff --git a/web/src/pages/agents/index.tsx b/web/src/pages/agents/index.tsx index 3779290ee0..d4d5c913ac 100644 --- a/web/src/pages/agents/index.tsx +++ b/web/src/pages/agents/index.tsx @@ -36,7 +36,7 @@ export default function Agents() {
& kFProps> = ({ render={({ field }) => ( -
+
{t('chunk.question')} - + ? diff --git a/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/components/chunk-result-bar/index.tsx b/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/components/chunk-result-bar/index.tsx index 6441fc1b14..2d392ead6d 100644 --- a/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/components/chunk-result-bar/index.tsx +++ b/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/components/chunk-result-bar/index.tsx @@ -95,7 +95,10 @@ export default ({
-
diff --git a/web/src/pages/dataset/setting/configuration/common-item.tsx b/web/src/pages/dataset/setting/configuration/common-item.tsx index 66287d754a..5706b671f8 100644 --- a/web/src/pages/dataset/setting/configuration/common-item.tsx +++ b/web/src/pages/dataset/setting/configuration/common-item.tsx @@ -28,6 +28,7 @@ export function ChunkMethodItem() {
@@ -68,6 +69,7 @@ export function EmbeddingModelItem() {
diff --git a/web/src/pages/dataset/setting/utils.ts b/web/src/pages/dataset/setting/utils.ts index ceb9cc97e6..4c5666467c 100644 --- a/web/src/pages/dataset/setting/utils.ts +++ b/web/src/pages/dataset/setting/utils.ts @@ -16,4 +16,5 @@ export const ImageMap = { table: getImageName('table', 2), one: getImageName('one', 2), knowledge_graph: getImageName('knowledge-graph', 2), + tag: getImageName('tag', 2), }; diff --git a/web/src/pages/dataset/testing/testing-form.tsx b/web/src/pages/dataset/testing/testing-form.tsx index 983fe6fea9..ba614ed678 100644 --- a/web/src/pages/dataset/testing/testing-form.tsx +++ b/web/src/pages/dataset/testing/testing-form.tsx @@ -83,7 +83,7 @@ export default function TestingForm({ diff --git a/web/src/pages/datasets/dataset-card.tsx b/web/src/pages/datasets/dataset-card.tsx index 897ce818d7..ff92c85e87 100644 --- a/web/src/pages/datasets/dataset-card.tsx +++ b/web/src/pages/datasets/dataset-card.tsx @@ -4,6 +4,7 @@ import { SharedBadge } from '@/components/shared-badge'; import { Card, CardContent } from '@/components/ui/card'; import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks'; import { IKnowledge } from '@/interfaces/database/knowledge'; +import { t } from 'i18next'; import { ChevronRight } from 'lucide-react'; import { DatasetDropdown } from './dataset-dropdown'; import { useRenameDataset } from './use-rename-dataset'; @@ -20,7 +21,10 @@ export function DatasetCard({ return ( - {breadcrumbItems.length > 0 ? : 'File'} + {breadcrumbItems.length > 0 ? ( + + ) : ( + t('fileManager.files') + )}
); diff --git a/web/src/pages/home/applications.tsx b/web/src/pages/home/applications.tsx index 9147b8a5f1..3c2e3ce596 100644 --- a/web/src/pages/home/applications.tsx +++ b/web/src/pages/home/applications.tsx @@ -26,8 +26,8 @@ export function Applications() { const options = useMemo( () => [ - { value: Routes.Chats, label: t('header.chat') }, - { value: Routes.Searches, label: t('header.search') }, + { value: Routes.Chats, label: t('chat.chatApps') }, + { value: Routes.Searches, label: t('search.searchApps') }, { value: Routes.Agents, label: t('header.flow') }, ], [t], diff --git a/web/src/pages/home/datasets.tsx b/web/src/pages/home/datasets.tsx index af4ee13131..f8e27e66c0 100644 --- a/web/src/pages/home/datasets.tsx +++ b/web/src/pages/home/datasets.tsx @@ -22,7 +22,7 @@ export function Datasets() {

- {t('header.knowledgeBase')} + {t('header.dataset')}

{loading ? ( diff --git a/web/src/pages/next-chats/chat/app-settings/chat-basic-settings.tsx b/web/src/pages/next-chats/chat/app-settings/chat-basic-settings.tsx index 01d2782e69..d945f78418 100644 --- a/web/src/pages/next-chats/chat/app-settings/chat-basic-settings.tsx +++ b/web/src/pages/next-chats/chat/app-settings/chat-basic-settings.tsx @@ -43,7 +43,7 @@ export default function ChatBasicSetting() { name="name" render={({ field }) => ( - {t('assistantName')} + {t('assistantName')} @@ -69,7 +69,9 @@ export default function ChatBasicSetting() { name={'prompt_config.empty_response'} render={({ field }) => ( - {t('emptyResponse')} + + {t('emptyResponse')} + @@ -82,7 +84,9 @@ export default function ChatBasicSetting() { name={'prompt_config.prologue'} render={({ field }) => ( - {t('setAnOpener')} + + {t('setAnOpener')} + @@ -93,14 +97,17 @@ export default function ChatBasicSetting() { diff --git a/web/src/pages/next-chats/chat/app-settings/chat-prompt-engine.tsx b/web/src/pages/next-chats/chat/app-settings/chat-prompt-engine.tsx index 9a7ed285c0..8360733357 100644 --- a/web/src/pages/next-chats/chat/app-settings/chat-prompt-engine.tsx +++ b/web/src/pages/next-chats/chat/app-settings/chat-prompt-engine.tsx @@ -37,11 +37,12 @@ export function ChatPromptEngine() { )} /> - + -

Apply model configs

+

{t('chat.applyModelConfigs')}

{!isLatestChat || chatBoxIds.length === 3 ? ( diff --git a/web/src/pages/next-chats/chat/index.tsx b/web/src/pages/next-chats/chat/index.tsx index 34be965ae9..f384a76269 100644 --- a/web/src/pages/next-chats/chat/index.tsx +++ b/web/src/pages/next-chats/chat/index.tsx @@ -63,10 +63,10 @@ export default function Chat() {
- Multiple Models ({chatBoxIds.length}/3) + {t('chat.multipleModels')} ({chatBoxIds.length}/3)
- Multiple Models + {t('chat.multipleModels')} diff --git a/web/src/pages/next-chats/chat/sessions.tsx b/web/src/pages/next-chats/chat/sessions.tsx index 7fde0ad2ac..98b707374e 100644 --- a/web/src/pages/next-chats/chat/sessions.tsx +++ b/web/src/pages/next-chats/chat/sessions.tsx @@ -71,7 +71,7 @@ export function Sessions({
- Conversations + {t('chat.conversations')} {conversationList.length} diff --git a/web/src/pages/next-chats/index.tsx b/web/src/pages/next-chats/index.tsx index 446a286778..5def23e213 100644 --- a/web/src/pages/next-chats/index.tsx +++ b/web/src/pages/next-chats/index.tsx @@ -38,7 +38,7 @@ export default function ChatList() {
- Search + {t('header.search')} diff --git a/web/src/pages/next-search/search-setting.tsx b/web/src/pages/next-search/search-setting.tsx index 183130683c..8a9e136cb6 100644 --- a/web/src/pages/next-search/search-setting.tsx +++ b/web/src/pages/next-search/search-setting.tsx @@ -397,7 +397,11 @@ const SearchSetting: React.FC = ({ name="search_config.similarity_threshold" render={({ field }) => ( - Similarity Threshold + + {t('knowledgeDetails.similarityThreshold')} +
= ({ name="search_config.vector_similarity_weight" render={({ field }) => ( - - *Vector - Similarity Weight + + * + {t('knowledgeDetails.vectorSimilarityWeight')}

- {t('relatedSearch')} + {t('search.relatedSearch')}

{relatedQuestions?.map((x, idx) => ( diff --git a/web/src/pages/next-searches/index.tsx b/web/src/pages/next-searches/index.tsx index 935fcee7ca..713ed7e64d 100644 --- a/web/src/pages/next-searches/index.tsx +++ b/web/src/pages/next-searches/index.tsx @@ -49,7 +49,7 @@ export default function SearchList() {
handleSearchChange(e.target.value)} > diff --git a/web/tailwind.config.js b/web/tailwind.config.js index 27de063aea..c04ca939d1 100644 --- a/web/tailwind.config.js +++ b/web/tailwind.config.js @@ -17,6 +17,15 @@ module.exports = { '2xl': '1400px', }, }, + screens: { + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px', + '2xl': '1400px', + '3xl': '1780px', + '4xl': '1980px', + }, extend: { colors: { border: 'var(--colors-outline-neutral-strong)',