@sheet-i18n/react-client 1.4.1 → 1.5.0-canary.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,6 +1,32 @@
1
+ import { I18nStore } from '@sheet-i18n/react-core';
2
+ import { ObserverManager } from '@sheet-i18n/shared-utils';
1
3
  import { MessageDescriptor, IntlShape } from 'react-intl';
2
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
- import { I18nStore } from '@sheet-i18n/react-core';
5
+
6
+ interface IStorageService<V extends string> {
7
+ getItem(key: string): V;
8
+ setItem(key: string, value: V): boolean;
9
+ removeItem(key: string): boolean;
10
+ clear(): boolean;
11
+ }
12
+ /**
13
+ * locale storage manager
14
+ * implements ILocaleStorageManager (injected StorageService)
15
+ */
16
+ interface ILocaleStorageManager<TSupportedLocales extends readonly string[]> {
17
+ getLocale(): TSupportedLocales[number];
18
+ setLocale(locale: TSupportedLocales[number]): void;
19
+ }
20
+ declare class LocaleStorageManager<TSupportedLocales extends readonly string[], TLocaleSet extends Partial<Record<TSupportedLocales[number], Record<string, any>>>, TTypeSafe extends boolean = false> implements ILocaleStorageManager<TSupportedLocales> {
21
+ private readonly storageService;
22
+ private readonly i18nStore;
23
+ private readonly localeStorageKey;
24
+ observerManager: ObserverManager<TSupportedLocales[number]>;
25
+ constructor(storageService: IStorageService<TSupportedLocales[number]>, i18nStore: I18nStore<TSupportedLocales, TLocaleSet, TTypeSafe>, localeStorageKey?: string);
26
+ private initializeCurrentLocale;
27
+ getLocale: () => TSupportedLocales[number];
28
+ setLocale: (locale: TSupportedLocales[number]) => void;
29
+ }
4
30
 
5
31
  type UseIntlParams<D = MessageDescriptor> = Parameters<IntlShape['$t']> extends [D, ...infer R] ? [...R, Omit<D, 'id'>] : never;
6
32
  type ExtendedUseIntlParams<D = MessageDescriptor> = UseIntlParams<D> extends [infer A, infer B, ...infer Rest] ? A extends Record<string, infer V> ? [Record<string, V | React.ReactNode>, B, ...Rest] : [A, B, ...Rest] : UseIntlParams<D>;
@@ -39,13 +65,26 @@ type IntlProviderProps<TSupportedLocales extends readonly string[], TLocaleSet e
39
65
  children: React.ReactNode;
40
66
  };
41
67
 
68
+ declare function useLocaleStorage<TSupportedLocales extends readonly string[], TLocaleSet extends Partial<Record<TSupportedLocales[number], Record<string, any>>>, TTypeSafe extends boolean = false>(localeStorageManager: LocaleStorageManager<TSupportedLocales, TLocaleSet, TTypeSafe>): {
69
+ locale: TSupportedLocales[number];
70
+ };
71
+
72
+ interface StorageBasedIntlProviderProps<TSupportedLocales extends readonly string[], TLocaleSet extends Partial<Record<TSupportedLocales[number], Record<string, any>>>, TTypeSafe extends boolean = false> {
73
+ i18nStore: I18nStore<TSupportedLocales, TLocaleSet, TTypeSafe>;
74
+ storageManager: LocaleStorageManager<TSupportedLocales, TLocaleSet, TTypeSafe>;
75
+ children: React.ReactNode;
76
+ }
77
+
42
78
  declare function createI18nContext<TSupportedLocales extends readonly string[], TLocaleSet extends Partial<Record<TSupportedLocales[number], Record<string, any>>>, TTypeSafe extends boolean = false>(i18nStore: I18nStore<TSupportedLocales, TLocaleSet, TTypeSafe>): {
43
79
  IntlProvider: ({ currentLocale, children, }: Omit<IntlProviderProps<TSupportedLocales, TLocaleSet>, "currentLocale" | "i18nStore"> & {
44
80
  currentLocale?: string;
45
81
  children?: React.ReactNode;
46
82
  }) => react_jsx_runtime.JSX.Element;
83
+ StorageBasedIntlProvider: ({ storageManager, children, }: Omit<StorageBasedIntlProviderProps<TSupportedLocales, TLocaleSet, TTypeSafe>, "i18nStore">) => react_jsx_runtime.JSX.Element;
47
84
  useTranslation: <TSheetTitle extends TTypeSafe extends true ? keyof TLocaleSet[TSupportedLocales[number]] extends never ? string : keyof TLocaleSet[TSupportedLocales[number]] : string>(sheetTitle: TSheetTitle) => UseTranslationReturn<TSupportedLocales, TLocaleSet, TTypeSafe, TSheetTitle>;
48
85
  getTranslation: <TSheetTitle extends TTypeSafe extends true ? keyof TLocaleSet[TSupportedLocales[number]] extends never ? string : keyof TLocaleSet[TSupportedLocales[number]] : string>(sheetTitle: TSheetTitle) => GetTranslationReturn<TSupportedLocales, TLocaleSet, TTypeSafe, TSheetTitle>;
86
+ getLocaleStorageManager: (storageService?: IStorageService<string>) => LocaleStorageManager<TSupportedLocales, TLocaleSet, TTypeSafe>;
87
+ useLocaleStorage: typeof useLocaleStorage;
49
88
  };
