mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-27 13:29:15 +07:00
✨ feat(i18n): Add i18next and lobe-i18n internationalization configuration files and update dependencies
This commit introduces new configuration files for internationalization, deletes one file, modifies existing files, and adds new files. The changes also involve importing dependencies and updating app and document pages. Additional libraries and modules are used in a React application. The Header component is modified, the index page is updated for server-side translations, and the tsconfig.json file is modified. Description: - Added configuration files for internationalization - Deleted one file - Modified existing files - Added new files - Imported dependencies - Updated app and document pages - Used additional libraries and modules in a React application - Modified the Header component - Updated the index page for server-side translations - Modified the tsconfig.json file.
This commit is contained in:
12
.i18nrc.js
Normal file
12
.i18nrc.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const { description } = require('./package.json');
|
||||
|
||||
module.exports = {
|
||||
reference: description,
|
||||
entry: 'public/locales/zh_CN',
|
||||
entryLocale: 'zh_CN',
|
||||
output: 'public/locales',
|
||||
outputLocales: ['zh_HK', 'en_US', 'ja_JP', 'ko_KR'],
|
||||
splitToken: 2500,
|
||||
temperature: 0,
|
||||
modelName: 'gpt-3.5-turbo',
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
extends: ['gitmoji'],
|
||||
};
|
||||
13
next-i18next.config.js
Normal file
13
next-i18next.config.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const i18n = require('./.i18nrc');
|
||||
|
||||
/** @type {import('next-i18next').UserConfig} */
|
||||
module.exports = {
|
||||
debug: process.env.NODE_ENV === 'development',
|
||||
i18n: {
|
||||
defaultLocale: i18n.entryLocale,
|
||||
locales: [i18n.entryLocale, i18n.outputLocales],
|
||||
},
|
||||
localePath:
|
||||
typeof window === 'undefined' ? require('node:path').resolve('./', i18n.output) : '/locales',
|
||||
reloadOnPrerender: process.env.NODE_ENV === 'development',
|
||||
};
|
||||
22
next-utils.config.js
Normal file
22
next-utils.config.js
Normal file
@@ -0,0 +1,22 @@
|
||||
const pc = require('picocolors');
|
||||
|
||||
const nextUtilsConfig = () => {
|
||||
const trueEnv = ['true', '1', 'yes'];
|
||||
const esmExternals = trueEnv.includes(process.env?.NEXTJS_ESM_EXTERNALS ?? 'false');
|
||||
const tsconfigPath = process.env.NEXTJS_TSCONFIG_PATH
|
||||
? process.env.NEXTJS_TSCONFIG_PATH
|
||||
: './tsconfig.json';
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
`${pc.green('warn -')} experimental.esmExternals is ${esmExternals ? 'enabled' : 'disabled'}`,
|
||||
);
|
||||
return {
|
||||
esmExternals,
|
||||
tsconfigPath,
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
loadCustomBuildParams: nextUtilsConfig,
|
||||
};
|
||||
@@ -1,11 +1,22 @@
|
||||
// @ts-check
|
||||
import i18nConfig from './next-i18next.config.js';
|
||||
import utilsConfig from './next-utils.config.js';
|
||||
|
||||
const API_END_PORT_URL = process.env.API_END_PORT_URL || '';
|
||||
|
||||
const { esmExternals = false, tsconfigPath } = utilsConfig.loadCustomBuildParams();
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
experimental: {
|
||||
esmExternals, // https://nextjs.org/blog/next-11-1#es-modules-support
|
||||
},
|
||||
i18n: i18nConfig.i18n,
|
||||
reactStrictMode: true,
|
||||
pageExtensions: ['page.tsx', 'api.ts'],
|
||||
transpilePackages: ['@lobehub/ui', 'antd-style'],
|
||||
typescript: {
|
||||
tsconfigPath,
|
||||
},
|
||||
webpack(config) {
|
||||
config.experiments = {
|
||||
asyncWebAssembly: true,
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"scripts": {
|
||||
"build": "next build",
|
||||
"dev": "next dev -p 3010",
|
||||
"i18n": "lobe-i18n",
|
||||
"lint": "eslint \"{src,tests}/**/*.{js,jsx,ts,tsx}\" --fix",
|
||||
"lint:md": "remark . --quiet --frail --output",
|
||||
"lint:style": "stylelint \"{src,tests}/**/*.{js,jsx,ts,tsx}\" --fix",
|
||||
@@ -34,6 +35,7 @@
|
||||
"test": "vitest --passWithNoTests",
|
||||
"test:coverage": "vitest run --coverage --passWithNoTests",
|
||||
"test:update": "vitest -u",
|
||||
"toc": "i18next-resources-for-ts toc -i ./public/locales/zh_CN -o ./src/types/resources.ts",
|
||||
"type-check": "tsc --noEmit"
|
||||
},
|
||||
"lint-staged": {
|
||||
@@ -75,6 +77,7 @@
|
||||
"lucide-react": "latest",
|
||||
"nanoid": "^4",
|
||||
"next": "13.4.7",
|
||||
"next-i18next": "^14",
|
||||
"polished": "^4",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
@@ -88,6 +91,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^17",
|
||||
"@lobehub/i18n-cli": "latest",
|
||||
"@lobehub/lint": "latest",
|
||||
"@next/eslint-plugin-next": "^13",
|
||||
"@testing-library/jest-dom": "^5",
|
||||
@@ -104,10 +108,12 @@
|
||||
"commitlint": "^17",
|
||||
"eslint": "^8",
|
||||
"husky": "^8",
|
||||
"i18next-resources-for-ts": "^1",
|
||||
"jsdom": "^22",
|
||||
"lint-staged": "^13",
|
||||
"next-pwa": "^5",
|
||||
"node-fetch": "^3",
|
||||
"picocolors": "^1",
|
||||
"postcss-styled-syntax": "^0.4",
|
||||
"prettier": "^2",
|
||||
"remark": "^14",
|
||||
|
||||
4
public/locales/en_US/common.json
Normal file
4
public/locales/en_US/common.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"setting": "Setting",
|
||||
"share": "Share"
|
||||
}
|
||||
4
public/locales/ja_JP/common.json
Normal file
4
public/locales/ja_JP/common.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"setting": "設定",
|
||||
"share": "共有する"
|
||||
}
|
||||
4
public/locales/ko_KR/common.json
Normal file
4
public/locales/ko_KR/common.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"setting": "설정",
|
||||
"share": "공유"
|
||||
}
|
||||
4
public/locales/zh_CN/common.json
Normal file
4
public/locales/zh_CN/common.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"setting": "设置",
|
||||
"share": "分享"
|
||||
}
|
||||
4
public/locales/zh_HK/common.json
Normal file
4
public/locales/zh_HK/common.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"setting": "設置",
|
||||
"share": "分享"
|
||||
}
|
||||
18
src/i18n/index.ts
Normal file
18
src/i18n/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import type { Namespace } from 'i18next';
|
||||
import type { SSRConfig, UserConfig } from 'next-i18next';
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
||||
|
||||
import nextI18nextConfig from '@/../next-i18next.config';
|
||||
|
||||
type ArrayElementOrSelf<T> = T extends Array<infer U> ? U[] : T[];
|
||||
|
||||
export const getServerTranslations = async (
|
||||
locale: string,
|
||||
namespacesRequired?: ArrayElementOrSelf<Namespace> | undefined,
|
||||
configOverride?: UserConfig,
|
||||
extraLocales?: string[] | false,
|
||||
): Promise<SSRConfig> => {
|
||||
const config = configOverride ?? nextI18nextConfig;
|
||||
// @ts-ignore
|
||||
return serverSideTranslations(locale, namespacesRequired, config, extraLocales);
|
||||
};
|
||||
@@ -1,15 +1,19 @@
|
||||
import { Analytics } from '@vercel/analytics/react';
|
||||
import { appWithTranslation } from 'next-i18next';
|
||||
import type { AppProps } from 'next/app';
|
||||
import { Suspense } from 'react';
|
||||
|
||||
import Layout from '@/layout';
|
||||
|
||||
function MyApp({ Component, pageProps }: AppProps) {
|
||||
return (
|
||||
<Layout>
|
||||
<Component {...pageProps} />
|
||||
<Analytics />
|
||||
</Layout>
|
||||
<Suspense fallback="loading">
|
||||
<Layout>
|
||||
<Component {...pageProps} />
|
||||
<Analytics />
|
||||
</Layout>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
export default MyApp;
|
||||
export default appWithTranslation(MyApp);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
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 getInitialProps(ctx: DocumentContext) {
|
||||
const page = await ctx.renderPage({
|
||||
@@ -28,9 +30,37 @@ class MyDocument extends Document {
|
||||
}
|
||||
|
||||
render() {
|
||||
const currentLocale = this.props.__NEXT_DATA__.locale ?? i18nextConfig.i18n.defaultLocale;
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head></Head>
|
||||
<Html lang={currentLocale}>
|
||||
<Head>
|
||||
<link
|
||||
href="https://npm.elemecdn.com/@lobehub/assets-favicons/assets/apple-touch-icon.png"
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
/>
|
||||
<link
|
||||
href="https://npm.elemecdn.com/@lobehub/assets-favicons/assets/favicon-32x32.png"
|
||||
rel="icon"
|
||||
sizes="32x32"
|
||||
type="image/png"
|
||||
/>
|
||||
<link
|
||||
href="https://npm.elemecdn.com/@lobehub/assets-favicons/assets/favicon-16x16.png"
|
||||
rel="icon"
|
||||
sizes="16x16"
|
||||
type="image/png"
|
||||
/>
|
||||
<link
|
||||
color="#000000"
|
||||
href="https://npm.elemecdn.com/@lobehub/assets-favicons/assets/safari-pinned-tab.svg"
|
||||
rel="mask-icon"
|
||||
/>
|
||||
<meta content="LobeHub" name="apple-mobile-web-app-title" />
|
||||
<meta content="LobeHub" name="application-name" />
|
||||
<meta content="#000000" name="msapplication-TileColor" />
|
||||
<meta content="#000000" name="theme-color" />
|
||||
</Head>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ActionIcon, Avatar } from '@lobehub/ui';
|
||||
import { createStyles, useTheme } from 'antd-style';
|
||||
import { ArchiveIcon, MoreVerticalIcon, Share2Icon } from 'lucide-react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { memo } from 'react';
|
||||
import { Flexbox } from 'react-layout-kit';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
@@ -19,6 +20,7 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
}));
|
||||
const Header = memo(() => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation('common');
|
||||
const meta = useChatStore((s) => {
|
||||
const chat = sessionSelectors.currentSession(s);
|
||||
return chat?.meta;
|
||||
@@ -62,7 +64,7 @@ const Header = memo(() => {
|
||||
onClick={() => {
|
||||
// genShareUrl();
|
||||
}}
|
||||
title={'分享'}
|
||||
title={t('share')}
|
||||
/>
|
||||
<ActionIcon icon={ArchiveIcon} title={'归档'} />
|
||||
<ActionIcon icon={MoreVerticalIcon} onClick={toggleConfig} />
|
||||
|
||||
@@ -1 +1,17 @@
|
||||
export { default } from './chat/index.page';
|
||||
import type { GetStaticProps, InferGetStaticPropsType } from 'next';
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
||||
|
||||
import Chat from './chat/index.page';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const Index = (_props: InferGetStaticPropsType<typeof getStaticProps>) => {
|
||||
return <Chat />;
|
||||
};
|
||||
|
||||
export const getStaticProps: GetStaticProps = async ({ locale }) => ({
|
||||
props: {
|
||||
...(await serverSideTranslations(locale ?? 'zh_CN', ['common'])),
|
||||
},
|
||||
});
|
||||
|
||||
export default Index;
|
||||
|
||||
8
src/types/i18next.d.ts
vendored
Normal file
8
src/types/i18next.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import resources from '@/types/resources';
|
||||
|
||||
declare module 'i18next' {
|
||||
interface CustomTypeOptions {
|
||||
defaultNS: 'common';
|
||||
resources: typeof resources;
|
||||
}
|
||||
}
|
||||
7
src/types/resources.ts
Normal file
7
src/types/resources.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import common from '@/../public/locales/zh_CN/common.json';
|
||||
|
||||
const resources = {
|
||||
common,
|
||||
} as const;
|
||||
|
||||
export default resources;
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
@@ -21,5 +22,5 @@
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules"],
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.d.ts", "**/*.tsx"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user