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:
devin-ai-integration[bot]
2025-05-13 22:39:19 +08:00
committed by GitHub
parent 91cd8cf380
commit 2bf94539bd
25 changed files with 898 additions and 233 deletions

View File

@@ -0,0 +1,20 @@
'use client';
import { ReactNode } from 'react';
import '@/i18n';
import { I18nText } from '@/app/infra/entities/api';
interface I18nProviderProps {
children: ReactNode;
}
export default function I18nProvider({ children }: I18nProviderProps) {
return <>{children}</>;
}
export function i18nObj(i18nText: I18nText): string {
const language = localStorage.getItem('langbot_language');
if ((language === 'zh-Hans' && i18nText.zh_CN) || !i18nText.en_US) {
return i18nText.zh_CN;
}
return i18nText.en_US;
}

34
web/src/i18n/index.ts Normal file
View File

@@ -0,0 +1,34 @@
'use client';
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import enUS from './locales/en-US';
import zhHans from './locales/zh-Hans';
i18n
.use(LanguageDetector)
.use(initReactI18next)
.init({
resources: {
'en-US': {
translation: enUS,
},
'zh-Hans': {
translation: zhHans,
},
},
fallbackLng: 'zh-Hans',
debug: process.env.NODE_ENV === 'development',
interpolation: {
escapeValue: false, // React already escapes values
},
detection: {
order: ['localStorage', 'navigator'],
lookupLocalStorage: 'langbot_language',
caches: ['localStorage'],
},
});
export default i18n;

View File

