DEV Community

Cover image for A Better Approach to Translating JS Apps
Lasse
Lasse

Posted on

A Better Approach to Translating JS Apps

Summary: Using @formatjs/intl and git18n.com for internationalization outperforms and saves time and effort compared with the commonly used approach that keeps everything in .json locale files. NextJS implementation example.


Often when developers think about internalization, they (consciously or subconsciously) associate it with large and unmaintainable .json locale files containing translations. And this isn't without reason, most translation management tools are over-focused on using .json locale files for translations. This approach can be exemplified using the popular and quite fragmented i18next internationalization framework.

An short excerpt form one of their many framework specific implementations next-i18next. First and foremost it has the .json locale files:

└── public
  └── locales
    ├── en
    |   └── common.json
    └── de
        └── common.json
Enter fullscreen mode Exit fullscreen mode

And the corresponding code snippet that uses the .json locale files:

import { useTranslation } from 'next-i18next';

export const Footer = () => {
  const { t } = useTranslation('footer');

  return (
    <footer>
      <p>{t('description')}</p>
    </footer>
  );
};
Enter fullscreen mode Exit fullscreen mode

Side note, this requires a bit more configuration like wrapping the root app in the translation provider, which is quite common. But it also requires all "pages" to import specific translations via serverSideTranslations, which adds additional code and complexity to what ideally should be a simple internalization.

This structure is perhaps technical logically, but the actual use is strenuous for developers and stakeholders alike (usually other team members provide the translations):

  • .json locale files almost instantly becomes unmaintainable due to sheer size and the effort required to keep them up to date
  • beyond the translation key, developers can only guess what t('description') returns and in situations with multiple related keys, this means constantly looking up keys in the .json locale files
  • .json locale files ensure constant merge conflicts in developers teams
  • hard to determine if one .json locale file is missing a translation as compared to others (faulty translations live long lives in .json locale files)

These are some of the drawbacks of doing internationalization with the .json locale file approach. It is obliviously time consuming for the developers. But the productivity killer expands outside of the developer realm and affects translators too. Often other team members are responsible for authoring the translations used. This is often done constructing large spreadsheets containing the translations and mapping it to an id key and/or page in the app. This is obliviously time consuming, error prone and creates multiple sources of truths.

Not to mention, that whenever a stakeholder want to change a translation (even a simple misspelling) the developer is forced to be involved. Not only does this cause translation rigidity but also time and effort.

Internationalization without .json locale files

If you aren't already convinced about the benefits of not using a .json locale file centric approach, the ease of use and translating can perhaps convince.

This approach requires 2 packages: the core internationalization library from @formatjs/intl and the simple translation management utility git18n.

With this approach the above example would look like:

import Intl from '../i18n'; // Singleton that can be used backend and frontend (doesn't get simpler)

export const Footer = () => (
  <footer>
    <p>
      {Intl.t.formatMessage({
        id: 'footer.description',
        defaultMessage: 'This is the translation for the defaultLocale.',
      })}
    </p>
  </footer>
);
Enter fullscreen mode Exit fullscreen mode

The Intl class is a singleton that returns the IntlShape object containing all the formatters requires for date, number and text internationalization. No reason to being forced to jump between t() and <Trans /> component as with i18next.

Side note an NextJS implementation example is available. Other branches in the repository contains react-intl and i18next implementation examples.

This approach gives the developer both the id indicating feature domain and specific purpose (i.e. "description") and the defaultMessage containing the actual inline translation for the defaultLocale. This already eliminated an entire .json locale file for the defaultLocale and increases developer experience with directly understandable inline translation.

In this way the internalization is abstracted away, meaning the developer can focus on developing and simply add the defaultMessage. The rest is added through git18n.com. This benefits of this are big:

  • stakeholders can change translations (even defaultLocale can be overwritten) without having to write a ticket with what should be changed, finding and updating the correct key in the .json locale files, creating a pull request and getting it reviewed (watch out, high risk of merge conflicts with .json locale files) and then deploying
  • ever growing and unmaintainable .json locale files are eliminated
  • git18n.com functions as the source of truth, forget multiple spreadsheet, tickets with translations and .json locale files

In short, this massively pays of in time and effort (from feedback, I reckon likely to be counted in days rather than hours). The ease of updating translations makes it trivial to update a misspelling, an incorrect translation or improve the wording based on customer feedback or a particular marketing campaign. This makes translations "first-class citizen" in the app, as it should be.

Short remark on git18n.com

Git18n.com is intentional simple by design and functionality. It is a translation management utility that does 2 things:

  • a CLI script that effortless extracts text for translation
  • simple web app to translate extracted text

Usage is visualized on the flow chart below:

git18n usage on flow chart

The CLI script is available on NPM.

In later posts I will dig more into usage, implementation and comparisons with other internalization libraries (any suggestions?). If you have any suggestions, feedback or questions, please let me know in the comment box below.

And if you are curious, please sign up on git18n.com and try for yourself.

Links

Top comments (0)