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
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>
);
};
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>
);
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:
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
- git18n.com
- git18n NPM package
- git18n docs (note: I will update with implementation examples to feature the singleton as recommended approach)
- NextJS implementation using singleton pattern
- Create React App implemention using react-intl
- Documentation for @formatjs/intl
-
Performance comparison (
i18next
significantly outperformed) - jacqueline brandwayn, cover photo credit
Top comments (0)