Files
documenso/packages/lib/utils/i18n.ts
2025-02-13 14:10:38 +11:00

81 lines
2.2 KiB
TypeScript

import type { I18n, MessageDescriptor } from '@lingui/core';
import { i18n } from '@lingui/core';
import type { I18nLocaleData, SupportedLanguageCodes } from '../constants/i18n';
import { APP_I18N_OPTIONS } from '../constants/i18n';
import { env } from './env';
export async function dynamicActivate(locale: string) {
const extension = env('NODE_ENV') === 'development' ? 'po' : 'mjs';
const { messages } = await import(`../translations/${locale}/web.${extension}`);
i18n.loadAndActivate({ locale, messages });
}
const parseLanguageFromLocale = (locale: string): SupportedLanguageCodes | null => {
const [language, _country] = locale.split('-');
const foundSupportedLanguage = APP_I18N_OPTIONS.supportedLangs.find(
(lang): lang is SupportedLanguageCodes => lang === language,
);
if (!foundSupportedLanguage) {
return null;
}
return foundSupportedLanguage;
};
/**
* Extracts the language from the `accept-language` header.
*/
export const extractLocaleDataFromHeaders = (
headers: Headers,
): { lang: SupportedLanguageCodes | null; locales: string[] } => {
const headerLocales = (headers.get('accept-language') ?? '').split(',');
const language = parseLanguageFromLocale(headerLocales[0]);
return {
lang: language,
locales: [headerLocales[0]],
};
};
type ExtractLocaleDataOptions = {
headers: Headers;
};
/**
* Extract the supported language from the header.
*
* Will return the default fallback language if not found.
*/
export const extractLocaleData = ({ headers }: ExtractLocaleDataOptions): I18nLocaleData => {
const headerLocales = (headers.get('accept-language') ?? '').split(',');
const unknownLanguages = headerLocales
.map((locale) => parseLanguageFromLocale(locale))
.filter((value): value is SupportedLanguageCodes => value !== null);
// Filter out locales that are not valid.
const languages = (unknownLanguages ?? []).filter((language) => {
try {
new Intl.Locale(language);
return true;
} catch {
return false;
}
});
return {
lang: languages[0] || APP_I18N_OPTIONS.sourceLang,
locales: headerLocales,
};
};
export const parseMessageDescriptor = (_: I18n['_'], value: string | MessageDescriptor) => {
return typeof value === 'string' ? value : _(value);
};