a bit of more restructuring
This commit is contained in:
committed by
Jacob Overgaard
parent
83b466cacc
commit
444cae8b31
@@ -1,6 +1,6 @@
|
||||
import { aTimeout, elementUpdated, expect, fixture, html } from '@open-wc/testing';
|
||||
import type { UmbLocalizationSet, UmbLocalizationSetBase } from './localization.manager.js';
|
||||
import { registerLocalization, localizations } from './localization.manager.js';
|
||||
import { umbLocalizationManager } from './localization.manager.js';
|
||||
import { UmbLocalizationController } from './localization.controller.js';
|
||||
import { LitElement, customElement, property } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
|
||||
@@ -57,10 +57,10 @@ const danishRegional: UmbLocalizationSet = {
|
||||
//#endregion
|
||||
|
||||
describe('UmbLocalizeController', () => {
|
||||
let controller: UmbLocalizationController<TestLocalization>;
|
||||
let controller: UmbLocalizationController;
|
||||
|
||||
beforeEach(async () => {
|
||||
registerLocalization(english, danish, danishRegional);
|
||||
umbLocalizationManager.registerManyLocalizations([english, danish, danishRegional]);
|
||||
document.documentElement.lang = english.$code;
|
||||
document.documentElement.dir = english.$dir;
|
||||
await aTimeout(0);
|
||||
@@ -77,7 +77,7 @@ describe('UmbLocalizeController', () => {
|
||||
|
||||
afterEach(() => {
|
||||
controller.destroy();
|
||||
localizations.clear();
|
||||
umbLocalizationManager.localizations.clear();
|
||||
});
|
||||
|
||||
it('should have a default language', () => {
|
||||
@@ -132,7 +132,7 @@ describe('UmbLocalizeController', () => {
|
||||
|
||||
it('should override a term if new translation is registered', () => {
|
||||
// Let the registry load the new extension
|
||||
registerLocalization(englishOverride);
|
||||
umbLocalizationManager.registerLocalization(englishOverride);
|
||||
|
||||
expect(controller.term('close')).to.equal('Close 2');
|
||||
});
|
||||
|
||||
@@ -11,7 +11,12 @@ The above copyright notice and this permission notice shall be included in all c
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
import type { UmbLocalizationSet, FunctionParams, UmbLocalizationSetBase } from './localization.manager.js';
|
||||
import type {
|
||||
UmbLocalizationSet,
|
||||
FunctionParams,
|
||||
UmbLocalizationSetBase,
|
||||
UmbLocalizationSetKey,
|
||||
} from './localization.manager.js';
|
||||
import { umbLocalizationManager } from './localization.manager.js';
|
||||
import type { LitElement } from '@umbraco-cms/backoffice/external/lit';
|
||||
import type { UmbController, UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
@@ -35,11 +40,13 @@ const LocalizationControllerAlias = Symbol();
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export class UmbLocalizationController implements UmbController {
|
||||
export class UmbLocalizationController<LocalizationSetType extends UmbLocalizationSetBase = UmbLocalizationSet>
|
||||
implements UmbController
|
||||
{
|
||||
#host;
|
||||
#hostEl?: HTMLElement & Partial<Pick<LitElement, 'requestUpdate'>>;
|
||||
readonly controllerAlias = LocalizationControllerAlias;
|
||||
#usedKeys = new Array<keyof UmbLocalizationSet>();
|
||||
#usedKeys = new Array<UmbLocalizationSetKey>();
|
||||
|
||||
constructor(host: UmbControllerHost) {
|
||||
this.#host = host;
|
||||
@@ -64,7 +71,7 @@ export class UmbLocalizationController implements UmbController {
|
||||
this.#hostEl?.requestUpdate?.();
|
||||
}
|
||||
|
||||
keysChanged(changedKeys: Set<keyof UmbLocalizationSet>) {
|
||||
keysChanged(changedKeys: Set<UmbLocalizationSetKey>) {
|
||||
const hasOneOfTheseKeys = this.#usedKeys.find((key) => changedKeys.has(key));
|
||||
|
||||
if (hasOneOfTheseKeys) {
|
||||
@@ -92,14 +99,14 @@ export class UmbLocalizationController implements UmbController {
|
||||
const locale = new Intl.Locale(lang);
|
||||
const language = locale?.language.toLowerCase();
|
||||
const region = locale?.region?.toLowerCase() ?? '';
|
||||
const primary = <UmbLocalizationSet>umbLocalizationManager.localizations.get(`${language}-${region}`);
|
||||
const secondary = <UmbLocalizationSet>umbLocalizationManager.localizations.get(language);
|
||||
const primary = umbLocalizationManager.localizations.get(`${language}-${region}`) as LocalizationSetType;
|
||||
const secondary = umbLocalizationManager.localizations.get(language) as LocalizationSetType;
|
||||
|
||||
return { locale, language, region, primary, secondary };
|
||||
}
|
||||
|
||||
/** Outputs a translated term. */
|
||||
term<K extends keyof UmbLocalizationSet>(key: K, ...args: FunctionParams<UmbLocalizationSet[K]>): string {
|
||||
term<K extends keyof LocalizationSetType>(key: K, ...args: FunctionParams<LocalizationSetType[K]>): string {
|
||||
this.#usedKeys.push(key);
|
||||
|
||||
const { primary, secondary } = this.getLocalizationData(this.lang());
|
||||
@@ -110,11 +117,8 @@ export class UmbLocalizationController implements UmbController {
|
||||
term = primary[key];
|
||||
} else if (secondary && secondary[key]) {
|
||||
term = secondary[key];
|
||||
} else if (
|
||||
umbLocalizationManager.fallback &&
|
||||
umbLocalizationManager.fallback[key as keyof UmbLocalizationSetBase]
|
||||
) {
|
||||
term = umbLocalizationManager.fallback[key as keyof UmbLocalizationSetBase];
|
||||
} else if (umbLocalizationManager.fallback && umbLocalizationManager.fallback[key]) {
|
||||
term = umbLocalizationManager.fallback[key];
|
||||
} else {
|
||||
return String(key);
|
||||
}
|
||||
|
||||
@@ -20,21 +20,29 @@ export interface UmbLocalizationSetBase {
|
||||
$code: string; // e.g. en, en-GB
|
||||
$dir: 'ltr' | 'rtl';
|
||||
}
|
||||
|
||||
export type UmbLocalizationSetKey = string | number | symbol;
|
||||
|
||||
export interface UmbLocalizationSet extends UmbLocalizationSetBase {
|
||||
[key: string]: UmbLocalizationEntry;
|
||||
[key: UmbLocalizationSetKey]: UmbLocalizationEntry;
|
||||
}
|
||||
|
||||
export const UMB_DEFAULT_LOCALIZATION_CULTURE = 'en-us';
|
||||
|
||||
export class UmbLocalizationManager {
|
||||
connectedControllers = new Set<UmbLocalizationController>();
|
||||
connectedControllers = new Set<UmbLocalizationController<UmbLocalizationSetBase>>();
|
||||
#documentElementObserver: MutationObserver;
|
||||
|
||||
#changedKeys: Set<keyof UmbLocalizationSet> = new Set();
|
||||
#changedKeys: Set<UmbLocalizationSetKey> = new Set();
|
||||
#requestUpdateChangedKeysId?: number = undefined;
|
||||
|
||||
localizations: Map<string, UmbLocalizationSetBase> = new Map();
|
||||
documentDirection = document.documentElement.dir || 'ltr';
|
||||
documentLanguage = document.documentElement.lang || navigator.language;
|
||||
fallback?: UmbLocalizationSetBase;
|
||||
|
||||
get fallback(): UmbLocalizationSet | undefined {
|
||||
return this.localizations.get(UMB_DEFAULT_LOCALIZATION_CULTURE) as UmbLocalizationSet;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.#documentElementObserver = new MutationObserver(this.updateAll);
|
||||
@@ -44,11 +52,11 @@ export class UmbLocalizationManager {
|
||||
});
|
||||
}
|
||||
|
||||
appendConsumer(consumer: UmbLocalizationController) {
|
||||
appendConsumer(consumer: UmbLocalizationController<UmbLocalizationSetBase>) {
|
||||
if (this.connectedControllers.has(consumer)) return;
|
||||
this.connectedControllers.add(consumer);
|
||||
}
|
||||
removeConsumer(consumer: UmbLocalizationController) {
|
||||
removeConsumer(consumer: UmbLocalizationController<UmbLocalizationSetBase>) {
|
||||
this.connectedControllers.delete(consumer);
|
||||
}
|
||||
|
||||
@@ -63,12 +71,7 @@ export class UmbLocalizationManager {
|
||||
this.localizations.set(code, t);
|
||||
}
|
||||
|
||||
// The first translation we registerer will become the fallback
|
||||
if (!this.fallback) {
|
||||
this.fallback = t;
|
||||
}
|
||||
|
||||
this.requestChangedKeysUpdate();
|
||||
this.#requestChangedKeysUpdate();
|
||||
}
|
||||
#registerLocalizationBind = this.registerLocalization.bind(this);
|
||||
|
||||
@@ -99,7 +102,7 @@ export class UmbLocalizationManager {
|
||||
this.#changedKeys.clear();
|
||||
};
|
||||
|
||||
updateChangedKeys = () => {
|
||||
#updateChangedKeys = () => {
|
||||
this.#requestUpdateChangedKeysId = undefined;
|
||||
|
||||
this.connectedControllers.forEach((ctrl) => {
|
||||
@@ -109,9 +112,13 @@ export class UmbLocalizationManager {
|
||||
this.#changedKeys.clear();
|
||||
};
|
||||
|
||||
requestChangedKeysUpdate() {
|
||||
/**
|
||||
* Request an update of all consumers of the keys defined in #changedKeys.
|
||||
* This waits one frame, which ensures that multiple changes are collected into one.
|
||||
*/
|
||||
#requestChangedKeysUpdate() {
|
||||
if (this.#requestUpdateChangedKeysId) return;
|
||||
this.#requestUpdateChangedKeysId = requestAnimationFrame(this.updateChangedKeys);
|
||||
this.#requestUpdateChangedKeysId = requestAnimationFrame(this.#updateChangedKeys);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,10 +21,6 @@ function addOrUpdateDictionary(
|
||||
}
|
||||
|
||||
export class UmbLocalizationRegistry {
|
||||
//
|
||||
#isDefaultLoadedPromise?: Promise<boolean>;
|
||||
#isDefaultLoadedResolve?: (value: boolean) => void;
|
||||
|
||||
#currentLanguage = new UmbStringState(document.documentElement.lang ?? 'en-us');
|
||||
readonly currentLanguage = this.#currentLanguage.asObservable();
|
||||
|
||||
@@ -37,13 +33,6 @@ export class UmbLocalizationRegistry {
|
||||
return umbLocalizationManager.localizations;
|
||||
}
|
||||
|
||||
get isDefaultLoaded() {
|
||||
this.#isDefaultLoadedPromise ??= new Promise<boolean>((resolve) => {
|
||||
this.#isDefaultLoadedResolve = resolve;
|
||||
});
|
||||
return this.#isDefaultLoadedPromise;
|
||||
}
|
||||
|
||||
constructor(extensionRegistry: UmbBackofficeExtensionRegistry) {
|
||||
combineLatest([this.currentLanguage, extensionRegistry.extensionsOfType('localization')]).subscribe(
|
||||
async ([currentLanguage, extensions]) => {
|
||||
@@ -54,7 +43,7 @@ export class UmbLocalizationRegistry {
|
||||
ext.meta.culture.toLowerCase() === locale.language.toLowerCase(),
|
||||
);
|
||||
|
||||
// Check if there is any difference to the cached aliases
|
||||
// Only get the extensions that are not already loading/loaded:
|
||||
const diff = filteredExt.filter((ext) => !this.#loadedExtAliases.includes(ext.alias));
|
||||
if (diff.length !== 0) {
|
||||
// got new localizations to load:
|
||||
|
||||
@@ -13,8 +13,6 @@ export class UmbSectionSidebarElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
render() {
|
||||
// TODO: just for testing purpose, should be removed in PR.
|
||||
console.log('Render', this);
|
||||
return html`
|
||||
<umb-section-sidebar-context-menu>
|
||||
<uui-scroll-container id="scroll-container">
|
||||
|
||||
@@ -25,16 +25,8 @@ export class UmbCurrentUserContext extends UmbBaseController {
|
||||
this.#observeIsAuthorized();
|
||||
});
|
||||
|
||||
umbLocalizationRegistry.isDefaultLoaded.then((isDefaultLoaded) => {
|
||||
if (!isDefaultLoaded) return;
|
||||
|
||||
this.observe(
|
||||
this.languageIsoCode,
|
||||
(currentLanguageIsoCode) => {
|
||||
umbLocalizationRegistry.loadLanguage(currentLanguageIsoCode);
|
||||
},
|
||||
'umbCurrentUserLanguageIsoCode',
|
||||
);
|
||||
this.observe(this.languageIsoCode, (currentLanguageIsoCode) => {
|
||||
umbLocalizationRegistry.loadLanguage(currentLanguageIsoCode);
|
||||
});
|
||||
|
||||
this.provideContext(UMB_CURRENT_USER_CONTEXT, this);
|
||||
|
||||
Reference in New Issue
Block a user