From a460d59e24d7d7f126d8dc5862cb7f55bb653cbd Mon Sep 17 00:00:00 2001 From: Salman ORAK <41747037+salmanorak@users.noreply.github.com> Date: Thu, 28 Dec 2023 13:27:41 +0000 Subject: [PATCH 1/2] Reduce Downloaded Locale With Defining Scope --- examples/next-pages/locales/en.ts | 2 + examples/next-pages/pages/ssr-ssg-scoped.tsx | 22 ++++++++ .../__tests__/get-locale-props.test.ts | 54 ++++++++++++++++++- .../src/common/filter-locales-by-namespace.ts | 18 +++++++ .../src/pages/create-get-locale-props.ts | 11 ++-- 5 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 examples/next-pages/pages/ssr-ssg-scoped.tsx create mode 100644 packages/next-international/src/common/filter-locales-by-namespace.ts diff --git a/examples/next-pages/locales/en.ts b/examples/next-pages/locales/en.ts index 272422a..16712c4 100644 --- a/examples/next-pages/locales/en.ts +++ b/examples/next-pages/locales/en.ts @@ -13,6 +13,8 @@ export default { 'missing.translation.in.fr': 'This should work', 'cows#one': 'A cow', 'cows#other': '{count} cows', + 'scope2.test': 'A scope', + 'scope2.more.test': 'A more scoped ', } as const; // We can also write locales using nested objects diff --git a/examples/next-pages/pages/ssr-ssg-scoped.tsx b/examples/next-pages/pages/ssr-ssg-scoped.tsx new file mode 100644 index 0000000..2acbd73 --- /dev/null +++ b/examples/next-pages/pages/ssr-ssg-scoped.tsx @@ -0,0 +1,22 @@ +import type { GetServerSideProps } from 'next'; +import { getLocaleProps, useChangeLocale, useCurrentLocale, useI18n, useScopedI18n } from '../locales'; + + +export const getServerSideProps: GetServerSideProps = getLocaleProps(['scope2']); +// export const getStaticProps: GetStaticProps = getLocaleProps(); + +export default function SSR() { + const t = useI18n(); + const locale = useCurrentLocale(); + + return ( +
+

SSR / SSG

+

+ Current locale: {locale} +

+

Hello: {t('scope2.test')}

+

Hello: {t('scope2.more.test')}

