rmQo5ts9WsHYP1;3gEq;NV*@1HT$S!z^6Gg!%#Kf6YDN@vq*{$ zHPc|WuuonZQ}#!;S1+4_ k+y*XKylVVj!>0L9T}DY z@4ZtW{ouW4MuM)r+$d$jk0BXWf$P(n#Go@Q^#1pM`B9eHs6vM8@MouNkihuc7j2Mw z=fUP0z|^g_kRH1FH892ya2nK;nh1UhWSacNUl+@LqMe#0_=5o%qs`<|98)m%n{V@} z!+{|S13+y#DIJXB!NL#;J}V`z{AW)gM@yB0<`07DGya;E63lcuM0FBHISO0_%ZVya zlk-T^KX#~;1_@n^ow7yA#q2E^`QUs09A$J&ig;dWWy9xN%9E5qjv7sVC{(`Xu~ {Bv~b87b!tR#am66OpK<=imy7$&zkME3mi{Fk1kMDgML-H>d|r^! z(ei2DpckW$zWw*K;baBakXEKzbHkUq1*m&R#4>GT-pvTpl|h=VKY05FL97RHv$*2G zwdZgAS$-~~$_)DX-=!24AT6?j9pYRmAb@-1t#648u9nA9hv_&9T;^jSK hX4Z}6AY }={Z_)HjztGN)|2Be}XwAG?N4Q zbmdVH_qADyTVsQ6{&+@YR`XEg0l<{U1<#>=(477p^!DG;NS>fsI%c>$Fe-ef3Lb7l zYDL$x)$k-&ELh+{JsbJXOGx&eIy%MR2kc$wFa0~G!oBPn19CnbsV#GXTJg?E%d2yZ z-pM-JrVdDCfO1d_N1^tA_{v{{yTW8f&c=yLIgl@#2QvDAUXTw+=^ZYm;QHfI-~vs@ zdU|=k2ge7>RcDB_8E017IX!_gfE@<$Gpuu5DX(flN}B=|A72FDFBz6C(KqKn@BQnd zl!EUAz4mn1JFggvATbO8#+v>CZ;@6W3%Q=Xmd+G{1Nu)KNS$^?#?2$APAztq3Q2=B zzy1YD!Rb#xoi>md;2f3b$AJ%@$p7H088gLBU)R)s%s{2Pcmy%1PJ;jz0W|p@kgtUX zi_%OBUW|vRxak>F)4zTH64#SjA3;s^pN)`~(?o(%>)uRAbiEg&yHtw7U1kcDLaKfU zw8#G4-=V!y;oxqb)B$K=mmUyx{gWkghdE%*DgUp}JvHWACMEyx>3@9z(u8qNKPn;a zV2lAaNx+Zr7#B=SQdn3>?HPl>#BoW-kuZXQ!!4Y2A3L6^kInY1j#C~;TH>A*OmgQq z5Z0KIfsFp{kre*)Z#bQ$hK>NDNnB`7M@hzP3Iq *!_H3k)64yF|%9bXA|AgA<6gvbczdA#f&0{-d~ zhCC$tC*!RHi?j&`jPdqVJE55?bHI>ii*<%NijDDHGqsJQ3IOK-DnYp?tc+7Y)ky|i z`I3DFoULmLjP8N%)znHbZX1En-43SjZ=`BFR3vp+@NHbkX `IWviHO}6*bGq3F5S*UbZRKy;bbjOk=k!@!$vamBsjsb6d c_O-YtxJ#u)EMz_qWp*CQ#_zt``TGLJSc zYE*Y-J|r5hD7}0#7^$+}yjzoz`r5x#t&BoOFs5~lu>V*+S3WC+^hFyFnLcYz1iqx4 zpu%)|4G7>aQA0oWDZe=;pm7EC(!lW+uFCG4G@EBGwR`m&W{w13micu<0CFS&kL{;( zVjOu_;kAp-@ll@8PrL8z1Y0=a+KvH{&5+pvl5mgw-3woLG?`#b6~}|^mNK<-9StCO zgTw}-RS*L!!$y#ls%2XsyCQ+#>9){Z2e^Zpjf|jJcGMSt^DiLLgK5SkR#>@4C}vO& zS>(P 5HG+?U0Ieh7;MI$fUb-kn!qpa218Pc9 z_B{K$D;K3r?9J~(=<{Pd14iCS3vE?5KgV8Fn+K2^DDf?BLT sp5&X6Ep;( zT1aw1+)CwINb6E61R#=&phg~&XFV`)9*slN$K?rVaDWlT6A5UG=Ag=o*ZvYRZ~r*H z)B>9hFD0I{F9J19TC6XZS&pL%iQmmHuwjxFtPgaaGlU*|>scf~2zPVH4z8UBO``{# z8yuMq6(06G$ygd)$7nwT;yRqKq96lUhrya?N5GI9C<1uCO !q+{|9i^?FKnu z9QSS7j~vZ4-2}!hvP*vxtQFGxPlE}H8EFm#aJrK`?@T4L)c>d+OZGPqY2<5v1$K%9 z1KblAtks%&iAxHF?>@v0K18DfXFM!TE8E4OJRek;8m-Z`{>{`B_|5Z@zIsv8y)@Oa z$X5NagptV;mAn5KC?wAoW8@<)z%75UwO|y9!8|~VGt>ZUhc(f3=D4kZ^Np6Xw03{~ zI3s#FdT__pOCDz-o}CUdBXNL-z_7L2szx`d6F}-a6C`z;bq2B<-4Y&j0sP&6OlLHj zc-obL=%UVqJyBW+1QngUEZ1X* g?tXw{b2|fhJW%J1`EE rX+=1vEyffiaQY z-7r;dPKnU})O T z4$h-SV3;csA(GK2put)|zxe?eHwT+9*l3XsV?put#~}dw7)gm)`q#(25dfjx9{adB z&r{r3z%*#Arom%Q3t }rDcN+yS!~r6DZGFjpma
;C!i7o&mVxh<-Cad>{aY0$P7Nj;|j ERK;#cP!fgN{lF`_wUK7z|?2T8&3IpNg`B5NQSO#(o}U z&fjW4rdBBn5s2;p(?2z8gfP`L%}&XnRiS@!rGK$vHs)(IS5GQ8MX( 03fzrjs*?#4 z54tSti6CfYYKLrpfv?10^RG}_!GBSU_RStbt@{E;oIL<0n4s5Y+~N)PCw{I(f7}_; zEP;I|EEpFh9Xxwo5v_lhjuLG?FwIRF)}1D&SLW#MYcE^?Uj|KrI0|5u#BG^w@>HW5 l#`JGjT2VCQKBy&!+avXpR|1Bm1Aq0ZuBx#Tx&1b<{|~G@=I{Uj literal 0 HcmV?d00001 diff --git a/src/app/gateway/client/actions.ts b/src/app/[lang]/gateway/client/actions.ts similarity index 100% rename from src/app/gateway/client/actions.ts rename to src/app/[lang]/gateway/client/actions.ts diff --git a/src/app/gateway/index.ts b/src/app/[lang]/gateway/index.ts similarity index 100% rename from src/app/gateway/index.ts rename to src/app/[lang]/gateway/index.ts diff --git a/src/app/gateway/server/actions.ts b/src/app/[lang]/gateway/server/actions.ts similarity index 100% rename from src/app/gateway/server/actions.ts rename to src/app/[lang]/gateway/server/actions.ts diff --git a/src/app/gateway/server/hypnos/private/actions.ts b/src/app/[lang]/gateway/server/hypnos/private/actions.ts similarity index 100% rename from src/app/gateway/server/hypnos/private/actions.ts rename to src/app/[lang]/gateway/server/hypnos/private/actions.ts diff --git a/src/app/gateway/server/hypnos/private/index.ts b/src/app/[lang]/gateway/server/hypnos/private/index.ts similarity index 100% rename from src/app/gateway/server/hypnos/private/index.ts rename to src/app/[lang]/gateway/server/hypnos/private/index.ts diff --git a/src/app/gateway/server/hypnos/public/actions.ts b/src/app/[lang]/gateway/server/hypnos/public/actions.ts similarity index 100% rename from src/app/gateway/server/hypnos/public/actions.ts rename to src/app/[lang]/gateway/server/hypnos/public/actions.ts diff --git a/src/app/gateway/server/hypnos/public/index.ts b/src/app/[lang]/gateway/server/hypnos/public/index.ts similarity index 100% rename from src/app/gateway/server/hypnos/public/index.ts rename to src/app/[lang]/gateway/server/hypnos/public/index.ts diff --git a/src/app/[lang]/global-error.jsx b/src/app/[lang]/global-error.jsx new file mode 100644 index 00000000..fc093df1 --- /dev/null +++ b/src/app/[lang]/global-error.jsx @@ -0,0 +1,19 @@ +'use client'; + +import * as Sentry from '@sentry/nextjs'; +import Error from 'next/error'; +import { useEffect } from 'react'; + +export default function GlobalError({ error }) { + useEffect(() => { + Sentry.captureException(error); + }, [error]); + + return ( + + + + + + ); +} diff --git a/src/app/globals.css b/src/app/[lang]/globals.css similarity index 100% rename from src/app/globals.css rename to src/app/[lang]/globals.css diff --git a/src/app/layout.tsx b/src/app/[lang]/layout.tsx similarity index 64% rename from src/app/layout.tsx rename to src/app/[lang]/layout.tsx index e80063ac..03686522 100644 --- a/src/app/layout.tsx +++ b/src/app/[lang]/layout.tsx @@ -8,11 +8,14 @@ export const metadata: Metadata = { description: process.env.PATTERNS_DESCRIPTION, }; -export default function RootLayout({ children }: { children: React.ReactNode }) { +export default function RootLayout({ children, params }: { children: React.ReactNode; params: any }) { + const { lang: orig } = params; + const locale = orig === 'default' ? 'en' : orig; + return ( - + diff --git a/src/app/page.tsx b/src/app/[lang]/page.tsx similarity index 100% rename from src/app/page.tsx rename to src/app/[lang]/page.tsx diff --git a/src/app/styles/page.module.css b/src/app/[lang]/styles/page.module.css similarity index 100% rename from src/app/styles/page.module.css rename to src/app/[lang]/styles/page.module.css diff --git a/src/middleware.ts b/src/middleware.ts index 532acf15..e3b42ee7 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -1,9 +1,30 @@ // middleware.ts import type { NextRequest } from 'next/server'; import { NextResponse } from 'next/server'; +import acceptLanguage from 'accept-language'; +import { localeMap, LOCALES } from '@constants/server'; + +const supportedLocales = [ + 'en', + 'it-IT', + 'pt-BR', + 'it', + 'pt', + 'ro', + 'ru', + 'pl-PL', + 'de', + 'fr', + 'ja-JP', + 'sv-SE', + 'et-EE', + 'cs-CZ', +]; + +acceptLanguage.languages(supportedLocales); export const config = { - matcher: ['/api/:path*'], + matcher: ['/api/:path*', '/default/dash/:path*'], }; const allowedOrigins = { @@ -23,32 +44,53 @@ const headers: Record {children} = { }; export function middleware(request: NextRequest) { - const origin = request.headers.get('x-forwarded-host') || ''; - if (origin !== process.env.MAIN_URL) { - headers['Access-Control-Allow-Origin'] = allowedOrigins[origin] || 'https://www.dreampip.com'; - } - - const response = NextResponse.next(); - const pkce = request.cookies.get('next-auth.pkce.code_verifier'); + // API COOKIES + if (request.nextUrl.pathname.startsWith('/api')) { + const origin = request.headers.get('x-forwarded-host') || ''; + if (origin !== process.env.MAIN_URL) { + headers['Access-Control-Allow-Origin'] = allowedOrigins[origin] || 'https://www.dreampip.com'; + } - Object.keys(headers).forEach((key: string) => { - response.headers.set(key, headers[key]); - }); + const response = NextResponse.next(); + const pkce = request.cookies.get('next-auth.pkce.code_verifier'); - if (pkce?.value) { - response.cookies.set('next-auth.pkce.code_verifier', pkce.value, { - httpOnly: true, - sameSite: 'none', - path: '/', - secure: true, + Object.keys(headers).forEach((key: string) => { + response.headers.set(key, headers[key]); }); - console.log({ pkce, response, to: request.nextUrl.pathname }); + + if (pkce?.value) { + response.cookies.set('next-auth.pkce.code_verifier', pkce.value, { + httpOnly: true, + sameSite: 'none', + path: '/', + secure: true, + }); + console.log({ pkce, response, to: request.nextUrl.pathname }); + } + return NextResponse.rewrite( + new URL( + `${process.env.REMOTE_DEV ? process.env.API_HOST_DEV : process.env.API_HOST}${request.nextUrl.pathname}${request.nextUrl.search}`, + ), + response, + ); } - return NextResponse.rewrite( - new URL( - `${process.env.REMOTE_DEV ? process.env.API_HOST_DEV : process.env.API_HOST}${request.nextUrl.pathname}${request.nextUrl.search}`, - ), - response, - ); + // LOCALIZATION + if ( + !/\.(.*)$/.test(request.nextUrl.pathname) && + (LOCALES.every((locale) => !request.nextUrl.href.includes(locale)) || + request.nextUrl.pathname.startsWith('/default')) + ) { + const newUrl = request.nextUrl.clone(); + const headers = request.headers.get('accept-language'); + + if (!headers) return NextResponse.rewrite(newUrl); + const savedLocale = request?.cookies?.get('NEXT_LOCALE'); + const newlocale = (savedLocale?.value || + acceptLanguage?.get(headers)?.toLocaleLowerCase() || + 'en') as keyof typeof localeMap; + newUrl.pathname = newUrl?.pathname?.replace('/default', localeMap[newlocale] || newlocale); + + return NextResponse.redirect(newUrl); + } } diff --git a/tsconfig.json b/tsconfig.json index 39e999ed..8bac0deb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,16 +19,18 @@ }, ], "paths": { - "@styles": ["./src/app/styles"], - "@styles/*": ["./src/app/styles/*"], - "@atoms": ["./src/app/components/system/atoms"], - "@atoms/*": ["./src/app/components/system/atoms/*"], - "@blocks/client": ["./src/app/components/client/blocks"], - "@blocks/client/*": ["./src/app/components/client/blocks/*"], - "@blocks/server": ["./src/app/components/server/blocks"], - "@blocks/server/*": ["./src/app/components/server/blocks/*"], - "@elements/client": ["./src/app/components/client/elements"], - "@elements/client/*": ["./src/app/components/client/elements/*"], + "@styles": ["./src/app/[lang]/styles"], + "@styles/*": ["./src/app/[lang]/styles/*"], + "@atoms": ["./src/app/[lang]/components/system/atoms"], + "@atoms/*": ["./src/app/[lang]/components/system/atoms/*"], + "@blocks/client": ["./src/app/[lang]/components/client/blocks"], + "@blocks/client/*": ["./src/app/[lang]/components/client/blocks/*"], + "@blocks/server": ["./src/app/[lang]/components/server/blocks"], + "@blocks/server/*": ["./src/app/[lang]/components/server/blocks/*"], + "@constants/server": ["./lib/constants/server"], + "@constants/client": ["./lib/constants/client"], + "@elements/client": ["./src/app/[lang]/components/client/elements"], + "@elements/client/*": ["./src/app/[lang]/components/client/elements/*"], "@model": ["./lib/model"], "@model/*": ["./lib/model/*"], "@view": ["./lib/view"], @@ -40,20 +42,20 @@ "@types": ["./lib/types"], "@types/*": ["./lib/types/*"], "@auth": ["./lib/auth"], - "@auth/adapter": ["./src/app/api/auth/[...nextauth]"], - "@auth/adapter/*": ["./src/app/api/auth/[...nextauth]/*"], + "@auth/adapter": ["./src/app/[lang]/api/auth/[...nextauth]"], + "@auth/adapter/*": ["./src/app/[lang]/api/auth/[...nextauth]/*"], "@state/*": ["./lib/state/*"], "@state": ["./lib/state"], "@hooks/*": ["./lib/hooks/*"], "@hooks": ["./lib/hooks"], "@actions/*": ["./lib/actions/*"], "@actions": ["./lib/actions"], - "@gateway/*": ["./src/app/gateway/*"], - "@gateway": ["./src/app/gateway"], + "@gateway/*": ["./src/app/[lang]/gateway/*"], + "@gateway": ["./src/app/[lang]/gateway"], "@controller/*": ["./lib/model/interfaces/*"], "@controller": ["./lib/model/interfaces"], - "@components/*": ["./src/app/components/*"], - "@components": ["./src/app/components"], + "@components/*": ["./src/app/[lang]/components/*"], + "@components": ["./src/app/[lang]/components"], }, }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], From 9a5d2bd504b68770a4e4659e0be14411ffcd6570 Mon Sep 17 00:00:00 2001 From: Angelo Reale <12191809+angeloreale@users.noreply.github.com> Date: Wed, 21 Aug 2024 15:42:32 +0100 Subject: [PATCH 07/21] ar(feat) [DPCP-37]: Localization Part 2: Dictionaries (#42) * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization --- lib/dictionaries/global/cs-cz.json | 15 +++ lib/dictionaries/global/de-de.json | 15 +++ lib/dictionaries/global/default.json | 15 +++ lib/dictionaries/global/en.json | 14 +++ lib/dictionaries/global/es-es.json | 15 +++ lib/dictionaries/global/et-ee.json | 15 +++ lib/dictionaries/global/fr-fr.json | 15 +++ lib/dictionaries/global/it-it.json | 15 +++ lib/dictionaries/global/ja-jp.json | 15 +++ lib/dictionaries/global/pl-pl.json | 15 +++ lib/dictionaries/global/pt-br.json | 11 ++ lib/dictionaries/global/ro.json | 15 +++ lib/dictionaries/global/ru-ru.json | 15 +++ lib/dictionaries/global/sv-se.json | 15 +++ lib/state/providers.tsx | 2 +- next.config.js | 5 +- package-lock.json | 105 ++++++++++++++++++ package.json | 1 + src/app/[lang]/layout.tsx | 25 ----- .../components/client/blocks/index.ts | 0 .../components/client/blocks/topnav-view.tsx | 10 +- .../client/elements/calendar-view.tsx | 0 .../components/client/elements/index.ts | 0 .../client/elements/link-decorator.tsx | 0 .../components/client/elements/list-view.tsx | 0 .../components/client/elements/map-view.tsx | 0 .../client/elements/navbar-view.tsx | 0 .../client/elements/signin-view.tsx | 7 +- .../client/elements/signup-view.tsx | 9 +- .../client/elements/usersettings-view.tsx | 0 .../components/client/index.ts | 0 .../{[lang] => [locale]}/components/index.ts | 0 .../components/navbar.tsx | 0 .../server/blocks/hypnos-public-list.tsx | 0 .../components/server/blocks/index.ts | 0 .../components/server/blocks/rm-list.tsx | 0 .../components/server/blocks/topnav.tsx | 0 .../components/server/index.ts | 0 .../components/server/navbar-controller.tsx | 0 .../components/server/signup-controller.tsx | 0 .../server/usersettings-controller.tsx | 0 .../components/toolbar.tsx | 0 .../{[lang] => [locale]}/dash/error/page.tsx | 0 .../dash/services/hypnos/[mode]/page.tsx | 0 .../dash/services/rickmorty/[mode]/page.tsx | 0 .../{[lang] => [locale]}/dash/signin/page.tsx | 0 .../{[lang] => [locale]}/dash/verify/page.tsx | 0 src/app/{[lang] => [locale]}/favicon.ico | Bin .../gateway/client/actions.ts | 0 src/app/{[lang] => [locale]}/gateway/index.ts | 2 +- .../gateway/server/actions.ts | 14 ++- .../gateway/server/hypnos/private/actions.ts | 0 .../gateway/server/hypnos/private/index.ts | 0 .../gateway/server/hypnos/public/actions.ts | 0 .../gateway/server/hypnos/public/index.ts | 0 src/app/{[lang] => [locale]}/global-error.jsx | 0 src/app/{[lang] => [locale]}/globals.css | 0 src/app/[locale]/i18n.ts | 13 +++ src/app/[locale]/layout.tsx | 32 ++++++ src/app/{[lang] => [locale]}/page.tsx | 0 .../styles/page.module.css | 0 src/middleware.ts | 97 ++-------------- src/middlewares/authMiddleware.ts | 54 +++++++++ src/middlewares/i18nDetectMiddleware.ts | 58 ++++++++++ tsconfig.json | 32 +++--- 65 files changed, 532 insertions(+), 139 deletions(-) create mode 100644 lib/dictionaries/global/cs-cz.json create mode 100644 lib/dictionaries/global/de-de.json create mode 100644 lib/dictionaries/global/default.json create mode 100644 lib/dictionaries/global/en.json create mode 100644 lib/dictionaries/global/es-es.json create mode 100644 lib/dictionaries/global/et-ee.json create mode 100644 lib/dictionaries/global/fr-fr.json create mode 100644 lib/dictionaries/global/it-it.json create mode 100644 lib/dictionaries/global/ja-jp.json create mode 100644 lib/dictionaries/global/pl-pl.json create mode 100644 lib/dictionaries/global/pt-br.json create mode 100644 lib/dictionaries/global/ro.json create mode 100644 lib/dictionaries/global/ru-ru.json create mode 100644 lib/dictionaries/global/sv-se.json delete mode 100644 src/app/[lang]/layout.tsx rename src/app/{[lang] => [locale]}/components/client/blocks/index.ts (100%) rename src/app/{[lang] => [locale]}/components/client/blocks/topnav-view.tsx (94%) rename src/app/{[lang] => [locale]}/components/client/elements/calendar-view.tsx (100%) rename src/app/{[lang] => [locale]}/components/client/elements/index.ts (100%) rename src/app/{[lang] => [locale]}/components/client/elements/link-decorator.tsx (100%) rename src/app/{[lang] => [locale]}/components/client/elements/list-view.tsx (100%) rename src/app/{[lang] => [locale]}/components/client/elements/map-view.tsx (100%) rename src/app/{[lang] => [locale]}/components/client/elements/navbar-view.tsx (100%) rename src/app/{[lang] => [locale]}/components/client/elements/signin-view.tsx (83%) rename src/app/{[lang] => [locale]}/components/client/elements/signup-view.tsx (95%) rename src/app/{[lang] => [locale]}/components/client/elements/usersettings-view.tsx (100%) rename src/app/{[lang] => [locale]}/components/client/index.ts (100%) rename src/app/{[lang] => [locale]}/components/index.ts (100%) rename src/app/{[lang] => [locale]}/components/navbar.tsx (100%) rename src/app/{[lang] => [locale]}/components/server/blocks/hypnos-public-list.tsx (100%) rename src/app/{[lang] => [locale]}/components/server/blocks/index.ts (100%) rename src/app/{[lang] => [locale]}/components/server/blocks/rm-list.tsx (100%) rename src/app/{[lang] => [locale]}/components/server/blocks/topnav.tsx (100%) rename src/app/{[lang] => [locale]}/components/server/index.ts (100%) rename src/app/{[lang] => [locale]}/components/server/navbar-controller.tsx (100%) rename src/app/{[lang] => [locale]}/components/server/signup-controller.tsx (100%) rename src/app/{[lang] => [locale]}/components/server/usersettings-controller.tsx (100%) rename src/app/{[lang] => [locale]}/components/toolbar.tsx (100%) rename src/app/{[lang] => [locale]}/dash/error/page.tsx (100%) rename src/app/{[lang] => [locale]}/dash/services/hypnos/[mode]/page.tsx (100%) rename src/app/{[lang] => [locale]}/dash/services/rickmorty/[mode]/page.tsx (100%) rename src/app/{[lang] => [locale]}/dash/signin/page.tsx (100%) rename src/app/{[lang] => [locale]}/dash/verify/page.tsx (100%) rename src/app/{[lang] => [locale]}/favicon.ico (100%) rename src/app/{[lang] => [locale]}/gateway/client/actions.ts (100%) rename src/app/{[lang] => [locale]}/gateway/index.ts (70%) rename src/app/{[lang] => [locale]}/gateway/server/actions.ts (76%) rename src/app/{[lang] => [locale]}/gateway/server/hypnos/private/actions.ts (100%) rename src/app/{[lang] => [locale]}/gateway/server/hypnos/private/index.ts (100%) rename src/app/{[lang] => [locale]}/gateway/server/hypnos/public/actions.ts (100%) rename src/app/{[lang] => [locale]}/gateway/server/hypnos/public/index.ts (100%) rename src/app/{[lang] => [locale]}/global-error.jsx (100%) rename src/app/{[lang] => [locale]}/globals.css (100%) create mode 100644 src/app/[locale]/i18n.ts create mode 100644 src/app/[locale]/layout.tsx rename src/app/{[lang] => [locale]}/page.tsx (100%) rename src/app/{[lang] => [locale]}/styles/page.module.css (100%) create mode 100644 src/middlewares/authMiddleware.ts create mode 100644 src/middlewares/i18nDetectMiddleware.ts diff --git a/lib/dictionaries/global/cs-cz.json b/lib/dictionaries/global/cs-cz.json new file mode 100644 index 00000000..f4595c86 --- /dev/null +++ b/lib/dictionaries/global/cs-cz.json @@ -0,0 +1,15 @@ +{ + "NavBar": { + "welcome": "Vítejte" + }, + "SignIn": { + "continue": "Pokračovat", + "continue with": "Pokračovat s", + "sign in": "Přihlásit", + "sign out": "Odhlásit", + "your email": "Váš e-mail" + }, + "CardGrid": { + "staff picks": "Výběr zaměstnanců" + } +} diff --git a/lib/dictionaries/global/de-de.json b/lib/dictionaries/global/de-de.json new file mode 100644 index 00000000..7a5729b5 --- /dev/null +++ b/lib/dictionaries/global/de-de.json @@ -0,0 +1,15 @@ +{ + "NavBar": { + "welcome": "Willkommen" + }, + "SignIn": { + "continue": "Weiter", + "continue with": "Weiter mit", + "sign in": "Anmelden", + "sign out": "Abmelden", + "your email": "Deine E-Mail" + }, + "CardGrid": { + "staff picks": "Auswahl des Personals" + } +} diff --git a/lib/dictionaries/global/default.json b/lib/dictionaries/global/default.json new file mode 100644 index 00000000..bc506591 --- /dev/null +++ b/lib/dictionaries/global/default.json @@ -0,0 +1,15 @@ +{ + "NavBar": { + "welcome": "Welcome" + }, + "SignIn": { + "continue": "Continue", + "continue with": "Continue with", + "sign in": "Sign in", + "sign out": "Sign out", + "your email": "Your email" + }, + "CardGrid": { + "staff picks": "Staff Picks" + } +} diff --git a/lib/dictionaries/global/en.json b/lib/dictionaries/global/en.json new file mode 100644 index 00000000..ae88cfc3 --- /dev/null +++ b/lib/dictionaries/global/en.json @@ -0,0 +1,14 @@ +{ + "NavBar": { + "welcome": "Welcome" + }, + "SignIn": { + "continue": "Continue", + "continue with": "Continue with", + "sign in": "Sign in", + "sign out": "Sign out" + }, + "CardGrid": { + "staff picks": "Staff Picks" + } +} diff --git a/lib/dictionaries/global/es-es.json b/lib/dictionaries/global/es-es.json new file mode 100644 index 00000000..1a804560 --- /dev/null +++ b/lib/dictionaries/global/es-es.json @@ -0,0 +1,15 @@ +{ + "NavBar": { + "welcome": "Bienvenido" + }, + "SignIn": { + "continue": "Continuar", + "continue with": "Continuar con", + "sign in": "Iniciar sesión", + "sign out": "Cerrar sesión", + "your email": "Tu correo electrónico" + }, + "CardGrid": { + "staff picks": "Selecciones del personal" + } +} diff --git a/lib/dictionaries/global/et-ee.json b/lib/dictionaries/global/et-ee.json new file mode 100644 index 00000000..1896dd6c --- /dev/null +++ b/lib/dictionaries/global/et-ee.json @@ -0,0 +1,15 @@ +{ + "NavBar": { + "welcome": "Tere tulemast" + }, + "SignIn": { + "continue": "Jätka", + "continue with": "Jätka", + "sign in": "Logi sisse", + "sign out": "Logi välja", + "your email": "Sinu e-post" + }, + "CardGrid": { + "staff picks": "Töötajate valikud" + } +} diff --git a/lib/dictionaries/global/fr-fr.json b/lib/dictionaries/global/fr-fr.json new file mode 100644 index 00000000..21db518c --- /dev/null +++ b/lib/dictionaries/global/fr-fr.json @@ -0,0 +1,15 @@ +{ + "NavBar": { + "welcome": "Bienvenue" + }, + "SignIn": { + "continue": "Continuer", + "continue with": "Continuer avec", + "sign in": "Se connecter", + "sign out": "Se déconnecter", + "your email": "Votre adresse e-mail" + }, + "CardGrid": { + "staff picks": "Choix du personnel" + } +} diff --git a/lib/dictionaries/global/it-it.json b/lib/dictionaries/global/it-it.json new file mode 100644 index 00000000..7cd1f4a4 --- /dev/null +++ b/lib/dictionaries/global/it-it.json @@ -0,0 +1,15 @@ +{ + "NavBar": { + "welcome": "Benvenuto" + }, + "SignIn": { + "continue": "Prosegue", + "continue with": "Prosegue con", + "sign in": "Accedi", + "sign out": "Scollega", + "your email": "La sua mail" + }, + "CardGrid": { + "staff picks": "Preferiti dello Staff" + } +} diff --git a/lib/dictionaries/global/ja-jp.json b/lib/dictionaries/global/ja-jp.json new file mode 100644 index 00000000..2d3c71e9 --- /dev/null +++ b/lib/dictionaries/global/ja-jp.json @@ -0,0 +1,15 @@ +{ + "NavBar": { + "welcome": "ようこそ" + }, + "SignIn": { + "continue": "続行", + "continue with": "続行する", + "sign in": "サインイン", + "sign out": "ログアウト", + "your email": "あなたのメール" + }, + "CardGrid": { + "staff picks": "スタッフおすすめ" + } +} diff --git a/lib/dictionaries/global/pl-pl.json b/lib/dictionaries/global/pl-pl.json new file mode 100644 index 00000000..095d9adb --- /dev/null +++ b/lib/dictionaries/global/pl-pl.json @@ -0,0 +1,15 @@ +{ + "NavBar": { + "welcome": "Witaj" + }, + "SignIn": { + "continue": "Kontynuuj", + "continue with": "Kontynuuj z", + "sign in": "Zaloguj się", + "sign out": "Wyloguj się", + "your email": "Twój adres email" + }, + "CardGrid": { + "staff picks": "Wybór pracowników" + } +} diff --git a/lib/dictionaries/global/pt-br.json b/lib/dictionaries/global/pt-br.json new file mode 100644 index 00000000..8708a40f --- /dev/null +++ b/lib/dictionaries/global/pt-br.json @@ -0,0 +1,11 @@ +{ + "NavBar": { "welcome": "Bem-vindo" }, + "SignIn": { + "continue": "Continuar", + "continue with": "Continuar com", + "sign in": "Entrar", + "sign out": "Sair", + "your email": "Seu email" + }, + "CardGrid": { "staff picks": "Escolhas da Equipe" } +} diff --git a/lib/dictionaries/global/ro.json b/lib/dictionaries/global/ro.json new file mode 100644 index 00000000..81defd72 --- /dev/null +++ b/lib/dictionaries/global/ro.json @@ -0,0 +1,15 @@ +{ + "NavBar": { + "welcome": "Bine ai venit" + }, + "SignIn": { + "continue": "Continuați", + "continue with": "Continuați cu", + "sign in": "Conectați-vă", + "sign out": "Deconectați-vă", + "your email": "Adresa ta de email" + }, + "CardGrid": { + "staff picks": "Alegerile personalului" + } +} diff --git a/lib/dictionaries/global/ru-ru.json b/lib/dictionaries/global/ru-ru.json new file mode 100644 index 00000000..7f392d86 --- /dev/null +++ b/lib/dictionaries/global/ru-ru.json @@ -0,0 +1,15 @@ +{ + "NavBar": { + "welcome": "Добро пожаловать" + }, + "SignIn": { + "continue": "Продолжить", + "continue with": "Продолжить с", + "sign in": "Войти", + "sign out": "Выйти", + "your email": "Ваш электронный адрес" + }, + "CardGrid": { + "staff picks": "Выбор персонала" + } +} diff --git a/lib/dictionaries/global/sv-se.json b/lib/dictionaries/global/sv-se.json new file mode 100644 index 00000000..112636b6 --- /dev/null +++ b/lib/dictionaries/global/sv-se.json @@ -0,0 +1,15 @@ +{ + "NavBar": { + "welcome": "Välkommen" + }, + "SignIn": { + "continue": "Fortsätt", + "continue with": "Fortsätt med", + "sign in": "Logga in", + "sign out": "Logga ut", + "your email": "Din e-post" + }, + "CardGrid": { + "staff picks": "Personals val" + } +} diff --git a/lib/state/providers.tsx b/lib/state/providers.tsx index 2e8e779a..a3998cbe 100644 --- a/lib/state/providers.tsx +++ b/lib/state/providers.tsx @@ -16,7 +16,7 @@ export function RootProviders({ children, locale }: { children: React.ReactNode; const [globalState, setGlobalState] = useState ({ ...globalContext, locale }); const init = useRef(false); - const [storedGlobal, setStoredGlobal] = useLocalStorage('globalSettings', { theme: 'dark' }); + const [storedGlobal, setStoredGlobal] = useLocalStorage('globalSettings', { theme: 'dark', locale }); const handleGlobalSettingUpdate = (next: any) => { setGlobalState(next); diff --git a/next.config.js b/next.config.js index 92e254d8..306993fb 100644 --- a/next.config.js +++ b/next.config.js @@ -1,5 +1,8 @@ /** @type {import('next').NextConfig} */ const { withSentryConfig } = require('@sentry/nextjs'); +const createNextIntlPlugin = require('next-intl/plugin'); +const withNextIntl = createNextIntlPlugin('./src/app/[locale]/i18n.ts'); + const nextConfig = { assetPrefix: process.env.NEXUS_HOST || 'https://nyx.dreampip.com', transpilePackages: ['next-auth'], @@ -37,7 +40,7 @@ const nextConfig = { }, }; -module.exports = nextConfig; +module.exports = withNextIntl(nextConfig); module.exports = withSentryConfig( module.exports, diff --git a/package-lock.json b/package-lock.json index 3a7c060f..78bab80c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,6 +34,7 @@ "eslint-config-next": "14.0.4", "husky": "9.0.11", "lodash": "4.17.21", + "next-intl": "^3.17.4", "postcss": "^8.4.38", "prettier": "3.2.4", "server-only": "0.0.1", @@ -511,6 +512,55 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.0.0.tgz", + "integrity": "sha512-rRqXOqdFmk7RYvj4khklyqzcfQl9vEL/usogncBHRZfZBDOwMGuSRNFl02fu5KGHXdbinju+YXyuR+Nk8xlr/g==", + "dev": true, + "dependencies": { + "@formatjs/intl-localematcher": "0.5.4", + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz", + "integrity": "sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==", + "dev": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.7.8", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.8.tgz", + "integrity": "sha512-nBZJYmhpcSX0WeJ5SDYUkZ42AgR3xiyhNCsQweFx3cz/ULJjym8bHAzWKvG5e2+1XO98dBYC0fWeeAECAVSwLA==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "2.0.0", + "@formatjs/icu-skeleton-parser": "1.8.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.2.tgz", + "integrity": "sha512-k4ERKgw7aKGWJZgTarIcNEmvyTVD9FYh0mTrrBMHZ1b8hUu6iOJ4SzsZlo3UNAvHYa+PnvntIwRPt1/vy4nA9Q==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "2.0.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz", + "integrity": "sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==", + "dev": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -4083,6 +4133,18 @@ "node": ">= 0.4" } }, + "node_modules/intl-messageformat": { + "version": "10.5.14", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.5.14.tgz", + "integrity": "sha512-IjC6sI0X7YRjjyVH9aUgdftcmZK7WXdHeil4KwbjDnRWjnVitKpAx3rr6t6di1joFp5188VqKcobOPA6mCLG/w==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "2.0.0", + "@formatjs/fast-memoize": "2.2.0", + "@formatjs/icu-messageformat-parser": "2.7.8", + "tslib": "^2.4.0" + } + }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -4826,6 +4888,15 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/next": { "version": "14.2.4", "resolved": "https://registry.npmjs.org/next/-/next-14.2.4.tgz", @@ -4876,6 +4947,27 @@ } } }, + "node_modules/next-intl": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/next-intl/-/next-intl-3.17.4.tgz", + "integrity": "sha512-ro3yNIaMNVhCmCdG6u9R00HllMdJXsGdKkBaBq75iM0sSnjLr7IytiGmCuZsUMDqCnGswXfXvs/FjI/lC8OAOw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/amannn" + } + ], + "dependencies": { + "@formatjs/intl-localematcher": "^0.5.4", + "negotiator": "^0.6.3", + "use-intl": "^3.17.4" + }, + "peerDependencies": { + "next": "^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -6534,6 +6626,19 @@ "punycode": "^2.1.0" } }, + "node_modules/use-intl": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-3.17.4.tgz", + "integrity": "sha512-6t3tScvli9TvIBwordjZul59ubYzStcMTCgYJEkEikVGqBJKzfpdpifZhRTU7CxgSoB63rt9+AOPGKklXvtebA==", + "dev": true, + "dependencies": { + "@formatjs/fast-memoize": "^2.2.0", + "intl-messageformat": "^10.5.14" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index 749f9e16..4bffe52f 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "eslint-config-next": "14.0.4", "husky": "9.0.11", "lodash": "4.17.21", + "next-intl": "^3.17.4", "postcss": "^8.4.38", "prettier": "3.2.4", "server-only": "0.0.1", diff --git a/src/app/[lang]/layout.tsx b/src/app/[lang]/layout.tsx deleted file mode 100644 index 03686522..00000000 --- a/src/app/[lang]/layout.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import type { Metadata } from 'next'; -import { DPTopNav } from '@blocks/server'; -import { RootProviders } from '@state'; -import './globals.css'; - -export const metadata: Metadata = { - title: process.env.PATTERNS_TITLE, - description: process.env.PATTERNS_DESCRIPTION, -}; - -export default function RootLayout({ children, params }: { children: React.ReactNode; params: any }) { - const { lang: orig } = params; - const locale = orig === 'default' ? 'en' : orig; - - return ( - - - - - - - ); -} diff --git a/src/app/[lang]/components/client/blocks/index.ts b/src/app/[locale]/components/client/blocks/index.ts similarity index 100% rename from src/app/[lang]/components/client/blocks/index.ts rename to src/app/[locale]/components/client/blocks/index.ts diff --git a/src/app/[lang]/components/client/blocks/topnav-view.tsx b/src/app/[locale]/components/client/blocks/topnav-view.tsx similarity index 94% rename from src/app/[lang]/components/client/blocks/topnav-view.tsx rename to src/app/[locale]/components/client/blocks/topnav-view.tsx index bdc8f7d4..3c2a395f 100644 --- a/src/app/[lang]/components/client/blocks/topnav-view.tsx +++ b/src/app/[locale]/components/client/blocks/topnav-view.tsx @@ -1,13 +1,15 @@ // @block/topnav-view.tsx 'use client'; import type { UserSchema } from '@types'; -import { getSession } from '@auth' +import { getSession } from '@auth'; import { useContext, useRef, useEffect, useState, useMemo } from 'react'; import { AuthContext, GlobalContext } from '@state'; import { ASwitchThemes, ALogIn } from '@actions'; import { navigate } from '@gateway'; import { AudioPlayer, Button as DPButton, EGridVariant, Grid as DPGrid, EBleedVariant, Typography as DPTypo, TypographyVariant, ESystemIcon } from "@dreampipcom/oneiros"; import { VSignIn, InternalLink } from '@elements/client'; +import { useTranslations } from 'next-intl'; + interface IAuthProvider { id?: string; @@ -24,8 +26,10 @@ export const VTopNav = ({ user }: VTopNavProps) => { const authContext = useContext(AuthContext); const globalContext = useContext(GlobalContext); + const t = useTranslations('NavBar'); + const { authd, name } = authContext; - const { theme } = globalContext; + const { theme, locale } = globalContext; const initd = useRef(false); @@ -66,7 +70,7 @@ export const VTopNav = ({ user }: VTopNavProps) => {- {children} - @@ -135,7 +138,7 @@ export const VSignUp = ({ providers, user }: VSignUpProps) => { )} diff --git a/src/app/[lang]/components/client/elements/usersettings-view.tsx b/src/app/[locale]/components/client/elements/usersettings-view.tsx similarity index 100% rename from src/app/[lang]/components/client/elements/usersettings-view.tsx rename to src/app/[locale]/components/client/elements/usersettings-view.tsx diff --git a/src/app/[lang]/components/client/index.ts b/src/app/[locale]/components/client/index.ts similarity index 100% rename from src/app/[lang]/components/client/index.ts rename to src/app/[locale]/components/client/index.ts diff --git a/src/app/[lang]/components/index.ts b/src/app/[locale]/components/index.ts similarity index 100% rename from src/app/[lang]/components/index.ts rename to src/app/[locale]/components/index.ts diff --git a/src/app/[lang]/components/navbar.tsx b/src/app/[locale]/components/navbar.tsx similarity index 100% rename from src/app/[lang]/components/navbar.tsx rename to src/app/[locale]/components/navbar.tsx diff --git a/src/app/[lang]/components/server/blocks/hypnos-public-list.tsx b/src/app/[locale]/components/server/blocks/hypnos-public-list.tsx similarity index 100% rename from src/app/[lang]/components/server/blocks/hypnos-public-list.tsx rename to src/app/[locale]/components/server/blocks/hypnos-public-list.tsx diff --git a/src/app/[lang]/components/server/blocks/index.ts b/src/app/[locale]/components/server/blocks/index.ts similarity index 100% rename from src/app/[lang]/components/server/blocks/index.ts rename to src/app/[locale]/components/server/blocks/index.ts diff --git a/src/app/[lang]/components/server/blocks/rm-list.tsx b/src/app/[locale]/components/server/blocks/rm-list.tsx similarity index 100% rename from src/app/[lang]/components/server/blocks/rm-list.tsx rename to src/app/[locale]/components/server/blocks/rm-list.tsx diff --git a/src/app/[lang]/components/server/blocks/topnav.tsx b/src/app/[locale]/components/server/blocks/topnav.tsx similarity index 100% rename from src/app/[lang]/components/server/blocks/topnav.tsx rename to src/app/[locale]/components/server/blocks/topnav.tsx diff --git a/src/app/[lang]/components/server/index.ts b/src/app/[locale]/components/server/index.ts similarity index 100% rename from src/app/[lang]/components/server/index.ts rename to src/app/[locale]/components/server/index.ts diff --git a/src/app/[lang]/components/server/navbar-controller.tsx b/src/app/[locale]/components/server/navbar-controller.tsx similarity index 100% rename from src/app/[lang]/components/server/navbar-controller.tsx rename to src/app/[locale]/components/server/navbar-controller.tsx diff --git a/src/app/[lang]/components/server/signup-controller.tsx b/src/app/[locale]/components/server/signup-controller.tsx similarity index 100% rename from src/app/[lang]/components/server/signup-controller.tsx rename to src/app/[locale]/components/server/signup-controller.tsx diff --git a/src/app/[lang]/components/server/usersettings-controller.tsx b/src/app/[locale]/components/server/usersettings-controller.tsx similarity index 100% rename from src/app/[lang]/components/server/usersettings-controller.tsx rename to src/app/[locale]/components/server/usersettings-controller.tsx diff --git a/src/app/[lang]/components/toolbar.tsx b/src/app/[locale]/components/toolbar.tsx similarity index 100% rename from src/app/[lang]/components/toolbar.tsx rename to src/app/[locale]/components/toolbar.tsx diff --git a/src/app/[lang]/dash/error/page.tsx b/src/app/[locale]/dash/error/page.tsx similarity index 100% rename from src/app/[lang]/dash/error/page.tsx rename to src/app/[locale]/dash/error/page.tsx diff --git a/src/app/[lang]/dash/services/hypnos/[mode]/page.tsx b/src/app/[locale]/dash/services/hypnos/[mode]/page.tsx similarity index 100% rename from src/app/[lang]/dash/services/hypnos/[mode]/page.tsx rename to src/app/[locale]/dash/services/hypnos/[mode]/page.tsx diff --git a/src/app/[lang]/dash/services/rickmorty/[mode]/page.tsx b/src/app/[locale]/dash/services/rickmorty/[mode]/page.tsx similarity index 100% rename from src/app/[lang]/dash/services/rickmorty/[mode]/page.tsx rename to src/app/[locale]/dash/services/rickmorty/[mode]/page.tsx diff --git a/src/app/[lang]/dash/signin/page.tsx b/src/app/[locale]/dash/signin/page.tsx similarity index 100% rename from src/app/[lang]/dash/signin/page.tsx rename to src/app/[locale]/dash/signin/page.tsx diff --git a/src/app/[lang]/dash/verify/page.tsx b/src/app/[locale]/dash/verify/page.tsx similarity index 100% rename from src/app/[lang]/dash/verify/page.tsx rename to src/app/[locale]/dash/verify/page.tsx diff --git a/src/app/[lang]/favicon.ico b/src/app/[locale]/favicon.ico similarity index 100% rename from src/app/[lang]/favicon.ico rename to src/app/[locale]/favicon.ico diff --git a/src/app/[lang]/gateway/client/actions.ts b/src/app/[locale]/gateway/client/actions.ts similarity index 100% rename from src/app/[lang]/gateway/client/actions.ts rename to src/app/[locale]/gateway/client/actions.ts diff --git a/src/app/[lang]/gateway/index.ts b/src/app/[locale]/gateway/index.ts similarity index 70% rename from src/app/[lang]/gateway/index.ts rename to src/app/[locale]/gateway/index.ts index fa20fcbf..bef6d9b8 100644 --- a/src/app/[lang]/gateway/index.ts +++ b/src/app/[locale]/gateway/index.ts @@ -4,7 +4,7 @@ export { navigate, setCookie, getCookie } from './client/actions'; // server -export { getUser, loadChars, reloadChars, getChars } from './server/actions'; +export { getUser, loadChars, reloadChars, getChars, getUserLocale, setUserLocale } from './server/actions'; // hypnos-public export { loadHypnosPublicListings } from './server/hypnos/public'; diff --git a/src/app/[lang]/gateway/server/actions.ts b/src/app/[locale]/gateway/server/actions.ts similarity index 76% rename from src/app/[lang]/gateway/server/actions.ts rename to src/app/[locale]/gateway/server/actions.ts index df3d921f..9db70a1a 100644 --- a/src/app/[lang]/gateway/server/actions.ts +++ b/src/app/[locale]/gateway/server/actions.ts @@ -2,7 +2,7 @@ // actions.ts 'use server'; // import type { UserSchema } from '@types'; -import { cookies } from 'next/headers'; +import { cookies, headers } from 'next/headers'; import { getRMCharacters } from '@controller'; import { decorateRMCharacters } from '@model'; import { getSession } from '@auth'; @@ -43,3 +43,15 @@ export async function getUser() { // we might need to decorate users in the future, // reference decorateRMCharactes() } + +const COOKIE_NAME = 'NEXT_LOCALE'; +const defaultLocale = 'default'; + +export async function getUserLocale() { + const headersList = headers(); + return headersList.get('x-dp-locale') || cookies().get(COOKIE_NAME)?.value || defaultLocale; +} + +export async function setUserLocale(locale: string) { + cookies().set(COOKIE_NAME, locale); +} diff --git a/src/app/[lang]/gateway/server/hypnos/private/actions.ts b/src/app/[locale]/gateway/server/hypnos/private/actions.ts similarity index 100% rename from src/app/[lang]/gateway/server/hypnos/private/actions.ts rename to src/app/[locale]/gateway/server/hypnos/private/actions.ts diff --git a/src/app/[lang]/gateway/server/hypnos/private/index.ts b/src/app/[locale]/gateway/server/hypnos/private/index.ts similarity index 100% rename from src/app/[lang]/gateway/server/hypnos/private/index.ts rename to src/app/[locale]/gateway/server/hypnos/private/index.ts diff --git a/src/app/[lang]/gateway/server/hypnos/public/actions.ts b/src/app/[locale]/gateway/server/hypnos/public/actions.ts similarity index 100% rename from src/app/[lang]/gateway/server/hypnos/public/actions.ts rename to src/app/[locale]/gateway/server/hypnos/public/actions.ts diff --git a/src/app/[lang]/gateway/server/hypnos/public/index.ts b/src/app/[locale]/gateway/server/hypnos/public/index.ts similarity index 100% rename from src/app/[lang]/gateway/server/hypnos/public/index.ts rename to src/app/[locale]/gateway/server/hypnos/public/index.ts diff --git a/src/app/[lang]/global-error.jsx b/src/app/[locale]/global-error.jsx similarity index 100% rename from src/app/[lang]/global-error.jsx rename to src/app/[locale]/global-error.jsx diff --git a/src/app/[lang]/globals.css b/src/app/[locale]/globals.css similarity index 100% rename from src/app/[lang]/globals.css rename to src/app/[locale]/globals.css diff --git a/src/app/[locale]/i18n.ts b/src/app/[locale]/i18n.ts new file mode 100644 index 00000000..28d3b67f --- /dev/null +++ b/src/app/[locale]/i18n.ts @@ -0,0 +1,13 @@ +import { getRequestConfig } from 'next-intl/server'; +import { getUserLocale } from '@gateway'; + +export default getRequestConfig(async () => { + const userLocale = await getUserLocale(); + + const locale = userLocale || 'en'; + + return { + locale, + messages: (await import(`../../../lib/dictionaries/global/${locale}.json`)).default, + }; +}); diff --git a/src/app/[locale]/layout.tsx b/src/app/[locale]/layout.tsx new file mode 100644 index 00000000..70047dab --- /dev/null +++ b/src/app/[locale]/layout.tsx @@ -0,0 +1,32 @@ +import type { Metadata } from 'next'; +import { DPTopNav } from '@blocks/server'; +import { RootProviders } from '@state'; +import { NextIntlClientProvider } from 'next-intl'; +import { getLocale, getMessages } from 'next-intl/server'; +import './globals.css'; + +export const metadata: Metadata = { + title: process.env.PATTERNS_TITLE, + description: process.env.PATTERNS_DESCRIPTION, +}; + +export default async function RootLayout({ children, params }: { children: React.ReactNode; params: any }) { + const { locale: orig } = params; + const locale = orig === 'default' ? 'en' : orig; + + const messages = await getMessages(); + const libLocale = await getLocale(); + + return ( + + +- Welcome, {coercedName} + {t('welcome')}, {coercedName} Rick Morty diff --git a/src/app/[lang]/components/client/elements/calendar-view.tsx b/src/app/[locale]/components/client/elements/calendar-view.tsx similarity index 100% rename from src/app/[lang]/components/client/elements/calendar-view.tsx rename to src/app/[locale]/components/client/elements/calendar-view.tsx diff --git a/src/app/[lang]/components/client/elements/index.ts b/src/app/[locale]/components/client/elements/index.ts similarity index 100% rename from src/app/[lang]/components/client/elements/index.ts rename to src/app/[locale]/components/client/elements/index.ts diff --git a/src/app/[lang]/components/client/elements/link-decorator.tsx b/src/app/[locale]/components/client/elements/link-decorator.tsx similarity index 100% rename from src/app/[lang]/components/client/elements/link-decorator.tsx rename to src/app/[locale]/components/client/elements/link-decorator.tsx diff --git a/src/app/[lang]/components/client/elements/list-view.tsx b/src/app/[locale]/components/client/elements/list-view.tsx similarity index 100% rename from src/app/[lang]/components/client/elements/list-view.tsx rename to src/app/[locale]/components/client/elements/list-view.tsx diff --git a/src/app/[lang]/components/client/elements/map-view.tsx b/src/app/[locale]/components/client/elements/map-view.tsx similarity index 100% rename from src/app/[lang]/components/client/elements/map-view.tsx rename to src/app/[locale]/components/client/elements/map-view.tsx diff --git a/src/app/[lang]/components/client/elements/navbar-view.tsx b/src/app/[locale]/components/client/elements/navbar-view.tsx similarity index 100% rename from src/app/[lang]/components/client/elements/navbar-view.tsx rename to src/app/[locale]/components/client/elements/navbar-view.tsx diff --git a/src/app/[lang]/components/client/elements/signin-view.tsx b/src/app/[locale]/components/client/elements/signin-view.tsx similarity index 83% rename from src/app/[lang]/components/client/elements/signin-view.tsx rename to src/app/[locale]/components/client/elements/signin-view.tsx index f776c5eb..5f0a1462 100644 --- a/src/app/[lang]/components/client/elements/signin-view.tsx +++ b/src/app/[locale]/components/client/elements/signin-view.tsx @@ -1,6 +1,7 @@ // signin-view.ts 'use client'; import { useContext, useEffect, useRef } from 'react'; +import { useTranslations } from 'next-intl'; import { signOut } from '@auth'; import { AuthContext, GlobalContext } from '@state'; import { ALogOut } from '@actions'; @@ -32,6 +33,8 @@ export const VSignIn = ({ user }: VSignInProps) => { const [, unloadUser] = ALogOut({}); const initd = useRef(false); + const t = useTranslations('SignIn'); + const handleSignOut = async () => { unloadUser(); @@ -41,9 +44,9 @@ export const VSignIn = ({ user }: VSignInProps) => { if (user || authd) return ( -); - returnSign out +{t('sign out')} navigate('/api/v1/auth/signin')}>Sign in ; + returnnavigate('/api/v1/auth/signin')}>{t('sign in')} ; }; diff --git a/src/app/[lang]/components/client/elements/signup-view.tsx b/src/app/[locale]/components/client/elements/signup-view.tsx similarity index 95% rename from src/app/[lang]/components/client/elements/signup-view.tsx rename to src/app/[locale]/components/client/elements/signup-view.tsx index 6b0d5950..e670a550 100644 --- a/src/app/[lang]/components/client/elements/signup-view.tsx +++ b/src/app/[locale]/components/client/elements/signup-view.tsx @@ -2,6 +2,7 @@ 'use client'; import { clsx } from "clsx"; import { useContext, useEffect, useRef, useState } from 'react'; +import { useTranslations } from 'next-intl'; import { signIn, signOut, getCsrf } from "@auth"; import { AuthContext } from '@state'; import { ALogIn, ALogOut } from '@actions'; @@ -47,6 +48,8 @@ export const VSignUp = ({ providers, user }: VSignUpProps) => { const signInUrl = '/api/v1/auth/signin' + const t = useTranslations('SignIn'); + const callbackUrl = process.env.NEXT_PUBLIC_NEXUS_BASE_PATH || "/" @@ -111,12 +114,12 @@ export const VSignUp = ({ providers, user }: VSignUpProps) => { name="email" value={email} onChange={(e) => setEmail(e)} - label="Your email" + label={t("your email")} className="pb-a1" placeholder="jack@doe.com" />+ + + + ); +} diff --git a/src/app/[lang]/page.tsx b/src/app/[locale]/page.tsx similarity index 100% rename from src/app/[lang]/page.tsx rename to src/app/[locale]/page.tsx diff --git a/src/app/[lang]/styles/page.module.css b/src/app/[locale]/styles/page.module.css similarity index 100% rename from src/app/[lang]/styles/page.module.css rename to src/app/[locale]/styles/page.module.css diff --git a/src/middleware.ts b/src/middleware.ts index e3b42ee7..924edb08 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -1,96 +1,21 @@ -// middleware.ts +// @middleware import type { NextRequest } from 'next/server'; import { NextResponse } from 'next/server'; -import acceptLanguage from 'accept-language'; -import { localeMap, LOCALES } from '@constants/server'; +import { authMiddleware } from './middlewares/authMiddleware'; +import { i18nDetectMiddleware } from './middlewares/i18nDetectMiddleware'; -const supportedLocales = [ - 'en', - 'it-IT', - 'pt-BR', - 'it', - 'pt', - 'ro', - 'ru', - 'pl-PL', - 'de', - 'fr', - 'ja-JP', - 'sv-SE', - 'et-EE', - 'cs-CZ', -]; - -acceptLanguage.languages(supportedLocales); +export const middlewares = [authMiddleware, i18nDetectMiddleware]; export const config = { - matcher: ['/api/:path*', '/default/dash/:path*'], -}; - -const allowedOrigins = { - [`${process.env.MAIN_URL}`]: process.env.MAIN_URL, - [`${process.env.NEXUS_HOST}`]: process.env.NEXUS_HOST, - [`${process.env.API_HOST}`]: process.env.API_HOST, + matcher: ['/api/:path*', '/(default|cs-cz|de-de|en|es-es|et-ee|fr-fr|it-it|ja-jp|pl-pl|ro|ru-ru|sv-se)/:path*'], }; -const headers: Record+ ++ {children} + = { - 'Access-Control-Allow-Origin': process.env.MAIN_URL || 'https://www.dreampip.com', - 'Cache-Control': 'maxage=0, s-maxage=300, stale-while-revalidate=300', - // DEV-DEBUG: - // 'content-type': 'application/json', - // 'Access-Control-Allow-Origin': 'http://localhost:2999', - 'Access-Control-Allow-Credentials': 'true', - 'Access-Control-Allow-Headers': 'baggage, sentry-trace', -}; - -export function middleware(request: NextRequest) { - // API COOKIES - if (request.nextUrl.pathname.startsWith('/api')) { - const origin = request.headers.get('x-forwarded-host') || ''; - if (origin !== process.env.MAIN_URL) { - headers['Access-Control-Allow-Origin'] = allowedOrigins[origin] || 'https://www.dreampip.com'; - } - - const response = NextResponse.next(); - const pkce = request.cookies.get('next-auth.pkce.code_verifier'); - - Object.keys(headers).forEach((key: string) => { - response.headers.set(key, headers[key]); - }); - - if (pkce?.value) { - response.cookies.set('next-auth.pkce.code_verifier', pkce.value, { - httpOnly: true, - sameSite: 'none', - path: '/', - secure: true, - }); - console.log({ pkce, response, to: request.nextUrl.pathname }); - } - return NextResponse.rewrite( - new URL( - `${process.env.REMOTE_DEV ? process.env.API_HOST_DEV : process.env.API_HOST}${request.nextUrl.pathname}${request.nextUrl.search}`, - ), - response, - ); +export default async function middleware(request: NextRequest) { + // if a response is returned, return it otherwise call `next()` + for (const fn of middlewares) { + const response = await fn(request); + if (response) return response; } - // LOCALIZATION - if ( - !/\.(.*)$/.test(request.nextUrl.pathname) && - (LOCALES.every((locale) => !request.nextUrl.href.includes(locale)) || - request.nextUrl.pathname.startsWith('/default')) - ) { - const newUrl = request.nextUrl.clone(); - const headers = request.headers.get('accept-language'); - - if (!headers) return NextResponse.rewrite(newUrl); - const savedLocale = request?.cookies?.get('NEXT_LOCALE'); - const newlocale = (savedLocale?.value || - acceptLanguage?.get(headers)?.toLocaleLowerCase() || - 'en') as keyof typeof localeMap; - newUrl.pathname = newUrl?.pathname?.replace('/default', localeMap[newlocale] || newlocale); - - return NextResponse.redirect(newUrl); - } + return NextResponse.next(); } diff --git a/src/middlewares/authMiddleware.ts b/src/middlewares/authMiddleware.ts new file mode 100644 index 00000000..1746ff23 --- /dev/null +++ b/src/middlewares/authMiddleware.ts @@ -0,0 +1,54 @@ +// middleware.ts +import type { NextRequest } from 'next/server'; +import { NextResponse } from 'next/server'; + +const allowedOrigins = { + [`${process.env.MAIN_URL}`]: process.env.MAIN_URL, + [`${process.env.NEXUS_HOST}`]: process.env.NEXUS_HOST, + [`${process.env.API_HOST}`]: process.env.API_HOST, +}; + +const headers: Record = { + 'Access-Control-Allow-Origin': process.env.MAIN_URL || 'https://www.dreampip.com', + 'Cache-Control': 'maxage=0, s-maxage=300, stale-while-revalidate=300', + // DEV-DEBUG: + // 'content-type': 'application/json', + // 'Access-Control-Allow-Origin': 'http://localhost:2999', + 'Access-Control-Allow-Credentials': 'true', + 'Access-Control-Allow-Headers': 'baggage, sentry-trace', +}; + +export const authMiddleware = async (request: NextRequest) => { + console.log('--- ran: API MIDDLEWARE ---'); + // API COOKIES + if (request.nextUrl.pathname.startsWith('/api')) { + const origin = request.headers.get('x-forwarded-host') || ''; + if (origin !== process.env.MAIN_URL) { + headers['Access-Control-Allow-Origin'] = allowedOrigins[origin] || 'https://www.dreampip.com'; + } + + const response = NextResponse.next(); + const pkce = request.cookies.get('next-auth.pkce.code_verifier'); + + Object.keys(headers).forEach((key: string) => { + response.headers.set(key, headers[key]); + }); + + if (pkce?.value) { + response.cookies.set('next-auth.pkce.code_verifier', pkce.value, { + httpOnly: true, + sameSite: 'none', + path: '/', + secure: true, + }); + console.log({ pkce, response, to: request.nextUrl.pathname }); + } + return NextResponse.rewrite( + new URL( + `${process.env.REMOTE_DEV ? process.env.API_HOST_DEV : process.env.API_HOST}${request.nextUrl.pathname}${request.nextUrl.search}`, + ), + response, + ); + } + return; +}; diff --git a/src/middlewares/i18nDetectMiddleware.ts b/src/middlewares/i18nDetectMiddleware.ts new file mode 100644 index 00000000..e5fd1cc0 --- /dev/null +++ b/src/middlewares/i18nDetectMiddleware.ts @@ -0,0 +1,58 @@ +// middleware.ts +'use server'; +import type { NextRequest } from 'next/server'; +import { NextResponse } from 'next/server'; +import acceptLanguage from 'accept-language'; +import { localeMap, LOCALES } from '@constants/server'; + +const supportedLocales = [ + 'en', + 'it-IT', + 'pt-BR', + 'it', + 'pt', + 'ro', + 'ru', + 'pl-PL', + 'de', + 'fr', + 'ja-JP', + 'sv-SE', + 'et-EE', + 'cs-CZ', +]; + +acceptLanguage.languages(supportedLocales); + +export const i18nDetectMiddleware = async (request: NextRequest) => { + console.log('--- ran: I18N DETECT MIDDLEWARE ---'); + // LOCALIZATION + if ( + !/\.(.*)$/.test(request.nextUrl.pathname) && + (LOCALES.every((locale) => !request.nextUrl.href.includes(locale)) || + request.nextUrl.pathname.startsWith('/default')) + ) { + const newUrl = request.nextUrl.clone(); + const headers = request.headers.get('accept-language'); + + if (!headers) return NextResponse.rewrite(newUrl); + const savedLocale = request?.cookies?.get('NEXT_LOCALE'); + const newlocale = (savedLocale?.value || + acceptLanguage?.get(headers)?.toLocaleLowerCase() || + 'en') as keyof typeof localeMap; + newUrl.pathname = newUrl?.pathname?.replace('/default', localeMap[newlocale] || newlocale); + + return NextResponse.redirect(newUrl); + } + + if (!/\.(.*)$/.test(request.nextUrl.pathname) && LOCALES.some((locale) => !request.nextUrl.href.includes(locale))) { + const newHeaders = new Headers(request.headers); + newHeaders.set('x-dp-locale', request.nextUrl.pathname.split('/')[1]); + return NextResponse.next({ + request: { + headers: newHeaders, + }, + }); + } + return; +}; diff --git a/tsconfig.json b/tsconfig.json index 8bac0deb..b164b986 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,18 +19,18 @@ }, ], "paths": { - "@styles": ["./src/app/[lang]/styles"], - "@styles/*": ["./src/app/[lang]/styles/*"], - "@atoms": ["./src/app/[lang]/components/system/atoms"], - "@atoms/*": ["./src/app/[lang]/components/system/atoms/*"], - "@blocks/client": ["./src/app/[lang]/components/client/blocks"], - "@blocks/client/*": ["./src/app/[lang]/components/client/blocks/*"], - "@blocks/server": ["./src/app/[lang]/components/server/blocks"], - "@blocks/server/*": ["./src/app/[lang]/components/server/blocks/*"], + "@styles": ["./src/app/[locale]/styles"], + "@styles/*": ["./src/app/[locale]/styles/*"], + "@atoms": ["./src/app/[locale]/components/system/atoms"], + "@atoms/*": ["./src/app/[locale]/components/system/atoms/*"], + "@blocks/client": ["./src/app/[locale]/components/client/blocks"], + "@blocks/client/*": ["./src/app/[locale]/components/client/blocks/*"], + "@blocks/server": ["./src/app/[locale]/components/server/blocks"], + "@blocks/server/*": ["./src/app/[locale]/components/server/blocks/*"], "@constants/server": ["./lib/constants/server"], "@constants/client": ["./lib/constants/client"], - "@elements/client": ["./src/app/[lang]/components/client/elements"], - "@elements/client/*": ["./src/app/[lang]/components/client/elements/*"], + "@elements/client": ["./src/app/[locale]/components/client/elements"], + "@elements/client/*": ["./src/app/[locale]/components/client/elements/*"], "@model": ["./lib/model"], "@model/*": ["./lib/model/*"], "@view": ["./lib/view"], @@ -42,20 +42,20 @@ "@types": ["./lib/types"], "@types/*": ["./lib/types/*"], "@auth": ["./lib/auth"], - "@auth/adapter": ["./src/app/[lang]/api/auth/[...nextauth]"], - "@auth/adapter/*": ["./src/app/[lang]/api/auth/[...nextauth]/*"], + "@auth/adapter": ["./src/app/[locale]/api/auth/[...nextauth]"], + "@auth/adapter/*": ["./src/app/[locale]/api/auth/[...nextauth]/*"], "@state/*": ["./lib/state/*"], "@state": ["./lib/state"], "@hooks/*": ["./lib/hooks/*"], "@hooks": ["./lib/hooks"], "@actions/*": ["./lib/actions/*"], "@actions": ["./lib/actions"], - "@gateway/*": ["./src/app/[lang]/gateway/*"], - "@gateway": ["./src/app/[lang]/gateway"], + "@gateway/*": ["./src/app/[locale]/gateway/*"], + "@gateway": ["./src/app/[locale]/gateway"], "@controller/*": ["./lib/model/interfaces/*"], "@controller": ["./lib/model/interfaces"], - "@components/*": ["./src/app/[lang]/components/*"], - "@components": ["./src/app/[lang]/components"], + "@components/*": ["./src/app/[locale]/components/*"], + "@components": ["./src/app/[locale]/components"], }, }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], From 5ec790ab98fbb2c84868cc43d028d8adbb16f2c4 Mon Sep 17 00:00:00 2001 From: Angelo Reale <12191809+angeloreale@users.noreply.github.com> Date: Wed, 21 Aug 2024 21:25:25 +0100 Subject: [PATCH 08/21] [DPCP-37] [DPCP-91] [DPCP-92] Nits (#43) * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization * ar(feat) [DPCP-37]: Localization --- lib/dictionaries/global/cs-cz.json | 8 +++++- lib/dictionaries/global/de-de.json | 8 +++++- lib/dictionaries/global/default.json | 8 +++++- lib/dictionaries/global/en.json | 8 +++++- lib/dictionaries/global/es-es.json | 8 +++++- lib/dictionaries/global/et-ee.json | 8 +++++- lib/dictionaries/global/fr-fr.json | 8 +++++- lib/dictionaries/global/it-it.json | 8 +++++- lib/dictionaries/global/ja-jp.json | 8 +++++- lib/dictionaries/global/pl-pl.json | 8 +++++- lib/dictionaries/global/pt-br.json | 8 +++++- lib/dictionaries/global/ro.json | 8 +++++- lib/dictionaries/global/ru-ru.json | 8 +++++- lib/dictionaries/global/sv-se.json | 8 +++++- next.config.js | 25 ++++++++++++++----- .../client/elements/signin-view.tsx | 4 ++- .../client/elements/signup-view.tsx | 4 +-- src/app/[locale]/dash/services/page.tsx | 13 ++++++++++ src/app/[locale]/layout.tsx | 17 ++++++++----- src/app/layout.tsx | 14 +++++++++++ src/middleware.ts | 7 ++++++ src/middlewares/authMiddleware.ts | 2 +- src/middlewares/i18nDetectMiddleware.ts | 2 +- 23 files changed, 169 insertions(+), 31 deletions(-) create mode 100644 src/app/[locale]/dash/services/page.tsx create mode 100644 src/app/layout.tsx diff --git a/lib/dictionaries/global/cs-cz.json b/lib/dictionaries/global/cs-cz.json index f4595c86..d5ca34e5 100644 --- a/lib/dictionaries/global/cs-cz.json +++ b/lib/dictionaries/global/cs-cz.json @@ -1,13 +1,19 @@ { + "Dashboard": { + "title": "DreamPip — Nástěnka", + "description": "Vaše cesta začíná zde. DreamPip je fintech pro soucit." + }, "NavBar": { "welcome": "Vítejte" }, "SignIn": { + "welcome": "Vítejte", "continue": "Pokračovat", "continue with": "Pokračovat s", "sign in": "Přihlásit", "sign out": "Odhlásit", - "your email": "Váš e-mail" + "your email": "Váš e-mail", + "i hope you make yourself at home": "Doufám, že se uvidíš jako doma" }, "CardGrid": { "staff picks": "Výběr zaměstnanců" diff --git a/lib/dictionaries/global/de-de.json b/lib/dictionaries/global/de-de.json index 7a5729b5..37748c62 100644 --- a/lib/dictionaries/global/de-de.json +++ b/lib/dictionaries/global/de-de.json @@ -1,13 +1,19 @@ { + "Dashboard": { + "title": "DreamPip — Dashboard", + "description": "Ihre Reise beginnt hier. DreamPip ist Finanztechnologie für Mitgefühl." + }, "NavBar": { "welcome": "Willkommen" }, "SignIn": { + "welcome": "Willkommen", "continue": "Weiter", "continue with": "Weiter mit", "sign in": "Anmelden", "sign out": "Abmelden", - "your email": "Deine E-Mail" + "your email": "Deine E-Mail", + "i hope you make yourself at home": "Ich hoffe, du fühlst dich wie zu Hause" }, "CardGrid": { "staff picks": "Auswahl des Personals" diff --git a/lib/dictionaries/global/default.json b/lib/dictionaries/global/default.json index bc506591..9238009a 100644 --- a/lib/dictionaries/global/default.json +++ b/lib/dictionaries/global/default.json @@ -1,13 +1,19 @@ { + "Dashboard": { + "title": "DreamPip — Dashboard", + "description": "Your journey starts here. DreamPip is fintech for compassion." + }, "NavBar": { "welcome": "Welcome" }, "SignIn": { + "welcome": "Welcome", "continue": "Continue", "continue with": "Continue with", "sign in": "Sign in", "sign out": "Sign out", - "your email": "Your email" + "your email": "Your email", + "i hope you make yourself at home": "I hope you make yourself at home" }, "CardGrid": { "staff picks": "Staff Picks" diff --git a/lib/dictionaries/global/en.json b/lib/dictionaries/global/en.json index ae88cfc3..e8038033 100644 --- a/lib/dictionaries/global/en.json +++ b/lib/dictionaries/global/en.json @@ -1,12 +1,18 @@ { + "Dashboard": { + "title": "DreamPip — Dashboard", + "description": "Your journey starts here. DreamPip is fintech for compassion." + }, "NavBar": { "welcome": "Welcome" }, "SignIn": { + "welcome": "Welcome", "continue": "Continue", "continue with": "Continue with", "sign in": "Sign in", - "sign out": "Sign out" + "sign out": "Sign out", + "i hope you make yourself at home": "I hope you make yourself at home" }, "CardGrid": { "staff picks": "Staff Picks" diff --git a/lib/dictionaries/global/es-es.json b/lib/dictionaries/global/es-es.json index 1a804560..2674d280 100644 --- a/lib/dictionaries/global/es-es.json +++ b/lib/dictionaries/global/es-es.json @@ -1,13 +1,19 @@ { + "Dashboard": { + "title": "DreamPip — Panel de control", + "description": "Tu viaje comienza aquí. DreamPip es fintech para la compasión." + }, "NavBar": { "welcome": "Bienvenido" }, "SignIn": { + "welcome": "Bienvenido", "continue": "Continuar", "continue with": "Continuar con", "sign in": "Iniciar sesión", "sign out": "Cerrar sesión", - "your email": "Tu correo electrónico" + "your email": "Tu correo electrónico", + "i hope you make yourself at home": "Espero que te sientas como en casa" }, "CardGrid": { "staff picks": "Selecciones del personal" diff --git a/lib/dictionaries/global/et-ee.json b/lib/dictionaries/global/et-ee.json index 1896dd6c..ad95a264 100644 --- a/lib/dictionaries/global/et-ee.json +++ b/lib/dictionaries/global/et-ee.json @@ -1,13 +1,19 @@ { + "Dashboard": { + "title": "DreamPip — Juhtpaneel", + "description": "Teie teekond algab siin. DreamPip on finantstehnoloogia kaastunde jaoks." + }, "NavBar": { "welcome": "Tere tulemast" }, "SignIn": { + "welcome": "Tere tulemast", "continue": "Jätka", "continue with": "Jätka", "sign in": "Logi sisse", "sign out": "Logi välja", - "your email": "Sinu e-post" + "your email": "Sinu e-post", + "i hope you make yourself at home": "Loodan, et tunned end koduselt" }, "CardGrid": { "staff picks": "Töötajate valikud" diff --git a/lib/dictionaries/global/fr-fr.json b/lib/dictionaries/global/fr-fr.json index 21db518c..f8fc85cf 100644 --- a/lib/dictionaries/global/fr-fr.json +++ b/lib/dictionaries/global/fr-fr.json @@ -1,13 +1,19 @@ { + "Dashboard": { + "title": "DreamPip — Tableau de bord", + "description": "Votre voyage commence ici. DreamPip est de la fintech pour la compassion." + }, "NavBar": { "welcome": "Bienvenue" }, "SignIn": { + "welcome": "Bienvenue", "continue": "Continuer", "continue with": "Continuer avec", "sign in": "Se connecter", "sign out": "Se déconnecter", - "your email": "Votre adresse e-mail" + "your email": "Votre adresse e-mail", + "i hope you make yourself at home": "J’espère que vous vous sentirez comme chez vous" }, "CardGrid": { "staff picks": "Choix du personnel" diff --git a/lib/dictionaries/global/it-it.json b/lib/dictionaries/global/it-it.json index 7cd1f4a4..4fbbde0e 100644 --- a/lib/dictionaries/global/it-it.json +++ b/lib/dictionaries/global/it-it.json @@ -1,13 +1,19 @@ { + "Dashboard": { + "title": "DreamPip — Pannello di controllo", + "description": "Il tuo viaggio inizia qui. DreamPip è un'azienda fintech per la compassione." + }, "NavBar": { "welcome": "Benvenuto" }, "SignIn": { + "welcome": "Benvenuto", "continue": "Prosegue", "continue with": "Prosegue con", "sign in": "Accedi", "sign out": "Scollega", - "your email": "La sua mail" + "your email": "La sua mail", + "i hope you make yourself at home": "Spero che tu ti senta come a casa" }, "CardGrid": { "staff picks": "Preferiti dello Staff" diff --git a/lib/dictionaries/global/ja-jp.json b/lib/dictionaries/global/ja-jp.json index 2d3c71e9..1cba18b9 100644 --- a/lib/dictionaries/global/ja-jp.json +++ b/lib/dictionaries/global/ja-jp.json @@ -1,13 +1,19 @@ { + "Dashboard": { + "title": "DreamPip — ダッシュボード", + "description": "あなたの旅はここから始まります。DreamPipは共感のためのフィンテックです。" + }, "NavBar": { "welcome": "ようこそ" }, "SignIn": { + "welcome": "ようこそ", "continue": "続行", "continue with": "続行する", "sign in": "サインイン", "sign out": "ログアウト", - "your email": "あなたのメール" + "your email": "あなたのメール", + "i hope you make yourself at home": "くつろいでくださいね" }, "CardGrid": { "staff picks": "スタッフおすすめ" diff --git a/lib/dictionaries/global/pl-pl.json b/lib/dictionaries/global/pl-pl.json index 095d9adb..4472faa3 100644 --- a/lib/dictionaries/global/pl-pl.json +++ b/lib/dictionaries/global/pl-pl.json @@ -1,13 +1,19 @@ { + "Dashboard": { + "title": "DreamPip — Panel", + "description": "Twoja podróż zaczyna się tutaj. DreamPip to finanse technologiczne dla współczucia." + }, "NavBar": { "welcome": "Witaj" }, "SignIn": { + "welcome": "Witaj", "continue": "Kontynuuj", "continue with": "Kontynuuj z", "sign in": "Zaloguj się", "sign out": "Wyloguj się", - "your email": "Twój adres email" + "your email": "Twój adres email", + "i hope you make yourself at home": "Mam nadzieję, że będziesz się czuł jak u siebie w domu" }, "CardGrid": { "staff picks": "Wybór pracowników" diff --git a/lib/dictionaries/global/pt-br.json b/lib/dictionaries/global/pt-br.json index 8708a40f..f0dfdc9d 100644 --- a/lib/dictionaries/global/pt-br.json +++ b/lib/dictionaries/global/pt-br.json @@ -1,11 +1,17 @@ { + "Dashboard": { + "title": "DreamPip — Painel", + "description": "Sua jornada começa aqui. DreamPip é uma fintech para a compaixão." + }, "NavBar": { "welcome": "Bem-vindo" }, "SignIn": { + "welcome": "Bem-vindo", "continue": "Continuar", "continue with": "Continuar com", "sign in": "Entrar", "sign out": "Sair", - "your email": "Seu email" + "your email": "Seu email", + "i hope you make yourself at home": "Espero que você se sinta em casa" }, "CardGrid": { "staff picks": "Escolhas da Equipe" } } diff --git a/lib/dictionaries/global/ro.json b/lib/dictionaries/global/ro.json index 81defd72..b44b6d9d 100644 --- a/lib/dictionaries/global/ro.json +++ b/lib/dictionaries/global/ro.json @@ -1,13 +1,19 @@ { + "Dashboard": { + "title": "DreamPip — Tablou de bord", + "description": "Călătoria ta începe aici. DreamPip este fintech pentru compasiune." + }, "NavBar": { "welcome": "Bine ai venit" }, "SignIn": { + "welcome": "Bine ai venit", "continue": "Continuați", "continue with": "Continuați cu", "sign in": "Conectați-vă", "sign out": "Deconectați-vă", - "your email": "Adresa ta de email" + "your email": "Adresa ta de email", + "i hope you make yourself at home": "Sper că te simți ca acasă" }, "CardGrid": { "staff picks": "Alegerile personalului" diff --git a/lib/dictionaries/global/ru-ru.json b/lib/dictionaries/global/ru-ru.json index 7f392d86..0ba10ea4 100644 --- a/lib/dictionaries/global/ru-ru.json +++ b/lib/dictionaries/global/ru-ru.json @@ -1,13 +1,19 @@ { + "Dashboard": { + "title": "DreamPip — Панель", + "description": "Ваше путешествие начинается здесь. DreamPip - финтех для сострадания." + }, "NavBar": { "welcome": "Добро пожаловать" }, "SignIn": { + "welcome": "Добро пожаловать", "continue": "Продолжить", "continue with": "Продолжить с", "sign in": "Войти", "sign out": "Выйти", - "your email": "Ваш электронный адрес" + "your email": "Ваш электронный адрес", + "i hope you make yourself at home": "Я надеюсь, что вы почувствуете себя как дома" }, "CardGrid": { "staff picks": "Выбор персонала" diff --git a/lib/dictionaries/global/sv-se.json b/lib/dictionaries/global/sv-se.json index 112636b6..d3889943 100644 --- a/lib/dictionaries/global/sv-se.json +++ b/lib/dictionaries/global/sv-se.json @@ -1,13 +1,19 @@ { + "Dashboard": { + "title": "DreamPip — Instrumentpanel", + "description": "Din resa börjar här. DreamPip är fintech för medkänsla." + }, "NavBar": { "welcome": "Välkommen" }, "SignIn": { + "welcome": "Välkommen", "continue": "Fortsätt", "continue with": "Fortsätt med", "sign in": "Logga in", "sign out": "Logga ut", - "your email": "Din e-post" + "your email": "Din e-post", + "i hope you make yourself at home": "Jag hoppas att du känner dig som hemma" }, "CardGrid": { "staff picks": "Personals val" diff --git a/next.config.js b/next.config.js index 306993fb..e4d39424 100644 --- a/next.config.js +++ b/next.config.js @@ -4,7 +4,10 @@ const createNextIntlPlugin = require('next-intl/plugin'); const withNextIntl = createNextIntlPlugin('./src/app/[locale]/i18n.ts'); const nextConfig = { - assetPrefix: process.env.NEXUS_HOST || 'https://nyx.dreampip.com', + assetPrefix: + (process.env.VERCEL_ENV && process.env.VERCEL_ENV !== 'production' + ? `https://${process.env.VERCEL_URL}` + : process.env.NEXUS_HOST) || 'https://nyx.dreampip.com', transpilePackages: ['next-auth'], images: { remotePatterns: [ @@ -31,11 +34,21 @@ const nextConfig = { destination: '/dash/services/rickmorty/list', permanent: false, }, - // { - // source: '/signin', - // destination: '/dash/signin', - // permanent: false, - // }, + { + source: '/', + destination: '/default/dash/signin', + permanent: false, + }, + { + source: '/dash', + destination: '/default/dash/signin', + permanent: false, + }, + { + source: '/dash/:path*', + destination: '/default/dash/:path*', + permanent: false, + }, ]; }, }; diff --git a/src/app/[locale]/components/client/elements/signin-view.tsx b/src/app/[locale]/components/client/elements/signin-view.tsx index 5f0a1462..88625979 100644 --- a/src/app/[locale]/components/client/elements/signin-view.tsx +++ b/src/app/[locale]/components/client/elements/signin-view.tsx @@ -48,5 +48,7 @@ export const VSignIn = ({ user }: VSignInProps) => { ); - return navigate('/api/v1/auth/signin')}>{t('sign in')} ; + return{ + navigate('/dash/signin'); + }}>{t('sign in')} ; }; diff --git a/src/app/[locale]/components/client/elements/signup-view.tsx b/src/app/[locale]/components/client/elements/signup-view.tsx index e670a550..4648e0d8 100644 --- a/src/app/[locale]/components/client/elements/signup-view.tsx +++ b/src/app/[locale]/components/client/elements/signup-view.tsx @@ -94,8 +94,8 @@ export const VSignUp = ({ providers, user }: VSignUpProps) => { if (user || authd) { return- } diff --git a/src/app/[locale]/dash/services/page.tsx b/src/app/[locale]/dash/services/page.tsx new file mode 100644 index 00000000..47679737 --- /dev/null +++ b/src/app/[locale]/dash/services/page.tsx @@ -0,0 +1,13 @@ +// page.tsx +import { DPPublicListings } from '@blocks/server'; + +export default function Home({ params }: any) { + const mode = params?.mode || 'list'; + return ( +Welcome, {coercedName}. I hope you make yourself at home. - +{t('welcome')}, {coercedName}. {t('i hope you make yourself at home')}. ++ + ); +} diff --git a/src/app/[locale]/layout.tsx b/src/app/[locale]/layout.tsx index 70047dab..9d313e5c 100644 --- a/src/app/[locale]/layout.tsx +++ b/src/app/[locale]/layout.tsx @@ -2,13 +2,18 @@ import type { Metadata } from 'next'; import { DPTopNav } from '@blocks/server'; import { RootProviders } from '@state'; import { NextIntlClientProvider } from 'next-intl'; -import { getLocale, getMessages } from 'next-intl/server'; +import { getLocale, getMessages, getTranslations } from 'next-intl/server'; import './globals.css'; -export const metadata: Metadata = { - title: process.env.PATTERNS_TITLE, - description: process.env.PATTERNS_DESCRIPTION, -}; +export async function generateMetadata(): Promise+ ++ { + // fetch data + const t = await getTranslations('Dashboard'); + + return { + title: t('title'), + description: t('description'), + }; +} export default async function RootLayout({ children, params }: { children: React.ReactNode; params: any }) { const { locale: orig } = params; @@ -18,7 +23,7 @@ export default async function RootLayout({ children, params }: { children: React const libLocale = await getLocale(); return ( - + diff --git a/src/app/layout.tsx b/src/app/layout.tsx new file mode 100644 index 00000000..0f5bdae7 --- /dev/null +++ b/src/app/layout.tsx @@ -0,0 +1,14 @@ +import type { Metadata } from 'next'; + +export const metadata: Metadata = { + title: 'DreamPip — Dashboard', + description: 'Your journey starts here. DreamPip is fintech for compassion.', +}; + +export default async function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} diff --git a/src/middleware.ts b/src/middleware.ts index 924edb08..21ebd02f 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -10,7 +10,14 @@ export const config = { matcher: ['/api/:path*', '/(default|cs-cz|de-de|en|es-es|et-ee|fr-fr|it-it|ja-jp|pl-pl|ro|ru-ru|sv-se)/:path*'], }; +const blocklist = ['_next']; + export default async function middleware(request: NextRequest) { + const url = request?.nextUrl?.pathname; + if (blocklist.some((pattern) => url?.includes(pattern))) { + console.log('--- PATTERN BOCKED: ---', url); + return NextResponse.next(); + } // if a response is returned, return it otherwise call `next()` for (const fn of middlewares) { const response = await fn(request); diff --git a/src/middlewares/authMiddleware.ts b/src/middlewares/authMiddleware.ts index 1746ff23..dd5699a1 100644 --- a/src/middlewares/authMiddleware.ts +++ b/src/middlewares/authMiddleware.ts @@ -19,7 +19,7 @@ const headers: Record = { }; export const authMiddleware = async (request: NextRequest) => { - console.log('--- ran: API MIDDLEWARE ---'); + console.log('--- ran: API MIDDLEWARE ---', request.nextUrl.href); // API COOKIES if (request.nextUrl.pathname.startsWith('/api')) { const origin = request.headers.get('x-forwarded-host') || ''; diff --git a/src/middlewares/i18nDetectMiddleware.ts b/src/middlewares/i18nDetectMiddleware.ts index e5fd1cc0..06a741e5 100644 --- a/src/middlewares/i18nDetectMiddleware.ts +++ b/src/middlewares/i18nDetectMiddleware.ts @@ -25,7 +25,7 @@ const supportedLocales = [ acceptLanguage.languages(supportedLocales); export const i18nDetectMiddleware = async (request: NextRequest) => { - console.log('--- ran: I18N DETECT MIDDLEWARE ---'); + console.log('--- ran: I18N DETECT MIDDLEWARE ---', request.nextUrl.href); // LOCALIZATION if ( !/\.(.*)$/.test(request.nextUrl.pathname) && From 707cecfa66b0578e573a5fa2d44485a28b973b9d Mon Sep 17 00:00:00 2001 From: Angelo Reale <12191809+angeloreale@users.noreply.github.com> Date: Wed, 21 Aug 2024 21:39:49 +0100 Subject: [PATCH 09/21] ar(fix): services --- next.config.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/next.config.js b/next.config.js index e4d39424..11b2ac3f 100644 --- a/next.config.js +++ b/next.config.js @@ -25,13 +25,13 @@ const nextConfig = { async redirects() { return [ { - source: '/dash/services/hypnos', - destination: '/dash/services/hypnos/list', + source: '/dash/services/:service', + destination: '/dash/services/:service/list', permanent: false, }, { - source: '/dash/services/rickmorty', - destination: '/dash/services/rickmorty/list', + source: '/:locale/dash/services/:service', + destination: '/:locale/dash/services/:service/list', permanent: false, }, { From 138e59de58c13db207a78166e76e6782be500cb5 Mon Sep 17 00:00:00 2001 From: Angelo Reale <12191809+angeloreale@users.noreply.github.com> Date: Fri, 23 Aug 2024 23:09:47 +0100 Subject: [PATCH 10/21] ar(fix) apple pkce --- src/middlewares/authMiddleware.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/middlewares/authMiddleware.ts b/src/middlewares/authMiddleware.ts index dd5699a1..7b2356cb 100644 --- a/src/middlewares/authMiddleware.ts +++ b/src/middlewares/authMiddleware.ts @@ -28,14 +28,14 @@ export const authMiddleware = async (request: NextRequest) => { } const response = NextResponse.next(); - const pkce = request.cookies.get('next-auth.pkce.code_verifier'); + const pkce = request.cookies.get('authjs.pkce.code_verifier'); Object.keys(headers).forEach((key: string) => { response.headers.set(key, headers[key]); }); if (pkce?.value) { - response.cookies.set('next-auth.pkce.code_verifier', pkce.value, { + response.cookies.set('authjs.pkce.code_verifier', pkce.value, { httpOnly: true, sameSite: 'none', path: '/', From 8aeced17863a1e5604725c9311ee238cd5834629 Mon Sep 17 00:00:00 2001 From: Angelo Reale <12191809+angeloreale@users.noreply.github.com> Date: Fri, 23 Aug 2024 23:32:51 +0100 Subject: [PATCH 11/21] ar(fix) apple pkce --- src/app/[locale]/components/client/elements/signup-view.tsx | 2 +- src/middlewares/authMiddleware.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/[locale]/components/client/elements/signup-view.tsx b/src/app/[locale]/components/client/elements/signup-view.tsx index 4648e0d8..51ebff0d 100644 --- a/src/app/[locale]/components/client/elements/signup-view.tsx +++ b/src/app/[locale]/components/client/elements/signup-view.tsx @@ -132,7 +132,7 @@ export const VSignUp = ({ providers, user }: VSignUpProps) => { )}