Internationalization is the way you make your apps available to people who speak different languages. It helps make sure you're reaching users who speak languages other than your own, especially as your applications scale to a global audience. Ever noticed how some apps feel a bit off when you switch languages? That's often because internationalization was an afterthought. The best way to handle internationalization is by doing it early and often.
Let's delve into some common tools and best practices for handling internationalization in your React app.
Common internationalization tools for React
i18next
is the most popular internationalization framework for React. The framework detects the user language from the browser, loads the translations, and pushes them into your application. Translations are commonly stored as strings in a JSON file and mapped to a specific locale code, such as en
for English or it
for Italian. You may have a single file with all the translations, or multiple files to load them on demand. i18next
has many built-in features that you can discover in their docs, and they have a 20-minute crash course video to get you started.
If you're using a React framework, like Next.js, there are even framework-specific internationalization libraries. I use next-intl
for this application because it was straightforward to set up, and it allowed me to decide if I wanted to use unique pathnames for every language that the app supports. Some other options include next-i18n-router
and next-international
. Other React frameworks may have their own internationalization solutions as well.
Best practices for internationalization
The most important idea to take away from this blog post is to internationalize early and often. Integrate a process for handling string translations into your CI/CD pipeline, either using a cloud-based tool or integrating it in a custom way yourself. This supports the ideology of continuous localization, an extension of the commonly adopted Agile methodology of continuous integration / continuous deployment. Software is constantly being shipped in incremental pieces to deliver incremental improvement, and translations should be a part of that process.
Avoid Compound Strings
Another thing to keep in mind is that dates, numbers, units, and times should be externalized. Using compound strings that are built at run time from concatenated phrases is an antipattern, and you should avoid doing it.
Why? Compound strings are difficult to localize because they often assume a sentence structure in English works well in other languages. Instead, use placeholders for accurate translations across languages. For example, instead of having multiple keys for a single sentence that contains some placeholder information (like a date), use interpolation:
{
"key": "{{who}} is {{what}}"
}
Using a translation library like i18next, you would interpolate like this in your React code:
t("key", { who: "Bumi", what: "the best dog ever" });
// the string would be "Bumi is the best dog ever"
Handle Plurals Correctly
You should also be aware that numbers and plurals work differently across languages. Implement your count logic with placeholders that are inclusive of these differences. For example, 0 is plural in English (I have 0 cats), but 0 is singular in French (J'ai 0 chat). You can use interpolation context to account for plurals. For example:
{
"key_one": "item",
"key_other": "items"
}
Then, you would interpolate the counts like this in your React code:
t("key", { count: 0 }); // "items"
t("key", { count: 1 }); // "item"
t("key", { count: 3 }); // "items"
Design Considerations
Some other tips to support a globally-minded app include:
-
Avoid using images / icons that contain text in your application. These won't be able to support multiple languages since they can't be edited at run time.
-
Allow space on the UI for strings to expand / shrink depending on the language. The 31-char German string "nahrungsmittelunverträglichkeit" is almost twice as long as the 16-char English equivalent "food intolerance". Your carefully designed layouts will inevitably change!
-
Consider the use case for supporting languages that are written and read in both left-to-right and right-to-left orientations. This is especially important as your applications scale to a global audience. The UI for an English-language website will essentially be flipped around for the Arabic-language version. Airbnb does a great job supporting both left-to-right and right-to-left languages. Engage UX designers early in discussions on how to support this.
What about localization?
Think of localization as internationalization's more specific partner. While internationalization gets you speaking the right language, localization helps you use more region-specific terms.
Localization is the process of adapting your internationalized application to a more specific region. You can add a suffix to a language code to make it more specific to the regional language spoken. Think about the country that you will need to support, and how strings may change based on that. This is an example of when localization could be useful in Spanish: The Spain Spanish word for computer is ordenador and the Mexican Spanish word for computer is computadora. Being more specific to the region will give your users a more familiar experience.
Here are some examples of different locales and language codes:
-
es
: The most generic Spanish. If a browser has its language set to Spanish, these translations will display. -
es-MX
: Mexican-localized Spanish. If a browser has its language set to Spanish (Mexico), these translations will display. -
es-ES
: Spain-localized Spanish. If a browser has its language set to Spanish (Spain), these translations will display.
Localization fallbacks
A fallback will happen when a selected locale is not supported with translation files. Instead, another supported language will be displayed. Fallback behavior is often configurable in internationalization libraries. My preferred setup is the following:
If the browser is set to a locale that is not supported, i18n will automatically fall back to the more general language supported. This ensures users will see content in a language they can understand, even if their specific locale isn't supported. If the browser is set to a language that is not supported, i18n will automatically fall back to the specified fallback language- I use en
. For example:
-
es-CL
would fall back toes
if strings for localized Chilean Spanish are not supported but Spanish is supported. -
es-CL
would fall back toen
if both strings for localized Chilean Spanish AND Spanish are not supported.
Conclusion
Internationalization and localization are two important aspects of your application that can be handled by well-developed and well-maintained libraries. Consider integrating it into your CI/CD pipeline. Localization can provide an even better user experience, tailoring app language to specific regions. Ultimately, it's important to internationalize early and often, especially as your app scales to an international user base. Both you and your users will appreciate the effort in the long run!