+
+ ); +} diff --git a/packages/next-international/__tests__/get-locale-props.test.ts b/packages/next-international/__tests__/get-locale-props.test.ts index 01f73bb..245b49b 100644 --- a/packages/next-international/__tests__/get-locale-props.test.ts +++ b/packages/next-international/__tests__/get-locale-props.test.ts @@ -48,7 +48,7 @@ describe('getLocaleProps', () => { fr: () => import('./utils/fr'), }); - const props = await getLocaleProps(() => ({ + const props = await getLocaleProps(undefined,() => ({ props: { hello: 'world', }, @@ -66,3 +66,55 @@ describe('getLocaleProps', () => { }); }); }); + + +it('should return scoped locale with when scope defined in params getStaticProps', async () => { + const { getLocaleProps } = createI18n({ + en: () => import('./utils/en'), + fr: () => import('./utils/fr'), + }); + + const props = await getLocaleProps(['namespace'])({ + locale: 'en', + defaultLocale: 'en', + locales: ['en', 'fr'], + }) + + expect(props).toEqual({ + props: { + locale:{ + 'namespace.hello': 'Hello', + 'namespace.subnamespace.hello': 'Hello', + 'namespace.subnamespace.hello.world': 'Hello World!', + 'namespace.subnamespace.weather': "Today's weather is {weather}", + 'namespace.subnamespace.user.description': '{name} is {years} years old', + } + }, + }); + + it('should return scoped locale with when scope defined in params getStaticProps', async () => { + const { getLocaleProps } = createI18n({ + en: () => import('./utils/en'), + fr: () => import('./utils/fr'), + }); + + const props = await getLocaleProps(['namespace.subnamespace'])({ + locale: 'en', + defaultLocale: 'en', + locales: ['en', 'fr'], + }) + + expect(props).toEqual({ + props: { + locale:{ + + 'namespace.subnamespace.hello': 'Hello', + 'namespace.subnamespace.hello.world': 'Hello World!', + 'namespace.subnamespace.weather': "Today's weather is {weather}", + 'namespace.subnamespace.user.description': '{name} is {years} years old', + locale: en, + } + }, + }); + }) +}) \ No newline at end of file diff --git a/packages/next-international/src/common/filter-locales-by-namespace.ts b/packages/next-international/src/common/filter-locales-by-namespace.ts new file mode 100644 index 0000000..1f92b79 --- /dev/null +++ b/packages/next-international/src/common/filter-locales-by-namespace.ts @@ -0,0 +1,18 @@ +import type { BaseLocale, Scopes } from 'international-types'; + +export const filterLocalesByNameSpace = >(locale: Locale, scopes?: Scope[]): Locale =>{ + if(!scopes?.length) return locale + + return Object.entries(locale).reduce( + (prev, [name, value]) => { + if(scopes.some(scope => name.startsWith(scope))){ + const k = name as keyof Locale + prev[k] = value as Locale[string] + } + + return prev + }, + {} as Locale, + ); +} + diff --git a/packages/next-international/src/pages/create-get-locale-props.ts b/packages/next-international/src/pages/create-get-locale-props.ts index bc87462..d223167 100644 --- a/packages/next-international/src/pages/create-get-locale-props.ts +++ b/packages/next-international/src/pages/create-get-locale-props.ts @@ -1,13 +1,15 @@ -import type { ImportedLocales } from 'international-types'; +import type { BaseLocale, ImportedLocales, Scopes } from 'international-types'; import type { GetStaticProps, GetServerSideProps } from 'next'; import { error } from '../helpers/log'; import { flattenLocale } from '../common/flatten-locale'; +import { filterLocalesByNameSpace } from '../common/filter-locales-by-namespace'; export function createGetLocaleProps(locales: ImportedLocales) { return function getLocaleProps< T extends { [key: string]: any }, GetProps extends GetStaticProps | GetServerSideProps, - >(initialGetProps?: GetProps) { + Scope extends Scopes + >(scopes?:Scope[], initialGetProps?: GetProps) { return async (context: any) => { const initialResult = await initialGetProps?.(context); @@ -18,13 +20,14 @@ export function createGetLocaleProps(locales: ImportedLocales) { } const load = locales[context.locale]; - + const allLocale = flattenLocale((await load()).default) + const scopedLocale = filterLocalesByNameSpace(allLocale,scopes) return { ...initialResult, props: { // @ts-expect-error Next `GetStaticPropsResult` doesn't have `props` ...initialResult?.props, - locale: flattenLocale((await load()).default), + locale: scopedLocale, }, }; }; From 70350b3b76475b33f0cf9945659bbc5fec8e11ab Mon Sep 17 00:00:00 2001 From: Salman ORAK <41747037+salmanorak@users.noreply.github.com> Date: Thu, 28 Dec 2023 13:32:34 +0000 Subject: [PATCH 2/2] Fixed type and prettier errors --- examples/next-pages/pages/ssr-ssg-scoped.tsx | 3 +-- .../__tests__/get-locale-props.test.ts | 24 ++++++++--------- .../src/common/filter-locales-by-namespace.ts | 27 +++++++++---------- .../src/pages/create-get-locale-props.ts | 8 +++--- 4 files changed, 29 insertions(+), 33 deletions(-) diff --git a/examples/next-pages/pages/ssr-ssg-scoped.tsx b/examples/next-pages/pages/ssr-ssg-scoped.tsx index 2acbd73..41af0bb 100644 --- a/examples/next-pages/pages/ssr-ssg-scoped.tsx +++ b/examples/next-pages/pages/ssr-ssg-scoped.tsx @@ -1,6 +1,5 @@ import type { GetServerSideProps } from 'next'; -import { getLocaleProps, useChangeLocale, useCurrentLocale, useI18n, useScopedI18n } from '../locales'; - +import { getLocaleProps, useCurrentLocale, useI18n } from '../locales'; export const getServerSideProps: GetServerSideProps = getLocaleProps(['scope2']); // export const getStaticProps: GetStaticProps = getLocaleProps(); diff --git a/packages/next-international/__tests__/get-locale-props.test.ts b/packages/next-international/__tests__/get-locale-props.test.ts index 245b49b..bc17e6f 100644 --- a/packages/next-international/__tests__/get-locale-props.test.ts +++ b/packages/next-international/__tests__/get-locale-props.test.ts @@ -48,7 +48,7 @@ describe('getLocaleProps', () => { fr: () => import('./utils/fr'), }); - const props = await getLocaleProps(undefined,() => ({ + const props = await getLocaleProps(undefined, () => ({ props: { hello: 'world', }, @@ -67,7 +67,6 @@ describe('getLocaleProps', () => { }); }); - it('should return scoped locale with when scope defined in params getStaticProps', async () => { const { getLocaleProps } = createI18n({ en: () => import('./utils/en'), @@ -78,17 +77,17 @@ it('should return scoped locale with when scope defined in params getStaticProps locale: 'en', defaultLocale: 'en', locales: ['en', 'fr'], - }) + }); expect(props).toEqual({ props: { - locale:{ + locale: { 'namespace.hello': 'Hello', 'namespace.subnamespace.hello': 'Hello', 'namespace.subnamespace.hello.world': 'Hello World!', 'namespace.subnamespace.weather': "Today's weather is {weather}", 'namespace.subnamespace.user.description': '{name} is {years} years old', - } + }, }, }); @@ -97,24 +96,23 @@ it('should return scoped locale with when scope defined in params getStaticProps en: () => import('./utils/en'), fr: () => import('./utils/fr'), }); - + const props = await getLocaleProps(['namespace.subnamespace'])({ locale: 'en', defaultLocale: 'en', locales: ['en', 'fr'], - }) - + }); + expect(props).toEqual({ props: { - locale:{ - + locale: { 'namespace.subnamespace.hello': 'Hello', 'namespace.subnamespace.hello.world': 'Hello World!', 'namespace.subnamespace.weather': "Today's weather is {weather}", 'namespace.subnamespace.user.description': '{name} is {years} years old', locale: en, - } + }, }, }); - }) -}) \ No newline at end of file + }); +}); diff --git a/packages/next-international/src/common/filter-locales-by-namespace.ts b/packages/next-international/src/common/filter-locales-by-namespace.ts index 1f92b79..a391159 100644 --- a/packages/next-international/src/common/filter-locales-by-namespace.ts +++ b/packages/next-international/src/common/filter-locales-by-namespace.ts @@ -1,18 +1,17 @@ import type { BaseLocale, Scopes } from 'international-types'; -export const filterLocalesByNameSpace = >(locale: Locale, scopes?: Scope[]): Locale =>{ - if(!scopes?.length) return locale +export const filterLocalesByNameSpace = >( + locale: Locale, + scopes?: Scope[], +): Locale => { + if (!scopes?.length) return locale; - return Object.entries(locale).reduce( - (prev, [name, value]) => { - if(scopes.some(scope => name.startsWith(scope))){ - const k = name as keyof Locale - prev[k] = value as Locale[string] - } - - return prev - }, - {} as Locale, - ); -} + return Object.entries(locale).reduce((prev, [name, value]) => { + if (scopes.some(scope => name.startsWith(scope))) { + const k = name as keyof Locale; + prev[k] = value as Locale[string]; + } + return prev; + }, {} as Locale); +}; diff --git a/packages/next-international/src/pages/create-get-locale-props.ts b/packages/next-international/src/pages/create-get-locale-props.ts index d223167..e0e88c8 100644 --- a/packages/next-international/src/pages/create-get-locale-props.ts +++ b/packages/next-international/src/pages/create-get-locale-props.ts @@ -8,8 +8,8 @@ export function createGetLocaleProps(locales: ImportedLocales) { return function getLocaleProps< T extends { [key: string]: any }, GetProps extends GetStaticProps | GetServerSideProps, - Scope extends Scopes - >(scopes?:Scope[], initialGetProps?: GetProps) { + Scope extends Scopes, + >(scopes?: Scope[], initialGetProps?: GetProps) { return async (context: any) => { const initialResult = await initialGetProps?.(context); @@ -20,8 +20,8 @@ export function createGetLocaleProps(locales: ImportedLocales) { } const load = locales[context.locale]; - const allLocale = flattenLocale((await load()).default) - const scopedLocale = filterLocalesByNameSpace(allLocale,scopes) + const allLocale = flattenLocale((await load()).default); + const scopedLocale = filterLocalesByNameSpace(allLocale, scopes); return { ...initialResult, props: {