import { action , observable , makeObservable } from 'mobx' ; import { Bootstrap , injectable } from '@cloudbeaver/core-di' ; import { NotificationService } from '@cloudbeaver/core-events' ; import { ServerConfigResource , SessionResource } from '@cloudbeaver/core-root' ; import type { ServerLanguage } from '@cloudbeaver/core-sdk' ; import { SettingsService } from '@cloudbeaver/core-settings' ; import type { ILocaleProvider } from './ILocaleProvider' ; import { defaultENLocale } from './locales/en' ; import { defaultITLocale } from './locales/it' ; import { defaultRULocale } from './locales/ru' ; import { defaultZHLocale } from './locales/zh' ; import type { TLocalizationToken } from './TLocalizationToken' ; export type ServerLanguageShort = Pick < ServerLanguage , 'isoCode' | 'nativeName' > ; const DEFAULT_LOCALE_NAME = 'en' ; const LANG_SETTINGS_KEY = 'langSettings' ; @ injectable ( ) export class LocalizationService extends Bootstrap { settings = { language : DEFAULT_LOCALE_NAME , } ; private localeMap : Map < string , Map < string , string > > = new Map ( ) ; private localeProviders : ILocaleProvider [ ] = [ ] ; constructor ( private readonly notificationService , private readonly sessionResource , private readonly serverConfigResource , private readonly settingsService ) { super ( ) ; makeObservable < LocalizationService , 'localeMap' | 'setCurrentLocale' > ( this , { settings : observable , localeMap : observable . shallow , setCurrentLocale : action , } ) ; sessionResource . onDataUpdate . addHandler ( this . syncLanguage . bind ( this ) ) ; } addProvider ( provider ) { this . localeProviders . push ( provider ) ; } readonly translate = < T extends TLocalizationToken | undefined > ( token , fallback ? ) : T => { if ( token === undefined ) { return undefined as T ; } let translation = this . localeMap . get ( this . getCurrentLanguage ( ) ) ?. get ( token as TLocalizationToken ) ; if ( ! translation ) { translation = this . localeMap . get ( DEFAULT_LOCALE_NAME ) ?. get ( token as TLocalizationToken ) ; } if ( typeof translation === 'string' ) { return translation as T ; } if ( fallback !== undefined ) { return this . translate ( fallback ) ; } return token ; } ; register ( ) { this . addProvider ( this . coreProvider . bind ( this ) ) ; this . settingsService . registerSettings ( this . settings , LANG_SETTINGS_KEY ) ; this . sessionResource . setDefaultLocale ( this . settings . language ) ; } async load ( ) { await this . loadLocaleAsync ( DEFAULT_LOCALE_NAME ) ; await this . loadLocaleAsync ( this . settings . language ) ; } getCurrentLanguage ( ) { return this . settings . language ; } async changeLocaleAsync ( key ) { if ( key === this . settings . language ) { return ; } await this . sessionResource . changeLanguage ( key ) ; } private async syncLanguage ( ) { await this . sessionResource . refreshSilent ( ) ; const session = this . sessionResource . data ; if ( session ) { await this . setLocale ( session . locale ) ; } } private coreProvider ( locale ) { switch ( locale ) { case 'ru' : return defaultRULocale ; case 'it' : return defaultITLocale ; case 'zh' : return defaultZHLocale ; default : return defaultENLocale ; } } private setCurrentLocale ( lang ) { this . settings . language = lang ; } private async setLocale ( key ) { const config = await this . serverConfigResource . load ( ) ; if ( ! config ) { throw new Error ( 'Can\'t get server settings' ) ; } if ( ! config . supportedLanguages . some ( lang => lang . isoCode === key ) ) { this . setCurrentLocale ( config ! . supportedLanguages [ 0 ] ! . isoCode ) ; throw new Error ( `Language '${ key }' is not supported` ) ; } this . setCurrentLocale ( key ) ; await this . loadLocaleAsync ( key ) ; } private async loadLocaleAsync ( localeKey ) { if ( this . localeMap . has ( localeKey ) ) { return ; } try { const locale = new Map < string , string > ( ) ; for ( const provider of this . localeProviders ) { for ( const [ key , value ] of await provider ( localeKey ) ) { locale . set ( key , value ) ; } } this . localeMap . set ( localeKey , locale ) ; } catch ( error ) { this . notificationService . logException ( error , 'Locale is not found' , '' , true ) ; } } }