diff --git a/__tests__/getFallbackPageNamespaces.test.js b/__tests__/getFallbackPageNamespaces.test.js new file mode 100644 index 00000000..07dc782e --- /dev/null +++ b/__tests__/getFallbackPageNamespaces.test.js @@ -0,0 +1,100 @@ +import getFallbackPageNamespaces from '../src/getFallbackPageNamespaces' + +describe('getFallbackPageNamespaces', () => { + let ctx + beforeAll(() => { + ctx = { query: {} } + }) + + describe('empty', () => { + test('should not return any namespace with empty pages', () => { + const input = [{ pages: {} }, '/test-page', ctx] + const output = getFallbackPageNamespaces(...input) + + expect(output.length).toBe(0) + }) + test('should not return any namespace with pages as undefined', () => { + const input = [{}, '/test-page', ctx] + const output = getFallbackPageNamespaces(...input) + + expect(output.length).toBe(0) + }) + }) + + describe('regular expressions', () => { + test('should return namespaces that match the rgx', () => { + const config = { + pages: { + '*': ['common'], + '/example/form': ['valid'], + '/example/form/other': ['invalid'], + 'rgx:/form$': ['form'], + 'rgx:/invalid$': ['invalid'], + 'rgx:^/example': ['example'], + }, + } + const input = [config, '/example/form'] + const output = getFallbackPageNamespaces(...input) + + expect(output.length).toBe(4) + expect(output[0]).toBe('common') + expect(output[1]).toBe('valid') + expect(output[2]).toBe('form') + expect(output[3]).toBe('example') + }) + }) + + describe('as array', () => { + test('should return the page namespace', () => { + const input = [ + { pages: { '/test-page': ['test-ns'] } }, + '/test-page', + ctx, + ] + const output = getFallbackPageNamespaces(...input) + const expected = ['test-ns'] + + expect(output.length).toBe(1) + expect(output[0]).toBe(expected[0]) + }) + + test('should return the page namespace + common', () => { + const input = [ + { + pages: { + '*': ['common'], + '/test-page': ['test-ns'], + }, + }, + '/test-page', + ctx, + ] + const output = getFallbackPageNamespaces(...input) + const expected = ['common', 'test-ns'] + + expect(output.length).toBe(2) + expect(output[0]).toBe(expected[0]) + expect(output[1]).toBe(expected[1]) + }) + }) + + describe('as function', () => { + test('should work as a fn', () => { + ctx.query.example = '1' + const input = [ + { + pages: { + '/test-page': ({ query }) => (query.example ? ['test-ns'] : []), + }, + }, + '/test-page', + ctx, + ] + const output = getFallbackPageNamespaces(...input) + const expected = ['test-ns'] + + expect(output.length).toBe(1) + expect(output[0]).toBe(expected[0]) + }) + }) +}) diff --git a/examples/complex/i18n.js b/examples/complex/i18n.js index 097d3baf..34da3b34 100644 --- a/examples/complex/i18n.js +++ b/examples/complex/i18n.js @@ -1,3 +1,5 @@ +const fs = require('fs') + module.exports = { locales: ['en', 'ca', 'es'], defaultLocale: 'en', @@ -14,4 +16,10 @@ module.exports = { }, loadLocaleFrom: (locale, namespace) => import(`./src/translations/${namespace}_${locale}`).then((m) => m.default), + + loadLocaleFromSync: (locale, namespace) => { + return JSON.parse( + fs.readFileSync(`./src/translations/${namespace}_${locale}.json`) + ) + }, } diff --git a/examples/complex/src/pages/more-examples/fallback/[slug].tsx b/examples/complex/src/pages/more-examples/fallback/[slug].tsx new file mode 100644 index 00000000..3f654783 --- /dev/null +++ b/examples/complex/src/pages/more-examples/fallback/[slug].tsx @@ -0,0 +1,43 @@ +import { GetStaticProps } from 'next' +import getT from 'next-translate/getT' +import useTranslation from 'next-translate/useTranslation' +import withFallbackTranslation from 'next-translate/withFallbackTranslation' +import Link from 'next/link' +import { useRouter } from 'next/router' + +function DynamicRoute({ title = '' }) { + const { query } = useRouter() + const { t, lang } = useTranslation() + + console.log({ query }) + + return ( + <> +

{title}

+

{t`more-examples:dynamic-route`}

+

+ {query.slug} - {lang} +

+ + {t`more-examples:go-to-home`} + + + ) +} + +export function getStaticPaths({ locales }: any) { + return { + paths: locales.map((locale: string) => ({ + locale, + params: { slug: 'example' }, + })), + fallback: true, + } +} + +export const getStaticProps: GetStaticProps = async ({ locale }) => { + const t = await getT(locale, 'common') + return { props: { title: t('title') }, revalidate: 5 } +} + +export default withFallbackTranslation(DynamicRoute) diff --git a/package.json b/package.json index a1627ea4..448115b2 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "scripts": { "build": "yarn clean && cross-env NODE_ENV=production && yarn tsc", "clean": "yarn clean:build && yarn clean:examples", - "clean:build": "rm -rf lib plugin appWith* Dynamic* I18n* index _context loadNa* setLang* Trans useT* withT* getP* getC* *.d.ts getT transC* wrapT* types", + "clean:build": "rm -rf lib plugin appWith* Dynamic* I18n* index _context loadNa* loadFa* setLang* Trans useT* withT* getFa* getP* getC* *.d.ts getT transC* wrapT* withFall* types", "clean:examples": "rm -rf examples/**/.next && rm -rf examples/**/node_modules && rm -rf examples/**/yarn.lock", "example": "yarn example:complex", "example:basic": "yarn build && cd examples/basic && yarn && yarn dev", diff --git a/src/appWithI18n.tsx b/src/appWithI18n.tsx index a06b91f3..76a8d882 100644 --- a/src/appWithI18n.tsx +++ b/src/appWithI18n.tsx @@ -36,13 +36,58 @@ export default function appWithI18n( function AppWithTranslations(props: Props) { const { defaultLocale } = config + var ns = {} + var pageProps + + if (typeof window === 'undefined') { + if ( + props.router && + props.router.isFallback && + props.Component && + typeof props.Component.__PAGE_NEXT_NAMESPACES === 'function' + ) { + ns = + props.Component.__PAGE_NEXT_NAMESPACES({ + locale: props.router.locale, + pathname: props.router.pathname, + }) || {} + + pageProps = { ...ns, ...props.pageProps } + } + } else { + if ( + props.Component && + typeof props.Component.__PAGE_NEXT_NAMESPACES === 'function' + ) { + ns = props.Component.__PAGE_NEXT_NAMESPACES() || {} + + pageProps = { ...ns, ...props.pageProps } + } + } + + if (pageProps == null) { + pageProps = props.pageProps + } + + var newProps: any = { + ...props, + pageProps, + } + return ( - + +