UNPKG

superstatic

Version:

A static file server for fancy apps

126 lines (125 loc) 4.34 kB
"use strict"; /** * Copyright (c) 2022 Google LLC * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.i18nContentOptions = void 0; const pathutils_1 = require("./pathutils"); /** * Returns the list of paths to check for i18n content. * The path order is: * (1) root/language_country/path (for each language) * (2) root/ALL_country/path (if country is set) * (3) root/language_ALL/path or root/language/path (for each language) * * If i18n is *not* configured, an empty list is returned. * @param p requested path. * @param req the request object containing superstatic and i18n configuration. * @return list of paths to check for i18n content. */ function i18nContentOptions(p, req) { const paths = []; const i18n = req.superstatic.i18n; if (!i18n?.root) { return paths; } const country = getCountryCode(req.headers); const languages = getI18nLanguages(req.headers); // (1) if (country) { for (const l of languages) { paths.push(join(i18n.root, `${l}_${country}`, p)); } // (2) paths.push(join(i18n.root, `ALL_${country}`, p)); } // (3) for (const l of languages) { paths.push(join(i18n.root, `${l}_ALL`, p)); paths.push(join(i18n.root, `${l}`, p)); } return paths; } exports.i18nContentOptions = i18nContentOptions; function join(...arr) { arr.unshift("/"); return (0, pathutils_1.normalizeMultiSlashes)(arr.join("/")); } /** * Fetches the country code from the headers object. * @param headers headers from the request. * @return country code, or an empty string. */ function getCountryCode(headers) { const overrideValue = cookieValue(headers.cookie, "firebase-country-override"); if (overrideValue) { return overrideValue; } return headers["x-country-code"] || ""; } /** * Fetches the languages from the accept-language header. * @param headers headers from the request. * @return ordered list of languages from the header. */ function getI18nLanguages(headers) { const overrideValue = cookieValue(headers.cookie, "firebase-language-override"); if (overrideValue) { return overrideValue.includes(",") ? overrideValue.split(",") : [overrideValue]; } const acceptLanguage = headers["accept-language"]; if (!acceptLanguage) { return []; } const languagesSeen = new Set(); const languagesOrdered = []; for (const v of acceptLanguage.split(",")) { const l = v.split("-")[0]; if (!l) { continue; } if (!languagesSeen.has(l)) { languagesOrdered.push(l); } languagesSeen.add(l); } return languagesOrdered; } /** * Fetches a value from a cookie string. * @param cookieString full cookie string. * @param key key to look for. * @return the value, or empty string; */ function cookieValue(cookieString, key) { if (!cookieString) { return ""; } const cookies = cookieString.split(";").map((c) => c.trim()); for (const cookie of cookies) { if (cookie.startsWith(key)) { const s = cookie.split("=", 2); return s.length === 2 ? s[1] : ""; } } return ""; }