Design principles
This page provides a deep dive about the design principles that next-intl
is based on.
While this page doesn't need to be read in order to use the library effectively in a project, it can provide you with a better understanding of the philosophy behind the library and can help you evaluate if next-intl
is a good fit for your project.
This page also links to planned improvements in order to act as a transparent reference for enhancements to expect from next-intl
in the future.
Holistic
Internationalization clearly requires flexibility from your codebase. However, even implementing a single language properly can already be a challenge by itself.
Using dynamic text labels is the most obvious aspect of internationalization, but supporting a language well also includes many other aspects:
- Pluralization rules: While a language like English has only two plural forms (singular and plural), other languages have up to six different forms.
- Date and time formatting: Different languages have different conventions for formatting dates and times. Even the year displayed can vary from country to country; for example, Thailand uses the Buddhist calendar, which is 543 years ahead of the Gregorian one.
- Number formatting: Formatting conventions for numbers vary across different languages. For instance, when comparing English and German, the separators for thousands and decimals are flipped.
- List formatting: Formatting lists like "HTML, CSS, and JavaScript" is not only a matter of assembling strings in the right order, but also of using language-specific conjunctions and punctuation marks.
- Text direction: While most languages are written from left to right, some languages like Arabic are written from right to left and require a mirrored layout.
On top of this come typical app problems like:
- Rich text formatting: Many apps need to support some way of rich text, e.g. to embed links into text labels ("Learn more in the rich text docs.").
- Time zones: Displaying dates requires consistent handling of time zones across the server and client, potentially even customized based on a preference of the user.
- Relative time formatting: Displaying relative times like "5 minutes ago" or "in 2 hours" requires special care to get the formatting right, and also to make sure the rendered result is in sync across the server and client. Potentially, you also need a mechanism to update the displayed time regularly.
- Localized URLs: URLs should be localized to match the user's language preference (e.g.
/en/about-us
for English and/es/sobre-nosotros
for Spanish). Implementation-wise this requires mapping incoming requests to the right pages and providing streamlined APIs for developers to link between pages in a locale-agnostic way. - Language negotiation: The user's language preference should be detected based on browser settings, but should also be manually configurable—even if a user hasn't signed in.
- SEO: Search engines need to be informed about localized versions of your pages (opens in a new tab) in order to present the best-matching content to your users.
- Country-specifics: If you provide services or products in different countries, you might need to consider country-specifics like different currencies.
Considering this list, it might be apparent how large the problem space is and how interconnected different pieces of internationalization are.
next-intl
takes a holistic approach to internationalization that nudges you towards best practices for handling languages and country-specific conventions. This way, you have more time to focus on what makes your app unique.
→ Planned enhancements (opens in a new tab)
Ergonomic
The bold claim of this library is that your app code will become simpler instead of more complex when you implement internationalization.
If you consider the holistic picture of what internationalization entails, it's clear that a majority of your components will be involved with internationalization in one way or another. Due to this, next-intl
makes it a priority to provide convenient APIs that ensure you feel productive and in control. As a developer, you should be able to focus solely on solving practical problems, with internationalization seamlessly integrated as a side effect of your efforts.
Once internationalization is set up, adding a new language is in the simplest case only a matter of adding a new JSON file with translations—everything else is being taken care of by next-intl
.
→ Planned enhancements (opens in a new tab)
Standards-based
With the introduction of the ECMAScript Internationalization API (opens in a new tab), JavaScript has gotten very capable in the recent years in regard to formatting of dates, times, numbers, lists and pluralization. next-intl
builds on top of this API and provides an ergonomic interface to work with these features, while considering your app-specific configuration & needs.
For text formatting, next-intl
is based on International Components for Unicode (ICU) (opens in a new tab). ICU is a mature and widely used standard for internationalization that is supported by many programming languages and frameworks. next-intl
uses the ICU message syntax for defining text labels, which allows to express complex formatting requirements like interpolating variables and pluralization in a concise and readable way—also for non-developers like translators.
By being based on standards, next-intl
ensures that your internationalization code is future-proof and feels familiar to developers who have existing experience with internationalization. Additionally, relying on standards ensures that next-intl
integrates well with translation management systems like Crowdin (opens in a new tab).
next-intl
uses a nested style to provide structure to messages, allowing to express hierarchies of messages without redundancy. By supporting only a single style, we can offer advanced features that rely on these assumptions like type-safety for messages. If you're coming from a different style, you can consider migrating to the nested style (see "Can I use a different style for structuring my messages?" in the structuring messages docs).
As standards can change, next-intl
is expected to keep up with the latest developments in the ECMAScript standard (e.g. Temporal
(opens in a new tab) and Intl.MessageFormat
(opens in a new tab)).
→ Planned enhancements (opens in a new tab)
Compatible
While next-intl
is designed to tackle internationalization in a holistic way, it's important to consider that internationalization might require integration with other tools and services, enabling you to use the best tools for the job and to collaborate with non-developers.
Typical apps require some of the following integrations:
Translation Management Systems (TMS)
These are typically used to manage translations and to collaborate with translators. Services like Crowdin (opens in a new tab) provide a wide range of features, allowing translators to work in a web-based interface on translations, while providing different mechanisms to sync translations with your app.
next-intl
integrates well with these services as it uses ICU message syntax for defining text labels, which is a widely supported standard. The recommended way to store messages is in JSON files that are structured by locale since this is a popular format that can be imported into a TMS. While it's recommended to have at least the messages for the default locale available locally (e.g. for type-safe messages), you can also load messages dynamically, e.g. from a CDN that your TMS provides.
Content Management Systems (CMS)
If your app uses content from a CMS, you can use this alongside next-intl
. For instance, you might want to manage content like blog posts or marketing copy in a CMS, while managing UI labels in next-intl
.
A CMS typically provides a way to define content for multiple languages, and to fetch this content via a REST API. By using the negotiated app locale that is returned from next-intl
via getLocale
and passing it to requests to your CMS API, you can retrieve content for the user's preferred language.
Backend data
Similar to a CMS, you might have data in a backend service or database that needs to be queried based on the language and country of the user. For instance, you might want to show different prices & currencies for different countries, or you might want to show localized product names. By using the negotiated app locale from next-intl
for requests to your backend, you can ensure localization reaches all parts of your app.
Other libraries
Next.js has a rich ecosystem of libraries that can be used alongside next-intl
, e.g. to handle authentication. By providing documentation and examples for common integrations, next-intl
ensures that you'll have a frictionless experience when integrating with other libraries.
→ Planned enhancements (opens in a new tab)
Performance-obsessed
next-intl
was designed with high-traffic sites in mind that need to deliver a fast and reliable user experience and has proven to work on complex e-commerce pages with outstanding Core Web Vitals.
To achieve this, next-intl
primarly relies on these techniques currently:
- RSC-first: By integrating deeply with React Server Components, we can offload work to a build step or a capable server, therefore reducing the runtime footprint of your app on the client side.
- Splitting of messages: By splitting messages by locale, and optionally also by server, client and component, we can reduce the amount of messages that are sent to the client. This is especially important for apps that support many languages and have a large amount of messages.
- Caching: Parsing of messages, as well as the instantiation of
Intl
(opens in a new tab) constructors is cached across your app, therefore reducing the amount of necessary computation. - Shortcuts: By detecting plain messages, these messages can be returned immediately without having to parse them first.
→ Planned enhancements (opens in a new tab)
Next.js-first
Next.js comes with a lot of bells and whistles, but at the same time there are a number of aspects that need to be handled carefully to enable a reliable internationalization integration. next-intl
, as the name implies, is primarly designed to work well with Next.js. Rather than trying to be a one-size-fits-all solution, next-intl
integrates with Next.js as deeply as necessary and makes it a priority to stay on top of the latest developments in the Next.js ecosystem.
That being said, next-intl
has a Next.js-agnostic core that can be used in any React app, or even in plain JavaScript: use-intl
. This core library contains most features of next-intl
, but lacks Next.js-specific integrations like routing APIs. The goal of this library is to make it possibly to use familiar APIs in other parts of your stack (e.g. React Native) and, in case you ever feel like Next.js is not the right fit for your project anymore, to provide a straightforward migration path.
Migration-friendly
We've all been there, technology moves on, and sometimes you need to move on as well. next-intl
is designed to be a good citizen in your codebase, and to make it possible to migrate away from certain parts of your stack in case this becomes necessary.
If you ever feel like Next.js or next-intl
is not the right fit for your project anymore, you have multiple options here:
- Moving away from Next.js: If you decide to migrate away from Next.js, you can continue to use the core library
use-intl
in any React app, e.g. allowing you to reuse existing components in a Remix app. - Moving away from
next-intl
: If you find thatnext-intl
doesn't fit your needs anymore, you'll have to adapt app code that references the library, but you can still reuse your standards-based ICU messages and replace formatting APIs e.g. with direct calls to the ECMAScript Internationalization API (opens in a new tab).
We wont hold you back, but if you like, we can stay friends.
That being said, we're doing our best to make next-intl
a great fit for your project. If you ever feel like something is not working as expected or if you have ideas for improvements, please let us know on the issue tracker (opens in a new tab) and we'll do our best to help you out.
Woah, this was a long read. Did you really read all of this? next-intl
was created out of a lot of curiosity and passion for internationalization, seems like we share that! We're always curious to hear how next-intl
is working out for you. If you have any feedback or questions, please don't hesitate to reach out (opens in a new tab)!