@microsoft/windows-admin-center-sdk
Version:
Microsoft - Windows Admin Center Shell
1 lines • 15.6 kB
Source Map (JSON)
{"version":3,"sources":["../../../packages/core/data/localization-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAuB,MAAM,MAAM,CAAC;AAOvD,OAAO,EAAE,QAAQ,EAAqB,MAAM,YAAY,CAAC;AASzD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACtB;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,qBAAa,mBAAmB,CAAC,CAAC;IAuBX,OAAO,CAAC,OAAO,CAAC;IAtBnC,OAAO,CAAC,MAAM,CAAC,6BAA6B,CAAoB;IAChE,OAAO,CAAC,MAAM,CAAC,oBAAoB,CAAmB;IACtD,OAAO,CAAC,MAAM,CAAC,0BAA0B,CAAuB;IAChE,OAAO,CAAC,MAAM,CAAC,eAAe,CAA2B;IACzD,OAAc,qBAAqB,SAA4B;IAC/D,OAAc,wBAAwB,SAA+B;IACrE,OAAc,eAAe,EAAE,QAAQ,EAAE,CAAuD;IAChG,OAAc,gBAAgB,EAAE,QAAQ,EAAE,CAAwD;IAElG,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA6C;IAC7E,OAAO,CAAC,qBAAqB,CAAS;IACtC,OAAO,CAAC,0BAA0B,CAAS;IAE3C,OAAO,CAAC,IAAI,CAAoB;IAChC,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,aAAa,CAAS;IAE9B;;;;OAIG;gBACwB,OAAO,CAAC,EAAE,0BAA0B;IAmB/D;;;OAGG;IACH,IAAW,QAAQ,IAAI,SAAS,CAE/B;IAED;;OAEG;IACI,oBAAoB,IAAI,MAAM;IAIrC;;OAEG;IACI,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS;IAI/D;;;OAGG;IACI,UAAU,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAa7C;;OAEG;IACI,sBAAsB,IAAI,GAAG;IAKpC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAU3B;;;;;OAKG;IACI,WAAW,IAAI,SAAS;IA0C/B;;;OAGG;IACI,qBAAqB,IAAI,UAAU,CAAC,CAAC,CAAC;IAuB7C,OAAO,CAAC,mBAAmB;IAMpB,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO;IAUxD,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,mBAAmB;IAsB3B,OAAO,CAAC,kBAAkB;IA0B1B,OAAO,CAAC,sBAAsB;CA2CjC","file":"localization-manager.d.ts","sourcesContent":["import { Observable, of, throwError, zip } from 'rxjs';\r\nimport { AjaxError, AjaxResponse } from 'rxjs/ajax';\r\nimport { catchError, map } from 'rxjs/operators';\r\nimport { LogLevel } from '../diagnostics/log-level';\r\nimport { LogRecord } from '../diagnostics/log-record';\r\nimport { Logging } from '../diagnostics/logging';\r\nimport { Http } from './http';\r\nimport { Language, LanguageInventory } from './language';\r\n\r\n/**\r\n * Interface that contains all the possible localized resources in the json file\r\n */\r\ninterface LocalizedResources<T> {\r\n Strings: T;\r\n}\r\n\r\n/**\r\n * Options to initialize the localization manager\r\n */\r\nexport interface LocalizationManagerOptions {\r\n /**\r\n * The URL path (relative or absolute)\r\n * to the resources folder containing the json files with the localized assets.\r\n * defaults to '/assets/strings' if not specified.\r\n * Ex: '/assets/strings'\r\n */\r\n resourcesPath?: string;\r\n\r\n /**\r\n * The Azure locale to start localization manager with\r\n */\r\n azureLocale?: string;\r\n}\r\n\r\nexport interface LocaleSet {\r\n /**\r\n * The locale ID covering all reginal locale.\r\n */\r\n id: string;\r\n\r\n /**\r\n * The neutral ID used for loading string resources.\r\n */\r\n neutral: string;\r\n}\r\n\r\n/**\r\n * Class to retrieve localized resources based on the user locale\r\n * This class lets you load resources from a json file in an\r\n * arbitrary location and determines what locale resources to return\r\n * on the user preference\r\n */\r\nexport class LocalizationManager<T> {\r\n private static defaultResourcesStringsFolder = 'assets/strings';\r\n private static resourcesStringsFile = '/strings.json';\r\n private static resourcesStringsFileFormat = '/{0}/strings.json';\r\n private static languageManager = new LanguageInventory();\r\n public static localStorageLocaleKey = 'locale:@msft-sme/shell';\r\n public static localStorageLocaleSetKey = 'localeSet:@msft-sme/shell';\r\n public static neutralCultures: Language[] = LocalizationManager.languageManager.neutralCultures;\r\n public static regionalCultures: Language[] = LocalizationManager.languageManager.regionalCultures;\r\n\r\n private readonly defaultLocaleId = LocalizationManager.neutralCultures[0].id;\r\n private resourcesStringFormat: string;\r\n private resourcesStringDefaultFile: string;\r\n\r\n private http: Http = new Http();\r\n private localeIdInternal: LocaleSet;\r\n private resourcesPath: string;\r\n\r\n /**\r\n * Initializes a new instance of the LocalizationManager class that reads the localized assets from\r\n * the given locations.\r\n * @param options? The options to initialize the localization manager.\r\n */\r\n public constructor(private options?: LocalizationManagerOptions) {\r\n const resourcesPath = options && options.resourcesPath;\r\n if (resourcesPath) {\r\n this.resourcesPath = MsftSme.trimEnd(resourcesPath.trim(), '/');\r\n } else {\r\n this.resourcesPath = LocalizationManager.defaultResourcesStringsFolder;\r\n }\r\n\r\n const azureLocale = options && options.azureLocale;\r\n if (azureLocale) {\r\n const azureLocaleSet = this.normalizeAzureLocaleId(azureLocale);\r\n if (azureLocaleSet) {\r\n this.localeIdInternal = azureLocaleSet;\r\n }\r\n }\r\n\r\n this.initializeResources();\r\n }\r\n\r\n /**\r\n * Gets current locale.\r\n * @return string the locale string.\r\n */\r\n public get localeId(): LocaleSet {\r\n return this.localeIdInternal;\r\n }\r\n\r\n /**\r\n * Gets the navigator language\r\n */\r\n public getNavigatorLanguage(): string {\r\n return navigator.language;\r\n }\r\n\r\n /**\r\n * Creates a LocaleSet from a string\r\n */\r\n public createLocaleSet(id: string, neutral?: string): LocaleSet {\r\n return { id: id, neutral: neutral || id };\r\n }\r\n\r\n /**\r\n * Sets the current locale in persistent storage\r\n * @param localeId the string representing the locale selected by the user. Ex: 'es' or 'en'\r\n */\r\n public saveLocale(localeSet: LocaleSet): void {\r\n if (!this.checkBothAvailable(localeSet)) {\r\n throw new Error(`The locale specified, ${localeSet.id} and ${localeSet.neutral} were not recognized.`);\r\n }\r\n\r\n this.localeIdInternal = localeSet;\r\n\r\n MsftSme.LocalStorageHandler.setItem(LocalizationManager.localStorageLocaleSetKey, JSON.stringify(localeSet));\r\n\r\n MsftSme.LocalStorageHandler.setItem(LocalizationManager.localStorageLocaleKey, localeSet.neutral);\r\n this.updateDocumentLanguage();\r\n }\r\n\r\n /**\r\n * Updates the lang attribute of the document to reflect the current locale.\r\n */\r\n public updateDocumentLanguage(): any {\r\n const locale = this.getLocaleId();\r\n document.documentElement.setAttribute('lang', locale.id);\r\n }\r\n\r\n /**\r\n * Ensures Resources are Initialized\r\n */\r\n private initializeResources() {\r\n const self = MsftSme.self();\r\n const locale = this.getLocaleId();\r\n self.Resources = <MsftSme.MsftSmeResources>{\r\n strings: {},\r\n localeId: locale.neutral,\r\n localeRegionalId: locale.id\r\n };\r\n }\r\n\r\n /**\r\n * Gets the current locale.\r\n * Throughout code, locale code is using <lower case>-<upper case> format which is standard on both Microsoft Edge and Google Chrome.\r\n * ex) en-US, de-DE, ja-JP and so on.\r\n * @returns The current locale selected by the user\r\n */\r\n public getLocaleId(): LocaleSet {\r\n if (this.localeIdInternal) {\r\n return this.localeIdInternal;\r\n }\r\n\r\n const storageLocaleSet = MsftSme.LocalStorageHandler.getItem(LocalizationManager.localStorageLocaleSetKey);\r\n let localeSet: LocaleSet;\r\n if (storageLocaleSet) {\r\n localeSet = JSON.parse(storageLocaleSet);\r\n if (this.checkBothAvailable(localeSet)) {\r\n return this.localeIdInternal = localeSet;\r\n }\r\n }\r\n\r\n // Now we read the browser locales and if it's supported, then we use that otherwise use default locale\r\n const navigatorLanguage = this.getNavigatorLanguage();\r\n if (!navigatorLanguage) {\r\n return this.localeIdInternal = { id: this.defaultLocaleId, neutral: this.defaultLocaleId };\r\n }\r\n\r\n localeSet = { id: navigatorLanguage, neutral: navigatorLanguage };\r\n if (this.checkBothAvailable(localeSet)) {\r\n return this.localeIdInternal = localeSet;\r\n }\r\n\r\n // Try with the neutral part only\r\n const neutral = navigatorLanguage.split('-')[0].toLowerCase();\r\n const found = LocalizationManager.neutralCultures.find(item => item.id.split('-')[0] === neutral);\r\n if (found) {\r\n // adjust default string language.\r\n localeSet.neutral = found.id;\r\n if (this.checkIdAvailable(localeSet)) {\r\n return this.localeIdInternal = localeSet;\r\n }\r\n\r\n // cannot found the regional code.\r\n return this.localeIdInternal = { id: found.id, neutral: found.id };\r\n }\r\n\r\n return this.localeIdInternal = { id: this.defaultLocaleId, neutral: this.defaultLocaleId };\r\n }\r\n\r\n /**\r\n * Fetches the localized strings from the server based on the current culture.\r\n * @returns an observable with object the localized strings.\r\n */\r\n public fetchLocalizedStrings(): Observable<T> {\r\n this.configureFetchFiles();\r\n this.getLocaleId();\r\n if (this.localeId.neutral === this.defaultLocaleId) {\r\n // Only fetch the default locale\r\n return this.fetchDefaultStrings();\r\n }\r\n\r\n return zip(\r\n this.fetchDefaultStrings(),\r\n this.fetchLocaleStrings())\r\n .pipe(\r\n catchError(() => of(null)),\r\n map(([fetchDefault, fetchLocale]) => {\r\n // get the english strings and replace those properties of the localized json\r\n if (fetchLocale) {\r\n return MsftSme.deepAssign({}, fetchDefault, fetchLocale);\r\n }\r\n\r\n return fetchDefault;\r\n }));\r\n }\r\n\r\n private configureFetchFiles(): void {\r\n const version = MsftSme.self() && MsftSme.self().Environment && MsftSme.self().Environment.version || 'no-version';\r\n this.resourcesStringFormat = `${this.resourcesPath}${LocalizationManager.resourcesStringsFileFormat}?v=${version}`;\r\n this.resourcesStringDefaultFile = `${this.resourcesPath}${LocalizationManager.resourcesStringsFile}?v=${version}`;\r\n }\r\n\r\n public checkBothAvailable(localeSet: LocaleSet): boolean {\r\n if (!localeSet || !localeSet.neutral || !localeSet.id) {\r\n return false;\r\n }\r\n\r\n const checkNeutral = LocalizationManager.neutralCultures.find(item => item.id === localeSet.neutral);\r\n const checkId = LocalizationManager.regionalCultures.find(item => item.id === localeSet.id);\r\n return !!checkNeutral && !!checkId;\r\n }\r\n\r\n private checkIdAvailable(localeSet: LocaleSet): boolean {\r\n const checkId = LocalizationManager.regionalCultures.find(item => item.id === localeSet.id);\r\n return !!checkId;\r\n }\r\n\r\n private fetchDefaultStrings(): Observable<T> {\r\n return this.http.get(this.resourcesStringDefaultFile)\r\n .pipe(\r\n catchError((error: AjaxError) => {\r\n if (error.status >= 400) {\r\n // If we got any error, we just reply with that error and the map function will handle it\r\n Logging.log(<LogRecord>{\r\n source: 'LocalizationManager',\r\n level: LogLevel.Error,\r\n message:\r\n `Error ${error.status} received when getting default localized strings for the ` +\r\n `${this.defaultLocaleId} locale. The error was: ${error.message}`\r\n });\r\n }\r\n\r\n return throwError(() => error);\r\n }),\r\n map((result: AjaxResponse<any>) => {\r\n return (<LocalizedResources<T>>result.response).Strings;\r\n }));\r\n }\r\n\r\n private fetchLocaleStrings(): Observable<T> {\r\n return this.http.get(this.resourcesStringFormat.format(this.localeId.neutral))\r\n .pipe(\r\n catchError((error: AjaxError) => {\r\n if (error.status >= 400) {\r\n // If we got any error, we just reply with that error and the map function will handle it\r\n Logging.log(<LogRecord>{\r\n source: 'LocalizationManager',\r\n level: LogLevel.Warning,\r\n message:\r\n `Error ${error.status} received when getting localized strings for the ` +\r\n `user specified locale: '${this.localeId.neutral}'. The error was: ${error.message}`\r\n });\r\n return of({});\r\n }\r\n }),\r\n map((result: AjaxResponse<any>) => {\r\n // If response has body, use that\r\n if (!result || !result.response) {\r\n return null;\r\n }\r\n\r\n return (<LocalizedResources<T>>result.response).Strings;\r\n }));\r\n }\r\n\r\n private normalizeAzureLocaleId(azureLocale: string): LocaleSet {\r\n if (MsftSme.isNullOrWhiteSpace(azureLocale)) {\r\n return null;\r\n }\r\n\r\n const neutralCultures: { [index: string]: string } = {};\r\n neutralCultures['de'] = 'de-DE';\r\n neutralCultures['en'] = 'en-US';\r\n neutralCultures['es'] = 'es-ES';\r\n neutralCultures['fr'] = 'fr-FR';\r\n neutralCultures['it'] = 'it-IT';\r\n neutralCultures['hu'] = 'hu-HU';\r\n neutralCultures['nl'] = 'nl-NL';\r\n neutralCultures['pl'] = 'pl-PL';\r\n neutralCultures['pt'] = 'pt-BR';\r\n neutralCultures['sv'] = 'sv-SE';\r\n neutralCultures['tr'] = 'tr-TR';\r\n neutralCultures['cs'] = 'cs-CZ';\r\n neutralCultures['ru'] = 'ru-RU';\r\n neutralCultures['zh'] = 'zh-CN';\r\n neutralCultures['zh-hans'] = 'zh-CN';\r\n neutralCultures['zh-chs'] = 'zh-CN';\r\n neutralCultures['zh-hant'] = 'zh-TW';\r\n neutralCultures['zh-cht'] = 'zh-TW';\r\n neutralCultures['ja'] = 'ja-JP';\r\n neutralCultures['ko'] = 'ko-KR';\r\n\r\n const languages = azureLocale.split('.');\r\n const segments = languages[1].split('-');\r\n const id = `${segments[0]}-${segments[1].toUpperCase()}`;\r\n const neutral = neutralCultures[languages[0]];\r\n if (!neutral) {\r\n return null;\r\n }\r\n\r\n const localeSet: LocaleSet = { id, neutral };\r\n if (this.checkBothAvailable(localeSet)) {\r\n return localeSet;\r\n }\r\n\r\n // cannot found the regional code.\r\n return <LocaleSet>{ id: localeSet.neutral, neutral: localeSet.neutral };\r\n }\r\n}\r\n"]}