50
89
 
51
90
  export { createI18nContext };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,32 @@
1
+ import { I18nStore } from '@sheet-i18n/react-core';
2
+ import { ObserverManager } from '@sheet-i18n/shared-utils';
1
3
  import { MessageDescriptor, IntlShape } from 'react-intl';
2
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
- import { I18nStore } from '@sheet-i18n/react-core';
5
+
6
+ interface IStorageService<V extends string> {
7
+ getItem(key: string): V;
8
+ setItem(key: string, value: V): boolean;
9
+ removeItem(key: string): boolean;
10
+ clear(): boolean;
11
+ }
12
+ /**
13
+ * locale storage manager
14
+ * implements ILocaleStorageManager (injected StorageService)
15
+ */
16
+ interface ILocaleStorageManager<TSupportedLocales extends readonly string[]> {
17
+ getLocale(): TSupportedLocales[number];
18
+ setLocale(locale: TSupportedLocales[number]): void;
19
+ }
20
+ declare class LocaleStorageManager<TSupportedLocales extends readonly string[], TLocaleSet extends Partial<Record<TSupportedLocales[number], Record<string, any>>>, TTypeSafe extends boolean = false> implements ILocaleStorageManager<TSupportedLocales> {
21
+ private readonly storageService;
22
+ private readonly i18nStore;
23
+ private readonly localeStorageKey;
24
+ observerManager: ObserverManager<TSupportedLocales[number]>;
25
+ constructor(storageService: IStorageService<TSupportedLocales[number]>, i18nStore: I18nStore<TSupportedLocales, TLocaleSet, TTypeSafe>, localeStorageKey?: string);
26
+ private initializeCurrentLocale;
27
+ getLocale: () => TSupportedLocales[number];
28
+ setLocale: (locale: TSupportedLocales[number]) => void;
29
+ }
4
30
 
5
31
  type UseIntlParams<D = MessageDescriptor> = Parameters<IntlShape['$t']> extends [D, ...infer R] ? [...R, Omit<D, 'id'>] : never;
6
32
  type ExtendedUseIntlParams<D = MessageDescriptor> = UseIntlParams<D> extends [infer A, infer B, ...infer Rest] ? A extends Record<string, infer V> ? [Record<string, V | React.ReactNode>, B, ...Rest] : [A, B, ...Rest] : UseIntlParams<D>;
@@ -39,13 +65,26 @@ type IntlProviderProps<TSupportedLocales extends readonly string[], TLocaleSet e
39
65
  children: React.ReactNode;
40
66
  };
41
67
 
