From 05eeb7f491b0c6e7cd8147c96272c4331a2a23e9 Mon Sep 17 00:00:00 2001 From: Nafees Nazik <84864519+G3root@users.noreply.github.com> Date: Sat, 8 Oct 2022 23:24:43 +0530 Subject: [PATCH] feat: add i18n internationalization (#560) * chore: add next-i18next * feat: add i8n-config * feat: i18n config to next config * feat: wrap app with the appWithTranslation * feat: add initial dummy translation * chore: pin version * feat: add translation Co-authored-by: Deepak Prabhakara --- locales/en/common.json | 3 + next-i18next.config.js | 9 ++ next.config.js | 3 + package-lock.json | 204 ++++++++++++++++++++++++++++- package.json | 5 +- pages/_app.tsx | 4 +- pages/admin/directory-sync/new.tsx | 8 +- 7 files changed, 226 insertions(+), 10 deletions(-) create mode 100644 locales/en/common.json create mode 100644 next-i18next.config.js diff --git a/locales/en/common.json b/locales/en/common.json new file mode 100644 index 000000000..9d36bf715 --- /dev/null +++ b/locales/en/common.json @@ -0,0 +1,3 @@ +{ + "back": "Back" +} diff --git a/next-i18next.config.js b/next-i18next.config.js new file mode 100644 index 000000000..10645539d --- /dev/null +++ b/next-i18next.config.js @@ -0,0 +1,9 @@ +const path = require('path'); + +module.exports = { + i18n: { + defaultLocale: 'en', + locales: ['en'], + }, + localePath: path.resolve('./locales'), +}; diff --git a/next.config.js b/next.config.js index 93a544fc6..0ee39e3bc 100644 --- a/next.config.js +++ b/next.config.js @@ -1,7 +1,10 @@ +const { i18n } = require('./next-i18next.config'); + /** @type {import('next').NextConfig} */ module.exports = { reactStrictMode: true, + i18n, output: 'standalone', webpack: (config, { webpack, isServer }) => { if (isServer) { diff --git a/package-lock.json b/package-lock.json index f810d7351..96ca3d934 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "micromatch": "4.0.5", "next": "12.3.1", "next-auth": "4.12.2", + "next-i18next": "12.0.1", "next-mdx-remote": "4.1.0", "nodemailer": "6.8.0", "raw-body": "2.5.1", @@ -1350,6 +1351,15 @@ "@types/unist": "*" } }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/js-yaml": { "version": "4.0.5", "license": "MIT" @@ -2710,6 +2720,16 @@ "node": ">= 0.6" } }, + "node_modules/core-js": { + "version": "3.25.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.25.3.tgz", + "integrity": "sha512-y1hvKXmPHvm5B7w4ln1S4uc9eV/O5+iFExSRUimnvIph11uaizFR8LFMdONN8hG3P2pipUfX4Y/fR8rAEtcHcQ==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-js-pure": { "version": "3.24.1", "dev": true, @@ -4268,6 +4288,22 @@ "node": "*" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "dependencies": { + "void-elements": "3.1.0" + } + }, "node_modules/http-errors": { "version": "2.0.0", "license": "MIT", @@ -4304,6 +4340,33 @@ "url": "https://github.com/sponsors/typicode" } }, + "node_modules/i18next": { + "version": "21.9.2", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.9.2.tgz", + "integrity": "sha512-00fVrLQOwy45nm3OtC9l1WiLK3nJlIYSljgCt0qzTaAy65aciMdRy9GsuW+a2AtKtdg9/njUGfRH30LRupV7ZQ==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "dependencies": { + "@babel/runtime": "^7.17.2" + } + }, + "node_modules/i18next-fs-backend": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-1.1.5.tgz", + "integrity": "sha512-raTel3EfshiUXxR0gvmIoqp75jhkj8+7R1LjB006VZKPTFBbXyx6TlUVhb8Z9+7ahgpFbcQg1QWVOdf/iNzI5A==" + }, "node_modules/iconv-lite": { "version": "0.4.24", "license": "MIT", @@ -6060,6 +6123,41 @@ } } }, + "node_modules/next-i18next": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/next-i18next/-/next-i18next-12.0.1.tgz", + "integrity": "sha512-i1yLpOvokldjqnnkP4KfZtnbp2+DILlUvavzJ9rvCSu1Yk5w45IRAYrJfu20/0WDeWxea/ktYDmXw+z/2roo3g==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "dependencies": { + "@babel/runtime": "^7.18.9", + "@types/hoist-non-react-statics": "^3.3.1", + "core-js": "^3", + "hoist-non-react-statics": "^3.3.2", + "i18next": "^21.9.1", + "i18next-fs-backend": "^1.1.5", + "react-i18next": "^11.18.4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "next": ">= 10.0.0", + "react": ">= 16.8.0" + } + }, "node_modules/next-mdx-remote": { "version": "4.1.0", "license": "MPL-2.0", @@ -6907,11 +7005,31 @@ "react-dom": ">=16" } }, + "node_modules/react-i18next": { + "version": "11.18.6", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.18.6.tgz", + "integrity": "sha512-yHb2F9BiT0lqoQDt8loZ5gWP331GwctHz9tYQ8A2EIEUu+CcEdjBLQWli1USG3RdWQt3W+jqQLg/d4rrQR96LA==", + "dependencies": { + "@babel/runtime": "^7.14.5", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 19.0.0", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-syntax-highlighter": { "version": "15.5.0", @@ -8700,6 +8818,14 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -15631,6 +15757,15 @@ "@types/unist": "*" } }, + "@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "@types/js-yaml": { "version": "4.0.5" }, @@ -16454,6 +16589,11 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" }, + "core-js": { + "version": "3.25.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.25.3.tgz", + "integrity": "sha512-y1hvKXmPHvm5B7w4ln1S4uc9eV/O5+iFExSRUimnvIph11uaizFR8LFMdONN8hG3P2pipUfX4Y/fR8rAEtcHcQ==" + }, "core-js-pure": { "version": "3.24.1", "dev": true @@ -17442,6 +17582,22 @@ "highlight.js": { "version": "10.7.3" }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, + "html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "requires": { + "void-elements": "3.1.0" + } + }, "http-errors": { "version": "2.0.0", "requires": { @@ -17460,6 +17616,19 @@ "version": "8.0.1", "dev": true }, + "i18next": { + "version": "21.9.2", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.9.2.tgz", + "integrity": "sha512-00fVrLQOwy45nm3OtC9l1WiLK3nJlIYSljgCt0qzTaAy65aciMdRy9GsuW+a2AtKtdg9/njUGfRH30LRupV7ZQ==", + "requires": { + "@babel/runtime": "^7.17.2" + } + }, + "i18next-fs-backend": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-1.1.5.tgz", + "integrity": "sha512-raTel3EfshiUXxR0gvmIoqp75jhkj8+7R1LjB006VZKPTFBbXyx6TlUVhb8Z9+7ahgpFbcQg1QWVOdf/iNzI5A==" + }, "iconv-lite": { "version": "0.4.24", "requires": { @@ -18436,6 +18605,20 @@ "uuid": "^8.3.2" } }, + "next-i18next": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/next-i18next/-/next-i18next-12.0.1.tgz", + "integrity": "sha512-i1yLpOvokldjqnnkP4KfZtnbp2+DILlUvavzJ9rvCSu1Yk5w45IRAYrJfu20/0WDeWxea/ktYDmXw+z/2roo3g==", + "requires": { + "@babel/runtime": "^7.18.9", + "@types/hoist-non-react-statics": "^3.3.1", + "core-js": "^3", + "hoist-non-react-statics": "^3.3.2", + "i18next": "^21.9.1", + "i18next-fs-backend": "^1.1.5", + "react-i18next": "^11.18.4" + } + }, "next-mdx-remote": { "version": "4.1.0", "requires": { @@ -18908,11 +19091,19 @@ "goober": "^2.1.10" } }, + "react-i18next": { + "version": "11.18.6", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.18.6.tgz", + "integrity": "sha512-yHb2F9BiT0lqoQDt8loZ5gWP331GwctHz9tYQ8A2EIEUu+CcEdjBLQWli1USG3RdWQt3W+jqQLg/d4rrQR96LA==", + "requires": { + "@babel/runtime": "^7.14.5", + "html-parse-stringify": "^3.0.1" + } + }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "react-syntax-highlighter": { "version": "15.5.0", @@ -19947,6 +20138,11 @@ "unist-util-stringify-position": "^3.0.0" } }, + "void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==" + }, "webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", diff --git a/package.json b/package.json index 921718af2..23f7295b2 100644 --- a/package.json +++ b/package.json @@ -57,13 +57,14 @@ "micromatch": "4.0.5", "next": "12.3.1", "next-auth": "4.12.2", + "next-i18next": "12.0.1", "next-mdx-remote": "4.1.0", "nodemailer": "6.8.0", "raw-body": "2.5.1", - "react-hot-toast": "2.4.0", - "react-syntax-highlighter": "15.5.0", "react": "18.2.0", "react-dom": "18.2.0", + "react-hot-toast": "2.4.0", + "react-syntax-highlighter": "15.5.0", "sharp": "0.31.1", "swr": "1.3.0" }, diff --git a/pages/_app.tsx b/pages/_app.tsx index 1ab27702d..747d9fcc0 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -3,7 +3,7 @@ import type { Session } from 'next-auth'; import { SessionProvider } from 'next-auth/react'; import { useRouter } from 'next/router'; import { Toaster } from 'react-hot-toast'; - +import { appWithTranslation } from 'next-i18next'; import { AccountLayout } from '@components/layouts'; import '../styles/globals.css'; @@ -30,4 +30,4 @@ function MyApp({ ); } -export default MyApp; +export default appWithTranslation(MyApp); diff --git a/pages/admin/directory-sync/new.tsx b/pages/admin/directory-sync/new.tsx index 475a61489..63c137c3f 100644 --- a/pages/admin/directory-sync/new.tsx +++ b/pages/admin/directory-sync/new.tsx @@ -5,10 +5,13 @@ import toast from 'react-hot-toast'; import Link from 'next/link'; import { ArrowLeftIcon } from '@heroicons/react/24/outline'; import classNames from 'classnames'; +import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; import jackson from '@lib/jackson'; +import { useTranslation } from 'next-i18next'; const New: NextPage<{ providers: any }> = ({ providers }) => { + const { t } = useTranslation('common'); const router = useRouter(); const [loading, setLoading] = React.useState(false); const [directory, setDirectory] = React.useState({ @@ -62,7 +65,7 @@ const New: NextPage<{ providers: any }> = ({ providers }) => { - Back + {t('back')}

New Directory

@@ -153,12 +156,13 @@ const New: NextPage<{ providers: any }> = ({ providers }) => { ); }; -export const getServerSideProps: GetServerSideProps = async () => { +export const getServerSideProps: GetServerSideProps = async ({ locale }) => { const { directorySyncController } = await jackson(); return { props: { providers: directorySyncController.providers(), + ...(await serverSideTranslations(locale ?? '', ['common'])), }, }; };