export class LanguageCode { private language : string ; private normalizedLanguage : string ; constructor ( languageCodeStr ) { this . language = languageCodeStr ; this . normalizedLanguage = languageCodeStr . toLowerCase ( ) ; } matches ( other ) { return this . normalizedLanguage === other . normalizedLanguage ; } string ( ) { return this . language ; } split ( ) { return this . language . split ( '-' ) ; } } export class LanguageMatcher { constructor ( private supportedLanguages , private defaultLanguage = undefined ) { } getBestSupportedLanguage ( userLanguages ) { for ( const userLanguage of userLanguages ) { const parts = userLanguage . split ( ) ; while ( parts . length > 0 ) { const trimmedUserLanguage = new LanguageCode ( parts . join ( '-' ) ) ; const supportedLanguage = this . getSupportedLanguage ( trimmedUserLanguage ) ; if ( supportedLanguage ) { return supportedLanguage ; } parts . pop ( ) ; } } return this . defaultLanguage ; } private getSupportedLanguage ( userLanguage ) { for ( const supportedLanguage of this . supportedLanguages ) { const parts = supportedLanguage . split ( ) ; while ( parts . length > 0 ) { const trimmedSupportedLanguage = new LanguageCode ( parts . join ( '-' ) ) ; if ( userLanguage . matches ( trimmedSupportedLanguage ) ) { return supportedLanguage ; } parts . pop ( ) ; } } return undefined ; } } export function languageList ( languagesAsStr ) { return languagesAsStr . map ( l => new LanguageCode ( l ) ) ; } export function getBrowserLanguages ( ) { let languages = navigator . languages as string [ ] ; if ( ! languages || languages . length === 0 ) { languages = [ navigator . language ] ; } return languageList ( languages ) ; }