@@ -12,135 +12,203 @@ import {
1212 dateRangePickerResourcesMap ,
1313} from './utils.js' ;
1414
15- interface I18nControllerHost extends ReactiveControllerHost , Element {
16- resourceStrings ?: any ;
15+ /**
16+ * Defines the structure for the host element that will use this controller.
17+ * The host must be a Lit element (ReactiveControllerHost) and an HTMLElement.
18+ */
19+ interface I18nControllerHost extends ReactiveControllerHost , HTMLElement {
20+ // Properties the host is expected to have/use, though they are managed by the controller.
21+ resourceStrings ?: unknown ;
1722 locale ?: string ;
1823}
1924
20- type I18nControllerConfig = {
21- defaultEN : any ;
22- onResourceChange ?: ( evt : CustomEvent < IResourceChangeEventArgs > ) => void ;
25+ type ResourceChangeCallback = (
26+ event : CustomEvent < IResourceChangeEventArgs >
27+ ) => unknown ;
28+
29+ /** Configuration object for the I18nController. */
30+ type I18nControllerConfig < T extends object > = {
31+ /** The full default English resource strings object for the component. */
32+ defaultEN : T ;
33+ /** An optional callback to execute when the global locale changes. */
34+ onResourceChange ?: ResourceChangeCallback ;
2335} ;
2436
25- export class I18nController < T > implements ReactiveController {
26- /** Set custom locale that overrides the global one. */
27- public set locale ( value : string ) {
28- this . _locale = value ;
29- this . _defaultResourceStrings = this . getCurrentResourceStrings ( ) ;
37+ /**
38+ * Manages localization (i18n) for a Lit web component.
39+ * It handles the current locale, component-specific resource overrides,
40+ * and updates when the global localization state changes.
41+ */
42+ class I18nController < T extends object > implements ReactiveController {
43+ //#region Internal properties and state
44+
45+ private readonly _host : I18nControllerHost ;
46+ private readonly _defaultEN : T ;
47+
48+ private _resourceChangeCallback ?: ResourceChangeCallback ;
49+ private _defaultResourceStrings : T ;
50+ private _locale ?: string ;
51+ private _resourceStrings ?: T ;
52+
53+ //#endregion
54+
55+ //#region Public properties
56+
57+ /**
58+ * Sets a custom locale that overrides the global one for this host component instance.
59+ * Setting a new locale triggers an update of the resource strings.
60+ */
61+ public set locale ( value : string | undefined ) {
62+ if ( this . _locale !== value ) {
63+ this . _locale = value ;
64+ this . _defaultResourceStrings = this . _getCurrentResourceStrings ( ) ;
65+ this . _host . requestUpdate ( ) ;
66+ }
3067 }
3168
32- /** Get resolved locale for component */
33- public get locale ( ) {
69+ /**
70+ * Gets the resolved locale for the host component.
71+ * This is the component's custom locale if set, otherwise it falls back to the
72+ * global locale.
73+ */
74+ public get locale ( ) : string {
3475 return this . _locale ?? getCurrentI18n ( ) ;
3576 }
3677
3778 /**
3879 * Sets custom resource string for component with this controller.
3980 * Gets the resolved resource string for component.
4081 */
41- public set resourceStrings ( value : T ) {
42- this . _resourceStrings = value ;
82+ public set resourceStrings ( value : T | undefined ) {
83+ if ( this . _resourceStrings !== value ) {
84+ this . _resourceStrings = value ;
85+ this . _host . requestUpdate ( ) ;
86+ }
4387 }
4488
4589 /** Get resolved resource strings for component */
4690 public get resourceStrings ( ) : T {
4791 return this . _resourceStrings ?? this . _defaultResourceStrings ;
4892 }
4993
50- private readonly _host : I18nControllerHost ;
51- private readonly _defaultEN : T ;
52- private readonly _resourceChangeHandler = this . onResourceChange . bind ( this ) ;
53- private _locale : string | undefined ;
54- private _resourceStrings : T | undefined ;
55- private _defaultResourceStrings : T ;
56- private _resourceChangeCallback ;
94+ //#endregion
5795
58- constructor ( host : I18nControllerHost , config : I18nControllerConfig ) {
96+ //#region Life-cycle hooks and event listener
97+
98+ constructor ( host : I18nControllerHost , config : I18nControllerConfig < T > ) {
5999 this . _host = host ;
60100 this . _defaultEN = config . defaultEN ;
61- this . _defaultResourceStrings = this . getCurrentResourceStrings ( ) ;
62- this . registerResources ( this . _defaultEN , true ) ;
101+ this . _resourceChangeCallback = config . onResourceChange ;
63102
64- if ( config ?. onResourceChange ) {
65- this . _resourceChangeCallback = config . onResourceChange ;
66- }
103+ this . _defaultResourceStrings = this . _getCurrentResourceStrings ( ) ;
104+ this . _registerResources ( this . _defaultEN ) ;
67105
68106 this . _host . addController ( this ) ;
69107 }
70108
71- public registerResources ( resource : T , isDefault = false ) {
72- const convertedResource = convertToCoreResource ( resource ) ;
73- getI18nManager ( ) . registerI18n (
74- convertedResource ,
75- isDefault ? getI18nManager ( ) . defaultLocale : this . locale
76- ) ;
77- }
78-
79109 /** @internal */
80110 public hostConnected ( ) : void {
81- getI18nManager ( ) . addEventListener (
82- 'onResourceChange' ,
83- this . _resourceChangeHandler
84- ) ;
111+ getI18nManager ( ) . addEventListener ( 'onResourceChange' , this ) ;
85112 }
86113
87114 /** @internal */
88115 public hostDisconnected ( ) : void {
89- getI18nManager ( ) . removeEventListener (
90- 'onResourceChange' ,
91- this . _resourceChangeHandler
92- ) ;
116+ getI18nManager ( ) . removeEventListener ( 'onResourceChange' , this ) ;
93117 }
94118
95- protected onResourceChange ( event : CustomEvent < IResourceChangeEventArgs > ) {
96- this . _defaultResourceStrings = this . getCurrentResourceStrings ( ) ;
97- if ( this . _resourceChangeCallback ) {
98- this . _resourceChangeCallback ( event ) ;
99- }
119+ /** @internal */
120+ public handleEvent ( event : CustomEvent < IResourceChangeEventArgs > ) : void {
121+ this . _defaultResourceStrings = this . _getCurrentResourceStrings ( ) ;
122+ this . _resourceChangeCallback ?.( event ) ;
100123 this . _host . requestUpdate ( ) ;
101124 }
102125
103- /** Get current resource strings based on default. Result is truncated result, containing only relevant locale strings. */
104- protected getCurrentResourceStrings ( ) {
105- const normalizedResourceStrings : T = { } as T ;
106- const igcResourceStringKeys = Object . keys ( this . _defaultEN as any ) ;
107- const resourceStrings = getI18nManager ( ) . getCurrentResourceStrings (
126+ //#endregion
127+
128+ //#region Internal API
129+
130+ /** Registers the default English resources with the global i18n manager. */
131+ private _registerResources ( resource : T ) : void {
132+ const convertedResource = convertToCoreResource ( resource ) ;
133+ const manager = getI18nManager ( ) ;
134+
135+ manager . registerI18n ( convertedResource , manager . defaultLocale ) ;
136+ }
137+
138+ /**
139+ * Helper to find the correct resource map based on the component's default resources (`#defaultEN`).
140+ * This relies on structural checking (the component's key names).
141+ */
142+ private _getResourceMapForComponent ( ) :
143+ | Map < string , string | undefined >
144+ | undefined {
145+ const keys = Object . keys ( this . _defaultEN ) ;
146+
147+ if ( keys . includes ( 'last7Days' ) ) {
148+ return dateRangePickerResourcesMap ;
149+ }
150+
151+ if ( keys . includes ( 'selectMonth' ) ) {
152+ return calendarResourcesMap ;
153+ }
154+
155+ return undefined ;
156+ }
157+
158+ /**
159+ * Gets the current, locale-specific resource strings for the component.
160+ * The logic maps component keys (from defaultEN) to core library keys
161+ * and retrieves the localized string from the i18n manager.
162+ *
163+ * Result is truncated, containing only relevant locale strings.
164+ */
165+ private _getCurrentResourceStrings ( ) : T {
166+ const coreResourceStrings = getI18nManager ( ) . getCurrentResourceStrings (
108167 this . locale
109168 ) ;
110- const resourceStringsKeys = Object . keys ( resourceStrings ) ;
111-
112- for ( const igcKey of igcResourceStringKeys ) {
113- const coreKey =
114- calendarResourcesMap . get ( igcKey ) ??
115- dateRangePickerResourcesMap . get ( igcKey ) ??
116- undefined ;
117- if ( coreKey && ! coreKey . includes ( 'i18n/' ) ) {
118- if ( resourceStringsKeys . includes ( coreKey ) ) {
119- normalizedResourceStrings [ igcKey as keyof T ] = resourceStrings [
120- coreKey as keyof IResourceStrings
121- ] as T [ keyof T ] ;
169+ const resourceMap = this . _getResourceMapForComponent ( ) ;
170+
171+ if ( ! resourceMap ) {
172+ return coreResourceStrings as T ;
173+ }
174+
175+ const normalizedResourceStrings : T = { } as T ;
176+ const defaultComponentKeys = Object . keys ( this . _defaultEN ) as ( keyof T ) [ ] ;
177+
178+ for ( const igcKey of defaultComponentKeys ) {
179+ const coreKey = resourceMap . get ( igcKey as string ) ;
180+ let resolvedValue : T [ keyof T ] = this . _defaultEN [ igcKey ] ;
181+
182+ if ( coreKey ) {
183+ if ( coreKey . includes ( 'getWeekLabel' ) ) {
184+ resolvedValue = getDisplayNamesFormatter ( ) . getWeekLabel ( this . locale , {
185+ style : 'short' ,
186+ } ) as T [ keyof T ] ;
122187 } else {
123- normalizedResourceStrings [ igcKey as keyof T ] =
124- this . _defaultEN [ igcKey as keyof T ] ;
188+ resolvedValue =
189+ coreKey in coreResourceStrings
190+ ? ( coreResourceStrings [
191+ coreKey as keyof IResourceStrings
192+ ] as T [ keyof T ] )
193+ : this . _defaultEN [ igcKey ] ;
125194 }
126- } else if ( coreKey ?. includes ( 'getWeekLabel' ) ) {
127- const weekLabel = getDisplayNamesFormatter ( ) . getWeekLabel ( this . locale , {
128- style : 'short' ,
129- } ) ;
130- normalizedResourceStrings [ igcKey as keyof T ] = weekLabel as T [ keyof T ] ;
131- } else {
132- // No mapped keys, no need to convert the resources then.
133- return resourceStrings as T ;
134195 }
196+
197+ normalizedResourceStrings [ igcKey ] = resolvedValue ;
135198 }
136199
137200 return normalizedResourceStrings ;
138201 }
202+
203+ //#endregion
139204}
140205
141- export function addI18nController < T > (
206+ /** Factory function to create and attach the I18nController to a host. */
207+ export function addI18nController < T extends object > (
142208 host : I18nControllerHost ,
143- config : I18nControllerConfig
144- ) {
209+ config : I18nControllerConfig < T >
210+ ) : I18nController < T > {
145211 return new I18nController < T > ( host , config ) ;
146212}
213+
214+ export type { I18nController } ;
0 commit comments