Compare commits

..

6 Commits

Author SHA1 Message Date
5a85f0d427 chore: hide workflow run detail 2024-08-07 18:01:00 +08:00
96bd12af44 Merge pull request #38 from Saul-BT/feat/spanish-language
feat: add spanish language
2024-08-07 17:14:47 +08:00
484a5dc102 Merge pull request #81 from yoyocircle/main
fix: typos
2024-08-07 17:08:50 +08:00
10eb176f72 Merge pull request #84 from langgenius/fix/optional-i18n
fix: optional copywriting i18n
2024-07-31 11:56:15 +08:00
f6b4b4a361 fix: typos 2024-07-17 03:59:08 +00:00
f7ff288ff1 feat: add spanish language 2023-12-07 21:20:21 +01:00
11 changed files with 125 additions and 102 deletions

View File

@ -4,25 +4,25 @@ import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
type IAppUnavailableProps = { type IAppUnavailableProps = {
isUnknwonReason: boolean isUnknownReason: boolean
errMessage?: string errMessage?: string
} }
const AppUnavailable: FC<IAppUnavailableProps> = ({ const AppUnavailable: FC<IAppUnavailableProps> = ({
isUnknwonReason, isUnknownReason,
errMessage, errMessage,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
let message = errMessage let message = errMessage
if (!errMessage) if (!errMessage)
message = (isUnknwonReason ? t('app.common.appUnkonwError') : t('app.common.appUnavailable')) as string message = (isUnknownReason ? t('app.common.appUnkonwError') : t('app.common.appUnavailable')) as string
return ( return (
<div className='flex items-center justify-center w-screen h-screen'> <div className='flex items-center justify-center w-screen h-screen'>
<h1 className='mr-5 h-[50px] leading-[50px] pr-5 text-[24px] font-medium' <h1 className='mr-5 h-[50px] leading-[50px] pr-5 text-[24px] font-medium'
style={{ style={{
borderRight: '1px solid rgba(0,0,0,.3)', borderRight: '1px solid rgba(0,0,0,.3)',
}}>{(errMessage || isUnknwonReason) ? 500 : 404}</h1> }}>{(errMessage || isUnknownReason) ? 500 : 404}</h1>
<div className='text-sm'>{message}</div> <div className='text-sm'>{message}</div>
</div> </div>
) )

View File

@ -58,7 +58,7 @@ type IAnswerProps = {
item: ChatItem item: ChatItem
feedbackDisabled: boolean feedbackDisabled: boolean
onFeedback?: FeedbackFunc onFeedback?: FeedbackFunc
isResponsing?: boolean isResponding?: boolean
allToolIcons?: Record<string, string | Emoji> allToolIcons?: Record<string, string | Emoji>
} }
@ -67,7 +67,7 @@ const Answer: FC<IAnswerProps> = ({
item, item,
feedbackDisabled = false, feedbackDisabled = false,
onFeedback, onFeedback,
isResponsing, isResponding,
allToolIcons, allToolIcons,
}) => { }) => {
const { id, content, feedback, agent_thoughts, workflowProcess } = item const { id, content, feedback, agent_thoughts, workflowProcess } = item
@ -153,7 +153,7 @@ const Answer: FC<IAnswerProps> = ({
<Thought <Thought
thought={item} thought={item}
allToolIcons={allToolIcons || {}} allToolIcons={allToolIcons || {}}
isFinished={!!item.observation || !isResponsing} isFinished={!!item.observation || !isResponding}
/> />
)} )}
@ -169,7 +169,7 @@ const Answer: FC<IAnswerProps> = ({
<div key={id}> <div key={id}>
<div className='flex items-start'> <div className='flex items-start'>
<div className={`${s.answerIcon} w-10 h-10 shrink-0`}> <div className={`${s.answerIcon} w-10 h-10 shrink-0`}>
{isResponsing {isResponding
&& <div className={s.typeingIcon}> && <div className={s.typeingIcon}>
<LoadingAnim type='avatar' /> <LoadingAnim type='avatar' />
</div> </div>
@ -181,7 +181,7 @@ const Answer: FC<IAnswerProps> = ({
{workflowProcess && ( {workflowProcess && (
<WorkflowProcess data={workflowProcess} hideInfo /> <WorkflowProcess data={workflowProcess} hideInfo />
)} )}
{(isResponsing && (isAgentMode ? (!content && (agent_thoughts || []).filter(item => !!item.thought || !!item.tool).length === 0) : !content)) {(isResponding && (isAgentMode ? (!content && (agent_thoughts || []).filter(item => !!item.thought || !!item.tool).length === 0) : !content))
? ( ? (
<div className='flex items-center justify-center w-6 h-5'> <div className='flex items-center justify-center w-6 h-5'>
<LoadingAnim type='text' /> <LoadingAnim type='text' />

View File

@ -30,7 +30,7 @@ export type IChatProps = {
checkCanSend?: () => boolean checkCanSend?: () => boolean
onSend?: (message: string, files: VisionFile[]) => void onSend?: (message: string, files: VisionFile[]) => void
useCurrentUserAvatar?: boolean useCurrentUserAvatar?: boolean
isResponsing?: boolean isResponding?: boolean
controlClearQuery?: number controlClearQuery?: number
visionConfig?: VisionSettings visionConfig?: VisionSettings
} }
@ -43,7 +43,7 @@ const Chat: FC<IChatProps> = ({
checkCanSend, checkCanSend,
onSend = () => { }, onSend = () => { },
useCurrentUserAvatar, useCurrentUserAvatar,
isResponsing, isResponding,
controlClearQuery, controlClearQuery,
visionConfig, visionConfig,
}) => { }) => {
@ -95,7 +95,7 @@ const Chat: FC<IChatProps> = ({
if (!files.find(item => item.type === TransferMethod.local_file && !item.fileId)) { if (!files.find(item => item.type === TransferMethod.local_file && !item.fileId)) {
if (files.length) if (files.length)
onClear() onClear()
if (!isResponsing) if (!isResponding)
setQuery('') setQuery('')
} }
} }
@ -129,7 +129,7 @@ const Chat: FC<IChatProps> = ({
item={item} item={item}
feedbackDisabled={feedbackDisabled} feedbackDisabled={feedbackDisabled}
onFeedback={onFeedback} onFeedback={onFeedback}
isResponsing={isResponsing && isLast} isResponding={isResponding && isLast}
/> />
} }
return ( return (

View File

@ -33,7 +33,7 @@ const Main: FC = () => {
* app info * app info
*/ */
const [appUnavailable, setAppUnavailable] = useState<boolean>(false) const [appUnavailable, setAppUnavailable] = useState<boolean>(false)
const [isUnknwonReason, setIsUnknwonReason] = useState<boolean>(false) const [isUnknownReason, setIsUnknownReason] = useState<boolean>(false)
const [promptConfig, setPromptConfig] = useState<PromptConfig | null>(null) const [promptConfig, setPromptConfig] = useState<PromptConfig | null>(null)
const [inited, setInited] = useState<boolean>(false) const [inited, setInited] = useState<boolean>(false)
// in mobile, show sidebar by click button // in mobile, show sidebar by click button
@ -86,7 +86,7 @@ const Main: FC = () => {
setCurrInputs(inputs) setCurrInputs(inputs)
setChatStarted() setChatStarted()
// parse variables in introduction // parse variables in introduction
setChatList(generateNewChatListWithOpenstatement('', inputs)) setChatList(generateNewChatListWithOpenStatement('', inputs))
} }
const hasSetInputs = (() => { const hasSetInputs = (() => {
if (!isNewConversation) if (!isNewConversation)
@ -121,10 +121,10 @@ const Main: FC = () => {
} }
// update chat list of current conversation // update chat list of current conversation
if (!isNewConversation && !conversationIdChangeBecauseOfNew && !isResponsing) { if (!isNewConversation && !conversationIdChangeBecauseOfNew && !isResponding) {
fetchChatList(currConversationId).then((res: any) => { fetchChatList(currConversationId).then((res: any) => {
const { data } = res const { data } = res
const newChatList: ChatItem[] = generateNewChatListWithOpenstatement(notSyncToStateIntroduction, notSyncToStateInputs) const newChatList: ChatItem[] = generateNewChatListWithOpenStatement(notSyncToStateIntroduction, notSyncToStateInputs)
data.forEach((item: any) => { data.forEach((item: any) => {
newChatList.push({ newChatList.push({
@ -148,7 +148,7 @@ const Main: FC = () => {
} }
if (isNewConversation && isChatStarted) if (isNewConversation && isChatStarted)
setChatList(generateNewChatListWithOpenstatement()) setChatList(generateNewChatListWithOpenStatement())
} }
useEffect(handleConversationSwitch, [currConversationId, inited]) useEffect(handleConversationSwitch, [currConversationId, inited])
@ -176,7 +176,7 @@ const Main: FC = () => {
chatListDomRef.current.scrollTop = chatListDomRef.current.scrollHeight chatListDomRef.current.scrollTop = chatListDomRef.current.scrollHeight
}, [chatList, currConversationId]) }, [chatList, currConversationId])
// user can not edit inputs if user had send message // user can not edit inputs if user had send message
const canEditInpus = !chatList.some(item => item.isAnswer === false) && isNewConversation const canEditInputs = !chatList.some(item => item.isAnswer === false) && isNewConversation
const createNewChat = () => { const createNewChat = () => {
// if new chat is already exist, do not create new chat // if new chat is already exist, do not create new chat
if (conversationList.some(item => item.id === '-1')) if (conversationList.some(item => item.id === '-1'))
@ -193,21 +193,21 @@ const Main: FC = () => {
} }
// sometime introduction is not applied to state // sometime introduction is not applied to state
const generateNewChatListWithOpenstatement = (introduction?: string, inputs?: Record<string, any> | null) => { const generateNewChatListWithOpenStatement = (introduction?: string, inputs?: Record<string, any> | null) => {
let caculatedIntroduction = introduction || conversationIntroduction || '' let calculatedIntroduction = introduction || conversationIntroduction || ''
const caculatedPromptVariables = inputs || currInputs || null const calculatedPromptVariables = inputs || currInputs || null
if (caculatedIntroduction && caculatedPromptVariables) if (calculatedIntroduction && calculatedPromptVariables)
caculatedIntroduction = replaceVarWithValues(caculatedIntroduction, promptConfig?.prompt_variables || [], caculatedPromptVariables) calculatedIntroduction = replaceVarWithValues(calculatedIntroduction, promptConfig?.prompt_variables || [], calculatedPromptVariables)
const openstatement = { const openstatement = {
id: `${Date.now()}`, id: `${Date.now()}`,
content: caculatedIntroduction, content: calculatedIntroduction,
isAnswer: true, isAnswer: true,
feedbackDisabled: true, feedbackDisabled: true,
isOpeningStatement: isShowPrompt, isOpeningStatement: isShowPrompt,
} }
if (caculatedIntroduction) if (calculatedIntroduction)
return [openstatement] return [openStatement]
return [] return []
} }
@ -255,14 +255,14 @@ const Main: FC = () => {
setAppUnavailable(true) setAppUnavailable(true)
} }
else { else {
setIsUnknwonReason(true) setIsUnknownReason(true)
setAppUnavailable(true) setAppUnavailable(true)
} }
} }
})() })()
}, []) }, [])
const [isResponsing, { setTrue: setResponsingTrue, setFalse: setResponsingFalse }] = useBoolean(false) const [isResponding, { setTrue: setRespondingTrue, setFalse: setRespondingFalse }] = useBoolean(false)
const [abortController, setAbortController] = useState<AbortController | null>(null) const [abortController, setAbortController] = useState<AbortController | null>(null)
const { notify } = Toast const { notify } = Toast
const logError = (message: string) => { const logError = (message: string) => {
@ -279,8 +279,8 @@ const Main: FC = () => {
const inputLens = Object.values(currInputs).length const inputLens = Object.values(currInputs).length
const promptVariablesLens = promptConfig.prompt_variables.length const promptVariablesLens = promptConfig.prompt_variables.length
const emytyInput = inputLens < promptVariablesLens || Object.values(currInputs).find(v => !v) const emptyInput = inputLens < promptVariablesLens || Object.values(currInputs).find(v => !v)
if (emytyInput) { if (emptyInput) {
logError(t('app.errorMessage.valueOfVarRequired')) logError(t('app.errorMessage.valueOfVarRequired'))
return false return false
} }
@ -291,7 +291,7 @@ const Main: FC = () => {
const [openingSuggestedQuestions, setOpeningSuggestedQuestions] = useState<string[]>([]) const [openingSuggestedQuestions, setOpeningSuggestedQuestions] = useState<string[]>([])
const [messageTaskId, setMessageTaskId] = useState('') const [messageTaskId, setMessageTaskId] = useState('')
const [hasStopResponded, setHasStopResponded, getHasStopResponded] = useGetState(false) const [hasStopResponded, setHasStopResponded, getHasStopResponded] = useGetState(false)
const [isResponsingConIsCurrCon, setIsResponsingConCurrCon, getIsResponsingConIsCurrCon] = useGetState(true) const [isRespondingConIsCurrCon, setIsRespondingConCurrCon, getIsRespondingConIsCurrCon] = useGetState(true)
const [userQuery, setUserQuery] = useState('') const [userQuery, setUserQuery] = useState('')
const updateCurrentQA = ({ const updateCurrentQA = ({
@ -318,7 +318,7 @@ const Main: FC = () => {
} }
const handleSend = async (message: string, files?: VisionFile[]) => { const handleSend = async (message: string, files?: VisionFile[]) => {
if (isResponsing) { if (isResponding) {
notify({ type: 'info', message: t('app.errorMessage.waitForResponse') }) notify({ type: 'info', message: t('app.errorMessage.waitForResponse') })
return return
} }
@ -340,7 +340,7 @@ const Main: FC = () => {
}) })
} }
// qustion // question
const questionId = `question-${Date.now()}` const questionId = `question-${Date.now()}`
const questionItem = { const questionItem = {
id: questionId, id: questionId,
@ -374,7 +374,7 @@ const Main: FC = () => {
const prevTempNewConversationId = getCurrConversationId() || '-1' const prevTempNewConversationId = getCurrConversationId() || '-1'
let tempNewConversationId = '' let tempNewConversationId = ''
setResponsingTrue() setRespondingTrue()
sendChatMessage(data, { sendChatMessage(data, {
getAbortController: (abortController) => { getAbortController: (abortController) => {
setAbortController(abortController) setAbortController(abortController)
@ -399,7 +399,7 @@ const Main: FC = () => {
setMessageTaskId(taskId) setMessageTaskId(taskId)
// has switched to other conversation // has switched to other conversation
if (prevTempNewConversationId !== getCurrConversationId()) { if (prevTempNewConversationId !== getCurrConversationId()) {
setIsResponsingConCurrCon(false) setIsRespondingConCurrCon(false)
return return
} }
updateCurrentQA({ updateCurrentQA({
@ -426,7 +426,7 @@ const Main: FC = () => {
resetNewConversationInputs() resetNewConversationInputs()
setChatNotStarted() setChatNotStarted()
setCurrConversationId(tempNewConversationId, APP_ID, true) setCurrConversationId(tempNewConversationId, APP_ID, true)
setResponsingFalse() setRespondingFalse()
}, },
onFile(file) { onFile(file) {
const lastThought = responseItem.agent_thoughts?.[responseItem.agent_thoughts?.length - 1] const lastThought = responseItem.agent_thoughts?.[responseItem.agent_thoughts?.length - 1]
@ -465,7 +465,7 @@ const Main: FC = () => {
} }
// has switched to other conversation // has switched to other conversation
if (prevTempNewConversationId !== getCurrConversationId()) { if (prevTempNewConversationId !== getCurrConversationId()) {
setIsResponsingConCurrCon(false) setIsRespondingConCurrCon(false)
return false return false
} }
@ -520,7 +520,7 @@ const Main: FC = () => {
)) ))
}, },
onError() { onError() {
setResponsingFalse() setRespondingFalse()
// role back placeholder answer // role back placeholder answer
setChatList(produce(getChatList(), (draft) => { setChatList(produce(getChatList(), (draft) => {
draft.splice(draft.findIndex(item => item.id === placeholderAnswerId), 1) draft.splice(draft.findIndex(item => item.id === placeholderAnswerId), 1)
@ -604,7 +604,7 @@ const Main: FC = () => {
} }
if (appUnavailable) if (appUnavailable)
return <AppUnavailable isUnknwonReason={isUnknwonReason} errMessage={!hasSetAppConfig ? 'Please set APP_ID and API_KEY in config/index.tsx' : ''} /> return <AppUnavailable isUnknownReason={isUnknownReason} errMessage={!hasSetAppConfig ? 'Please set APP_ID and API_KEY in config/index.tsx' : ''} />
if (!APP_ID || !APP_INFO || !promptConfig) if (!APP_ID || !APP_INFO || !promptConfig)
return <Loading type='app' /> return <Loading type='app' />
@ -639,7 +639,7 @@ const Main: FC = () => {
siteInfo={APP_INFO} siteInfo={APP_INFO}
promptConfig={promptConfig} promptConfig={promptConfig}
onStartChat={handleStartChat} onStartChat={handleStartChat}
canEidtInpus={canEditInpus} canEditInputs={canEditInputs}
savedInputs={currInputs as Record<string, any>} savedInputs={currInputs as Record<string, any>}
onInputsChange={setCurrInputs} onInputsChange={setCurrInputs}
></ConfigSence> ></ConfigSence>
@ -652,7 +652,7 @@ const Main: FC = () => {
chatList={chatList} chatList={chatList}
onSend={handleSend} onSend={handleSend}
onFeedback={handleFeedback} onFeedback={handleFeedback}
isResponsing={isResponsing} isResponding={isResponding}
checkCanSend={checkCanSend} checkCanSend={checkCanSend}
visionConfig={visionConfig} visionConfig={visionConfig}
/> />

View File

@ -20,7 +20,7 @@ export type IWelcomeProps = {
siteInfo: AppInfo siteInfo: AppInfo
promptConfig: PromptConfig promptConfig: PromptConfig
onStartChat: (inputs: Record<string, any>) => void onStartChat: (inputs: Record<string, any>) => void
canEidtInpus: boolean canEditInputs: boolean
savedInputs: Record<string, any> savedInputs: Record<string, any>
onInputsChange: (inputs: Record<string, any>) => void onInputsChange: (inputs: Record<string, any>) => void
} }
@ -32,7 +32,7 @@ const Welcome: FC<IWelcomeProps> = ({
siteInfo, siteInfo,
promptConfig, promptConfig,
onStartChat, onStartChat,
canEidtInpus, canEditInputs,
savedInputs, savedInputs,
onInputsChange, onInputsChange,
}) => { }) => {
@ -131,8 +131,8 @@ const Welcome: FC<IWelcomeProps> = ({
const canChat = () => { const canChat = () => {
const inputLens = Object.values(inputs).length const inputLens = Object.values(inputs).length
const promptVariablesLens = promptConfig.prompt_variables.length const promptVariablesLens = promptConfig.prompt_variables.length
const emytyInput = inputLens < promptVariablesLens || Object.values(inputs).filter(v => v === '').length > 0 const emptyInput = inputLens < promptVariablesLens || Object.values(inputs).filter(v => v === '').length > 0
if (emytyInput) { if (emptyInput) {
logError(t('app.errorMessage.valueOfVarRequired')) logError(t('app.errorMessage.valueOfVarRequired'))
return false return false
} }
@ -217,7 +217,7 @@ const Welcome: FC<IWelcomeProps> = ({
} }
const renderHasSetInputsPublic = () => { const renderHasSetInputsPublic = () => {
if (!canEidtInpus) { if (!canEditInputs) {
return ( return (
<TemplateVarPanel <TemplateVarPanel
isFold={false} isFold={false}
@ -260,7 +260,7 @@ const Welcome: FC<IWelcomeProps> = ({
} }
const renderHasSetInputsPrivate = () => { const renderHasSetInputsPrivate = () => {
if (!canEidtInpus || !hasVar) if (!canEditInputs || !hasVar)
return null return null
return ( return (
@ -284,7 +284,7 @@ const Welcome: FC<IWelcomeProps> = ({
} }
const renderHasSetInputs = () => { const renderHasSetInputs = () => {
if ((!isPublicVersion && !canEidtInpus) || !hasVar) if ((!isPublicVersion && !canEditInputs) || !hasVar)
return null return null
return ( return (

View File

@ -3,13 +3,10 @@ import type { FC } from 'react'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import cn from 'classnames' import cn from 'classnames'
import BlockIcon from './block-icon' import BlockIcon from './block-icon'
import CodeEditor from './code-editor'
import { CodeLanguage } from '@/types/app'
import AlertCircle from '@/app/components/base/icons/line/alert-circle' import AlertCircle from '@/app/components/base/icons/line/alert-circle'
import AlertTriangle from '@/app/components/base/icons/line/alert-triangle' import AlertTriangle from '@/app/components/base/icons/line/alert-triangle'
import Loading02 from '@/app/components/base/icons/line/loading-02' import Loading02 from '@/app/components/base/icons/line/loading-02'
import CheckCircle from '@/app/components/base/icons/line/check-circle' import CheckCircle from '@/app/components/base/icons/line/check-circle'
import ChevronRight from '@/app/components/base/icons/line/chevron-right'
import type { NodeTracing } from '@/types/app' import type { NodeTracing } from '@/types/app'
type Props = { type Props = {
@ -52,12 +49,6 @@ const NodePanel: FC<Props> = ({ nodeInfo, hideInfo = false }) => {
)} )}
onClick={() => setCollapseState(!collapseState)} onClick={() => setCollapseState(!collapseState)}
> >
<ChevronRight
className={cn(
'shrink-0 w-3 h-3 mr-1 text-gray-400 transition-all group-hover:text-gray-500',
!collapseState && 'rotate-90',
)}
/>
<BlockIcon size={hideInfo ? 'xs' : 'sm'} className={cn('shrink-0 mr-2', hideInfo && '!mr-1')} type={nodeInfo.node_type} toolIcon={nodeInfo.extras?.icon || nodeInfo.extras} /> <BlockIcon size={hideInfo ? 'xs' : 'sm'} className={cn('shrink-0 mr-2', hideInfo && '!mr-1')} type={nodeInfo.node_type} toolIcon={nodeInfo.extras?.icon || nodeInfo.extras} />
<div className={cn( <div className={cn(
'grow text-gray-700 text-[13px] leading-[16px] font-semibold truncate', 'grow text-gray-700 text-[13px] leading-[16px] font-semibold truncate',
@ -82,48 +73,6 @@ const NodePanel: FC<Props> = ({ nodeInfo, hideInfo = false }) => {
</div> </div>
)} )}
</div> </div>
{!collapseState && (
<div className='pb-2'>
<div className={cn('px-[10px] py-1', hideInfo && '!px-2 !py-0.5')}>
{nodeInfo.status === 'failed' && (
<div className='px-3 py-[10px] bg-[#fef3f2] rounded-lg border-[0.5px] border-[rbga(0,0,0,0.05)] text-xs leading-[18px] text-[#d92d20] shadow-xs'>{nodeInfo.error}</div>
)}
</div>
{nodeInfo.inputs && (
<div className={cn('px-[10px] py-1', hideInfo && '!px-2 !py-0.5')}>
<CodeEditor
readOnly
title={<div>INPUT</div>}
language={CodeLanguage.json}
value={nodeInfo.inputs}
isJSONStringifyBeauty
/>
</div>
)}
{nodeInfo.process_data && (
<div className={cn('px-[10px] py-1', hideInfo && '!px-2 !py-0.5')}>
<CodeEditor
readOnly
title={<div>PROCESS DATA</div>}
language={CodeLanguage.json}
value={nodeInfo.process_data}
isJSONStringifyBeauty
/>
</div>
)}
{nodeInfo.outputs && (
<div className={cn('px-[10px] py-1', hideInfo && '!px-2 !py-0.5')}>
<CodeEditor
readOnly
title={<div>OUTPUT</div>}
language={CodeLanguage.json}
value={nodeInfo.outputs}
isJSONStringifyBeauty
/>
</div>
)}
</div>
)}
</div> </div>
</div> </div>
) )

View File

@ -7,7 +7,7 @@ export const APP_INFO: AppInfo = {
description: '', description: '',
copyright: '', copyright: '',
privacy_policy: '', privacy_policy: '',
default_language: 'zh-Hans', default_language: 'en',
} }
export const isShowPrompt = false export const isShowPrompt = false

View File

@ -2,8 +2,10 @@
import i18n from 'i18next' import i18n from 'i18next'
import { initReactI18next } from 'react-i18next' import { initReactI18next } from 'react-i18next'
import commonEn from './lang/common.en' import commonEn from './lang/common.en'
import commonEs from './lang/common.es'
import commonZh from './lang/common.zh' import commonZh from './lang/common.zh'
import appEn from './lang/app.en' import appEn from './lang/app.en'
import appEs from './lang/app.es'
import appZh from './lang/app.zh' import appZh from './lang/app.zh'
import toolsEn from './lang/tools.en' import toolsEn from './lang/tools.en'
import toolsZh from './lang/tools.zh' import toolsZh from './lang/tools.zh'
@ -18,6 +20,12 @@ const resources = {
tools: toolsEn, tools: toolsEn,
}, },
}, },
'es': {
translation: {
common: commonEs,
app: appEs,
},
},
'zh-Hans': { 'zh-Hans': {
translation: { translation: {
common: commonZh, common: commonZh,

View File

@ -1,6 +1,6 @@
export const i18n = { export const i18n = {
defaultLocale: 'en', defaultLocale: 'en',
locales: ['en', 'zh-Hans'], locales: ['en', 'es', 'zh-Hans'],
} as const } as const
export type Locale = typeof i18n['locales'][number] export type Locale = typeof i18n['locales'][number]

33
i18n/lang/app.es.ts Normal file
View File

@ -0,0 +1,33 @@
const translation = {
common: {
welcome: 'Bienvenido a usar',
appUnavailable: 'App es inaccesible',
appUnkonwError: 'App es inaccesible',
},
chat: {
newChat: 'Nuevo chat',
newChatDefaultName: 'Nueva conversación',
openingStatementTitle: 'Frase de apertura',
powerBy: 'Desarrollado por',
prompt: 'Prompt',
privatePromptConfigTitle: 'Ajustes de conversación',
publicPromptConfigTitle: 'Prompt inicial',
configStatusDes: 'Antes de comenzar, puede modificar la configuración de la conversación',
configDisabled:
'La configuración de la sesión anterior se ha utilizado para esta sesión.',
startChat: 'Comenzar chat',
privacyPolicyLeft:
'Por favor lea la ',
privacyPolicyMiddle:
'política de privacidad',
privacyPolicyRight:
' proporcionada por el desarrollador de la aplicación.',
},
errorMessage: {
valueOfVarRequired: 'El valor de las variables no puede estar vacío',
waitForResponse:
'Por favor espere a que la respuesta al mensaje anterior se complete.',
},
}
export default translation

33
i18n/lang/common.es.ts Normal file
View File

@ -0,0 +1,33 @@
const translation = {
api: {
success: 'Éxito',
saved: 'Guardado',
create: 'Creado',
},
operation: {
confirm: 'Confirmar',
cancel: 'Cancelar',
clear: 'Limpiar',
save: 'Guardar',
edit: 'Editar',
refresh: 'Reiniciar',
search: 'Buscar',
send: 'Enviar',
lineBreak: 'Salto de línea',
like: 'Me gusta',
dislike: 'No me gusta',
ok: 'OK',
},
imageUploader: {
uploadFromComputer: 'Subir desde el ordenador',
uploadFromComputerReadError: 'La lectura de la imagen falló, por favor inténtelo de nuevo.',
uploadFromComputerUploadError: 'Error al subir la imagen, por favor inténtelo de nuevo.',
uploadFromComputerLimit: 'Las imágenes subidas no pueden superar los {{size}} MB',
pasteImageLink: 'Pegar enlace de imagen',
pasteImageLinkInputPlaceholder: 'Pegar enlace de imagen aquí',
pasteImageLinkInvalid: 'Enlace de imagen no válido',
imageUpload: 'Subir imagen',
},
}
export default translation