i18n support is not compatible with next export.
NextJS dont run the deploy with i18n
Im using nextJS 10, and the main reason that i choose next 10, is that i can do SSR and use the i18n.
Internationalized Routing its a new next js 10 feature and have a page only to tha feature.
But when im gonna do a deploy, this error appears: i18n support is not compatible with next export.
Theres nothing about this in internationalized routing page.
My code
next.config.js
const withImages = require('next-images')
const path = require('path')
module.exports = withImages({
esModule: false,
i18n: {
locales: ['en-US', 'pt-BR', 'pt-PT', 'es-ES'],
defaultLocale: 'pt-BR',
},
});
I created a translate archive that make the condition with next router
obs: PT and EN are JSON files with text
import * as pt from "./pt";
import * as en from './en';
import { useRouter } from "next/router"
export const traducao = () =>{
let routes = useRouter();
let translate;
if (routes.locale == 'pt-PT' || routes.locale == 'pt-BR') {
translate = pt.default;
} else {
translate = en.default;
}
return translate
}
And the i just use in my project like a function:
{traducao().homeText.button_text}
Work well, recognizes the browser language and switch.
Im using deploy script
npm run deploy
"deploy": "npm run clean && npm run build && next export -o dist/"
Steps to reproduce
- Go to ‘next.config,js’
- create the i18n export
- create a Translate file that recognizes the browser language
- import JSONs files with your site text
- Use where you want
- Try to deploy
Expected behavior
Its just suppose to work fine and Deploy normal.
Screenshots
System information
- OS: Linux Ubuntu
- IDE: VSCode
- Version of Next.js: 10
- Version of Node.js: v15.3.0
- Deployment: next deploy
i18n support is not compatible with next export.
NextJS dont run the deploy with i18n
Im using nextJS 10, and the main reason that i choose next 10, is that i can do SSR and use the i18n.
Internationalized Routing its a new next js 10 feature and have a page only to tha feature.
But when im gonna do a deploy, this error appears: i18n support is not compatible with next export.
Theres nothing about this in internationalized routing page.
My code
next.config.js
const withImages = require('next-images')
const path = require('path')
module.exports = withImages({
esModule: false,
i18n: {
locales: ['en-US', 'pt-BR', 'pt-PT', 'es-ES'],
defaultLocale: 'pt-BR',
},
});
I created a translate archive that make the condition with next router
obs: PT and EN are JSON files with text
import * as pt from "./pt";
import * as en from './en';
import { useRouter } from "next/router"
export const traducao = () =>{
let routes = useRouter();
let translate;
if (routes.locale == 'pt-PT' || routes.locale == 'pt-BR') {
translate = pt.default;
} else {
translate = en.default;
}
return translate
}
And the i just use in my project like a function:
{traducao().homeText.button_text}
Work well, recognizes the browser language and switch.
Im using deploy script
npm run deploy
"deploy": "npm run clean && npm run build && next export -o dist/"
Steps to reproduce
- Go to ‘next.config,js’
- create the i18n export
- create a Translate file that recognizes the browser language
- import JSONs files with your site text
- Use where you want
- Try to deploy
Expected behavior
Its just suppose to work fine and Deploy normal.
Screenshots
System information
- OS: Linux Ubuntu
- IDE: VSCode
- Version of Next.js: 10
- Version of Node.js: v15.3.0
- Deployment: next deploy
You know Next.js, right? — If not, stop reading this article and make something else.
If you’re using Next.js 13 with app directory, have a look at this blog post.
Next.js is awesome! It gives you the best developer experience with all the features you need…
TOC
- BUT, you may have heard about this
- So what can we do now?
- The recipe
- The outcome
- The voluntary part
- 🎉🥳 Congratulations 🎊🎁
BUT, you may have heard about this:
Error: i18n support is not compatible with next export. See here for more info on deploying: https://nextjs.org/docs/deployment
This happens if you’re using the internationalized routing feature and are trying to generate a static HTML export by executing next export
.
Well, this features requires a Node.js server, or dynamic logic that cannot be computed during the build process, that’s why it is unsupported.
This is the case if you’re using next-i18next for example.
So what can we do now?
An obvious option is, to renounce to the static HTML export and use a Node.js server or Vercel as deployment environment.
But sometimes, due to company or architectural guidelines it is mandatory to use a static web server.
Ok then renounce to i18n? — Not really, if we are here, it seems like to be a requirement.
So then do it without Next.js? — But this usually means to rewrite the whole project.
Executing next export
when not using i18n seems to work.
What if we do not try to use the internationalized routing feature and do the i18n routing on our own?
The recipe
To «cook» this recipe you will need the following ingredients:
- use the dynamic route segments feature
- willingness to change the structure of your project files
- willingness to adapt a bit of code
- a logic to detect the user language and redirect accordingly
Sounds feasible. Let’s start!
1. Remove the i18n options from next.config.js
.
1 |
- const { i18n } = require('./next-i18next.config') |
2. Create a [locale]
folder inside your pages directory.
a) Move all your pages files to that folder (not _app.js
or _document.js
etc..).
b) Adapt your imports, if needed.
3. Create a getStatic.js
file and place it for example in a lib
directory.
1 |
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; |
4. Use getStaticPaths
and makeStaticProps
in your pages, like this:
1 |
import { useTranslation } from 'next-i18next' |
5. Install next-language-detector.
npm i next-language-detector
6. Create a languageDetector.js
file and place it for example in the lib
directory.
1 |
import languageDetector from 'next-language-detector' |
7. Create a redirect.js
file and place it for example in the lib
directory.
1 |
import { useEffect } from 'react' |
8. For each of your pages files in your [locale]
directory, but especially for the index.js
file, create a file with the same name with this content:
1 |
import { Redirect } from '../lib/redirect' |
9. Create a Link.js
component and place it for example in the components
directory.
1 |
import React from 'react' |
10. Replace al next/link
Link
imports with the appropriate ../components/Link
Link
import:
1 |
- import Link from 'next/link' |
11. Add or modify your _document.js
file to set the correct html lang
attribute:
1 |
import Document, { Html, Head, Main, NextScript } from 'next/document' |
12. In case you have a language switcher, create or adapt it:
1 |
|
1 |
|
The outcome
If you now start your project (next dev
) you should see, more or less, the same behaviour as before.
So what’s the benefit?
Try: next build && next export
You should see something like this at the end:
1 |
● (SSG) automatically generated as static HTML + JSON (uses getStaticProps) |
Yeah no i18n support is not compatible with next export
error anymore!!!
Congratulations! Now you can «deploy» the content of your out
directory to any static web server.
🧑💻 The complete code can be found here.
The voluntary part
Connect to an awesome translation management system and manage your translations outside of your code.
Let’s synchronize the translation files with locize.
This can be done on-demand or on the CI-Server or before deploying the app.
What to do to reach this step:
- in locize: signup at https://locize.app/register and login
- in locize: create a new project
- in locize: add all your additional languages (this can also be done via API)
- install the locize-cli (
npm i locize-cli
)
Use the locize-cli
Use the locize sync
command to synchronize your local repository (public/locales
) with what is published on locize.
Alternatively, you can also use the locize download
command to always download the published locize translations to your local repository (public/locales
) before bundling your app.
🎉🥳 Congratulations 🎊🎁
I hope you’ve learned a few new things about static site generation (SSG), Next.js, next-i18next, i18next and modern localization workflows.
So if you want to take your i18n topic to the next level, it’s worth trying the localization management platform — locize.
The founders of locize are also the creators of i18next. So by using locize you directly support the future of i18next.
👍
Looking for an optimized Next.js translations setup?
Here you’ll find a blog post on how to best use next-i18next with client side translation download and SEO optimization.
You know Next.js, right? — If not, stop reading this article and make something else.
Next.js is awesome! It gives you the best developer experience with all the features you need…
TOC
- BUT, you may have heard about this
- So what can we do now?
- The recipe
- The outcome
- The voluntary part
- 🎉🥳 Congratulations 🎊🎁
BUT, you may have heard about this:
Error: i18n support is not compatible with next export. See here for more info on deploying: https://nextjs.org/docs/deployment
This happens if you’re using the internationalized routing feature and are trying to generate a static HTML export by executing next export
.
Well, this features requires a Node.js server, or dynamic logic that cannot be computed during the build process, that’s why it is unsupported.
This is the case if you’re using next-i18next for example.
So what can we do now?
An obvious option is, to renounce to the static HTML export and use a Node.js server or Vercel as deployment environment.
But sometimes, due to company or architectural guidelines it is mandatory to use a static web server.
Ok then renounce to i18n? — Not really, if we are here, it seems like to be a requirement.
So then do it without Next.js? — But this usually means to rewrite the whole project.
Executing next export
when not using i18n seems to work.
What if we do not try to use the internationalized routing feature and do the i18n routing on our own?
The recipe
To «cook» this recipe you will need the following ingredients:
- use the dynamic route segments feature
- willingness to change the structure of your project files
- willingness to adapt a bit of code
- a logic to detect the user language and redirect accordingly
Sounds feasible. Let’s start!
1. Remove the i18n options from next.config.js
.
- const { i18n } = require('./next-i18next.config')
-
module.exports = {
- i18n,
trailingSlash: true,
}
Enter fullscreen mode
Exit fullscreen mode
2. Create a [locale]
folder inside your pages directory.
a) Move all your pages files to that folder (not _app.js
or _document.js
etc..).
b) Adapt your imports, if needed.
3. Create a getStatic.js
file and place it for example in a lib
directory.
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import i18nextConfig from '../next-i18next.config'
export const getI18nPaths = () =>
i18nextConfig.i18n.locales.map((lng) => ({
params: {
locale: lng
}
}))
export const getStaticPaths = () => ({
fallback: false,
paths: getI18nPaths()
})
export async function getI18nProps(ctx, ns = ['common']) {
const locale = ctx?.params?.locale
let props = {
...(await serverSideTranslations(locale, ns))
}
return props
}
export function makeStaticProps(ns = {}) {
return async function getStaticProps(ctx) {
return {
props: await getI18nProps(ctx, ns)
}
}
}
Enter fullscreen mode
Exit fullscreen mode
4. Use getStaticPaths
and makeStaticProps
in your pages, like this:
import { useTranslation } from 'next-i18next'
import { getStaticPaths, makeStaticProps } from '../../lib/getStatic'
import { Header } from '../../components/Header'
import { Footer } from '../../components/Footer'
import Link from '../../components/Link'
+ const getStaticProps = makeStaticProps(['common', 'footer'])
+ export { getStaticPaths, getStaticProps }
const Homepage = () => {
const { t } = useTranslation('common')
return (
<>
<main>
<Header heading={t('h1')} title={t('title')} />
<div>
<Link href='/second-page'><button type='button'>{t('to-second-page')}</button></Link>
</div>
</main>
<Footer />
</>
)
}
export default Homepage
Enter fullscreen mode
Exit fullscreen mode
5. Install next-language-detector.
npm i next-language-detector
6. Create a languageDetector.js
file and place it for example in the lib
directory.
import languageDetector from 'next-language-detector'
import i18nextConfig from '../next-i18next.config'
export default languageDetector({
supportedLngs: i18nextConfig.i18n.locales,
fallbackLng: i18nextConfig.i18n.defaultLocale
})
Enter fullscreen mode
Exit fullscreen mode
7. Create a redirect.js
file and place it for example in the lib
directory.
import { useEffect } from 'react'
import { useRouter } from 'next/router'
import languageDetector from './languageDetector'
export const useRedirect = (to) => {
const router = useRouter()
to = to || router.asPath
// language detection
useEffect(() => {
const detectedLng = languageDetector.detect()
if (to.startsWith('/' + detectedLng) && router.route === '/404') { // prevent endless loop
router.replace('/' + detectedLng + router.route)
return
}
languageDetector.cache(detectedLng)
router.replace('/' + detectedLng + to)
})
return <></>
};
export const Redirect = () => {
useRedirect()
return <></>
}
// eslint-disable-next-line react/display-name
export const getRedirect = (to) => () => {
useRedirect(to)
return <></>
}
Enter fullscreen mode
Exit fullscreen mode
8. For each of your pages files in your [locale]
directory, but especially for the index.js
file, create a file with the same name with this content:
import { Redirect } from '../lib/redirect'
export default Redirect
Enter fullscreen mode
Exit fullscreen mode
9. Create a Link.js
component and place it for example in the components
directory.
import React from 'react'
import Link from 'next/link'
import { useRouter } from 'next/router'
const LinkComponent = ({ children, skipLocaleHandling, ...rest }) => {
const router = useRouter()
const locale = rest.locale || router.query.locale || ''
let href = rest.href || router.asPath
if (href.indexOf('http') === 0) skipLocaleHandling = true
if (locale && !skipLocaleHandling) {
href = href
? `/${locale}${href}`
: router.pathname.replace('[locale]', locale)
}
return (
<>
<Link href={href}>
<a {...rest}>{children}</a>
</Link>
</>
)
}
export default LinkComponent
Enter fullscreen mode
Exit fullscreen mode
10. Replace al next/link
Link
imports with the appropriate ../components/Link
Link
import:
- import Link from 'next/link'
+ import Link from '../../components/Link'
Enter fullscreen mode
Exit fullscreen mode
11. Add or modify your _document.js
file to set the correct html lang
attribute:
import Document, { Html, Head, Main, NextScript } from 'next/document'
import i18nextConfig from '../next-i18next.config'
class MyDocument extends Document {
render() {
const currentLocale = this.props.__NEXT_DATA__.query.locale || i18nextConfig.i18n.defaultLocale
return (
<Html lang={currentLocale}>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
Enter fullscreen mode
Exit fullscreen mode
12. In case you have a language switcher, create or adapt it:
// components/LanguageSwitchLink.js
import languageDetector from '../lib/languageDetector'
import { useRouter } from 'next/router'
import Link from 'next/link'
const LanguageSwitchLink = ({ locale, ...rest }) => {
const router = useRouter()
let href = rest.href || router.asPath
let pName = router.pathname
Object.keys(router.query).forEach((k) => {
if (k === 'locale') {
pName = pName.replace(`[${k}]`, locale)
return
}
pName = pName.replace(`[${k}]`, router.query[k])
})
if (locale) {
href = rest.href ? `/${locale}${rest.href}` : pName
}
return (
<Link
href={href}
onClick={() => languageDetector.cache(locale)}
>
<button style={{ fontSize: 'small' }}>{locale}</button>
</Link>
);
};
export default LanguageSwitchLink
Enter fullscreen mode
Exit fullscreen mode
// components/Footer.js
import { useTranslation } from 'next-i18next'
import { useRouter } from 'next/router'
import LanguageSwitchLink from './LanguageSwitchLink'
import i18nextConfig from '../next-i18next.config'
export const Footer = () => {
const router = useRouter()
const { t } = useTranslation('footer')
const currentLocale = router.query.locale || i18nextConfig.i18n.defaultLocale
return (
<footer>
<p>
<span style={{ lineHeight: '4.65em', fontSize: 'small' }}>{t('change-locale')}</span>
{i18nextConfig.i18n.locales.map((locale) => {
if (locale === currentLocale) return null
return (
<LanguageSwitchLink
locale={locale}
key={locale}
/>
)
})}
</p>
</footer>
)
}
Enter fullscreen mode
Exit fullscreen mode
The outcome
If you now start your project (next dev
) you should see, more or less, the same behaviour as before.
So what’s the benefit?
Try: next build && next export
You should see something like this at the end:
● (SSG) automatically generated as static HTML + JSON (uses getStaticProps)
info - using build directory: /Users/usr/projects/my-awesome-project/.next
info - Copying "static build" directory
info - No "exportPathMap" found in "/Users/usr/projects/my-awesome-project/next.config.js". Generating map from "./pages"
info - Launching 9 workers
info - Copying "public" directory
info - Exporting (3/3)
Export successful. Files written to /Users/usr/projects/my-awesome-project/out
Enter fullscreen mode
Exit fullscreen mode
Yeah no i18n support is not compatible with next export
error anymore!!!
Congratulations! Now you can «deploy» the content of your out
directory to any static web server.
🧑💻 The complete code can be found here.
The voluntary part
Connect to an awesome translation management system and manage your translations outside of your code.
Let’s synchronize the translation files with locize.
This can be done on-demand or on the CI-Server or before deploying the app.
What to do to reach this step:
- in locize: signup at https://locize.app/register and login
- in locize: create a new project
- in locize: add all your additional languages (this can also be done via API)
- install the locize-cli (
npm i locize-cli
)
Use the locize-cli
Use the locize sync
command to synchronize your local repository (public/locales
) with what is published on locize.
Alternatively, you can also use the locize download
command to always download the published locize translations to your local repository (public/locales
) before bundling your app.
🎉🥳 Congratulations 🎊🎁
I hope you’ve learned a few new things about static site generation (SSG), Next.js, next-i18next, i18next and modern localization workflows.
So if you want to take your i18n topic to the next level, it’s worth to try the localization management platform — locize.
The founders of locize are also the creators of i18next. So with using locize you directly support the future of i18next.
👍
Looking for an optimized Next.js translations setup?
Here you’ll find a blog post on how to best use next-i18next with client side translation download and SEO optimization.
December 7, 2021 01:56 pm GMT
You know Next.js, right? — If not, stop reading this article and make something else.
Next.js is awesome! It gives you the best developer experience with all the features you need…
TOC
- BUT, you may have heared about this
- So what can we do now?
- The receipe
- The outcome
- The voluntary part
- Congratulations
BUT, you may have heared about this:
Error: i18n support is not compatible with next export. See here for more info on deploying: https://nextjs.org/docs/deployment
This happens if you’re using the internationalized routing feature and are trying to generate a static HTML export by executing next export
.
Well, this features requires a Node.js server, or dynamic logic that cannot be computed during the build process, that’s why it is unsupported.
This is the case if you’re using next-i18next for example.
So what can we do now?
An obious option is, to renounce to the static HTML export and use a Node.js server or Vercel as deployment environment.
But sometimes, due to company or architectural guidelines it is mandatory to use a static webserver.
Ok then renounce to i18n? — Not really, if we are here, it seems like to be a requirement.
So then do it without Next.js? — But this usually means to rewrite the whole project.
Executing next export
when not using i18n seems to work.
What if we do not try to use the internationalized routing feature and do the i18n routing on our own?
The receipe
To «cook» this recipe you will need the following ingredients:
- use the dynamic route segments feature
- willingness to change the structure of your project files
- willingness to adapt a bit of code
- a logic to detect the user language and redirect accordingly
Sounds feasible. Let’s start!
1. Remove the i18n options from next.config.js
.
- const { i18n } = require('./next-i18next.config') - module.exports = { - i18n, trailingSlash: true, }
2. Create a [locale]
folder inside your pages directory.
a) Move all your pages files to that folder (not _app.js
or _document.js
etc..).
b) Adapt your imports, if needed.
3. Create a getStatic.js
file and place it for example in a lib
directory.
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; import i18nextConfig from '../next-i18next.config' export const getI18nPaths = () => i18nextConfig.i18n.locales.map((lng) => ({ params: { locale: lng } })) export const getStaticPaths = () => ({ fallback: false, paths: getI18nPaths() }) export async function getI18nProps(ctx, ns = ['common']) { const locale = ctx?.params?.locale let props = { ...(await serverSideTranslations(locale, ns)) } return props } export function makeStaticProps(ns = {}) { return async function getStaticProps(ctx) { return { props: await getI18nProps(ctx, ns) } } }
4. Use getStaticPaths
and makeStaticProps
in your pages, like this:
import { useTranslation } from 'next-i18next' import { getStaticPaths, makeStaticProps } from '../../lib/getStatic' import { Header } from '../../components/Header' import { Footer } from '../../components/Footer' import Link from '../../components/Link' + const getStaticProps = makeStaticProps(['common', 'footer']) + export { getStaticPaths, getStaticProps } const Homepage = () => { const { t } = useTranslation('common') return ( <> <main> <Header heading={t('h1')} title={t('title')} /> <div> <Link href='/second-page'><button type='button'>{t('to-second-page')}</button></Link> </div> </main> <Footer /> </> ) } export default Homepage
5. Install next-language-detector.
npm i next-language-detector
6. Create a languageDetector.js
file and place it for example in the lib
directory.
import languageDetector from 'next-language-detector' import i18nextConfig from '../next-i18next.config' export default languageDetector({ supportedLngs: i18nextConfig.i18n.locales, fallbackLng: i18nextConfig.i18n.defaultLocale })
7. Create a redirect.js
file and place it for example in the lib
directory.
import { useEffect } from 'react' import { useRouter } from 'next/router' import languageDetector from './languageDetector' export const useRedirect = (to) => { const router = useRouter() to = to || router.asPath // language detection useEffect(() => { const detectedLng = languageDetector.detect() if (to.startsWith('/' + detectedLng) && router.route === '/404') { // prevent endless loop router.replace('/' + detectedLng + router.route) return } languageDetector.cache(detectedLng) router.replace('/' + detectedLng + to) }) return <></> }; export const Redirect = () => { useRedirect() return <></> } // eslint-disable-next-line react/display-name export const getRedirect = (to) => () => { useRedirect(to) return <></> }
8. For each of your pages files in your [locale]
directory, but especially for the index.js
file, create a file with the same name with this content:
import { Redirect } from '../lib/redirect' export default Redirect
9. Create a Link.js
component and place it for example in the components
directory.
import React from 'react' import Link from 'next/link' import { useRouter } from 'next/router' const LinkComponent = ({ children, skipLocaleHandling, ...rest }) => { const router = useRouter() const locale = rest.locale || router.query.locale || '' let href = rest.href || router.asPath if (href.indexOf('http') === 0) skipLocaleHandling = true if (locale && !skipLocaleHandling) { href = href ? `/${locale}${href}` : router.pathname.replace('[locale]', locale) } return ( <> <Link href={href}> <a {...rest}>{children}</a> </Link> </> ) } export default LinkComponent
10. Replace al next/link
Link
imports with the appropriate ../components/Link
Link
import:
- import Link from 'next/link' + import Link from '../../components/Link'
11. Add or modify your _document.js
file to set the correct html lang
attribute:
import Document, { Html, Head, Main, NextScript } from 'next/document' import i18nextConfig from '../next-i18next.config' class MyDocument extends Document { render() { const currentLocale = this.props.__NEXT_DATA__.query.locale || i18nextConfig.i18n.defaultLocale return ( <Html lang={currentLocale}> <Head /> <body> <Main /> <NextScript /> </body> </Html> ) } } export default MyDocument
12. In case you have a language switcher, create or adapt it:
// components/LanguageSwitchLink.js import languageDetector from '../lib/languageDetector' import { useRouter } from 'next/router' import Link from 'next/link' const LanguageSwitchLink = ({ locale, ...rest }) => { const router = useRouter() let href = rest.href || router.asPath let pName = router.pathname Object.keys(router.query).forEach((k) => { if (k === 'locale') { pName = pName.replace(`[${k}]`, locale) return } pName = pName.replace(`[${k}]`, router.query[k]) }) if (locale) { href = rest.href ? `/${locale}${rest.href}` : pName } return ( <Link href={href} onClick={() => languageDetector.cache(locale)} > <button style={{ fontSize: 'small' }}>{locale}</button> </Link> ); }; export default LanguageSwitchLink
// components/Footer.js import { useTranslation } from 'next-i18next' import { useRouter } from 'next/router' import LanguageSwitchLink from './LanguageSwitchLink' import i18nextConfig from '../next-i18next.config' export const Footer = () => { const router = useRouter() const { t } = useTranslation('footer') const currentLocale = router.query.locale || i18nextConfig.i18n.defaultLocale return ( <footer> <p> <span style={{ lineHeight: '4.65em', fontSize: 'small' }}>{t('change-locale')}</span> {i18nextConfig.i18n.locales.map((locale) => { if (locale === currentLocale) return null return ( <LanguageSwitchLink locale={locale} key={locale} /> ) })} </p> </footer> ) }
The outcome
If you know start your project (next dev
) you should see, more or less, the same behaviour as before.
So what’s the benefit?
Try: next build && next export
You should see something like this at the end:
(SSG) automatically generated as static HTML + JSON (uses getStaticProps)info - using build directory: /Users/usr/projects/my-awesome-project/.nextinfo - Copying "static build" directoryinfo - No "exportPathMap" found in "/Users/usr/projects/my-awesome-project/next.config.js". Generating map from "./pages"info - Launching 9 workersinfo - Copying "public" directoryinfo - Exporting (3/3)Export successful. Files written to /Users/usr/projects/my-awesome-project/out
Yeah no i18n support is not compatible with next export
error anymore!!!
Congratulations! Now you can «deploy» the content of your out
directory to any static werbserver.
The complete code can be found here.
The voluntary part
Connect to an awesome translation management system and manage your translations outside of your code.
Let’s synchronize the translation files with locize.
This can be done on-demand or on the CI-Server or before deploying the app.
What to do to reach this step:
- in locize: signup at https://locize.com/register and login
- in locize: create a new project
- in locize: add all your additional languages (this can also be done via API)
- install the locize-cli (
npm i locize-cli
)
Use the locize-cli
Use the locize sync
command to synchronize your local repository (public/locales
) with what is published on locize.
Alternatively, you can also use the locize download
command to always download the published locize translations to your local repository (public/locales
) before bundling your app.
Congratulations
I hope youve learned a few new things about static site generation (SSG), Next.js, next-i18next, i18next and modern localization workflows.
So if you want to take your i18n topic to the next level, it’s worth to try the localization management platform — locize.
The founders of locize are also the creators of i18next. So with using locize you directly support the future of i18next.
Original Link: https://dev.to/adrai/static-html-export-with-i18n-compatibility-in-nextjs-8cd
Share this article:
View Full Article
i18n support is not compatible with next export.
NextJS dont run the deploy with i18n
Im using nextJS 10, and the main reason that i choose next 10, is that i can do SSR and use the i18n.
Internationalized Routing its a new next js 10 feature and have a page only to tha feature.
But when im gonna do a deploy, this error appears: i18n support is not compatible with next export.
Theres nothing about this in internationalized routing page.
My code
next.config.js
const withImages = require('next-images')
const path = require('path')
module.exports = withImages({
esModule: false,
i18n: {
locales: ['en-US', 'pt-BR', 'pt-PT', 'es-ES'],
defaultLocale: 'pt-BR',
},
});
I created a translate archive that make the condition with next router
obs: PT and EN are JSON files with text
import * as pt from "./pt";
import * as en from './en';
import { useRouter } from "next/router"
export const traducao = () =>{
let routes = useRouter();
let translate;
if (routes.locale == 'pt-PT' || routes.locale == 'pt-BR') {
translate = pt.default;
} else {
translate = en.default;
}
return translate
}
And the i just use in my project like a function:
{traducao().homeText.button_text}
Work well, recognizes the browser language and switch.
Im using deploy script
npm run deploy
"deploy": "npm run clean && npm run build && next export -o dist/"
Steps to reproduce
- Go to ‘next.config,js’
- create the i18n export
- create a Translate file that recognizes the browser language
- import JSONs files with your site text
- Use where you want
- Try to deploy
Expected behavior
Its just suppose to work fine and Deploy normal.
Screenshots
System information
- OS: Linux Ubuntu
- IDE: VSCode
- Version of Next.js: 10
- Version of Node.js: v15.3.0
- Deployment: next deploy
Statically generating a website with the NextJS framework in different languages is not so obvious. The framework does not bring clear support for this use case and the NextJS documentation explains that i18n routing is not supported for SSG.
If you are seeing the message i18n support is not compatible with next export
, this post should be able to help find a workaround.
Bootstrap the project
First of all, let’s create a new next project from the with-react-intl
template
npx create-next-app -e with-react-intl
If don’t need anymore to manage any localization client side, you can remove the getInitialProps
function and the part for localization in the render
function.
The SSR server is useless if you only need SSG as well. So you can remove server tsconfig, server.ts
file and change your package.json
file script part as follow :
"scripts": {
"dev": "next dev",
"build": "npm run extract:i18n && npm run compile:i18n && next build",
"export": "next export",
"extract:i18n": "formatjs extract '{pages,components}/*.{js,ts,tsx}' --format simple --id-interpolation-pattern '[sha512:contenthash:base64:6]' --out-file lang/en.json",
"compile:i18n": "formatjs compile-folder --ast --format simple lang compiled-lang",
"start": "next start"
},
Static Site Generation (aka SSG) with NextJS
When you generate your website statically, it is not possible to use browser request header or any other information from the browser to know which language to use.
We need to introduce a new environment variable NEXT_LOCALE
which will contain the locale of the website generated during the export process.
Example of content in .env.*
file
NEXT_LOCALE=en
You can now use the NEXT_LOCALE
variable in your _app.tsx
file in the getInitialProps
function to define the locale.
const getInitialProps: typeof App.getInitialProps = async (appContext) => {
const locale = appContext.router.locale || process.env.NEXT_LOCALE
const [supportedLocale, messagePromise] = getMessages(locale)
const [, messages, appProps] = await Promise.all([
polyfill(supportedLocale),
messagePromise,
App.getInitialProps(appContext),
])
return {
...(appProps as any),
locale: supportedLocale,
messages: messages.default,
}
}
Thanks to this variable and the change done, react-intl
will now use as locale the content from the env variable. The translated messages taken are now from the right locale.
Now you have a website available for multiple languages. You can build your website for multiple domains as well dealing with multiple build processes, one for each locale. Feel free to implement it with the service you want like Netlify, Vercel, … etc
The showcase generated for two languages deployed with Vercel :
- English
- French
If you want to know more, have a look into the Source Code