mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-03-30 04:22:58 +00:00
Merge pull request #1991 from Sacode/i18n
feat: complete English, French and Russian translation and add i18n configuration
This commit is contained in:
95
web/i18next.config.js
Normal file
95
web/i18next.config.js
Normal 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
|
||||
}
|
||||
});
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -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
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
@@ -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}>
|
||||
|
||||
Reference in New Issue
Block a user