Merge pull request #1991 from Sacode/i18n

feat: complete English, French and Russian translation and add i18n configuration
This commit is contained in:
Seefs
2025-10-11 15:56:55 +08:00
committed by GitHub
12 changed files with 8659 additions and 4709 deletions

95
web/i18next.config.js Normal file
View File

@@ -0,0 +1,95 @@
/*
Copyright (C) 2025 QuantumNous
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { defineConfig } from 'i18next-cli';
/** @type {import('i18next-cli').I18nextToolkitConfig} */
export default defineConfig({
locales: [
"zh",
"en",
"fr",
"ru"
],
extract: {
input: [
"src/**/*.{js,jsx,ts,tsx}"
],
ignore: [
"src/i18n/**/*"
],
output: "src/i18n/locales/{{language}}.json",
ignoredAttributes: [
"accept",
"align",
"aria-label",
"autoComplete",
"className",
"clipRule",
"color",
"crossOrigin",
"data-index",
"data-name",
"data-testid",
"data-type",
"defaultActiveKey",
"direction",
"editorType",
"field",
"fill",
"fillRule",
"height",
"hoverStyle",
"htmlType",
"id",
"itemKey",
"key",
"keyPrefix",
"layout",
"margin",
"maxHeight",
"mode",
"name",
"overflow",
"placement",
"position",
"rel",
"role",
"rowKey",
"searchPosition",
"selectedStyle",
"shape",
"size",
"style",
"theme",
"trigger",
"uploadTrigger",
"validateStatus",
"value",
"viewBox",
"width"
],
sort: true,
disablePlurals: false,
removeUnusedKeys: false,
nsSeparator: false,
keySeparator: false,
mergeNamespaces: true
}
});

View File

@@ -49,7 +49,11 @@
"lint:fix": "prettier . --write",
"eslint": "bunx eslint \"**/*.{js,jsx}\" --cache",
"eslint:fix": "bunx eslint \"**/*.{js,jsx}\" --fix --cache",
"preview": "vite preview"
"preview": "vite preview",
"i18n:extract": "bunx i18next-cli extract",
"i18n:status": "bunx i18next-cli status",
"i18n:sync": "bunx i18next-cli sync",
"i18n:lint": "bunx i18next-cli lint"
},
"eslintConfig": {
"extends": [
@@ -81,7 +85,8 @@
"prettier": "^3.0.0",
"tailwindcss": "^3",
"typescript": "4.4.2",
"vite": "^5.2.0"
"vite": "^5.2.0",
"i18next-cli": "^1.10.3"
},
"prettier": {
"singleQuote": true,

View File

@@ -20,7 +20,7 @@ For commercial licensing, please contact support@quantumnous.com
import React from 'react';
import { Button, Dropdown } from '@douyinfe/semi-ui';
import { Languages } from 'lucide-react';
import { CN, GB, FR } from 'country-flag-icons/react/3x2';
import { CN, GB, FR, RU } from 'country-flag-icons/react/3x2';
const LanguageSelector = ({ currentLang, onLanguageChange, t }) => {
return (
@@ -49,6 +49,13 @@ const LanguageSelector = ({ currentLang, onLanguageChange, t }) => {
<FR title='Français' className='!w-5 !h-auto' />
<span>Français</span>
</Dropdown.Item>
<Dropdown.Item
onClick={() => onLanguageChange('ru')}
className={`!flex !items-center !gap-2 !px-3 !py-1.5 !text-sm !text-semi-color-text-0 dark:!text-gray-200 ${currentLang === 'ru' ? '!bg-semi-color-primary-light-default dark:!bg-blue-600 !font-semibold' : 'hover:!bg-semi-color-fill-1 dark:hover:!bg-gray-600'}`}
>
<RU title='Русский' className='!w-5 !h-auto' />
<span>Русский</span>
</Dropdown.Item>
</Dropdown.Menu>
}
>

View File

@@ -24,6 +24,7 @@ import LanguageDetector from 'i18next-browser-languagedetector';
import enTranslation from './locales/en.json';
import frTranslation from './locales/fr.json';
import zhTranslation from './locales/zh.json';
import ruTranslation from './locales/ru.json';
i18n
.use(LanguageDetector)
@@ -31,15 +32,10 @@ i18n
.init({
load: 'languageOnly',
resources: {
en: {
translation: enTranslation,
},
zh: {
translation: zhTranslation,
},
fr: {
translation: frTranslation,
},
en: enTranslation,
zh: zhTranslation,
fr: frTranslation,
ru: ruTranslation,
},
fallbackLng: 'zh',
interpolation: {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2093
web/src/i18n/locales/ru.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -105,7 +105,7 @@ export default function SettingGlobalModel(props) {
})
}
extraText={
'开启后,所有请求将直接透传给上游,不会进行任何处理(重定向和渠道适配也将失效),请谨慎开启'
t('开启后,所有请求将直接透传给上游,不会进行任何处理(重定向和渠道适配也将失效),请谨慎开启')
}
/>
</Col>
@@ -116,7 +116,7 @@ export default function SettingGlobalModel(props) {
<Col span={24}>
<Banner
type='warning'
description='警告启用保活后如果已经写入保活数据后渠道出错系统无法重试如果必须开启推荐设置尽可能大的Ping间隔'
description={t('警告启用保活后如果已经写入保活数据后渠道出错系统无法重试如果必须开启推荐设置尽可能大的Ping间隔')}
/>
</Col>
</Row>
@@ -131,7 +131,7 @@ export default function SettingGlobalModel(props) {
'general_setting.ping_interval_enabled': value,
})
}
extraText={'开启后将定期发送ping数据保持连接活跃'}
extraText={t('开启后将定期发送ping数据保持连接活跃')}
/>
</Col>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>