68
+ declare function useLocaleStorage<TSupportedLocales extends readonly string[], TLocaleSet extends Partial<Record<TSupportedLocales[number], Record<string, any>>>, TTypeSafe extends boolean = false>(localeStorageManager: LocaleStorageManager<TSupportedLocales, TLocaleSet, TTypeSafe>): {
69
+ locale: TSupportedLocales[number];
70
+ };
71
+
72
+ interface StorageBasedIntlProviderProps<TSupportedLocales extends readonly string[], TLocaleSet extends Partial<Record<TSupportedLocales[number], Record<string, any>>>, TTypeSafe extends boolean = false> {
73
+ i18nStore: I18nStore<TSupportedLocales, TLocaleSet, TTypeSafe>;
74
+ storageManager: LocaleStorageManager<TSupportedLocales, TLocaleSet, TTypeSafe>;
75
+ children: React.ReactNode;
76
+ }
77
+
42
78
  declare function createI18nContext<TSupportedLocales extends readonly string[], TLocaleSet extends Partial<Record<TSupportedLocales[number], Record<string, any>>>, TTypeSafe extends boolean = false>(i18nStore: I18nStore<TSupportedLocales, TLocaleSet, TTypeSafe>): {
43
79
  IntlProvider: ({ currentLocale, children, }: Omit<IntlProviderProps<TSupportedLocales, TLocaleSet>, "currentLocale" | "i18nStore"> & {
44
80
  currentLocale?: string;
45
81
  children?: React.ReactNode;
46
82
  }) => react_jsx_runtime.JSX.Element;
83
+ StorageBasedIntlProvider: ({ storageManager, children, }: Omit<StorageBasedIntlProviderProps<TSupportedLocales, TLocaleSet, TTypeSafe>, "i18nStore">) => react_jsx_runtime.JSX.Element;
47
84
  useTranslation: <TSheetTitle extends TTypeSafe extends true ? keyof TLocaleSet[TSupportedLocales[number]] extends never ? string : keyof TLocaleSet[TSupportedLocales[number]] : string>(sheetTitle: TSheetTitle) => UseTranslationReturn<TSupportedLocales, TLocaleSet, TTypeSafe, TSheetTitle>;
48
85
  getTranslation: <TSheetTitle extends TTypeSafe extends true ? keyof TLocaleSet[TSupportedLocales[number]] extends never ? string : keyof TLocaleSet[TSupportedLocales[number]] : string>(sheetTitle: TSheetTitle) => GetTranslationReturn<TSupportedLocales, TLocaleSet, TTypeSafe, TSheetTitle>;
86
+ getLocaleStorageManager: (storageService?: IStorageService<string>) => LocaleStorageManager<TSupportedLocales, TLocaleSet, TTypeSafe>;
87
+ useLocaleStorage: typeof useLocaleStorage;
49
88
  };
50
89
 
51
90
  export { createI18nContext };
