frontend: add OXC lint/format setup and apply semicolon fixes
This commit is contained in:
+309
-313
@@ -1,331 +1,327 @@
|
||||
import * as flagSvgs from 'country-flag-icons/string/3x2';
|
||||
import * as flagSvgs from "country-flag-icons/string/3x2"
|
||||
|
||||
export interface LanguageFlagEntry {
|
||||
countryCode: string;
|
||||
svg: string;
|
||||
sourceCodes: string[];
|
||||
countryCode: string
|
||||
svg: string
|
||||
sourceCodes: string[]
|
||||
}
|
||||
|
||||
const FLAGS = flagSvgs as Record<string, string>;
|
||||
const FLAGS = flagSvgs as Record<string, string>
|
||||
|
||||
const LANGUAGE_TO_COUNTRY: Record<string, string> = {
|
||||
// English
|
||||
en: 'GB',
|
||||
eng: 'GB',
|
||||
en: "GB",
|
||||
eng: "GB",
|
||||
|
||||
// Spanish (including LATAM variants collapsed to Spain flag)
|
||||
es: 'ES',
|
||||
spa: 'ES',
|
||||
esl: 'ES',
|
||||
spl: 'ES',
|
||||
'es-es': 'ES',
|
||||
'es-419': 'ES',
|
||||
'spa-la': 'ES',
|
||||
es: "ES",
|
||||
spa: "ES",
|
||||
esl: "ES",
|
||||
spl: "ES",
|
||||
"es-es": "ES",
|
||||
"es-419": "ES",
|
||||
"spa-la": "ES",
|
||||
|
||||
// Portuguese
|
||||
pt: 'PT',
|
||||
por: 'PT',
|
||||
'pt-pt': 'PT',
|
||||
'pt-br': 'BR',
|
||||
pt: "PT",
|
||||
por: "PT",
|
||||
"pt-pt": "PT",
|
||||
"pt-br": "BR",
|
||||
|
||||
// Major European languages
|
||||
fr: 'FR',
|
||||
fra: 'FR',
|
||||
fre: 'FR',
|
||||
de: 'DE',
|
||||
deu: 'DE',
|
||||
ger: 'DE',
|
||||
it: 'IT',
|
||||
ita: 'IT',
|
||||
nl: 'NL',
|
||||
nld: 'NL',
|
||||
dut: 'NL',
|
||||
sv: 'SE',
|
||||
swe: 'SE',
|
||||
no: 'NO',
|
||||
nor: 'NO',
|
||||
da: 'DK',
|
||||
dan: 'DK',
|
||||
fi: 'FI',
|
||||
fin: 'FI',
|
||||
pl: 'PL',
|
||||
पोल: 'PL',
|
||||
cs: 'CZ',
|
||||
ces: 'CZ',
|
||||
cze: 'CZ',
|
||||
hu: 'HU',
|
||||
hun: 'HU',
|
||||
ro: 'RO',
|
||||
ron: 'RO',
|
||||
rum: 'RO',
|
||||
el: 'GR',
|
||||
gre: 'GR',
|
||||
ell: 'GR',
|
||||
tr: 'TR',
|
||||
tur: 'TR',
|
||||
fr: "FR",
|
||||
fra: "FR",
|
||||
fre: "FR",
|
||||
de: "DE",
|
||||
deu: "DE",
|
||||
ger: "DE",
|
||||
it: "IT",
|
||||
ita: "IT",
|
||||
nl: "NL",
|
||||
nld: "NL",
|
||||
dut: "NL",
|
||||
sv: "SE",
|
||||
swe: "SE",
|
||||
no: "NO",
|
||||
nor: "NO",
|
||||
da: "DK",
|
||||
dan: "DK",
|
||||
fi: "FI",
|
||||
fin: "FI",
|
||||
pl: "PL",
|
||||
पोल: "PL",
|
||||
cs: "CZ",
|
||||
ces: "CZ",
|
||||
cze: "CZ",
|
||||
hu: "HU",
|
||||
hun: "HU",
|
||||
ro: "RO",
|
||||
ron: "RO",
|
||||
rum: "RO",
|
||||
el: "GR",
|
||||
gre: "GR",
|
||||
ell: "GR",
|
||||
tr: "TR",
|
||||
tur: "TR",
|
||||
|
||||
// Slavic / Eurasian
|
||||
ru: 'RU',
|
||||
rus: 'RU',
|
||||
uk: 'UA',
|
||||
ukr: 'UA',
|
||||
bg: 'BG',
|
||||
bul: 'BG',
|
||||
sr: 'RS',
|
||||
srp: 'RS',
|
||||
hr: 'HR',
|
||||
hrv: 'HR',
|
||||
sl: 'SI',
|
||||
slv: 'SI',
|
||||
sk: 'SK',
|
||||
slk: 'SK',
|
||||
slo: 'SK',
|
||||
ru: "RU",
|
||||
rus: "RU",
|
||||
uk: "UA",
|
||||
ukr: "UA",
|
||||
bg: "BG",
|
||||
bul: "BG",
|
||||
sr: "RS",
|
||||
srp: "RS",
|
||||
hr: "HR",
|
||||
hrv: "HR",
|
||||
sl: "SI",
|
||||
slv: "SI",
|
||||
sk: "SK",
|
||||
slk: "SK",
|
||||
slo: "SK",
|
||||
|
||||
// East / South / SE Asia
|
||||
ja: 'JP',
|
||||
jpn: 'JP',
|
||||
ko: 'KR',
|
||||
kor: 'KR',
|
||||
zh: 'CN',
|
||||
zho: 'CN',
|
||||
chi: 'CN',
|
||||
yue: 'HK',
|
||||
th: 'TH',
|
||||
tha: 'TH',
|
||||
vi: 'VN',
|
||||
vie: 'VN',
|
||||
id: 'ID',
|
||||
ind: 'ID',
|
||||
ms: 'MY',
|
||||
msa: 'MY',
|
||||
may: 'MY',
|
||||
hi: 'IN',
|
||||
hin: 'IN',
|
||||
ja: "JP",
|
||||
jpn: "JP",
|
||||
ko: "KR",
|
||||
kor: "KR",
|
||||
zh: "CN",
|
||||
zho: "CN",
|
||||
chi: "CN",
|
||||
yue: "HK",
|
||||
th: "TH",
|
||||
tha: "TH",
|
||||
vi: "VN",
|
||||
vie: "VN",
|
||||
id: "ID",
|
||||
ind: "ID",
|
||||
ms: "MY",
|
||||
msa: "MY",
|
||||
may: "MY",
|
||||
hi: "IN",
|
||||
hin: "IN",
|
||||
|
||||
// Middle East / Africa
|
||||
ar: 'SA',
|
||||
ara: 'SA',
|
||||
he: 'IL',
|
||||
heb: 'IL',
|
||||
fa: 'IR',
|
||||
fas: 'IR',
|
||||
per: 'IR',
|
||||
ur: 'PK',
|
||||
urd: 'PK',
|
||||
sw: 'TZ',
|
||||
swa: 'TZ',
|
||||
ar: "SA",
|
||||
ara: "SA",
|
||||
he: "IL",
|
||||
heb: "IL",
|
||||
fa: "IR",
|
||||
fas: "IR",
|
||||
per: "IR",
|
||||
ur: "PK",
|
||||
urd: "PK",
|
||||
sw: "TZ",
|
||||
swa: "TZ",
|
||||
|
||||
// Other common
|
||||
ca: 'ES',
|
||||
cat: 'ES',
|
||||
eu: 'ES',
|
||||
baq: 'ES',
|
||||
eus: 'ES',
|
||||
};
|
||||
ca: "ES",
|
||||
cat: "ES",
|
||||
eu: "ES",
|
||||
baq: "ES",
|
||||
eus: "ES",
|
||||
}
|
||||
|
||||
function normalizeLanguageCode(code: string): string {
|
||||
return code.trim().toLowerCase().replace('_', '-');
|
||||
return code.trim().toLowerCase().replace("_", "-")
|
||||
}
|
||||
|
||||
function normalizeLanguageName(name: string): string {
|
||||
return name
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(/[_-]+/g, ' ')
|
||||
.replace(/\s+/g, ' ');
|
||||
return name.trim().toLowerCase().replace(/[_-]+/g, " ").replace(/\s+/g, " ")
|
||||
}
|
||||
|
||||
let _browserLanguagePreferences: string[] | null = null;
|
||||
let _browserPreferenceRanks: Map<string, number> | null = null;
|
||||
let _browserLanguagePreferences: string[] | null = null
|
||||
let _browserPreferenceRanks: Map<string, number> | null = null
|
||||
|
||||
const LANGUAGE_NAME_TO_CODE: Record<string, string> = {
|
||||
english: 'en',
|
||||
spanish: 'es',
|
||||
portuguese: 'pt',
|
||||
french: 'fr',
|
||||
german: 'de',
|
||||
italian: 'it',
|
||||
dutch: 'nl',
|
||||
swedish: 'sv',
|
||||
norwegian: 'no',
|
||||
danish: 'da',
|
||||
finnish: 'fi',
|
||||
polish: 'pl',
|
||||
czech: 'cs',
|
||||
hungarian: 'hu',
|
||||
romanian: 'ro',
|
||||
greek: 'el',
|
||||
turkish: 'tr',
|
||||
russian: 'ru',
|
||||
ukrainian: 'uk',
|
||||
bulgarian: 'bg',
|
||||
serbian: 'sr',
|
||||
croatian: 'hr',
|
||||
slovenian: 'sl',
|
||||
slovak: 'sk',
|
||||
japanese: 'ja',
|
||||
korean: 'ko',
|
||||
chinese: 'zh',
|
||||
cantonese: 'yue',
|
||||
thai: 'th',
|
||||
vietnamese: 'vi',
|
||||
indonesian: 'id',
|
||||
malay: 'ms',
|
||||
hindi: 'hi',
|
||||
arabic: 'ar',
|
||||
hebrew: 'he',
|
||||
persian: 'fa',
|
||||
urdu: 'ur',
|
||||
swahili: 'sw',
|
||||
catalan: 'ca',
|
||||
basque: 'eu',
|
||||
};
|
||||
english: "en",
|
||||
spanish: "es",
|
||||
portuguese: "pt",
|
||||
french: "fr",
|
||||
german: "de",
|
||||
italian: "it",
|
||||
dutch: "nl",
|
||||
swedish: "sv",
|
||||
norwegian: "no",
|
||||
danish: "da",
|
||||
finnish: "fi",
|
||||
polish: "pl",
|
||||
czech: "cs",
|
||||
hungarian: "hu",
|
||||
romanian: "ro",
|
||||
greek: "el",
|
||||
turkish: "tr",
|
||||
russian: "ru",
|
||||
ukrainian: "uk",
|
||||
bulgarian: "bg",
|
||||
serbian: "sr",
|
||||
croatian: "hr",
|
||||
slovenian: "sl",
|
||||
slovak: "sk",
|
||||
japanese: "ja",
|
||||
korean: "ko",
|
||||
chinese: "zh",
|
||||
cantonese: "yue",
|
||||
thai: "th",
|
||||
vietnamese: "vi",
|
||||
indonesian: "id",
|
||||
malay: "ms",
|
||||
hindi: "hi",
|
||||
arabic: "ar",
|
||||
hebrew: "he",
|
||||
persian: "fa",
|
||||
urdu: "ur",
|
||||
swahili: "sw",
|
||||
catalan: "ca",
|
||||
basque: "eu",
|
||||
}
|
||||
|
||||
function getBrowserLanguagePreferences(): string[] {
|
||||
if (_browserLanguagePreferences) return _browserLanguagePreferences;
|
||||
if (_browserLanguagePreferences) return _browserLanguagePreferences
|
||||
|
||||
const preferences: string[] = [];
|
||||
if (typeof navigator !== 'undefined') {
|
||||
const preferences: string[] = []
|
||||
if (typeof navigator !== "undefined") {
|
||||
if (Array.isArray(navigator.languages)) {
|
||||
for (const lang of navigator.languages) {
|
||||
if (typeof lang === 'string' && lang.trim()) {
|
||||
preferences.push(normalizeLanguageCode(lang));
|
||||
if (typeof lang === "string" && lang.trim()) {
|
||||
preferences.push(normalizeLanguageCode(lang))
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof navigator.language === 'string' && navigator.language.trim()) {
|
||||
preferences.push(normalizeLanguageCode(navigator.language));
|
||||
if (typeof navigator.language === "string" && navigator.language.trim()) {
|
||||
preferences.push(normalizeLanguageCode(navigator.language))
|
||||
}
|
||||
}
|
||||
|
||||
const deduped = Array.from(new Set(preferences));
|
||||
_browserLanguagePreferences = deduped;
|
||||
return deduped;
|
||||
const deduped = Array.from(new Set(preferences))
|
||||
_browserLanguagePreferences = deduped
|
||||
return deduped
|
||||
}
|
||||
|
||||
function getBrowserPreferenceRanks(): Map<string, number> {
|
||||
if (_browserPreferenceRanks) return _browserPreferenceRanks;
|
||||
if (_browserPreferenceRanks) return _browserPreferenceRanks
|
||||
|
||||
const preferences = getBrowserLanguagePreferences();
|
||||
const ranks = new Map<string, number>();
|
||||
const display = new Intl.DisplayNames(['en'], { type: 'language' });
|
||||
const preferences = getBrowserLanguagePreferences()
|
||||
const ranks = new Map<string, number>()
|
||||
const display = new Intl.DisplayNames(["en"], { type: "language" })
|
||||
|
||||
for (const [index, pref] of preferences.entries()) {
|
||||
const base = pref.split('-', 1)[0];
|
||||
if (!ranks.has(pref)) ranks.set(pref, index);
|
||||
if (!ranks.has(base)) ranks.set(base, index);
|
||||
const base = pref.split("-", 1)[0]
|
||||
if (!ranks.has(pref)) ranks.set(pref, index)
|
||||
if (!ranks.has(base)) ranks.set(base, index)
|
||||
|
||||
const prefName = display.of(pref);
|
||||
const prefName = display.of(pref)
|
||||
if (prefName) {
|
||||
const key = normalizeLanguageName(prefName);
|
||||
if (!ranks.has(key)) ranks.set(key, index);
|
||||
const key = normalizeLanguageName(prefName)
|
||||
if (!ranks.has(key)) ranks.set(key, index)
|
||||
}
|
||||
const baseName = display.of(base);
|
||||
const baseName = display.of(base)
|
||||
if (baseName) {
|
||||
const key = normalizeLanguageName(baseName);
|
||||
if (!ranks.has(key)) ranks.set(key, index);
|
||||
const key = normalizeLanguageName(baseName)
|
||||
if (!ranks.has(key)) ranks.set(key, index)
|
||||
}
|
||||
}
|
||||
|
||||
_browserPreferenceRanks = ranks;
|
||||
return ranks;
|
||||
_browserPreferenceRanks = ranks
|
||||
return ranks
|
||||
}
|
||||
|
||||
function resolveLanguageIdentifier(value: string): string {
|
||||
const normalized = normalizeLanguageCode(value);
|
||||
const normalized = normalizeLanguageCode(value)
|
||||
if (/^[a-z]{2,3}(?:-[a-z0-9]{2,})?$/i.test(normalized)) {
|
||||
return normalized;
|
||||
return normalized
|
||||
}
|
||||
|
||||
const nameKey = normalizeLanguageName(value);
|
||||
const byName = LANGUAGE_NAME_TO_CODE[nameKey];
|
||||
if (byName) return byName;
|
||||
const nameKey = normalizeLanguageName(value)
|
||||
const byName = LANGUAGE_NAME_TO_CODE[nameKey]
|
||||
if (byName) return byName
|
||||
|
||||
return normalized;
|
||||
return normalized
|
||||
}
|
||||
|
||||
function getPreferenceRank(value: string, preferenceRanks: Map<string, number>): number {
|
||||
const normalized = resolveLanguageIdentifier(value);
|
||||
const exact = preferenceRanks.get(normalized);
|
||||
if (exact !== undefined) return exact;
|
||||
const normalized = resolveLanguageIdentifier(value)
|
||||
const exact = preferenceRanks.get(normalized)
|
||||
if (exact !== undefined) return exact
|
||||
|
||||
const base = normalized.split('-', 1)[0];
|
||||
const baseRank = preferenceRanks.get(base);
|
||||
if (baseRank !== undefined) return baseRank;
|
||||
const base = normalized.split("-", 1)[0]
|
||||
const baseRank = preferenceRanks.get(base)
|
||||
if (baseRank !== undefined) return baseRank
|
||||
|
||||
const nameKey = normalizeLanguageName(toLanguageName(normalized));
|
||||
const nameRank = preferenceRanks.get(nameKey);
|
||||
if (nameRank !== undefined) return nameRank;
|
||||
const nameKey = normalizeLanguageName(toLanguageName(normalized))
|
||||
const nameRank = preferenceRanks.get(nameKey)
|
||||
if (nameRank !== undefined) return nameRank
|
||||
|
||||
const rawNameRank = preferenceRanks.get(normalizeLanguageName(value));
|
||||
if (rawNameRank !== undefined) return rawNameRank;
|
||||
const rawNameRank = preferenceRanks.get(normalizeLanguageName(value))
|
||||
if (rawNameRank !== undefined) return rawNameRank
|
||||
|
||||
return Number.MAX_SAFE_INTEGER;
|
||||
return Number.MAX_SAFE_INTEGER
|
||||
}
|
||||
|
||||
export function mapLanguageToCountry(code: string): string | null {
|
||||
const normalized = resolveLanguageIdentifier(code);
|
||||
const normalized = resolveLanguageIdentifier(code)
|
||||
|
||||
const direct = LANGUAGE_TO_COUNTRY[normalized];
|
||||
if (direct) return direct;
|
||||
const direct = LANGUAGE_TO_COUNTRY[normalized]
|
||||
if (direct) return direct
|
||||
|
||||
// region-tag style code like en-us / pt-br / es-mx
|
||||
const hyphenParts = normalized.split('-');
|
||||
const hyphenParts = normalized.split("-")
|
||||
if (hyphenParts.length >= 2) {
|
||||
const region = hyphenParts[hyphenParts.length - 1];
|
||||
const region = hyphenParts[hyphenParts.length - 1]
|
||||
if (/^[a-z]{2}$/i.test(region)) {
|
||||
return region.toUpperCase();
|
||||
return region.toUpperCase()
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
export function buildLanguageFlags(codes: string[] | null | undefined): {
|
||||
flags: LanguageFlagEntry[];
|
||||
unmappedCodes: string[];
|
||||
flags: LanguageFlagEntry[]
|
||||
unmappedCodes: string[]
|
||||
} {
|
||||
if (!codes || codes.length === 0) {
|
||||
return { flags: [], unmappedCodes: [] };
|
||||
return { flags: [], unmappedCodes: [] }
|
||||
}
|
||||
|
||||
const byCountry = new Map<string, string[]>();
|
||||
const unmapped: string[] = [];
|
||||
const seenUnmapped = new Set<string>();
|
||||
const preferenceRanks = getBrowserPreferenceRanks();
|
||||
const byCountry = new Map<string, string[]>()
|
||||
const unmapped: string[] = []
|
||||
const seenUnmapped = new Set<string>()
|
||||
const preferenceRanks = getBrowserPreferenceRanks()
|
||||
|
||||
const ordered = codes
|
||||
.map((raw, index) => ({ raw, index }))
|
||||
.filter((v) => Boolean(v.raw && String(v.raw).trim()))
|
||||
.sort((a, b) => {
|
||||
const aRank = getPreferenceRank(String(a.raw), preferenceRanks);
|
||||
const bRank = getPreferenceRank(String(b.raw), preferenceRanks);
|
||||
if (aRank !== bRank) return aRank - bRank;
|
||||
return a.index - b.index;
|
||||
});
|
||||
const aRank = getPreferenceRank(String(a.raw), preferenceRanks)
|
||||
const bRank = getPreferenceRank(String(b.raw), preferenceRanks)
|
||||
if (aRank !== bRank) return aRank - bRank
|
||||
return a.index - b.index
|
||||
})
|
||||
|
||||
for (const { raw } of ordered) {
|
||||
if (!raw) continue;
|
||||
const countryCode = mapLanguageToCountry(raw);
|
||||
if (!raw) continue
|
||||
const countryCode = mapLanguageToCountry(raw)
|
||||
if (!countryCode) {
|
||||
const upper = raw.toUpperCase();
|
||||
const upper = raw.toUpperCase()
|
||||
if (!seenUnmapped.has(upper)) {
|
||||
seenUnmapped.add(upper);
|
||||
unmapped.push(upper);
|
||||
seenUnmapped.add(upper)
|
||||
unmapped.push(upper)
|
||||
}
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
if (!FLAGS[countryCode]) {
|
||||
const upper = raw.toUpperCase();
|
||||
const upper = raw.toUpperCase()
|
||||
if (!seenUnmapped.has(upper)) {
|
||||
seenUnmapped.add(upper);
|
||||
unmapped.push(upper);
|
||||
seenUnmapped.add(upper)
|
||||
unmapped.push(upper)
|
||||
}
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
const existing = byCountry.get(countryCode) || [];
|
||||
existing.push(raw);
|
||||
byCountry.set(countryCode, existing);
|
||||
const existing = byCountry.get(countryCode) || []
|
||||
existing.push(raw)
|
||||
byCountry.set(countryCode, existing)
|
||||
}
|
||||
|
||||
const flags: LanguageFlagEntry[] = Array.from(byCountry.entries()).map(
|
||||
@@ -333,114 +329,114 @@ export function buildLanguageFlags(codes: string[] | null | undefined): {
|
||||
countryCode,
|
||||
svg: FLAGS[countryCode],
|
||||
sourceCodes,
|
||||
})
|
||||
);
|
||||
}),
|
||||
)
|
||||
|
||||
return {
|
||||
flags,
|
||||
unmappedCodes: unmapped,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const LANGUAGE_NAME_OVERRIDES: Record<string, string> = {
|
||||
eng: 'English',
|
||||
spa: 'Spanish',
|
||||
'spa-la': 'Spanish',
|
||||
esl: 'Spanish',
|
||||
spl: 'Spanish',
|
||||
por: 'Portuguese',
|
||||
fre: 'French',
|
||||
fra: 'French',
|
||||
ger: 'German',
|
||||
deu: 'German',
|
||||
ita: 'Italian',
|
||||
nld: 'Dutch',
|
||||
dut: 'Dutch',
|
||||
swe: 'Swedish',
|
||||
nor: 'Norwegian',
|
||||
dan: 'Danish',
|
||||
fin: 'Finnish',
|
||||
pol: 'Polish',
|
||||
ces: 'Czech',
|
||||
cze: 'Czech',
|
||||
hun: 'Hungarian',
|
||||
ron: 'Romanian',
|
||||
rum: 'Romanian',
|
||||
ell: 'Greek',
|
||||
gre: 'Greek',
|
||||
tur: 'Turkish',
|
||||
rus: 'Russian',
|
||||
ukr: 'Ukrainian',
|
||||
bul: 'Bulgarian',
|
||||
srp: 'Serbian',
|
||||
hrv: 'Croatian',
|
||||
slv: 'Slovenian',
|
||||
slk: 'Slovak',
|
||||
slo: 'Slovak',
|
||||
jpn: 'Japanese',
|
||||
kor: 'Korean',
|
||||
zho: 'Chinese',
|
||||
chi: 'Chinese',
|
||||
yue: 'Cantonese',
|
||||
tha: 'Thai',
|
||||
vie: 'Vietnamese',
|
||||
ind: 'Indonesian',
|
||||
msa: 'Malay',
|
||||
may: 'Malay',
|
||||
hin: 'Hindi',
|
||||
ara: 'Arabic',
|
||||
heb: 'Hebrew',
|
||||
fas: 'Persian',
|
||||
per: 'Persian',
|
||||
urd: 'Urdu',
|
||||
swa: 'Swahili',
|
||||
cat: 'Catalan',
|
||||
eus: 'Basque',
|
||||
baq: 'Basque',
|
||||
};
|
||||
eng: "English",
|
||||
spa: "Spanish",
|
||||
"spa-la": "Spanish",
|
||||
esl: "Spanish",
|
||||
spl: "Spanish",
|
||||
por: "Portuguese",
|
||||
fre: "French",
|
||||
fra: "French",
|
||||
ger: "German",
|
||||
deu: "German",
|
||||
ita: "Italian",
|
||||
nld: "Dutch",
|
||||
dut: "Dutch",
|
||||
swe: "Swedish",
|
||||
nor: "Norwegian",
|
||||
dan: "Danish",
|
||||
fin: "Finnish",
|
||||
pol: "Polish",
|
||||
ces: "Czech",
|
||||
cze: "Czech",
|
||||
hun: "Hungarian",
|
||||
ron: "Romanian",
|
||||
rum: "Romanian",
|
||||
ell: "Greek",
|
||||
gre: "Greek",
|
||||
tur: "Turkish",
|
||||
rus: "Russian",
|
||||
ukr: "Ukrainian",
|
||||
bul: "Bulgarian",
|
||||
srp: "Serbian",
|
||||
hrv: "Croatian",
|
||||
slv: "Slovenian",
|
||||
slk: "Slovak",
|
||||
slo: "Slovak",
|
||||
jpn: "Japanese",
|
||||
kor: "Korean",
|
||||
zho: "Chinese",
|
||||
chi: "Chinese",
|
||||
yue: "Cantonese",
|
||||
tha: "Thai",
|
||||
vie: "Vietnamese",
|
||||
ind: "Indonesian",
|
||||
msa: "Malay",
|
||||
may: "Malay",
|
||||
hin: "Hindi",
|
||||
ara: "Arabic",
|
||||
heb: "Hebrew",
|
||||
fas: "Persian",
|
||||
per: "Persian",
|
||||
urd: "Urdu",
|
||||
swa: "Swahili",
|
||||
cat: "Catalan",
|
||||
eus: "Basque",
|
||||
baq: "Basque",
|
||||
}
|
||||
|
||||
function toLanguageName(code: string): string {
|
||||
const normalized = normalizeLanguageCode(code);
|
||||
const override = LANGUAGE_NAME_OVERRIDES[normalized];
|
||||
if (override) return override;
|
||||
const normalized = normalizeLanguageCode(code)
|
||||
const override = LANGUAGE_NAME_OVERRIDES[normalized]
|
||||
if (override) return override
|
||||
|
||||
const display = new Intl.DisplayNames(['en'], { type: 'language' });
|
||||
const candidate = display.of(normalized);
|
||||
if (candidate) return candidate;
|
||||
const display = new Intl.DisplayNames(["en"], { type: "language" })
|
||||
const candidate = display.of(normalized)
|
||||
if (candidate) return candidate
|
||||
|
||||
const base = normalized.split('-', 1)[0];
|
||||
const baseOverride = LANGUAGE_NAME_OVERRIDES[base];
|
||||
if (baseOverride) return baseOverride;
|
||||
const baseCandidate = display.of(base);
|
||||
if (baseCandidate) return baseCandidate;
|
||||
const base = normalized.split("-", 1)[0]
|
||||
const baseOverride = LANGUAGE_NAME_OVERRIDES[base]
|
||||
if (baseOverride) return baseOverride
|
||||
const baseCandidate = display.of(base)
|
||||
if (baseCandidate) return baseCandidate
|
||||
|
||||
return code.toUpperCase();
|
||||
return code.toUpperCase()
|
||||
}
|
||||
|
||||
function summarizeLanguageCodes(codes: string[] | null | undefined): string {
|
||||
if (!codes || codes.length === 0) return '';
|
||||
const names: string[] = [];
|
||||
const seen = new Set<string>();
|
||||
if (!codes || codes.length === 0) return ""
|
||||
const names: string[] = []
|
||||
const seen = new Set<string>()
|
||||
|
||||
for (const raw of codes) {
|
||||
if (!raw) continue;
|
||||
const name = toLanguageName(raw).trim();
|
||||
if (!name) continue;
|
||||
const key = name.toLowerCase();
|
||||
if (seen.has(key)) continue;
|
||||
seen.add(key);
|
||||
names.push(name);
|
||||
if (!raw) continue
|
||||
const name = toLanguageName(raw).trim()
|
||||
if (!name) continue
|
||||
const key = name.toLowerCase()
|
||||
if (seen.has(key)) continue
|
||||
seen.add(key)
|
||||
names.push(name)
|
||||
}
|
||||
|
||||
return names.join(', ');
|
||||
return names.join(", ")
|
||||
}
|
||||
|
||||
export function formatAudioSubtitleSummary(
|
||||
audioCodes: string[] | null | undefined,
|
||||
subtitleCodes: string[] | null | undefined
|
||||
subtitleCodes: string[] | null | undefined,
|
||||
): string {
|
||||
const audio = summarizeLanguageCodes(audioCodes);
|
||||
const subs = summarizeLanguageCodes(subtitleCodes);
|
||||
if (audio && subs) return `${audio} / ${subs}`;
|
||||
return audio || subs;
|
||||
const audio = summarizeLanguageCodes(audioCodes)
|
||||
const subs = summarizeLanguageCodes(subtitleCodes)
|
||||
if (audio && subs) return `${audio} / ${subs}`
|
||||
return audio || subs
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user