Files
suwayomi-material-you-webui/src/modules/core/utils/Languages.ts
T

143 lines
4.3 KiB
TypeScript
Raw Normal View History

/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
2021-03-09 16:44:09 +03:30
* 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/.
*/
2023-03-23 13:59:32 +01:00
import { t } from 'i18next';
2024-10-05 23:22:42 +02:00
import { ISOLanguage, IsoLanguages } from '@/modules/core/IsoLanguages.ts';
2025-05-09 01:08:44 +02:00
import { TranslationKey } from '@/Base.types.ts';
2021-03-09 16:44:09 +03:30
2023-04-21 00:27:42 +02:00
export enum DefaultLanguage {
ALL = 'all',
OTHER = 'other',
LOCAL_SOURCE = 'localsourcelang',
2025-05-17 22:17:15 +02:00
PINNED = 'pinned',
2023-04-21 00:27:42 +02:00
}
2025-05-09 01:08:44 +02:00
const DEFAULT_LANGUAGE_TO_TRANSLATION: Record<DefaultLanguage, TranslationKey> = {
[DefaultLanguage.ALL]: 'extension.language.all',
[DefaultLanguage.OTHER]: 'extension.language.other',
[DefaultLanguage.LOCAL_SOURCE]: 'extension.language.other',
2025-05-17 22:17:15 +02:00
[DefaultLanguage.PINNED]: 'global.label.pinned',
2025-05-09 01:08:44 +02:00
};
2025-04-21 19:01:52 +02:00
type LanguageObject = ISOLanguage & { orgCode: string; isoCode: string };
function getISOLanguage(code: string): LanguageObject | null {
2024-10-05 16:09:34 +02:00
if (IsoLanguages[code]) {
2025-04-21 19:01:52 +02:00
return {
...IsoLanguages[code],
orgCode: code,
isoCode: code,
};
2021-03-09 18:05:34 +03:30
}
2024-10-05 16:09:34 +02:00
if (IsoLanguages[code.toLocaleLowerCase()]) {
2025-04-21 19:01:52 +02:00
return {
...IsoLanguages[code.toLocaleLowerCase()],
orgCode: code,
isoCode: code.toLocaleLowerCase(),
};
2024-03-09 02:52:34 +01:00
}
const whereToCut = code.indexOf('-') !== -1 ? code.indexOf('-') : code.length;
const processedCode = code.toLocaleLowerCase().substring(0, whereToCut);
2024-10-05 16:09:34 +02:00
if (IsoLanguages[processedCode]) {
2025-04-21 19:01:52 +02:00
return {
...IsoLanguages[processedCode],
orgCode: code,
isoCode: processedCode,
};
2024-03-09 02:52:34 +01:00
}
return null;
}
2025-04-21 19:01:52 +02:00
export function getLanguage(code: string): LanguageObject {
2024-03-09 02:52:34 +01:00
const isoLanguage = getISOLanguage(code);
if (isoLanguage) {
return isoLanguage;
}
return {
2025-04-21 19:01:52 +02:00
orgCode: code,
isoCode: code,
2024-03-09 02:52:34 +01:00
name: t('global.language.label.language_with_code', { code }),
nativeName: t('global.language.label.language_with_code', { code }),
};
}
export function languageCodeToName(code: string): string {
2025-05-09 01:08:44 +02:00
const isCustomLanguage = Object.keys(DEFAULT_LANGUAGE_TO_TRANSLATION).includes(code);
if (isCustomLanguage) {
return t(DEFAULT_LANGUAGE_TO_TRANSLATION[code as DefaultLanguage]);
}
2024-03-09 02:52:34 +01:00
return getLanguage(code).nativeName;
2021-03-09 16:44:09 +03:30
}
export const toUniqueLanguageCodes = (codes: string[]): string[] => {
const languages = codes.map((code) => getLanguage(code));
const languagesByIsoCode = Object.groupBy(languages, (language) => language.isoCode);
return Object.entries(languagesByIsoCode)
.filter(([, languagesOfIsoCode]) => !!languagesOfIsoCode?.length)
.map(([, languagesOfIsoCode]) => languagesOfIsoCode![0].orgCode);
};
2025-04-24 13:38:05 +02:00
export const toComparableLanguage = (code: string): string => getLanguage(code).isoCode;
export const toComparableLanguages = (codes: string[]): string[] => codes.map(toComparableLanguage);
function defaultNativeLang(): readonly string[] {
const preferredLanguages = toUniqueLanguageCodes([...navigator.languages]);
if (!preferredLanguages.length) {
return ['en'];
}
return preferredLanguages;
}
2025-05-09 00:44:48 +02:00
export function getDefaultLanguages(): string[] {
return [...defaultNativeLang(), DefaultLanguage.ALL];
2021-03-09 16:44:09 +03:30
}
2025-05-09 01:08:44 +02:00
/**
* Sort languages by their native name.
* Custom languages are optionally treated specially:
* - All: first
* - Other: last
*/
export const languageSortComparator = (a: string, b: string, specialCustomLanguagesHandling?: boolean) => {
const isALanguageAll = a === DefaultLanguage.ALL;
const isALanguageOther = a === DefaultLanguage.OTHER || a === DefaultLanguage.LOCAL_SOURCE;
const isBLanguageAll = b === DefaultLanguage.ALL;
const isBLanguageOther = b === DefaultLanguage.OTHER || b === DefaultLanguage.LOCAL_SOURCE;
if (specialCustomLanguagesHandling) {
if (isALanguageAll || isBLanguageOther) {
return -1;
}
if (isALanguageOther || isBLanguageAll) {
return 1;
}
}
return languageCodeToName(a).localeCompare(languageCodeToName(b));
};
/**
* Sort languages by their native name.
* Custom languages are treated specially:
* - All: first
* - Other: last
*/
export const languageSpecialSortComparator = (a: string, b: string) => languageSortComparator(a, b, true);