express-intlayer
Version:
Manage internationalization i18n in a simple way for express application.
129 lines (127 loc) • 5.45 kB
JavaScript
import { getConfiguration } from "@intlayer/config/node";
import { getDictionary as getDictionary$1, getIntlayer as getIntlayer$1, getTranslation } from "@intlayer/core/interpreter";
import { localeDetector } from "@intlayer/core/localization";
import { getLocaleFromStorageServer } from "@intlayer/core/utils";
import { prepareIntlayer } from "@intlayer/engine/build";
import { createNamespace } from "cls-hooked";
//#region src/index.ts
let debug = () => {};
const configuration = getConfiguration();
const { internationalization } = configuration;
debug = (msg) => console.debug(msg);
/**
* Retrieves the locale from storage (cookies, localStorage, sessionStorage).
*/
const getStorageLocale = (req) => getLocaleFromStorageServer({
getCookie: (name) => req.cookies?.[name],
getHeader: (name) => req.headers?.[name]
});
const appNamespace = createNamespace("app");
prepareIntlayer(configuration);
const translateFunction = (_req, res, _next) => (content, locale) => {
const { locale: currentLocale, defaultLocale } = res.locals;
const targetLocale = locale ?? currentLocale;
if (typeof content === "undefined") return "";
if (typeof content === "string") return content;
if (typeof content?.[targetLocale] === "undefined") if (typeof content?.[defaultLocale] === "undefined") return content;
else return getTranslation(content, defaultLocale);
return getTranslation(content, targetLocale);
};
/**
* Express middleware that detects the user's locale and populates `res.locals` with Intlayer data.
*
* It performs:
* 1. Locale detection from cookies, headers, or default settings.
* 2. Injects `t`, `getIntlayer`, and `getDictionary` functions into `res.locals`.
* 3. Sets up a `cls-hooked` namespace for accessing these functions anywhere in the request lifecycle.
*
* @returns An Express middleware function.
*
* @example
* ```ts
* import express from 'express';
* import { intlayer } from 'express-intlayer';
*
* const app = express();
* app.use(intlayer());
* ```
*/
const intlayer = () => async (req, res, next) => {
const localeFromStorage = getStorageLocale(req);
const negotiatorHeaders = {};
if (req && typeof req.headers === "object") {
for (const key in req.headers) if (typeof req.headers[key] === "string") negotiatorHeaders[key] = req.headers[key];
}
const localeDetected = localeDetector(negotiatorHeaders, internationalization.locales, internationalization.defaultLocale);
res.locals.locale_storage = localeFromStorage;
res.locals.locale_detected = localeDetected;
res.locals.locale = localeFromStorage ?? localeDetected;
res.locals.defaultLocale = internationalization.defaultLocale;
const t = translateFunction(req, res, next);
const getIntlayer = (key, localeArg = localeDetected, ...props) => getIntlayer$1(key, localeArg, ...props);
const getDictionary = (key, localeArg = localeDetected, ...props) => getDictionary$1(key, localeArg, ...props);
res.locals.t = t;
res.locals.getIntlayer = getIntlayer;
res.locals.getDictionary = getDictionary;
appNamespace.run(() => {
appNamespace.set("t", t);
appNamespace.set("getIntlayer", getIntlayer);
appNamespace.set("getDictionary", getDictionary);
next();
});
};
/**
* Translation function to retrieve content for the current locale.
*
* This function works within the request lifecycle managed by the `intlayer` middleware.
*
* @param content - A map of locales to content.
* @param locale - Optional locale override.
* @returns The translated content.
*
* @example
* ```ts
* import { t } from 'express-intlayer';
*
* app.get('/', (req, res) => {
* const greeting = t({
* en: 'Hello',
* fr: 'Bonjour',
* });
* res.send(greeting);
* });
* ```
*/
const t = (content, locale) => {
try {
if (typeof appNamespace === "undefined") throw new Error("Intlayer is not initialized. Add the `app.use(intlayer());` middleware before using this function.");
if (typeof appNamespace.get("t") !== "function") throw new Error("Using the import { t } from \"express-intlayer\" is not supported in your environment. Use the res.locals.t syntax instead.");
return appNamespace.get("t")(content, locale);
} catch (error) {
debug(error.message);
return getTranslation(content, locale ?? internationalization.defaultLocale);
}
};
const getIntlayer = (...args) => {
try {
if (typeof appNamespace === "undefined") throw new Error("Intlayer is not initialized. Add the `app.use(intlayer());` middleware before using this function.");
if (typeof appNamespace.get("getIntlayer") !== "function") throw new Error("Using the import { t } from \"express-intlayer\" is not supported in your environment. Use the res.locals.t syntax instead.");
return appNamespace.get("getIntlayer")(...args);
} catch (error) {
debug(error.message);
return getIntlayer$1(...args);
}
};
const getDictionary = (...args) => {
try {
if (typeof appNamespace === "undefined") throw new Error("Intlayer is not initialized. Add the `app.use(intlayer());` middleware before using this function.");
if (typeof appNamespace.get("getDictionary") !== "function") throw new Error("Using the import { t } from \"express-intlayer\" is not supported in your environment. Use the res.locals.t syntax instead.");
return appNamespace.get("getDictionary")(...args);
} catch (error) {
debug(error.message);
return getDictionary$1(...args);
}
};
//#endregion
export { getDictionary, getIntlayer, intlayer, t, translateFunction };
//# sourceMappingURL=index.mjs.map