Browse Source

Fix/language support (#2154)

crazywoola 1 year ago
parent
commit
e58c3ac374
28 changed files with 103 additions and 71 deletions
  1. 3 2
      web/app/(commonLayout)/datasets/Doc.tsx
  2. 4 5
      web/app/activate/activateForm.tsx
  3. 5 5
      web/app/components/app/annotation/batch-add-annotation-modal/csv-downloader.tsx
  4. 4 3
      web/app/components/app/annotation/header-opts/index.tsx
  5. 3 2
      web/app/components/app/configuration/config/agent/agent-tools/choose-tool/index.tsx
  6. 6 5
      web/app/components/app/configuration/config/agent/agent-tools/setting-built-in-tool.tsx
  7. 3 2
      web/app/components/app/configuration/toolbox/moderation/index.tsx
  8. 5 3
      web/app/components/app/configuration/toolbox/moderation/moderation-setting-modal.tsx
  9. 4 2
      web/app/components/app/configuration/tools/external-data-tool-modal.tsx
  10. 3 1
      web/app/components/app/overview/customize/index.tsx
  11. 3 1
      web/app/components/datasets/create/file-uploader/index.tsx
  12. 3 2
      web/app/components/datasets/create/step-two/index.tsx
  13. 7 5
      web/app/components/datasets/documents/detail/batch-modal/csv-downloader.tsx
  14. 4 2
      web/app/components/develop/doc.tsx
  15. 3 1
      web/app/components/develop/secret-key/secret-key-modal.tsx
  16. 4 2
      web/app/components/header/account-about/index.tsx
  17. 3 2
      web/app/components/header/account-dropdown/index.tsx
  18. 4 3
      web/app/components/header/account-setting/members-page/index.tsx
  19. 3 1
      web/app/components/tools/edit-custom-collection-modal/test-api.tsx
  20. 4 2
      web/app/components/tools/tool-list/header.tsx
  21. 4 2
      web/app/components/tools/tool-list/item.tsx
  22. 3 2
      web/app/components/tools/tool-nav-list/item.tsx
  23. 1 4
      web/app/components/tools/types.ts
  24. 6 4
      web/app/install/installForm.tsx
  25. 4 3
      web/app/signin/normalForm.tsx
  26. 4 4
      web/app/signin/oneMoreStep.tsx
  27. 1 1
      web/models/common.ts
  28. 2 0
      web/utils/language.ts

+ 3 - 2
web/app/(commonLayout)/datasets/Doc.tsx

@@ -5,6 +5,7 @@ import { useContext } from 'use-context-selector'
 import TemplateEn from './template/template.en.mdx'
 import TemplateZh from './template/template.zh.mdx'
 import I18n from '@/context/i18n'
+import { LanguagesSupportedUnderscore, getModelRuntimeSupported } from '@/utils/language'
 
 type DocProps = {
   apiBaseUrl: string
@@ -13,11 +14,11 @@ const Doc: FC<DocProps> = ({
   apiBaseUrl,
 }) => {
   const { locale } = useContext(I18n)
-
+  const language = getModelRuntimeSupported(locale)
   return (
     <article className='mx-1 px-4 sm:mx-12 pt-16 bg-white rounded-t-xl prose prose-xl'>
       {
-        locale === 'en'
+        language !== LanguagesSupportedUnderscore[1]
           ? <TemplateEn apiBaseUrl={apiBaseUrl} />
           : <TemplateZh apiBaseUrl={apiBaseUrl} />
       }

+ 4 - 5
web/app/activate/activateForm.tsx

@@ -12,12 +12,11 @@ import Button from '@/app/components/base/button'
 
 import { SimpleSelect } from '@/app/components/base/select'
 import { timezones } from '@/utils/timezone'
-import { LanguagesSupported, languages } from '@/utils/language'
+import { LanguagesSupportedUnderscore, getModelRuntimeSupported, languages } from '@/utils/language'
 import { activateMember, invitationCheck } from '@/service/common'
 import Toast from '@/app/components/base/toast'
 import Loading from '@/app/components/base/loading'
 import I18n from '@/context/i18n'
-
 const validPassword = /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/
 
 const ActivateForm = () => {
@@ -43,9 +42,9 @@ const ActivateForm = () => {
   const [name, setName] = useState('')
   const [password, setPassword] = useState('')
   const [timezone, setTimezone] = useState('Asia/Shanghai')
-  const [language, setLanguage] = useState('en-US')
+  const [language, setLanguage] = useState(getModelRuntimeSupported(locale))
   const [showSuccess, setShowSuccess] = useState(false)
-  const defaultLanguage = useCallback(() => (window.navigator.language.startsWith('zh') ? LanguagesSupported[1] : LanguagesSupported[0]) || LanguagesSupported[0], [])
+  const defaultLanguage = useCallback(() => (window.navigator.language.startsWith('zh') ? LanguagesSupportedUnderscore[1] : LanguagesSupportedUnderscore[0]) || LanguagesSupportedUnderscore[0], [])
 
   const showErrorMessage = useCallback((message: string) => {
     Toast.notify({
@@ -208,7 +207,7 @@ const ActivateForm = () => {
                 <Link
                   className='text-primary-600'
                   target={'_blank'}
-                  href={`https://docs.dify.ai/${locale === 'en' ? '' : `v/${locale.toLowerCase()}`}/community/open-source`}
+                  href={`https://docs.dify.ai/${language !== LanguagesSupportedUnderscore[1] ? '' : `v/${locale.toLowerCase()}`}/community/open-source`}
                 >{t('login.license.link')}</Link>
               </div>
             </div>

+ 5 - 5
web/app/components/app/annotation/batch-add-annotation-modal/csv-downloader.tsx

@@ -8,6 +8,7 @@ import { useTranslation } from 'react-i18next'
 import { useContext } from 'use-context-selector'
 import { Download02 as DownloadIcon } from '@/app/components/base/icons/src/vender/solid/general'
 import I18n from '@/context/i18n'
+import { LanguagesSupportedUnderscore, getModelRuntimeSupported } from '@/utils/language'
 
 const CSV_TEMPLATE_QA_EN = [
   ['question', 'answer'],
@@ -22,14 +23,13 @@ const CSV_TEMPLATE_QA_CN = [
 
 const CSVDownload: FC = () => {
   const { t } = useTranslation()
+
   const { locale } = useContext(I18n)
+  const language = getModelRuntimeSupported(locale)
   const { CSVDownloader, Type } = useCSVDownloader()
 
   const getTemplate = () => {
-    if (locale === 'en')
-      return CSV_TEMPLATE_QA_EN
-
-    return CSV_TEMPLATE_QA_CN
+    return language !== LanguagesSupportedUnderscore[1] ? CSV_TEMPLATE_QA_EN : CSV_TEMPLATE_QA_CN
   }
 
   return (
@@ -58,7 +58,7 @@ const CSVDownload: FC = () => {
       <CSVDownloader
         className="block mt-2 cursor-pointer"
         type={Type.Link}
-        filename={'template'}
+        filename={`template-${language}`}
         bom={true}
         data={getTemplate()}
       >

+ 4 - 3
web/app/components/app/annotation/header-opts/index.tsx

@@ -14,10 +14,10 @@ import type { AnnotationItemBasic } from '../type'
 import BatchAddModal from '../batch-add-annotation-modal'
 import s from './style.module.css'
 import CustomPopover from '@/app/components/base/popover'
-// import Divider from '@/app/components/base/divider'
 import { FileDownload02, FilePlus02 } from '@/app/components/base/icons/src/vender/line/files'
 import I18n from '@/context/i18n'
 import { fetchExportAnnotationList } from '@/service/annotation'
+import { LanguagesSupportedUnderscore, getModelRuntimeSupported } from '@/utils/language'
 const CSV_HEADER_QA_EN = ['Question', 'Answer']
 const CSV_HEADER_QA_CN = ['问题', '答案']
 
@@ -38,6 +38,7 @@ const HeaderOptions: FC<Props> = ({
 }) => {
   const { t } = useTranslation()
   const { locale } = useContext(I18n)
+  const language = getModelRuntimeSupported(locale)
   const { CSVDownloader, Type } = useCSVDownloader()
   const [list, setList] = useState<AnnotationItemBasic[]>([])
   const fetchList = async () => {
@@ -67,10 +68,10 @@ const HeaderOptions: FC<Props> = ({
 
         <CSVDownloader
           type={Type.Link}
-          filename="annotations"
+          filename={`annotations-${language}`}
           bom={true}
           data={[
-            locale === 'en' ? CSV_HEADER_QA_EN : CSV_HEADER_QA_CN,
+            language !== LanguagesSupportedUnderscore[1] ? CSV_HEADER_QA_EN : CSV_HEADER_QA_CN,
             ...list.map(item => [item.question, item.answer]),
           ]}
         >

+ 3 - 2
web/app/components/app/configuration/config/agent/agent-tools/choose-tool/index.tsx

@@ -10,6 +10,7 @@ import Drawer from '@/app/components/base/drawer-plus'
 import ConfigContext from '@/context/debug-configuration'
 import type { ModelConfig } from '@/models/debug'
 import I18n from '@/context/i18n'
+import { getModelRuntimeSupported } from '@/utils/language'
 type Props = {
   show: boolean
   onHide: () => void
@@ -23,7 +24,7 @@ const ChooseTool: FC<Props> = ({
 }) => {
   const { t } = useTranslation()
   const { locale } = useContext(I18n)
-
+  const language = getModelRuntimeSupported(locale)
   const {
     modelConfig,
     setModelConfig,
@@ -59,7 +60,7 @@ const ChooseTool: FC<Props> = ({
                 provider_type: collection.type,
                 provider_name: collection.name,
                 tool_name: tool.name,
-                tool_label: tool.label[locale === 'en' ? 'en_US' : 'zh_Hans'],
+                tool_label: tool.label[language],
                 tool_parameters: parameters,
                 enabled: true,
               })

+ 6 - 5
web/app/components/app/configuration/config/agent/agent-tools/setting-built-in-tool.tsx

@@ -13,7 +13,7 @@ import I18n from '@/context/i18n'
 import Button from '@/app/components/base/button'
 import Loading from '@/app/components/base/loading'
 import { DiagonalDividingLine } from '@/app/components/base/icons/src/public/common'
-
+import { getModelRuntimeSupported } from '@/utils/language'
 type Props = {
   collection: Collection
   toolName: string
@@ -32,6 +32,7 @@ const SettingBuiltInTool: FC<Props> = ({
   onSave,
 }) => {
   const { locale } = useContext(I18n)
+  const language = getModelRuntimeSupported(locale)
   const { t } = useTranslation()
 
   const [isLoading, setIsLoading] = useState(true)
@@ -83,7 +84,7 @@ const SettingBuiltInTool: FC<Props> = ({
         {t('tools.setBuiltInTools.toolDescription')}
       </div>
       <div className='mt-1 leading-[18px] text-xs font-normal text-gray-600'>
-        {currTool?.description[locale === 'en' ? 'en_US' : 'zh_Hans']}
+        {currTool?.description[language]}
       </div>
 
       {infoSchemas.length > 0 && (
@@ -96,7 +97,7 @@ const SettingBuiltInTool: FC<Props> = ({
             {infoSchemas.map((item: any, index) => (
               <div key={index}>
                 <div className='flex items-center space-x-2 leading-[18px]'>
-                  <div className='text-[13px] font-semibold text-gray-900'>{item.label[locale === 'en' ? 'en_US' : 'zh_Hans']}</div>
+                  <div className='text-[13px] font-semibold text-gray-900'>{item.label[language]}</div>
                   <div className='text-xs font-medium text-gray-500'>{item.type === 'number-input' ? t('tools.setBuiltInTools.number') : t('tools.setBuiltInTools.string')}</div>
                   {item.required && (
                     <div className='text-xs font-medium text-[#EC4A0A]'>{t('tools.setBuiltInTools.required')}</div>
@@ -104,7 +105,7 @@ const SettingBuiltInTool: FC<Props> = ({
                 </div>
                 {item.human_description && (
                   <div className='mt-1 leading-[18px] text-xs font-normal text-gray-600'>
-                    {item.human_description?.[locale === 'en' ? 'en_US' : 'zh_Hans']}
+                    {item.human_description?.[language]}
                   </div>
                 )}
               </div>
@@ -140,7 +141,7 @@ const SettingBuiltInTool: FC<Props> = ({
               backgroundImage: `url(${collection.icon})`,
             }}
           ></div>
-          <div className='ml-2 leading-6 text-base font-semibold text-gray-900'>{currTool?.label[locale === 'en' ? 'en_US' : 'zh_Hans']}</div>
+          <div className='ml-2 leading-6 text-base font-semibold text-gray-900'>{currTool?.label[language]}</div>
           {(hasSetting && !readonly) && (<>
             <DiagonalDividingLine className='mx-4' />
             <div className='flex space-x-6'>

+ 3 - 2
web/app/components/app/configuration/toolbox/moderation/index.tsx

@@ -7,11 +7,12 @@ import { useModalContext } from '@/context/modal-context'
 import ConfigContext from '@/context/debug-configuration'
 import { fetchCodeBasedExtensionList } from '@/service/common'
 import I18n from '@/context/i18n'
-
+import { getModelRuntimeSupported } from '@/utils/language'
 const Moderation = () => {
   const { t } = useTranslation()
   const { setShowModerationSettingModal } = useModalContext()
   const { locale } = useContext(I18n)
+  const language = getModelRuntimeSupported(locale)
   const {
     moderationConfig,
     setModerationConfig,
@@ -38,7 +39,7 @@ const Moderation = () => {
     else if (moderationConfig.type === 'api')
       prefix = t('common.apiBasedExtension.selector.title')
     else
-      prefix = codeBasedExtensionList?.data.find(item => item.name === moderationConfig.type)?.label[locale === 'en' ? 'en-US' : 'zh-Hans'] || ''
+      prefix = codeBasedExtensionList?.data.find(item => item.name === moderationConfig.type)?.label[language] || ''
 
     if (moderationConfig.config?.inputs_config?.enabled && moderationConfig.config?.outputs_config?.enabled)
       suffix = t('appDebug.feature.moderation.allEnabled')

+ 5 - 3
web/app/components/app/configuration/toolbox/moderation/moderation-setting-modal.tsx

@@ -17,6 +17,7 @@ import {
 } from '@/service/common'
 import type { CodeBasedExtensionItem } from '@/models/common'
 import I18n from '@/context/i18n'
+import { LanguagesSupportedUnderscore, getModelRuntimeSupported } from '@/utils/language'
 import { InfoCircle } from '@/app/components/base/icons/src/vender/line/general'
 import { useModalContext } from '@/context/modal-context'
 import { CustomConfigurationStatusEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
@@ -43,6 +44,7 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
   const { t } = useTranslation()
   const { notify } = useToastContext()
   const { locale } = useContext(I18n)
+  const language = getModelRuntimeSupported(locale)
   const { data: modelProviders, isLoading, mutate } = useSWR('/workspaces/current/model-providers', fetchModelProviders)
   const [localeData, setLocaleData] = useState<ModerationConfig>(data)
   const { setShowAccountSettingModal } = useModalContext()
@@ -198,12 +200,12 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
     }
 
     if (localeData.type === 'keywords' && !localeData.config.keywords) {
-      notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: locale === 'en' ? 'keywords' : '关键词' }) })
+      notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: language !== LanguagesSupportedUnderscore[1] ? 'keywords' : '关键词' }) })
       return
     }
 
     if (localeData.type === 'api' && !localeData.config.api_based_extension_id) {
-      notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: locale === 'en' ? 'API Extension' : 'API 扩展' }) })
+      notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: language !== LanguagesSupportedUnderscore[1] ? 'API Extension' : 'API 扩展' }) })
       return
     }
 
@@ -212,7 +214,7 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
         if (!localeData.config?.[currentProvider.form_schema[i].variable] && currentProvider.form_schema[i].required) {
           notify({
             type: 'error',
-            message: t('appDebug.errorMessage.valueOfVarRequired', { key: locale === 'en' ? currentProvider.form_schema[i].label['en-US'] : currentProvider.form_schema[i].label['zh-Hans'] }),
+            message: t('appDebug.errorMessage.valueOfVarRequired', { key: language !== LanguagesSupportedUnderscore[1] ? currentProvider.form_schema[i].label['en-US'] : currentProvider.form_schema[i].label['zh-Hans'] }),
           })
           return
         }

+ 4 - 2
web/app/components/app/configuration/tools/external-data-tool-modal.tsx

@@ -12,6 +12,7 @@ import { BookOpen01 } from '@/app/components/base/icons/src/vender/line/educatio
 import { fetchCodeBasedExtensionList } from '@/service/common'
 import { SimpleSelect } from '@/app/components/base/select'
 import I18n from '@/context/i18n'
+import { LanguagesSupportedUnderscore, getModelRuntimeSupported } from '@/utils/language'
 import type {
   CodeBasedExtensionItem,
   ExternalDataTool,
@@ -40,6 +41,7 @@ const ExternalDataToolModal: FC<ExternalDataToolModalProps> = ({
   const { t } = useTranslation()
   const { notify } = useToastContext()
   const { locale } = useContext(I18n)
+  const language = getModelRuntimeSupported(locale)
   const [localeData, setLocaleData] = useState(data.type ? data : { ...data, type: 'api' })
   const [showEmojiPicker, setShowEmojiPicker] = useState(false)
   const { data: codeBasedExtensionList } = useSWR(
@@ -155,7 +157,7 @@ const ExternalDataToolModal: FC<ExternalDataToolModalProps> = ({
     }
 
     if (localeData.type === 'api' && !localeData.config?.api_based_extension_id) {
-      notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: locale === 'en' ? 'API Extension' : 'API 扩展' }) })
+      notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: language !== LanguagesSupportedUnderscore[1] ? 'API Extension' : 'API 扩展' }) })
       return
     }
 
@@ -164,7 +166,7 @@ const ExternalDataToolModal: FC<ExternalDataToolModalProps> = ({
         if (!localeData.config?.[currentProvider.form_schema[i].variable] && currentProvider.form_schema[i].required) {
           notify({
             type: 'error',
-            message: t('appDebug.errorMessage.valueOfVarRequired', { key: locale === 'en' ? currentProvider.form_schema[i].label['en-US'] : currentProvider.form_schema[i].label['zh-Hans'] }),
+            message: t('appDebug.errorMessage.valueOfVarRequired', { key: language !== LanguagesSupportedUnderscore[1] ? currentProvider.form_schema[i].label['en-US'] : currentProvider.form_schema[i].label['zh-Hans'] }),
           })
           return
         }

+ 3 - 1
web/app/components/app/overview/customize/index.tsx

@@ -9,6 +9,7 @@ import I18n from '@/context/i18n'
 import Button from '@/app/components/base/button'
 import Modal from '@/app/components/base/modal'
 import Tag from '@/app/components/base/tag'
+import { LanguagesSupportedUnderscore, getModelRuntimeSupported } from '@/utils/language'
 
 type IShareLinkProps = {
   isShow: boolean
@@ -43,6 +44,7 @@ const CustomizeModal: FC<IShareLinkProps> = ({
 }) => {
   const { t } = useTranslation()
   const { locale } = useContext(I18n)
+  const language = getModelRuntimeSupported(locale)
   const isChatApp = mode === 'chat'
 
   return <Modal
@@ -98,7 +100,7 @@ const CustomizeModal: FC<IShareLinkProps> = ({
       <p className='mt-2 text-base font-medium text-gray-800'>{t(`${prefixCustomize}.way2.name`)}</p>
       <Button
         className='w-36 mt-2'
-        onClick={() => window.open(`https://docs.dify.ai/${locale === 'en' ? '' : `v/${locale.toLowerCase()}`}/application/developing-with-apis`, '_blank')}
+        onClick={() => window.open(`https://docs.dify.ai/${language !== LanguagesSupportedUnderscore[1] ? '' : `v/${locale.toLowerCase()}`}/application/developing-with-apis`, '_blank')}
       >
         <span className='text-sm text-gray-800'>{t(`${prefixCustomize}.way2.operation`)}</span>
         <ArrowTopRightOnSquareIcon className='w-4 h-4 ml-1 text-gray-800 shrink-0' />

+ 3 - 1
web/app/components/datasets/create/file-uploader/index.tsx

@@ -12,6 +12,7 @@ import { upload } from '@/service/base'
 import { fetchFileUploadConfig } from '@/service/common'
 import { fetchSupportFileTypes } from '@/service/datasets'
 import I18n from '@/context/i18n'
+import { LanguagesSupportedUnderscore, getModelRuntimeSupported } from '@/utils/language'
 
 type IFileUploaderProps = {
   fileList: FileItem[]
@@ -33,6 +34,7 @@ const FileUploader = ({
   const { t } = useTranslation()
   const { notify } = useContext(ToastContext)
   const { locale } = useContext(I18n)
+  const language = getModelRuntimeSupported(locale)
   const [dragging, setDragging] = useState(false)
   const dropRef = useRef<HTMLDivElement>(null)
   const dragRef = useRef<HTMLDivElement>(null)
@@ -71,7 +73,7 @@ const FileUploader = ({
       return item
     })
 
-    return res.map(item => item.toUpperCase()).join(locale === 'en' ? ', ' : '、 ')
+    return res.map(item => item.toUpperCase()).join(language !== LanguagesSupportedUnderscore[1] ? ', ' : '、 ')
   })()
   const ACCEPTS = supportTypes.map((ext: string) => `.${ext}`)
   const fileUploadConfig = useMemo(() => fileUploadConfigResponse ?? {

+ 3 - 2
web/app/components/datasets/create/step-two/index.tsx

@@ -41,6 +41,7 @@ import { RETRIEVE_METHOD } from '@/types/app'
 import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
 import Tooltip from '@/app/components/base/tooltip'
 import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
+import { LanguagesSupportedUnderscore, getModelRuntimeSupported } from '@/utils/language'
 
 type ValueOf<T> = T[keyof T]
 type StepTwoProps = {
@@ -87,7 +88,7 @@ const StepTwo = ({
 }: StepTwoProps) => {
   const { t } = useTranslation()
   const { locale } = useContext(I18n)
-
+  const language = getModelRuntimeSupported(locale)
   const media = useBreakpoints()
   const isMobile = media === MediaType.mobile
 
@@ -111,7 +112,7 @@ const StepTwo = ({
   const [docForm, setDocForm] = useState<DocForm | string>(
     (datasetId && documentDetail) ? documentDetail.doc_form : DocForm.TEXT,
   )
-  const [docLanguage, setDocLanguage] = useState<string>(locale === 'en' ? 'English' : 'Chinese')
+  const [docLanguage, setDocLanguage] = useState<string>(language !== LanguagesSupportedUnderscore[1] ? 'English' : 'Chinese')
   const [QATipHide, setQATipHide] = useState(false)
   const [previewSwitched, setPreviewSwitched] = useState(false)
   const [showPreview, { setTrue: setShowPreview, setFalse: hidePreview }] = useBoolean()

+ 7 - 5
web/app/components/datasets/documents/detail/batch-modal/csv-downloader.tsx

@@ -9,6 +9,7 @@ import { useContext } from 'use-context-selector'
 import { Download02 as DownloadIcon } from '@/app/components/base/icons/src/vender/solid/general'
 import { DocForm } from '@/models/datasets'
 import I18n from '@/context/i18n'
+import { LanguagesSupportedUnderscore, getModelRuntimeSupported } from '@/utils/language'
 
 const CSV_TEMPLATE_QA_EN = [
   ['question', 'answer'],
@@ -34,17 +35,18 @@ const CSV_TEMPLATE_CN = [
 const CSVDownload: FC<{ docForm: DocForm }> = ({ docForm }) => {
   const { t } = useTranslation()
   const { locale } = useContext(I18n)
+  const language = getModelRuntimeSupported(locale)
   const { CSVDownloader, Type } = useCSVDownloader()
 
   const getTemplate = () => {
-    if (locale === 'en') {
+    if (language === LanguagesSupportedUnderscore[1]) {
       if (docForm === DocForm.QA)
-        return CSV_TEMPLATE_QA_EN
-      return CSV_TEMPLATE_EN
+        return CSV_TEMPLATE_QA_CN
+      return CSV_TEMPLATE_CN
     }
     if (docForm === DocForm.QA)
-      return CSV_TEMPLATE_QA_CN
-    return CSV_TEMPLATE_CN
+      return CSV_TEMPLATE_QA_EN
+    return CSV_TEMPLATE_EN
   }
 
   return (

+ 4 - 2
web/app/components/develop/doc.tsx

@@ -5,6 +5,7 @@ import TemplateZh from './template/template.zh.mdx'
 import TemplateChatEn from './template/template_chat.en.mdx'
 import TemplateChatZh from './template/template_chat.zh.mdx'
 import I18n from '@/context/i18n'
+import { LanguagesSupportedUnderscore, getModelRuntimeSupported } from '@/utils/language'
 
 type IDocProps = {
   appDetail: any
@@ -12,6 +13,7 @@ type IDocProps = {
 
 const Doc = ({ appDetail }: IDocProps) => {
   const { locale } = useContext(I18n)
+  const language = getModelRuntimeSupported(locale)
   const variables = appDetail?.model_config?.configs?.prompt_variables || []
   const inputs = variables.reduce((res: any, variable: any) => {
     res[variable.key] = variable.name || ''
@@ -22,10 +24,10 @@ const Doc = ({ appDetail }: IDocProps) => {
     <article className="prose prose-xl" >
       {appDetail?.mode === 'completion'
         ? (
-          locale === 'en' ? <TemplateEn appDetail={appDetail} variables={variables} inputs={inputs} /> : <TemplateZh appDetail={appDetail} variables={variables} inputs={inputs} />
+          language !== LanguagesSupportedUnderscore[1] ? <TemplateEn appDetail={appDetail} variables={variables} inputs={inputs} /> : <TemplateZh appDetail={appDetail} variables={variables} inputs={inputs} />
         )
         : (
-          locale === 'en' ? <TemplateChatEn appDetail={appDetail} variables={variables} inputs={inputs} /> : <TemplateChatZh appDetail={appDetail} variables={variables} inputs={inputs} />
+          language !== LanguagesSupportedUnderscore[1] ? <TemplateChatEn appDetail={appDetail} variables={variables} inputs={inputs} /> : <TemplateChatZh appDetail={appDetail} variables={variables} inputs={inputs} />
         )}
     </article>
   )

+ 3 - 1
web/app/components/develop/secret-key/secret-key-modal.tsx

@@ -27,6 +27,7 @@ import Tooltip from '@/app/components/base/tooltip'
 import Loading from '@/app/components/base/loading'
 import Confirm from '@/app/components/base/confirm'
 import I18n from '@/context/i18n'
+import { LanguagesSupported, getModelRuntimeSupported } from '@/utils/language'
 import { useAppContext } from '@/context/app-context'
 
 type ISecretKeyModalProps = {
@@ -55,6 +56,7 @@ const SecretKeyModal = ({
   const [delKeyID, setDelKeyId] = useState('')
 
   const { locale } = useContext(I18n)
+  const language = getModelRuntimeSupported(locale)
 
   // const [isCopied, setIsCopied] = useState(false)
   const [copyValue, setCopyValue] = useState('')
@@ -100,7 +102,7 @@ const SecretKeyModal = ({
   }
 
   const formatDate = (timestamp: string) => {
-    if (locale === 'en')
+    if (language === LanguagesSupported[0])
       return new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'long', day: 'numeric' }).format((+timestamp) * 1000)
     else
       return new Intl.DateTimeFormat('fr-CA', { year: 'numeric', month: '2-digit', day: '2-digit' }).format((+timestamp) * 1000)

+ 4 - 2
web/app/components/header/account-about/index.tsx

@@ -9,6 +9,7 @@ import { XClose } from '@/app/components/base/icons/src/vender/line/general'
 import type { LangGeniusVersionResponse } from '@/models/common'
 import { IS_CE_EDITION } from '@/config'
 import I18n from '@/context/i18n'
+import { LanguagesSupportedUnderscore, getModelRuntimeSupported } from '@/utils/language'
 import LogoSite from '@/app/components/base/logo/logo-site'
 
 type IAccountSettingProps = {
@@ -25,6 +26,7 @@ export default function AccountAbout({
 }: IAccountSettingProps) {
   const { t } = useTranslation()
   const { locale } = useContext(I18n)
+  const language = getModelRuntimeSupported(locale)
   const isLatest = langeniusVersionInfo.current_version === langeniusVersionInfo.latest_version
 
   return (
@@ -47,8 +49,8 @@ export default function AccountAbout({
                 IS_CE_EDITION
                   ? <Link href={'https://github.com/langgenius/dify/blob/main/LICENSE'} target='_blank'>Open Source License</Link>
                   : <>
-                    <Link href={locale === 'en' ? 'https://docs.dify.ai/user-agreement/privacy-policy' : 'https://docs.dify.ai/v/zh-hans/user-agreement/privacy-policy'} target='_blank'>Privacy Policy</Link>,
-                    <Link href={locale === 'en' ? 'https://docs.dify.ai/user-agreement/terms-of-service' : 'https://docs.dify.ai/v/zh-hans/user-agreement/terms-of-service'} target='_blank'>Terms of Service</Link>
+                    <Link href={language !== LanguagesSupportedUnderscore[1] ? 'https://docs.dify.ai/user-agreement/privacy-policy' : 'https://docs.dify.ai/v/zh-hans/user-agreement/privacy-policy'} target='_blank'>Privacy Policy</Link>,
+                    <Link href={language !== LanguagesSupportedUnderscore[1] ? 'https://docs.dify.ai/user-agreement/terms-of-service' : 'https://docs.dify.ai/v/zh-hans/user-agreement/terms-of-service'} target='_blank'>Terms of Service</Link>
                   </>
               }
             </div>

+ 3 - 2
web/app/components/header/account-dropdown/index.tsx

@@ -16,7 +16,7 @@ import { useAppContext } from '@/context/app-context'
 import { ArrowUpRight, ChevronDown } from '@/app/components/base/icons/src/vender/line/arrows'
 import { LogOut01 } from '@/app/components/base/icons/src/vender/line/general'
 import { useModalContext } from '@/context/modal-context'
-
+import { LanguagesSupportedUnderscore, getModelRuntimeSupported } from '@/utils/language'
 export type IAppSelecotr = {
   isMobile: boolean
 }
@@ -30,6 +30,7 @@ export default function AppSelector({ isMobile }: IAppSelecotr) {
   const [aboutVisible, setAboutVisible] = useState(false)
 
   const { locale } = useContext(I18n)
+  const language = getModelRuntimeSupported(locale)
   const { t } = useTranslation()
   const { userProfile, langeniusVersionInfo } = useAppContext()
   const { setShowAccountSettingModal } = useModalContext()
@@ -122,7 +123,7 @@ export default function AppSelector({ isMobile }: IAppSelecotr) {
                       <Link
                         className={classNames(itemClassName, 'group justify-between')}
                         href={
-                          locale === 'en' ? 'https://docs.dify.ai/' : `https://docs.dify.ai/v/${locale.toLowerCase()}/`
+                          language !== LanguagesSupportedUnderscore[1] ? 'https://docs.dify.ai/' : `https://docs.dify.ai/v/${locale.toLowerCase()}/`
                         }
                         target='_blank'>
                         <div>{t('common.userProfile.helpCenter')}</div>

+ 4 - 3
web/app/components/header/account-setting/members-page/index.tsx

@@ -20,7 +20,7 @@ import { useProviderContext } from '@/context/provider-context'
 import { Plan } from '@/app/components/billing/type'
 import UpgradeBtn from '@/app/components/billing/upgrade-btn'
 import { NUM_INFINITE } from '@/app/components/billing/config'
-
+import { LanguagesSupportedUnderscore, getModelRuntimeSupported } from '@/utils/language'
 dayjs.extend(relativeTime)
 
 const MembersPage = () => {
@@ -31,6 +31,7 @@ const MembersPage = () => {
     normal: t('common.members.normal'),
   }
   const { locale } = useContext(I18n)
+  const language = getModelRuntimeSupported(locale)
   const { userProfile, currentWorkspace, isCurrentWorkspaceManager } = useAppContext()
   const { data, mutate } = useSWR({ url: '/workspaces/current/members' }, fetchMembers)
   const [inviteModalVisible, setInviteModalVisible] = useState(false)
@@ -54,7 +55,7 @@ const MembersPage = () => {
                 {isNotUnlimitedMemberPlan
                   ? (
                     <div className='flex space-x-1'>
-                      <div>{t('billing.plansCommon.member')}{locale === 'en' && accounts.length > 1 && 's'}</div>
+                      <div>{t('billing.plansCommon.member')}{language !== LanguagesSupportedUnderscore[1] && accounts.length > 1 && 's'}</div>
                       <div className='text-gray-700'>{accounts.length}</div>
                       <div>/</div>
                       <div>{plan.total.teamMembers === NUM_INFINITE ? t('billing.plansCommon.unlimited') : plan.total.teamMembers}</div>
@@ -63,7 +64,7 @@ const MembersPage = () => {
                   : (
                     <div className='flex space-x-1'>
                       <div>{accounts.length}</div>
-                      <div>{t('billing.plansCommon.memberAfter')}{locale === 'en' && accounts.length > 1 && 's'}</div>
+                      <div>{t('billing.plansCommon.memberAfter')}{language !== LanguagesSupportedUnderscore[1] && accounts.length > 1 && 's'}</div>
                     </div>
                   )}
               </div>

+ 3 - 1
web/app/components/tools/edit-custom-collection-modal/test-api.tsx

@@ -10,6 +10,7 @@ import Button from '@/app/components/base/button'
 import Drawer from '@/app/components/base/drawer-plus'
 import I18n from '@/context/i18n'
 import { testAPIAvailable } from '@/service/tools'
+import { getModelRuntimeSupported } from '@/utils/language'
 
 type Props = {
   customCollection: CustomCollectionBackend
@@ -26,6 +27,7 @@ const TestApi: FC<Props> = ({
 }) => {
   const { t } = useTranslation()
   const { locale } = useContext(I18n)
+  const language = getModelRuntimeSupported(locale)
   const [credentialsModalShow, setCredentialsModalShow] = useState(false)
   const [tempCredential, setTempCredential] = React.useState<Credential>(customCollection.credentials)
   const [result, setResult] = useState<string>('')
@@ -78,7 +80,7 @@ const TestApi: FC<Props> = ({
                       {parameters.map((item, index) => (
                         <tr key={index} className='border-b last:border-0 border-gray-200'>
                           <td className="py-2 pl-3 pr-2.5">
-                            {item.label[locale === 'en' ? 'en_US' : 'zh_Hans']}
+                            {item.label[language]}
                           </td>
                           <td className="">
                             <input

+ 4 - 2
web/app/components/tools/tool-list/header.tsx

@@ -8,6 +8,7 @@ import type { Collection } from '../types'
 import { CollectionType, LOC } from '../types'
 import { Settings01 } from '../../base/icons/src/vender/line/general'
 import I18n from '@/context/i18n'
+import { getModelRuntimeSupported } from '@/utils/language'
 
 type Props = {
   icon: JSX.Element
@@ -25,6 +26,7 @@ const Header: FC<Props> = ({
   onShowEditCustomCollection,
 }) => {
   const { locale } = useContext(I18n)
+  const language = getModelRuntimeSupported(locale)
   const { t } = useTranslation()
   const isInToolsPage = loc === LOC.tools
   const isInDebugPage = !isInToolsPage
@@ -38,13 +40,13 @@ const Header: FC<Props> = ({
         {icon}
         <div className='ml-3 grow w-0'>
           <div className='flex items-center h-6 space-x-1'>
-            <div className={cn(isInDebugPage && 'truncate', 'text-base font-semibold text-gray-900')}>{collection.label[locale === 'en' ? 'en_US' : 'zh_Hans']}</div>
+            <div className={cn(isInDebugPage && 'truncate', 'text-base font-semibold text-gray-900')}>{collection.label[language]}</div>
             <div className='text-xs font-normal text-gray-500'>·</div>
             <div className='text-xs font-normal text-gray-500'>{t('tools.author')}&nbsp;{collection.author}</div>
           </div>
           {collection.description && (
             <div className={cn('leading-[18px] text-[13px] font-normal text-gray-500')}>
-              {collection.description[locale === 'en' ? 'en_US' : 'zh_Hans']}
+              {collection.description[language]}
             </div>
           )}
         </div>

+ 4 - 2
web/app/components/tools/tool-list/item.tsx

@@ -10,6 +10,7 @@ import { CollectionType } from '../types'
 import TooltipPlus from '../../base/tooltip-plus'
 import I18n from '@/context/i18n'
 import SettingBuiltInTool from '@/app/components/app/configuration/config/agent/agent-tools/setting-built-in-tool'
+import { getModelRuntimeSupported } from '@/utils/language'
 
 type Props = {
   collection: Collection
@@ -32,6 +33,7 @@ const Item: FC<Props> = ({
 }) => {
   const { t } = useTranslation()
   const { locale } = useContext(I18n)
+  const language = getModelRuntimeSupported(locale)
   const isBuiltIn = collection.type === CollectionType.builtIn
   const canShowDetail = !isBuiltIn || (isBuiltIn && isInToolsPage)
   const [showDetail, setShowDetail] = useState(false)
@@ -45,9 +47,9 @@ const Item: FC<Props> = ({
         <div className='flex items-start w-full'>
           {icon}
           <div className='ml-3 w-0 grow'>
-            <div className={cn('text-base font-semibold text-gray-900 truncate')}>{payload.label[locale === 'en' ? 'en_US' : 'zh_Hans']}</div>
+            <div className={cn('text-base font-semibold text-gray-900 truncate')}>{payload.label[language]}</div>
             <div className={cn('leading-[18px] text-[13px] font-normal text-gray-500')}>
-              {payload.description[locale === 'en' ? 'en_US' : 'zh_Hans']}
+              {payload.description[language]}
             </div>
           </div>
         </div>

+ 3 - 2
web/app/components/tools/tool-nav-list/item.tsx

@@ -6,6 +6,7 @@ import cn from 'classnames'
 import AppIcon from '../../base/app-icon'
 import type { Collection } from '@/app/components/tools/types'
 import I18n from '@/context/i18n'
+import { getModelRuntimeSupported } from '@/utils/language'
 
 type Props = {
   isCurrent: boolean
@@ -19,7 +20,7 @@ const Item: FC<Props> = ({
   onClick,
 }) => {
   const { locale } = useContext(I18n)
-
+  const language = getModelRuntimeSupported(locale)
   return (
     <div
       className={cn(isCurrent && 'bg-white shadow-xs rounded-lg', 'mt-1 flex h-9 items-center px-2 space-x-2 cursor-pointer')}
@@ -41,7 +42,7 @@ const Item: FC<Props> = ({
             background={payload.icon.background}
           />
         )}
-      <div className={cn(isCurrent && 'text-primary-600 font-semibold', 'leading-5 text-sm font-normal truncate')}>{payload.label[locale === 'en' ? 'en_US' : 'zh_Hans']}</div>
+      <div className={cn(isCurrent && 'text-primary-600 font-semibold', 'leading-5 text-sm font-normal truncate')}>{payload.label[language]}</div>
 
     </div>
   )

+ 1 - 4
web/app/components/tools/types.ts

@@ -55,10 +55,7 @@ export type ToolParameter = {
 export type Tool = {
   name: string
   label: TypeWithI18N
-  description: {
-    zh_Hans: string
-    en_US: string
-  }
+  description: any
   parameters: ToolParameter[]
 }
 

+ 6 - 4
web/app/install/installForm.tsx

@@ -3,11 +3,12 @@ import React, { useEffect } from 'react'
 import { useTranslation } from 'react-i18next'
 import Link from 'next/link'
 import { useRouter } from 'next/navigation'
-import { useContext } from 'use-context-selector'
+// import { useContext } from 'use-context-selector'
 import Toast from '../components/base/toast'
 import Loading from '../components/base/loading'
 import Button from '@/app/components/base/button'
-import I18n from '@/context/i18n'
+// import I18n from '@/context/i18n'
+
 import { fetchSetupStatus, setup } from '@/service/common'
 import type { SetupStatusResponse } from '@/models/common'
 
@@ -16,7 +17,8 @@ const validPassword = /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/
 
 const InstallForm = () => {
   const { t } = useTranslation()
-  const { locale } = useContext(I18n)
+  // const { locale } = useContext(I18n)
+  // const language = getModelRuntimeSupported(locale)
   const router = useRouter()
 
   const [email, setEmail] = React.useState('')
@@ -168,7 +170,7 @@ const InstallForm = () => {
               <Link
                 className='text-primary-600'
                 target={'_blank'}
-                href={`https://docs.dify.ai/${locale === 'en' ? '' : `v/${locale.toLowerCase()}/`}community/open-source`}
+                href={'https://docs.dify.ai/user-agreement/open-source'}
               >{t('login.license.link')}</Link>
             </div>
           </div>

+ 4 - 3
web/app/signin/normalForm.tsx

@@ -8,11 +8,11 @@ import Link from 'next/link'
 import { useContext } from 'use-context-selector'
 import Toast from '../components/base/toast'
 import style from './page.module.css'
-// import Tooltip from '@/app/components/base/tooltip/index'
 import { IS_CE_EDITION, apiPrefix } from '@/config'
 import Button from '@/app/components/base/button'
 import { login, oauth } from '@/service/common'
 import I18n from '@/context/i18n'
+import { LanguagesSupportedUnderscore, getModelRuntimeSupported } from '@/utils/language'
 
 const validEmailReg = /^[\w\.-]+@([\w-]+\.)+[\w-]{2,}$/
 
@@ -67,6 +67,7 @@ const NormalForm = () => {
   const { t } = useTranslation()
   const router = useRouter()
   const { locale } = useContext(I18n)
+  const language = getModelRuntimeSupported(locale)
 
   const [state, dispatch] = useReducer(reducer, {
     formValid: false,
@@ -282,13 +283,13 @@ const NormalForm = () => {
             <Link
               className='text-primary-600'
               target={'_blank'}
-              href={locale === 'en' ? 'https://docs.dify.ai/user-agreement/terms-of-service' : 'https://docs.dify.ai/v/zh-hans/user-agreement/terms-of-service'}
+              href={language !== LanguagesSupportedUnderscore[1] ? 'https://docs.dify.ai/user-agreement/terms-of-service' : 'https://docs.dify.ai/v/zh-hans/user-agreement/terms-of-service'}
             >{t('login.tos')}</Link>
             &nbsp;&&nbsp;
             <Link
               className='text-primary-600'
               target={'_blank'}
-              href={locale === 'en' ? 'https://docs.dify.ai/user-agreement/privacy-policy' : 'https://docs.dify.ai/v/zh-hans/user-agreement/privacy-policy'}
+              href={language !== LanguagesSupportedUnderscore[1] ? 'https://docs.dify.ai/user-agreement/privacy-policy' : 'https://docs.dify.ai/v/zh-hans/user-agreement/privacy-policy'}
             >{t('login.pp')}</Link>
           </div>
 

+ 4 - 4
web/app/signin/oneMoreStep.tsx

@@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next'
 import Link from 'next/link'
 import useSWR from 'swr'
 import { useRouter } from 'next/navigation'
-import { useContext } from 'use-context-selector'
+// import { useContext } from 'use-context-selector'
 import Button from '@/app/components/base/button'
 import Tooltip from '@/app/components/base/tooltip/index'
 
@@ -13,7 +13,7 @@ import { timezones } from '@/utils/timezone'
 import { LanguagesSupported, languages } from '@/utils/language'
 import { oneMoreStep } from '@/service/common'
 import Toast from '@/app/components/base/toast'
-import I18n from '@/context/i18n'
+// import I18n from '@/context/i18n'
 
 type IState = {
   formState: 'processing' | 'error' | 'success' | 'initial'
@@ -47,7 +47,7 @@ const reducer = (state: IState, action: any) => {
 const OneMoreStep = () => {
   const { t } = useTranslation()
   const router = useRouter()
-  const { locale } = useContext(I18n)
+  // const { locale } = useContext(I18n)
 
   const [state, dispatch] = useReducer(reducer, {
     formState: 'initial',
@@ -161,7 +161,7 @@ const OneMoreStep = () => {
             <Link
               className='text-primary-600'
               target={'_blank'}
-              href={`https://docs.dify.ai/${locale === 'en' ? '' : `v/${locale.toLowerCase()}`}/community/open-source`}
+              href={'https://docs.dify.ai/user-agreement/open-source'}
             >{t('login.license.link')}</Link>
           </div>
         </div>

+ 1 - 1
web/models/common.ts

@@ -219,7 +219,7 @@ export type CodeBasedExtensionForm = {
 
 export type CodeBasedExtensionItem = {
   name: string
-  label: I18nText
+  label: any
   form_schema: CodeBasedExtensionForm[]
 }
 export type CodeBasedExtension = {

+ 2 - 0
web/utils/language.ts

@@ -4,6 +4,8 @@ export type Item = {
 }
 
 export const LanguagesSupported = ['en-US', 'zh-Hans', 'pt-BR', 'es-ES', 'fr-FR', 'de-DE', 'ja-JP', 'ko-KR', 'ru-RU', 'it-IT']
+export const LanguagesSupportedUnderscore = ['en_US', 'zh_Hans', 'pt_BR', 'es_ES', 'fr_FR', 'de_DE', 'ja_JP', 'ko_KR', 'ru_RU', 'it_IT']
+
 export const languages = [
   {
     value: 'en-US',