From d5e2efbbaa53225e9bb041d93d72f52a2b095180 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Fri, 21 Feb 2025 16:58:23 +0100 Subject: [PATCH] V15: A user cannot switch back to the default language (#18414) * chore: prettier * fix: loads all extensions everytime but register only new localizations this ensures that the browser is updated even if you switch back to a previously loaded language * test: adds a test to check if we can switch between already loaded languages --- .../src/assets/lang/en.ts | 3 +- .../registry/localization.registry.test.ts | 46 ++++++++++++++++++- .../registry/localization.registry.ts | 44 ++++++++++-------- 3 files changed, 71 insertions(+), 22 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts b/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts index 320236b6d4..eba1078fc0 100644 --- a/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts +++ b/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts @@ -1261,7 +1261,8 @@ export default { colorsTitle: 'Colours', colorsDescription: 'Add, remove or sort colours', showLabelTitle: 'Include labels?', - showLabelDescription: 'Stores colours as a JSON object containing both the colour hex string and label, rather than just the hex string.', + showLabelDescription: + 'Stores colours as a JSON object containing both the colour hex string and label, rather than just the hex string.', }, contentPicker: { allowedItemTypes: 'You can only select items of type(s): %0%', diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/localization/registry/localization.registry.test.ts b/src/Umbraco.Web.UI.Client/src/packages/core/localization/registry/localization.registry.test.ts index 03b59277d5..62e7959a9a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/localization/registry/localization.registry.test.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/localization/registry/localization.registry.test.ts @@ -4,15 +4,30 @@ import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registr import type { ManifestLocalization } from '../extensions/localization.extension.js'; //#region Localizations -const english: ManifestLocalization = { +const englishUk: ManifestLocalization = { type: 'localization', alias: 'test.en', - name: 'Test English', + name: 'Test English (UK)', + meta: { + culture: 'en', + localizations: { + general: { + color: 'Colour', + }, + }, + }, +}; + +const english: ManifestLocalization = { + type: 'localization', + alias: 'test.en-us', + name: 'Test English (US)', meta: { culture: 'en-us', direction: 'ltr', localizations: { general: { + color: 'Color', close: 'Close', logout: 'Log out', withInlineToken: '{0} {1}', @@ -72,6 +87,7 @@ const danishRegional: ManifestLocalization = { //#endregion describe('UmbLocalizeController', () => { + umbExtensionsRegistry.register(englishUk); umbExtensionsRegistry.register(english); umbExtensionsRegistry.register(danish); umbExtensionsRegistry.register(danishRegional); @@ -111,6 +127,32 @@ describe('UmbLocalizeController', () => { expect(current).to.have.property('general_logout', 'Log out'); }); + it('should be able to switch to the fallback language', async () => { + // Verify that the document language and direction is set correctly to the default language + expect(document.documentElement.lang).to.equal(english.meta.culture); + expect(document.documentElement.dir).to.equal(english.meta.direction); + + // Switch to the fallback language, which is the UK version of English + registry.loadLanguage('en'); + await aTimeout(0); + + expect(document.documentElement.lang).to.equal('en'); + expect(document.documentElement.dir).to.equal('ltr'); + + const current = registry.localizations.get(englishUk.meta.culture); + expect(current).to.have.property('general_color', 'Colour'); + + // And switch back again + registry.loadLanguage('en-us'); + await aTimeout(0); + + expect(document.documentElement.lang).to.equal('en-us'); + expect(document.documentElement.dir).to.equal('ltr'); + + const newCurrent = registry.localizations.get(english.meta.culture); + expect(newCurrent).to.have.property('general_color', 'Color'); + }); + it('should load a new language', async () => { registry.loadLanguage(danish.meta.culture); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/localization/registry/localization.registry.ts b/src/Umbraco.Web.UI.Client/src/packages/core/localization/registry/localization.registry.ts index 24ebb1ad55..5fd55b451c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/localization/registry/localization.registry.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/localization/registry/localization.registry.ts @@ -48,33 +48,39 @@ export class UmbLocalizationRegistry { combineLatest([this.currentLanguage, extensionRegistry.byType('localization')]).subscribe( async ([currentLanguage, extensions]) => { const locale = new Intl.Locale(currentLanguage); - const filteredExt = extensions.filter( + const currentLanguageExtensions = extensions.filter( (ext) => ext.meta.culture.toLowerCase() === locale.baseName.toLowerCase() || ext.meta.culture.toLowerCase() === locale.language.toLowerCase(), ); - // 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: - const translations = await Promise.all(diff.map(this.#loadExtension)); + // If there are no extensions for the current language, return early + if (!currentLanguageExtensions.length) return; - if (translations.length) { - umbLocalizationManager.registerManyLocalizations(translations); + // Register the new translations only if they have not been registered before + const diff = currentLanguageExtensions.filter((ext) => !this.#loadedExtAliases.includes(ext.alias)); - // Set the document language - const newLang = locale.baseName.toLowerCase(); - if (document.documentElement.lang.toLowerCase() !== newLang) { - document.documentElement.lang = newLang; - } + // Load all localizations + const translations = await Promise.all(currentLanguageExtensions.map(this.#loadExtension)); - // Set the document direction to the direction of the primary language - const newDir = translations[0].$dir ?? 'ltr'; - if (document.documentElement.dir !== newDir) { - document.documentElement.dir = newDir; - } - } + // If there are no translations, return early + if (!translations.length) return; + + if (diff.length) { + const filteredTranslations = translations.filter((t) => diff.some((ext) => ext.meta.culture === t.$code)); + umbLocalizationManager.registerManyLocalizations(filteredTranslations); + } + + // Set the document language + const newLang = locale.baseName.toLowerCase(); + if (document.documentElement.lang.toLowerCase() !== newLang) { + document.documentElement.lang = newLang; + } + + // Set the document direction to the direction of the primary language + const newDir = translations[0].$dir ?? 'ltr'; + if (document.documentElement.dir !== newDir) { + document.documentElement.dir = newDir; } }, );