@@ -0,0 +1,174 @@
const enUS = {
common: {
login: 'Login',
logout: 'Logout',
email: 'Email',
password: 'Password',
welcome: 'Welcome back to LangBot 👋',
continueToLogin: 'Login to continue',
loginSuccess: 'Login successful',
loginFailed: 'Login failed, please check your email and password',
enterEmail: 'Enter email address',
enterPassword: 'Enter password',
invalidEmail: 'Please enter a valid email address',
emptyPassword: 'Please enter your password',
language: 'Language',
helpDocs: 'Get Help',
create: 'Create',
edit: 'Edit',
delete: 'Delete',
add: 'Add',
select: 'Select',
cancel: 'Cancel',
submit: 'Submit',
error: 'Error',
success: 'Success',
save: 'Save',
saving: 'Saving...',
confirm: 'Confirm',
confirmDelete: 'Confirm Delete',
deleteConfirmation: 'Are you sure you want to delete this?',
selectOption: 'Select an option',
required: 'Required',
enable: 'Enable',
name: 'Name',
description: 'Description',
close: 'Close',
deleteSuccess: 'Deleted successfully',
deleteError: 'Delete failed: ',
addRound: 'Add Round',
},
models: {
title: 'Models',
description: 'Configure and manage models that can be used in pipelines',
createModel: 'Create Model',
editModel: 'Edit Model',
getModelListError: 'Failed to get model list: ',
modelName: 'Model Name',
modelProvider: 'Model Provider',
modelBaseURL: 'Base URL',
modelAbilities: 'Model Abilities',
saveSuccess: 'Saved successfully',
saveError: 'Save failed: ',
createSuccess: 'Created successfully',
createError: 'Creation failed: ',
deleteSuccess: 'Deleted successfully',
deleteError: 'Delete failed: ',
deleteConfirmation: 'Are you sure you want to delete this model?',
modelNameRequired: 'Model name cannot be empty',
modelProviderRequired: 'Model provider cannot be empty',
requestURLRequired: 'Request URL cannot be empty',
apiKeyRequired: 'API Key cannot be empty',
keyNameRequired: 'Key name cannot be empty',
mustBeValidNumber: 'Must be a valid number',
mustBeTrueOrFalse: 'Must be true or false',
requestURL: 'Request URL',
apiKey: 'API Key',
abilities: 'Abilities',
selectModelAbilities: 'Select model abilities',
visionAbility: 'Vision Ability',
functionCallAbility: 'Function Call',
extraParameters: 'Extra Parameters',
addParameter: 'Add Parameter',
keyName: 'Key Name',
type: 'Type',
value: 'Value',
string: 'String',
number: 'Number',
boolean: 'Boolean',
extraParametersDescription:
'Will be attached to the request body, such as max_tokens, temperature, top_p, etc.',
selectModelProvider: 'Select Model Provider',
modelProviderDescription:
'Please fill in the model name provided by the supplier',
selectModel: 'Select Model',
},
bots: {
title: 'Bots',
description:
'Create and manage bots, which are the entry points for LangBot to connect with various platforms',
createBot: 'Create Bot',
editBot: 'Edit Bot',
getBotListError: 'Failed to get bot list: ',
botName: 'Bot Name',
botDescription: 'Bot Description',
botNameRequired: 'Bot name cannot be empty',
botDescriptionRequired: 'Bot description cannot be empty',
adapterRequired: 'Adapter cannot be empty',
defaultDescription: 'A bot',
getBotConfigError: 'Failed to get bot configuration: ',
saveSuccess: 'Saved successfully',
saveError: 'Save failed: ',
createSuccess:
'Created successfully. Please enable or modify the bound pipeline',
createError: 'Creation failed: ',
deleteSuccess: 'Deleted successfully',
deleteError: 'Delete failed: ',
deleteConfirmation: 'Are you sure you want to delete this bot?',
platformAdapter: 'Platform/Adapter Selection',
selectAdapter: 'Select Adapter',
adapterConfig: 'Adapter Configuration',
bindPipeline: 'Bind Pipeline',
selectPipeline: 'Select Pipeline',
},
plugins: {
title: 'Plugins',
description:
'Install and configure plugins to extend LangBot functionality',
createPlugin: 'Create Plugin',
editPlugin: 'Edit Plugin',
installed: 'Installed',
marketplace: 'Marketplace',
arrange: 'Sort Plugins',
install: 'Install',
installFromGithub: 'Install Plugin from GitHub',
onlySupportGithub: 'Currently only supports installation from GitHub',
enterGithubLink: 'Enter GitHub link of the plugin',
installing: 'Installing plugin...',
installSuccess: 'Plugin installed successfully',
installFailed: 'Plugin installation failed:',
searchPlugin: 'Search plugins',
sortBy: 'Sort by',
mostStars: 'Most stars',
recentlyAdded: 'Recently added',
recentlyUpdated: 'Recently updated',
noMatchingPlugins: 'No matching plugins found',
loading: 'Loading...',
getPluginListError: 'Failed to get plugin list:',
noPluginInstalled: 'No plugins installed',
pluginConfig: 'Plugin Configuration',
pluginSort: 'Plugin Sort',
pluginSortDescription:
'Plugin order affects the processing order within the same event, please drag the plugin card to sort',
pluginSortSuccess: 'Plugin sort successful',
pluginSortError: 'Plugin sort failed: ',
},
pipelines: {
title: 'Pipelines',
description:
'Pipelines define the processing flow for message events, used to bind to bots',
createPipeline: 'Create Pipeline',
editPipeline: 'Edit Pipeline',
getPipelineListError: 'Failed to get pipeline list: ',
daysAgo: 'days ago',
today: 'Today',
updateTime: 'Updated ',
defaultBadge: 'Default',
basicInfo: 'Basic',
aiCapabilities: 'AI',
triggerConditions: 'Trigger',
safetyControls: 'Safety',
outputProcessing: 'Output',
nameRequired: 'Name cannot be empty',
descriptionRequired: 'Description cannot be empty',
createSuccess: 'Created successfully. Please edit pipeline parameters',
createError: 'Creation failed: ',
saveSuccess: 'Saved successfully',
saveError: 'Save failed: ',
deleteConfirmation:
'Are you sure you want to delete this pipeline? Bots bound to this pipeline will not work.',
defaultPipelineCannotDelete: 'Default pipeline cannot be deleted',
},
};
export default enUS;

View File

