From 9202b8a9d41f88d68760917edc0335cd2f4c3553 Mon Sep 17 00:00:00 2001 From: Hugomndez Date: Sun, 14 Aug 2022 22:32:08 -0500 Subject: [PATCH 1/8] Add i18n locales --- next.config.js | 4 ++++ src/pages/_document.tsx | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/next.config.js b/next.config.js index 2059457..5ba3214 100644 --- a/next.config.js +++ b/next.config.js @@ -4,6 +4,10 @@ const generateRobotsTxt = require('./src/utils/generate-robots-txt'); const nextConfig = { reactStrictMode: true, swcMinify: true, + i18n: { + locales: ['en-US', 'es-MX'], + defaultLocale: 'en-US', + }, experimental: { images: { allowFutureImage: true, diff --git a/src/pages/_document.tsx b/src/pages/_document.tsx index 5e490e8..c717c08 100644 --- a/src/pages/_document.tsx +++ b/src/pages/_document.tsx @@ -2,7 +2,7 @@ import { Head, Html, Main, NextScript } from 'next/document'; export default function Document() { return ( - + Date: Sun, 14 Aug 2022 22:32:50 -0500 Subject: [PATCH 2/8] Add Language API --- package.json | 2 ++ src/pages/api/language/index.ts | 59 +++++++++++++++++++++++++++++++++ yarn.lock | 10 ++++++ 3 files changed, 71 insertions(+) create mode 100644 src/pages/api/language/index.ts diff --git a/package.json b/package.json index bc4cf4e..d765a1e 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "lint": "next lint" }, "dependencies": { + "cookie": "0.5.0", "critters": "0.0.16", "next": "12.2.4", "next-auth": "4.10.3", @@ -34,6 +35,7 @@ "react-dom": "18.2.0" }, "devDependencies": { + "@types/cookie": "0.5.1", "@types/node": "18.7.1", "@types/react": "18.0.17", "@types/react-dom": "18.0.6", diff --git a/src/pages/api/language/index.ts b/src/pages/api/language/index.ts new file mode 100644 index 0000000..1c00c2d --- /dev/null +++ b/src/pages/api/language/index.ts @@ -0,0 +1,59 @@ +import { serialize, CookieSerializeOptions } from 'cookie'; +import { NextApiHandler, NextApiResponse } from 'next'; + +// Sadly, getting the locale info in API Routes is not officially supported. +// It should match next.config::i18n.defaultLocale +const DEFAULT_LOCALE = 'en-US'; + +// Learn more: https://nextjs.org/docs/advanced-features/i18n-routing#leveraging-the-next_locale-cookie +const PREFERRED_LOCALE_COOKIE = 'NEXT_LOCALE'; + +const language: NextApiHandler = (request, response) => { + if (request.method === 'GET') { + const preferredLocale = request.cookies[PREFERRED_LOCALE_COOKIE] || ''; + + return response.status(200).json({ + preferredLocale, + defaultLocale: DEFAULT_LOCALE, + }); + } + + if (request.method === 'POST') { + const newPreferredLocale = request.body.preferredLocale as + | string + | undefined; + + // For this page, we don't care setting an invalid value. + // worst case: the value is ignored and Next.js defaults to defaultLocale. Not critical. + setCookie(response, PREFERRED_LOCALE_COOKIE, newPreferredLocale, { + // Heads-up: the NEXT_LOCALE must be set to the `/` path + path: '/', + }); + + // 307 (temporary) redirect to homepage + response.redirect('/'); + return response.end(); + } + + // Not other supported method + response.status(405).end(); +}; + +function setCookie( + res: NextApiResponse, + name: string, + value: unknown, + options: CookieSerializeOptions = {} +) { + const stringValue = + typeof value === 'object' ? 'j:' + JSON.stringify(value) : String(value); + + if ('maxAge' in options) { + options.expires = new Date(Date.now() + options.maxAge!); + options.maxAge! /= 1000; + } + + res.setHeader('Set-Cookie', serialize(name, String(stringValue), options)); +} + +export default language; diff --git a/yarn.lock b/yarn.lock index 9c89dfa..905a97d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -166,6 +166,11 @@ dependencies: tslib "^2.4.0" +"@types/cookie@^0.5.1": + version "0.5.1" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.5.1.tgz#b29aa1f91a59f35e29ff8f7cb24faf1a3a750554" + integrity sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g== + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -415,6 +420,11 @@ cookie@^0.4.1: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== +cookie@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + core-js-pure@^3.20.2: version "3.23.5" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.23.5.tgz#23daaa9af9230e50f10b0fa4b8e6b87402be4c33" From 127a04c3870734b38b8732aa3e89eb80590e1a56 Mon Sep 17 00:00:00 2001 From: Hugomndez Date: Sun, 14 Aug 2022 23:09:17 -0500 Subject: [PATCH 3/8] Add LocaleOptions component --- .../LocaleOptions/LocaleOptions.tsx | 22 +++++++++++++++++++ src/components/LocaleOptions/index.ts | 1 + src/components/index.ts | 1 + src/layout/Footer/Footer.tsx | 2 ++ 4 files changed, 26 insertions(+) create mode 100644 src/components/LocaleOptions/LocaleOptions.tsx create mode 100644 src/components/LocaleOptions/index.ts diff --git a/src/components/LocaleOptions/LocaleOptions.tsx b/src/components/LocaleOptions/LocaleOptions.tsx new file mode 100644 index 0000000..075f5d2 --- /dev/null +++ b/src/components/LocaleOptions/LocaleOptions.tsx @@ -0,0 +1,22 @@ +import { useRouter } from 'next/router'; + +const LocaleOptions = () => { + const { locale, locales } = useRouter(); + + // Locales aren't configured + if (locale == undefined || locales == undefined) return null; + + return ( + <> +

Language:

+ {locales.map(loc => ( +
+ + +
+ ))} + + ); +}; + +export default LocaleOptions; diff --git a/src/components/LocaleOptions/index.ts b/src/components/LocaleOptions/index.ts new file mode 100644 index 0000000..774c275 --- /dev/null +++ b/src/components/LocaleOptions/index.ts @@ -0,0 +1 @@ +export { default as LocaleOptions } from './LocaleOptions'; diff --git a/src/components/index.ts b/src/components/index.ts index 1dc8de9..051a59f 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,4 +1,5 @@ export { Exchange } from './Exchange'; +export { LocaleOptions } from './LocaleOptions'; export { LoginLogout } from './LoginLogout'; export { Plans } from './Plans'; export { Poster } from './Poster'; diff --git a/src/layout/Footer/Footer.tsx b/src/layout/Footer/Footer.tsx index 9689332..8edb5a8 100644 --- a/src/layout/Footer/Footer.tsx +++ b/src/layout/Footer/Footer.tsx @@ -1,5 +1,6 @@ import Image from 'next/future/image'; import logoFooter from '../../assets/images/logo-footer.svg'; +import { LocaleOptions } from '../../components'; import styles from './Footer.module.css'; const Footer = () => { @@ -24,6 +25,7 @@ const Footer = () => { +
Logo Batatabit 2021
From 67ee52b50a3f3b74f62981babf53f768c02bdafc Mon Sep 17 00:00:00 2001 From: Hugomndez Date: Mon, 15 Aug 2022 10:55:29 -0500 Subject: [PATCH 4/8] Add misc change --- src/utils/generate-robots-txt.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/utils/generate-robots-txt.js b/src/utils/generate-robots-txt.js index f626822..ec0b713 100644 --- a/src/utils/generate-robots-txt.js +++ b/src/utils/generate-robots-txt.js @@ -5,19 +5,17 @@ const crawlableRobotsTxt = `User-agent: *\nAllow: /`; const uncrawlableRobotsTxt = `User-agent: *\nDisallow: /`; function generateRobotsTxt() { - // Create a non-crawlable robots.txt in non-production environments const robotsTxt = process.env.VERCEL_ENV === 'production' ? crawlableRobotsTxt : uncrawlableRobotsTxt; - // Create robots.txt file fs.writeFileSync('public/robots.txt', robotsTxt); console.log( `Generated a ${ process.env.VERCEL_ENV === 'production' ? 'crawlable' : 'non-crawlable' - } public/robots.txt` + } robots.txt` ); } From 6aa7ed17336742ab5b3a1848f2480e921ff33b22 Mon Sep 17 00:00:00 2001 From: Hugomndez Date: Mon, 15 Aug 2022 10:56:04 -0500 Subject: [PATCH 5/8] Add next-i18next --- next-i18next.config.js | 6 ++++ next.config.js | 6 ++-- package.json | 1 + src/pages/_app.tsx | 3 +- yarn.lock | 81 +++++++++++++++++++++++++++++++++++++----- 5 files changed, 84 insertions(+), 13 deletions(-) create mode 100644 next-i18next.config.js diff --git a/next-i18next.config.js b/next-i18next.config.js new file mode 100644 index 0000000..3f86991 --- /dev/null +++ b/next-i18next.config.js @@ -0,0 +1,6 @@ +module.exports = { + i18n: { + locales: ['en-US', 'es-MX'], + defaultLocale: 'en-US', + }, +}; diff --git a/next.config.js b/next.config.js index 5ba3214..c8b56f8 100644 --- a/next.config.js +++ b/next.config.js @@ -1,13 +1,11 @@ /** @type {import('next').NextConfig} */ const generateRobotsTxt = require('./src/utils/generate-robots-txt'); +const { i18n } = require('./next-i18next.config'); const nextConfig = { reactStrictMode: true, swcMinify: true, - i18n: { - locales: ['en-US', 'es-MX'], - defaultLocale: 'en-US', - }, + i18n, experimental: { images: { allowFutureImage: true, diff --git a/package.json b/package.json index d765a1e..7c8cca6 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "critters": "0.0.16", "next": "12.2.4", "next-auth": "4.10.3", + "next-i18next": "11.3.0", "react": "18.2.0", "react-dom": "18.2.0" }, diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 9f8f88e..c1fce28 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,4 +1,5 @@ import { SessionProvider as AuthProvider } from 'next-auth/react'; +import { appWithTranslation } from 'next-i18next'; import type { AppProps } from 'next/app'; import Head from 'next/head'; import '../styles/globals.css'; @@ -17,4 +18,4 @@ function MyApp({ Component, pageProps }: AppProps) { ); } -export default MyApp; +export default appWithTranslation(MyApp); diff --git a/yarn.lock b/yarn.lock index 905a97d..841f0cd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,7 +10,7 @@ core-js-pure "^3.20.2" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.10.2", "@babel/runtime@^7.16.3", "@babel/runtime@^7.18.9": +"@babel/runtime@^7.10.2", "@babel/runtime@^7.14.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.6", "@babel/runtime@^7.18.9": version "7.18.9" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a" integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw== @@ -166,11 +166,19 @@ dependencies: tslib "^2.4.0" -"@types/cookie@^0.5.1": +"@types/cookie@0.5.1": version "0.5.1" resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.5.1.tgz#b29aa1f91a59f35e29ff8f7cb24faf1a3a750554" integrity sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g== +"@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/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -415,21 +423,26 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + cookie@^0.4.1: version "0.4.2" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== -cookie@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" - integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== - core-js-pure@^3.20.2: version "3.23.5" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.23.5.tgz#23daaa9af9230e50f10b0fa4b8e6b87402be4c33" integrity sha512-8t78LdpKSuCq4pJYCYk8hl7XEkAX+BP16yRIwL3AanTksxuEf7CM83vRyctmiEL8NDZ3jpUcv56fk9/zG3aIuw== +core-js@^3: + version "3.24.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.24.1.tgz#cf7724d41724154010a6576b7b57d94c5d66e64f" + integrity sha512-0QTBSYSUZ6Gq21utGzkfITDylE8jWC9Ne1D2MrhvlsZBI1x39OdDIVbzSqtgMndIy6BlHxBXpMGqzZmnztg2rg== + critters@0.0.16: version "0.0.16" resolved "https://registry.yarnpkg.com/critters/-/critters-0.0.16.tgz#ffa2c5561a65b43c53b940036237ce72dcebfe93" @@ -1050,6 +1063,32 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: + 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" + +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" + +i18next-fs-backend@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/i18next-fs-backend/-/i18next-fs-backend-1.1.5.tgz#dcbd8227b1c1e4323b3c40e269d4762e8313d9e5" + integrity sha512-raTel3EfshiUXxR0gvmIoqp75jhkj8+7R1LjB006VZKPTFBbXyx6TlUVhb8Z9+7ahgpFbcQg1QWVOdf/iNzI5A== + +i18next@^21.8.13: + version "21.9.0" + resolved "https://registry.yarnpkg.com/i18next/-/i18next-21.9.0.tgz#b63ebb0d4e1b23709951ca4774dc19d2ffac9553" + integrity sha512-B+6/yd7rCpJidyPuBaEApUECx7G8Ai6+tqYhrChsY4MmQqJhG7qJ4eT6Lm1OnRhieVelEtfxh4aAQktdNVZtDA== + dependencies: + "@babel/runtime" "^7.17.2" + ignore@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" @@ -1355,6 +1394,19 @@ next-auth@4.10.3: preact-render-to-string "^5.1.19" uuid "^8.3.2" +next-i18next@^11.3.0: + version "11.3.0" + resolved "https://registry.yarnpkg.com/next-i18next/-/next-i18next-11.3.0.tgz#bfce51d8df07fb5cd61097423eeb7d744e09ae25" + integrity sha512-xl0oIRtiVrk9ZaWBRUbNk/prva4Htdu59o9rFWzd9ax/KemaDVuTTuBZTQMkmXohUQk/MJ7w1rV/mICL6TzyGw== + dependencies: + "@babel/runtime" "^7.18.6" + "@types/hoist-non-react-statics" "^3.3.1" + core-js "^3" + hoist-non-react-statics "^3.3.2" + i18next "^21.8.13" + i18next-fs-backend "^1.1.4" + react-i18next "^11.18.0" + next@12.2.4: version "12.2.4" resolved "https://registry.yarnpkg.com/next/-/next-12.2.4.tgz#88f7a7a4cd76063704cda28b3b07c4217b8928b0" @@ -1647,7 +1699,15 @@ react-dom@18.2.0: loose-envify "^1.1.0" scheduler "^0.23.0" -react-is@^16.13.1: +react-i18next@^11.18.0: + version "11.18.3" + resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.18.3.tgz#50211810bcc9fdea2d70c8aefdfff5f1eb39a923" + integrity sha512-EttTX31HbqzZymUM3SIrMPuvamfSXFZVsDHm/ZAqoDfTLjhzlwyxqfbDNxcKNAGOi2mjZaXfR7hSNMlvLNpB/g== + dependencies: + "@babel/runtime" "^7.14.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" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -1924,6 +1984,11 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== +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== + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" From 22a7fc4a95b08b076b1ccac0d3ab4da561aaf132 Mon Sep 17 00:00:00 2001 From: Hugomndez Date: Mon, 15 Aug 2022 10:57:32 -0500 Subject: [PATCH 6/8] Fix i18 translation --- src/middleware.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/middleware.ts diff --git a/src/middleware.ts b/src/middleware.ts new file mode 100644 index 0000000..e757114 --- /dev/null +++ b/src/middleware.ts @@ -0,0 +1,12 @@ +import type { NextRequest } from 'next/server'; +import { NextResponse } from 'next/server'; + +// TODO: Remove this based on resolution for https://github.com/vercel/next.js/issues/35185 +export function middleware(req: NextRequest) { + // Only execute for specific pathnames if running this needs to run for at "/pages" to avoid running for all requests + if (req.method === 'POST' && req.nextUrl.pathname === '/') { + // Redirect to the correct static page using semantic 303 + // ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/303 + return NextResponse.redirect(req.nextUrl.clone(), 303); + } +} From 7de857df2d8edd03dc39bc42484a067d9221ac5e Mon Sep 17 00:00:00 2001 From: Hugomndez Date: Mon, 15 Aug 2022 10:58:31 -0500 Subject: [PATCH 7/8] Add translation json's --- public/locales/en-US/common.json | 5 +++ public/locales/en-US/exchange.json | 7 +++ public/locales/en-US/header.json | 5 +++ public/locales/en-US/plans.json | 25 +++++++++++ public/locales/en-US/poster.json | 3 ++ public/locales/en-US/productDetails.json | 22 ++++++++++ public/locales/es-MX/common.json | 5 +++ public/locales/es-MX/exchange.json | 7 +++ public/locales/es-MX/header.json | 5 +++ public/locales/es-MX/plans.json | 25 +++++++++++ public/locales/es-MX/poster.json | 3 ++ public/locales/es-MX/productDetails.json | 22 ++++++++++ src/components/Exchange/Exchange.tsx | 19 ++++---- .../LocaleOptions/LocaleOptions.tsx | 4 +- src/components/LoginLogout/LoginLogout.tsx | 6 ++- src/components/Plans/Plans.tsx | 39 ++++++++--------- src/components/Poster/Poster.tsx | 4 +- src/components/ProductDetail/index.ts | 1 - .../ProductDetails.module.css} | 0 .../ProductDetails.tsx} | 43 +++++++------------ src/components/ProductDetails/index.ts | 1 + src/components/index.ts | 2 +- src/layout/Header/Header.tsx | 13 +++--- src/pages/index.tsx | 21 ++++++++- 24 files changed, 212 insertions(+), 75 deletions(-) create mode 100644 public/locales/en-US/common.json create mode 100644 public/locales/en-US/exchange.json create mode 100644 public/locales/en-US/header.json create mode 100644 public/locales/en-US/plans.json create mode 100644 public/locales/en-US/poster.json create mode 100644 public/locales/en-US/productDetails.json create mode 100644 public/locales/es-MX/common.json create mode 100644 public/locales/es-MX/exchange.json create mode 100644 public/locales/es-MX/header.json create mode 100644 public/locales/es-MX/plans.json create mode 100644 public/locales/es-MX/poster.json create mode 100644 public/locales/es-MX/productDetails.json delete mode 100644 src/components/ProductDetail/index.ts rename src/components/{ProductDetail/ProductDetail.module.css => ProductDetails/ProductDetails.module.css} (100%) rename src/components/{ProductDetail/ProductDetail.tsx => ProductDetails/ProductDetails.tsx} (53%) create mode 100644 src/components/ProductDetails/index.ts diff --git a/public/locales/en-US/common.json b/public/locales/en-US/common.json new file mode 100644 index 0000000..fb1976f --- /dev/null +++ b/public/locales/en-US/common.json @@ -0,0 +1,5 @@ +{ + "language": "Language", + "signIn": "Sign In", + "signOut": "Sign Out" +} diff --git a/public/locales/en-US/exchange.json b/public/locales/en-US/exchange.json new file mode 100644 index 0000000..fb25e22 --- /dev/null +++ b/public/locales/en-US/exchange.json @@ -0,0 +1,7 @@ +{ + "title": "We make all exchange rates visible.", + "subTitle": "We bring real-time information from the world's most important exchange houses and currencies.", + "coins": "Coins", + "commissions": "Commissions", + "updated": "Updated" +} diff --git a/public/locales/en-US/header.json b/public/locales/en-US/header.json new file mode 100644 index 0000000..468539a --- /dev/null +++ b/public/locales/en-US/header.json @@ -0,0 +1,5 @@ +{ + "title": "The next revolution in cryptocurrency exchange.", + "subTitle": "Batatabit helps you navigate between the different prices and trends.", + "callToAction": "See Our Plans" +} diff --git a/public/locales/en-US/plans.json b/public/locales/en-US/plans.json new file mode 100644 index 0000000..347e808 --- /dev/null +++ b/public/locales/en-US/plans.json @@ -0,0 +1,25 @@ +{ + "title": "Choose the plan that best suits you.", + "subTitle": "Any plan gives you full access to our platform.", + "recommended": "Recommended", + "plans": [ + { + "payment": "Monthly payment", + "price": 19, + "description": "Limited access", + "callToAction": "Choose this" + }, + { + "payment": "Annual payment", + "price": 99, + "description": "You save $129 compared to the monthly plan.", + "callToAction": "Choose this" + }, + { + "payment": "Annual payment", + "price": 199, + "description": "Unlimited access", + "callToAction": "Choose this" + } + ] +} diff --git a/public/locales/en-US/poster.json b/public/locales/en-US/poster.json new file mode 100644 index 0000000..02e82a4 --- /dev/null +++ b/public/locales/en-US/poster.json @@ -0,0 +1,3 @@ +{ + "title": "Subscribe Today" +} diff --git a/public/locales/en-US/productDetails.json b/public/locales/en-US/productDetails.json new file mode 100644 index 0000000..229b146 --- /dev/null +++ b/public/locales/en-US/productDetails.json @@ -0,0 +1,22 @@ +{ + "title": "We create a product like no other.", + "subTitle": "Reliable and designed for your daily use.", + "details": [ + { + "name": "Real time", + "description": "Our API takes minute-by-minute information on the rates that most determine behavior." + }, + { + "name": "There are no hidden fees", + "description": "Neither in the purchase nor at the time of exit, Batabit always shows you the real cost of what you are purchasing." + }, + { + "name": "Compare currencies", + "description": "Neither in the purchase nor at the time of exit, Batabit always shows you the real cost of what you are purchasing." + }, + { + "name": "Reliable information", + "description": "Our sources are 100% verified and we continue to audit their content as they update." + } + ] +} diff --git a/public/locales/es-MX/common.json b/public/locales/es-MX/common.json new file mode 100644 index 0000000..ddb65b8 --- /dev/null +++ b/public/locales/es-MX/common.json @@ -0,0 +1,5 @@ +{ + "language": "Idioma", + "signIn": "Ingresar", + "signOut": "Salir" +} diff --git a/public/locales/es-MX/exchange.json b/public/locales/es-MX/exchange.json new file mode 100644 index 0000000..8213fac --- /dev/null +++ b/public/locales/es-MX/exchange.json @@ -0,0 +1,7 @@ +{ + "title": "Visibilizamos todas las tasas de cambio.", + "subTitle": "Traemos información en tiempo real de las casas de cambio y las monedas más importantes del mundo.", + "coins": "Monedas", + "commissions": "Comisiones", + "updated": "Actualizado" +} diff --git a/public/locales/es-MX/header.json b/public/locales/es-MX/header.json new file mode 100644 index 0000000..c457ec4 --- /dev/null +++ b/public/locales/es-MX/header.json @@ -0,0 +1,5 @@ +{ + "title": "La próxima revolución en el intercambio de criptomonedas.", + "subTitle": "Batatabit te ayuda a navegar entre los diferentes precios y tendencias.", + "callToAction": "Conoce Nuestros Planes" +} diff --git a/public/locales/es-MX/plans.json b/public/locales/es-MX/plans.json new file mode 100644 index 0000000..570bea7 --- /dev/null +++ b/public/locales/es-MX/plans.json @@ -0,0 +1,25 @@ +{ + "title": "Escoge el plan que mejor se ajuste a ti.", + "subTitle": "Cualquier plan te da acceso completo a nuestra plataforma.", + "recommended": "Recomendado", + "plans": [ + { + "payment": "Pago mensual", + "price": 19, + "description": "Acceso limitado", + "callToAction": "Escoger este" + }, + { + "payment": "Pago anual", + "price": 99, + "description": "Ahorras $129 comparado al plan mensual.", + "callToAction": "Escoger este" + }, + { + "payment": "Pago anual", + "price": 199, + "description": "Acceso ilimitado", + "callToAction": "Escoger este" + } + ] +} diff --git a/public/locales/es-MX/poster.json b/public/locales/es-MX/poster.json new file mode 100644 index 0000000..92a1558 --- /dev/null +++ b/public/locales/es-MX/poster.json @@ -0,0 +1,3 @@ +{ + "title": "Conócelo Hoy" +} diff --git a/public/locales/es-MX/productDetails.json b/public/locales/es-MX/productDetails.json new file mode 100644 index 0000000..5096b60 --- /dev/null +++ b/public/locales/es-MX/productDetails.json @@ -0,0 +1,22 @@ +{ + "title": "Creamos un producto sin comparación.", + "subTitle": "Confiable y diseñado para su uso diario.", + "details": [ + { + "name": "Tiempo real", + "description": "Nuestra API toma información minuto a minuto sobre las tasas que más determinan el comportamiento." + }, + { + "name": "No hay tasas escondidas", + "description": "Ni en la compra o al momento de exit, Batabit siempre te muestra el costo real de lo que estás adquiriendo." + }, + { + "name": "Compara monedas", + "description": "Ni en la compra o al momento de exit, Batabit siempre te muestra el costo real de lo que estás adquiriendo." + }, + { + "name": "Información confiable", + "description": "Nuestras fuentes están 100% verificadas y continuamos auditando su contenido mientras actualizan." + } + ] +} diff --git a/src/components/Exchange/Exchange.tsx b/src/components/Exchange/Exchange.tsx index 444f640..d2d0995 100644 --- a/src/components/Exchange/Exchange.tsx +++ b/src/components/Exchange/Exchange.tsx @@ -1,3 +1,4 @@ +import { useTranslation } from 'next-i18next'; import Image from 'next/future/image'; import trendingDown from '../../assets/icons/trending-down.svg'; import trendingUp from '../../assets/icons/trending-up.svg'; @@ -6,23 +7,19 @@ import { useDate } from '../../hooks'; import styles from './Exchange.module.css'; const Exchange = () => { + const { t } = useTranslation('exchange'); const date = useDate(); return (
-

- Visibilizamos todas las tasas de cambio. -

-

- Traemos información en tiempo real de las casas de cambio y las - monedas más importantes del mundo. -

+

{t('title')}

+

{t('subTitle')}

-

Monedas

+

{t('coins')}

@@ -93,12 +90,12 @@ const Exchange = () => {

- Actualizado: {date} + {t('updated')}: {date}

-

Comisiones

+

{t('commissions')}

@@ -137,7 +134,7 @@ const Exchange = () => {

- Actualizado: {date} + {t('updated')}: {date}

diff --git a/src/components/LocaleOptions/LocaleOptions.tsx b/src/components/LocaleOptions/LocaleOptions.tsx index 075f5d2..33ec7c1 100644 --- a/src/components/LocaleOptions/LocaleOptions.tsx +++ b/src/components/LocaleOptions/LocaleOptions.tsx @@ -1,14 +1,16 @@ +import { useTranslation } from 'next-i18next'; import { useRouter } from 'next/router'; const LocaleOptions = () => { const { locale, locales } = useRouter(); + const { t } = useTranslation('common'); // Locales aren't configured if (locale == undefined || locales == undefined) return null; return ( <> -

Language:

+

{t('language')}:

{locales.map(loc => ( diff --git a/src/components/LoginLogout/LoginLogout.tsx b/src/components/LoginLogout/LoginLogout.tsx index 408a8fd..f70ebf3 100644 --- a/src/components/LoginLogout/LoginLogout.tsx +++ b/src/components/LoginLogout/LoginLogout.tsx @@ -1,16 +1,18 @@ import { signIn, signOut, useSession } from 'next-auth/react'; +import { useTranslation } from 'next-i18next'; import styles from './LoginLogout.module.css'; const LoginLogout = () => { const { data: session, status } = useSession(); // Obteniendo status const loading = status === 'loading'; + const { t } = useTranslation('common'); if (loading) return null; // if loading don't show anything if (!session) { return ( ); } @@ -19,7 +21,7 @@ const LoginLogout = () => { <> {session.user?.name} ); diff --git a/src/components/Plans/Plans.tsx b/src/components/Plans/Plans.tsx index b8bfb98..bf86817 100644 --- a/src/components/Plans/Plans.tsx +++ b/src/components/Plans/Plans.tsx @@ -1,28 +1,27 @@ +import { useTranslation } from 'next-i18next'; import Image from 'next/future/image'; import orangeRightArrow from '../../assets/icons/orange-right-arrow.svg'; import styles from './Plans.module.css'; const Plans = () => { + const { t } = useTranslation('plans'); + return (
-

- Escoge el plan que mejor se ajuste a ti. -

-

- Cualquier plan te da acceso completo a nuestra plataforma. -

+

{t('title')}

+

{t('subTitle')}

-

Pago mensual

+

{t('plans.0.payment')}

- $ 19 + $ {t('plans.0.price')}

-

* Acceso limitado.

+

* {t('plans.0.description')}

-

Recomendado

+

{t('recommended')}

-

Pago anual

+

{t('plans.1.payment')}

- $ 99 -

-

- * Ahorras $129 comparado al plan mensual. + $ {t('plans.1.price')}

+

* {t('plans.1.description')}

-

Pago anual

+

{t('plans.2.payment')}

- $ 199 + $ {t('plans.2.price')}

-

* Acceso ilimitado.

+

* {t('plans.2.description')}

- ))} - + ))} */} + {locales.map((loc, index) => { + return ( +
+ + {loc} + +
+ ); + })} +
); };