Next.js
Localize Next.js with Transifex Native
In this guide we'll be covering how to localize your Next.js app with Server-Side-Rendering (SSR), using Transifex Native and Over-The-Air translations.
Next.js has already built-in support for i18n routing, and we are going to leverage this, by binding Transifex Native on top of that.
Basic setup
Install Transifex Native
In your Next.js app, install the Transifex Native dependencies for React applications.
npm install @transifex/native @transifex/react @transifex/cli --save
Update your next.config.js
Edit or create a next.config.js
file in your root folder and add the supported locales, as well as your Transifex Native public token.
// next.config.js
module.exports = {
i18n: {
// These are all the locales you want to support in
// your application
locales: ['en', 'fr', 'de', 'el'],
// This is the default locale you want to be used when visiting
// a non-locale prefixed path e.g. `/hello`
defaultLocale: 'en',
localeDetection: false,
},
publicRuntimeConfig: {
TxNativePublicToken: 'YOUR-PUBLIC-TX-NATIVE-TOKEN',
}
}
Read the official Next.js Internationalized Routing for more configuration options.
Create an Transifex Native utility
In the source folder, where the code exists, add a new i18n.js
library file, and paste the following:
// nextjs/i18n.js
import { tx, normalizeLocale } from '@transifex/native';
import getConfig from 'next/config';
const { publicRuntimeConfig } = getConfig();
/**
* Used by SSR to pass translation to browser
*
* @param {*} { locale, locales }
* @return {*} { locale, locales, translations }
*/
export async function getServerSideTranslations({ locale, locales }) {
tx.init({
token: publicRuntimeConfig.TxNativePublicToken,
});
// ensure that nextjs locale is in the Transifex format,
// for example, de-de -> de_DE
const txLocale = normalizeLocale(locale);
// load translations over-the-air
await tx.fetchTranslations(txLocale);
return {
locale,
locales,
translations: tx.cache.getTranslations(txLocale),
};
}
/**
* Initialize client side Transifex Native instance cache
*
* @param {*} { locale, translations }
*/
export function setClientSideTranslations({ locale, translations }) {
if (!locale || !translations) return;
tx.init({
currentLocale: locale,
});
tx.cache.update(locale, translations);
}
Use getServerSideProps to load translations
On the pages you'd like i18n to be translated, load translations server side, and pass them to the client, using the sample below.
// nextjs/pages/index.js
import { useState } from 'react';
import { T, UT } from '@transifex/react';
import { useRouter } from 'next/router';
import { getServerSideTranslations, setClientSideTranslations } from '../i18n';
export default function Home(props) {
// initialize client side translation from server side props
setClientSideTranslations(props); // { locale, locales, translations }
return (
<div>
<T _str="Hello world" />
</div>
);
}
export async function getServerSideProps(context) {
const data = await getServerSideTranslations(context)
return {
props: {
...data, // { locale, locales, translations }
}
}
}
You can view a full blown example in the Transifex Native Sandbox and also read React guide on how to localize React applications.
Advanced features
Set translations globally
Instead of setting translations in every page, you can move the code in the Custom App space.
// nextjs/pages/_app.js
import { setClientSideTranslations } from '../i18n';
// This default export is required in a new `pages/_app.js` file.
export default function MyApp({ Component, pageProps }) {
setClientSideTranslations(pageProps);
return <Component {...pageProps} />
}
However, due to custom app limitations, you will still need to implement getServerSideProps
on each page, as App
does not support data fetching methods, like getStaticProps
or getServerSideProps
.
Auto refresh translations
By modifying our i18n.js
utility function from the previous example, we can program some custom automatic refresh logic, in order to check for fresh translations at specific intervals.
// ------------ <NEW> ------------
const TRANSLATIONS_TTL_SEC = 10 * 60; // 10 minutes
// ------------ </NEW> -----------
/**
* Used by SSR to pass translation to browser
*
* @export
* @param {*} { locale, locales }
* @return {*}
*/
export async function getServerSideTranslations({ locale, locales }) {
tx.init({
token: publicRuntimeConfig.TxNativePublicToken,
});
// ensure that nextjs locale is in the Transifex format,
// for example, de-de -> de_DE
const txLocale = normalizeLocale(locale);
await tx.fetchTranslations(txLocale);
// ------------ <NEW> ------------
// bind a helper object in the Native instance for auto-refresh
tx._autorefresh = tx._autorefresh || {};
if (!tx._autorefresh[txLocale]) {
tx._autorefresh[txLocale] = Date.now();
}
// check for stale content in the background
if (Date.now() - tx._autorefresh[txLocale] > TRANSLATIONS_TTL_SEC * 1000) {
tx._autorefresh[txLocale] = Date.now();
tx.fetchTranslations(txLocale, { refresh: true });
}
// ------------ </NEW> -----------
return {
locale,
locales,
translations: tx.cache.getTranslations(txLocale),
};
}
In the example above, translations are refreshed every 10min. Modify the TRANSLATIONS_TTL_SEC
variable with an interval more suited to your own use case.
Limitations
- For Next.js apps with lots of content, the setup would need some more complex coding to leverage Content Splitting in order to get optimal performance and reduce data use.
- The basic setup does not offer Over-The-Air updates when new translations are updated in Transifex, thus a server restart is required. Use the Advanced Setup sample to enable automatic translation updates.
Updated almost 2 years ago