Dwarves
Memo
Type ESC to close search bar

I18n Frontend Guideline

In a front-end web application, locales are used to determine the language and geographic location of the user and to display the appropriate content to them.

When a user visits a web page, the application will first detect their locale, then use this information to determine which version of the content to display.

To support multiple languages and locales, the application needs to have the necessary content available for each locale. This can be achieved by creating separate files or resources for each locale or by using a localization library like **i18next** that allows for dynamic localization based on the user’s detected locale.

In this frontend guideline, we will discuss general principles and provide examples using i18next with React.js

Locale detection

There are several ways to detect the user’s locale (i.e., their language and geographic location) in a front-end application:

There are a few libraries where that offer locale detection based on the settings listed above. For instance, In React.js, there is the i18next-browser-languageDetector library that detects language based on:

Another example would be Next.js, where the locale will be automatically detected based on the Accept-Language header and the current domain. Locale detection is enabled by default.

Internationalized routing

Internationalized routing is a way to handle different URLs for the same page based on the user’s detected locale. There are two types of URL routing:

For example in React.js, the routing process can be implemented like this

With Next.js, there is built-in support for internationalized routing since v10.0.0

// next.config.js
module.exports = {
  i18n: {
    locales: ['en-US', 'fr', 'nl-NL', 'nl-BE'],
    defaultLocale: 'en-US',
    domains: [
      {
        // Note: subdomains must be included in the domain value to be matched
        // e.g. www.example.com should be used if that is the expected hostname
        domain: 'example.com',
        defaultLocale: 'en-US',
      },
      {
        domain: 'example.fr',
        defaultLocale: 'fr',
      },
      {
        domain: 'example.nl',
        defaultLocale: 'nl-NL',
        // specify other locales that should be redirected to this domain
        locales: ['nl-BE'],
      },
    ],
  },
}

Supports LTR and RTL text

For some languages, such as Arabic, the letters are arranged from right to left. To ensure that your application supports Right-To-Left (RTL) layout rendering for such languages, you need to add LTR or RTL support.

To add LTR or RTL support to the application, we will set the dir attribute on the body element dynamically in the index.html file.

You can also set the dir attribute on global components such as Header and Footer.

Here’s an example of setting the dir attribute dynamically in the App component:

import React from 'react';
import { useTranslation } from 'react-i18next';
import './App.css';

function App()  {
    const { t, i18n } = useTranslation();
    document.body.dir = i18n.dir(); // return ltr or rtl of current language
    return (
      <div className="App">
        {t('welcome')}
      </div>
    );
}

export default App;

Here’s an example of setting the **dir** attribute on a global **Header** component:

import { useEffect } from 'react';
import { useTranslation } from 'next-i18next';

const Header = () => {
  const { t, i18n } = useTranslation('common');
  const localeDir = i18n.dir(); // return ltr or rtl of current language

  useEffect(() => {
    document.querySelector('html')?.setAttribute('dir', localeDir);
  }, [localeDir]);

  return (
    <header>
				{...}
    </header>
  );
};

export default Header;

Formatting

Starting from i18next version 21.3.0, you can take advantage of the built-in formatting functions based on the Intl API for the following formats:

With these built-in formatting functions, you can easily format and localize various types of data in your application to match the user’s preferred language and regional settings, improving the overall user experience of your application.

Here’s an example of how you can use them:

// Translation JSON
{
  "number": "Number: {{val, number}}",
  "currency": "Currency: {{val, currency(USD)}}",
  "dateTime": "Date/Time: {{val, datetime}}",
  "relativeTime": "Relative Time: {{val, relativetime}}",
  "list": "List: {{val, list}}",
  "weekdays": [
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday"
  ]
}

// Number
i18next.t('number', { val: 1000 }); // --> Number: 1,000
i18next.t('number', { val: 1000.1, formatParams: { val: { minimumFractionDigits: 3 } } }); // --> Number: 1,000.100

// Currency
i18next.t('currency', { val: 2000 }); // --> Currency: $2,000.00
i18next.t('currency', {
  val: 2000.12,
  currency: 'CAD',
  locale: 'fr-CA'
}); // --> Currency: 2 000,12 $ CA

// DateTime
i18next.t('dateTime', { val: new Date(Date.UTC(2012, 11, 20, 3, 0, 0)) }); // --> Date/Time: 12/20/2012
i18next.t('dateTime', {
  val: new Date(Date.UTC(2012, 11, 20, 3, 0, 0)),
  formatParams: {
    val: { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' },
  },
}); // --> Date/Time: Thursday, December 20, 2012

// RelativeTime
i18next.t('relativeTime', { val: 3 }); // --> Relative Time: in 3 days

// List
i18next.t('list', {
  val: i18next.t('weekdays', { returnObjects: true }),
}); // --> List: Monday, Tuesday, Wednesday, Thursday, and Friday

Conclusion

Multilingual is a very important function for web or mobile applications nowadays, Users will come from all over the world and always ask for support for their language. Above is a guide to help you install multi-language for your application or website, You can implement it according to the instructions to automatically find the user’s language, setup multi-language by domain or subpath, support LTR and RTL text, and finally format of number, currency, time, list…

If you have a difficult problem that you would like us to help you on, please feel free to submit a challenge request here.

Come be with us We’d love to have you in our next chapter, by all means.

Follow our journey