From 37c87b22c69ffa3a6d005de6d83a0204db8b0acb Mon Sep 17 00:00:00 2001 From: robertsavian Date: Tue, 29 Jun 2021 13:16:52 -0500 Subject: [PATCH 1/2] Add react-i18next example --- next-i18next.config.js | 10 --- next.config.js | 6 +- package.json | 5 +- src/components/pages/about-page/AboutPage.tsx | 8 +- src/components/pages/index-page/IndexPage.tsx | 8 +- src/components/shared/Header.tsx | 8 +- src/i18n.js | 31 ++++++++ src/pages/_app.tsx | 19 ++++- src/pages/about/index.tsx | 9 +-- src/pages/index.tsx | 9 +-- yarn.lock | 78 ++++++------------- 11 files changed, 98 insertions(+), 93 deletions(-) delete mode 100644 next-i18next.config.js create mode 100644 src/i18n.js diff --git a/next-i18next.config.js b/next-i18next.config.js deleted file mode 100644 index 0daf708..0000000 --- a/next-i18next.config.js +++ /dev/null @@ -1,10 +0,0 @@ -const path = require('path'); - -module.exports = { - i18n: { - locales: ['en', 'nl', 'no', 'es'], - defaultLocale: 'en', - defaultNS: 'CommonText', - localePath: path.resolve('./public/static/locales'), - }, -}; diff --git a/next.config.js b/next.config.js index 99529b7..f701b4a 100644 --- a/next.config.js +++ b/next.config.js @@ -2,7 +2,6 @@ const path = require('path'); const withPlugins = require('next-compose-plugins'); const withBundleAnalyzer = require('@next/bundle-analyzer'); const DuplicatePackageCheckerPlugin = require('duplicate-package-checker-webpack-plugin'); -const { i18n } = require('./next-i18next.config'); // https://medium.com/ne-digital/how-to-reduce-next-js-bundle-size-68f7ac70c375 // https://medium.com/ne-digital/build-frontend-performance-monitor-dashboard-using-pagespeed-insights-e807a2caa6cf @@ -16,7 +15,10 @@ module.exports = withPlugins( { reactStrictMode: true, - i18n, + i18n: { + locales: ['en', 'nl', 'no', 'es'], + defaultLocale: 'en', + }, eslint: { dirs: ['src'], diff --git a/package.json b/package.json index b2ab34b..7e9a4db 100644 --- a/package.json +++ b/package.json @@ -29,11 +29,14 @@ "dependencies": { "axios": "0.21.1", "clsx": "1.1.1", + "i18next": "20.3.2", + "i18next-browser-languagedetector": "6.1.2", + "i18next-http-backend": "1.2.6", "luxon": "1.27.0", "next": "11.0.1", - "next-i18next": "8.5.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "11.11.0", "semantic-ui-css": "2.4.1", "semantic-ui-react": "2.0.3" }, diff --git a/src/components/pages/about-page/AboutPage.tsx b/src/components/pages/about-page/AboutPage.tsx index 05d4e74..1367f61 100644 --- a/src/components/pages/about-page/AboutPage.tsx +++ b/src/components/pages/about-page/AboutPage.tsx @@ -1,11 +1,15 @@ import React from 'react'; -import { useTranslation } from 'next-i18next'; +import { useTranslation } from 'react-i18next'; import { Header } from 'semantic-ui-react'; interface IProps {} export const AboutPage: React.FC = (props) => { - const { t } = useTranslation(['CommonText', 'AboutPage']); + const { t, ready } = useTranslation(['CommonText', 'AboutPage'], { useSuspense: false }); + + if (!ready) { + return null; + } return ( <> diff --git a/src/components/pages/index-page/IndexPage.tsx b/src/components/pages/index-page/IndexPage.tsx index 2b12660..41529a1 100644 --- a/src/components/pages/index-page/IndexPage.tsx +++ b/src/components/pages/index-page/IndexPage.tsx @@ -1,11 +1,15 @@ import React from 'react'; -import { useTranslation } from 'next-i18next'; +import { useTranslation } from 'react-i18next'; import { Header } from 'semantic-ui-react'; interface IProps {} export const IndexPage: React.FC = (props) => { - const { t } = useTranslation(['CommonText', 'IndexPage']); + const { t, ready } = useTranslation(['CommonText', 'IndexPage'], { useSuspense: false }); + + if (!ready) { + return null; + } return (
diff --git a/src/components/shared/Header.tsx b/src/components/shared/Header.tsx index 672dc51..581eba8 100644 --- a/src/components/shared/Header.tsx +++ b/src/components/shared/Header.tsx @@ -2,7 +2,7 @@ import { Menu, Icon } from 'semantic-ui-react'; import { LocalePicker } from './LocalePicker'; import { useRouter } from 'next/router'; import Link from 'next/link'; -import { useTranslation } from 'next-i18next'; +import { useTranslation } from 'react-i18next'; import { Routes } from '../../constants/Routes'; import { SemanticICONS } from 'semantic-ui-react/dist/commonjs/generic'; import React from 'react'; @@ -11,7 +11,11 @@ interface IProps {} export const Header: React.FC = (props) => { const { pathname } = useRouter(); - const { t } = useTranslation(['CommonText']); + const { t, ready } = useTranslation(['CommonText'], { useSuspense: false }); + + if (!ready) { + return null; + } const buttons: { path: Routes; text: string; icon: SemanticICONS }[] = [ { path: Routes.Index, text: 'CommonText:home', icon: 'home' }, diff --git a/src/i18n.js b/src/i18n.js new file mode 100644 index 0000000..6cab7a6 --- /dev/null +++ b/src/i18n.js @@ -0,0 +1,31 @@ +import i18n from 'i18next'; +import Backend from 'i18next-http-backend'; +import LanguageDetector from 'i18next-browser-languagedetector'; +import { initReactI18next } from 'react-i18next'; + +if (typeof window !== 'undefined') { + i18n + // learn more: https://github.com/i18next/i18next-http-backend + .use(Backend) + // learn more: https://github.com/i18next/i18next-browser-languageDetector + .use(LanguageDetector) + // pass the i18n instance to react-i18next. + .use(initReactI18next) + // learn more: https://www.i18next.com/overview/configuration-options + .init({ + fallbackLng: 'en', + debug: true, + + interpolation: { + escapeValue: false, // not needed for react as it escapes by default + }, + + ns: [], + // defaultNS: ['CommonText'], + backend: { + loadPath: '/static/locales/{{lng}}/{{ns}}.json', + }, + }); +} + +export default i18n; diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 4c2492e..88827df 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -4,14 +4,27 @@ import '../css/main.css'; import React from 'react'; import { AppProps } from 'next/app'; import Head from 'next/head'; -import { appWithTranslation, useTranslation } from 'next-i18next'; import { Container, Segment } from 'semantic-ui-react'; import { CurrentDate } from '../components/shared/CurrentDate'; import { Header } from '../components/shared/Header'; +import i18next from '../i18n'; +import Router from 'next/router'; +import { useTranslation } from 'react-i18next'; + +Router.events.on('routeChangeStart', (): void => { + i18next.changeLanguage(Router.router?.locale); +}); + const NextApp: React.FC = (props) => { - const { t } = useTranslation(['CommonText']); + const { t, ready } = useTranslation(['CommonText'], { useSuspense: false }); + // + + if (!ready) { + return null; + } + // console.log(`i18n`, i18n); return ( @@ -38,4 +51,4 @@ const NextApp: React.FC = (props) => { }; // ts-prune-ignore-next -export default appWithTranslation(NextApp); +export default NextApp; diff --git a/src/pages/about/index.tsx b/src/pages/about/index.tsx index 217e1d2..da242f8 100644 --- a/src/pages/about/index.tsx +++ b/src/pages/about/index.tsx @@ -1,8 +1,7 @@ import React from 'react'; import { MainLayout } from '../../components/shared/main-layout/MainLayout'; -import { GetServerSideProps, NextPage } from 'next'; +import { NextPage } from 'next'; import { AboutPage } from '../../components/pages/about-page/AboutPage'; -import { typedServerSideTranslations } from '../../utils/i18n.utils'; interface IProps {} @@ -14,11 +13,5 @@ const AboutRoute: NextPage = (props) => { ); }; -export const getServerSideProps: GetServerSideProps = async (context) => ({ - props: { - ...(await typedServerSideTranslations(context.locale!, ['AboutPage', 'CommonText'])), - }, -}); - // ts-prune-ignore-next export default AboutRoute; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 617a17b..2b483f4 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,8 +1,7 @@ import React from 'react'; import { MainLayout } from '../components/shared/main-layout/MainLayout'; import { IndexPage } from '../components/pages/index-page/IndexPage'; -import { GetServerSideProps, NextPage } from 'next'; -import { typedServerSideTranslations } from '../utils/i18n.utils'; +import { NextPage } from 'next'; interface IProps {} @@ -14,11 +13,5 @@ const IndexRoute: NextPage = (props) => { ); }; -export const getServerSideProps: GetServerSideProps = async (context) => ({ - props: { - ...(await typedServerSideTranslations(context.locale!, ['IndexPage', 'CommonText'])), - }, -}); - // ts-prune-ignore-next export default IndexRoute; diff --git a/yarn.lock b/yarn.lock index 528ecbd..fae3d99 100644 --- a/yarn.lock +++ b/yarn.lock @@ -59,7 +59,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.10.4", "@babel/runtime@^7.10.5", "@babel/runtime@^7.12.0", "@babel/runtime@^7.13.17", "@babel/runtime@^7.14.5": +"@babel/runtime@^7.10.4", "@babel/runtime@^7.10.5", "@babel/runtime@^7.12.0", "@babel/runtime@^7.14.5", "@babel/runtime@^7.14.6": version "7.14.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.6.tgz#535203bc0892efc7dec60bdc27b2ecf6e409062d" integrity sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg== @@ -213,21 +213,6 @@ exenv "^1.2.2" prop-types "^15.6.2" -"@types/hoist-non-react-statics@^3.3.1": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" - integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== - dependencies: - "@types/react" "*" - hoist-non-react-statics "^3.3.0" - -"@types/i18next-fs-backend@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/i18next-fs-backend/-/i18next-fs-backend-1.0.0.tgz#3fb0374f4d376375b7cc1d3729bca663d104fa64" - integrity sha512-PotQ0NE17NavxXCsdyq9qIKZQOB7+A5O/2nDdvfbfm6/IgvvC1YUO6hxK3nIHASu+QGjO1QV5J8PJw4OL12LMQ== - dependencies: - i18next "^19.7.0" - "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -258,7 +243,7 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== -"@types/react@*", "@types/react@17.0.11": +"@types/react@17.0.11": version "17.0.11" resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.11.tgz#67fcd0ddbf5a0b083a0f94e926c7d63f3b836451" integrity sha512-yFRQbD+whVonItSk7ZzP/L+gPTJVBkL/7shLEF+i9GC/1cV3JmUxEQz6+9ylhUpWSDuqo1N9qEvqS6vTj4USUA== @@ -927,11 +912,6 @@ core-js-pure@^3.0.0: resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.8.0.tgz#4cdd2eca37d49cda206b66e26204818dba77884a" integrity sha512-fRjhg3NeouotRoIV0L1FdchA6CK7ZD+lyINyMoz19SyV+ROpC4noS1xItWHFtwZdlqfMfVPJEyEGdfri2bD1pA== -core-js@^3: - version "3.15.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.15.1.tgz#6c08ab88abdf56545045ccf5fd81f47f407e7f1a" - integrity sha512-h8VbZYnc9pDzueiS2610IULDkpFFPunHwIpl8yRwFahAEEdSpHlTy3h3z3rKq5h11CaUdBEeRViu9AYvbxiMeg== - core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -984,6 +964,13 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" +cross-fetch@3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39" + integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ== + dependencies: + node-fetch "2.6.1" + cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -1937,13 +1924,6 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.2.0, hoist-non-react-statics@^3.3.0: - version "3.3.2" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" - integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== - dependencies: - react-is "^16.7.0" - hosted-git-info@^2.1.4: version "2.8.8" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" @@ -2018,19 +1998,21 @@ husky@4.3.0: slash "^3.0.0" which-pm-runs "^1.0.0" -i18next-fs-backend@^1.0.7: - version "1.1.1" - resolved "https://registry.yarnpkg.com/i18next-fs-backend/-/i18next-fs-backend-1.1.1.tgz#1d8028926803f63784ffa0f2b1478fb369f92735" - integrity sha512-RFkfy10hNxJqc7MVAp5iAZq0Tum6msBCNebEe3OelOBvrROvzHUPaR8Qe10RQrOGokTm0W4vJGEJzruFkEt+hQ== +i18next-browser-languagedetector@6.1.2: + version "6.1.2" + resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-6.1.2.tgz#68565a28b929cbc98ab6a56826ef2faf0e927ff8" + integrity sha512-YDzIGHhMRvr7M+c8B3EQUKyiMBhfqox4o1qkFvt4QXuu5V2cxf74+NCr+VEkUuU0y+RwcupA238eeolW1Yn80g== + dependencies: + "@babel/runtime" "^7.14.6" -i18next@^19.7.0: - version "19.9.2" - resolved "https://registry.yarnpkg.com/i18next/-/i18next-19.9.2.tgz#ea5a124416e3c5ab85fddca2c8e3c3669a8da397" - integrity sha512-0i6cuo6ER6usEOtKajUUDj92zlG+KArFia0857xxiEHAQcUwh/RtOQocui1LPJwunSYT574Pk64aNva1kwtxZg== +i18next-http-backend@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/i18next-http-backend/-/i18next-http-backend-1.2.6.tgz#80b12e8b207814aebb3b8a74c4487dd156973bee" + integrity sha512-NeNNRofj+rR6Cw+/Elf8bCVaCiqWg2Y6F+CrmDvHiPzAW2Dtxxlk8O0na2et/rr1n3ST6rJr4nMXH/QOFuhaeA== dependencies: - "@babel/runtime" "^7.12.0" + cross-fetch "3.1.4" -i18next@^20.1.0: +i18next@20.3.2: version "20.3.2" resolved "https://registry.yarnpkg.com/i18next/-/i18next-20.3.2.tgz#5195e76b9e0848a1c198001bf6c7fc72995a55f1" integrity sha512-e8CML2R9Ng2sSQOM80wb/PrM2j8mDm84o/T4Amzn9ArVyNX5/ENWxxAXkRpZdTQNDaxKImF93Wep4mAoozFrKw== @@ -2651,20 +2633,6 @@ next-compose-plugins@2.2.1: resolved "https://registry.yarnpkg.com/next-compose-plugins/-/next-compose-plugins-2.2.1.tgz#020fc53f275a7e719d62521bef4300fbb6fde5ab" integrity sha512-OjJ+fV15FXO2uQXQagLD4C0abYErBjyjE0I0FHpOEIB8upw0hg1ldFP6cqHTJBH1cZqy96OeR3u1dJ+Ez2D4Bg== -next-i18next@8.5.1: - version "8.5.1" - resolved "https://registry.yarnpkg.com/next-i18next/-/next-i18next-8.5.1.tgz#9ec3baf31aeb27be0a878283e135c6e9557b3130" - integrity sha512-ETr6yOw69PPvbUCH2RoujgRzreTzcbSS4YrTusP5878ovBSmoah/mZ4+iUVVRU4ToeaSBZiIIJA6MtAJWGFBTw== - dependencies: - "@babel/runtime" "^7.13.17" - "@types/hoist-non-react-statics" "^3.3.1" - "@types/i18next-fs-backend" "^1.0.0" - core-js "^3" - hoist-non-react-statics "^3.2.0" - i18next "^20.1.0" - i18next-fs-backend "^1.0.7" - react-i18next "^11.8.13" - next@11.0.1: version "11.0.1" resolved "https://registry.yarnpkg.com/next/-/next-11.0.1.tgz#b8e3914d153aaf7143cb98c09bcd3c8230eeb17a" @@ -3316,7 +3284,7 @@ react-fast-compare@^3.0.1: resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== -react-i18next@^11.8.13: +react-i18next@11.11.0: version "11.11.0" resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.11.0.tgz#2f7c6cb4f81f94d1728a02d60e4bb5216709f942" integrity sha512-p1jHmoyJgDFQmyubUEjrx6kCsr1izW/C8i9pOiJy+9lJqLYwNA8sElVplm0VAnop3kH68edT0/g3wB3UvAcRCQ== @@ -3329,7 +3297,7 @@ react-is@17.0.2, "react-is@^16.8.6 || ^17.0.0": resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -react-is@^16.6.3, react-is@^16.7.0, react-is@^16.8.1: +react-is@^16.6.3, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== From 76f8de94e14584588b2268c2d42f52c7710ad1da Mon Sep 17 00:00:00 2001 From: robertsavian Date: Tue, 29 Jun 2021 13:39:53 -0500 Subject: [PATCH 2/2] Add react-i18next example --- src/{i18n.js => i18n.ts} | 0 src/utils/i18n.utils.ts | 6 ------ 2 files changed, 6 deletions(-) rename src/{i18n.js => i18n.ts} (100%) delete mode 100644 src/utils/i18n.utils.ts diff --git a/src/i18n.js b/src/i18n.ts similarity index 100% rename from src/i18n.js rename to src/i18n.ts diff --git a/src/utils/i18n.utils.ts b/src/utils/i18n.utils.ts deleted file mode 100644 index bc07a21..0000000 --- a/src/utils/i18n.utils.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; -import { AppI18nNamespaces } from 'react-i18next'; - -export const typedServerSideTranslations = (locale: string, keys: AppI18nNamespaces[]) => { - return serverSideTranslations(locale as string, keys); -};