2020-11-06 01:58:26 +01:00
import Locale from "./Locale" ;
import { Utils } from "../../Utils" ;
2021-06-10 01:36:20 +02:00
import BaseUIElement from "../BaseUIElement" ;
2020-11-06 01:58:26 +01:00
2021-06-10 01:36:20 +02:00
export class Translation extends BaseUIElement {
2020-11-06 01:58:26 +01:00
2021-03-17 14:35:40 +01:00
public static forcedLanguage = undefined ;
2020-11-06 01:58:26 +01:00
2020-11-11 16:23:49 +01:00
public readonly translations : object
constructor ( translations : object , context? : string ) {
2021-06-10 01:36:20 +02:00
super ( )
2021-01-14 22:25:11 +01:00
if ( translations === undefined ) {
2020-11-11 16:23:49 +01:00
throw ` Translation without content ( ${ context } ) `
}
let count = 0 ;
for ( const translationsKey in translations ) {
2021-06-10 01:36:20 +02:00
if ( ! translations . hasOwnProperty ( translationsKey ) ) {
2021-06-01 21:24:35 +02:00
continue
}
2020-11-11 16:23:49 +01:00
count ++ ;
2021-04-11 19:21:41 +02:00
if ( typeof ( translations [ translationsKey ] ) != "string" ) {
2021-04-23 17:22:01 +02:00
console . error ( "Non-string object in translation: " , translations [ translationsKey ] )
2021-04-11 19:21:41 +02:00
throw "Error in an object depicting a translation: a non-string object was found. (" + context + ")\n You probably put some other section accidentally in the translation"
2021-04-10 03:50:44 +02:00
}
2020-11-11 16:23:49 +01:00
}
this . translations = translations ;
2021-01-14 22:25:11 +01:00
if ( count === 0 ) {
2020-11-11 16:23:49 +01:00
throw ` No translations given in the object ( ${ context } ) `
}
}
2021-01-14 22:25:11 +01:00
get txt ( ) : string {
2021-06-14 02:39:23 +02:00
return this . textFor ( Translation . forcedLanguage ? ? Locale . language . data )
}
public textFor ( language : string ) : string {
2021-01-14 22:25:11 +01:00
if ( this . translations [ "*" ] ) {
return this . translations [ "*" ] ;
}
2021-06-14 02:39:23 +02:00
const txt = this . translations [ language ] ;
2021-01-14 22:25:11 +01:00
if ( txt !== undefined ) {
return txt ;
}
const en = this . translations [ "en" ] ;
if ( en !== undefined ) {
return en ;
}
for ( const i in this . translations ) {
2021-06-10 01:36:20 +02:00
if ( ! this . translations . hasOwnProperty ( i ) ) {
continue ;
}
2021-01-14 22:25:11 +01:00
return this . translations [ i ] ; // Return a random language
}
console . error ( "Missing language " , Locale . language . data , "for" , this . translations )
return "" ;
}
2021-06-14 02:39:23 +02:00
2021-06-10 01:36:20 +02:00
InnerConstructElement ( ) : HTMLElement {
const el = document . createElement ( "span" )
Locale . language . addCallbackAndRun ( _ = > {
el . innerHTML = this . txt
} )
return el ;
}
2021-01-14 22:25:11 +01:00
public SupportedLanguages ( ) : string [ ] {
const langs = [ ]
for ( const translationsKey in this . translations ) {
2021-06-10 01:36:20 +02:00
if ( ! this . translations . hasOwnProperty ( translationsKey ) ) {
continue ;
}
2021-04-09 02:57:06 +02:00
if ( translationsKey === "#" ) {
2021-01-14 22:25:11 +01:00
continue ;
}
2021-06-08 18:54:29 +02:00
if ( ! this . translations . hasOwnProperty ( translationsKey ) ) {
continue
}
2021-01-14 22:25:11 +01:00
langs . push ( translationsKey )
}
return langs ;
}
2020-11-11 16:23:49 +01:00
2020-11-06 01:58:26 +01:00
public Subs ( text : any ) : Translation {
const newTranslations = { } ;
for ( const lang in this . translations ) {
2021-06-10 01:36:20 +02:00
if ( ! this . translations . hasOwnProperty ( lang ) ) {
continue ;
}
2020-11-06 01:58:26 +01:00
let template : string = this . translations [ lang ] ;
for ( const k in text ) {
2021-06-10 01:36:20 +02:00
if ( ! text . hasOwnProperty ( k ) ) {
continue
}
const combined : ( string ) [ ] = [ ] ;
2020-11-06 01:58:26 +01:00
const parts = template . split ( "{" + k + "}" ) ;
2021-06-28 00:45:49 +02:00
const el : string | BaseUIElement = text [ k ] ;
2020-11-06 01:58:26 +01:00
if ( el === undefined ) {
continue ;
}
let rtext : string = "" ;
if ( typeof ( el ) === "string" ) {
rtext = el ;
2021-04-21 01:26:36 +02:00
} else if ( typeof ( el ) === "number" ) {
// HUH? Where did that number come from? It might be a version number or something calculated
2021-04-11 19:21:41 +02:00
rtext = "" + el ;
2021-04-21 01:26:36 +02:00
} else if ( el [ "toISOString" ] != undefined ) {
// This is a date, probably the timestamp of the object
// @ts-ignore
const date : Date = el ;
rtext = date . toLocaleString ( ) ;
2021-07-18 14:52:09 +02:00
} else if ( el . ConstructElement === undefined ) {
console . error ( "ConstructElement is not defined" , el ) ;
2021-09-02 21:22:34 +02:00
throw "ConstructElement is not defined, you are working with a " + ( typeof el ) + ":" + ( el . constructor . name )
2021-09-03 17:00:36 +02:00
} else if ( el [ "textFor" ] !== undefined ) {
// @ts-ignore
rtext = el . textFor ( lang )
2021-04-21 01:26:36 +02:00
} else {
2021-06-14 02:39:23 +02:00
rtext = el . ConstructElement ( ) . innerHTML ;
2021-04-11 19:21:41 +02:00
2020-11-06 01:58:26 +01:00
}
for ( let i = 0 ; i < parts . length - 1 ; i ++ ) {
combined . push ( parts [ i ] ) ;
combined . push ( rtext )
}
combined . push ( parts [ parts . length - 1 ] ) ;
2021-06-10 01:36:20 +02:00
template = combined . join ( "" )
2020-11-06 01:58:26 +01:00
}
newTranslations [ lang ] = template ;
}
return new Translation ( newTranslations ) ;
}
public replace ( a : string , b : string ) {
if ( a . startsWith ( "{" ) && a . endsWith ( "}" ) ) {
a = a . substr ( 1 , a . length - 2 ) ;
}
2021-06-10 01:36:20 +02:00
return this . Subs ( { [ a ] : b } ) ;
2020-11-06 01:58:26 +01:00
}
public Clone() {
return new Translation ( this . translations )
}
FirstSentence() {
const tr = { } ;
for ( const lng in this . translations ) {
2021-06-10 01:36:20 +02:00
if ( ! this . translations . hasOwnProperty ( lng ) ) {
continue
}
2020-11-06 01:58:26 +01:00
let txt = this . translations [ lng ] ;
txt = txt . replace ( /\..*/ , "" ) ;
txt = Utils . EllipsesAfter ( txt , 255 ) ;
tr [ lng ] = txt ;
}
return new Translation ( tr ) ;
}
2021-04-09 02:57:06 +02:00
public ExtractImages ( isIcon = false ) : string [ ] {
const allIcons : string [ ] = [ ]
for ( const key in this . translations ) {
2021-06-10 01:36:20 +02:00
if ( ! this . translations . hasOwnProperty ( key ) ) {
continue ;
}
2021-04-09 02:57:06 +02:00
const render = this . translations [ key ]
if ( isIcon ) {
const icons = render . split ( ";" ) . filter ( part = > part . match ( /(\.svg|\.png|\.jpg)$/ ) != null )
allIcons . push ( . . . icons )
2021-04-09 13:59:49 +02:00
} else if ( ! Utils . runningFromConsole ) {
2021-04-09 02:57:06 +02:00
// This might be a tagrendering containing some img as html
const htmlElement = document . createElement ( "div" )
htmlElement . innerHTML = render
const images = Array . from ( htmlElement . getElementsByTagName ( "img" ) ) . map ( img = > img . src )
allIcons . push ( . . . images )
2021-04-09 13:59:49 +02:00
} else {
// We are running this in ts-node (~= nodejs), and can not access document
// So, we fallback to simple regex
2021-04-10 03:50:44 +02:00
try {
const matches = render . match ( /<img[^>]+>/g )
if ( matches != null ) {
const sources = matches . map ( img = > img . match ( /src=("[^"]+"|'[^']+'|[^/ ]+)/ ) )
. filter ( match = > match != null )
. map ( match = > match [ 1 ] . trim ( ) . replace ( /^['"]/ , '' ) . replace ( /['"]$/ , '' ) ) ;
allIcons . push ( . . . sources )
}
2021-04-11 19:21:41 +02:00
} catch ( e ) {
2021-04-10 03:50:44 +02:00
console . error ( "Could not search for images: " , render , this . txt )
throw e
2021-04-09 13:59:49 +02:00
}
2021-04-09 02:57:06 +02:00
}
}
return allIcons . filter ( icon = > icon != undefined )
}
2021-06-27 19:21:31 +02:00
2020-11-06 01:58:26 +01:00
}