Skip to content

Commit 18dac56

Browse files
authored
Get i18n working (#36)
* Attempt to get i18n working * Add patch * Remove app-level package-lock * Fix Next patches * Works, hydration error on client though * Remove debugger statement * Fix home link * Build fix * Kinda works for static pages only * Make static page translations work * Cleanups
1 parent 8423bbd commit 18dac56

File tree

20 files changed

+1230
-697
lines changed

20 files changed

+1230
-697
lines changed

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"files.exclude": {
33
"cdk.out": true
44
},
5-
"editor.formatOnSave": false,
5+
"editor.formatOnSave": true,
66
"editor.insertSpaces": true,
77
"editor.tabSize": 2,
88
"files.associations": {

package-lock.json

Lines changed: 482 additions & 217 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/app/components/date.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { parseISO, format } from 'date-fns';
33

4-
export default function Date({ dateString }) {
4+
export default function Date({ dateString }: { dateString: string }) {
55
const date = parseISO(dateString);
66
return <time dateTime={dateString}>{format(date, 'LLLL d, yyyy')}</time>;
77
}

packages/app/components/layout.tsx

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
import Head from 'next/head';
22
import Image from 'next/image';
3-
import styles from './layout.module.css';
4-
import utilStyles from '../styles/utils.module.css';
53
import Link from 'next/link';
64
import getConfig from 'next/config';
75
import React from 'react';
6+
import { useTranslation } from 'next-i18next';
7+
import styles from './layout.module.css';
8+
import utilStyles from '../styles/utils.module.css';
89

9-
const name = 'PwrDrvr';
1010
export const siteTitle = 'PwrDrvr - Next.js Demo';
1111

12-
export default function Layout({
13-
children,
14-
home = undefined,
15-
}: {
12+
const name = 'PwrDrvr';
13+
export default function Layout(context: {
1614
children: React.ReactNode;
1715
home?: boolean;
16+
locale: string;
1817
}): JSX.Element {
18+
const { children, home = undefined } = context;
1919
const base = getConfig().publicRuntimeConfig.staticFolder;
20+
const { t } = useTranslation('common');
2021

2122
return (
2223
<div className={styles.container}>
@@ -54,13 +55,13 @@ export default function Layout({
5455
src={`${base}/images/profile.jpg`}
5556
unoptimized
5657
className={utilStyles.borderCircle}
57-
height={108}
58-
width={108}
58+
height={144}
59+
width={144}
5960
alt={name}
6061
/>
6162
</Link>
6263
<h2 className={utilStyles.headingLg}>
63-
<Link href="/nextjs-demo" className={utilStyles.colorInherit}>
64+
<Link href={`/${context.locale}/nextjs-demo`} className={utilStyles.colorInherit}>
6465
{name}
6566
</Link>
6667
</h2>
@@ -70,7 +71,7 @@ export default function Layout({
7071
<main>{children}</main>
7172
{!home && (
7273
<div className={styles.backToHome}>
73-
<Link href="/nextjs-demo">← Back to home</Link>
74+
<Link href={`/nextjs-demo`}>{`← ${t('back-to-home')}`}</Link>
7475
</div>
7576
)}
7677
</div>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type { Namespace } from 'i18next';
2+
import type { SSRConfig, UserConfig } from 'next-i18next';
3+
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
4+
import nextI18nextConfig from '../next-i18next.config';
5+
6+
//
7+
// Trick to fix server-side bundling 'can't find module packages/app/next-i18next.config.js'
8+
// From: https://github.com/i18next/next-i18next/blob/master/TROUBLESHOOT.md#how-to-explicitly-pass-the-config
9+
//
10+
11+
type ArrayElementOrSelf<T> = T extends Array<infer U> ? U[] : T[];
12+
13+
export const getServerTranslations = async (
14+
locale: string,
15+
namespacesRequired?: ArrayElementOrSelf<Namespace> | undefined,
16+
configOverride?: UserConfig,
17+
extraLocales?: string[] | false,
18+
): Promise<SSRConfig> => {
19+
const config = configOverride ?? nextI18nextConfig;
20+
return serverSideTranslations(locale || 'en', namespacesRequired, config, extraLocales);
21+
};
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const path = require('path');
2+
3+
const backend = require('i18next-http-backend/cjs');
4+
5+
/**
6+
* @type {import('next-i18next/dist/types/types').UserConfig}
7+
*/
8+
const config = {
9+
debug: process.env.NODE_ENV === 'development',
10+
i18n: {
11+
defaultLocale: 'en',
12+
locales: ['en', 'sv'],
13+
},
14+
ns: ['common'],
15+
/** To avoid issues when deploying to some paas (vercel...) */
16+
localePath:
17+
typeof window === 'undefined' ? require('path').resolve('./public/locales') : '/locales',
18+
19+
reloadOnPrerender: process.env.NODE_ENV === 'development',
20+
react: { useSuspense: false }, //this line
21+
};
22+
23+
module.exports = config;

packages/app/next.config.js

Lines changed: 45 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
// eslint-disable-next-line @typescript-eslint/no-var-requires
2-
// const path = require('path');
3-
// next-compose-plugins
4-
// const withPlugins = require('next-compose-plugins');
5-
// next-images
6-
// const withImages = require('next-images')
2+
const i18NextConfig = require('./next-i18next.config');
3+
const { i18n } = i18NextConfig;
4+
75
const isProd = process.env.NODE_ENV === 'production';
86

97
const BASE_PREFIX_APP = '/nextjs-demo';
@@ -16,12 +14,14 @@ const BASE_PREFIX_APP_WITH_VERSION = `${BASE_PREFIX_APP}${BASE_VERSION_ONLY}`;
1614
* @type {import('next').NextConfig}
1715
*/
1816
module.exports = {
19-
output: 'standalone',
17+
...(isProd ? { output: 'standalone' } : {}),
2018
outputFileTracing: isProd,
2119
experimental: {
2220
bundleServerPackages: isProd,
2321
},
2422

23+
i18n,
24+
2525
// We want the static assets, api calls, and _next/data calls
2626
// to have /nextjs-demo/0.0.0/ as the prefix so they route cleanly
2727
// to an isolated folder on the S3 bucket and to a specific
@@ -61,41 +61,49 @@ module.exports = {
6161
// in the path, which is perfect because that's where the assets
6262
// will be on the S3 bucket.
6363
async rewrites() {
64-
return [
65-
{
66-
/** Static Assets and getServerSideProps (_next/data/) */
67-
source: `${BASE_PREFIX_APP_WITH_VERSION}/_next/:path*`,
68-
destination: `/_next/:path*`,
69-
},
70-
{
71-
/** Image optimizer (not tested yet) */
72-
source: `${BASE_VERSION_ONLY}/_next/image/:query*`,
73-
destination: `/_next/image/:query*`,
74-
},
75-
{
76-
// Images
77-
// Only used for local development
78-
// On deployed environments, the images are served from S3
79-
// and image requests will never reach this rewrite
80-
source: `${BASE_PREFIX_APP_WITH_VERSION}/images/:query*`,
81-
destination: `/images/:query*`,
82-
},
83-
{
84-
// Favicon
85-
// Only used for local development
86-
source: `${BASE_PREFIX_APP_WITH_VERSION}/favicon.ico`,
87-
destination: `/favicon.ico`,
88-
},
89-
/** Api Calls */
90-
{
91-
source: `${BASE_VERSION_ONLY}/api/:path*`,
92-
destination: `/api/:path*`,
93-
},
94-
];
64+
return {
65+
beforeFiles: [
66+
{
67+
/** Static Assets and getServerSideProps (_next/data/) */
68+
source: `${BASE_PREFIX_APP_WITH_VERSION}/_next/static/:path*`,
69+
destination: `/_next/static/:path*`,
70+
},
71+
{
72+
// Favicon
73+
// Only used for local development
74+
source: `${BASE_PREFIX_APP_WITH_VERSION}/favicon.ico`,
75+
destination: `/favicon.ico`,
76+
},
77+
{
78+
// Images
79+
// Only used for local development
80+
// On deployed environments, the images are served from S3
81+
// and image requests will never reach this rewrite
82+
source: `${BASE_PREFIX_APP_WITH_VERSION}/images/:query*`,
83+
destination: `/images/:query*`,
84+
},
85+
],
86+
afterFiles: [
87+
{
88+
/** Image optimizer (not tested yet) */
89+
source: `${BASE_VERSION_ONLY}/_next/image/:query*`,
90+
destination: `/_next/image/:query*`,
91+
},
92+
/** Api Calls */
93+
{
94+
source: `${BASE_VERSION_ONLY}/api/:path*`,
95+
destination: `/api/:path*`,
96+
},
97+
],
98+
};
9599
},
96100

97101
publicRuntimeConfig: {
98102
// Will be available on both server and client
99103
staticFolder: isProd ? BASE_PREFIX_APP_WITH_VERSION : BASE_PREFIX_APP_WITH_VERSION,
100104
},
105+
106+
typescript: {
107+
tsconfigPath: './tsconfig.json',
108+
},
101109
};

0 commit comments

Comments
 (0)