From d136ce48bbe9f19a7b977cc23836bfa872c7d616 Mon Sep 17 00:00:00 2001 From: sriramveeraghanta Date: Mon, 9 Oct 2023 18:26:24 +0530 Subject: [PATCH] i18n setup --- web/next-i18next.config.js | 18 ++++++++ web/next.config.js | 3 +- web/package.json | 3 ++ web/pages/_app.tsx | 3 +- web/pages/index.tsx | 10 +++- web/public/locales/en/homepage.json | 3 ++ web/public/locales/fr/homepage.json | 3 ++ yarn.lock | 72 +++++++++++++++++++++++++---- 8 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 web/next-i18next.config.js create mode 100644 web/public/locales/en/homepage.json create mode 100644 web/public/locales/fr/homepage.json diff --git a/web/next-i18next.config.js b/web/next-i18next.config.js new file mode 100644 index 0000000000..c712e96c28 --- /dev/null +++ b/web/next-i18next.config.js @@ -0,0 +1,18 @@ +// @ts-check + +/** + * @type {import('next-i18next').UserConfig} + */ +module.exports = { + // https://www.i18next.com/overview/configuration-options#logging + debug: process.env.NODE_ENV === "development", + i18n: { + defaultLocale: "en", + locales: ["en", "fr"], + }, + /** To avoid issues when deploying to some paas (vercel...) */ + localePath: + typeof window === "undefined" ? require("path").resolve("./public/locales") : "/locales", + react: { useSuspense: false }, + reloadOnPrerender: process.env.NODE_ENV === "development", +}; diff --git a/web/next.config.js b/web/next.config.js index 058a68b7d2..cca3bdc9eb 100644 --- a/web/next.config.js +++ b/web/next.config.js @@ -1,5 +1,5 @@ require("dotenv").config({ path: ".env" }); - +const { i18n } = require("./next-i18next.config.js"); const { withSentryConfig } = require("@sentry/nextjs"); const path = require("path"); @@ -27,6 +27,7 @@ const nextConfig = { // this includes files from the monorepo base two directories up outputFileTracingRoot: path.join(__dirname, "../"), }, + i18n, }; if (parseInt(process.env.NEXT_PUBLIC_ENABLE_SENTRY || "0")) { diff --git a/web/package.json b/web/package.json index e0cf4efed7..c221fbc60f 100644 --- a/web/package.json +++ b/web/package.json @@ -53,6 +53,7 @@ "cmdk": "^0.2.0", "dotenv": "^16.0.3", "highlight.js": "^11.8.0", + "i18next": "^23.5.1", "js-cookie": "^3.0.1", "lodash.debounce": "^4.0.8", "lowlight": "^2.9.0", @@ -60,6 +61,7 @@ "mobx": "^6.10.0", "mobx-react-lite": "^4.0.3", "next": "12.3.2", + "next-i18next": "^14.0.3", "next-pwa": "^5.6.0", "next-themes": "^0.2.1", "nprogress": "^0.2.0", @@ -70,6 +72,7 @@ "react-dom": "18.2.0", "react-dropzone": "^14.2.3", "react-hook-form": "^7.38.0", + "react-i18next": "^13.2.2", "react-markdown": "^8.0.7", "react-moveable": "^0.54.1", "sharp": "^0.32.1", diff --git a/web/pages/_app.tsx b/web/pages/_app.tsx index b94e52d6bd..8e383e03da 100644 --- a/web/pages/_app.tsx +++ b/web/pages/_app.tsx @@ -3,6 +3,7 @@ import dynamic from "next/dynamic"; import Router from "next/router"; import { ThemeProvider } from "next-themes"; import NProgress from "nprogress"; +import { appWithTranslation } from "next-i18next"; // styles import "styles/globals.css"; import "styles/editor.css"; @@ -48,4 +49,4 @@ function MyApp({ Component, pageProps }: AppProps) { ); } -export default MyApp; +export default appWithTranslation(MyApp); diff --git a/web/pages/index.tsx b/web/pages/index.tsx index cccd32407e..7d41d6f08d 100644 --- a/web/pages/index.tsx +++ b/web/pages/index.tsx @@ -1,5 +1,9 @@ import React, { useEffect, useState } from "react"; +import type { GetStaticProps, InferGetStaticPropsType } from "next"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { useTranslation, Trans } from "next-i18next"; import Image from "next/image"; +import { useRouter } from "next/router"; import type { NextPage } from "next"; import { useTheme } from "next-themes"; import useSWR from "swr"; @@ -40,6 +44,10 @@ type EmailPasswordFormValues = { const HomePage: NextPage = observer(() => { const store: any = useMobxStore(); + // router + const router = useRouter(); + // i18 + const { t, i18n } = useTranslation("common"); // theme const { setTheme } = useTheme(); // user @@ -176,7 +184,7 @@ const HomePage: NextPage = observer(() => {

