Skip to content

Commit

Permalink
[NextJs] i18n updates (#493)
Browse files Browse the repository at this point in the history
* Source Next.js i18n defaultLocale from package config

* Fallback to using package config language for page props (allows sample to run when Next.js i18n is disabled)

* Add locale variants of configured rewrites

* Upgraded next-localization (w/ rosetta) library as dictionary solution of choice (atm). Simplified usage examples. Updated comments in _app.tsx.

* Remove export scripts and build logic for now (since it doesn't work with next.js v10 i18n and image optimization), to be addressed in separate task
  • Loading branch information
ambrauer authored Nov 17, 2020
1 parent df8bf35 commit f1b4417
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 51 deletions.
45 changes: 35 additions & 10 deletions samples/nextjs/next.config.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
const jssConfig = require('./src/temp/config');
const packageConfig = require('./package.json').config;

const disconnectedServerUrl = `http://localhost:${process.env.DISCONNECTED_SERVER_PORT || 3042}/`;
const disconnected = process.env.JSS_MODE === 'disconnected';

module.exports = (phase) => {

const env = {
// Expose current Next.js phase as an environment variable
// See available phases here: https://github.com/vercel/next.js/blob/canary/packages/next/next-server/lib/constants.ts#L1-L4
NEXT_PHASE: phase
}
NEXT_PHASE: phase,
};

const i18n = {
// These are all the locales you want to support in your application.
// These should generally match (or at least be a subset of) those in Sitecore.
locales: ['en', 'da-DK'],
defaultLocale: 'en'
}
// This is the locale that will be used when visiting a non-locale
// prefixed path e.g. `/styleguide`.
defaultLocale: packageConfig.language,
};

async function rewrites() {
if (disconnected) {
Expand All @@ -24,36 +29,56 @@ module.exports = (phase) => {
source: '/sitecore/:path*',
destination: `${disconnectedServerUrl}/sitecore/:path*`,
},
{
source: '/:locale/sitecore/:path*',
destination: `${disconnectedServerUrl}/sitecore/:path*`,
},
// media items
{
source: '/data/media/:path*',
destination: `${disconnectedServerUrl}/data/media/:path*`,
},
]
{
source: '/:locale/data/media/:path*',
destination: `${disconnectedServerUrl}/data/media/:path*`,
},
];
} else {
// When in connected mode we want to proxy Sitecore paths off to Sitecore
return [
{
source: '/sitecore/:path*',
destination: `${jssConfig.sitecoreApiHost}/sitecore/:path*`,
},
{
source: '/:locale/sitecore/:path*',
destination: `${jssConfig.sitecoreApiHost}/sitecore/:path*`,
},
// media items
{
source: '/-/:path*',
destination: `${jssConfig.sitecoreApiHost}/-/:path*`,
},
{
source: '/:locale/-/:path*',
destination: `${jssConfig.sitecoreApiHost}/-/:path*`,
},
// visitor identification
{
source: '/layouts/:path*',
destination: `${jssConfig.sitecoreApiHost}/layouts/:path*`,
},
]
{
source: '/:locale/layouts/:path*',
destination: `${jssConfig.sitecoreApiHost}/layouts/:path*`,
},
];
}
}
};

