From ead43f081c48f713ababc301c9aaa127eeeb347b Mon Sep 17 00:00:00 2001 From: t0ng7u Date: Fri, 18 Jul 2025 10:55:05 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=89=20feat(i18n):=20integrate=20Semi?= =?UTF-8?q?=20UI=20LocaleProvider=20with=20dynamic=20i18next=20language=20?= =?UTF-8?q?support?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Semi UI internationalization to the project by wrapping the root component tree with `LocaleProvider`. A new `SemiLocaleWrapper` component maps the current `i18next` language code to the corresponding Semi locale (currently `zh_CN` and `en_GB`) and falls back to Chinese when no match is found. Key changes ----------- 1. web/src/index.js • Import `LocaleProvider`, `useTranslation`, and Semi locale files. • Introduce `SemiLocaleWrapper` to determine `semiLocale` from `i18next.language` using a concise prefix-based mapping. • Wrap `PageLayout` with `SemiLocaleWrapper` inside the existing `ThemeProvider`. 2. Ensures that all Semi components automatically display the correct language when the app language is switched via i18next. BREAKING CHANGE --------------- Applications embedding this project must now ensure that `i18next` initialization occurs before React render so that `LocaleProvider` receives the correct initial language. --- web/src/components/table/ChannelsTable.js | 5 ----- web/src/components/table/LogsTable.js | 6 ------ web/src/components/table/MjLogsTable.js | 6 ------ web/src/components/table/ModelPricing.js | 6 ------ web/src/components/table/RedemptionsTable.js | 6 ------ web/src/components/table/TaskLogsTable.js | 6 ------ web/src/components/table/TokensTable.js | 6 ------ web/src/components/table/UsersTable.js | 6 ------ web/src/i18n/i18n.js | 1 + web/src/i18n/locales/en.json | 1 - web/src/index.js | 21 +++++++++++++++++--- 11 files changed, 19 insertions(+), 51 deletions(-) diff --git a/web/src/components/table/ChannelsTable.js b/web/src/components/table/ChannelsTable.js index d49f23de..4bf94cb8 100644 --- a/web/src/components/table/ChannelsTable.js +++ b/web/src/components/table/ChannelsTable.js @@ -1917,11 +1917,6 @@ const ChannelsTable = () => { total: channelCount, pageSizeOpts: [10, 20, 50, 100], showSizeChanger: true, - formatPageText: (page) => t('第 {{start}} - {{end}} 条,共 {{total}} 条', { - start: page.currentStart, - end: page.currentEnd, - total: channelCount, - }), onPageSizeChange: (size) => { handlePageSizeChange(size); }, diff --git a/web/src/components/table/LogsTable.js b/web/src/components/table/LogsTable.js index a59b9128..e3116e41 100644 --- a/web/src/components/table/LogsTable.js +++ b/web/src/components/table/LogsTable.js @@ -1439,12 +1439,6 @@ const LogsTable = () => { /> } pagination={{ - formatPageText: (page) => - t('第 {{start}} - {{end}} 条,共 {{total}} 条', { - start: page.currentStart, - end: page.currentEnd, - total: logCount, - }), currentPage: activePage, pageSize: pageSize, total: logCount, diff --git a/web/src/components/table/MjLogsTable.js b/web/src/components/table/MjLogsTable.js index af7d1a1e..0efe5e25 100644 --- a/web/src/components/table/MjLogsTable.js +++ b/web/src/components/table/MjLogsTable.js @@ -942,12 +942,6 @@ const LogsTable = () => { /> } pagination={{ - formatPageText: (page) => - t('第 {{start}} - {{end}} 条,共 {{total}} 条', { - start: page.currentStart, - end: page.currentEnd, - total: logCount, - }), currentPage: activePage, pageSize: pageSize, total: logCount, diff --git a/web/src/components/table/ModelPricing.js b/web/src/components/table/ModelPricing.js index e3f68a76..7e8d3995 100644 --- a/web/src/components/table/ModelPricing.js +++ b/web/src/components/table/ModelPricing.js @@ -535,12 +535,6 @@ const ModelPricing = () => { pageSize: pageSize, showSizeChanger: true, pageSizeOptions: [10, 20, 50, 100], - formatPageText: (page) => - t('第 {{start}} - {{end}} 条,共 {{total}} 条', { - start: page.currentStart, - end: page.currentEnd, - total: filteredModels.length, - }), onPageSizeChange: (size) => setPageSize(size), }} /> diff --git a/web/src/components/table/RedemptionsTable.js b/web/src/components/table/RedemptionsTable.js index 6e096b84..108cde4b 100644 --- a/web/src/components/table/RedemptionsTable.js +++ b/web/src/components/table/RedemptionsTable.js @@ -589,12 +589,6 @@ const RedemptionsTable = () => { total: tokenCount, showSizeChanger: true, pageSizeOptions: [10, 20, 50, 100], - formatPageText: (page) => - t('第 {{start}} - {{end}} 条,共 {{total}} 条', { - start: page.currentStart, - end: page.currentEnd, - total: tokenCount, - }), onPageSizeChange: (size) => { setPageSize(size); setActivePage(1); diff --git a/web/src/components/table/TaskLogsTable.js b/web/src/components/table/TaskLogsTable.js index 86e63b35..dcfad292 100644 --- a/web/src/components/table/TaskLogsTable.js +++ b/web/src/components/table/TaskLogsTable.js @@ -778,12 +778,6 @@ const LogsTable = () => { /> } pagination={{ - formatPageText: (page) => - t('第 {{start}} - {{end}} 条,共 {{total}} 条', { - start: page.currentStart, - end: page.currentEnd, - total: logCount, - }), currentPage: activePage, pageSize: pageSize, total: logCount, diff --git a/web/src/components/table/TokensTable.js b/web/src/components/table/TokensTable.js index 09e180b1..4d5a346f 100644 --- a/web/src/components/table/TokensTable.js +++ b/web/src/components/table/TokensTable.js @@ -893,12 +893,6 @@ const TokensTable = () => { total: tokenCount, showSizeChanger: true, pageSizeOptions: [10, 20, 50, 100], - formatPageText: (page) => - t('第 {{start}} - {{end}} 条,共 {{total}} 条', { - start: page.currentStart, - end: page.currentEnd, - total: tokenCount, - }), onPageSizeChange: handlePageSizeChange, onPageChange: handlePageChange, }} diff --git a/web/src/components/table/UsersTable.js b/web/src/components/table/UsersTable.js index c85395f0..8cfc35b8 100644 --- a/web/src/components/table/UsersTable.js +++ b/web/src/components/table/UsersTable.js @@ -649,12 +649,6 @@ const UsersTable = () => { dataSource={users} scroll={compactMode ? undefined : { x: 'max-content' }} pagination={{ - formatPageText: (page) => - t('第 {{start}} - {{end}} 条,共 {{total}} 条', { - start: page.currentStart, - end: page.currentEnd, - total: userCount, - }), currentPage: activePage, pageSize: pageSize, total: userCount, diff --git a/web/src/i18n/i18n.js b/web/src/i18n/i18n.js index c1bf5860..c7d69868 100644 --- a/web/src/i18n/i18n.js +++ b/web/src/i18n/i18n.js @@ -9,6 +9,7 @@ i18n .use(LanguageDetector) .use(initReactI18next) .init({ + load: 'languageOnly', resources: { en: { translation: enTranslation, diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json index 1ff11e1f..cfddb57f 100644 --- a/web/src/i18n/locales/en.json +++ b/web/src/i18n/locales/en.json @@ -1189,7 +1189,6 @@ "令牌无法精确控制使用额度,只允许自用,请勿直接将令牌分发给他人。": "Tokens cannot accurately control usage, only for self-use, please do not distribute tokens directly to others.", "添加兑换码": "Add redemption code", "复制所选兑换码到剪贴板": "Copy selected redemption codes to clipboard", - "第 {{start}} - {{end}} 条,共 {{total}} 条": "Items {{start}} - {{end}} of {{total}}", "新建兑换码": "Code", "兑换码更新成功!": "Redemption code updated successfully!", "兑换码创建成功!": "Redemption code created successfully!", diff --git a/web/src/index.js b/web/src/index.js index 2a097023..77d129e6 100644 --- a/web/src/index.js +++ b/web/src/index.js @@ -9,15 +9,28 @@ import { ThemeProvider } from './context/Theme'; import PageLayout from './components/layout/PageLayout.js'; import './i18n/i18n.js'; import './index.css'; +import { LocaleProvider } from '@douyinfe/semi-ui'; +import { useTranslation } from 'react-i18next'; +import zh_CN from '@douyinfe/semi-ui/lib/es/locale/source/zh_CN'; +import en_GB from '@douyinfe/semi-ui/lib/es/locale/source/en_GB'; -// 欢迎信息(二次开发者不准将此移除) -// Welcome message (Secondary developers are not allowed to remove this) +// 欢迎信息(二次开发者未经允许不准将此移除) +// Welcome message (Do not remove this without permission from the original developer) if (typeof window !== 'undefined') { console.log('%cWe ❤ NewAPI%c Github: https://github.com/QuantumNous/new-api', 'color: #10b981; font-weight: bold; font-size: 24px;', 'color: inherit; font-size: 14px;'); } +function SemiLocaleWrapper({ children }) { + const { i18n } = useTranslation(); + const semiLocale = React.useMemo( + () => ({ zh: zh_CN, en: en_GB }[i18n.language] || zh_CN), + [i18n.language], + ); + return {children}; +} + // initialization const root = ReactDOM.createRoot(document.getElementById('root')); @@ -32,7 +45,9 @@ root.render( }} > - + + +