Skip to content

Instantly share code, notes, and snippets.

@eligrey
Last active April 12, 2022 05:10
Show Gist options
  • Save eligrey/c15d8ec3e500dcfc3a5ec0256ce07c2b to your computer and use it in GitHub Desktop.
Save eligrey/c15d8ec3e500dcfc3a5ec0256ce07c2b to your computer and use it in GitHub Desktop.
Simple language matcher
import { matchLanguages, getNearestSupportedLanguage } from './match-languages';
const supportedLanguages = ['en-GB', 'fr'];
console.log('navigator.languages: ', navigator.languages);
const matches = matchLanguages(navigator.languages, supportedLanguages);
console.log('preferred language matches:', matches);
const nearest = getNearestSupportedLanguage(matches, supportedLanguages);
console.log('nearest matching supported language:', nearest);
/**
* Get all potential sub-languages from a given ISO 639-1 language code
*
* @param langCode - ISO 639-1 format language code
* @returns Array of potential sub-languages, sorted by most to least specific
*/
const getAllSubLanguages = (langCode: string): string[] =>
langCode
.toLowerCase()
.split('-')
.flatMap((_, i, tags) => tags.slice(0, i + 1).join('-'))
.reverse();
/**
* Match preferred language list against a supported languages list
*
* @param preferred - Sorted language list in order of most preferable to least preferable
* @param supported - List of supported languages to match from
* @returns Preferred languages (including sub-language matches) that match supported languages list
*/
export const matchLanguages = (
preferred: string[],
supported: string[],
): string[] => {
const matches = new Set<string>();
const allSupportedLanguages = supported.flatMap(getAllSubLanguages);
return preferred.flatMap(getAllSubLanguages).filter((language) => {
if (!allSupportedLanguages.includes(language)) {
return false;
}
const unique = !matches.has(language);
if (unique) {
matches.add(language);
}
return unique;
});
};
/**
* Get nearest matching language from a list of supported languages
*
* @param preferred - Sorted language list in order of most preferable to least preferable
* @param supported - List of supported languages to match from
* @returns Nearest supported language, sorted by preferred language list
*/
export const getNearestSupportedLanguage = (
preferred: string[],
supported: string[],
): string | undefined =>
supported.find((language) =>
getAllSubLanguages(language).some((lang) =>
preferred.some((preferredLang) =>
preferredLang.toLowerCase() === lang
)
),
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment