Internationalization
We make use of react-i18next, a powerful internationalization framework for React / React Native which is based on i18next. In certain projects we also use:
In order to understand how this repository implements i18n, it is important to understand how these libraries work. The remainder of this document assumes a working knowledge of these libraries.
Adding i18n to your project
- add i18next-parser.config.js to project root.
const i18nextParserConfigBase = require('../../i18next-parser.config.base') // this file is located in the workspace root
module.exports = {
...i18nextParserConfigBase,
input: ['src/**/*.{js,jsx,ts,tsx}']
}
- add extract-translations command to targets object and implicitDependencies to base object in project.json. You must replace PROJECT_PATH with your project path e.g.
apps/journeys
.
{
...
"implicitDependencies": ["locales"],
"targets": {
"extract-translations": {
"executor": "@nrwl/workspace:run-commands",
"options": {
"commands": [
{
"command": "npx i18next --config PROJECT_PATH/i18next-parser.config.js"
}
]
}
}
...
}
}
- update your components to make use of useTranslation hooks, appWithTranslation HOCs, Trans components etc in order to indicate to the parser that there is a string available for translation.
It is very important that you include a namespace. This namespace should be a dashed version of your project path. For example apps/journeys
would become apps-journeys
or libs/journeys/ui
would become libs-journeys-ui
.
import { useTranslation } from 'react-i18next'
function Component() {
const { t } = useTranslation('libs-journeys-ui') // must include namespace
return <div>{t('hello world')}</div>
}
- run nx command
extract-translations
for the project you are working on. This should pull all of the strings requiring translations into a namespaced file for examplelocales/en/libs-journeys-ui.json
ready for translation. This needs to be committed and kept up to date. This is tested in CI so will fail if not correctly updated.
Next.js configuration
- update input in i18next-parser.config.js located in the project root
const i18nextParserConfigBase = require('../../i18next-parser.config.base')
module.exports = {
...i18nextParserConfigBase,
input: ['src/**/*.{js,jsx,ts,tsx}', 'pages/**/*.{js,jsx,ts,tsx}']
}
- add next-i18next.config.js to the project root
const path = require('path')
/**
* @type {import('next-i18next').UserConfig}
**/
const i18nConfig = {
i18n: {
defaultLocale: 'en',
locales: ['en'],
localePath: path.resolve('./libs/locales')
}
}
module.exports = i18nConfig
- update next.config.js
const { i18n } = require('./next-i18next.config')
const nextConfig = {
i18n,
...
}
- update pages/_app.tsx to use appWithTranslation HOC
import { appWithTranslation } from 'next-i18next'
import i18nConfig from '../next-i18next.config'
// your _app component
function CustomApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default appWithTranslation(JourneysApp, i18nConfig)
- add async function on your page-level components, via either getStaticProps or getServerSideProps (depending on your use case)
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import i18nConfig from '../next-i18next.config' // project root
export async function getStaticProps({ locale }) {
return {
props: {
...(await serverSideTranslations(
context.locale ?? 'en',
['apps-watch'], // namespaces your components make use of
i18nConfig
))
},
};
}
Crowdin
Once your files have been committed and your PR merged to main a Crowdin GitHub Action will run to upload any changes to locales/en
. It will also propose a PR with newly minted translations automatically. New translation requests should be sent to the Jesus Film Project Translation Manager so that these strings can be localized.