return {
env,
i18n,
rewrites
rewrites,
};
};
};
6 changes: 3 additions & 3 deletions samples/nextjs/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions samples/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"graphql": "~14.5.7",
"graphql-tag": "~2.10.1",
"next": "^10.0.0",
"next-localization": "^0.9.3",
"next-localization": "^0.10.0",
"nprogress": "~0.2.0",
"react": "^16.9.0",
"react-apollo": "~3.1.1",
Expand Down Expand Up @@ -86,11 +86,9 @@
"lint": "eslint --fix ./src/**/*.tsx ./src/**/*.ts ./sitecore/definitions/**/*.ts ./scripts/**/*.ts ./data/**/*.yml",
"bootstrap": "ts-node --project tsconfig.scripts.json scripts/bootstrap.ts",
"build": "npm-run-all --serial bootstrap next:build",
"export": "cross-env-shell BUILD_MODE=export \"npm-run-all --serial bootstrap next:build next:export\"",
"graphql:update": "ts-node --project tsconfig.scripts.json ./scripts/update-graphql-fragment-data.ts",
"next:build": "next build",
"next:dev": "cross-env NODE_OPTIONS='--inspect' next dev",
"next:export": "next export",
"next:start": "next start",
"scaffold": "ts-node --project tsconfig.scripts.json scripts/scaffold-component.ts",
"start": "npm-run-all --serial bootstrap --parallel next:dev start:watch-components",
Expand Down
8 changes: 4 additions & 4 deletions samples/nextjs/src/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const LOGO_SIZE = { WIDTH: 221, HEIGHT: 48 };
// This is boilerplate navigation for sample purposes. Most apps should throw this away and use their own navigation implementation.
// Most apps may also wish to use GraphQL for their navigation construction; this sample does not simply to support disconnected mode.
const Navigation = () => {
const i18n = useI18n();
const { t } = useI18n();

return (
<div className="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom">
Expand All @@ -38,13 +38,13 @@ const Navigation = () => {
target="_blank"
rel="noopener noreferrer"
>
{i18n.t('Documentation')}
{t('Documentation')}
</a>
<Link href="/styleguide">
<a className="p-2 text-dark">{i18n.t('Styleguide')}</a>
<a className="p-2 text-dark">{t('Styleguide')}</a>
</Link>
<Link href="/graphql">
<a className="p-2 text-dark">{i18n.t('GraphQL')}</a>
<a className="p-2 text-dark">{t('GraphQL')}</a>
</Link>
</nav>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type StyleguideMultilingualProps = StyleguideComponentWithContextProps &
* multiple languages.
*/
const StyleguideMultilingual = (props: StyleguideMultilingualProps): JSX.Element => {
const i18n = useI18n();
const { t, locale } = useI18n();

return (
<StyleguideSpecimen {...props} e2eId="styleguide-multilingual">
Expand All @@ -25,7 +25,7 @@ const StyleguideMultilingual = (props: StyleguideMultilingualProps): JSX.Element
<p>
This is a static dictionary entry from <code>/data/dictionary</code>
:&nbsp;
{i18n.t('styleguide-sample')}
{t('styleguide-sample')}
</p>

<p>
Expand All @@ -38,7 +38,7 @@ const StyleguideMultilingual = (props: StyleguideMultilingualProps): JSX.Element
</Link>
</p>

<p>The current language is: {i18n.locale()}</p>
<p>The current language is: {locale()}</p>
</StyleguideSpecimen>
);
};
Expand Down
39 changes: 14 additions & 25 deletions samples/nextjs/src/pages/[[...path]].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { SitecorePageProps, extractPath } from 'lib/page-props';
import componentFactory from 'temp/componentFactory';
import { configBasedLayoutService as layoutService } from 'lib/layout-service';
import { configBasedDictionaryService as dictionaryService } from 'lib/dictionary-service';
import { config as packageConfig } from '../../package.json';

const SitecorePage = ({ layoutData }: SitecorePageProps): JSX.Element => {
if (!layoutData?.sitecore?.route) {
Expand All @@ -32,30 +33,17 @@ const SitecorePage = ({ layoutData }: SitecorePageProps): JSX.Element => {
// This function gets called at build and export time to determine
// pages for SSG ("paths", as tokenized array).
export const getStaticPaths: GetStaticPaths = async () => {
if (process.env.BUILD_MODE === 'export') {
// If performing an export, fallback is not allowed.
// Use hard-coded values for now for demo-purposes.
// Ultimately, this is where we'll request a "sitemap" from Sitecore.
return {
paths: [
{ params: { path: [''] }, locale: 'en' },
{ params: { path: ['styleguide'] }, locale: 'en' },
{ params: { path: ['styleguide', 'custom-route-type'] }, locale: 'en' },
{ params: { path: ['graphql'] }, locale: 'en' },
],
fallback: false,
};
} else {
// Fallback, along with revalidate in getStaticProps (below),
// enables Incremental Static Regeneration. This allows us to
// leave certain (or all) paths empty if desired and static pages
// will be generated on request.
// See https://nextjs.org/docs/basic-features/data-fetching#incremental-static-regeneration
return {
paths: [],
fallback: 'blocking',
};
}
// Fallback, along with revalidate in getStaticProps (below),
// enables Incremental Static Regeneration. This allows us to
// leave certain (or all) paths empty if desired and static pages
// will be generated on request.
// See https://nextjs.org/docs/basic-features/data-fetching#incremental-static-regeneration
//
// Ultimately, this is where we'll also be able to request a "sitemap" from Sitecore.
return {
paths: [],
fallback: 'blocking',
};
};

// This function gets called at build time on server-side.
Expand All @@ -65,7 +53,8 @@ export const getStaticProps: GetStaticProps = async ({ params, locale }) => {
const path = extractPath(params);

const props: SitecorePageProps = {
locale: locale ?? 'en',
// Use context locale if Next.js i18n is configured, otherwise use language defined in package.json
locale: locale ?? packageConfig.language,
layoutData: null,
dictionary: null,
};
Expand Down
5 changes: 3 additions & 2 deletions samples/nextjs/src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ function App({ Component, pageProps }: AppProps): JSX.Element {
const { dictionary, ...rest } = pageProps;

return (
// Will be doing further evaluation on best i18n library to use for dictionary translation with Next.js.
// 'i18next' and 'react-i18next' seem heavy-handed, 'next-localization' (used here) is promising ...
// Use the next-localization (w/ rosetta) library to provide our translation dictionary to the app.
// Note Next.js does not (currently) provide anything for translation, only i18n routing.
// If your app is not multilingual, next-localization and references to it can be removed.
<I18nProvider lngDict={dictionary} locale={pageProps.locale}>
<Component {...rest} />
</I18nProvider>
Expand Down
4 changes: 3 additions & 1 deletion samples/nextjs/src/pages_examples/[[...path]].SSR.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { SitecorePageProps, extractPath } from 'lib/page-props';
import componentFactory from 'temp/componentFactory';
import { configBasedLayoutService as layoutService } from 'lib/layout-service';
import { configBasedDictionaryService as dictionaryService } from 'lib/dictionary-service';
import { config as packageConfig } from '../../package.json';

const SitecorePage = ({ layoutData }: SitecorePageProps): JSX.Element => {
if (!layoutData?.sitecore?.route) {
Expand Down Expand Up @@ -34,7 +35,8 @@ export const getServerSideProps: GetServerSideProps = async ({ params, locale, r
const path = extractPath(params);

const props: SitecorePageProps = {
locale: locale ?? 'en',
// Use context locale if Next.js i18n is configured, otherwise use language defined in package.json
locale: locale ?? packageConfig.language,
layoutData: null,
dictionary: null,
};
Expand Down

0 comments on commit f1b4417

Please sign in to comment.