Skip to content
Open

I18n #94

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .env.example

This file was deleted.

5 changes: 4 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{
"extends": "next/core-web-vitals"
"extends": "next/core-web-vitals",
"rules": {
"react/jsx-key": "off"
}
}
22 changes: 21 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,25 @@
"editor.quickSuggestions": {
"strings": true
},
"cSpell.words": ["DBGPT"]
"cSpell.words": [
"DBGPT"
],
"MicroPython.executeButton": [
{
"text": "▶",
"tooltip": "运行",
"alignment": "left",
"command": "extension.executeFile",
"priority": 3.5
}
],
"MicroPython.syncButton": [
{
"text": "$(sync)",
"tooltip": "同步",
"alignment": "left",
"command": "extension.execute",
"priority": 4
}
]
}
58 changes: 58 additions & 0 deletions app/i18n.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/*
* @Date: 2024-05-14 15:41:13
* @LastEditors: CZH
* @LastEditTime: 2024-05-23 17:33:01
* @FilePath: /DB-GPT-Web/app/i18n.ts
*/
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';

Expand Down Expand Up @@ -219,6 +225,32 @@ const en = {
operators: 'Operators',
Chinese: 'Chinese',
English: 'English',
no: 'No',
yes: 'Yes',
confirm: 'Confirm',
Request_error: 'Request error',
new: 'New',
Preview: 'Preview',
add_knowledge: 'Add Knowledge',
Editor: 'Editor',
Start_a_conversation: 'Start a conversation',
Run: 'Run',
Save: 'Save',
Select_File: 'Select File',
No_flow_found: 'No flow found',
Label: 'Label',
Deploy: 'Deploy',
Copy_AWEL_Flow: 'Copy AWEL Flow',
Editable: 'Editable',
Title: 'Title',
Create_Now: 'Create Now',
Host: 'Host',
Path: 'Path',
Delete_Chat: 'Delete Chat',
DB_Name: 'DB Name',
DB_Type: 'DB Type',
Are_you_sure_delete_this_chat: 'Are you sure delete this chat?',
Do_you_Want_to_delete_the: 'Do you Want to delete the',
} as const;

export type I18nKeys = keyof typeof en;
Expand All @@ -228,6 +260,31 @@ export interface Resources {
}

