diff --git a/next-i18next.config.js b/next-i18next.config.js deleted file mode 100644 index 40860a2cd35f..000000000000 --- a/next-i18next.config.js +++ /dev/null @@ -1,19 +0,0 @@ -const i18n = require('./.i18nrc'); - -/** @type {import('next-i18next').UserConfig} */ -module.exports = { - //debug: process.env.NODE_ENV === 'development', - fallbackLng: { - default: ['zh_CN'], - zh_TW: ['zh_CN'], - }, - i18n: { - defaultLocale: i18n.entryLocale, - locales: [i18n.entryLocale, ...i18n.outputLocales], - }, - localePath: - typeof window === 'undefined' ? require('node:path').resolve('./', i18n.output) : '/locales', - react: { useSuspense: false }, - reloadOnPrerender: process.env.NODE_ENV === 'development', - strictMode: true, -}; diff --git a/next.config.mjs b/next.config.mjs index fa0a988d98e4..06765f1dc567 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,10 +1,7 @@ -import i18nConfig from './next-i18next.config.js'; - const API_END_PORT_URL = process.env.API_END_PORT_URL || ''; /** @type {import('next').NextConfig} */ const nextConfig = { - i18n: i18nConfig.i18n, reactStrictMode: true, pageExtensions: ['page.tsx', 'api.ts'], transpilePackages: ['@lobehub/ui', 'antd-style'], diff --git a/package.json b/package.json index d8cccacc80fb..4abfed342b26 100644 --- a/package.json +++ b/package.json @@ -77,8 +77,7 @@ "lodash-es": "^4", "lucide-react": "latest", "nanoid": "^4", - "next": "^13", - "next-i18next": "^14", + "next": "13.4.7", "openai-edge": "^1", "polished": "^4", "react": "^18", @@ -110,15 +109,18 @@ "commitlint": "^17", "eslint": "^8", "husky": "^8", + "i18next-browser-languagedetector": "^7", "i18next-resources-for-ts": "^1", "jsdom": "^22", "lint-staged": "^13", "next-pwa": "^5", "node-fetch": "^3", + "postcss-styled-syntax": "^0.4", "prettier": "^2", "remark": "^14", "remark-cli": "^11", "semantic-release": "^21", + "semantic-release-config-gitmoji": "^1", "stylelint": "^15", "typescript": "^5", "vitest": "latest" diff --git a/public/locales/en_US/common.json b/public/locales/en_US/common.json deleted file mode 100644 index 932ffa7555c0..000000000000 --- a/public/locales/en_US/common.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "advanceSettings": "Advanced Settings", - "agentAvatar": "Avatar", - "agentDescription": "Description", - "agentDescriptionPlaceholder": "Please enter a description", - "agentModel": "Model", - "agentName": "Name", - "agentNamePlaceholder": "Please enter a name", - "agentProfile": "Agent Profile", - "agentPrompt": "AI Prompt", - "agentPromptPlaceholder": "Please enter AI prompt", - "agentTag": "Tag", - "agentTagPlaceholder": "Please enter a tag", - "archive": "Archive", - "autoGenerate": "Auto Generate", - "cancel": "Cancel", - "close": "Close", - "confirmRemoveSessionItemAlert": "You are about to remove this agent. Once removed, it cannot be recovered. Please confirm your action.", - "defaultAgent": "Default Agent", - "edit": "Edit", - "editAgentProfile": "Edit Agent Profile", - "export": "Export", - "gpt-3.5-turbo": "GPT 3.5 Turbo", - "gpt-3.5-turbo-16k": "GPT 3.5 Turbo (16K)", - "gpt-4": "GPT 4", - "gpt-4-32k": "GPT 4 (32K)", - "modelConfig": "Model Configuration", - "modelTemperature": "Temperature", - "newAgent": "New Agent", - "noDescription": "No description", - "ok": "OK", - "profile": "Profile", - "reset": "Reset", - "searchAgentPlaceholder": "Search agents and conversations...", - "sessionSetting": "Session Setting", - "setting": "Setting", - "share": "Share", - "updateAgent": "Update Agent", - "updatePrompt": "Update Prompt" -} diff --git a/public/locales/en_US/setting.json b/public/locales/en_US/setting.json deleted file mode 100644 index ff97d744551b..000000000000 --- a/public/locales/en_US/setting.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "danger": { - "reset": { - "title": "Reset All Settings", - "desc": "Reset all settings to default values", - "action": "Reset Now", - "confirm": "Confirm reset all settings?", - "currentVersion": "Current Version" - }, - "clear": { - "title": "Clear All Data", - "desc": "Clear all chat and settings data", - "action": "Clear Now", - "confirm": "Confirm clear all chat and settings data?" - } - }, - "header": "Settings", - "settingChat": { - "title": "Chat Settings", - "inputTemplate": { - "title": "User Input Template", - "desc": "The latest user message will be filled into this template" - }, - "compressThreshold": { - "title": "History Message Length Compression Threshold", - "desc": "When the uncompressed history message exceeds this value, it will be compressed" - }, - "historyCount": { - "title": "Number of History Messages", - "desc": "Number of history messages carried in each request" - }, - "maxTokens": { - "title": "Max Tokens per Response", - "desc": "The maximum number of tokens used for each interaction" - }, - "sendKey": { - "title": "Send Key" - } - }, - "settingModel": { - "title": "Model Settings", - "model": { - "title": "Model" - }, - "temperature": { - "title": "Randomness (temperature)", - "desc": "The higher the value, the more random the response" - }, - "topP": { - "title": "Nucleus Sampling (top_p)", - "desc": "Similar to randomness, but do not change it together with randomness" - }, - "presencePenalty": { - "title": "Topic Freshness (presence_penalty)", - "desc": "The higher the value, the more likely it is to expand to new topics" - }, - "frequencyPenalty": { - "title": "Frequency Penalty (frequency_penalty)", - "desc": "The higher the value, the more likely it is to reduce repeated words" - } - }, - "settingOpenAI": { - "title": "OpenAI Settings", - "token": { - "title": "API Key", - "desc": "Use your own key to bypass password access restrictions", - "placeholder": "OpenAI API Key" - }, - "endpoint": { - "title": "API Endpoint", - "desc": "In addition to the default address, it must include http(s)://" - } - }, - "settingSystem": { - "title": "System Settings", - "accessCode": { - "title": "Access Code", - "desc": "Encryption access has been enabled by the administrator", - "placeholder": "Please enter the access code" - } - }, - "settingTheme": { - "title": "Theme Settings", - "avatar": { - "title": "Avatar", - "desc": "Supports URL / Base64 / Emoji" - }, - "fontSize": { - "title": "Font Size", - "desc": "Font size of chat content" - }, - "lang": { - "name": "Language Settings", - "all": "All Languages" - } - } -} diff --git a/public/locales/zh_CN/common.json b/public/locales/zh_CN/common.json deleted file mode 100644 index ac50fe476f75..000000000000 --- a/public/locales/zh_CN/common.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "advanceSettings": "高级设置", - "agentAvatar": "头像", - "agentDescription": "描述", - "agentDescriptionPlaceholder": "请输入描述", - "agentModel": "模型", - "agentName": "名称", - "agentNamePlaceholder": "请输入名称", - "agentProfile": "助手信息", - "agentPrompt": "提示词", - "agentPromptPlaceholder": "请输入 AI 提示词", - "agentTag": "标签", - "agentTagPlaceholder": "请输入标签", - "archive": "归档", - "autoGenerate": "自动补全", - "cancel": "取消", - "close": "关闭", - "confirmRemoveSessionItemAlert": "即将删除该助手,删除后该将无法找回,请确认你的操作", - "defaultAgent": "默认助手", - "edit": "编辑", - "editAgentProfile": "编辑助手信息", - "export": "导出", - "gpt-3.5-turbo": "GPT 3.5", - "gpt-3.5-turbo-16k": "GPT 3.5 (16K)", - "gpt-4": "GPT 4", - "gpt-4-32k": "GPT 4 (32K)", - "modelConfig": "模型配置", - "modelTemperature": "发散度", - "newAgent": "新建助手", - "noDescription": "暂无描述", - "ok": "确定", - "profile": "身份卡", - "reset": "重置", - "searchAgentPlaceholder": "搜索助手和对话...", - "sessionSetting": "会话设置", - "setting": "设置", - "share": "分享", - "updateAgent": "更新助理信息", - "updatePrompt": "更新提示词" -} diff --git a/public/locales/zh_CN/setting.json b/public/locales/zh_CN/setting.json deleted file mode 100644 index a61973c36106..000000000000 --- a/public/locales/zh_CN/setting.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "danger": { - "reset": { - "title": "重置所有设置", - "desc": "重置所有设置项回默认值", - "action": "立即重置", - "confirm": "确认重置所有设置?", - "currentVersion": "当前版本" - }, - "clear": { - "title": "清除所有数据", - "desc": "清除所有聊天、设置数据", - "action": "立即清除", - "confirm": "确认清除所有聊天、设置数据?" - } - }, - - "header": "设置", - "settingChat": { - "title": "聊天设置", - "inputTemplate": { - "title": "用户输入预处理", - "desc": "用户最新的一条消息会填充到此模板" - }, - "compressThreshold": { - "title": "历史消息长度压缩阈值", - "desc": "当未压缩的历史消息超过该值时,将进行压缩" - }, - "historyCount": { - "title": "附带历史消息数", - "desc": "每次请求携带的历史消息数" - }, - "maxTokens": { - "title": "单次回复限制 (max_tokens)", - "desc": "单次交互所用的最大 Token 数" - }, - "sendKey": { - "title": "发送键" - } - }, - "settingModel": { - "title": "模型设置", - "model": { - "title": "模型" - }, - "temperature": { - "title": "随机性 (temperature)", - "desc": "值越大,回复越随机" - }, - "topP": { - "title": "核采样 (top_p)", - "desc": "与随机性类似,但不要和随机性一起更改" - }, - "presencePenalty": { - "title": "话题新鲜度 (presence_penalty)", - "desc": "值越大,越有可能扩展到新话题" - }, - "frequencyPenalty": { - "title": "频率惩罚度 (frequency_penalty)", - "desc": "值越大,越有可能降低重复字词" - } - }, - "settingOpenAI": { - "title": "OpenAI 设置", - "token": { - "title": "API Key", - "desc": "使用自己的 Key 可绕过密码访问限制", - "placeholder": "OpenAI API Key" - }, - "endpoint": { - "title": "接口地址", - "desc": "除默认地址外,必须包含 http(s)://" - } - }, - "settingSystem": { - "title": "系统设置", - "accessCode": { - "title": "访问密码", - "desc": "管理员已开启加密访问", - "placeholder": "请输入访问密码" - } - }, - "settingTheme": { - "title": "主题设置", - "avatar": { - "title": "头像", - "desc": "支持 URL / Base64 / Emoji 表情符号" - }, - "fontSize": { - "title": "字体大小", - "desc": "聊天内容的字体大小" - }, - "lang": { - "name": "语言设置", - "all": "所有语言" - } - } -} diff --git a/src/layout/index.tsx b/src/layout/index.tsx index 6d950121b542..f97e86efd432 100644 --- a/src/layout/index.tsx +++ b/src/layout/index.tsx @@ -8,11 +8,17 @@ import { useSessionStore } from '@/store/session'; import { useSettings } from '@/store/settings'; import { GlobalStyle } from '@/styles'; +import i18n from '../locales'; import { useStyles } from './style'; const Layout = ({ children }: PropsWithChildren) => { const { styles } = useStyles(); + useEffect(() => { + // 用一种比较奇怪的方式import 了 18n + i18n.finally(() => {}); + }, []); + return ( {children} diff --git a/src/locales/create.ts b/src/locales/create.ts new file mode 100644 index 000000000000..9ec3c9c5d2ef --- /dev/null +++ b/src/locales/create.ts @@ -0,0 +1,50 @@ +import i18n from 'i18next'; +import LanguageDetector from 'i18next-browser-languagedetector'; +import { initReactI18next } from 'react-i18next'; + +import { commonLocaleSet } from './namespaces'; + +interface LocalSet { + ['en-US']: Record; + ['zh-CN']: Record; +} + +interface I18NOptions { + localSet: LocalSet; + namespace: string; +} + +export const createI18nNext = (options: I18NOptions) => { + // 将语言包合并 + const resources = { + 'en-US': { + common: commonLocaleSet['en-US'], + [options.namespace]: options.localSet['en-US'], + }, + 'zh-CN': { + common: commonLocaleSet['zh-CN'], + [options.namespace]: options.localSet['zh-CN'], + }, + }; + + return ( + i18n + // detect user language + // learn more: https://github.com/i18next/i18next-browser-languageDetector + .use(LanguageDetector) + // pass the i18n instance to react-i18next. + .use(initReactI18next) + // init i18next + // for all options read: https://www.i18next.com/overview/configuration-options + .init({ + debug: process.env.NODE_ENV === 'development', + defaultNS: [options.namespace, 'common'], + fallbackLng: 'zh-CN', + interpolation: { + escapeValue: false, // not needed for react as it escapes by default + }, + ns: [options.namespace, 'common'], + resources, + }) + ); +}; diff --git a/src/locales/en_US/common.ts b/src/locales/en_US/common.ts new file mode 100644 index 000000000000..43327263783f --- /dev/null +++ b/src/locales/en_US/common.ts @@ -0,0 +1,41 @@ +export default { + 'advanceSettings': 'Advanced Settings', + 'agentAvatar': 'Avatar', + 'agentDescription': 'Description', + 'agentDescriptionPlaceholder': 'Please enter a description', + 'agentModel': 'Model', + 'agentName': 'Name', + 'agentNamePlaceholder': 'Please enter a name', + 'agentProfile': 'Agent Profile', + 'agentPrompt': 'AI Prompt', + 'agentPromptPlaceholder': 'Please enter AI prompt', + 'agentTag': 'Tag', + 'agentTagPlaceholder': 'Please enter a tag', + 'archive': 'Archive', + 'autoGenerate': 'Auto Generate', + 'cancel': 'Cancel', + 'close': 'Close', + 'confirmRemoveSessionItemAlert': + 'You are about to remove this agent. Once removed, it cannot be recovered. Please confirm your action.', + 'defaultAgent': 'Default Agent', + 'edit': 'Edit', + 'editAgentProfile': 'Edit Agent Profile', + 'export': 'Export', + 'gpt-3.5-turbo': 'GPT 3.5 Turbo', + 'gpt-3.5-turbo-16k': 'GPT 3.5 Turbo (16K)', + 'gpt-4': 'GPT 4', + 'gpt-4-32k': 'GPT 4 (32K)', + 'modelConfig': 'Model Configuration', + 'modelTemperature': 'Temperature', + 'newAgent': 'New Agent', + 'noDescription': 'No description', + 'ok': 'OK', + 'profile': 'Profile', + 'reset': 'Reset', + 'searchAgentPlaceholder': 'Search agents and conversations...', + 'sessionSetting': 'Session Setting', + 'setting': 'Setting', + 'share': 'Share', + 'updateAgent': 'Update Agent', + 'updatePrompt': 'Update Prompt', +}; diff --git a/src/locales/en_US/setting.ts b/src/locales/en_US/setting.ts new file mode 100644 index 000000000000..ea878d484281 --- /dev/null +++ b/src/locales/en_US/setting.ts @@ -0,0 +1,97 @@ +export default { + danger: { + clear: { + action: 'Clear Now', + confirm: 'Confirm clear all chat and settings data?', + desc: 'Clear all chat and settings data', + title: 'Clear All Data', + }, + reset: { + action: 'Reset Now', + confirm: 'Confirm reset all settings?', + currentVersion: 'Current Version', + desc: 'Reset all settings to default values', + title: 'Reset All Settings', + }, + }, + header: 'Settings', + settingChat: { + compressThreshold: { + desc: 'When the uncompressed history message exceeds this value, it will be compressed', + title: 'History Message Length Compression Threshold', + }, + historyCount: { + desc: 'Number of history messages carried in each request', + title: 'Number of History Messages', + }, + inputTemplate: { + desc: 'The latest user message will be filled into this template', + title: 'User Input Template', + }, + maxTokens: { + desc: 'The maximum number of tokens used for each interaction', + title: 'Max Tokens per Response', + }, + sendKey: { + title: 'Send Key', + }, + title: 'Chat Settings', + }, + settingModel: { + frequencyPenalty: { + desc: 'The higher the value, the more likely it is to reduce repeated words', + title: 'Frequency Penalty (frequency_penalty)', + }, + model: { + title: 'Model', + }, + presencePenalty: { + desc: 'The higher the value, the more likely it is to expand to new topics', + title: 'Topic Freshness (presence_penalty)', + }, + temperature: { + desc: 'The higher the value, the more random the response', + title: 'Randomness (temperature)', + }, + title: 'Model Settings', + topP: { + desc: 'Similar to randomness, but do not change it together with randomness', + title: 'Nucleus Sampling (top_p)', + }, + }, + settingOpenAI: { + endpoint: { + desc: 'In addition to the default address, it must include http(s)://', + title: 'API Endpoint', + }, + title: 'OpenAI Settings', + token: { + desc: 'Use your own key to bypass password access restrictions', + placeholder: 'OpenAI API Key', + title: 'API Key', + }, + }, + settingSystem: { + accessCode: { + desc: 'Encryption access has been enabled by the administrator', + placeholder: 'Please enter the access code', + title: 'Access Code', + }, + title: 'System Settings', + }, + settingTheme: { + avatar: { + desc: 'Supports URL / Base64 / Emoji', + title: 'Avatar', + }, + fontSize: { + desc: 'Font size of chat content', + title: 'Font Size', + }, + lang: { + all: 'All Languages', + name: 'Language Settings', + }, + title: 'Theme Settings', + }, +}; diff --git a/src/locales/index.ts b/src/locales/index.ts new file mode 100644 index 000000000000..f5269cda81ea --- /dev/null +++ b/src/locales/index.ts @@ -0,0 +1,6 @@ +import { createI18nNext } from './create'; +import { commonLocaleSet } from './namespaces'; + +const initI18n = createI18nNext({ localSet: commonLocaleSet, namespace: 'common' }); + +export default initI18n; diff --git a/src/locales/namespaces.ts b/src/locales/namespaces.ts new file mode 100644 index 000000000000..446f32015747 --- /dev/null +++ b/src/locales/namespaces.ts @@ -0,0 +1,16 @@ +import enCommon from './en_US/common'; +import settingEN from './en_US/setting'; +import zhCommon from './zh_CN/common'; +import settingZH from './zh_CN/setting'; + +export const commonLocaleSet = { + 'en-US': enCommon, + 'zh-CN': zhCommon, +}; + +export const settingsLocaleSet = { + 'en-US': settingEN, + 'zh-CN': settingZH, +}; + +export type Language = 'zh-CN' | 'en-US'; diff --git a/src/locales/zh_CN/common.ts b/src/locales/zh_CN/common.ts new file mode 100644 index 000000000000..55c172da20f0 --- /dev/null +++ b/src/locales/zh_CN/common.ts @@ -0,0 +1,40 @@ +export default { + 'advanceSettings': '高级设置', + 'agentAvatar': '头像', + 'agentDescription': '描述', + 'agentDescriptionPlaceholder': '请输入描述', + 'agentModel': '模型', + 'agentName': '名称', + 'agentNamePlaceholder': '请输入名称', + 'agentProfile': '助手信息', + 'agentPrompt': '提示词', + 'agentPromptPlaceholder': '请输入 AI 提示词', + 'agentTag': '标签', + 'agentTagPlaceholder': '请输入标签', + 'archive': '归档', + 'autoGenerate': '自动补全', + 'cancel': '取消', + 'close': '关闭', + 'confirmRemoveSessionItemAlert': '即将删除该助手,删除后该将无法找回,请确认你的操作', + 'defaultAgent': '默认助手', + 'edit': '编辑', + 'editAgentProfile': '编辑助手信息', + 'export': '导出', + 'gpt-3.5-turbo': 'GPT 3.5', + 'gpt-3.5-turbo-16k': 'GPT 3.5 (16K)', + 'gpt-4': 'GPT 4', + 'gpt-4-32k': 'GPT 4 (32K)', + 'modelConfig': '模型配置', + 'modelTemperature': '发散度', + 'newAgent': '新建助手', + 'noDescription': '暂无描述', + 'ok': '确定', + 'profile': '身份卡', + 'reset': '重置', + 'searchAgentPlaceholder': '搜索助手和对话...', + 'sessionSetting': '会话设置', + 'setting': '设置', + 'share': '分享', + 'updateAgent': '更新助理信息', + 'updatePrompt': '更新提示词', +}; diff --git a/src/locales/zh_CN/setting.ts b/src/locales/zh_CN/setting.ts new file mode 100644 index 000000000000..db1482624956 --- /dev/null +++ b/src/locales/zh_CN/setting.ts @@ -0,0 +1,97 @@ +export default { + danger: { + clear: { + action: '立即清除', + confirm: '确认清除所有聊天、设置数据?', + desc: '清除所有聊天、设置数据', + title: '清除所有数据', + }, + reset: { + action: '立即重置', + confirm: '确认重置所有设置?', + currentVersion: '当前版本', + desc: '重置所有设置项回默认值', + title: '重置所有设置', + }, + }, + header: '设置', + settingChat: { + compressThreshold: { + desc: '当未压缩的历史消息超过该值时,将进行压缩', + title: '历史消息长度压缩阈值', + }, + historyCount: { + desc: '每次请求携带的历史消息数', + title: '附带历史消息数', + }, + inputTemplate: { + desc: '用户最新的一条消息会填充到此模板', + title: '用户输入预处理', + }, + maxTokens: { + desc: '单次交互所用的最大 Token 数', + title: '单次回复限制 (max_tokens)', + }, + sendKey: { + title: '发送键', + }, + title: '聊天设置', + }, + settingModel: { + frequencyPenalty: { + desc: '值越大,越有可能降低重复字词', + title: '频率惩罚度 (frequency_penalty)', + }, + model: { + title: '模型', + }, + presencePenalty: { + desc: '值越大,越有可能扩展到新话题', + title: '话题新鲜度 (presence_penalty)', + }, + temperature: { + desc: '值越大,回复越随机', + title: '随机性 (temperature)', + }, + title: '模型设置', + topP: { + desc: '与随机性类似,但不要和随机性一起更改', + title: '核采样 (top_p)', + }, + }, + settingOpenAI: { + endpoint: { + desc: '除默认地址外,必须包含 http(s)://', + title: '接口地址', + }, + title: 'OpenAI 设置', + token: { + desc: '使用自己的 Key 可绕过密码访问限制', + placeholder: 'OpenAI API Key', + title: 'API Key', + }, + }, + settingSystem: { + accessCode: { + desc: '管理员已开启加密访问', + placeholder: '请输入访问密码', + title: '访问密码', + }, + title: '系统设置', + }, + settingTheme: { + avatar: { + desc: '支持 URL / Base64 / Emoji 表情符号', + title: '头像', + }, + fontSize: { + desc: '聊天内容的字体大小', + title: '字体大小', + }, + lang: { + all: '所有语言', + name: '语言设置', + }, + title: '主题设置', + }, +}; diff --git a/src/pages/_app.page.tsx b/src/pages/_app.page.tsx index a3212c7f02dc..26869b2fcc64 100644 --- a/src/pages/_app.page.tsx +++ b/src/pages/_app.page.tsx @@ -1,15 +1,13 @@ import { Analytics } from '@vercel/analytics/react'; -import { appWithTranslation } from 'next-i18next'; import type { AppProps } from 'next/app'; -import i18nConfig from '@/../next-i18next.config'; import Layout from '@/layout'; -export default appWithTranslation(({ Component, pageProps }: AppProps) => { +export default ({ Component, pageProps }: AppProps) => { return ( ); -}, i18nConfig); +}; diff --git a/src/pages/_document.page.tsx b/src/pages/_document.page.tsx index 2abff7092f59..14d3949e931a 100644 --- a/src/pages/_document.page.tsx +++ b/src/pages/_document.page.tsx @@ -1,8 +1,6 @@ import { StyleProvider, extractStaticStyle } from 'antd-style'; import Document, { DocumentContext, Head, Html, Main, NextScript } from 'next/document'; -import i18nextConfig from '../../next-i18next.config.js'; - class MyDocument extends Document { static async getStaticProps(ctx: DocumentContext) { const page = await ctx.renderPage({ @@ -30,9 +28,8 @@ class MyDocument extends Document { } render() { - const currentLocale = this.props.__NEXT_DATA__.locale ?? i18nextConfig.i18n.defaultLocale; return ( - + { ); }); -export { getStaticPaths } from '@/utils/makeI18nProps'; -export const getStaticProps = makeI18nProps(['common']); export default EditPage; diff --git a/src/pages/chat/[id]/index.page.tsx b/src/pages/chat/[id]/index.page.tsx index 9e81d105dc0d..e910e656fd7a 100644 --- a/src/pages/chat/[id]/index.page.tsx +++ b/src/pages/chat/[id]/index.page.tsx @@ -1,11 +1,9 @@ import isEqual from 'fast-deep-equal'; -import { useTranslation } from 'next-i18next'; import Head from 'next/head'; -import { memo, useEffect } from 'react'; +import { memo } from 'react'; import { Flexbox } from 'react-layout-kit'; import { sessionSelectors, useSessionStore } from '@/store/session'; -import { makeI18nProps } from '@/utils/makeI18nProps'; import Layout from '../layout'; import Config from './Config'; @@ -13,16 +11,11 @@ import Conversation from './Conversation'; import Header from './Header'; const Chat = memo(() => { - const { i18n } = useTranslation('common', { bindI18n: 'languageChanged loaded' }); const [title] = useSessionStore((s) => { const context = sessionSelectors.currentSession(s); return [context?.meta.title]; }, isEqual); - useEffect(() => { - i18n.reloadResources(i18n.resolvedLanguage, ['common']); - }, []); - const pageTitle = title ? `${title} - LobeChat` : 'LobeChat'; return ( @@ -44,7 +37,4 @@ const Chat = memo(() => { ); }); - -export { getStaticPaths } from '@/utils/makeI18nProps'; -export const getStaticProps = makeI18nProps(['common']); export default Chat; diff --git a/src/pages/chat/index.page.tsx b/src/pages/chat/index.page.tsx index 829d57ca1835..f62b86d32004 100644 --- a/src/pages/chat/index.page.tsx +++ b/src/pages/chat/index.page.tsx @@ -1,5 +1 @@ -import { makeI18nProps } from '@/utils/makeI18nProps'; - export { default } from './[id]/index.page'; - -export const getStaticProps = makeI18nProps(['common']); diff --git a/src/pages/chat/layout.tsx b/src/pages/chat/layout.tsx index 111676a6d8ca..d0906a1b3101 100644 --- a/src/pages/chat/layout.tsx +++ b/src/pages/chat/layout.tsx @@ -3,13 +3,21 @@ import { PropsWithChildren, memo, useEffect } from 'react'; import { Flexbox } from 'react-layout-kit'; import { shallow } from 'zustand/shallow'; +import { createI18nNext } from '@/locales/create'; +import { commonLocaleSet } from '@/locales/namespaces'; import { useSessionStore } from '@/store/session'; import { useSettings } from '@/store/settings'; import Sidebar from '../Sidebar'; import { Sessions } from './SessionList'; +const initI18n = createI18nNext({ localSet: commonLocaleSet, namespace: 'common' }); + const ChatLayout = memo(({ children }) => { + useEffect(() => { + initI18n.finally(); + }, []); + const [activeSession] = useSessionStore((s) => { return [s.activeSession]; }, shallow); diff --git a/src/pages/index.page.tsx b/src/pages/index.page.tsx index d93d70c99194..ac9e2586cd1e 100644 --- a/src/pages/index.page.tsx +++ b/src/pages/index.page.tsx @@ -1 +1 @@ -export { default, getStaticProps } from './chat/index.page'; +export { default } from './chat/index.page'; diff --git a/src/pages/setting/Header.tsx b/src/pages/setting/Header.tsx index 96248e7306df..b6005f5f327c 100644 --- a/src/pages/setting/Header.tsx +++ b/src/pages/setting/Header.tsx @@ -1,6 +1,6 @@ import { ChatHeader } from '@lobehub/ui'; import { createStyles } from 'antd-style'; -import { useTranslation } from 'next-i18next'; +import { useTranslation } from 'react-i18next'; import Router from 'next/router'; import { memo } from 'react'; diff --git a/src/pages/setting/index.page.tsx b/src/pages/setting/index.page.tsx index 39a5eb15e2d9..e30fac196dd4 100644 --- a/src/pages/setting/index.page.tsx +++ b/src/pages/setting/index.page.tsx @@ -1,18 +1,25 @@ -import { useTranslation } from 'next-i18next'; import Head from 'next/head'; -import { memo } from 'react'; +import { memo, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; +import { createI18nNext } from '@/locales/create'; +import { settingsLocaleSet } from '@/locales/namespaces'; import { Sessions } from '@/pages/chat/SessionList'; -import { makeI18nProps } from '@/utils/makeI18nProps'; import Sidebar from '../Sidebar'; import Header from './Header'; import SettingForm from './SettingForm'; +const initI18n = createI18nNext({ localSet: settingsLocaleSet, namespace: 'setting' }); + const SettingLayout = memo(() => { const { t } = useTranslation('setting'); const pageTitle = `${t('header')} - LobeChat`; + + useEffect(() => { + initI18n.finally(); + }, []); return ( <> @@ -32,6 +39,4 @@ const SettingLayout = memo(() => { ); }); -export const getStaticProps = makeI18nProps(['common', 'setting']); - export default SettingLayout; diff --git a/src/types/resources.ts b/src/types/resources.ts deleted file mode 100644 index 83d5192375c7..000000000000 --- a/src/types/resources.ts +++ /dev/null @@ -1,11 +0,0 @@ -import common from '@/../public/locales/zh_CN/common.json'; -import setting from '@/../public/locales/zh_CN/setting.json'; - -const resources = { - common, - setting, -} as const; - -export default resources; - -export type NS = keyof typeof resources; diff --git a/src/utils/makeI18nProps.ts b/src/utils/makeI18nProps.ts deleted file mode 100644 index ca83b222a420..000000000000 --- a/src/utils/makeI18nProps.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { GetServerSideProps, GetStaticPaths, GetStaticProps } from 'next'; -import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; - -import i18nextConfig from '@/../next-i18next.config'; -import { NS } from '@/types/resources'; - -const isServerReq = (req: any) => !req?.url?.startsWith('/_next'); - -export const getI18nProps = async (ctx: any, ns: NS[] = ['common']) => { - const locale = ctx?.params?.locale || ctx?.locale || i18nextConfig.i18n.defaultLocale; - const req = ctx?.params?.req || ctx?.req; - return isServerReq(req) ? await serverSideTranslations(locale, ns) : {}; -}; - -export const makeI18nProps = - (ns: NS[] = []): GetStaticProps | GetServerSideProps => - async (ctx: any) => { - const req = ctx?.params?.req || ctx?.req; - return { - props: isServerReq(req) ? await getI18nProps(ctx, ns) : {}, - revalidate: false, - }; - }; - -export const getStaticPaths: GetStaticPaths = async () => { - // We don't want to specify all possible countries as we get those from the headers - return { - fallback: 'blocking', - paths: [], - }; -};