I18n

FacilMap uses i18nextopen in new window for internationalization throughout the frontend, the server and its libraries. It detects the desired user language like this:

  • In the browser, i18next-browser-languageDetectoropen in new window is used to detect the user’s language. It looks at the configured browser languages (navigator.languagesopen in new window) and checks for which one a translation exists. The configured language can be overridden by setting a lang cookie or appending a ?lang= query parameter to the URL.
  • On the server, when a request is handled through HTTP (including the WebSocket), i18next-http-middlewareopen in new window is used to detect the user’s language. It looks at the configured browser languages (Accept-Languageopen in new window) and checks for which one a translation exists. The configured language can be overridden by setting a lang cookie or by appending a ?lang= query parameter to the URL. The server stores the selected language in the Node.js domainopen in new window that is created for each incoming request, causing all functions triggered (sync or async) from the request to use the language setting of the request.
  • On the sever, when a function is called outside of an incoming HTTP request, messages are not internationalized and output in English.

In addition, certain values can be shown in metric units or in US customary units. By default, metric units are used. This can be changed by sending a units query parameter or cookie with the value us_customary.

Translations are managed on Weblateopen in new window, changes there automatically trigger a pull request to the FacilMap repository.

Use FacilMap in an app not using i18next

When you import any of the FacilMap modules into a JavaScript app that does not use i18next, they will automatically detect the user language and internationalize their output accordingly as described above.

The main instance of i18next is initializedopen in new window by FacilMap as soon as the first message is internationalized. This that before calling any of the functions exported by FacilMap, you can still change the i18next configuration.

Change the language detector

To change the detected user language, you have two options. As mentioned above, both options need to be executed before calling any FacilMap functions that generate internationalized messages.

Option 1 is to set a custom language detectoropen in new window using the setLanguageDetector() function exported by facilmap-utils. This language detector is applied to the i18next main instance when it is initialized instead of the default language detector used by FacilMap.

import { setLanguageDetector } from "facilmap-utils";

setLanguageDetector(myLanguageDetector);

Option 2 is to set a custom i18next instanceopen in new window that will be used by FacilMap. In this example, we are disabling the language detector and use a custom i18next instance that always uses German:

import { setLanguageDetector, setI18nGetter } from "facilmap-utils";
import { createInstance } from "i18next";

setLanguageDetector(undefined);
setI18nGetter(() => createInstance({ lng: "de" }));

Use the backend language detector

If you are including some of FacilMap’s server modules in your own Node.js express server and want messages to be internationalized according to the user language as described above, you need to add FacilMap’s i18nMiddleware to your express server:

import express from "express";
import domainMiddleware from "express-domain-middleware";
import { i18nMiddleware } from "facilmap-server";

const app = express();
app.use(domainMiddleware);
app.use(i18nMiddleware);

As seen in the example, i18nMiddleware requires express-domain-middlewareopen in new window to be initialized before it.

Use FacilMap in an app already using i18next

When you use FacilMap’s modules in an app that is already using i18next, you may want FacilMap to reuse your existing i18n configuration (such as language detection), or you may want it to use its own configuration independently from yours.

When a FacilMap function internationalizes a message for the first time, it initializes i18next in the following way:

  1. It retrieves the i18next instance set through setI18nGetter() (exported by facilmap-utils). If no instance was set, it defaults to the i18next main instance (import i18next from "i18next").
  2. If the instance is not initialized yet (!i18next.isInitializing && !i18next.isInitialized), it initializes it with its default configuration (language detector as described above).
  3. It adds its resources to the instance under namespaces prefixed by facilmap-.

Reuse your i18next instance for FacilMap

You can make FacilMap reuse your existing i18next instance and configuration in the following way:

  • Make sure your i18next instance is initialized before you call any FacilMap functions that need to internationalize messages.
  • Call setI18nGetter() with a callback that returns your i18next instance (can be skipped if you are using the main instance).
import { setLanguageDetector, setI18nGetter } from "facilmap-utils";
import { createInstance } from "i18next";

const i18next = createInstance();
await i18next.init({
	lng: "en"
});
setI18nGetter(() => i18next);

Use a separate i18next instance for FacilMap

If you want to make FacilMap use a separate i18next instance, for example because you want to keep your and FacilMap’s language detection independent, use the following example:

import { setI18nGetter } from "facilmap-utils";
import { createInstance } from "i18next";

setLanguageDetector(undefined);
setI18nGetter(() => createInstance());

Because the instance returned by createInstance() is not initialized, FacilMap will initialize it using its default configuration.