I18n
FacilMap uses i18next for internationalization throughout the frontend, the server and its libraries. It detects the desired user language like this:
- In the browser, i18next-browser-languageDetector is used to detect the user’s language. It looks at the configured browser languages (
navigator.languages
) and checks for which one a translation exists. The configured language can be overridden by setting alang
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-middleware is used to detect the user’s language. It looks at the configured browser languages (
Accept-Language
) and checks for which one a translation exists. The configured language can be overridden by setting alang
cookie or by appending a?lang=
query parameter to the URL. The server stores the selected language in the Node.js domain 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 Weblate, 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 initialized 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 detector 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 instance 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-middleware 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:
- It retrieves the i18next instance set through
setI18nGetter()
(exported byfacilmap-utils
). If no instance was set, it defaults to the i18next main instance (import i18next from "i18next"
). - If the instance is not initialized yet (
!i18next.isInitializing && !i18next.isInitialized
), it initializes it with its default configuration (language detector as described above). - 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.