UNPKG

@dwp/govuk-casa

Version:

A framework for building GOVUK Collect-And-Submit-Applications

107 lines 4.48 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = i18nMiddleware; const i18next_1 = require("i18next"); const i18next_http_middleware_1 = require("i18next-http-middleware"); const node_path_1 = require("node:path"); const node_fs_1 = require("node:fs"); const deepmerge_1 = __importDefault(require("deepmerge")); const js_yaml_1 = require("js-yaml"); const logger_js_1 = __importDefault(require("../lib/logger.js")); /** * @typedef {import("express").RequestHandler} RequestHandler * @access private */ const log = (0, logger_js_1.default)("middleware:i18n"); const loadJson = (file) => { // Strip out newlines (this is a legacy feature which we're keeping for // backwards compatibility). /* eslint-disable-next-line security/detect-non-literal-fs-filename */ const json = (0, node_fs_1.readFileSync)(file, "utf8"); return JSON.parse(json.replace(/[\r\n]/g, "")); }; /* eslint-disable-next-line security/detect-non-literal-fs-filename */ const loadYaml = (file) => (0, js_yaml_1.load)((0, node_fs_1.readFileSync)(file, "utf8")); const extract = (file) => { const ext = /.yaml$/i.test(file) ? ".yaml" : ".json"; const data = ext === ".yaml" ? loadYaml(file) : loadJson(file); return { ns: (0, node_path_1.basename)(file, ext), data, }; }; const loadResources = (languages, directories) => { const store = Object.create(null); for (const language of languages) { // ESLint disabled as `store`, `language` and `ns` are all dev-controlled, // and this function is only called once, at boot-time. /* eslint-disable security/detect-object-injection */ store[language] = Object.create(null); for (const basedir of directories) { const dir = (0, node_path_1.resolve)(basedir, language); /* eslint-disable-next-line security/detect-non-literal-fs-filename */ if (!(0, node_fs_1.existsSync)(dir)) { continue; } log.info("Loading %s language from %s ...", language, dir); /* eslint-disable-next-line security/detect-non-literal-fs-filename */ for (const file of (0, node_fs_1.readdirSync)(dir)) { const { ns, data } = extract((0, node_path_1.resolve)(dir, file)); if (store[language][ns] === undefined) { store[language][ns] = Object.create(null); } store[language][ns] = (0, deepmerge_1.default)(store[language][ns], data); } } /* eslint-enable security/detect-object-injection */ } return store; }; /** * Internationalisation middleware. * * @param {object} opts Options * @param {string[]} [opts.languages] Language codes * @param {string[]} [opts.fallbackLng] Fallback language * @param {string[]} [opts.directories] Source translations directories * @returns {RequestHandler[]} Middleware functions */ function i18nMiddleware({ languages = ["en", "cy"], fallbackLng = false, directories = [], }) { // Load _all_ translations, from all directories into memory. const resources = loadResources(languages, directories); // Configure i18next const i18nInstance = (0, i18next_1.createInstance)(); i18nInstance.use(i18next_http_middleware_1.LanguageDetector).init({ initAsync: false, // because we need synchronous loading supportedLngs: languages, fallbackLng, defaultNS: "common", // debug: true, // All translation resources resources, // LanguageDetector options detection: { lookupQuerystring: "lang", lookupSession: "language", order: ["querystring", "session"], }, }); // 2 middleware: one to read/set the session language, and one to enhance the // req/res objects with i18n features return [ (req, res, next) => { if (!req.session.language) { req.session.language = languages[0]; } if (req?.query.lang && languages.includes(req.query.lang)) { req.session.language = String(req.query.lang); } next(); }, (0, i18next_http_middleware_1.handle)(i18nInstance), ]; } //# sourceMappingURL=i18n.js.map