Commit c5f50b65 by archer

feat: i18n

parent 81577046
{ {
"editor.formatOnSave": true, //每次保存自动格式化 "editor.formatOnSave": true,
"editor.mouseWheelZoom": true, "editor.mouseWheelZoom": true,
"typescript.tsdk": "./client/node_modules/typescript/lib", "typescript.tsdk": "client/node_modules/typescript/lib",
"prettier.prettierPath": "./node_modules/prettier" "prettier.prettierPath": "./node_modules/prettier",
"i18n-ally.localesPaths": [
"client/public/locales"
],
"i18n-ally.enabledParsers": ["json"],
"i18n-ally.keystyle": "nested",
"i18n-ally.sortKeys": true,
"i18n-ally.keepFulfilled": true,
"i18n-ally.sourceLanguage": "zh", // 根据此语言文件翻译其他语言文件的变量和内容
"i18n-ally.displayLanguage": "en", // 显示语言
} }
\ No newline at end of file
//next-i18next.config.js
/**
* @type {import('next-i18next').UserConfig}
*/
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en', 'zh', 'zh-Hans'],
localeDetection: false
}
};
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const { i18n } = require('./next-i18next.config');
const nextConfig = { const nextConfig = {
i18n,
output: 'standalone', output: 'standalone',
reactStrictMode: false, reactStrictMode: false,
compress: true, compress: true,
webpack(config) { webpack(config, { isServer }) {
if (!isServer) {
config.resolve = {
...config.resolve,
fallback: {
...config.resolve.fallback,
fs: false
}
};
}
config.experiments = { config.experiments = {
asyncWebAssembly: true, asyncWebAssembly: true,
layers: true layers: true
......
...@@ -25,12 +25,14 @@ ...@@ -25,12 +25,14 @@
"cookie": "^0.5.0", "cookie": "^0.5.0",
"crypto": "^1.0.1", "crypto": "^1.0.1",
"date-fns": "^2.30.0", "date-fns": "^2.30.0",
"echarts": "^5.4.1",
"dayjs": "^1.11.7", "dayjs": "^1.11.7",
"echarts": "^5.4.1",
"formidable": "^2.1.1", "formidable": "^2.1.1",
"framer-motion": "^9.0.6", "framer-motion": "^9.0.6",
"hyperdown": "^2.4.29", "hyperdown": "^2.4.29",
"i18next": "^22.5.1",
"immer": "^9.0.19", "immer": "^9.0.19",
"js-cookie": "^3.0.5",
"jsonwebtoken": "^9.0.0", "jsonwebtoken": "^9.0.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mammoth": "^1.5.1", "mammoth": "^1.5.1",
...@@ -38,6 +40,7 @@ ...@@ -38,6 +40,7 @@
"mongoose": "^6.10.0", "mongoose": "^6.10.0",
"nanoid": "^4.0.1", "nanoid": "^4.0.1",
"next": "13.1.6", "next": "13.1.6",
"next-i18next": "^13.3.0",
"nextjs-cors": "^2.1.2", "nextjs-cors": "^2.1.2",
"nodemailer": "^6.9.1", "nodemailer": "^6.9.1",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
...@@ -48,6 +51,7 @@ ...@@ -48,6 +51,7 @@
"react-day-picker": "^8.7.1", "react-day-picker": "^8.7.1",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-hook-form": "^7.43.1", "react-hook-form": "^7.43.1",
"react-i18next": "^12.3.1",
"react-markdown": "^8.0.7", "react-markdown": "^8.0.7",
"react-syntax-highlighter": "^15.5.0", "react-syntax-highlighter": "^15.5.0",
"reactflow": "^11.7.4", "reactflow": "^11.7.4",
...@@ -65,6 +69,7 @@ ...@@ -65,6 +69,7 @@
"@svgr/webpack": "^6.5.1", "@svgr/webpack": "^6.5.1",
"@types/cookie": "^0.5.1", "@types/cookie": "^0.5.1",
"@types/formidable": "^2.0.5", "@types/formidable": "^2.0.5",
"@types/js-cookie": "^3.0.3",
"@types/jsonwebtoken": "^9.0.1", "@types/jsonwebtoken": "^9.0.1",
"@types/lodash": "^4.14.191", "@types/lodash": "^4.14.191",
"@types/node": "18.14.0", "@types/node": "18.14.0",
......
{
"home": {
"Quickly build AI question and answer library": "Quickly build AI question and answer library",
"Start Now": "Start Now",
"Visual AI orchestration": "Visual AI orchestration"
}
}
{
"home": {
"Quickly build AI question and answer library": "快速搭建 AI 问答系统",
"Start Now": "立即开始",
"Visual AI orchestration": "可视化 AI 编排"
}
}
...@@ -8,11 +8,12 @@ import { theme } from '@/constants/theme'; ...@@ -8,11 +8,12 @@ import { theme } from '@/constants/theme';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import NProgress from 'nprogress'; //nprogress module import NProgress from 'nprogress'; //nprogress module
import Router from 'next/router'; import Router from 'next/router';
import { clientInitData, feConfigs } from '@/store/static';
import { appWithTranslation } from 'next-i18next';
import { setLangStore } from '@/utils/i18n';
import 'nprogress/nprogress.css'; import 'nprogress/nprogress.css';
import '@/styles/reset.scss'; import '@/styles/reset.scss';
import { clientInitData, feConfigs } from '@/store/static';
import { NextPageContext } from 'next';
import { useGlobalStore } from '@/store/global';
//Binding events. //Binding events.
Router.events.on('routeChangeStart', () => NProgress.start()); Router.events.on('routeChangeStart', () => NProgress.start());
...@@ -30,14 +31,9 @@ const queryClient = new QueryClient({ ...@@ -30,14 +31,9 @@ const queryClient = new QueryClient({
} }
}); });
function App({ Component, pageProps, isPc }: AppProps & { isPc?: boolean; response: any }) { function App({ Component, pageProps }: AppProps) {
const [googleClientVerKey, setGoogleVerKey] = useState<string>(); const [googleClientVerKey, setGoogleVerKey] = useState<string>();
const [baiduTongji, setBaiduTongji] = useState<string>(); const [baiduTongji, setBaiduTongji] = useState<string>();
const { initIsPc } = useGlobalStore();
// if (isPc !== undefined) {
// initIsPc(isPc);
// }
useEffect(() => { useEffect(() => {
(async () => { (async () => {
...@@ -47,12 +43,14 @@ function App({ Component, pageProps, isPc }: AppProps & { isPc?: boolean; respon ...@@ -47,12 +43,14 @@ function App({ Component, pageProps, isPc }: AppProps & { isPc?: boolean; respon
setGoogleVerKey(googleClientVerKey); setGoogleVerKey(googleClientVerKey);
setBaiduTongji(baiduTongji); setBaiduTongji(baiduTongji);
})(); })();
setLangStore('en');
}, []); }, []);
return ( return (
<> <>
<Head> <Head>
<title>{feConfigs?.systemTitle || 'AI知识库'}</title> <title>{feConfigs?.systemTitle || 'FastAI'}</title>
<meta name="description" content="Embedding + LLM, Build AI knowledge base" /> <meta name="description" content="Embedding + LLM, Build AI knowledge base" />
<meta <meta
name="viewport" name="viewport"
...@@ -85,12 +83,4 @@ function App({ Component, pageProps, isPc }: AppProps & { isPc?: boolean; respon ...@@ -85,12 +83,4 @@ function App({ Component, pageProps, isPc }: AppProps & { isPc?: boolean; respon
); );
} }
App.getInitialProps = async ({ ctx }: { ctx: NextPageContext }) => { export default appWithTranslation(App);
const reg = /mobile/gi;
const isPc = !reg.test(ctx.req?.headers?.['user-agent'] || '');
return { isPc };
};
export default App;
...@@ -4,6 +4,8 @@ import { useRouter } from 'next/router'; ...@@ -4,6 +4,8 @@ import { useRouter } from 'next/router';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/store/global';
import { beianText } from '@/store/static'; import { beianText } from '@/store/static';
import { feConfigs } from '@/store/static'; import { feConfigs } from '@/store/static';
import { serviceSideProps } from '@/utils/i18n';
import { useTranslation } from 'next-i18next';
import styles from './index.module.scss'; import styles from './index.module.scss';
import axios from 'axios'; import axios from 'axios';
...@@ -11,6 +13,7 @@ import MyIcon from '@/components/Icon'; ...@@ -11,6 +13,7 @@ import MyIcon from '@/components/Icon';
const Home = () => { const Home = () => {
const router = useRouter(); const router = useRouter();
const { t } = useTranslation();
const { inviterId } = router.query as { inviterId: string }; const { inviterId } = router.query as { inviterId: string };
const { isPc } = useGlobalStore(); const { isPc } = useGlobalStore();
const [star, setStar] = useState(1500); const [star, setStar] = useState(1500);
...@@ -157,9 +160,11 @@ const Home = () => { ...@@ -157,9 +160,11 @@ const Home = () => {
<Flex <Flex
flexDirection={'column'} flexDirection={'column'}
alignItems={'center'} alignItems={'center'}
justifyContent={'center'}
mt={'22vh'} mt={'22vh'}
position={'absolute'} position={'absolute'}
userSelect={'none'} userSelect={'none'}
textAlign={'center'}
> >
<Image src="/icon/logo2.png" w={['70px', '120px']} h={['70px', '120px']} alt={''}></Image> <Image src="/icon/logo2.png" w={['70px', '120px']} h={['70px', '120px']} alt={''}></Image>
<Box <Box
...@@ -171,10 +176,10 @@ const Home = () => { ...@@ -171,10 +176,10 @@ const Home = () => {
{feConfigs?.systemTitle || 'AI知识库'} {feConfigs?.systemTitle || 'AI知识库'}
</Box> </Box>
<Box className={styles.textlg} fontWeight={'bold'} fontSize={['30px', '50px']}> <Box className={styles.textlg} fontWeight={'bold'} fontSize={['30px', '50px']}>
可视化 AI 编排 {t('home.Visual AI orchestration')}
</Box> </Box>
<Box className={styles.textlg} fontWeight={'bold'} fontSize={['30px', '50px']}> <Box className={styles.textlg} fontWeight={'bold'} fontSize={['30px', '50px']}>
快速搭建 AI 问答库 {t('home.Quickly build AI question and answer library')}
</Box> </Box>
<Flex flexDirection={['column', 'row']} my={5}> <Flex flexDirection={['column', 'row']} my={5}>
...@@ -205,7 +210,7 @@ const Home = () => { ...@@ -205,7 +210,7 @@ const Home = () => {
py={[2, 3]} py={[2, 3]}
onClick={() => router.push(`/app/list`)} onClick={() => router.push(`/app/list`)}
> >
立即开始 {t('home.Start Now')}
</Button> </Button>
</Flex> </Flex>
</Flex> </Flex>
...@@ -227,4 +232,12 @@ const Home = () => { ...@@ -227,4 +232,12 @@ const Home = () => {
); );
}; };
export async function getServerSideProps(content: any) {
return {
props: {
...(await serviceSideProps(content))
}
};
}
export default Home; export default Home;
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import Cookies from 'js-cookie';
export const LANG_KEY = 'NEXT_LOCALE_LANG';
export enum LangEnum {
'zh' = 'zh',
'en' = 'en'
}
export const setLangStore = (value: `${LangEnum}`) => {
return Cookies.set(LANG_KEY, value, { expires: 7, sameSite: 'None', secure: true });
};
export const getLangStore = () => {
return Cookies.get(LANG_KEY) || LangEnum.zh;
};
export const removeLangStore = () => {
Cookies.remove(LANG_KEY);
};
export const serviceSideProps = (content: any) => {
return serverSideTranslations(
content.req.cookies[LANG_KEY] || 'en',
undefined,
null,
content.locales
);
};
...@@ -8,8 +8,11 @@ ...@@ -8,8 +8,11 @@
}, },
"devDependencies": { "devDependencies": {
"husky": "^8.0.3", "husky": "^8.0.3",
"i18next": "^23.2.11",
"lint-staged": "^13.2.1", "lint-staged": "^13.2.1",
"prettier": "^2.8.7" "next-i18next": "^14.0.0",
"prettier": "^2.8.7",
"react-i18next": "^13.0.2"
}, },
"lint-staged": { "lint-staged": {
"./**/**/*.{ts,tsx,scss}": "npm run format" "./**/**/*.{ts,tsx,scss}": "npm run format"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment