From c4332d97c7f180cc387761d9760df51298873b06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85rth=E1=80=9Dur?= Date: Mon, 2 Oct 2023 23:58:17 +0400 Subject: [PATCH 1/5] fix: use dictionary --- .gitignore | 3 +++ app/dictionaries.ts | 8 +++++++ components/hello-world/hello-world.tsx | 32 +++++++++++++++----------- 3 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 app/dictionaries.ts diff --git a/.gitignore b/.gitignore index 8f322f0..7b88226 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,6 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +# StoryBook +/storybook-static diff --git a/app/dictionaries.ts b/app/dictionaries.ts new file mode 100644 index 0000000..8a0829d --- /dev/null +++ b/app/dictionaries.ts @@ -0,0 +1,8 @@ +import 'server-only'; + +const dictionaries = { + en: () => import('../dictionaries/en.json').then((module) => module.default), + es: () => import('../dictionaries/es.json').then((module) => module.default), +}; + +export const getDictionary = async (locale: string) => dictionaries[locale](); diff --git a/components/hello-world/hello-world.tsx b/components/hello-world/hello-world.tsx index 879ec2a..662dff8 100644 --- a/components/hello-world/hello-world.tsx +++ b/components/hello-world/hello-world.tsx @@ -2,17 +2,23 @@ import Image from 'next/image'; import Earth from '@/public/earth.svg'; import { Title } from './hello-world.css'; +import { getDictionary } from '../../app/dictionaries'; -export const HelloWorld = ({ name = 'World' }) => ( - <> -

Hello {name}!

- Earth image - -); +export const HelloWorld = async ({ name = 'World' }) => { + const dict = await getDictionary('en'); + return ( + <> +

+ {dict.hello} {name}! +

+ Earth image + + ); +}; From 7024af58473ea7d34a0f9ad897403df5a62532d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85rth=E1=80=9Dur?= Date: Tue, 3 Oct 2023 00:00:34 +0400 Subject: [PATCH 2/5] chore: fix typings --- app/dictionaries.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/dictionaries.ts b/app/dictionaries.ts index 8a0829d..a2b4eeb 100644 --- a/app/dictionaries.ts +++ b/app/dictionaries.ts @@ -5,4 +5,5 @@ const dictionaries = { es: () => import('../dictionaries/es.json').then((module) => module.default), }; -export const getDictionary = async (locale: string) => dictionaries[locale](); +export const getDictionary = async (locale: 'es' | 'en') => + dictionaries[locale](); From 0b99663813196a068c0202bd97ea6b3a2a9feaee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85rth=E1=80=9Dur?= Date: Tue, 3 Oct 2023 23:32:12 +0400 Subject: [PATCH 3/5] fix: translation issues --- README.md | 12 ++++++++++-- app/{ => [lang]}/globals.css | 0 app/{ => [lang]}/growthbook.ts | 0 app/{ => [lang]}/layout.tsx | 11 ++++++++++- app/{ => [lang]}/page.tsx | 11 +++++++++-- app/{ => [lang]}/providers.tsx | 0 app/dictionaries.ts | 9 --------- components/hello-world/hello-world.tsx | 13 ++++++++++--- dictionaries/en.json | 6 ++++-- dictionaries/es.json | 6 ++++-- dictionaries/index.ts | 9 +++++++++ tsconfig.json | 4 +++- types/locales.ts | 1 + 13 files changed, 60 insertions(+), 22 deletions(-) rename app/{ => [lang]}/globals.css (100%) rename app/{ => [lang]}/growthbook.ts (100%) rename app/{ => [lang]}/layout.tsx (71%) rename app/{ => [lang]}/page.tsx (95%) rename app/{ => [lang]}/providers.tsx (100%) delete mode 100644 app/dictionaries.ts create mode 100644 dictionaries/index.ts create mode 100644 types/locales.ts diff --git a/README.md b/README.md index 50910de..3f8bf92 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,24 @@ +# React.js Hello World (Enterprise Edition) + This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). +## Currently Supported Features to be continued... + +- A/B testing +- Localization +- Server-side rendering + ## Getting Started First, run the development server: -```bash +```sh bun run dev # or pnpm dev ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +Open [http://localhost:3000/en](http://localhost:3000/en) with your browser to see the result. You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. diff --git a/app/globals.css b/app/[lang]/globals.css similarity index 100% rename from app/globals.css rename to app/[lang]/globals.css diff --git a/app/growthbook.ts b/app/[lang]/growthbook.ts similarity index 100% rename from app/growthbook.ts rename to app/[lang]/growthbook.ts diff --git a/app/layout.tsx b/app/[lang]/layout.tsx similarity index 71% rename from app/layout.tsx rename to app/[lang]/layout.tsx index 8bc3f36..89a3c5a 100644 --- a/app/layout.tsx +++ b/app/[lang]/layout.tsx @@ -3,6 +3,11 @@ import type { Metadata } from 'next'; import { Inter } from 'next/font/google'; import Providers from './providers'; +import type { Locales } from '@/types/locales'; + +export async function generateStaticParams() { + return [{ lang: 'en' }, { lang: 'es' }]; +} const inter = Inter({ subsets: ['latin'] }); @@ -13,11 +18,15 @@ export const metadata: Metadata = { export default function RootLayout({ children, + params, }: { children: React.ReactNode; + params: { + lang: Locales; + }; }) { return ( - + {children} diff --git a/app/page.tsx b/app/[lang]/page.tsx similarity index 95% rename from app/page.tsx rename to app/[lang]/page.tsx index be146b8..234c12c 100644 --- a/app/page.tsx +++ b/app/[lang]/page.tsx @@ -1,7 +1,14 @@ import Image from 'next/image'; import { HelloWorld } from '@/components/hello-world'; +import { Locales } from '@/types/locales'; +import { getDictionary } from '@/dictionaries/index'; -export default function Home() { +export default async function Home({ + params: { lang }, +}: { + params: { lang: Locales }; +}) { + const dict = await getDictionary(lang); return (
@@ -40,7 +47,7 @@ export default function Home() { />
- +
import('../dictionaries/en.json').then((module) => module.default), - es: () => import('../dictionaries/es.json').then((module) => module.default), -}; - -export const getDictionary = async (locale: 'es' | 'en') => - dictionaries[locale](); diff --git a/components/hello-world/hello-world.tsx b/components/hello-world/hello-world.tsx index 662dff8..eaf1a24 100644 --- a/components/hello-world/hello-world.tsx +++ b/components/hello-world/hello-world.tsx @@ -2,10 +2,17 @@ import Image from 'next/image'; import Earth from '@/public/earth.svg'; import { Title } from './hello-world.css'; -import { getDictionary } from '../../app/dictionaries'; +import { getDictionary } from '@/dictionaries/index'; +import type { Locales } from '@/types/locales'; -export const HelloWorld = async ({ name = 'World' }) => { - const dict = await getDictionary('en'); +export const HelloWorld = async ({ + name, + lang = 'en', +}: { + name: string; + lang: Locales; +}) => { + const dict = await getDictionary(lang); return ( <>

diff --git a/dictionaries/en.json b/dictionaries/en.json index 8a91e98..2ba81d0 100644 --- a/dictionaries/en.json +++ b/dictionaries/en.json @@ -1,3 +1,5 @@ { - "hello": "Hola" -} \ No newline at end of file + "hello": "Hello", + "hey": "Hey", + "world": "World" +} diff --git a/dictionaries/es.json b/dictionaries/es.json index a479da3..d6c98c2 100644 --- a/dictionaries/es.json +++ b/dictionaries/es.json @@ -1,3 +1,5 @@ { - "hello": "Hello" -} \ No newline at end of file + "hello": "Hola", + "hey": "Eh", + "world": "Mundo" +} diff --git a/dictionaries/index.ts b/dictionaries/index.ts new file mode 100644 index 0000000..55a43c2 --- /dev/null +++ b/dictionaries/index.ts @@ -0,0 +1,9 @@ +import 'server-only'; +import type { Locales } from '@/types/locales'; + +const dictionaries = { + en: () => import('./en.json').then((module) => module.default), + es: () => import('./es.json').then((module) => module.default), +}; + +export const getDictionary = async (locale: Locales) => dictionaries[locale](); diff --git a/tsconfig.json b/tsconfig.json index dc4f358..94cb2f1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -31,7 +31,9 @@ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ "paths": { "@/components/*": ["./components/*"], - "@/public/*": ["./public/*"] + "@/public/*": ["./public/*"], + "@/dictionaries/*": ["./dictionaries/*"], + "@/types/*": ["./types/*"] }, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ diff --git a/types/locales.ts b/types/locales.ts new file mode 100644 index 0000000..9396ab6 --- /dev/null +++ b/types/locales.ts @@ -0,0 +1 @@ +export type Locales = 'en' | 'es'; From 78153c31a7bbb3cc588dea024095c9ecc1dd997c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85rth=E1=80=9Dur?= Date: Wed, 4 Oct 2023 00:57:21 +0400 Subject: [PATCH 4/5] chore: some moves --- app/{ => [lang]}/favicon.ico | Bin app/[lang]/layout.tsx | 5 +++-- 2 files changed, 3 insertions(+), 2 deletions(-) rename app/{ => [lang]}/favicon.ico (100%) diff --git a/app/favicon.ico b/app/[lang]/favicon.ico similarity index 100% rename from app/favicon.ico rename to app/[lang]/favicon.ico diff --git a/app/[lang]/layout.tsx b/app/[lang]/layout.tsx index 89a3c5a..7dc0acd 100644 --- a/app/[lang]/layout.tsx +++ b/app/[lang]/layout.tsx @@ -1,10 +1,11 @@ -import './globals.css'; import type { Metadata } from 'next'; import { Inter } from 'next/font/google'; import Providers from './providers'; import type { Locales } from '@/types/locales'; +import './globals.css'; + export async function generateStaticParams() { return [{ lang: 'en' }, { lang: 'es' }]; } @@ -12,7 +13,7 @@ export async function generateStaticParams() { const inter = Inter({ subsets: ['latin'] }); export const metadata: Metadata = { - title: 'React Hello World Enterprise Edition', + title: 'React Hello World | Enterprise Edition', description: 'Generated by create next app', }; From 203be3a2ad156b9ecb66b44b2df1e0214ce38edc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85rth=E1=80=9Dur?= Date: Wed, 4 Oct 2023 02:05:19 +0400 Subject: [PATCH 5/5] fix: build --- README.md | 2 +- app/{[lang] => }/favicon.ico | Bin app/{[lang] => }/globals.css | 0 app/{[lang] => }/growthbook.ts | 0 app/{[lang] => }/layout.tsx | 0 app/{[lang] => }/page.tsx | 0 app/{[lang] => }/providers.tsx | 0 components/hello-world/hello-world.stories.ts | 10 ++++++++-- dictionaries/index.ts | 3 ++- i18n-config.ts | 6 ++++++ 10 files changed, 17 insertions(+), 4 deletions(-) rename app/{[lang] => }/favicon.ico (100%) rename app/{[lang] => }/globals.css (100%) rename app/{[lang] => }/growthbook.ts (100%) rename app/{[lang] => }/layout.tsx (100%) rename app/{[lang] => }/page.tsx (100%) rename app/{[lang] => }/providers.tsx (100%) create mode 100644 i18n-config.ts diff --git a/README.md b/README.md index 3f8bf92..6d6f85d 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ bun run dev pnpm dev ``` -Open [http://localhost:3000/en](http://localhost:3000/en) with your browser to see the result. +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. diff --git a/app/[lang]/favicon.ico b/app/favicon.ico similarity index 100% rename from app/[lang]/favicon.ico rename to app/favicon.ico diff --git a/app/[lang]/globals.css b/app/globals.css similarity index 100% rename from app/[lang]/globals.css rename to app/globals.css diff --git a/app/[lang]/growthbook.ts b/app/growthbook.ts similarity index 100% rename from app/[lang]/growthbook.ts rename to app/growthbook.ts diff --git a/app/[lang]/layout.tsx b/app/layout.tsx similarity index 100% rename from app/[lang]/layout.tsx rename to app/layout.tsx diff --git a/app/[lang]/page.tsx b/app/page.tsx similarity index 100% rename from app/[lang]/page.tsx rename to app/page.tsx diff --git a/app/[lang]/providers.tsx b/app/providers.tsx similarity index 100% rename from app/[lang]/providers.tsx rename to app/providers.tsx diff --git a/components/hello-world/hello-world.stories.ts b/components/hello-world/hello-world.stories.ts index 0b3934a..92b9545 100644 --- a/components/hello-world/hello-world.stories.ts +++ b/components/hello-world/hello-world.stories.ts @@ -15,10 +15,16 @@ const meta = { export default meta; type Story = StoryObj; -export const LoggedIn: Story = { +export const LangdEn: Story = { args: { name: 'Jane Doe', + lang: 'en', }, }; -export const LoggedOut: Story = {}; +export const LangEs: Story = { + args: { + name: 'Jane Doe', + lang: 'es', + }, +}; diff --git a/dictionaries/index.ts b/dictionaries/index.ts index 55a43c2..48a3b96 100644 --- a/dictionaries/index.ts +++ b/dictionaries/index.ts @@ -6,4 +6,5 @@ const dictionaries = { es: () => import('./es.json').then((module) => module.default), }; -export const getDictionary = async (locale: Locales) => dictionaries[locale](); +export const getDictionary = async (locale: Locales) => + dictionaries[locale]?.() ?? dictionaries.en(); diff --git a/i18n-config.ts b/i18n-config.ts new file mode 100644 index 0000000..46b2e75 --- /dev/null +++ b/i18n-config.ts @@ -0,0 +1,6 @@ +export const i18n = { + defaultLocale: 'en', + locales: ['en', 'es'], +} as const; + +export type Locale = (typeof i18n)['locales'][number];