Files
suwayomi-material-you-webui/src/lib/ISOLanguageUtil.ts

158 lines
3.9 KiB
TypeScript
Raw Normal View History

2026-01-11 17:18:42 +01:00
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
2026-03-11 00:11:29 +01:00
import type { ISOLanguage } from '@/base/IsoLanguages.ts';
import { IsoLanguages } from '@/base/IsoLanguages.ts';
2026-01-22 00:12:22 +01:00
import { i18nResources } from '@/i18n';
import { AppStorage } from '@/lib/storage/AppStorage.ts';
2026-01-11 17:18:42 +01:00
export type LanguageObject = ISOLanguage & { orgCode: string; isoCode: string };
export const DEFAULT_LANGUAGE = 'en';
export const SELECTED_LANGUAGE_CODE_KEY = 'i18n:selected-language';
// source: https://github.com/i18next/i18next/blob/485b4ec8183952b3de8fe5e79dff6467c3afd9d3/src/i18next.js#L561
const RTL_LANGUAGES = [
'ar',
'shu',
'sqr',
'ssh',
'xaa',
'yhd',
'yud',
'aao',
'abh',
'abv',
'acm',
'acq',
'acw',
'acx',
'acy',
'adf',
'ads',
'aeb',
'aec',
'afb',
'ajp',
'apc',
'apd',
'arb',
'arq',
'ars',
'ary',
'arz',
'auz',
'avl',
'ayh',
'ayl',
'ayn',
'ayp',
'bbz',
'pga',
'he',
'iw',
'ps',
'pbt',
'pbu',
'pst',
'prp',
'prd',
'ug',
'ur',
'ydd',
'yds',
'yih',
'ji',
'yi',
'hbo',
'men',
'xmn',
'fa',
'jpr',
'peo',
'pes',
'prs',
'dv',
'sam',
'ckb',
];
2026-01-11 17:18:42 +01:00
export function getISOLanguageFor(code: string, orgCode: string = code, isoCode: string = code): LanguageObject | null {
if (IsoLanguages[code]) {
return {
...IsoLanguages[code],
orgCode,
isoCode,
};
}
return null;
}
export function getISOLanguage(code: string): LanguageObject | null {
return (
getISOLanguageFor(code) ??
getISOLanguageFor(code.toLowerCase(), code) ??
getISOLanguageFor(code.replace('-', '_'), code) ??
getISOLanguageFor(code.replace('_', '-'), code) ??
getISOLanguageFor(code.split('-')[0], code) ??
getISOLanguageFor(code.split('_')[0], code)
);
}
const toUniqueISOLanguageCodes = (codes: string[]): string[] => {
2026-01-11 17:18:42 +01:00
const languages = codes.map((code) => getISOLanguage(code)).filter((code) => code !== null);
const languagesByIsoCode = Object.groupBy(languages, (language) => language.isoCode);
return Object.entries(languagesByIsoCode)
.filter(([, languagesOfIsoCode]) => !!languagesOfIsoCode?.length)
.map(([, languagesOfIsoCode]) => languagesOfIsoCode![0].orgCode);
};
export function getPreferredISOLanguageCodes(): readonly string[] {
const preferredLanguages = toUniqueISOLanguageCodes([...navigator.languages]);
if (!preferredLanguages.length) {
return [DEFAULT_LANGUAGE];
}
return preferredLanguages;
}
export function getLanguageReadingDirection(code: string): 'ltr' | 'rtl' {
const language = getISOLanguage(code);
if (code.toLowerCase().includes('-latn') || language?.isoCode.includes('-latn')) {
return 'ltr';
}
if (code.toLowerCase().includes('-arab') || language?.isoCode.toLowerCase().includes('-arab')) {
return 'rtl';
}
if (RTL_LANGUAGES.includes(code) || RTL_LANGUAGES.includes(language?.isoCode as string)) {
return 'rtl';
}
return 'ltr';
}
2026-01-22 00:12:22 +01:00
export function detectLocale(): string {
const storedLanguage = AppStorage.local.getItem(SELECTED_LANGUAGE_CODE_KEY);
const preferredLanguages = getPreferredISOLanguageCodes();
const languageCodes = [storedLanguage, ...preferredLanguages];
const normalizedLanguageCodes = languageCodes
2026-01-22 00:12:22 +01:00
.filter((code) => code !== null)
.filter((code) => getISOLanguage(code))
.filter((code) => i18nResources.includes(code as (typeof i18nResources)[number]));
return normalizedLanguageCodes[0] ?? DEFAULT_LANGUAGE;
}