- {isResettingPassword ? "Reset your password" : "Sign in to Plane"} + {isResettingPassword ? "Reset your password" : t("homepage.sign-in-to-plane")}

{isResettingPassword ? ( diff --git a/web/public/locales/en/homepage.json b/web/public/locales/en/homepage.json new file mode 100644 index 0000000000..ad3f717940 --- /dev/null +++ b/web/public/locales/en/homepage.json @@ -0,0 +1,3 @@ +{ + "sign-in-to-plane": "Sign In to Plane" +} diff --git a/web/public/locales/fr/homepage.json b/web/public/locales/fr/homepage.json new file mode 100644 index 0000000000..b1fad1c07d --- /dev/null +++ b/web/public/locales/fr/homepage.json @@ -0,0 +1,3 @@ +{ + "sign-in-to-plane": "connectez-vous à Plane" +} diff --git a/yarn.lock b/yarn.lock index 9d18f4ceed..fad022ecba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -926,6 +926,13 @@ dependencies: regenerator-runtime "^0.14.0" +"@babel/runtime@^7.20.13", "@babel/runtime@^7.22.5": + version "7.23.1" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.1.tgz#72741dc4d413338a91dcb044a86f3c0bc402646d" + integrity sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.22.15", "@babel/template@^7.22.5": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" @@ -2462,6 +2469,14 @@ "@types/react" "*" hoist-non-react-statics "^3.3.0" +"@types/hoist-non-react-statics@^3.3.1": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#dc1e9ded53375d37603c479cc12c693b0878aa2a" + integrity sha512-YIQtIg4PKr7ZyqNPZObpxfHsHEmuB8dXCxd6qVcGuQVDK2bpsF7bYNnBJ4Nn7giuACZg+WewExgrtAJ3XnA4Xw== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + "@types/js-cookie@^3.0.2", "@types/js-cookie@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-3.0.3.tgz#d6bfbbdd0c187354ca555213d1962f6d0691ff4e" @@ -3456,6 +3471,11 @@ core-js-compat@^3.31.0: dependencies: browserslist "^4.21.10" +core-js@^3: + version "3.33.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.33.0.tgz#70366dbf737134761edb017990cf5ce6c6369c40" + integrity sha512-HoZr92+ZjFEKar5HS6MC776gYslNOKHt75mEBKWKnPeFDpZ6nH5OeF3S6HFT1mUAUZKrzkez05VboaX8myjSuw== + cosmiconfig@^7.0.0: version "7.1.0" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" @@ -4878,6 +4898,13 @@ hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react- dependencies: react-is "^16.7.0" +html-parse-stringify@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2" + integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg== + dependencies: + void-elements "3.1.0" + https-proxy-agent@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" @@ -4886,6 +4913,18 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" +i18next-fs-backend@^2.1.5: + version "2.2.0" + resolved "https://registry.yarnpkg.com/i18next-fs-backend/-/i18next-fs-backend-2.2.0.tgz#016c865344632a666ea80653deae466fbfa6042c" + integrity sha512-VOPHhdDX0M/csRqEw+9Ectpf6wvTIg1MZDfAHxc3JKnAlJz7fcZSAKAeyDohOq0xuLx57esYpJopIvBaRb0Bag== + +i18next@^23.5.1: + version "23.5.1" + resolved "https://registry.yarnpkg.com/i18next/-/i18next-23.5.1.tgz#7f7c35ffaa907618d9489f106d5006b09fbca3d3" + integrity sha512-JelYzcaCoFDaa+Ysbfz2JsGAKkrHiMG6S61+HLBUEIPaF40WMwW9hCPymlQGrP+wWawKxKPuSuD71WZscCsWHg== + dependencies: + "@babel/runtime" "^7.22.5" + idb@^7.0.1: version "7.1.1" resolved "https://registry.yarnpkg.com/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b" @@ -6021,6 +6060,17 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +next-i18next@^14.0.3: + version "14.0.3" + resolved "https://registry.yarnpkg.com/next-i18next/-/next-i18next-14.0.3.tgz#9c17e69483b3af4172b15454af2ef92c5f79be48" + integrity sha512-FtnjRMfhlamk8YyeyWqd+pndNL+3er83iMZnH4M4mhiGA93l0+vtBUvuObgOAMHDJGLLB2SS2xOOZq69oiJh7A== + dependencies: + "@babel/runtime" "^7.20.13" + "@types/hoist-non-react-statics" "^3.3.1" + core-js "^3" + hoist-non-react-statics "^3.3.2" + i18next-fs-backend "^2.1.5" + next-images@^1.8.5: version "1.8.5" resolved "https://registry.yarnpkg.com/next-images/-/next-images-1.8.5.tgz#2eb5535bb1d6c58a5c4e03bc3be6c72c8a053a45" @@ -6628,20 +6678,13 @@ prosemirror-menu@^1.2.1: prosemirror-history "^1.0.0" prosemirror-state "^1.0.0" -prosemirror-model@^1.0.0, prosemirror-model@^1.16.0, prosemirror-model@^1.18.1, prosemirror-model@^1.8.1: +prosemirror-model@1.18.1, prosemirror-model@^1.0.0, prosemirror-model@^1.16.0, prosemirror-model@^1.18.1, prosemirror-model@^1.19.0, prosemirror-model@^1.8.1: version "1.18.1" resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.18.1.tgz#1d5d6b6de7b983ee67a479dc607165fdef3935bd" integrity sha512-IxSVBKAEMjD7s3n8cgtwMlxAXZrC7Mlag7zYsAKDndAqnDScvSmp/UdnRTV/B33lTCVU3CCm7dyAn/rVVD0mcw== dependencies: orderedmap "^2.0.0" -prosemirror-model@^1.19.0: - version "1.19.3" - resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.19.3.tgz#f0d55285487fefd962d0ac695f716f4ec6705006" - integrity sha512-tgSnwN7BS7/UM0sSARcW+IQryx2vODKX4MI7xpqY2X+iaepJdKBPc7I4aACIsDV/LTaTjt12Z56MhDr9LsyuZQ== - dependencies: - orderedmap "^2.0.0" - prosemirror-schema-basic@^1.2.0: version "1.2.2" resolved "https://registry.yarnpkg.com/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.2.tgz#6695f5175e4628aab179bf62e5568628b9cfe6c7" @@ -6826,6 +6869,14 @@ react-hook-form@^7.38.0: resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.46.1.tgz#39347dbff19d980cb41087ac32a57abdc6045bb3" integrity sha512-0GfI31LRTBd5tqbXMGXT1Rdsv3rnvy0FjEk8Gn9/4tp6+s77T7DPZuGEpBRXOauL+NhyGT5iaXzdIM2R6F/E+w== +react-i18next@^13.2.2: + version "13.2.2" + resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-13.2.2.tgz#b1e78ed66a54f4bc819616f68b98221e1b1a1936" + integrity sha512-+nFUkbRByFwnrfDcYqvzBuaeZb+nACHx+fAWN/pZMddWOCJH5hoc21+Sa/N/Lqi6ne6/9wC/qRGOoQhJa6IkEQ== + dependencies: + "@babel/runtime" "^7.22.5" + html-parse-stringify "^3.0.1" + react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -8219,6 +8270,11 @@ vfile@^5.0.0: unist-util-stringify-position "^3.0.0" vfile-message "^3.0.0" +void-elements@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" + integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w== + w3c-keyname@^2.2.0: version "2.2.8" resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz#7b17c8c6883d4e8b86ac8aba79d39e880f8869c5"