remix-i18next
Version:
The easiest way to translate your Full Stack React Router apps
107 lines • 3.8 kB
JavaScript
import { formatLanguageString } from "./format-language-string.js";
/**
* Check whether a value is a string.
*/
function isString(value) {
return typeof value === "string";
}
/**
* Parse an `Accept-Language` header into sorted language entries.
*/
export function parse(acceptLanguage) {
let languages = [];
for (let part of (acceptLanguage || "").split(",")) {
let entry = part.trim();
if (!entry)
continue;
let bits = entry.split(";");
let languageTag = bits.shift()?.trim();
if (!languageTag || !isLanguageTag(languageTag))
continue;
let ietf = languageTag.split("-");
let hasScript = ietf.length === 3;
let quality = 1.0;
for (let parameter of bits) {
let parsedQuality = getQuality(parameter);
if (parsedQuality === null)
continue;
quality = parsedQuality;
break;
}
languages.push({
code: ietf[0],
script: hasScript ? ietf[1] : null,
region: hasScript ? ietf[2] : ietf[1],
quality,
});
}
return languages.sort((a, b) => b.quality - a.quality);
}
function isLanguageTag(value) {
if (value === "*")
return true;
let parts = value.split("-");
if (parts.length === 0 || parts.length > 3)
return false;
if (!/^[a-zA-Z]+$/.test(parts[0] ?? ""))
return false;
for (let index = 1; index < parts.length; index++) {
if (!/^[a-zA-Z0-9]+$/.test(parts[index] ?? ""))
return false;
}
return true;
}
function getQuality(value) {
let parameter = value.trim();
if (!parameter.startsWith("q"))
return null;
let [key, quality] = parameter.split("=");
if (key?.trim() !== "q" || !quality)
return null;
if (!/^[0-1](\.[0-9]+)?\s*$/.test(quality))
return null;
return Number.parseFloat(quality);
}
/**
* Pick the best supported language for a given `Accept-Language` value.
*/
export function pick(supportedLanguages, acceptLanguage, options = { loose: false }) {
if (!supportedLanguages?.length || !acceptLanguage) {
return null;
}
let parsedAcceptLanguage = isString(acceptLanguage) ? parse(acceptLanguage) : acceptLanguage;
let supported = supportedLanguages.map((support) => {
let bits = support.split("-");
let hasScript = bits.length === 3;
return {
code: bits[0],
script: hasScript ? bits[1] : null,
region: (hasScript ? bits[2] : bits[1]) ?? undefined,
};
});
for (let lang of parsedAcceptLanguage) {
if (!lang)
continue;
let langCode = lang.code.toLowerCase();
let langRegion = lang.region ? lang.region.toLowerCase() : lang.region;
let langScript = lang.script ? lang.script.toLowerCase() : lang.script;
for (let supportedLanguage of supported) {
let supportedCode = supportedLanguage.code?.toLowerCase() ?? "";
if (langCode !== supportedCode)
continue;
let supportedScript = supportedLanguage.script
? supportedLanguage.script.toLowerCase()
: supportedLanguage.script;
let supportedRegion = supportedLanguage.region
? supportedLanguage.region.toLowerCase()
: supportedLanguage.region;
if (langCode === supportedCode &&
(options?.loose || !langScript || langScript === supportedScript) &&
(options?.loose || !langRegion || langRegion === supportedRegion)) {
return formatLanguageString(supportedLanguage);
}
}
}
return null;
}
//# sourceMappingURL=parser.js.map