package/dist/index.js CHANGED
@@ -43,14 +43,14 @@ __export(src_exports, {
43
43
  module.exports = __toCommonJS(src_exports);
44
44
 
45
45
  // src/createI18nContext.tsx
46
- var import_shared_utils4 = require("@sheet-i18n/shared-utils");
46
+ var import_shared_utils5 = require("@sheet-i18n/shared-utils");
47
47
  var import_react_core = require("@sheet-i18n/react-core");
48
48
 
49
- // src/IntlProvider.tsx
49
+ // src/Provider/IntlProvider.tsx
50
50
  var import_react_intl2 = require("react-intl");
51
51
  var import_react2 = require("react");
52
52
 
53
- // src/useDynamicLocale.ts
53
+ // src/hooks/useDynamicLocale.ts
54
54
  var import_shared_utils2 = require("@sheet-i18n/shared-utils");
55
55
  var import_react = require("react");
56
56
 
@@ -122,7 +122,7 @@ var IntlInstanceCache = class _IntlInstanceCache {
122
122
  };
123
123
  var intlInstanceCache = IntlInstanceCache.init();
124
124
 
125
- // src/useDynamicLocale.ts
125
+ // src/hooks/useDynamicLocale.ts
126
126
  function useDynamicLocale(useDynamicLocaleProps) {
127
127
  const { i18nStore } = useDynamicLocaleProps != null ? useDynamicLocaleProps : {};
128
128
  const currentLocale = i18nStore == null ? void 0 : i18nStore.getCurrentLocale();
@@ -154,7 +154,7 @@ ${err}`);
154
154
  };
155
155
  }
156
156
 
157
- // src/IntlProvider.tsx
157
+ // src/Provider/IntlProvider.tsx
158
158
  var import_jsx_runtime = require("react/jsx-runtime");
159
159
  function IntlProvider({
160
160
  i18nStore,
@@ -183,8 +183,7 @@ function useIntlLocale({
183
183
  i18nStore,
184
184
  currentLocale
185
185
  }) {
186
- var _a;
187
- const locale = (_a = currentLocale != null ? currentLocale : detectClientLanguage(i18nStore)) != null ? _a : i18nStore.defaultLocale;
186
+ const locale = currentLocale || detectClientLanguage(i18nStore) || i18nStore.defaultLocale;
188
187
  i18nStore.setCurrentLocale(locale);
189
188
  (0, import_react2.useEffect)(() => {
190
189
  i18nStore.setCurrentLocale(locale);
@@ -248,7 +247,7 @@ var TranslationService = class {
248
247
  }
249
248
  };
250
249
 
251
- // src/useTranslation.ts
250
+ // src/hooks/useTranslation.ts
252
251
  function useTranslation({
253
252
  sheetTitle,
254
253
  i18nStore
@@ -275,7 +274,7 @@ var InvalidI18nContextStateError = class extends import_errors.CustomError {
275
274
  var IsNotInstanceOfI18nStoreError = class extends import_errors.CustomError {
276
275
  };
277
276
 
278
- // src/getTranslation.ts
277
+ // src/hooks/getTranslation.ts
279
278
  function getTranslation({
280
279
  sheetTitle,
281
280
  i18nStore
@@ -319,10 +318,176 @@ function getTranslation({
319
318
  return { t };
320
319
  }
321
320
 
322
- // src/createI18nContext.tsx
321
+ // src/Service/StorageService.ts
322
+ var import_shared_utils4 = require("@sheet-i18n/shared-utils");
323
+ var StorageService = class {
324
+ constructor(storage) {
325
+ this.storage = null;
326
+ this.isClientSide = typeof window !== "undefined";
327
+ if (storage) {
328
+ this.storage = this.validateStorage(storage);
329
+ } else if (this.isClientSide) {
330
+ this.storage = this.initializeWindowLocalStorage();
331
+ }
332
+ }
333
+ validateStorage(storage) {
334
+ const requiredMethods = [
335
+ "getItem",
336
+ "setItem",
337
+ "removeItem",
338
+ "clear"
339
+ ];
340
+ try {
341
+ for (const method of requiredMethods) {
342
+ if (typeof storage[method] !== "function") {
343
+ throw new Error(
344
+ `Invalid storage object: missing required method '${method}'`
345
+ );
346
+ }
347
+ }
348
+ return storage;
349
+ } catch (error) {
350
+ console.error(error);
351
+ return null;
352
+ }
353
+ }
354
+ initializeWindowLocalStorage() {
355
+ try {
356
+ const testKey = "__storage_test__";
357
+ localStorage.setItem(testKey, "test");
358
+ localStorage.removeItem(testKey);
359
+ return localStorage;
360
+ } catch (error) {
361
+ console.warn("Window LocalStorage is not available:", error);
362
+ return null;
363
+ }
364
+ }
365
+ getItem(key) {
366
+ if (!this.storage || !key) {
367
+ return "";
368
+ }
369
+ try {
370
+ return this.storage.getItem(key);
371
+ } catch (error) {
372
+ console.error(`Failed to get item with key "${key}":`, error);
373
+ return "";
374
+ }
375
+ }
376
+ setItem(key, value) {
377
+ if (!this.storage || !key) {
378
+ return false;
379
+ }
380
+ try {
381
+ this.storage.setItem(key, value);
382
+ return true;
383
+ } catch (error) {
384
+ console.error(`Failed to set item with key "${key}":`, error);
385
+ return false;
386
+ }
387
+ }
388
+ removeItem(key) {
389
+ if (!this.storage || !key) {
390
+ return false;
391
+ }
392
+ try {
393
+ this.storage.removeItem(key);
394
+ return true;
395
+ } catch (error) {
396
+ console.error(`Failed to remove item with key "${key}":`, error);
397
+ return false;
398
+ }
399
+ }
400
+ clear() {
401
+ if (!this.storage) {
402
+ return false;
403
+ }
404
+ try {
405
+ this.storage.clear();
406
+ return true;
407
+ } catch (error) {
408
+ console.error("Failed to clear storage:", error);
409
+ return false;
410
+ }
411
+ }
412
+ };
413
+ var LocaleStorageManager = class {
414
+ constructor(storageService, i18nStore, localeStorageKey = "sheet-i18n-locale") {
415
+ this.storageService = storageService;
416
+ this.i18nStore = i18nStore;
417
+ this.localeStorageKey = localeStorageKey;
418
+ this.observerManager = new import_shared_utils4.ObserverManager();
419
+ this.initializeCurrentLocale = () => {
420
+ var _a, _b;
421
+ if (this.storageService && this.i18nStore.currentLocale) {
422
+ this.storageService.setItem(
423
+ this.localeStorageKey,
424
+ this.i18nStore.currentLocale
425
+ );
426
+ }
427
+ (_b = (_a = this.i18nStore) == null ? void 0 : _a.observerManager) == null ? void 0 : _b.addListener({
428
+ listenerId: this.localeStorageKey,
429
+ listener: (newLocale) => {
430
+ this.storageService.setItem(this.localeStorageKey, newLocale);
431
+ }
432
+ });
433
+ };
434
+ this.getLocale = () => {
435
+ const stored = this.storageService.getItem(this.localeStorageKey);
436
+ return stored != null ? stored : "";
437
+ };
438
+ this.setLocale = (locale) => {
439
+ this.storageService.setItem(this.localeStorageKey, locale);
440
+ this.observerManager.notify(locale);
441
+ };
442
+ this.initializeCurrentLocale();
443
+ }
444
+ };
445
+ var getLocaleStorageManager = (i18nStore, storage) => {
446
+ const localeStorageService = new StorageService(storage);
447
+ const localeStorageManager = new LocaleStorageManager(
448
+ localeStorageService,
449
+ i18nStore
450
+ );
451
+ return localeStorageManager;
452
+ };
453
+
454
+ // src/hooks/useLocaleStorage.ts
455
+ var import_react3 = require("react");
456
+ var LISTENER_ID = "LOCALE_STORAGE_LISTENER_ID";
457
+ function useLocaleStorage(localeStorageManager) {
458
+ var _a;
459
+ const [locale, setLocale] = (0, import_react3.useState)((_a = localeStorageManager == null ? void 0 : localeStorageManager.getLocale) == null ? void 0 : _a.call(localeStorageManager));
460
+ (0, import_react3.useEffect)(() => {
461
+ var _a2;
462
+ (_a2 = localeStorageManager == null ? void 0 : localeStorageManager.observerManager) == null ? void 0 : _a2.addListener({
463
+ listenerId: LISTENER_ID,
464
+ listener: (newLocale) => {
465
+ setLocale(newLocale);
466
+ }
467
+ });
468
+ return () => {
469
+ var _a3;
470
+ (_a3 = localeStorageManager == null ? void 0 : localeStorageManager.observerManager) == null ? void 0 : _a3.removeListener(LISTENER_ID);
471
+ };
472
+ }, []);
473
+ return { locale };
474
+ }
475
+
476
+ // src/Provider/StorageBasedIntlProvider.tsx
323
477
  var import_jsx_runtime2 = require("react/jsx-runtime");
478
+ function StorageBasedIntlProvider({
479
+ i18nStore,
480
+ storageManager,
481
+ children
482
+ }) {
483
+ const { locale } = useLocaleStorage(storageManager);
484
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(IntlProvider, { currentLocale: locale, i18nStore, children });
485
+ }
486
+
487
+ // src/createI18nContext.tsx
488
+ var import_jsx_runtime3 = require("react/jsx-runtime");
324
489
  function createI18nContext(i18nStore) {
325
- if (import_shared_utils4.validator.isNullish(i18nStore)) {
490
+ if (import_shared_utils5.validator.isNullish(i18nStore)) {
326
491
  throw new InvalidI18nContextStateError(
327
492
  "\u26A0\uFE0F no i18nStore provided. To use createI18nContext, you must provide an i18nStore as a parameter"
328
493
  );
@@ -335,7 +500,7 @@ function createI18nContext(i18nStore) {
335
500
  const IntlProviderImpl = ({
336
501
  currentLocale,
337
502
  children
338
- }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
503
+ }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
339
504
  IntlProvider,
340
505
  {
341
506
  currentLocale,
@@ -343,12 +508,29 @@ function createI18nContext(i18nStore) {
343
508
  children
344
509
  }
345
510
  );
511
+ const StorageBasedIntlProviderImpl = ({
512
+ storageManager,
513
+ children
514
+ }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
515
+ StorageBasedIntlProvider,
516
+ {
517
+ i18nStore,
518
+ storageManager,
519
+ children
520
+ }
521
+ );
346
522
  const useTranslationImpl = (sheetTitle) => useTranslation({ sheetTitle, i18nStore });
347
523
  const getTranslationImpl = (sheetTitle) => getTranslation({ sheetTitle, i18nStore });
524
+ const getLocaleStorageManagerImpl = (storageService) => {
525
+ return getLocaleStorageManager(i18nStore, storageService);
526
+ };
348
527
  return {
349
528
  IntlProvider: IntlProviderImpl,
529
+ StorageBasedIntlProvider: StorageBasedIntlProviderImpl,
350
530
  useTranslation: useTranslationImpl,
351
- getTranslation: getTranslationImpl
531
+ getTranslation: getTranslationImpl,
532
+ getLocaleStorageManager: getLocaleStorageManagerImpl,
533
+ useLocaleStorage
352
534
  };
353
535
  }
354
536
  // Annotate the CommonJS export names for ESM import in node:
package/dist/index.mjs CHANGED
@@ -23,11 +23,11 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
23
23
  import { validator as validator4 } from "@sheet-i18n/shared-utils";
24
24
  import { I18nStore } from "@sheet-i18n/react-core";
25
25
 
26
- // src/IntlProvider.tsx
26
+ // src/Provider/IntlProvider.tsx
27
27
  import { IntlProvider as ReactIntlProvider } from "react-intl";
28
28
  import { useEffect } from "react";
29
29
 
30
- // src/useDynamicLocale.ts
30
+ // src/hooks/useDynamicLocale.ts
31
31
  import { validator as validator2 } from "@sheet-i18n/shared-utils";
32
32
  import { useLayoutEffect, useState } from "react";
33
33
 
@@ -99,7 +99,7 @@ var IntlInstanceCache = class _IntlInstanceCache {
99
99
  };
100
100
  var intlInstanceCache = IntlInstanceCache.init();
101
101
 
102
- // src/useDynamicLocale.ts
102
+ // src/hooks/useDynamicLocale.ts
103
103
  function useDynamicLocale(useDynamicLocaleProps) {
104
104
  const { i18nStore } = useDynamicLocaleProps != null ? useDynamicLocaleProps : {};
105
105
  const currentLocale = i18nStore == null ? void 0 : i18nStore.getCurrentLocale();
@@ -131,7 +131,7 @@ ${err}`);
131
131
  };
132
132
  }
