Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions src/Umbraco.Web.UI.Client/src/external/rxjs/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
export {
BehaviorSubject,
Observable,
ReplaySubject,
Subject,
Observable,
BehaviorSubject,
Subscription,
map,
distinctUntilChanged,
catchError,
combineLatest,
shareReplay,
takeUntil,
debounceTime,
tap,
of,
lastValueFrom,
firstValueFrom,
switchMap,
distinctUntilChanged,
filter,
startWith,
skip,
first,
firstValueFrom,
from,
lastValueFrom,
map,
of,
shareReplay,
skip,
startWith,
switchMap,
takeUntil,
tap,
} from 'rxjs';
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { aTimeout, elementUpdated, expect, fixture, html } from '@open-wc/testin
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import { UmbLocalizationController } from '@umbraco-cms/backoffice/localization-api';
import { umbLocalizationRegistry } from './registry/localization.registry.js';
import type { ManifestLocalization } from './extensions/localization.extension.js';

const english = {
const english: ManifestLocalization = {
type: 'localization',
alias: 'test.en',
name: 'Test English',
weight: 100,
meta: {
culture: 'en',
localizations: {
Expand All @@ -27,7 +29,75 @@ const english = {
},
};

const danish = {
const englishUs: ManifestLocalization = {
type: 'localization',
alias: 'test.en-us',
name: 'Test English (US)',
weight: 100,
meta: {
culture: 'en-us',
localizations: {
general: {
close: 'Close US',
overridden: 'Overridden',
},
},
},
};

// This is a factory function that returns the localization object.
const asyncFactory = async (localizations: Record<string, any>, delay: number) => {
await aTimeout(delay); // Simulate async loading
return {
// Simulate a JS module that exports a localization object.
default: localizations,
};
};

// This is an async localization that overrides the previous one.
const englishAsyncOverride: ManifestLocalization = {
type: 'localization',
alias: 'test.en.async-override',
name: 'Test English Async Override',
weight: -100,
meta: {
culture: 'en-us',
},
js: () =>
asyncFactory(
{
general: {
close: 'Close Async',
overridden: 'Overridden Async',
},
},
100,
),
};

// This is another async localization that loads later than the previous one and overrides it because of a lower weight.
const english2AsyncOverride: ManifestLocalization = {
type: 'localization',
alias: 'test.en.async-override-2',
name: 'Test English Async Override 2',
weight: -200,
meta: {
culture: 'en-us',
},
js: () =>
asyncFactory(
{
general: {
close: 'Another Async Close',
},
},
200, // This will load after the first async override
// so it should override the close translation.
// The overridden translation should not be overridden.
),
};

const danish: ManifestLocalization = {
type: 'localization',
alias: 'test.da',
name: 'Test Danish',
Expand All @@ -53,8 +123,7 @@ describe('umb-localize', () => {
});

describe('localization', () => {
umbExtensionsRegistry.register(english);
umbExtensionsRegistry.register(danish);
umbExtensionsRegistry.registerMany([english, englishUs, danish]);

beforeEach(async () => {
umbLocalizationRegistry.loadLanguage(english.meta.culture);
Expand Down Expand Up @@ -123,13 +192,50 @@ describe('umb-localize', () => {
it('should change the value if the language is changed', async () => {
expect(element.shadowRoot?.innerHTML).to.contain('Close');

// Change to Danish
umbLocalizationRegistry.loadLanguage(danish.meta.culture);
await aTimeout(0);
await elementUpdated(element);

expect(element.shadowRoot?.innerHTML).to.contain('Luk');
});

it('should fall back to the fallback language if the key is not found', async () => {
expect(element.shadowRoot?.innerHTML).to.contain('Close');

// Change to US English
umbLocalizationRegistry.loadLanguage(englishUs.meta.culture);
await aTimeout(0);
await elementUpdated(element);
expect(element.shadowRoot?.innerHTML).to.contain('Close US');

element.key = 'general_overridden';
await elementUpdated(element);
expect(element.shadowRoot?.innerHTML).to.contain('Overridden');

element.key = 'general_logout';
await elementUpdated(element);
expect(element.shadowRoot?.innerHTML).to.contain('Log out');
});

it('should accept a lazy loaded localization', async () => {
umbExtensionsRegistry.registerMany([englishAsyncOverride, english2AsyncOverride]);
umbLocalizationRegistry.loadLanguage(englishAsyncOverride.meta.culture);
await aTimeout(200); // Wait for the async override to load

await elementUpdated(element);
expect(element.shadowRoot?.innerHTML).to.contain(
'Another Async Close',
'(async) Should have overridden the close (from first language)',
);

element.key = 'general_overridden';
await elementUpdated(element);
expect(element.shadowRoot?.innerHTML).to.contain(
'Overridden Async',
'(async) Should not have overridden the overridden (from first language)',
);
});

it('should use the slot if translation is not found', async () => {
element.key = 'non-existing-key';
await elementUpdated(element);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ const englishUk: ManifestLocalization = {
type: 'localization',
alias: 'test.en',
name: 'Test English (UK)',
weight: 100,
meta: {
culture: 'en',
direction: 'ltr',
localizations: {
general: {
color: 'Colour',
Expand All @@ -22,6 +24,7 @@ const english: ManifestLocalization = {
type: 'localization',
alias: 'test.en-us',
name: 'Test English (US)',
weight: 100,
meta: {
culture: 'en-us',
direction: 'ltr',
Expand All @@ -46,14 +49,41 @@ const englishOverride: ManifestLocalization = {
type: 'localization',
alias: 'test.en.override',
name: 'Test English',
weight: 0,
meta: {
culture: 'en-us',
localizations: {
general: {
close: 'Close 2',
overridden: 'Overridden',
},
},
},
};

// This is a factory function that returns the localization object.
const englishAsyncFactory = async () => {
await aTimeout(100); // Simulate async loading
return {
// Simulate a JS module that exports a localization object.
default: {
general: {
close: 'Close Async',
overridden: 'Overridden Async',
},
},
};
};

const englishAsyncOverride: ManifestLocalization = {
type: 'localization',
alias: 'test.en.async-override',
name: 'Test English Async Override',
weight: -100,
meta: {
culture: 'en-us',
},
js: englishAsyncFactory,
};

const danish: ManifestLocalization = {
Expand Down Expand Up @@ -87,10 +117,7 @@ const danishRegional: ManifestLocalization = {
//#endregion

describe('UmbLocalizeController', () => {
umbExtensionsRegistry.register(englishUk);
umbExtensionsRegistry.register(english);
umbExtensionsRegistry.register(danish);
umbExtensionsRegistry.register(danishRegional);
umbExtensionsRegistry.registerMany([englishUk, english, danish, danishRegional]);

let registry: UmbLocalizationRegistry;

Expand All @@ -102,6 +129,16 @@ describe('UmbLocalizeController', () => {

afterEach(() => {
registry.localizations.clear();
registry.destroy();
});

it('should register into the localization manager', async () => {
expect(registry.localizations.size).to.equal(2, 'Should have registered the 2 original iso codes (en, en-us)');

// Register an additional language to test the registry.
registry.loadLanguage(danish.meta.culture);
await aTimeout(0);
expect(registry.localizations.size).to.equal(3, 'Should have registered the 3rd language (da)');
});

it('should set the document language and direction', async () => {
Expand All @@ -122,9 +159,48 @@ describe('UmbLocalizeController', () => {

await aTimeout(0);

const current = registry.localizations.get(english.meta.culture);
expect(current).to.have.property('general_close', 'Close 2');
expect(current).to.have.property('general_logout', 'Log out');
const current = registry.localizations.get(englishOverride.meta.culture);
expect(current).to.have.property(
'general_close',
'Close 2',
'Should have overridden the close (from first language)',
);
expect(current).to.have.property('general_logout', 'Log out', 'Should not have overridden the logout');

umbExtensionsRegistry.unregister(englishOverride.alias);
});

it('should load translations based on weight (lowest weight overrides)', async () => {
// set weight to 200, so it will not override the existing translation
const englishOverrideLowWeight = { ...englishOverride, weight: 200 } satisfies ManifestLocalization;
umbExtensionsRegistry.register(englishOverrideLowWeight);
await aTimeout(0);

let current = registry.localizations.get(englishOverrideLowWeight.meta.culture);
expect(current).to.have.property(
'general_close',
'Close',
'Should not have overridden the close (from first language)',
);
expect(current).to.have.property('general_overridden', 'Overridden', 'Should be able to register its own keys');

// Now register a new async override with a lower weight
umbExtensionsRegistry.register(englishAsyncOverride);
await aTimeout(200); // Wait for the async override to load
current = registry.localizations.get(englishOverrideLowWeight.meta.culture);
expect(current).to.have.property(
'general_close',
'Close Async',
'(async) Should have overridden the close (from first language)',
);
expect(current).to.have.property(
'general_overridden',
'Overridden Async',
'(async) Should have overridden the overridden',
);

umbExtensionsRegistry.unregister(englishOverrideLowWeight.alias);
umbExtensionsRegistry.unregister(englishAsyncOverride.alias);
});

it('should be able to switch to the fallback language', async () => {
Expand Down
Loading
Loading