const zh: Resources['translation'] = {
Title: '标题',
Are_you_sure_delete_this_chat: '确认删除此对话?',
Do_you_Want_to_delete_the: '确定删除',
Host: '主机',
DB_Name: '数据库名称',
DB_Type: '数据类型',
Path: '路径',
Editable: '可编辑',
no: '否',
yes: '是',
Create_Now: '创建',
new: '新',
Run: '执行',
Save: '保存',
confirm: '确定',
Preview: '预览',
Editor: '编辑',
Label: '标签',
Deploy: '部署',
Copy_AWEL_Flow: '复制 AWEL 工作流',
No_flow_found: '暂无数据',
Select_File: '选择文件',
Start_a_conversation: '开始对话',
add_knowledge: '新增知识',
Request_error: '请求出错',
Knowledge_Space: '知识库',
space: '知识库',
Vector: '向量',
Expand Down Expand Up @@ -362,6 +419,7 @@ const zh: Resources['translation'] = {
input_count: '共计输入',
input_unit: '字',
Copy: '复制',
Delete_Chat: '删除对话',
Copy_success: '内容复制成功',
Copy_nothing: '内容复制为空',
Copry_error: '复制失败',
Expand Down
6 changes: 6 additions & 0 deletions client/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/*
* @Date: 2024-05-14 15:41:13
* @LastEditors: CZH
* @LastEditTime: 2024-05-22 14:22:00
* @FilePath: /DB-GPT-Web/client/api/index.ts
*/
import axios, { AxiosRequestConfig, AxiosError, AxiosResponse } from 'axios';

export type ResponseType<T = any> = {
Expand Down
5 changes: 3 additions & 2 deletions client/api/tools/interceptors.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AxiosError } from 'axios';
import { ApiResponse, FailedTuple, SuccessTuple, ResponseType } from '../';
import { notification } from 'antd';
import { t } from 'i18next';

/**
* Response processing
Expand All @@ -21,7 +22,7 @@ export const apiInterceptors = <T = any, D = any>(promise: Promise<ApiResponse<T
return [null, data.data, data, response];
} else {
notification.error({
message: `Request error`,
message: t(`Request_error`),
description: data?.err_msg ?? 'The interface is abnormal. Please try again later',
});
}
Expand All @@ -37,7 +38,7 @@ export const apiInterceptors = <T = any, D = any>(promise: Promise<ApiResponse<T
} catch (e) {}
}
notification.error({
message: `Request error`,
message: t(`Request_error`),
description: errMessage,
});
return [err, null, null, null];
Expand Down
4 changes: 2 additions & 2 deletions components/app/app-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ export default function AppCard(props: IProps) {
title: t('Tips'),
icon: <WarningOutlined />,
content: `do you want delete the application?`,
okText: 'Yes',
okText: t('yes'),
okType: 'danger',
cancelText: 'No',
cancelText: t('no'),
async onOk() {
await apiInterceptors(delApp({ app_code: app.app_code }));
updateApps(isCollected ? { is_collected: isCollected } : undefined);
Expand Down
2 changes: 1 addition & 1 deletion components/chat/completion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ const Completion = ({ messages, onSubmit }: Props) => {
image="/empty.png"
imageStyle={{ width: 320, height: 320, margin: '0 auto', maxWidth: '100%', maxHeight: '100%' }}
className="flex items-center justify-center flex-col h-full w-full"
description="Start a conversation"
description={t('Start_a_conversation')}
/>
)}
</div>
Expand Down
7 changes: 5 additions & 2 deletions components/chat/db-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import MonacoEditor from './monaco-editor';
import { sendGetRequest, sendSpacePostRequest } from '@/utils/request';
import { useSearchParams } from 'next/navigation';
import { OnChange } from '@monaco-editor/react';
import { useTranslation } from 'react-i18next';
import Header from './header';
import Chart from '../chart';

Expand Down Expand Up @@ -93,6 +94,7 @@ function DbEditorContent({ editorValue, chartData, tableData, handleChange }: IP
}

function DbEditor() {
const { t } = useTranslation();
const [expandedKeys, setExpandedKeys] = React.useState<React.Key[]>([]);
const [searchValue, setSearchValue] = React.useState('');
const [currentRound, setCurrentRound] = React.useState<null | string | number>();
Expand Down Expand Up @@ -437,7 +439,7 @@ function DbEditor() {
}
}}
>
Run
{t('Run')}
</Button>
<Button
loading={submitLoading || submitChartLoading}
Expand All @@ -449,7 +451,8 @@ function DbEditor() {
}
}}
>
Save
{t('Save')}

</Button>
</div>
<div className="flex items-center py-3">
Expand Down
4 changes: 3 additions & 1 deletion components/chat/header/excel-upload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Upload, UploadProps, Button, message, UploadFile, Tooltip } from 'antd'
import { LinkOutlined, SelectOutlined, UploadOutlined } from '@ant-design/icons';
import { apiInterceptors, postChatModeParamsFileLoad } from '@/client/api';
import { ChatContext } from '@/app/chat-context';
import { useTranslation } from 'react-i18next';

interface Props {
convUid: string;
Expand All @@ -11,6 +12,7 @@ interface Props {
}

function ExcelUpload({ convUid, chatMode, onComplete, ...props }: PropsWithChildren<Props & UploadProps>) {
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
const [messageApi, contextHolder] = message.useMessage();
const [fileList, setFileList] = useState<UploadFile[]>([]);
Expand Down Expand Up @@ -86,7 +88,7 @@ function ExcelUpload({ convUid, chatMode, onComplete, ...props }: PropsWithChild
{...props}
>
<Button className="flex justify-center items-center" type="primary" disabled={loading} icon={<SelectOutlined />}>
Select File
{t('Select_File')}
</Button>
</Upload>
</Tooltip>
Expand Down
13 changes: 11 additions & 2 deletions components/chat/mode-tab/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
/*
* @Date: 2024-05-14 15:41:13
* @LastEditors: CZH
* @LastEditTime: 2024-05-22 18:09:12
* @FilePath: /DB-GPT-Web/components/chat/mode-tab/index.tsx
*/
import './index.css';
import { useContext } from 'react';
import { ChatContext } from '@/app/chat-context';
import { Radio } from 'antd';
import Icon, { AppstoreFilled } from '@ant-design/icons';
import { StarsSvg } from '@/components/icons';
import { useTranslation } from 'react-i18next';

export default function ModeTab() {
const { t } = useTranslation();

const { isContract, setIsContract, scene } = useContext(ChatContext);
const isShow = scene && ['chat_with_db_execute', 'chat_dashboard'].includes(scene as string);

Expand All @@ -24,11 +33,11 @@ export default function ModeTab() {
>
<Radio.Button value={false}>
<Icon component={StarsSvg} className="mr-1" />
Preview
{t('Preview')}
</Radio.Button>
<Radio.Button value={true}>
<AppstoreFilled className="mr-1" />
Editor
{t('Editor')}
</Radio.Button>
</Radio.Group>
);
Expand Down
48 changes: 41 additions & 7 deletions components/chat/monaco-editor.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,72 @@
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js';
import Editor, { OnChange, loader } from '@monaco-editor/react';
import classNames from 'classnames';
import { useMemo } from 'react';
import { format } from 'sql-formatter';
import { useContext, useMemo } from 'react';
import { formatSql } from '@/utils';
import { getModelService } from './ob-editor/service';
import { useLatest } from 'ahooks';
import { ChatContext } from '@/app/chat-context';
import { github, githubDark } from './ob-editor/theme';
import { register } from './ob-editor/ob-plugin';

loader.config({ monaco });

export interface ISession {
getTableList: (schemaName?: string) => Promise<string[]>;
getTableColumns: (tableName: string) => Promise<{ columnName: string; columnType: string }[]>;
getSchemaList: () => Promise<string[]>;
}

interface MonacoEditorProps {
className?: string;
value: string;
language: string;
onChange?: OnChange;
thoughts?: string;
session?: ISession;

}

export default function MonacoEditor({ className, value, language = 'mysql', onChange, thoughts }: MonacoEditorProps) {
let plugin = null;
monaco.editor.defineTheme('github', github as any);
monaco.editor.defineTheme('githubDark', githubDark as any);

export default function MonacoEditor({ className, value, language = 'mysql', onChange, thoughts, session }: MonacoEditorProps) {
// merge value and thoughts
const editorValue = useMemo(() => {
if (language !== 'mysql') {
return value;
}
if (thoughts && thoughts.length > 0) {
return format(`-- ${thoughts} \n${value}`);
return formatSql(`-- ${thoughts} \n${value}`);
}
return format(value);
return formatSql(value);
}, [value, thoughts]);

const sessionRef = useLatest(session);

const context = useContext(ChatContext);

async function pluginRegister(editor: monaco.editor.IStandaloneCodeEditor) {
const plugin = await register()
plugin.setModelOptions(
editor.getModel()?.id || '',
getModelService({
modelId: editor.getModel()?.id || '',
delimiter: ';',
}, () => sessionRef.current || null)
)
}


return (
<Editor
className={classNames(className)}
onMount={pluginRegister}
value={editorValue}
language={language}
defaultLanguage={language}
onChange={onChange}
theme="vs-dark"
theme={context?.mode !== "dark" ? "github" : "githubDark"}
options={{
minimap: {
enabled: false,
Expand Down
31 changes: 31 additions & 0 deletions components/chat/ob-editor/ob-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

import type Plugin from '@oceanbase-odc/monaco-plugin-ob';

let plugin: Plugin;

export async function register(): Promise<Plugin> {
window.obMonaco = {
getWorkerUrl: (type: string) => {
switch (type) {
case 'mysql': {
return location.origin + '/_next/static/ob-workers/mysql.js'
}
case 'obmysql': {
return location.origin + '/_next/static/ob-workers/obmysql.js'
}
case 'oboracle': {
return location.origin + '/_next/static/ob-workers/oracle.js'
}
}
return "";
}
}
const module = await import('@oceanbase-odc/monaco-plugin-ob')
const Plugin = module.default;
if (plugin) {
return plugin;
}
plugin = new Plugin();
plugin.setup(["mysql"]);
return plugin;
}
Loading