2023-07-06 21:29:36 +02:00
class Localization {
constructor ( ) {
Localization . defaultLocale = "en" ;
2023-09-18 20:34:26 +02:00
Localization . supportedLocales = [ "en" , "nb" , "ru" , "zh-CN" , "de" ] ;
2023-07-06 21:29:36 +02:00
Localization . translations = { } ;
2023-07-07 14:58:15 +02:00
Localization . defaultTranslations = { } ;
2023-07-06 21:29:36 +02:00
2023-08-30 14:57:40 +02:00
Localization . systemLocale = Localization . supportedOrDefault ( navigator . languages ) ;
2023-07-06 21:29:36 +02:00
2023-08-30 14:57:40 +02:00
let storedLanguageCode = localStorage . getItem ( "language-code" ) ;
Localization . initialLocale = storedLanguageCode && Localization . isSupported ( storedLanguageCode )
? storedLanguageCode
: Localization . systemLocale ;
Localization . setTranslation ( Localization . initialLocale )
2023-07-06 21:29:36 +02:00
. then ( _ => {
2023-08-30 14:57:40 +02:00
console . log ( "Initial translation successful." ) ;
2023-09-14 20:06:17 +02:00
Events . fire ( "initial-translation-loaded" ) ;
2023-08-30 14:57:40 +02:00
} ) ;
2023-07-06 21:29:36 +02:00
}
static isSupported ( locale ) {
return Localization . supportedLocales . indexOf ( locale ) > - 1 ;
}
static supportedOrDefault ( locales ) {
return locales . find ( Localization . isSupported ) || Localization . defaultLocale ;
}
2023-08-30 14:57:40 +02:00
static async setTranslation ( locale ) {
if ( ! locale ) locale = Localization . systemLocale ;
await Localization . setLocale ( locale )
await Localization . translatePage ( ) ;
console . log ( "Page successfully translated" ,
` System language: ${ Localization . systemLocale } ` ,
` Selected language: ${ locale } `
) ;
2023-09-14 20:06:17 +02:00
Events . fire ( "translation-loaded" ) ;
2023-08-30 14:57:40 +02:00
}
2023-07-06 21:29:36 +02:00
static async setLocale ( newLocale ) {
if ( newLocale === Localization . locale ) return false ;
2023-09-13 17:08:57 +02:00
2023-07-07 14:58:15 +02:00
Localization . defaultTranslations = await Localization . fetchTranslationsFor ( Localization . defaultLocale ) ;
2023-07-07 14:58:15 +02:00
2023-07-06 21:29:36 +02:00
const newTranslations = await Localization . fetchTranslationsFor ( newLocale ) ;
if ( ! newTranslations ) return false ;
Localization . locale = newLocale ;
Localization . translations = newTranslations ;
2023-08-30 14:57:40 +02:00
}
2023-07-06 21:29:36 +02:00
2023-08-30 14:57:40 +02:00
static getLocale ( ) {
return Localization . locale ;
}
static isSystemLocale ( ) {
return ! localStorage . getItem ( 'language-code' ) ;
2023-07-06 21:29:36 +02:00
}
static async fetchTranslationsFor ( newLocale ) {
const response = await fetch ( ` lang/ ${ newLocale } .json ` )
if ( response . redirected === true || response . status !== 200 ) return false ;
return await response . json ( ) ;
}
2023-08-30 14:57:40 +02:00
static async translatePage ( ) {
2023-07-06 21:29:36 +02:00
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-08-30 14:57:40 +02:00
if ( attr . startsWith ( "data-" ) ) {
let dataAttr = attr . substring ( 5 ) ;
element . dataset . dataAttr = Localization . getTranslation ( key , attr ) ;
} {
element . setAttribute ( attr , Localization . getTranslation ( key , attr ) ) ;
}
2023-07-06 21:29:36 +02:00
}
}
}
2023-09-13 17:08:57 +02:00
static getTranslation ( key , attr = null , 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
2023-08-29 02:32:54 +02:00
let translation ;
try {
for ( let i = 0 ; i < keys . length - 1 ; i ++ ) {
translationCandidates = translationCandidates [ keys [ i ] ]
}
2023-07-06 21:29:36 +02:00
2023-08-29 02:32:54 +02:00
let lastKey = keys [ keys . length - 1 ] ;
2023-07-07 14:58:15 +02:00
2023-08-29 02:32:54 +02:00
if ( attr ) lastKey += "_" + attr ;
2023-07-06 21:29:36 +02:00
2023-08-29 02:32:54 +02:00
translation = translationCandidates [ lastKey ] ;
2023-07-06 21:29:36 +02:00
2023-08-29 02:32:54 +02:00
for ( let j in data ) {
translation = translation . replace ( ` {{ ${ j } }} ` , data [ j ] ) ;
}
} catch ( e ) {
translation = "" ;
2023-07-07 14:58:15 +02:00
}
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 ;
}
}