mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-12 16:56:02 +00:00
Add i18n support with language selector on login page (#1410)
* feat: add i18n support with language selector on login page Co-Authored-By: Junyan Qin <Chin> <rockchinq@gmail.com> * feat: complete i18n implementation for all webui components Co-Authored-By: Junyan Qin <Chin> <rockchinq@gmail.com> * feat: complete all hardcoded text * feat: dynamic label i18n * fix: lint errors * fix: lint errors * delete sh fils * fix: edit model dialog title --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Junyan Qin <Chin> <rockchinq@gmail.com>
This commit is contained in:
committed by
GitHub
parent
91cd8cf380
commit
2bf94539bd
@@ -12,6 +12,7 @@ import {
|
||||
} from '@/components/ui/form';
|
||||
import DynamicFormItemComponent from '@/app/home/components/dynamic-form/DynamicFormItemComponent';
|
||||
import { useEffect } from 'react';
|
||||
import { i18nObj } from '@/i18n/I18nProvider';
|
||||
|
||||
export default function DynamicFormComponent({
|
||||
itemConfigList,
|
||||
@@ -141,7 +142,7 @@ export default function DynamicFormComponent({
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{config.label.zh_CN}{' '}
|
||||
{i18nObj(config.label)}{' '}
|
||||
{config.required && <span className="text-red-500">*</span>}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
@@ -149,7 +150,7 @@ export default function DynamicFormComponent({
|
||||
</FormControl>
|
||||
{config.description && (
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{config.description.zh_CN}
|
||||
{i18nObj(config.description)}
|
||||
</p>
|
||||
)}
|
||||
<FormMessage />
|
||||
|
||||
@@ -23,6 +23,8 @@ import {
|
||||
HoverCardContent,
|
||||
HoverCardTrigger,
|
||||
} from '@/components/ui/hover-card';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { i18nObj } from '@/i18n/I18nProvider';
|
||||
|
||||
export default function DynamicFormItemComponent({
|
||||
config,
|
||||
@@ -33,6 +35,7 @@ export default function DynamicFormItemComponent({
|
||||
field: ControllerRenderProps<any, any>;
|
||||
}) {
|
||||
const [llmModels, setLlmModels] = useState<LLMModel[]>([]);
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
if (config.type === DynamicFormItemType.LLM_MODEL_SELECTOR) {
|
||||
@@ -106,7 +109,7 @@ export default function DynamicFormItemComponent({
|
||||
field.onChange([...field.value, '']);
|
||||
}}
|
||||
>
|
||||
添加
|
||||
{t('common.add')}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
@@ -115,13 +118,13 @@ export default function DynamicFormItemComponent({
|
||||
return (
|
||||
<Select value={field.value} onValueChange={field.onChange}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="请选择" />
|
||||
<SelectValue placeholder={t('common.select')} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{config.options?.map((option) => (
|
||||
<SelectItem key={option.name} value={option.name}>
|
||||
{option.label.zh_CN}
|
||||
{i18nObj(option.label)}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
@@ -133,7 +136,7 @@ export default function DynamicFormItemComponent({
|
||||
return (
|
||||
<Select value={field.value} onValueChange={field.onChange}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="请选择模型" />
|
||||
<SelectValue placeholder={t('models.selectModel')} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
@@ -205,9 +208,9 @@ export default function DynamicFormItemComponent({
|
||||
)}
|
||||
<span>
|
||||
{ability === 'vision'
|
||||
? '视觉能力'
|
||||
? t('models.visionAbility')
|
||||
: ability === 'func_call'
|
||||
? '函数调用'
|
||||
? t('models.functionCallAbility')
|
||||
: ability}
|
||||
</span>
|
||||
</div>
|
||||
@@ -217,7 +220,9 @@ export default function DynamicFormItemComponent({
|
||||
{model.extra_args &&
|
||||
Object.keys(model.extra_args).length > 0 && (
|
||||
<div className="text-xs">
|
||||
<div className="font-semibold mb-1">额外参数:</div>
|
||||
<div className="font-semibold mb-1">
|
||||
{t('models.extraParameters')}
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
{Object.entries(
|
||||
model.extra_args as Record<string, unknown>,
|
||||
@@ -321,7 +326,7 @@ export default function DynamicFormItemComponent({
|
||||
field.onChange([...field.value, { role: 'user', content: '' }]);
|
||||
}}
|
||||
>
|
||||
添加回合
|
||||
{t('common.addRound')}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useRouter, usePathname } from 'next/navigation';
|
||||
import { sidebarConfigList } from '@/app/home/components/home-sidebar/sidbarConfigList';
|
||||
import langbotIcon from '@/app/assets/langbot-logo.webp';
|
||||
import { httpClient } from '@/app/infra/http/HttpClient';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
// TODO 侧边导航栏要加动画
|
||||
export default function HomeSidebar({
|
||||
@@ -27,14 +28,15 @@ export default function HomeSidebar({
|
||||
|
||||
const [selectedChild, setSelectedChild] = useState<SidebarChildVO>();
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
console.log('HomeSidebar挂载完成');
|
||||
initSelect();
|
||||
if (!localStorage.getItem('token')) {
|
||||
localStorage.setItem('token', 'test-token');
|
||||
localStorage.setItem('userEmail', 'test@example.com');
|
||||
}
|
||||
return () => console.log('HomeSidebar卸载');
|
||||
return () => console.log('sidebar.unmounted');
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
@@ -148,7 +150,7 @@ export default function HomeSidebar({
|
||||
<path d="M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM11 15H13V17H11V15ZM13 13.3551V14H11V12.5C11 11.9477 11.4477 11.5 12 11.5C12.8284 11.5 13.5 10.8284 13.5 10C13.5 9.17157 12.8284 8.5 12 8.5C11.2723 8.5 10.6656 9.01823 10.5288 9.70577L8.56731 9.31346C8.88637 7.70919 10.302 6.5 12 6.5C13.933 6.5 15.5 8.067 15.5 10C15.5 11.5855 14.4457 12.9248 13 13.3551Z"></path>
|
||||
</svg>
|
||||
}
|
||||
name="帮助文档"
|
||||
name={t('common.helpDocs')}
|
||||
/>
|
||||
<SidebarChild
|
||||
onClick={() => {
|
||||
@@ -164,7 +166,7 @@ export default function HomeSidebar({
|
||||
<path d="M4 18H6V20H18V4H6V6H4V3C4 2.44772 4.44772 2 5 2H19C19.5523 2 20 2.44772 20 3V21C20 21.5523 19.5523 22 19 22H5C4.44772 22 4 21.5523 4 21V18ZM6 11H13V13H6V16L1 12L6 8V11Z"></path>
|
||||
</svg>
|
||||
}
|
||||
name="退出登录"
|
||||
name={t('common.logout')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
import { SidebarChildVO } from '@/app/home/components/home-sidebar/HomeSidebarChild';
|
||||
import styles from './HomeSidebar.module.css';
|
||||
import i18n from '@/i18n';
|
||||
|
||||
const t = (key: string) => {
|
||||
return i18n.t(key);
|
||||
};
|
||||
|
||||
export const sidebarConfigList = [
|
||||
new SidebarChildVO({
|
||||
id: 'bots',
|
||||
name: '机器人',
|
||||
name: t('bots.title'),
|
||||
icon: (
|
||||
<svg
|
||||
className={`${styles.sidebarChildIcon}`}
|
||||
@@ -16,12 +21,12 @@ export const sidebarConfigList = [
|
||||
</svg>
|
||||
),
|
||||
route: '/home/bots',
|
||||
description: '创建和管理机器人,这是 LangBot 与各个平台连接的入口',
|
||||
description: t('bots.description'),
|
||||
helpLink: 'https://docs.langbot.app/zh/deploy/platforms/readme.html',
|
||||
}),
|
||||
new SidebarChildVO({
|
||||
id: 'models',
|
||||
name: '模型配置',
|
||||
name: t('models.title'),
|
||||
icon: (
|
||||
<svg
|
||||
className={`${styles.sidebarChildIcon}`}
|
||||
@@ -33,12 +38,12 @@ export const sidebarConfigList = [
|
||||
</svg>
|
||||
),
|
||||
route: '/home/models',
|
||||
description: '配置和管理可在流水线中使用的模型',
|
||||
description: t('models.description'),
|
||||
helpLink: 'https://docs.langbot.app/zh/deploy/models/readme.html',
|
||||
}),
|
||||
new SidebarChildVO({
|
||||
id: 'pipelines',
|
||||
name: '流水线',
|
||||
name: t('pipelines.title'),
|
||||
icon: (
|
||||
<svg
|
||||
className={`${styles.sidebarChildIcon}`}
|
||||
@@ -50,12 +55,12 @@ export const sidebarConfigList = [
|
||||
</svg>
|
||||
),
|
||||
route: '/home/pipelines',
|
||||
description: '流水线定义了对消息事件的处理流程,用于绑定到机器人',
|
||||
description: t('pipelines.description'),
|
||||
helpLink: 'https://docs.langbot.app/zh/deploy/pipelines/readme.html',
|
||||
}),
|
||||
new SidebarChildVO({
|
||||
id: 'plugins',
|
||||
name: '插件管理',
|
||||
name: t('plugins.title'),
|
||||
icon: (
|
||||
<svg
|
||||
className={`${styles.sidebarChildIcon}`}
|
||||
@@ -67,7 +72,7 @@ export const sidebarConfigList = [
|
||||
</svg>
|
||||
),
|
||||
route: '/home/plugins',
|
||||
description: '安装和配置用于扩展 LangBot 功能的插件',
|
||||
description: t('plugins.description'),
|
||||
helpLink: 'https://docs.langbot.app/zh/plugin/plugin-intro.html',
|
||||
}),
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user