remix-i18next
Version:
The easiest way to translate your Full Stack React Router apps
66 lines (54 loc) • 1.85 kB
text/typescript
import { formatLanguageString } from "./format-language-string.js";
import { parse, pick } from "./parser.js";
export type Locales = string | string[] | undefined;
/**
* Get the client's locales from the Accept-Language header.
* If the header is not defined returns null.
* If the header is defined return an array of locales, sorted by the quality
* value.
*
* @example
* export let loader: LoaderFunction = async ({ request }) => {
* let locales = getClientLocales(request)
* let date = new Date().toLocaleDateString(locales, {
* "day": "numeric",
* });
* return json({ date })
* }
*/
export function getClientLocales(headers: Headers): Locales;
export function getClientLocales(request: Request): Locales;
export function getClientLocales(requestOrHeaders: Request | Headers): Locales {
let headers = getHeaders(requestOrHeaders);
let acceptLanguage = headers.get("Accept-Language");
// if the header is not defined, return undefined
if (!acceptLanguage) return undefined;
let parsedLocales = parse(acceptLanguage)
.filter((lang) => lang.code !== "*")
.map(formatLanguageString);
let validLocales: string[] = [];
for (let locale of parsedLocales) {
try {
// This will throw on invalid locales
new Intl.Locale(locale);
// If we get here, the locale is valid
validLocales.push(locale);
} catch {
// We want to ignore errors here
}
}
let locale = pick(
Intl.DateTimeFormat.supportedLocalesOf(validLocales),
acceptLanguage,
);
return locale ?? undefined;
}
/**
* Receives a Request or Headers objects.
* If it's a Request returns the request.headers
* If it's a Headers returns the object directly.
*/
function getHeaders(requestOrHeaders: Request | Headers): Headers {
if (requestOrHeaders instanceof Request) return requestOrHeaders.headers;
return requestOrHeaders;
}