* adapt not input type

* adapt not input type

* file i18n

* publish i18n

* translate

* i18n
This commit is contained in:
Archer
2024-05-11 00:21:01 +08:00
committed by GitHub
parent 8cf643d972
commit ee8cb0915e
28 changed files with 1515 additions and 1614 deletions

View File

@@ -21,6 +21,8 @@ usageMatchRegex:
- "[^\\w\\d]appT\\(['\"`]({key})['\"`]"
# 支持 datasetT("your.i18n.keys")
- "[^\\w\\d]datasetT\\(['\"`]({key})['\"`]"
- "[^\\w\\d]fileT\\(['\"`]({key})['\"`]"
- "[^\\w\\d]publishT\\(['\"`]({key})['\"`]"
# A RegEx to set a custom scope range. This scope will be used as a prefix when detecting keys
# and works like how the i18next framework identifies the namespace scope from the

View File

@@ -4,7 +4,7 @@ export enum BucketNameEnum {
}
export const bucketNameMap = {
[BucketNameEnum.dataset]: {
label: 'common.file.bucket.dataset'
label: 'file.bucket.dataset'
}
};

View File

@@ -13,36 +13,36 @@ export enum MongoImageTypeEnum {
}
export const mongoImageTypeMap = {
[MongoImageTypeEnum.systemAvatar]: {
label: 'common.file.type.appAvatar',
label: 'appAvatar',
unique: true
},
[MongoImageTypeEnum.appAvatar]: {
label: 'common.file.type.appAvatar',
label: 'appAvatar',
unique: true
},
[MongoImageTypeEnum.pluginAvatar]: {
label: 'common.file.type.pluginAvatar',
label: 'pluginAvatar',
unique: true
},
[MongoImageTypeEnum.datasetAvatar]: {
label: 'common.file.type.datasetAvatar',
label: 'datasetAvatar',
unique: true
},
[MongoImageTypeEnum.userAvatar]: {
label: 'common.file.type.userAvatar',
label: 'userAvatar',
unique: true
},
[MongoImageTypeEnum.teamAvatar]: {
label: 'common.file.type.teamAvatar',
label: 'teamAvatar',
unique: true
},
[MongoImageTypeEnum.chatImage]: {
label: 'common.file.type.chatImage',
label: 'chatImage',
unique: false
},
[MongoImageTypeEnum.collectionImage]: {
label: 'common.file.type.collectionImage',
label: 'collectionImage',
unique: false
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
{
"Click to view file": "Click to view the original file",
"Release the mouse to upload the file": "Release the mouse to upload the file",
"upload error description": "Only supports uploading multiple files or one folder at a time",
"Empty file tip": "The file content is empty, the file may not be readable or it may be a pure image file.",
"File Content": "File Content",
"File Name": "File Name",
"File Size": "File Size",
"File content can not be empty": "File content cannot be empty",
"Filename Can not Be Empty": "Filename cannot be empty",
"Read File Error": "File parsing failed",
"Select and drag file tip": "Click or drag files here to upload",
"Select failed": "File selection failed",
"Select file amount limit": "You can select up to {{max}} files",
"Select file amount limit 100": "You can select up to 100 files at a time",
"Some file count exceeds limit": "Exceeds {{maxCount}} files, automatically truncated",
"Some file size exceeds limit": "Some files exceed: {{maxSize}}, have been filtered",
"Support file type": "Supports {{fileType}} type files",
"Support max count": "Supports up to {{maxCount}} files.",
"Support max size": "Maximum size per file: {{maxSize}}.",
"Upload failed": "Upload failed"
}

View File

@@ -0,0 +1,22 @@
{
"Copy IFrame": "Embed webpage",
"Copy Link": "Copy",
"Create API Key": "Create new Key",
"Create Link": "Create link",
"Default Response": "Default Response",
"Delete Link": "Delete link",
"Edit API Key": "Edit Key information",
"Edit IFrame Link": "Update embed link",
"Edit Link": "Edit",
"Edit Share Window": "Update share window",
"Feishu name": "Lark",
"Link Name": "Name of the share link",
"QPM Tips": "How many times per minute can each IP ask at most",
"QPM is empty": "QPM cannot be empty",
"app key tips": "These keys have the current application identification, refer to the document for specific use ",
"key alias": "key alias, for display only ",
"key tips": "You can use the API Key to access certain interfaces (you can't access the app, you need to use the API key within the app to access the app)",
"token auth": "Token authentication",
"token auth Tips": "Identity verification server address, if this value is filled, a request will be sent to the specified server before each conversation to perform identity verification",
"token auth use cases": "View usage instructions for identity verification"
}

View File

@@ -149,26 +149,6 @@
"Update error": "更新失败",
"unKnow": "出现了点意外~"
},
"export": "",
"file": {
"Empty file tip": "文件内容为空,可能该文件无法读取或为纯图片文件内容。",
"File Content": "文件内容",
"File Name": "文件名",
"File Size": "文件大小",
"File content can not be empty": "文件内容不能为空",
"Filename Can not Be Empty": "文件名不能为空",
"Read File Error": "解析文件失败",
"Select and drag file tip": "点击或拖动文件到此处上传",
"Select failed": "选择文件异常",
"Select file amount limit": "最多选择 {{max}} 个文件",
"Select file amount limit 100": "每次最多选择100个文件",
"Some file count exceeds limit": "超出{{maxCount}}个文件,已自动截取",
"Some file size exceeds limit": "部分文件超出: {{maxSize}},已被过滤",
"Support file type": "支持 {{fileType}} 类型文件",
"Support max count": "最多支持 {{maxCount}} 个文件。",
"Support max size": "单个文件最大 {{maxSize}}。",
"Upload failed": "上传异常"
},
"folder": {
"Drag Tip": "点我可拖动",
"Move Success": "移动成功",
@@ -663,7 +643,6 @@
"Estimated Price Tips": "QA计费为\n输入: {{charsPointsPrice}}积分/1k Tokens",
"Estimated points": "预估消耗 {{points}} 积分",
"Fetch Error": "获取链接失败",
"Fetch Url": "网络链接",
"Fetch url placeholder": "最多10个链接每行一个。",
"Fetch url tip": "仅支持读取静态链接,请注意检查结果",
"File chunk amount": "分段: {{amount}}",
@@ -1208,73 +1187,6 @@
"overSize": "团队成员超出上限"
}
},
"file": {
"Click to download file template": "点击下载模板:{{name}}",
"Click to view file": "点击查看原始文件",
"Create File": "创建新文件",
"Create file": "创建文件",
"Drag and drop": "拖拽文件至此",
"Fetch Url": "链接读取",
"If the imported file is garbled, please convert CSV to UTF-8 encoding format": "如果导入文件乱码,请将 CSV 转成 UTF-8 编码格式",
"Parse": "{{name}} 解析中...",
"Release the mouse to upload the file": "松开鼠标上传文件",
"Select a maximum of 10 files": "最多选择10个文件",
"Uploading": "正在上传 {{name}},进度: {{percent}}%",
"max 10": "最多选择 10 个文件",
"select a document": "选择文件",
"support": "支持 {{fileExtension}} 文件",
"upload error description": "单次只支持上传多个文件或者一个文件夹"
},
"home": {
"AI Assistant": "AI 客服",
"AI Assistant Desc": "无论对内还是对外AI 将 24 小时为您的用户提供服务",
"Advanced Settings": "高级编排",
"Advanced Settings Desc": "基于 Flow 的流程编排模式,让你的 AI 轻松实现数据库查询、IO 操作、联网通信等扩展能力",
"Choice Debug": "调试便捷",
"Choice Debug Desc": "拥有搜索测试、引用修改、完整对话预览等多种调试途径",
"Choice Desc": "",
"Choice Extension": "无限扩展",
"Choice Extension Desc": "基于 HTTP 实现扩展,轻松实现定制功能",
"Choice Fast": "开箱即用",
"Choice Fast Desc": "{{title}} 提供开箱即用的可视化操作,点点点即可构建 AI 应用",
"Choice Models": "支持多种模型",
"Choice Models Desc": "支持 GPT、Claude、Spark、ChatGLM等多模型",
"Choice Open": "更开放",
"Choice Open Desc": "{{title}} 遵循 Apache License 2.0 开源协议",
"Choice QA": "独特的 QA 结构",
"Choice QA Desc": "采用 QA 对的结构构建索引,适应问答、阅读等多种场景",
"Choice Visual": "可视化工作流",
"Choice Visual Desc": "可视化模块操作,轻松实现复杂工作流,让你的 AI 不再单一",
"Commercial": "商务咨询",
"Community": "社区",
"Dateset": "自动数据预处理",
"Dateset Desc": "提供手动输入、直接分段、LLM 自动处理和 CSV 等多种数据导入途径",
"Docs": "文档",
"FastGPT Ability": "{{title}} 能力",
"FastGPT Desc": "{{title}} 是一个基于 LLM 大语言模型的知识库问答系统,提供开箱即用的数据处理、模型调用等能力。同时可以通过 Flow 可视化进行工作流编排,从而实现复杂的问答场景!",
"Features": "特点",
"Footer Developer": "开发者",
"Footer Docs": "文档",
"Footer FastGPT Cloud": "{{title}} 线上服务",
"Footer Feedback": "反馈",
"Footer Git": "源码",
"Footer Product": "产品",
"Footer Support": "支持",
"Login": "登录",
"Open": "",
"OpenAPI": "OpenAPI",
"OpenAPI Desc": "与 GPT API 一致的对外接口,助你轻松接入已有应用",
"Quickly build AI question and answer library": "快速搭建 AI 问答系统",
"Start Now": "立即开始",
"Visual AI orchestration": "可视化 AI 编排",
"Why FastGPT": "为什么选择 {{title}}",
"desc": "基于 LLM 大模型的 AI 知识库问答平台",
"navbar": {
"Use guidance": "使用引导",
"chatbot": "问答机器人"
},
"slogan": "让 AI 更懂你的知识"
},
"module": {
"Confirm Delete Module": "确认删除该自定义模块?",
"Confirm Sync Plugin": "确认同步插件最新信息?插件的连线和输入的内容将会被清空,请确认!",
@@ -1299,30 +1211,6 @@
"Store": "应用市场",
"Tools": "工具"
},
"openapi": {
"app key tips": "这些 key 已有当前应用标识,具体使用可参考文档",
"key alias": "key 的别名,仅用于展示",
"key tips": "你可以使用 API 秘钥访问一些特定的接口(无法访问应用访问应用需使用应用内的API Key)"
},
"outlink": {
"Copy IFrame": "嵌入网页",
"Copy Link": "复制",
"Create API Key": "创建新 Key",
"Create Link": "创建链接",
"Delete Link": "删除链接",
"Edit API Key": "编辑 Key 信息",
"Edit IFrame Link": "更新嵌入链接",
"Edit Link": "编辑",
"Edit Share Window": "更新分享窗口",
"Link Name": "分享链接的名字",
"Link is empty": "",
"QPM": "",
"QPM Tips": "每个 IP 每分钟最多提问多少次",
"QPM is empty": "QPM 不能为空",
"token auth": "身份验证",
"token auth Tips": "身份校验服务器地址,如填写该值,每次对话前都会向指定服务器发送一个请求,进行身份校验",
"token auth use cases": "查看身份验证使用说明"
},
"permission": {
"Private": "私有",
"Private Tip": "仅自己可用",

View File

@@ -0,0 +1,23 @@
{
"Click to view file": "点击查看原始文件",
"Release the mouse to upload the file": "松开鼠标上传文件",
"upload error description": "单次只支持上传多个文件或者一个文件夹",
"Empty file tip": "文件内容为空,可能该文件无法读取或为纯图片文件内容。",
"File Content": "文件内容",
"File Name": "文件名",
"File Size": "文件大小",
"File content can not be empty": "文件内容不能为空",
"Filename Can not Be Empty": "文件名不能为空",
"Read File Error": "解析文件失败",
"Select and drag file tip": "点击或拖动文件到此处上传",
"Select failed": "选择文件异常",
"Select file amount limit": "最多选择 {{max}} 个文件",
"Select file amount limit 100": "每次最多选择100个文件",
"Some file count exceeds limit": "超出{{maxCount}}个文件,已自动截取",
"Some file size exceeds limit": "部分文件超出: {{maxSize}},已被过滤",
"Support file type": "支持 {{fileType}} 类型文件",
"Support max count": "最多支持 {{maxCount}} 个文件。",
"Support max size": "单个文件最大 {{maxSize}}。",
"Upload failed": "上传异常"
}

View File

@@ -0,0 +1,20 @@
{
"Create API Key": "创建新 Key",
"Create Link": "创建链接",
"Default Response": "默认回复",
"Delete Link": "删除链接",
"Edit API Key": "编辑 Key 信息",
"Edit IFrame Link": "更新嵌入链接",
"Edit Link": "编辑",
"Edit Share Window": "更新分享窗口",
"Feishu name": "飞书",
"Link Name": "分享链接的名字",
"QPM Tips": "每个 IP 每分钟最多提问多少次",
"QPM is empty": "QPM 不能为空",
"app key tips": "这些 key 已有当前应用标识,具体使用可参考文档",
"key alias": "key 的别名,仅用于展示",
"key tips": "你可以使用 API 秘钥访问一些特定的接口(无法访问应用访问应用需使用应用内的API Key)",
"token auth": "身份验证",
"token auth Tips": "身份校验服务器地址,如填写该值,每次对话前都会向指定服务器发送一个请求,进行身份校验",
"token auth use cases": "查看身份验证使用说明"
}

View File

@@ -1,7 +1,7 @@
import React, { useMemo, useState } from 'react';
import { type ChatHistoryItemResType } from '@fastgpt/global/core/chat/type.d';
import { DispatchNodeResponseType } from '@fastgpt/global/core/workflow/runtime/type.d';
import { Flex, BoxProps, useDisclosure, useTheme, Box } from '@chakra-ui/react';
import { Flex, useDisclosure, useTheme, Box } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';

View File

@@ -1,5 +1,5 @@
import React, { useMemo } from 'react';
import { Box, BoxProps, Image } from '@chakra-ui/react';
import { Box, BoxProps } from '@chakra-ui/react';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { getErrText } from '@fastgpt/global/common/error/utils';
import MyTooltip from '@/components/MyTooltip';
@@ -8,6 +8,7 @@ import { getFileAndOpen } from '@/web/core/dataset/utils';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { getSourceNameIcon } from '@fastgpt/global/core/dataset/utils';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useI18n } from '@/web/context/I18n';
type Props = BoxProps & {
sourceName?: string;
@@ -17,6 +18,7 @@ type Props = BoxProps & {
const RawSourceBox = ({ sourceId, sourceName = '', canView = true, ...props }: Props) => {
const { t } = useTranslation();
const { fileT } = useI18n();
const { toast } = useToast();
const { setLoading } = useSystemStore();
@@ -25,10 +27,7 @@ const RawSourceBox = ({ sourceId, sourceName = '', canView = true, ...props }: P
const icon = useMemo(() => getSourceNameIcon({ sourceId, sourceName }), [sourceId, sourceName]);
return (
<MyTooltip
label={canPreview ? t('file.Click to view file') || '' : ''}
shouldWrapChildren={false}
>
<MyTooltip label={canPreview ? fileT('Click to view file') : ''} shouldWrapChildren={false}>
<Box
color={'myGray.900'}
fontWeight={'medium'}
@@ -44,7 +43,7 @@ const RawSourceBox = ({ sourceId, sourceName = '', canView = true, ...props }: P
await getFileAndOpen(sourceId as string);
} catch (error) {
toast({
title: t(getErrText(error, 'error.fileNotFound')),
title: getErrText(error, t('error.fileNotFound')),
status: 'error'
});
}

View File

@@ -43,6 +43,7 @@ import MyTooltip from '@/components/MyTooltip';
import { getDocPath } from '@/web/common/system/doc';
import MyMenu from '@fastgpt/web/components/common/MyMenu';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import { useI18n } from '@/web/context/I18n';
type EditProps = EditApiKeyProps & { _id?: string };
const defaultEditData: EditProps = {
@@ -295,6 +296,7 @@ function EditKeyModal({
onEdit: () => void;
}) {
const { t } = useTranslation();
const { publishT } = useI18n();
const isEdit = useMemo(() => !!defaultData._id, [defaultData]);
const { feConfigs } = useSystemStore();
@@ -324,13 +326,13 @@ function EditKeyModal({
<MyModal
isOpen={true}
iconSrc="/imgs/modal/key.svg"
title={isEdit ? t('outlink.Edit API Key') : t('outlink.Create API Key')}
title={isEdit ? publishT('Edit API Key') : publishT('Create API Key')}
>
<ModalBody>
<Flex alignItems={'center'}>
<Box flex={'0 0 90px'}>{t('Name')}:</Box>
<Input
placeholder={t('openapi.key alias') || 'key alias'}
placeholder={publishT('key alias') || 'key alias'}
maxLength={20}
{...register('name', {
required: t('common.Name is empty') || 'Name is empty'

View File

@@ -1,10 +1,11 @@
import React from 'react';
import { useTranslation } from 'next-i18next';
import ApiKeyTable from '@/components/support/apikey/Table';
import { useI18n } from '@/web/context/I18n';
const ApiKey = () => {
const { t } = useTranslation();
return <ApiKeyTable tips={t('openapi.key tips')}></ApiKeyTable>;
const { publishT } = useI18n();
return <ApiKeyTable tips={publishT('key tips')}></ApiKeyTable>;
};
export default ApiKey;

View File

@@ -190,7 +190,7 @@ export async function getServerSideProps(content: any) {
return {
props: {
currentTab: content?.query?.currentTab || TabEnum.info,
...(await serviceSideProps(content))
...(await serviceSideProps(content, ['publish']))
}
};
}

View File

@@ -2,12 +2,13 @@ import React, { useEffect, useState } from 'react';
import ApiKeyTable from '@/components/support/apikey/Table';
import { useTranslation } from 'next-i18next';
import { Box } from '@chakra-ui/react';
import { useI18n } from '@/web/context/I18n';
const API = ({ appId }: { appId: string }) => {
const { t } = useTranslation();
const { publishT } = useI18n();
return (
<Box pt={3}>
<ApiKeyTable tips={t('openapi.app key tips')} appId={appId} />
<ApiKeyTable tips={publishT('app key tips')} appId={appId} />
</Box>
);
};

View File

@@ -10,6 +10,7 @@ import { useForm } from 'react-hook-form';
import { useRequest } from '@/web/common/hooks/useRequest';
import dayjs from 'dayjs';
import { createShareChat, updateShareChat } from '@/web/support/outLink/api';
import { useI18n } from '@/web/context/I18n';
const FeiShuEditModal = ({
appId,
@@ -25,6 +26,7 @@ const FeiShuEditModal = ({
onEdit: () => void;
}) => {
const { t } = useTranslation();
const { publishT } = useI18n();
const {
register,
setValue,
@@ -58,13 +60,13 @@ const FeiShuEditModal = ({
<MyModal
isOpen={true}
iconSrc="/imgs/modal/shareFill.svg"
title={isEdit ? t('outlink.Edit Link') : t('outlink.Create Link')}
title={isEdit ? publishT('Edit Link') : publishT('Create Link')}
>
<ModalBody>
<Flex alignItems={'center'}>
<Box flex={'0 0 90px'}>{t('Name')}</Box>
<Input
placeholder={t('outlink.Feishu name') || 'Link Name'} // TODO: i18n
placeholder={publishT('Feishu name') || 'Link Name'} // TODO: i18n
maxLength={20}
{...register('name', {
required: t('common.Name is empty') || 'Name is empty'
@@ -74,7 +76,7 @@ const FeiShuEditModal = ({
<Flex alignItems={'center'} mt={4}>
<Flex flex={'0 0 90px'} alignItems={'center'}>
QPM
<MyTooltip label={t('outlink.QPM Tips' || '')}>
<MyTooltip label={publishT('QPM Tips' || '')}>
<QuestionOutlineIcon ml={1} />
</MyTooltip>
</Flex>
@@ -84,7 +86,7 @@ const FeiShuEditModal = ({
min: 0,
max: 1000,
valueAsNumber: true,
required: t('outlink.QPM is empty') || ''
required: publishT('QPM is empty') || ''
})}
/>
</Flex>
@@ -126,10 +128,10 @@ const FeiShuEditModal = ({
{/* TODO: i18n */}
</Flex>
<Input
placeholder={t('outlink.Default Response') || 'Link Name'}
placeholder={publishT('Default Response') || 'Link Name'}
maxLength={20}
{...register('defaultResponse', {
required: t('common.default Response is empty') || 'Name is empty'
required: true
})}
/>
</Flex>
@@ -139,10 +141,10 @@ const FeiShuEditModal = ({
{/* TODO: i18n */}
</Flex>
<Input
placeholder={t('outlink.Default Response') || 'Link Name'}
placeholder={publishT('Default Response') || 'Link Name'}
maxLength={20}
{...register('immediateResponse', {
required: t('common.default Response is empty') || 'Name is empty'
required: true
})}
/>
</Flex>
@@ -152,14 +154,14 @@ const FeiShuEditModal = ({
placeholder={t('core.module.http.appId') || 'Link Name'}
// maxLength={20}
{...register('app.appId', {
required: t('common.Name is empty') || 'Name is empty'
required: true
})}
/>
</Flex>
<Flex alignItems={'center'} mt={4}>
<Box flex={'0 0 90px'}>{t('core.module.http.AppSecret')}</Box>
<Input
placeholder={t('outlink.AppSecret') || 'Link Name'}
placeholder={'App Secret'}
// maxLength={20}
{...register('app.appSecret', {
required: t('common.Name is empty') || 'Name is empty'

View File

@@ -44,6 +44,7 @@ import { getDocPath } from '@/web/common/system/doc';
import dynamic from 'next/dynamic';
import MyMenu from '@fastgpt/web/components/common/MyMenu';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import { useI18n } from '@/web/context/I18n';
const SelectUsingWayModal = dynamic(() => import('./SelectUsingWayModal'));
@@ -261,6 +262,7 @@ function EditLinkModal({
}) {
const { feConfigs } = useSystemStore();
const { t } = useTranslation();
const { publishT } = useI18n();
const {
register,
setValue,
@@ -293,13 +295,13 @@ function EditLinkModal({
<MyModal
isOpen={true}
iconSrc="/imgs/modal/shareFill.svg"
title={isEdit ? t('outlink.Edit Link') : t('outlink.Create Link')}
title={isEdit ? publishT('Edit Link') : publishT('Create Link')}
>
<ModalBody>
<Flex alignItems={'center'}>
<Box flex={'0 0 90px'}>{t('Name')}</Box>
<Input
placeholder={t('outlink.Link Name') || 'Link Name'}
placeholder={publishT('Link Name')}
maxLength={20}
{...register('name', {
required: t('common.Name is empty') || 'Name is empty'
@@ -327,7 +329,7 @@ function EditLinkModal({
<Flex alignItems={'center'} mt={4}>
<Flex flex={'0 0 90px'} alignItems={'center'}>
QPM
<MyTooltip label={t('outlink.QPM Tips' || '')}>
<MyTooltip label={publishT('QPM Tips' || '')}>
<QuestionOutlineIcon ml={1} />
</MyTooltip>
</Flex>
@@ -337,7 +339,7 @@ function EditLinkModal({
min: 0,
max: 1000,
valueAsNumber: true,
required: t('outlink.QPM is empty') || ''
required: publishT('QPM is empty') || ''
})}
/>
</Flex>
@@ -360,13 +362,13 @@ function EditLinkModal({
<Flex alignItems={'center'} mt={4}>
<Flex flex={'0 0 90px'} alignItems={'center'}>
{t('outlink.token auth')}
<MyTooltip label={t('outlink.token auth Tips') || ''}>
{publishT('token auth')}
<MyTooltip label={publishT('token auth Tips') || ''}>
<QuestionOutlineIcon ml={1} />
</MyTooltip>
</Flex>
<Input
placeholder={t('outlink.token auth Tips') || ''}
placeholder={publishT('token auth Tips') || ''}
fontSize={'sm'}
{...register('limit.hookUrl')}
/>
@@ -377,7 +379,7 @@ function EditLinkModal({
fontSize={'sm'}
color={'myGray.500'}
>
{t('outlink.token auth use cases')}
{publishT('token auth use cases')}
</Link>
</>
)}

View File

@@ -196,7 +196,7 @@ export async function getServerSideProps(context: any) {
const currentTab = context?.query?.currentTab || TabEnum.simpleEdit;
return {
props: { currentTab, ...(await serviceSideProps(context, ['app'])) }
props: { currentTab, ...(await serviceSideProps(context, ['app', 'file', 'publish'])) }
};
}

View File

@@ -371,7 +371,7 @@ export async function getServerSideProps(context: any) {
props: {
appId: context?.query?.appId || '',
chatId: context?.query?.chatId || '',
...(await serviceSideProps(context))
...(await serviceSideProps(context, ['file']))
}
};
}

View File

@@ -431,7 +431,7 @@ export async function getServerSideProps(context: any) {
appName: app?.appId?.name || '',
appAvatar: app?.appId?.avatar || '',
appIntro: app?.appId?.intro || '',
...(await serviceSideProps(context))
...(await serviceSideProps(context, ['file']))
}
};
}

View File

@@ -382,7 +382,7 @@ const OutLink = () => {
export async function getServerSideProps(context: any) {
return {
props: {
...(await serviceSideProps(context))
...(await serviceSideProps(context, ['file']))
}
};
}

View File

@@ -27,9 +27,11 @@ import {
postCreateDatasetTextCollection
} from '@/web/core/dataset/api';
import Tag from '@fastgpt/web/components/common/Tag/index';
import { useI18n } from '@/web/context/I18n';
const Upload = () => {
const { t } = useTranslation();
const { fileT } = useI18n();
const { toast } = useToast();
const router = useRouter();
const { datasetDetail } = useDatasetStore();
@@ -131,7 +133,7 @@ const Upload = () => {
)
);
},
errorToast: t('common.file.Upload failed')
errorToast: fileT('Upload failed')
});
return (

View File

@@ -13,6 +13,7 @@ import { useSystemStore } from '@/web/common/system/useSystemStore';
import { uploadFile2DB } from '@/web/common/file/controller';
import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
import { ImportSourceItemType } from '@/web/core/dataset/type';
import { useI18n } from '@/web/context/I18n';
export type SelectFileItemType = {
fileId: string;
@@ -35,6 +36,8 @@ const FileSelector = ({
onFinishSelect: () => void;
} & FlexProps) => {
const { t } = useTranslation();
const { fileT } = useI18n();
const { toast } = useToast();
const { feConfigs } = useSystemStore();
@@ -129,7 +132,7 @@ const FileSelector = ({
files = files.slice(0, maxCount - selectFiles.length);
toast({
status: 'warning',
title: t('common.file.Some file count exceeds limit', { maxCount })
title: fileT('Some file count exceeds limit', { maxCount })
});
}
// size check
@@ -141,7 +144,7 @@ const FileSelector = ({
if (filterFiles.length < files.length) {
toast({
status: 'warning',
title: t('common.file.Some file size exceeds limit', { maxSize: formatFileSize(maxSize) })
title: fileT('Some file size exceeds limit', { maxSize: formatFileSize(maxSize) })
});
}
@@ -203,7 +206,7 @@ const FileSelector = ({
let isErr = files.some((item) => item.type === '');
if (isErr) {
return toast({
title: t('file.upload error description'),
title: fileT('upload error description'),
status: 'error'
});
}
@@ -262,18 +265,18 @@ const FileSelector = ({
<>
<Box fontWeight={'bold'}>
{isDragging
? t('file.Release the mouse to upload the file')
: t('common.file.Select and drag file tip')}
? fileT('Release the mouse to upload the file')
: fileT('Select and drag file tip')}
</Box>
{/* file type */}
<Box color={'myGray.500'} fontSize={'xs'}>
{t('common.file.Support file type', { fileType })}
{fileT('Support file type', { fileType })}
</Box>
<Box color={'myGray.500'} fontSize={'xs'}>
{/* max count */}
{maxCount && t('common.file.Support max count', { maxCount })}
{maxCount && fileT('Support max count', { maxCount })}
{/* max size */}
{maxSize && t('common.file.Support max size', { maxSize: formatFileSize(maxSize) })}
{maxSize && fileT('Support max size', { maxSize: formatFileSize(maxSize) })}
</Box>
<File

View File

@@ -16,6 +16,7 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
import { useTranslation } from 'next-i18next';
import MyTooltip from '@/components/MyTooltip';
import dynamic from 'next/dynamic';
import { useI18n } from '@/web/context/I18n';
const PreviewRawText = dynamic(() => import('./PreviewRawText'));
@@ -29,6 +30,7 @@ export const RenderUploadFiles = ({
showPreviewContent?: boolean;
}) => {
const { t } = useTranslation();
const { fileT } = useI18n();
const [previewFile, setPreviewFile] = useState<ImportSourceItemType>();
return files.length > 0 ? (
@@ -38,13 +40,13 @@ export const RenderUploadFiles = ({
<Thead draggable={false}>
<Tr bg={'myGray.100'} mb={2}>
<Th borderLeftRadius={'md'} borderBottom={'none'} py={4}>
{t('common.file.File Name')}
{fileT('File Name')}
</Th>
<Th borderBottom={'none'} py={4}>
{t('core.dataset.import.Upload file progress')}
</Th>
<Th borderBottom={'none'} py={4}>
{t('common.file.File Size')}
{fileT('File Size')}
</Th>
<Th borderRightRadius={'md'} borderBottom={'none'} py={4}>
{t('common.Action')}

View File

@@ -295,7 +295,7 @@ export async function getServerSideProps(context: any) {
const datasetId = context?.query?.datasetId;
return {
props: { currentTab, datasetId, ...(await serviceSideProps(context)) }
props: { currentTab, datasetId, ...(await serviceSideProps(context, ['file'])) }
};
}

View File

@@ -1,12 +1,16 @@
import 'i18next';
import common from '../../i18n/en/common.json';
import dataset from '../../i18n/en/dataset.json';
import app from '../../i18n/en/app.json';
import common from '../../i18n/zh/common.json';
import dataset from '../../i18n/zh/dataset.json';
import app from '../../i18n/zh/app.json';
import file from '../../i18n/zh/file.json';
import publish from '../../i18n/zh/publish.json';
export interface I18nNamespaces {
common: typeof common;
dataset: typeof dataset;
app: typeof app;
file: typeof file;
publish: typeof publish;
}
export type I18nNsType = (keyof I18nNamespaces)[];

View File

@@ -2,6 +2,7 @@ import React, { useRef, useCallback } from 'react';
import { Box } from '@chakra-ui/react';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useTranslation } from 'next-i18next';
import { useI18n } from '@/web/context/I18n';
export const useSelectFile = (props?: {
fileType?: string;
@@ -9,6 +10,7 @@ export const useSelectFile = (props?: {
maxCount?: number;
}) => {
const { t } = useTranslation();
const { fileT } = useI18n();
const { fileType = '*', multiple = false, maxCount = 10 } = props || {};
const { toast } = useToast();
const SelectFileDom = useRef<HTMLInputElement>(null);
@@ -30,7 +32,7 @@ export const useSelectFile = (props?: {
if (fileList.length > maxCount) {
toast({
status: 'warning',
title: t('common.file.Select file amount limit', { max: maxCount })
title: fileT('Select file amount limit', { max: maxCount })
});
fileList = fileList.slice(0, maxCount);
}
@@ -39,7 +41,7 @@ export const useSelectFile = (props?: {
/>
</Box>
),
[fileType, maxCount, multiple, t, toast]
[fileT, fileType, maxCount, multiple, toast]
);
const onOpen = useCallback((sign?: any) => {

View File

@@ -6,6 +6,8 @@ type I18nContextType = {
commonT: TFunction<['common'], undefined>;
appT: TFunction<['app'], undefined>;
datasetT: TFunction<['dataset'], undefined>;
fileT: TFunction<['file'], undefined>;
publishT: TFunction<['publish'], undefined>;
};
export const I18nContext = createContext<I18nContextType>({
@@ -17,13 +19,17 @@ const I18nContextProvider = ({ children }: { children: React.ReactNode }) => {
const { t: commonT } = useTranslation('common');
const { t: appT } = useTranslation('app');
const { t: datasetT } = useTranslation('dataset');
const { t: fileT } = useTranslation('file');
const { t: publishT } = useTranslation('publish');
return (
<I18nContext.Provider
value={{
commonT,
appT,
datasetT
datasetT,
fileT,
publishT
}}
>
{children}