From f62fa79f649e619cfc29468fc6e9728485d89e0f Mon Sep 17 00:00:00 2001 From: erdemcaygor Date: Thu, 22 Jan 2026 18:52:12 +0300 Subject: [PATCH] hybrid localization --- .../packages/core/src/lib/models/common.ts | 20 +++++++++++++++++++ .../providers/core-module-config.provider.ts | 12 ++++++++++- .../packages/core/src/lib/services/index.ts | 1 + .../src/lib/services/localization.service.ts | 2 ++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/npm/ng-packs/packages/core/src/lib/models/common.ts b/npm/ng-packs/packages/core/src/lib/models/common.ts index 704fde958a..2e52e113aa 100644 --- a/npm/ng-packs/packages/core/src/lib/models/common.ts +++ b/npm/ng-packs/packages/core/src/lib/models/common.ts @@ -16,6 +16,26 @@ export namespace ABP { othersGroup?: string; dynamicLayouts?: Map; disableProjectNameInTitle?: boolean; + uiLocalization?: UILocalizationOptions; + } + + export interface UILocalizationOptions { + /** + * Enable UI localization support via @angular/localize + * When enabled, localization files are automatically loaded based on selected language + * Files should be located at: {basePath}/{culture}.json + * Example: /assets/localization/en.json + * JSON format: { "ResourceName": { "Key": "Value" } } + * Merges with backend localizations (UI > Backend priority) + */ + enabled?: boolean; + /** + * Base path for localization JSON files + * Default: '/assets/localization' + * Files should be located at: {basePath}/{culture}.json + * Example: /assets/localization/en.json + */ + basePath?: string; } export interface Child { diff --git a/npm/ng-packs/packages/core/src/lib/providers/core-module-config.provider.ts b/npm/ng-packs/packages/core/src/lib/providers/core-module-config.provider.ts index 6d46caedeb..08f1beb706 100644 --- a/npm/ng-packs/packages/core/src/lib/providers/core-module-config.provider.ts +++ b/npm/ng-packs/packages/core/src/lib/providers/core-module-config.provider.ts @@ -23,7 +23,12 @@ import { RoutesHandler } from '../handlers'; import { ABP, SortableItem } from '../models'; import { AuthErrorFilterService } from '../abstracts'; import { DEFAULT_DYNAMIC_LAYOUTS } from '../constants'; -import { LocalizationService, LocalStorageListenerService, AbpTitleStrategy } from '../services'; +import { + LocalizationService, + LocalStorageListenerService, + AbpTitleStrategy, + UILocalizationService, +} from '../services'; import { DefaultQueueManager, getInitialData } from '../utils'; import { CookieLanguageProvider, IncludeLocalizationResourcesProvider, LocaleProvider } from './'; import { timezoneInterceptor, transferStateInterceptor } from '../interceptors'; @@ -113,6 +118,11 @@ export function provideAbpCore(...features: CoreFeature[]) { inject(LocalizationService); inject(LocalStorageListenerService); inject(RoutesHandler); + // Initialize UILocalizationService if UI-only mode is enabled + const options = inject(CORE_OPTIONS); + if (options?.uiLocalization?.enabled) { + inject(UILocalizationService); + } await getInitialData(); }), LocaleProvider, diff --git a/npm/ng-packs/packages/core/src/lib/services/index.ts b/npm/ng-packs/packages/core/src/lib/services/index.ts index 61fd1ef480..205fd2f0dc 100644 --- a/npm/ng-packs/packages/core/src/lib/services/index.ts +++ b/npm/ng-packs/packages/core/src/lib/services/index.ts @@ -8,6 +8,7 @@ export * from './http-wait.service'; export * from './lazy-load.service'; export * from './list.service'; export * from './localization.service'; +export * from './ui-localization.service'; export * from './multi-tenancy.service'; export * from './permission.service'; export * from './replaceable-components.service'; diff --git a/npm/ng-packs/packages/core/src/lib/services/localization.service.ts b/npm/ng-packs/packages/core/src/lib/services/localization.service.ts index d91679effb..6ed442db5b 100644 --- a/npm/ng-packs/packages/core/src/lib/services/localization.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/localization.service.ts @@ -60,6 +60,8 @@ export class LocalizationService { private initLocalizationValues() { localizations$.subscribe(val => this.addLocalization(val)); + // Backend-based localization loading (always enabled) + // UI localizations are merged via addLocalization() (UI > Backend priority) const legacyResources$ = this.configState.getDeep$('localization.values') as Observable< Record> >;