diff --git a/crowdin.yml b/crowdin.yml index 80e0784ea0..9df169a69e 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -3,32 +3,10 @@ "base_path": "." "base_url": "https://hyland.api.crowdin.com" "preserve_hierarchy": true -"languages_mapping": { - "osx_locale": { - "ar": "ar-SA", - "cs": "cs-CZ", - "da": "da-DK", - "de": "de-DE", - "en-AU": "en-AU", - "es": "es-ES", - "fi": "fi-FI", - "fr": "fr-FR", - "it": "it-IT", - "ja": "ja-JP", - "nb": "nb-NO", - "nl": "nl-NL", - "pl": "pl-PL", - "pt": "pt-PT", - "pt-BR": "pt-BR", - "ru": "ru-RU", - "sv": "sv-SE", - "zh-CN": "zh-CN" - } -} "files": [ { "source": "/**/**/i18n/en.json", - "translation": "/%original_path%/%osx_locale%.%file_extension%", + "translation": "/%original_path%/%two_letters_code%.%file_extension%", "export_only_approved": "true", "update_option": "update_without_changes" } diff --git a/lib/content-services/src/lib/i18n/ar-SA.json b/lib/content-services/src/lib/i18n/ar.json similarity index 100% rename from lib/content-services/src/lib/i18n/ar-SA.json rename to lib/content-services/src/lib/i18n/ar.json diff --git a/lib/content-services/src/lib/i18n/cs-CZ.json b/lib/content-services/src/lib/i18n/cs.json similarity index 100% rename from lib/content-services/src/lib/i18n/cs-CZ.json rename to lib/content-services/src/lib/i18n/cs.json diff --git a/lib/content-services/src/lib/i18n/da-DK.json b/lib/content-services/src/lib/i18n/da.json similarity index 100% rename from lib/content-services/src/lib/i18n/da-DK.json rename to lib/content-services/src/lib/i18n/da.json diff --git a/lib/content-services/src/lib/i18n/de-DE.json b/lib/content-services/src/lib/i18n/de.json similarity index 100% rename from lib/content-services/src/lib/i18n/de-DE.json rename to lib/content-services/src/lib/i18n/de.json diff --git a/lib/content-services/src/lib/i18n/es-ES.json b/lib/content-services/src/lib/i18n/es.json similarity index 100% rename from lib/content-services/src/lib/i18n/es-ES.json rename to lib/content-services/src/lib/i18n/es.json diff --git a/lib/content-services/src/lib/i18n/fi-FI.json b/lib/content-services/src/lib/i18n/fi.json similarity index 100% rename from lib/content-services/src/lib/i18n/fi-FI.json rename to lib/content-services/src/lib/i18n/fi.json diff --git a/lib/content-services/src/lib/i18n/fr-FR.json b/lib/content-services/src/lib/i18n/fr.json similarity index 100% rename from lib/content-services/src/lib/i18n/fr-FR.json rename to lib/content-services/src/lib/i18n/fr.json diff --git a/lib/content-services/src/lib/i18n/it-IT.json b/lib/content-services/src/lib/i18n/it.json similarity index 100% rename from lib/content-services/src/lib/i18n/it-IT.json rename to lib/content-services/src/lib/i18n/it.json diff --git a/lib/content-services/src/lib/i18n/ja-JP.json b/lib/content-services/src/lib/i18n/ja.json similarity index 100% rename from lib/content-services/src/lib/i18n/ja-JP.json rename to lib/content-services/src/lib/i18n/ja.json diff --git a/lib/content-services/src/lib/i18n/nb-NO.json b/lib/content-services/src/lib/i18n/nb.json similarity index 100% rename from lib/content-services/src/lib/i18n/nb-NO.json rename to lib/content-services/src/lib/i18n/nb.json diff --git a/lib/content-services/src/lib/i18n/nl-NL.json b/lib/content-services/src/lib/i18n/nl.json similarity index 100% rename from lib/content-services/src/lib/i18n/nl-NL.json rename to lib/content-services/src/lib/i18n/nl.json diff --git a/lib/content-services/src/lib/i18n/pl-PL.json b/lib/content-services/src/lib/i18n/pl.json similarity index 100% rename from lib/content-services/src/lib/i18n/pl-PL.json rename to lib/content-services/src/lib/i18n/pl.json diff --git a/lib/content-services/src/lib/i18n/pt-PT.json b/lib/content-services/src/lib/i18n/pt.json similarity index 100% rename from lib/content-services/src/lib/i18n/pt-PT.json rename to lib/content-services/src/lib/i18n/pt.json diff --git a/lib/content-services/src/lib/i18n/ru-RU.json b/lib/content-services/src/lib/i18n/ru.json similarity index 100% rename from lib/content-services/src/lib/i18n/ru-RU.json rename to lib/content-services/src/lib/i18n/ru.json diff --git a/lib/content-services/src/lib/i18n/sv-SE.json b/lib/content-services/src/lib/i18n/sv.json similarity index 100% rename from lib/content-services/src/lib/i18n/sv-SE.json rename to lib/content-services/src/lib/i18n/sv.json diff --git a/lib/core/src/lib/common/models/default-languages.model.ts b/lib/core/src/lib/common/models/default-languages.model.ts index ccb43e1321..9563cb885f 100644 --- a/lib/core/src/lib/common/models/default-languages.model.ts +++ b/lib/core/src/lib/common/models/default-languages.model.ts @@ -18,21 +18,21 @@ import { LanguageItem } from '../services/language-item.interface'; export const DEFAULT_LANGUAGE_LIST: LanguageItem[] = [ - { key: 'de-DE', label: 'Deutsch' }, + { key: 'de', label: 'Deutsch' }, { key: 'en', label: 'English' }, - { key: 'es-ES', label: 'Español' }, - { key: 'fr-FR', label: 'Français' }, - { key: 'it-IT', label: 'Italiano' }, - { key: 'ja-JP', label: '日本語' }, - { key: 'nb-NO', label: 'Bokmål' }, - { key: 'nl-NL', label: 'Nederlands' }, + { key: 'es', label: 'Español' }, + { key: 'fr', label: 'Français' }, + { key: 'it', label: 'Italiano' }, + { key: 'ja', label: '日本語' }, + { key: 'nb', label: 'Bokmål' }, + { key: 'nl', label: 'Nederlands' }, { key: 'pt-BR', label: 'Português (Brasil)' }, - { key: 'ru-RU', label: 'Русский' }, + { key: 'ru', label: 'Русский' }, { key: 'zh-CN', label: '中文简体' }, - { key: 'cs-CZ', label: 'Čeština' }, - { key: 'da-DK', label: 'Dansk' }, - { key: 'fi-FI', label: 'Suomi' }, - { key: 'pl-PL', label: 'Polski' }, - { key: 'sv-SE', label: 'Svenska' }, - { key: 'ar-SA', label: 'العربية', direction: 'rtl' } + { key: 'cs', label: 'Čeština' }, + { key: 'da', label: 'Dansk' }, + { key: 'fi', label: 'Suomi' }, + { key: 'pl', label: 'Polski' }, + { key: 'sv', label: 'Svenska' }, + { key: 'ar', label: 'العربية', direction: 'rtl' } ]; diff --git a/lib/core/src/lib/common/services/user-preferences.service.ts b/lib/core/src/lib/common/services/user-preferences.service.ts index 2d1bfaf439..5577feb04d 100644 --- a/lib/core/src/lib/common/services/user-preferences.service.ts +++ b/lib/core/src/lib/common/services/user-preferences.service.ts @@ -352,12 +352,7 @@ export class UserPreferencesService { if (Array.isArray(customLanguages)) { language = customLanguages.find((customLanguage) => key.includes(customLanguage.key)); } - // Try exact match first, then try base language (e.g., 'ar' matches 'ar-SA') - language ??= DEFAULT_LANGUAGE_LIST.find((defaultLang) => defaultLang.key === key); - language ??= DEFAULT_LANGUAGE_LIST.find( - (defaultLang) => defaultLang.key.startsWith(key + '-') || key.startsWith(defaultLang.key.split('-')[0]) - ); - language ??= defaultLanguage; + language ??= DEFAULT_LANGUAGE_LIST.find((defaultLang) => defaultLang.key === key) ?? defaultLanguage; return language; } } diff --git a/lib/core/src/lib/common/utils/date-fns-utils.spec.ts b/lib/core/src/lib/common/utils/date-fns-utils.spec.ts index d9442e22d4..8ee1b95184 100644 --- a/lib/core/src/lib/common/utils/date-fns-utils.spec.ts +++ b/lib/core/src/lib/common/utils/date-fns-utils.spec.ts @@ -16,45 +16,29 @@ */ import { addMinutes, isValid } from 'date-fns'; -import { ar, arSA, cs, da, de, enGB, enUS, es, fi, fr, it as italian, ja, nb, nl, pl, pt, ptBR, ru, sv, zhCN } from 'date-fns/locale'; +import { ar, cs, da, de, enUS, es, fi, fr, it as italian, ja, nb, nl, pl, ptBR, ru, sv, zhCN } from 'date-fns/locale'; import { DateFnsUtils } from './date-fns-utils'; describe('DateFnsUtils', () => { describe('getLocaleFromString', () => { const localeTestCases = [ - { localeCode: 'ar-SA', expectedLocale: arSA, description: 'Arabic (Saudi Arabia)' }, { localeCode: 'ar', expectedLocale: ar, description: 'Arabic' }, - { localeCode: 'cs-CZ', expectedLocale: cs, description: 'Czech' }, - { localeCode: 'cs', expectedLocale: cs, description: 'Czech (short)' }, - { localeCode: 'da-DK', expectedLocale: da, description: 'Danish' }, - { localeCode: 'da', expectedLocale: da, description: 'Danish (short)' }, - { localeCode: 'de-DE', expectedLocale: de, description: 'German' }, - { localeCode: 'de', expectedLocale: de, description: 'German (short)' }, - { localeCode: 'en-GB', expectedLocale: enGB, description: 'English (UK)' }, + { localeCode: 'cs', expectedLocale: cs, description: 'Czech' }, + { localeCode: 'da', expectedLocale: da, description: 'Danish' }, + { localeCode: 'de', expectedLocale: de, description: 'German' }, { localeCode: 'en', expectedLocale: enUS, description: 'English (US)' }, - { localeCode: 'es-ES', expectedLocale: es, description: 'Spanish' }, - { localeCode: 'es', expectedLocale: es, description: 'Spanish (short)' }, - { localeCode: 'fi-FI', expectedLocale: fi, description: 'Finnish' }, - { localeCode: 'fi', expectedLocale: fi, description: 'Finnish (short)' }, - { localeCode: 'fr-FR', expectedLocale: fr, description: 'French' }, - { localeCode: 'fr', expectedLocale: fr, description: 'French (short)' }, - { localeCode: 'it-IT', expectedLocale: italian, description: 'Italian' }, - { localeCode: 'it', expectedLocale: italian, description: 'Italian (short)' }, - { localeCode: 'ja-JP', expectedLocale: ja, description: 'Japanese' }, - { localeCode: 'ja', expectedLocale: ja, description: 'Japanese (short)' }, - { localeCode: 'nb-NO', expectedLocale: nb, description: 'Norwegian Bokmål' }, - { localeCode: 'nb', expectedLocale: nb, description: 'Norwegian Bokmål (short)' }, - { localeCode: 'nl-NL', expectedLocale: nl, description: 'Dutch' }, - { localeCode: 'nl', expectedLocale: nl, description: 'Dutch (short)' }, - { localeCode: 'pl-PL', expectedLocale: pl, description: 'Polish' }, - { localeCode: 'pl', expectedLocale: pl, description: 'Polish (short)' }, - { localeCode: 'pt-PT', expectedLocale: pt, description: 'Portuguese (Portugal)' }, + { localeCode: 'es', expectedLocale: es, description: 'Spanish' }, + { localeCode: 'fi', expectedLocale: fi, description: 'Finnish' }, + { localeCode: 'fr', expectedLocale: fr, description: 'French' }, + { localeCode: 'it', expectedLocale: italian, description: 'Italian' }, + { localeCode: 'ja', expectedLocale: ja, description: 'Japanese' }, + { localeCode: 'nb', expectedLocale: nb, description: 'Norwegian Bokmål' }, + { localeCode: 'nl', expectedLocale: nl, description: 'Dutch' }, + { localeCode: 'pl', expectedLocale: pl, description: 'Polish' }, + { localeCode: 'pt', expectedLocale: ptBR, description: 'Portuguese' }, { localeCode: 'pt-BR', expectedLocale: ptBR, description: 'Portuguese (Brazilian)' }, - { localeCode: 'pt', expectedLocale: ptBR, description: 'Portuguese (short)' }, - { localeCode: 'ru-RU', expectedLocale: ru, description: 'Russian' }, - { localeCode: 'ru', expectedLocale: ru, description: 'Russian (short)' }, - { localeCode: 'sv-SE', expectedLocale: sv, description: 'Swedish' }, - { localeCode: 'sv', expectedLocale: sv, description: 'Swedish (short)' }, + { localeCode: 'ru', expectedLocale: ru, description: 'Russian' }, + { localeCode: 'sv', expectedLocale: sv, description: 'Swedish' }, { localeCode: 'zh-CN', expectedLocale: zhCN, description: 'Chinese (Simplified)' } ]; diff --git a/lib/core/src/lib/common/utils/date-fns-utils.ts b/lib/core/src/lib/common/utils/date-fns-utils.ts index 10f36321c3..3e9e3f4ff1 100644 --- a/lib/core/src/lib/common/utils/date-fns-utils.ts +++ b/lib/core/src/lib/common/utils/date-fns-utils.ts @@ -16,7 +16,7 @@ */ import { format, parse, parseISO, isValid, isBefore, isAfter } from 'date-fns'; -import { ar, arSA, cs, da, de, enGB, enUS, es, fi, fr, it, ja, nb, nl, pl, pt, ptBR, ru, sv, zhCN } from 'date-fns/locale'; +import { ar, cs, da, de, enUS, es, fi, fr, it, ja, nb, nl, pl, ptBR, ru, sv, zhCN } from 'date-fns/locale'; const panDate = (num: number = 1): string => { let text = num.toString(); @@ -27,46 +27,66 @@ const panDate = (num: number = 1): string => { }; export class DateFnsUtils { - private static readonly localeMap: Record = { - 'ar-SA': arSA, - ar: ar, - 'cs-CZ': cs, - cs: cs, - 'da-DK': da, - da: da, - 'de-DE': de, - de: de, - 'en-GB': enGB, - 'en-AU': enGB, - en: enUS, - 'es-ES': es, - es: es, - 'fi-FI': fi, - fi: fi, - 'fr-FR': fr, - fr: fr, - 'it-IT': it, - it: it, - 'ja-JP': ja, - ja: ja, - 'nb-NO': nb, - nb: nb, - 'nl-NL': nl, - nl: nl, - 'pl-PL': pl, - pl: pl, - 'pt-PT': pt, - 'pt-BR': ptBR, - pt: ptBR, - 'ru-RU': ru, - ru: ru, - 'sv-SE': sv, - sv: sv, - 'zh-CN': zhCN - }; - static getLocaleFromString(locale: string): Locale { - return this.localeMap[locale] ?? enUS; + let dateFnsLocale: Locale; + switch (locale) { + case 'ar': + dateFnsLocale = ar; + break; + case 'cs': + dateFnsLocale = cs; + break; + case 'da': + dateFnsLocale = da; + break; + case 'de': + dateFnsLocale = de; + break; + case 'en': + dateFnsLocale = enUS; + break; + case 'es': + dateFnsLocale = es; + break; + case 'fi': + dateFnsLocale = fi; + break; + case 'fr': + dateFnsLocale = fr; + break; + case 'it': + dateFnsLocale = it; + break; + case 'ja': + dateFnsLocale = ja; + break; + case 'nb': + dateFnsLocale = nb; + break; + case 'nl': + dateFnsLocale = nl; + break; + case 'pl': + dateFnsLocale = pl; + break; + case 'pt': + case 'pt-BR': + dateFnsLocale = ptBR; + break; + case 'ru': + dateFnsLocale = ru; + break; + case 'sv': + dateFnsLocale = sv; + break; + case 'zh-CN': + dateFnsLocale = zhCN; + break; + default: + dateFnsLocale = enUS; + break; + } + return dateFnsLocale; } private static readonly momentToDateFnsMap = { diff --git a/lib/core/src/lib/datatable/components/date-cell/date-cell.component.ts b/lib/core/src/lib/datatable/components/date-cell/date-cell.component.ts index 1b63470cdb..7c18301696 100644 --- a/lib/core/src/lib/datatable/components/date-cell/date-cell.component.ts +++ b/lib/core/src/lib/datatable/components/date-cell/date-cell.component.ts @@ -74,7 +74,7 @@ export class DateCellComponent extends DataTableCellComponent implements OnInit super(); // Use effect to react to locale signal changes (must be in injection context) effect(() => { - this.userLocale = this.userPreferencesService.localeSignal() || 'en-GB'; + this.userLocale = this.userPreferencesService.localeSignal() || 'en'; this.setConfig(); }); } diff --git a/lib/core/src/lib/i18n/ar-SA.json b/lib/core/src/lib/i18n/ar.json similarity index 100% rename from lib/core/src/lib/i18n/ar-SA.json rename to lib/core/src/lib/i18n/ar.json diff --git a/lib/core/src/lib/i18n/cs-CZ.json b/lib/core/src/lib/i18n/cs.json similarity index 100% rename from lib/core/src/lib/i18n/cs-CZ.json rename to lib/core/src/lib/i18n/cs.json diff --git a/lib/core/src/lib/i18n/da-DK.json b/lib/core/src/lib/i18n/da.json similarity index 100% rename from lib/core/src/lib/i18n/da-DK.json rename to lib/core/src/lib/i18n/da.json diff --git a/lib/core/src/lib/i18n/de-DE.json b/lib/core/src/lib/i18n/de.json similarity index 100% rename from lib/core/src/lib/i18n/de-DE.json rename to lib/core/src/lib/i18n/de.json diff --git a/lib/core/src/lib/i18n/es-ES.json b/lib/core/src/lib/i18n/es.json similarity index 100% rename from lib/core/src/lib/i18n/es-ES.json rename to lib/core/src/lib/i18n/es.json diff --git a/lib/core/src/lib/i18n/fi-FI.json b/lib/core/src/lib/i18n/fi.json similarity index 100% rename from lib/core/src/lib/i18n/fi-FI.json rename to lib/core/src/lib/i18n/fi.json diff --git a/lib/core/src/lib/i18n/fr-FR.json b/lib/core/src/lib/i18n/fr.json similarity index 100% rename from lib/core/src/lib/i18n/fr-FR.json rename to lib/core/src/lib/i18n/fr.json diff --git a/lib/core/src/lib/i18n/it-IT.json b/lib/core/src/lib/i18n/it.json similarity index 100% rename from lib/core/src/lib/i18n/it-IT.json rename to lib/core/src/lib/i18n/it.json diff --git a/lib/core/src/lib/i18n/ja-JP.json b/lib/core/src/lib/i18n/ja.json similarity index 100% rename from lib/core/src/lib/i18n/ja-JP.json rename to lib/core/src/lib/i18n/ja.json diff --git a/lib/core/src/lib/i18n/nb-NO.json b/lib/core/src/lib/i18n/nb.json similarity index 100% rename from lib/core/src/lib/i18n/nb-NO.json rename to lib/core/src/lib/i18n/nb.json diff --git a/lib/core/src/lib/i18n/nl-NL.json b/lib/core/src/lib/i18n/nl.json similarity index 100% rename from lib/core/src/lib/i18n/nl-NL.json rename to lib/core/src/lib/i18n/nl.json diff --git a/lib/core/src/lib/i18n/pl-PL.json b/lib/core/src/lib/i18n/pl.json similarity index 100% rename from lib/core/src/lib/i18n/pl-PL.json rename to lib/core/src/lib/i18n/pl.json diff --git a/lib/core/src/lib/i18n/pt-PT.json b/lib/core/src/lib/i18n/pt.json similarity index 100% rename from lib/core/src/lib/i18n/pt-PT.json rename to lib/core/src/lib/i18n/pt.json diff --git a/lib/core/src/lib/i18n/ru-RU.json b/lib/core/src/lib/i18n/ru.json similarity index 100% rename from lib/core/src/lib/i18n/ru-RU.json rename to lib/core/src/lib/i18n/ru.json diff --git a/lib/core/src/lib/i18n/sv-SE.json b/lib/core/src/lib/i18n/sv.json similarity index 100% rename from lib/core/src/lib/i18n/sv-SE.json rename to lib/core/src/lib/i18n/sv.json diff --git a/lib/core/src/lib/mock/language.service.mock.ts b/lib/core/src/lib/mock/language.service.mock.ts index 1da65df02c..c6e7376bb5 100644 --- a/lib/core/src/lib/mock/language.service.mock.ts +++ b/lib/core/src/lib/mock/language.service.mock.ts @@ -23,23 +23,23 @@ import { LanguageItem } from '../common/services/language-item.interface'; @Injectable() export class LanguageServiceMock implements LanguageServiceInterface { private readonly languages = new BehaviorSubject([ - { key: 'de-DE', label: 'Deutsch' }, + { key: 'de', label: 'Deutsch' }, { key: 'en', label: 'English' }, - { key: 'es-ES', label: 'Español' }, - { key: 'fr-FR', label: 'Français' }, - { key: 'it-IT', label: 'Italiano' }, - { key: 'ja-JP', label: '日本語' }, - { key: 'nb-NO', label: 'Bokmål' }, - { key: 'nl-NL', label: 'Nederlands' }, + { key: 'es', label: 'Español' }, + { key: 'fr', label: 'Français' }, + { key: 'it', label: 'Italiano' }, + { key: 'ja', label: '日本語' }, + { key: 'nb', label: 'Bokmål' }, + { key: 'nl', label: 'Nederlands' }, { key: 'pt-BR', label: 'Português (Brasil)' }, - { key: 'ru-RU', label: 'Русский' }, + { key: 'ru', label: 'Русский' }, { key: 'zh-CN', label: '中文简体' }, - { key: 'cs-CZ', label: 'Čeština' }, - { key: 'da-DK', label: 'Dansk' }, - { key: 'fi-FI', label: 'Suomi' }, - { key: 'pl-PL', label: 'Polski' }, - { key: 'sv-SE', label: 'Svenska' }, - { key: 'ar-SA', label: 'العربية', direction: 'rtl' } + { key: 'cs', label: 'Čeština' }, + { key: 'da', label: 'Dansk' }, + { key: 'fi', label: 'Suomi' }, + { key: 'pl', label: 'Polski' }, + { key: 'sv', label: 'Svenska' }, + { key: 'ar', label: 'العربية', direction: 'rtl' } ]); languages$ = this.languages.asObservable(); diff --git a/lib/core/src/lib/stories/core-story.providers.ts b/lib/core/src/lib/stories/core-story.providers.ts index b6e961e75a..f510432ce4 100644 --- a/lib/core/src/lib/stories/core-story.providers.ts +++ b/lib/core/src/lib/stories/core-story.providers.ts @@ -42,7 +42,7 @@ export function provideStoryCore(): (Provider | EnvironmentProviders)[] { provideCoreAuthTesting(), provideAppInitializer(() => { const appConfig = inject(AppConfigService); - appConfig.config = { ...appConfig.config, locale: 'en-GB' }; + appConfig.config = { ...appConfig.config, locale: 'en' }; }), provideRouter([], withHashLocation()) ]; diff --git a/lib/core/src/lib/translation/translate-loader.service.ts b/lib/core/src/lib/translation/translate-loader.service.ts index 143a02b7b0..d48656a8eb 100644 --- a/lib/core/src/lib/translation/translate-loader.service.ts +++ b/lib/core/src/lib/translation/translate-loader.service.ts @@ -21,7 +21,7 @@ import { TranslateLoader } from '@ngx-translate/core'; import { Observable, forkJoin, throwError, of } from 'rxjs'; import { ComponentTranslationModel } from '../models/component.model'; import { ObjectUtils } from '../common/utils/object-utils'; -import { map, catchError } from 'rxjs/operators'; +import { map, catchError, retry } from 'rxjs/operators'; @Injectable({ providedIn: 'root' @@ -40,33 +40,8 @@ export class TranslateLoaderService implements TranslateLoader { private queue: string[][] = []; private defaultLang: string = 'en'; - private readonly localeAliases: Record = { - 'en-US': 'en', - 'en-GB': 'en', - 'en-AU': 'en', - de: 'de-DE', - es: 'es-ES', - fr: 'fr-FR', - it: 'it-IT', - ja: 'ja-JP', - nb: 'nb-NO', - nl: 'nl-NL', - ru: 'ru-RU', - cs: 'cs-CZ', - da: 'da-DK', - fi: 'fi-FI', - pl: 'pl-PL', - sv: 'sv-SE', - ar: 'ar-SA', - pt: 'pt-BR' - }; - - setDefaultLang(lang: string): void { - this.defaultLang = lang; - } - - getDefaultLang(): string { - return this.defaultLang; + setDefaultLang(value: string) { + this.defaultLang = value || 'en'; } registerProvider(name: string, path: string) { @@ -82,49 +57,23 @@ export class TranslateLoaderService implements TranslateLoader { return this.providers.some((x) => x.name === name); } - private resolveLocale(lang: string): string { - if (this.localeAliases[lang]) { - return this.localeAliases[lang]; - } - return lang; - } - - private getLocaleFallbacks(lang: string): string[] { - const fallbacks: string[] = [lang]; - const resolved = this.resolveLocale(lang); - if (resolved !== lang) { - fallbacks.push(resolved); - } - const baseLang = lang.split('-')[0]; - if (baseLang !== lang && !fallbacks.includes(baseLang)) { - const resolvedBase = this.resolveLocale(baseLang); - if (!fallbacks.includes(resolvedBase)) { - fallbacks.push(resolvedBase); - } - } - return fallbacks; - } - - fetchLanguageFile(lang: string, component: ComponentTranslationModel): Observable { - const fallbacks = this.getLocaleFallbacks(lang); - return this.tryFetchWithFallbacks(lang, fallbacks, component); - } - - private tryFetchWithFallbacks(originalLang: string, fallbacks: string[], component: ComponentTranslationModel): Observable { - if (fallbacks.length === 0) { - return throwError(() => new Error(`Failed to load translations for ${originalLang}`)); - } - - const [currentLocale, ...remainingFallbacks] = fallbacks; - const translationUrl = `${component.path}/${this.prefix}/${currentLocale}${this.suffix}?v=${Date.now()}`; + fetchLanguageFile(lang: string, component: ComponentTranslationModel, fallbackUrl?: string): Observable { + const translationUrl = fallbackUrl || `${component.path}/${this.prefix}/${lang}${this.suffix}?v=${Date.now()}`; return this.http.get(translationUrl).pipe( map((res: any) => { - component.json[originalLang] = res; + component.json[lang] = res; }), + retry(3), catchError(() => { - if (remainingFallbacks.length > 0) { - return this.tryFetchWithFallbacks(originalLang, remainingFallbacks, component); + if (!fallbackUrl && lang.includes('-')) { + const [langId] = lang.split('-'); + + if (langId && langId !== this.defaultLang) { + const url = `${component.path}/${this.prefix}/${langId}${this.suffix}?v=${Date.now()}`; + + return this.fetchLanguageFile(lang, component, url); + } } return throwError(() => new Error(`Failed to load ${translationUrl}`)); }) diff --git a/lib/core/src/lib/translation/translate-loader.spec.ts b/lib/core/src/lib/translation/translate-loader.spec.ts index 683998aa0e..d1da33693c 100644 --- a/lib/core/src/lib/translation/translate-loader.spec.ts +++ b/lib/core/src/lib/translation/translate-loader.spec.ts @@ -17,7 +17,6 @@ import { fakeAsync, TestBed, tick } from '@angular/core/testing'; import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing'; -import { provideHttpClient } from '@angular/common/http'; import { TranslateLoaderService } from './translate-loader.service'; describe('TranslateLoader', () => { @@ -26,7 +25,7 @@ describe('TranslateLoader', () => { beforeEach(() => { TestBed.configureTestingModule({ - providers: [provideHttpClient(), provideHttpClientTesting(), TranslateLoaderService] + providers: [provideHttpClientTesting(), TranslateLoaderService] }); customLoader = TestBed.inject(TranslateLoaderService); httpMock = TestBed.inject(HttpTestingController); @@ -61,107 +60,4 @@ describe('TranslateLoader', () => { subscription.unsubscribe(); httpMock.verify(); })); - - describe('locale fallback', () => { - it('should fallback from en-US to en when en-US file does not exist', fakeAsync(() => { - let nextInvoked = false; - - const subscription = customLoader.getTranslation('en-US').subscribe({ - next: () => (nextInvoked = true), - error: () => fail('Should not call error handler') - }); - - const enUsRequest = httpMock.expectOne((request) => request.url.includes('assets/adf-core/i18n/en-US.json')); - enUsRequest.flush(null, { status: 404, statusText: 'Not Found' }); - tick(); - - const enRequest = httpMock.expectOne((request) => request.url.includes('assets/adf-core/i18n/en.json')); - enRequest.flush({ 'TEST.KEY': 'Test value' }); - tick(); - - expect(nextInvoked).toBeTrue(); - subscription.unsubscribe(); - httpMock.verify(); - })); - - it('should fallback from en-GB to en when en-GB file does not exist', fakeAsync(() => { - let nextInvoked = false; - - const subscription = customLoader.getTranslation('en-GB').subscribe({ - next: () => (nextInvoked = true), - error: () => fail('Should not call error handler') - }); - - const enGbRequest = httpMock.expectOne((request) => request.url.includes('assets/adf-core/i18n/en-GB.json')); - enGbRequest.flush(null, { status: 404, statusText: 'Not Found' }); - tick(); - - const enRequest = httpMock.expectOne((request) => request.url.includes('assets/adf-core/i18n/en.json')); - enRequest.flush({ 'TEST.KEY': 'Test value' }); - tick(); - - expect(nextInvoked).toBeTrue(); - subscription.unsubscribe(); - httpMock.verify(); - })); - - it('should fallback from short locale (de) to full locale (de-DE)', fakeAsync(() => { - let nextInvoked = false; - - const subscription = customLoader.getTranslation('de').subscribe({ - next: () => (nextInvoked = true), - error: () => fail('Should not call error handler') - }); - - const deRequest = httpMock.expectOne((request) => request.url.includes('assets/adf-core/i18n/de.json')); - deRequest.flush(null, { status: 404, statusText: 'Not Found' }); - tick(); - - const deDeRequest = httpMock.expectOne((request) => request.url.includes('assets/adf-core/i18n/de-DE.json')); - deDeRequest.flush({ 'TEST.KEY': 'Testwert' }); - tick(); - - expect(nextInvoked).toBeTrue(); - subscription.unsubscribe(); - httpMock.verify(); - })); - - it('should use the file directly when it exists without fallback', fakeAsync(() => { - let nextInvoked = false; - - const subscription = customLoader.getTranslation('fr-FR').subscribe({ - next: () => (nextInvoked = true), - error: () => fail('Should not call error handler') - }); - - const frFrRequest = httpMock.expectOne((request) => request.url.includes('assets/adf-core/i18n/fr-FR.json')); - frFrRequest.flush({ 'TEST.KEY': 'Valeur de test' }); - tick(); - - expect(nextInvoked).toBeTrue(); - subscription.unsubscribe(); - httpMock.verify(); - })); - - it('should register translations under the original requested locale', fakeAsync(() => { - let translationResult: any; - - const subscription = customLoader.getTranslation('en-US').subscribe({ - next: (result) => (translationResult = result), - error: () => fail('Should not call error handler') - }); - - const enUsRequest = httpMock.expectOne((request) => request.url.includes('assets/adf-core/i18n/en-US.json')); - enUsRequest.flush(null, { status: 404, statusText: 'Not Found' }); - tick(); - - const enRequest = httpMock.expectOne((request) => request.url.includes('assets/adf-core/i18n/en.json')); - enRequest.flush({ 'TEST.KEY': 'Test value' }); - tick(); - - expect(translationResult).toEqual({ 'TEST.KEY': 'Test value' }); - subscription.unsubscribe(); - httpMock.verify(); - })); - }); }); diff --git a/lib/core/src/lib/translation/translation.service.spec.ts b/lib/core/src/lib/translation/translation.service.spec.ts index 7abc353bfd..a580237ec7 100644 --- a/lib/core/src/lib/translation/translation.service.spec.ts +++ b/lib/core/src/lib/translation/translation.service.spec.ts @@ -29,6 +29,10 @@ describe('TranslationService', () => { // No implementation needed for this test }; + setDefaultLang = (_lang: string): void => { + // No implementation needed for this test + }; + getTranslation = (lang: string) => { const translations = { en: { diff --git a/lib/core/src/lib/translation/translation.service.ts b/lib/core/src/lib/translation/translation.service.ts index 3fe8c59cb2..94a57d46b0 100644 --- a/lib/core/src/lib/translation/translation.service.ts +++ b/lib/core/src/lib/translation/translation.service.ts @@ -62,10 +62,8 @@ export class TranslationService { this.customLoader = this.translate.currentLoader as TranslateLoaderService; this.defaultLang = 'en'; - if (typeof this.customLoader?.setDefaultLang === 'function') { - this.customLoader.setDefaultLang(this.defaultLang); - } this.translate.setFallbackLang(this.defaultLang); + this.customLoader.setDefaultLang(this.defaultLang); if (this.providers && this.providers.length > 0) { for (const provider of this.providers) { diff --git a/lib/insights/karma.conf.js b/lib/insights/karma.conf.js index 9fea99cedb..a102bb44cc 100644 --- a/lib/insights/karma.conf.js +++ b/lib/insights/karma.conf.js @@ -17,7 +17,7 @@ module.exports = function (config) { served: true, watched: false }, - { pattern: 'lib/insights/src/lib/i18n/**/en-GB.json', included: false, served: true, watched: false }, + { pattern: 'lib/insights/src/lib/i18n/**/en.json', included: false, served: true, watched: false }, { pattern: 'lib/config/app.config.json', included: false, served: true, watched: false } ], @@ -25,7 +25,7 @@ module.exports = function (config) { proxies: { '/base/assets/': '/base/lib/insights/src/lib/assets/', - '/assets/adf-insights/i18n/en-GB.json': '/base/lib/insights/src/lib/i18n/en-GB.json', + '/assets/adf-insights/i18n/en.json': '/base/lib/insights/src/lib/i18n/en.json', '/app.config.json': '/base/lib/config/app.config.json' }, diff --git a/lib/insights/src/lib/i18n/ar-SA.json b/lib/insights/src/lib/i18n/ar.json similarity index 100% rename from lib/insights/src/lib/i18n/ar-SA.json rename to lib/insights/src/lib/i18n/ar.json diff --git a/lib/insights/src/lib/i18n/cs-CZ.json b/lib/insights/src/lib/i18n/cs.json similarity index 100% rename from lib/insights/src/lib/i18n/cs-CZ.json rename to lib/insights/src/lib/i18n/cs.json diff --git a/lib/insights/src/lib/i18n/da-DK.json b/lib/insights/src/lib/i18n/da.json similarity index 100% rename from lib/insights/src/lib/i18n/da-DK.json rename to lib/insights/src/lib/i18n/da.json diff --git a/lib/insights/src/lib/i18n/de-DE.json b/lib/insights/src/lib/i18n/de.json similarity index 100% rename from lib/insights/src/lib/i18n/de-DE.json rename to lib/insights/src/lib/i18n/de.json diff --git a/lib/insights/src/lib/i18n/es-ES.json b/lib/insights/src/lib/i18n/es.json similarity index 100% rename from lib/insights/src/lib/i18n/es-ES.json rename to lib/insights/src/lib/i18n/es.json diff --git a/lib/insights/src/lib/i18n/fi-FI.json b/lib/insights/src/lib/i18n/fi.json similarity index 100% rename from lib/insights/src/lib/i18n/fi-FI.json rename to lib/insights/src/lib/i18n/fi.json diff --git a/lib/insights/src/lib/i18n/fr-FR.json b/lib/insights/src/lib/i18n/fr.json similarity index 100% rename from lib/insights/src/lib/i18n/fr-FR.json rename to lib/insights/src/lib/i18n/fr.json diff --git a/lib/insights/src/lib/i18n/it-IT.json b/lib/insights/src/lib/i18n/it.json similarity index 100% rename from lib/insights/src/lib/i18n/it-IT.json rename to lib/insights/src/lib/i18n/it.json diff --git a/lib/insights/src/lib/i18n/ja-JP.json b/lib/insights/src/lib/i18n/ja.json similarity index 100% rename from lib/insights/src/lib/i18n/ja-JP.json rename to lib/insights/src/lib/i18n/ja.json diff --git a/lib/insights/src/lib/i18n/nb-NO.json b/lib/insights/src/lib/i18n/nb.json similarity index 100% rename from lib/insights/src/lib/i18n/nb-NO.json rename to lib/insights/src/lib/i18n/nb.json diff --git a/lib/insights/src/lib/i18n/nl-NL.json b/lib/insights/src/lib/i18n/nl.json similarity index 100% rename from lib/insights/src/lib/i18n/nl-NL.json rename to lib/insights/src/lib/i18n/nl.json diff --git a/lib/insights/src/lib/i18n/pl-PL.json b/lib/insights/src/lib/i18n/pl.json similarity index 100% rename from lib/insights/src/lib/i18n/pl-PL.json rename to lib/insights/src/lib/i18n/pl.json diff --git a/lib/insights/src/lib/i18n/pt-PT.json b/lib/insights/src/lib/i18n/pt.json similarity index 100% rename from lib/insights/src/lib/i18n/pt-PT.json rename to lib/insights/src/lib/i18n/pt.json diff --git a/lib/insights/src/lib/i18n/ru-RU.json b/lib/insights/src/lib/i18n/ru.json similarity index 100% rename from lib/insights/src/lib/i18n/ru-RU.json rename to lib/insights/src/lib/i18n/ru.json diff --git a/lib/insights/src/lib/i18n/sv-SE.json b/lib/insights/src/lib/i18n/sv.json similarity index 100% rename from lib/insights/src/lib/i18n/sv-SE.json rename to lib/insights/src/lib/i18n/sv.json diff --git a/lib/process-services-cloud/karma.conf.js b/lib/process-services-cloud/karma.conf.js index 31a01343c9..b0d7c302ba 100644 --- a/lib/process-services-cloud/karma.conf.js +++ b/lib/process-services-cloud/karma.conf.js @@ -30,8 +30,8 @@ module.exports = function (config) { '/base/assets/': '/base/lib/process-services/assets/', '/assets/adf-core/i18n/en.json': '/base/lib/core/src/lib/i18n/en.json', '/assets/adf-core/i18n/en-GB.json': '/base/lib/core/src/lib/i18n/en.json', - '/assets/adf-process-services-cloud/i18n/en.json': '/base/lib/process-services-cloud/src/lib/i18n/en.json', - '/assets/adf-process-services-cloud/i18n/en-GB.json': '/base/lib/process-services-cloud/src/lib/i18n/en.json', + '/assets/adf-process-services-cloud/i18n/en.json': '/base/lib/process-services-cloud/lib/i18n/en.json', + '/assets/adf-process-services-cloud/i18n/en-GB.json': '/base/lib/process-services-cloud/lib/i18n/en.json', '/app.config.json': '/base/lib/config/app.config.json' }, plugins: [ diff --git a/lib/process-services-cloud/src/lib/i18n/ar-SA.json b/lib/process-services-cloud/src/lib/i18n/ar.json similarity index 100% rename from lib/process-services-cloud/src/lib/i18n/ar-SA.json rename to lib/process-services-cloud/src/lib/i18n/ar.json diff --git a/lib/process-services-cloud/src/lib/i18n/cs-CZ.json b/lib/process-services-cloud/src/lib/i18n/cs.json similarity index 100% rename from lib/process-services-cloud/src/lib/i18n/cs-CZ.json rename to lib/process-services-cloud/src/lib/i18n/cs.json diff --git a/lib/process-services-cloud/src/lib/i18n/da-DK.json b/lib/process-services-cloud/src/lib/i18n/da.json similarity index 100% rename from lib/process-services-cloud/src/lib/i18n/da-DK.json rename to lib/process-services-cloud/src/lib/i18n/da.json diff --git a/lib/process-services-cloud/src/lib/i18n/de-DE.json b/lib/process-services-cloud/src/lib/i18n/de.json similarity index 100% rename from lib/process-services-cloud/src/lib/i18n/de-DE.json rename to lib/process-services-cloud/src/lib/i18n/de.json diff --git a/lib/process-services-cloud/src/lib/i18n/es-ES.json b/lib/process-services-cloud/src/lib/i18n/es.json similarity index 100% rename from lib/process-services-cloud/src/lib/i18n/es-ES.json rename to lib/process-services-cloud/src/lib/i18n/es.json diff --git a/lib/process-services-cloud/src/lib/i18n/fi-FI.json b/lib/process-services-cloud/src/lib/i18n/fi.json similarity index 100% rename from lib/process-services-cloud/src/lib/i18n/fi-FI.json rename to lib/process-services-cloud/src/lib/i18n/fi.json diff --git a/lib/process-services-cloud/src/lib/i18n/fr-FR.json b/lib/process-services-cloud/src/lib/i18n/fr.json similarity index 100% rename from lib/process-services-cloud/src/lib/i18n/fr-FR.json rename to lib/process-services-cloud/src/lib/i18n/fr.json diff --git a/lib/process-services-cloud/src/lib/i18n/it-IT.json b/lib/process-services-cloud/src/lib/i18n/it.json similarity index 100% rename from lib/process-services-cloud/src/lib/i18n/it-IT.json rename to lib/process-services-cloud/src/lib/i18n/it.json diff --git a/lib/process-services-cloud/src/lib/i18n/ja-JP.json b/lib/process-services-cloud/src/lib/i18n/ja.json similarity index 100% rename from lib/process-services-cloud/src/lib/i18n/ja-JP.json rename to lib/process-services-cloud/src/lib/i18n/ja.json diff --git a/lib/process-services-cloud/src/lib/i18n/nb-NO.json b/lib/process-services-cloud/src/lib/i18n/nb.json similarity index 100% rename from lib/process-services-cloud/src/lib/i18n/nb-NO.json rename to lib/process-services-cloud/src/lib/i18n/nb.json diff --git a/lib/process-services-cloud/src/lib/i18n/nl-NL.json b/lib/process-services-cloud/src/lib/i18n/nl.json similarity index 100% rename from lib/process-services-cloud/src/lib/i18n/nl-NL.json rename to lib/process-services-cloud/src/lib/i18n/nl.json diff --git a/lib/process-services-cloud/src/lib/i18n/pl-PL.json b/lib/process-services-cloud/src/lib/i18n/pl.json similarity index 100% rename from lib/process-services-cloud/src/lib/i18n/pl-PL.json rename to lib/process-services-cloud/src/lib/i18n/pl.json diff --git a/lib/process-services-cloud/src/lib/i18n/pt-PT.json b/lib/process-services-cloud/src/lib/i18n/pt.json similarity index 100% rename from lib/process-services-cloud/src/lib/i18n/pt-PT.json rename to lib/process-services-cloud/src/lib/i18n/pt.json diff --git a/lib/process-services-cloud/src/lib/i18n/ru-RU.json b/lib/process-services-cloud/src/lib/i18n/ru.json similarity index 100% rename from lib/process-services-cloud/src/lib/i18n/ru-RU.json rename to lib/process-services-cloud/src/lib/i18n/ru.json diff --git a/lib/process-services-cloud/src/lib/i18n/sv-SE.json b/lib/process-services-cloud/src/lib/i18n/sv.json similarity index 100% rename from lib/process-services-cloud/src/lib/i18n/sv-SE.json rename to lib/process-services-cloud/src/lib/i18n/sv.json diff --git a/lib/process-services/src/lib/i18n/ar-SA.json b/lib/process-services/src/lib/i18n/ar.json similarity index 100% rename from lib/process-services/src/lib/i18n/ar-SA.json rename to lib/process-services/src/lib/i18n/ar.json diff --git a/lib/process-services/src/lib/i18n/cs-CZ.json b/lib/process-services/src/lib/i18n/cs.json similarity index 100% rename from lib/process-services/src/lib/i18n/cs-CZ.json rename to lib/process-services/src/lib/i18n/cs.json diff --git a/lib/process-services/src/lib/i18n/da-DK.json b/lib/process-services/src/lib/i18n/da.json similarity index 100% rename from lib/process-services/src/lib/i18n/da-DK.json rename to lib/process-services/src/lib/i18n/da.json diff --git a/lib/process-services/src/lib/i18n/de-DE.json b/lib/process-services/src/lib/i18n/de.json similarity index 100% rename from lib/process-services/src/lib/i18n/de-DE.json rename to lib/process-services/src/lib/i18n/de.json diff --git a/lib/process-services/src/lib/i18n/es-ES.json b/lib/process-services/src/lib/i18n/es.json similarity index 100% rename from lib/process-services/src/lib/i18n/es-ES.json rename to lib/process-services/src/lib/i18n/es.json diff --git a/lib/process-services/src/lib/i18n/fi-FI.json b/lib/process-services/src/lib/i18n/fi.json similarity index 100% rename from lib/process-services/src/lib/i18n/fi-FI.json rename to lib/process-services/src/lib/i18n/fi.json diff --git a/lib/process-services/src/lib/i18n/fr-FR.json b/lib/process-services/src/lib/i18n/fr.json similarity index 100% rename from lib/process-services/src/lib/i18n/fr-FR.json rename to lib/process-services/src/lib/i18n/fr.json diff --git a/lib/process-services/src/lib/i18n/it-IT.json b/lib/process-services/src/lib/i18n/it.json similarity index 100% rename from lib/process-services/src/lib/i18n/it-IT.json rename to lib/process-services/src/lib/i18n/it.json diff --git a/lib/process-services/src/lib/i18n/ja-JP.json b/lib/process-services/src/lib/i18n/ja.json similarity index 100% rename from lib/process-services/src/lib/i18n/ja-JP.json rename to lib/process-services/src/lib/i18n/ja.json diff --git a/lib/process-services/src/lib/i18n/nb-NO.json b/lib/process-services/src/lib/i18n/nb.json similarity index 100% rename from lib/process-services/src/lib/i18n/nb-NO.json rename to lib/process-services/src/lib/i18n/nb.json diff --git a/lib/process-services/src/lib/i18n/nl-NL.json b/lib/process-services/src/lib/i18n/nl.json similarity index 100% rename from lib/process-services/src/lib/i18n/nl-NL.json rename to lib/process-services/src/lib/i18n/nl.json diff --git a/lib/process-services/src/lib/i18n/pl-PL.json b/lib/process-services/src/lib/i18n/pl.json similarity index 100% rename from lib/process-services/src/lib/i18n/pl-PL.json rename to lib/process-services/src/lib/i18n/pl.json diff --git a/lib/process-services/src/lib/i18n/pt-PT.json b/lib/process-services/src/lib/i18n/pt.json similarity index 100% rename from lib/process-services/src/lib/i18n/pt-PT.json rename to lib/process-services/src/lib/i18n/pt.json diff --git a/lib/process-services/src/lib/i18n/ru-RU.json b/lib/process-services/src/lib/i18n/ru.json similarity index 100% rename from lib/process-services/src/lib/i18n/ru-RU.json rename to lib/process-services/src/lib/i18n/ru.json diff --git a/lib/process-services/src/lib/i18n/sv-SE.json b/lib/process-services/src/lib/i18n/sv.json similarity index 100% rename from lib/process-services/src/lib/i18n/sv-SE.json rename to lib/process-services/src/lib/i18n/sv.json