@@ -0,0 +1,169 @@
const zhHans = {
common: {
login: '登录',
logout: '退出登录',
email: '邮箱',
password: '密码',
welcome: '欢迎回到 LangBot 👋',
continueToLogin: '登录以继续',
loginSuccess: '登录成功',
loginFailed: '登录失败,请检查邮箱和密码是否正确',
enterEmail: '输入邮箱地址',
enterPassword: '输入密码',
invalidEmail: '请输入有效的邮箱地址',
emptyPassword: '请输入密码',
language: '语言',
helpDocs: '帮助文档',
create: '创建',
edit: '编辑',
delete: '删除',
add: '添加',
select: '请选择',
cancel: '取消',
submit: '提交',
error: '错误',
success: '成功',
save: '保存',
saving: '保存中...',
confirm: '确认',
confirmDelete: '删除确认',
deleteConfirmation: '你确定要删除这个吗?',
selectOption: '选择一个选项',
required: '必填',
enable: '是否启用',
name: '名称',
description: '描述',
close: '关闭',
deleteSuccess: '删除成功',
deleteError: '删除失败:',
addRound: '添加回合',
},
models: {
title: '模型配置',
description: '配置和管理可在流水线中使用的模型',
createModel: '创建模型',
editModel: '编辑模型',
getModelListError: '获取模型列表失败:',
modelName: '模型名称',
modelProvider: '模型提供商',
modelBaseURL: '基础 URL',
modelAbilities: '模型能力',
saveSuccess: '保存成功',
saveError: '保存失败:',
createSuccess: '创建成功',
createError: '创建失败:',
deleteSuccess: '删除成功',
deleteError: '删除失败:',
deleteConfirmation: '你确定要删除这个模型吗?',
modelNameRequired: '模型名称不能为空',
modelProviderRequired: '模型供应商不能为空',
requestURLRequired: '请求URL不能为空',
apiKeyRequired: 'API Key不能为空',
keyNameRequired: '键名不能为空',
mustBeValidNumber: '必须是有效的数字',
mustBeTrueOrFalse: '必须是 true 或 false',
requestURL: '请求URL',
apiKey: 'API Key',
abilities: '能力',
selectModelAbilities: '选择模型能力',
visionAbility: '视觉能力',
functionCallAbility: '函数调用',
extraParameters: '额外参数',
addParameter: '添加参数',
keyName: '键名',
type: '类型',
value: '值',
string: '字符串',
number: '数字',
boolean: '布尔值',
extraParametersDescription:
'将在请求时附加到请求体中,如 max_tokens, temperature, top_p 等',
selectModelProvider: '选择模型供应商',
modelProviderDescription: '请填写供应商向您提供的模型名称',
selectModel: '请选择模型',
},
bots: {
title: '机器人',
description: '创建和管理机器人,这是 LangBot 与各个平台连接的入口',
createBot: '创建机器人',
editBot: '编辑机器人',
getBotListError: '获取机器人列表失败:',
botName: '机器人名称',
botDescription: '机器人描述',
botNameRequired: '机器人名称不能为空',
botDescriptionRequired: '机器人描述不能为空',
adapterRequired: '适配器不能为空',
defaultDescription: '一个机器人',
getBotConfigError: '获取机器人配置失败:',
saveSuccess: '保存成功',
saveError: '保存失败:',
createSuccess: '创建成功 请启用或修改绑定流水线',
createError: '创建失败:',
deleteSuccess: '删除成功',
deleteError: '删除失败:',
deleteConfirmation: '你确定要删除这个机器人吗?',
platformAdapter: '平台/适配器选择',
selectAdapter: '选择适配器',
adapterConfig: '适配器配置',
bindPipeline: '绑定流水线',
selectPipeline: '选择流水线',
},
plugins: {
title: '插件管理',
description: '安装和配置用于扩展 LangBot 功能的插件',
createPlugin: '创建插件',
editPlugin: '编辑插件',
installed: '已安装',
marketplace: '插件市场',
arrange: '编排',
install: '安装',
installFromGithub: '从 GitHub 安装插件',
onlySupportGithub: '目前仅支持从 GitHub 安装',
enterGithubLink: '请输入插件的Github链接',
installing: '正在安装插件...',
installSuccess: '插件安装成功',
installFailed: '插件安装失败:',
searchPlugin: '搜索插件',
sortBy: '排序方式',
mostStars: '最多星标',
recentlyAdded: '最近新增',
recentlyUpdated: '最近更新',
noMatchingPlugins: '没有找到匹配的插件',
loading: '加载中...',
getPluginListError: '获取插件列表失败:',
pluginConfig: '插件配置',
noPluginInstalled: '暂未安装任何插件',
pluginSort: '插件排序',
pluginSortDescription:
'插件顺序会影响同一事件内的处理顺序,请拖动插件卡片排序',
pluginSortSuccess: '插件排序成功',
pluginSortError: '插件排序失败:',
},
pipelines: {
title: '流水线',
description: '流水线定义了对消息事件的处理流程,用于绑定到机器人',
createPipeline: '创建流水线',
editPipeline: '编辑流水线',
getPipelineListError: '获取流水线列表失败:',
daysAgo: '天前',
today: '今天',
updateTime: '更新于',
defaultBadge: '默认',
basicInfo: '基础信息',
aiCapabilities: 'AI 能力',
triggerConditions: '触发条件',
safetyControls: '安全控制',
outputProcessing: '输出处理',
nameRequired: '名称不能为空',
descriptionRequired: '描述不能为空',
createSuccess: '创建成功 请编辑流水线详细参数',
createError: '创建失败:',
saveSuccess: '保存成功',
saveError: '保存失败:',
deleteConfirmation:
'你确定要删除这个流水线吗?已绑定此流水线的机器人将无法使用。',
defaultPipelineCannotDelete: '默认流水线不可删除',
},
};
export default zhHans;