mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-27 07:54:19 +00:00
feat: add i18n support for initialization page and fix plugin loading text
- Add language selector to register/initialization page with Chinese and English options
- Add register section translations to both zh-Hans.ts and en-US.ts
- Replace hardcoded Chinese texts in register page with i18n translation calls
- Fix hardcoded '加载中...' text in plugin configuration dialog to use t('plugins.loading')
- Follow existing login page pattern for language selector implementation
- Maintain consistent UI/UX design with proper language switching functionality
Co-Authored-By: Junyan Qin <Chin>, 秦骏言 in Chinese, you can call me my english name Rock Chin. <rockchinq@gmail.com>
This commit is contained in:
@@ -72,7 +72,7 @@ export default function PluginForm({
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!pluginInfo || !pluginConfig) {
|
if (!pluginInfo || !pluginConfig) {
|
||||||
return <div>加载中...</div>;
|
return <div>{t('plugins.loading')}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function deletePlugin() {
|
function deletePlugin() {
|
||||||
|
|||||||
@@ -8,6 +8,13 @@ import {
|
|||||||
CardTitle,
|
CardTitle,
|
||||||
CardDescription,
|
CardDescription,
|
||||||
} from '@/components/ui/card';
|
} from '@/components/ui/card';
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from '@/components/ui/select';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import * as z from 'zod';
|
import * as z from 'zod';
|
||||||
@@ -19,23 +26,28 @@ import {
|
|||||||
FormLabel,
|
FormLabel,
|
||||||
FormMessage,
|
FormMessage,
|
||||||
} from '@/components/ui/form';
|
} from '@/components/ui/form';
|
||||||
import { useEffect } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { httpClient } from '@/app/infra/http/HttpClient';
|
import { httpClient } from '@/app/infra/http/HttpClient';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { Mail, Lock } from 'lucide-react';
|
import { Mail, Lock, Globe } from 'lucide-react';
|
||||||
import langbotIcon from '@/app/assets/langbot-logo.webp';
|
import langbotIcon from '@/app/assets/langbot-logo.webp';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import i18n from '@/i18n';
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = (t: (key: string) => string) =>
|
||||||
email: z.string().email('请输入有效的邮箱地址'),
|
z.object({
|
||||||
password: z.string().min(1, '请输入密码'),
|
email: z.string().email(t('common.invalidEmail')),
|
||||||
});
|
password: z.string().min(1, t('common.emptyPassword')),
|
||||||
|
});
|
||||||
|
|
||||||
export default function Register() {
|
export default function Register() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [currentLanguage, setCurrentLanguage] = useState<string>(i18n.language);
|
||||||
|
|
||||||
const form = useForm<z.infer<typeof formSchema>>({
|
const form = useForm<z.infer<ReturnType<typeof formSchema>>>({
|
||||||
resolver: zodResolver(formSchema),
|
resolver: zodResolver(formSchema(t)),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
email: '',
|
email: '',
|
||||||
password: '',
|
password: '',
|
||||||
@@ -43,9 +55,31 @@ export default function Register() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
judgeLanguage();
|
||||||
getIsInitialized();
|
getIsInitialized();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const judgeLanguage = () => {
|
||||||
|
const language = navigator.language;
|
||||||
|
if (language) {
|
||||||
|
let lang = 'zh-Hans';
|
||||||
|
if (language === 'zh-CN') {
|
||||||
|
lang = 'zh-Hans';
|
||||||
|
} else {
|
||||||
|
lang = 'en-US';
|
||||||
|
}
|
||||||
|
i18n.changeLanguage(lang);
|
||||||
|
setCurrentLanguage(lang);
|
||||||
|
localStorage.setItem('langbot_language', lang);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLanguageChange = (value: string) => {
|
||||||
|
i18n.changeLanguage(value);
|
||||||
|
setCurrentLanguage(value);
|
||||||
|
localStorage.setItem('langbot_language', value);
|
||||||
|
};
|
||||||
|
|
||||||
function getIsInitialized() {
|
function getIsInitialized() {
|
||||||
httpClient
|
httpClient
|
||||||
.checkIfInited()
|
.checkIfInited()
|
||||||
@@ -59,7 +93,7 @@ export default function Register() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSubmit(values: z.infer<typeof formSchema>) {
|
function onSubmit(values: z.infer<ReturnType<typeof formSchema>>) {
|
||||||
handleRegister(values.email, values.password);
|
handleRegister(values.email, values.password);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,31 +102,46 @@ export default function Register() {
|
|||||||
.initUser(username, password)
|
.initUser(username, password)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
console.log('init user success: ', res);
|
console.log('init user success: ', res);
|
||||||
toast.success('初始化成功 请登录');
|
toast.success(t('register.initSuccess'));
|
||||||
router.push('/login');
|
router.push('/login');
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log('init user error: ', err);
|
console.log('init user error: ', err);
|
||||||
toast.error('初始化失败:' + err.message);
|
toast.error(t('register.initFailed') + err.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen flex items-center justify-center bg-gray-50">
|
<div className="min-h-screen flex items-center justify-center bg-gray-50">
|
||||||
<Card className="w-[360px]">
|
<Card className="w-[375px]">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
<div className="flex justify-end mb-6">
|
||||||
|
<Select
|
||||||
|
value={currentLanguage}
|
||||||
|
onValueChange={handleLanguageChange}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-[140px]">
|
||||||
|
<Globe className="h-4 w-4 mr-2" />
|
||||||
|
<SelectValue placeholder={t('common.language')} />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="zh-Hans">简体中文</SelectItem>
|
||||||
|
<SelectItem value="en-US">English</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
<img
|
<img
|
||||||
src={langbotIcon.src}
|
src={langbotIcon.src}
|
||||||
alt="LangBot"
|
alt="LangBot"
|
||||||
className="w-16 h-16 mb-4 mx-auto"
|
className="w-16 h-16 mb-4 mx-auto"
|
||||||
/>
|
/>
|
||||||
<CardTitle className="text-2xl text-center">
|
<CardTitle className="text-2xl text-center">
|
||||||
初始化 LangBot 👋
|
{t('register.title')}
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<CardDescription className="text-center">
|
<CardDescription className="text-center">
|
||||||
这是您首次启动 LangBot
|
{t('register.description')}
|
||||||
<br />
|
<br />
|
||||||
您填写的邮箱和密码将作为初始管理员账号
|
{t('register.adminAccountNote')}
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
@@ -103,12 +152,12 @@ export default function Register() {
|
|||||||
name="email"
|
name="email"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>邮箱</FormLabel>
|
<FormLabel>{t('common.email')}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Mail className="absolute left-3 top-3 h-4 w-4 text-gray-400" />
|
<Mail className="absolute left-3 top-3 h-4 w-4 text-gray-400" />
|
||||||
<Input
|
<Input
|
||||||
placeholder="输入邮箱地址"
|
placeholder={t('common.enterEmail')}
|
||||||
className="pl-10"
|
className="pl-10"
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
@@ -124,13 +173,13 @@ export default function Register() {
|
|||||||
name="password"
|
name="password"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>密码</FormLabel>
|
<FormLabel>{t('common.password')}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Lock className="absolute left-3 top-3 h-4 w-4 text-gray-400" />
|
<Lock className="absolute left-3 top-3 h-4 w-4 text-gray-400" />
|
||||||
<Input
|
<Input
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="输入密码"
|
placeholder={t('common.enterPassword')}
|
||||||
className="pl-10"
|
className="pl-10"
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
@@ -142,7 +191,7 @@ export default function Register() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Button type="submit" className="w-full mt-4 cursor-pointer">
|
<Button type="submit" className="w-full mt-4 cursor-pointer">
|
||||||
注册
|
{t('register.register')}
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@@ -203,6 +203,15 @@ const enUS = {
|
|||||||
'Are you sure you want to delete this pipeline? Bots bound to this pipeline will not work.',
|
'Are you sure you want to delete this pipeline? Bots bound to this pipeline will not work.',
|
||||||
defaultPipelineCannotDelete: 'Default pipeline cannot be deleted',
|
defaultPipelineCannotDelete: 'Default pipeline cannot be deleted',
|
||||||
},
|
},
|
||||||
|
register: {
|
||||||
|
title: 'Initialize LangBot 👋',
|
||||||
|
description: 'This is your first time starting LangBot',
|
||||||
|
adminAccountNote:
|
||||||
|
'The email and password you fill in will be used as the initial administrator account',
|
||||||
|
register: 'Register',
|
||||||
|
initSuccess: 'Initialization successful, please login',
|
||||||
|
initFailed: 'Initialization failed: ',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default enUS;
|
export default enUS;
|
||||||
|
|||||||
@@ -198,6 +198,14 @@ const zhHans = {
|
|||||||
'你确定要删除这个流水线吗?已绑定此流水线的机器人将无法使用。',
|
'你确定要删除这个流水线吗?已绑定此流水线的机器人将无法使用。',
|
||||||
defaultPipelineCannotDelete: '默认流水线不可删除',
|
defaultPipelineCannotDelete: '默认流水线不可删除',
|
||||||
},
|
},
|
||||||
|
register: {
|
||||||
|
title: '初始化 LangBot 👋',
|
||||||
|
description: '这是您首次启动 LangBot',
|
||||||
|
adminAccountNote: '您填写的邮箱和密码将作为初始管理员账号',
|
||||||
|
register: '注册',
|
||||||
|
initSuccess: '初始化成功 请登录',
|
||||||
|
initFailed: '初始化失败:',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default zhHans;
|
export default zhHans;
|
||||||
|
|||||||
Reference in New Issue
Block a user