2023-07-06 21:29:36 +02:00
class Localization {
constructor ( ) {
Localization . defaultLocale = "en" ;
Localization . supportedLocales = [ "en" ] ;
Localization . translations = { } ;
2023-07-07 14:58:15 +02:00
Localization . defaultTranslations = { } ;
2023-07-06 21:29:36 +02:00
const initialLocale = Localization . supportedOrDefault ( Localization . browserLocales ( ) ) ;
Localization . setLocale ( initialLocale )
. then ( _ => {
Localization . translatePage ( ) ;
} )
}
static isSupported ( locale ) {
return Localization . supportedLocales . indexOf ( locale ) > - 1 ;
}
static supportedOrDefault ( locales ) {
return locales . find ( Localization . isSupported ) || Localization . defaultLocale ;
}
static browserLocales ( ) {
return navigator . languages . map ( locale =>
locale . split ( "-" ) [ 0 ]
) ;
}
static async setLocale ( newLocale ) {
if ( newLocale === Localization . locale ) return false ;
2023-07-07 14:58:15 +02:00
const firstTranslation = ! Localization . locale
2023-07-06 21:29:36 +02:00
2023-07-07 14:58:15 +02:00
Localization . defaultTranslations = await Localization . fetchTranslationsFor ( Localization . defaultLocale ) ;
2023-07-06 21:29:36 +02:00
const newTranslations = await Localization . fetchTranslationsFor ( newLocale ) ;
if ( ! newTranslations ) return false ;
Localization . locale = newLocale ;
Localization . translations = newTranslations ;
if ( firstTranslation ) {
Events . fire ( "translation-loaded" ) ;
}
}
static async fetchTranslationsFor ( newLocale ) {
const response = await fetch ( ` lang/ ${ newLocale } .json ` )
if ( response . redirected === true || response . status !== 200 ) return false ;
return await response . json ( ) ;
}
static translatePage ( ) {
document
. querySelectorAll ( "[data-i18n-key]" )
. forEach ( element => Localization . translateElement ( element ) ) ;
}
static async translateElement ( element ) {
const key = element . getAttribute ( "data-i18n-key" ) ;
const attrs = element . getAttribute ( "data-i18n-attrs" ) . split ( " " ) ;
for ( let i in attrs ) {
let attr = attrs [ i ] ;
if ( attr === "text" ) {
2023-07-07 14:58:15 +02:00
element . innerText = Localization . getTranslation ( key ) ;
2023-07-06 21:29:36 +02:00
} else {
2023-07-07 14:58:15 +02:00
element . attr = Localization . getTranslation ( key , attr ) ;
2023-07-06 21:29:36 +02:00
}
}
}
2023-07-07 14:58:15 +02:00
static getTranslation ( key , attr , data , useDefault = false ) {
2023-07-06 21:29:36 +02:00
const keys = key . split ( "." ) ;
2023-07-07 14:58:15 +02:00
let translationCandidates = useDefault
? Localization . defaultTranslations
: Localization . translations ;
2023-07-06 21:29:36 +02:00
for ( let i = 0 ; i < keys . length - 1 ; i ++ ) {
translationCandidates = translationCandidates [ keys [ i ] ]
}
let lastKey = keys [ keys . length - 1 ] ;
if ( attr ) lastKey += "_" + attr ;
let translation = translationCandidates [ lastKey ] ;
2023-07-07 14:58:15 +02:00
for ( let j in data ) {
translation = translation . replace ( ` {{ ${ j } }} ` , data [ j ] ) ;
}
if ( ! translation ) {
if ( ! useDefault ) {
translation = this . getTranslation ( key , attr , data , true ) ;
console . warn ( ` Missing translation entry for your language ${ Localization . locale . toUpperCase ( ) } . Using ${ Localization . defaultLocale . toUpperCase ( ) } instead. ` , key , attr ) ;
console . warn ( "Help translating PairDrop: https://hosted.weblate.org/projects/pairdrop/pairdrop-spa/" ) ;
} else {
console . warn ( "Missing translation in default language:" , key , attr ) ;
}
2023-07-06 21:29:36 +02:00
}
return Localization . escapeHTML ( translation ) ;
}
static escapeHTML ( unsafeText ) {
let div = document . createElement ( 'div' ) ;
div . innerText = unsafeText ;
return div . innerHTML ;
}
}