i18n-check: Validating your Next.js internationalization
Introduction
In the previous i18n-check: End to end React i18n testing
 post we went into detail on how a React application can be validated in regards to i18n. i18n-check
 now also supports next-intl and also works with next-i18next out of the box, offering more options in regards to validating Next.js applications.
With the latest changes it’s now possible to validate i18n end to end for a Next.js application if one of the following i18n libraries is used: react-intl
, react-i18next
, next-intl
 or next-i18next
This enables you to find untranslated or invalid translation messages in locale files. Additionally, it identifies undefined key (used in the source code but missing in locale files) as well as unused keys (defined in the locale files but not used in the source code).
Checking i18n in a Next.js application
Running checks should help with being able to answer the following questions:
How many keys are missing in the
frtarget language file?
Are all keys valid in the
detarget file?
Are there any keys in the codebase that are missing in the
ensource language file?
Take a look at the following example:
// en.json
"message.greeting": "Hi, <b>{name}</b>!"
// de.json
"message.greeting": "Hallo {name}!"While the default message contains tags, the message in the de.json file does not. These tags might have been removed during the translation process or were never added, leading to a mismatch between the source and target language message.
// en.json
"message.greeting": "Hi {user}, it is {today, date, medium}.",
// de.json
"message.greeting": "Hallo {user}, heute ist {today, date, medium} und morgen ist {tomorrow, date, medium}.",The second example shows that the target translation contains more date information when compared to the source en.json file, indicating that the source and target translations are out of sync, which can lead to unexpected or weird display errors at runtime.
Running these i18n checks helps us to identify any potential runtime issues before they affect users. So instead of manually keeping track of the state of our translations, we rather want to be informed when something is missing or needs updating.
Setting up i18n-check
To set up i18n-check run the following command:
yarn add --dev @lingual/i18n-checkAlternatively if you are using npm:
npm install --save-dev @lingual/i18n-checkOr if you are using pnpm:
pnpm add --save-dev @lingual/i18n-checkUpdate the package.json file and add a new command:
"scripts": {
    // ...
    "i18n:check": "i18n-check"
}Run the i18n:check command directly from the CLI, i.e. yarn i18n:check.
Validating locale and source files
Checks can run against single files, single folders or a combination of files and folders and mainly depend on on how these localization files are organized inside an existing project.
To get a better understanding, let’s try to got through a basic example (for more advanced scenarios check the README
). A basic setup could for example include a folder called locales containing a number of translation files organized as en-en.json, fr-fr.json, it-it.json etc:
- locales/
  - en-en.json
  - fr-fr.json
  - it-it.jsonWith the -l or --locales option you can define where the target locale files are located and with the -s or --source option you can specify the base/reference file/folder to compare the target files against. To define where the source files are located you can use the -u or --unused option and also provide the -f or --formatto tell the parser if we need to check for react-intl, next-intl or the i18-next format.
yarn i18n:check --locales locales --source en-en -f next-intl -u srcThe above command would yield the following result:
i18n translations checker
Source: en-en
Found missing keys!
┌──────────────────────────────┬────────────┐
│ file                         │ key        │
├──────────────────────────────┼────────────┤
│  messageExamples/de-de.json  │  richText  │
│  messageExamples/de-de.json  │  nesting1  │
│  messageExamples/de-de.json  │  key1      │
└──────────────────────────────┴────────────┘
Found invalid keys!
┌──────────────────────────────┬─────────────────────┐
│ file                         │ key                 │
├──────────────────────────────┼─────────────────────┤
│  messageExamples/de-de.json  │  multipleVariables  │
└──────────────────────────────┴─────────────────────┘
Found unused keys!
┌─────────────────────────────────────────────────┬──────────────────┐
│ file                                            │ key              │
├─────────────────────────────────────────────────┼──────────────────┤
│  messageExamples/en-en.json                     │  format.ebook    │
│  messageExamples/en-en.json                     │  nonExistentKey  │
└─────────────────────────────────────────────────┴──────────────────┘
Found undefined keys!
┌──────────────────────────────────────────────────────┬────────────────────────────────┐
│ file                                                 │ key                            │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│  src/App.tsx                                         │  some.key.that.is.not.defined  │
└──────────────────────────────────────────────────────┴────────────────────────────────┘For more advanced examples check the examples section in the README .
Setup checks on the CI
The following is an example of how you could define a Github workflow for an existing Next.js application, where the source code to parse is under src.
name: i18n-check
on:
  pull_request:
    branches:
      - main
  push:
    branches:
      - main
jobs:
  i18n-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
      - name: yarn install & build
        run: |
          yarn install
          yarn build          
      - name: yarn i18n-check
        run: |
          yarn i18n:check -l translations/messageExamples -s en-US -u src/ -f next-intl          Checkout i18n-check here
Links
We are working on a new translation management system with first-class branching and CLI integration.
Subscribe to our newsletter and we'll let you know when the beta becomes available.