Align language sorting with mihon

Always show "All" as the first language and "Other" as the last
This commit is contained in:
schroda
2025-05-09 01:08:44 +02:00
parent 7e4e22b9e1
commit 0a853082db
3 changed files with 54 additions and 10 deletions

View File

@@ -8,6 +8,7 @@
import { t } from 'i18next'; import { t } from 'i18next';
import { ISOLanguage, IsoLanguages } from '@/modules/core/IsoLanguages.ts'; import { ISOLanguage, IsoLanguages } from '@/modules/core/IsoLanguages.ts';
import { TranslationKey } from '@/Base.types.ts';
export enum DefaultLanguage { export enum DefaultLanguage {
ALL = 'all', ALL = 'all',
@@ -15,6 +16,12 @@ export enum DefaultLanguage {
LOCAL_SOURCE = 'localsourcelang', LOCAL_SOURCE = 'localsourcelang',
} }
const DEFAULT_LANGUAGE_TO_TRANSLATION: Record<DefaultLanguage, TranslationKey> = {
[DefaultLanguage.ALL]: 'extension.language.all',
[DefaultLanguage.OTHER]: 'extension.language.other',
[DefaultLanguage.LOCAL_SOURCE]: 'extension.language.other',
};
type LanguageObject = ISOLanguage & { orgCode: string; isoCode: string }; type LanguageObject = ISOLanguage & { orgCode: string; isoCode: string };
function getISOLanguage(code: string): LanguageObject | null { function getISOLanguage(code: string): LanguageObject | null {
@@ -63,6 +70,11 @@ export function getLanguage(code: string): LanguageObject {
} }
export function languageCodeToName(code: string): string { export function languageCodeToName(code: string): string {
const isCustomLanguage = Object.keys(DEFAULT_LANGUAGE_TO_TRANSLATION).includes(code);
if (isCustomLanguage) {
return t(DEFAULT_LANGUAGE_TO_TRANSLATION[code as DefaultLanguage]);
}
return getLanguage(code).nativeName; return getLanguage(code).nativeName;
} }
@@ -93,5 +105,36 @@ export function getDefaultLanguages(): string[] {
return [...defaultNativeLang(), DefaultLanguage.ALL]; return [...defaultNativeLang(), DefaultLanguage.ALL];
} }
export const languageSortComparator = (a: string, b: string) => /**
languageCodeToName(a).localeCompare(languageCodeToName(b)); * 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);

View File

@@ -18,7 +18,7 @@ import {
import { import {
DefaultLanguage, DefaultLanguage,
languageCodeToName, languageCodeToName,
languageSortComparator, languageSpecialSortComparator,
toComparableLanguage, toComparableLanguage,
toComparableLanguages, toComparableLanguages,
toUniqueLanguageCodes, toUniqueLanguageCodes,
@@ -86,7 +86,7 @@ export function groupExtensionsByLanguage(extensions: TExtension[]): GroupedExte
return 1; return 1;
} }
return languageSortComparator(a, b); return languageSpecialSortComparator(a, b);
}); });
const groupedExtensionsSortedByLanguage = extensionsBySortedLanguage.map(([language, extensionsOfLanguage]) => [ const groupedExtensionsSortedByLanguage = extensionsBySortedLanguage.map(([language, extensionsOfLanguage]) => [
@@ -97,8 +97,9 @@ export function groupExtensionsByLanguage(extensions: TExtension[]): GroupedExte
return groupedExtensionsSortedByLanguage.filter(([, extensionsOfLanguage]) => !!extensionsOfLanguage.length); return groupedExtensionsSortedByLanguage.filter(([, extensionsOfLanguage]) => !!extensionsOfLanguage.length);
} }
export const getLanguagesFromExtensions = (extensions: TExtension[]): string[] => export const getLanguagesFromExtensions = (extensions: TExtension[]): string[] => [
[...new Set(extensions.map((extension) => extension.lang))].toSorted(languageSortComparator); ...new Set(extensions.map((extension) => extension.lang)),
];
export const filterExtensions = ( export const filterExtensions = (
extensions: TExtension[], extensions: TExtension[],

View File

@@ -15,7 +15,7 @@ import {
} from '@/modules/source/Source.types.ts'; } from '@/modules/source/Source.types.ts';
import { import {
DefaultLanguage, DefaultLanguage,
languageSortComparator, languageSpecialSortComparator,
toComparableLanguage, toComparableLanguage,
toComparableLanguages, toComparableLanguages,
toUniqueLanguageCodes, toUniqueLanguageCodes,
@@ -37,15 +37,15 @@ export class Sources {
} }
static getLanguages(sources: (SourceIdInfo & SourceLanguageInfo)[]): string[] { static getLanguages(sources: (SourceIdInfo & SourceLanguageInfo)[]): string[] {
return [...new Set(sources.map((source) => Sources.getLanguage(source)))].toSorted(languageSortComparator); return [...new Set(sources.map(Sources.getLanguage))];
} }
static groupByLanguage<Source extends SourceIdInfo & SourceLanguageInfo & SourceDisplayNameInfo>( static groupByLanguage<Source extends SourceIdInfo & SourceLanguageInfo & SourceDisplayNameInfo>(
sources: Source[], sources: Source[],
): Record<string, Source[]> { ): Record<string, Source[]> {
const sourcesByLanguage = Object.groupBy(sources, (source) => Sources.getLanguage(source)); const sourcesByLanguage = Object.groupBy(sources, Sources.getLanguage);
const sourcesBySortedLanguage = Object.entries(sourcesByLanguage).toSorted(([a], [b]) => const sourcesBySortedLanguage = Object.entries(sourcesByLanguage).toSorted(([a], [b]) =>
languageSortComparator(a, b), languageSpecialSortComparator(a, b),
); );
const sortedSourcesBySortedLanguage = sourcesBySortedLanguage.map(([language, sourcesOfLanguage]) => [ const sortedSourcesBySortedLanguage = sourcesBySortedLanguage.map(([language, sourcesOfLanguage]) => [
language, language,