133
133
 
134
- // src/IntlProvider.tsx
134
+ // src/Provider/IntlProvider.tsx
135
135
  import { jsx } from "react/jsx-runtime";
136
136
  function IntlProvider({
137
137
  i18nStore,
@@ -160,8 +160,7 @@ function useIntlLocale({
160
160
  i18nStore,
161
161
  currentLocale
162
162
  }) {
163
- var _a;
164
- const locale = (_a = currentLocale != null ? currentLocale : detectClientLanguage(i18nStore)) != null ? _a : i18nStore.defaultLocale;
163
+ const locale = currentLocale || detectClientLanguage(i18nStore) || i18nStore.defaultLocale;
165
164
  i18nStore.setCurrentLocale(locale);
166
165
  useEffect(() => {
167
166
  i18nStore.setCurrentLocale(locale);
@@ -225,7 +224,7 @@ var TranslationService = class {
225
224
  }
226
225
  };
227
226
 
228
- // src/useTranslation.ts
227
+ // src/hooks/useTranslation.ts
229
228
  function useTranslation({
230
229
  sheetTitle,
231
230
  i18nStore
@@ -252,7 +251,7 @@ var InvalidI18nContextStateError = class extends CustomError {
252
251
  var IsNotInstanceOfI18nStoreError = class extends CustomError {
253
252
  };
254
253
 
255
- // src/getTranslation.ts
254
+ // src/hooks/getTranslation.ts
256
255
  function getTranslation({
257
256
  sheetTitle,
258
257
  i18nStore
@@ -296,8 +295,174 @@ function getTranslation({
296
295
  return { t };
297
296
  }
298
297
 
299
- // src/createI18nContext.tsx
298
+ // src/Service/StorageService.ts
299
+ import { ObserverManager } from "@sheet-i18n/shared-utils";
300
+ var StorageService = class {
301
+ constructor(storage) {
302
+ this.storage = null;
303
+ this.isClientSide = typeof window !== "undefined";
304
+ if (storage) {
305
+ this.storage = this.validateStorage(storage);
306
+ } else if (this.isClientSide) {
307
+ this.storage = this.initializeWindowLocalStorage();
308
+ }
309
+ }
310
+ validateStorage(storage) {
311
+ const requiredMethods = [
312
+ "getItem",
313
+ "setItem",
314
+ "removeItem",
315
+ "clear"
316
+ ];
317
+ try {
318
+ for (const method of requiredMethods) {
319
+ if (typeof storage[method] !== "function") {
320
+ throw new Error(
321
+ `Invalid storage object: missing required method '${method}'`
322
+ );
323
+ }
324
+ }
325
+ return storage;
326
+ } catch (error) {
327
+ console.error(error);
328
+ return null;
329
+ }
330
+ }
331
+ initializeWindowLocalStorage() {
332
+ try {
333
+ const testKey = "__storage_test__";
334
+ localStorage.setItem(testKey, "test");
335
+ localStorage.removeItem(testKey);
336
+ return localStorage;
337
+ } catch (error) {
338
+ console.warn("Window LocalStorage is not available:", error);
339
+ return null;
340
+ }
341
+ }
342
+ getItem(key) {
343
+ if (!this.storage || !key) {
344
+ return "";
345
+ }
346
+ try {
347
+ return this.storage.getItem(key);
348
+ } catch (error) {
349
+ console.error(`Failed to get item with key "${key}":`, error);
350
+ return "";
351
+ }
352
+ }
353
+ setItem(key, value) {
354
+ if (!this.storage || !key) {
355
+ return false;
356
+ }
357
+ try {
358
+ this.storage.setItem(key, value);
359
+ return true;
360
+ } catch (error) {
361
+ console.error(`Failed to set item with key "${key}":`, error);
362
+ return false;
363
+ }
364
+ }
365
+ removeItem(key) {
366
+ if (!this.storage || !key) {
367
+ return false;
368
+ }
369
+ try {
370
+ this.storage.removeItem(key);
371
+ return true;
372
+ } catch (error) {
373
+ console.error(`Failed to remove item with key "${key}":`, error);
374
+ return false;
375
+ }
376
+ }
377
+ clear() {
378
+ if (!this.storage) {
379
+ return false;
380
+ }
381
+ try {
382
+ this.storage.clear();
383
+ return true;
384
+ } catch (error) {
385
+ console.error("Failed to clear storage:", error);
386
+ return false;
387
+ }
388
+ }
389
+ };
390
+ var LocaleStorageManager = class {
391
+ constructor(storageService, i18nStore, localeStorageKey = "sheet-i18n-locale") {
392
+ this.storageService = storageService;
393
+ this.i18nStore = i18nStore;
394
+ this.localeStorageKey = localeStorageKey;
395
+ this.observerManager = new ObserverManager();
396
+ this.initializeCurrentLocale = () => {
397
+ var _a, _b;
398
+ if (this.storageService && this.i18nStore.currentLocale) {
399
+ this.storageService.setItem(
400
+ this.localeStorageKey,
401
+ this.i18nStore.currentLocale
402
+ );
403
+ }
404
+ (_b = (_a = this.i18nStore) == null ? void 0 : _a.observerManager) == null ? void 0 : _b.addListener({
405
+ listenerId: this.localeStorageKey,
406
+ listener: (newLocale) => {
407
+ this.storageService.setItem(this.localeStorageKey, newLocale);
408
+ }
409
+ });
410
+ };
411
+ this.getLocale = () => {
412
+ const stored = this.storageService.getItem(this.localeStorageKey);
413
+ return stored != null ? stored : "";
414
+ };
415
+ this.setLocale = (locale) => {
416
+ this.storageService.setItem(this.localeStorageKey, locale);
417
+ this.observerManager.notify(locale);
418
+ };
419
+ this.initializeCurrentLocale();
420
+ }
421
+ };
422
+ var getLocaleStorageManager = (i18nStore, storage) => {
423
+ const localeStorageService = new StorageService(storage);
424
+ const localeStorageManager = new LocaleStorageManager(
425
+ localeStorageService,
426
+ i18nStore
427
+ );
428
+ return localeStorageManager;
429
+ };
430
+
431
+ // src/hooks/useLocaleStorage.ts
432
+ import { useEffect as useEffect2, useState as useState2 } from "react";
433
+ var LISTENER_ID = "LOCALE_STORAGE_LISTENER_ID";
434
+ function useLocaleStorage(localeStorageManager) {
435
+ var _a;
436
+ const [locale, setLocale] = useState2((_a = localeStorageManager == null ? void 0 : localeStorageManager.getLocale) == null ? void 0 : _a.call(localeStorageManager));
437
+ useEffect2(() => {
438
+ var _a2;
439
+ (_a2 = localeStorageManager == null ? void 0 : localeStorageManager.observerManager) == null ? void 0 : _a2.addListener({
440
+ listenerId: LISTENER_ID,
441
+ listener: (newLocale) => {
442
+ setLocale(newLocale);
443
+ }
444
+ });
445
+ return () => {
446
+ var _a3;
447
+ (_a3 = localeStorageManager == null ? void 0 : localeStorageManager.observerManager) == null ? void 0 : _a3.removeListener(LISTENER_ID);
448
+ };
449
+ }, []);
450
+ return { locale };
451
+ }
452
+
453
+ // src/Provider/StorageBasedIntlProvider.tsx
300
454
  import { jsx as jsx2 } from "react/jsx-runtime";
455
+ function StorageBasedIntlProvider({
456
+ i18nStore,
457
+ storageManager,
458
+ children
459
+ }) {
460
+ const { locale } = useLocaleStorage(storageManager);
461
+ return /* @__PURE__ */ jsx2(IntlProvider, { currentLocale: locale, i18nStore, children });
462
+ }
463
+
464
+ // src/createI18nContext.tsx
465
+ import { jsx as jsx3 } from "react/jsx-runtime";
301
466
  function createI18nContext(i18nStore) {
302
467
  if (validator4.isNullish(i18nStore)) {
303
468
  throw new InvalidI18nContextStateError(
@@ -312,7 +477,7 @@ function createI18nContext(i18nStore) {
312
477
  const IntlProviderImpl = ({
313
478
  currentLocale,
314
479
  children
315
- }) => /* @__PURE__ */ jsx2(
480
+ }) => /* @__PURE__ */ jsx3(
316
481
  IntlProvider,
317
482
  {
318
483
  currentLocale,
@@ -320,12 +485,29 @@ function createI18nContext(i18nStore) {
320
485
  children
321
486
  }
322
487
  );
488
+ const StorageBasedIntlProviderImpl = ({
489
+ storageManager,
490
+ children
491
+ }) => /* @__PURE__ */ jsx3(
492
+ StorageBasedIntlProvider,
493
+ {
494
+ i18nStore,
495
+ storageManager,
496
+ children
497
+ }
498
+ );
323
499
  const useTranslationImpl = (sheetTitle) => useTranslation({ sheetTitle, i18nStore });
324
500
  const getTranslationImpl = (sheetTitle) => getTranslation({ sheetTitle, i18nStore });
501
+ const getLocaleStorageManagerImpl = (storageService) => {
502
+ return getLocaleStorageManager(i18nStore, storageService);
503
+ };
325
504
  return {
326
505
  IntlProvider: IntlProviderImpl,
506
+ StorageBasedIntlProvider: StorageBasedIntlProviderImpl,
327
507
  useTranslation: useTranslationImpl,
328
- getTranslation: getTranslationImpl
508
+ getTranslation: getTranslationImpl,
509
+ getLocaleStorageManager: getLocaleStorageManagerImpl,
510
+ useLocaleStorage
329
511
  };
330
512
  }
331
513
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sheet-i18n/react-client",
3
- "version": "1.4.1",
3
+ "version": "1.5.0-canary.1",
4
4
  "description": "a client package for react modules used by sheet-i18n",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -25,20 +25,20 @@
25
25
  },
26
26
  "license": "ISC",
27
27
  "dependencies": {
28
- "@sheet-i18n/errors": "1.7.1",
29
- "@sheet-i18n/shared-utils": "1.7.1",
30
- "@sheet-i18n/react-core": "1.4.1"
28
+ "@sheet-i18n/shared-utils": "1.8.0-canary.0",
29
+ "@sheet-i18n/errors": "1.8.0-canary.0",
30
+ "@sheet-i18n/react-core": "1.5.0-canary.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/react": "^19.0.2",
34
34
  "@types/react-dom": "^19.0.2",
35
35
  "react": "^18.2.0",
36
36
  "react-intl": "^7.0.4",
37
- "@sheet-i18n/typescript-config": "1.7.1"
37
+ "@sheet-i18n/typescript-config": "1.8.0-canary.0"
38
38
  },
39
39
  "peerDependencies": {
40
- "react": "^18 || ^19",
41
- "react-dom": "^18 || ^19",
40
+ "react": "^18 || ^19 || ^20 || ^21",
41
+ "react-dom": "^18 || ^19 || ^20 || ^21",
42
42
  "react-intl": "^7.0.4"
43
43
  },
44
44
  "scripts": {