intor 2.2.12 → 2.2.13

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.
@@ -1,4 +1,4 @@
1
- import * as React6 from 'react';
1
+ import * as React7 from 'react';
2
2
  import { jsx } from 'react/jsx-runtime';
3
3
  import { logry } from 'logry';
4
4
  import Keyv from 'keyv';
@@ -6,20 +6,71 @@ import merge from 'lodash.merge';
6
6
  import { Translator } from 'intor-translator';
7
7
 
8
8
  // src/client/react/contexts/intor-provider/intor-provider.tsx
9
- var ConfigContext = React6.createContext(void 0);
9
+ var ConfigContext = React7.createContext(void 0);
10
10
  function ConfigProvider({
11
11
  value: { config, pathname },
12
12
  children
13
13
  }) {
14
- const value = React6.useMemo(() => ({ config, pathname }), [config, pathname]);
14
+ const value = React7.useMemo(() => ({ config, pathname }), [config, pathname]);
15
15
  return /* @__PURE__ */ jsx(ConfigContext.Provider, { value, children });
16
16
  }
17
17
  function useConfig() {
18
- const context = React6.useContext(ConfigContext);
18
+ const context = React7.useContext(ConfigContext);
19
19
  if (!context) throw new Error("useConfig must be used within ConfigProvider");
20
20
  return context;
21
21
  }
22
22
 
23
+ // src/shared/utils/client/build-cookie-string.ts
24
+ var buildCookieString = (cookie, locale) => {
25
+ const parts = [`${cookie.name}=${encodeURIComponent(locale)}`];
26
+ if (cookie.maxAge) {
27
+ const expires = new Date(Date.now() + cookie.maxAge * 1e3).toUTCString();
28
+ parts.push(`expires=${expires}`, `max-age=${cookie.maxAge}`);
29
+ }
30
+ parts.push(`path=${cookie.path ?? "/"}`);
31
+ if (cookie.domain) {
32
+ parts.push(`domain=${cookie.domain}`);
33
+ }
34
+ if (cookie.sameSite) {
35
+ parts.push(
36
+ `SameSite=${cookie.sameSite[0].toUpperCase()}${cookie.sameSite.slice(1).toLowerCase()}`
37
+ );
38
+ }
39
+ if (cookie.secure !== false) {
40
+ parts.push(`Secure`);
41
+ }
42
+ return parts.join("; ");
43
+ };
44
+
45
+ // src/shared/utils/client/set-locale-cookie-browser.ts
46
+ var setLocaleCookieBrowser = ({
47
+ cookie,
48
+ locale
49
+ }) => {
50
+ if (typeof document === "undefined") return;
51
+ if (!cookie.enabled || !cookie.autoSetCookie) return;
52
+ const cookieString = buildCookieString(cookie, locale);
53
+ document.cookie = cookieString;
54
+ };
55
+
56
+ // src/client/react/contexts/locale/utils/use-init-locale-cookie.ts
57
+ var useInitLocaleCookie = ({
58
+ config,
59
+ locale
60
+ }) => {
61
+ React7.useEffect(() => {
62
+ if (typeof document === "undefined") return;
63
+ const { cookie, routing } = config;
64
+ const { firstVisit } = routing;
65
+ const cookies = document.cookie.split(";").map((c) => c.trim());
66
+ const isCookieExists = cookies.some((c) => c.startsWith(`${cookie.name}=`));
67
+ if (isCookieExists) return;
68
+ if (!firstVisit.redirect) return;
69
+ if (!cookie.enabled || !cookie.autoSetCookie) return;
70
+ setLocaleCookieBrowser({ cookie, locale });
71
+ }, []);
72
+ };
73
+
23
74
  // src/config/constants/cache.constants.ts
24
75
  var DEFAULT_CACHE_OPTIONS = {
25
76
  enabled: process.env.NODE_ENV === "production",
@@ -332,19 +383,19 @@ var useRefetchMessages = ({
332
383
  setLoadedMessages,
333
384
  setIsLoadingMessages
334
385
  }) => {
335
- const { messages: staticMessages } = config;
336
- const namespaces = React6.useMemo(() => {
337
- if (!config.loader) return [];
386
+ const { messages: staticMessages, loader } = config;
387
+ const namespaces = React7.useMemo(() => {
388
+ if (!loader) return [];
338
389
  return resolveNamespaces({ config, pathname });
339
390
  }, [config, pathname]);
340
- const refetchMessages = React6.useCallback(
391
+ const refetchMessages = React7.useCallback(
341
392
  async (newLocale) => {
342
- if (config.loader?.type === "remote") {
393
+ if (loader?.type === "remote") {
343
394
  setIsLoadingMessages(true);
344
395
  const loadedMessages = await loadRemoteMessages({
345
- rootDir: config.loader.rootDir,
346
- remoteUrl: config.loader.remoteUrl,
347
- remoteHeaders: config.loader.remoteHeaders,
396
+ rootDir: loader.rootDir,
397
+ remoteUrl: loader.remoteUrl,
398
+ remoteHeaders: loader.remoteHeaders,
348
399
  locale: newLocale,
349
400
  fallbackLocales: config.fallbackLocales[newLocale] || [],
350
401
  namespaces,
@@ -359,8 +410,9 @@ var useRefetchMessages = ({
359
410
  }
360
411
  },
361
412
  [
362
- config.loader,
413
+ loader,
363
414
  config.fallbackLocales,
415
+ config.cache,
364
416
  config.id,
365
417
  setIsLoadingMessages,
366
418
  namespaces,
@@ -370,21 +422,21 @@ var useRefetchMessages = ({
370
422
  );
371
423
  return { refetchMessages };
372
424
  };
373
- var MessagesContext = React6.createContext(void 0);
425
+ var MessagesContext = React7.createContext(void 0);
374
426
  function MessagesProvider({
375
427
  value: { messages = {} },
376
428
  children
377
429
  }) {
378
430
  const { config, pathname } = useConfig();
379
- const [loadedMessages, setLoadedMessages] = React6.useState(null);
380
- const [isLoadingMessages, setIsLoadingMessages] = React6.useState(false);
431
+ const [loadedMessages, setLoadedMessages] = React7.useState(null);
432
+ const [isLoadingMessages, setIsLoadingMessages] = React7.useState(false);
381
433
  const { refetchMessages } = useRefetchMessages({
382
434
  config,
383
435
  pathname,
384
436
  setLoadedMessages,
385
437
  setIsLoadingMessages
386
438
  });
387
- const value = React6.useMemo(
439
+ const value = React7.useMemo(
388
440
  () => ({
389
441
  messages: loadedMessages || messages,
390
442
  isLoading: isLoadingMessages,
@@ -397,101 +449,34 @@ function MessagesProvider({
397
449
  return /* @__PURE__ */ jsx(MessagesContext.Provider, { value, children });
398
450
  }
399
451
  function useMessages() {
400
- const context = React6.useContext(MessagesContext);
452
+ const context = React7.useContext(MessagesContext);
401
453
  if (!context)
402
454
  throw new Error("useMessages must be used within a MessagesProvider");
403
455
  return context;
404
456
  }
405
-
406
- // src/client/react/contexts/locale/utils/use-init-lazy-load.ts
407
- var useInitLazyLoad = ({
408
- loaderOptions,
409
- currentLocale
410
- }) => {
411
- const { refetchMessages } = useMessages();
412
- const lazyLoad = !!loaderOptions?.lazyLoad;
413
- const isFirstLoadedRef = React6.useRef(false);
414
- React6.useEffect(() => {
415
- if (lazyLoad && !isFirstLoadedRef.current) {
416
- void refetchMessages(currentLocale);
417
- isFirstLoadedRef.current = true;
418
- }
419
- }, [lazyLoad, currentLocale, refetchMessages, isFirstLoadedRef]);
420
- };
421
-
422
- // src/shared/utils/client/build-cookie-string.ts
423
- var buildCookieString = (cookie, locale) => {
424
- const parts = [`${cookie.name}=${encodeURIComponent(locale)}`];
425
- if (cookie.maxAge) {
426
- const expires = new Date(Date.now() + cookie.maxAge * 1e3).toUTCString();
427
- parts.push(`expires=${expires}`, `max-age=${cookie.maxAge}`);
428
- }
429
- parts.push(`path=${cookie.path ?? "/"}`);
430
- if (cookie.domain) {
431
- parts.push(`domain=${cookie.domain}`);
432
- }
433
- if (cookie.sameSite) {
434
- parts.push(
435
- `SameSite=${cookie.sameSite[0].toUpperCase()}${cookie.sameSite.slice(1).toLowerCase()}`
436
- );
437
- }
438
- if (cookie.secure !== false) {
439
- parts.push(`Secure`);
440
- }
441
- return parts.join("; ");
442
- };
443
-
444
- // src/shared/utils/client/set-locale-cookie-browser.ts
445
- var setLocaleCookieBrowser = ({
446
- cookie,
447
- locale
448
- }) => {
449
- if (globalThis.window === void 0) return;
450
- if (cookie.disabled || !cookie.autoSetCookie) return;
451
- const cookieString = buildCookieString(cookie, locale);
452
- document.cookie = cookieString;
453
- };
454
-
455
- // src/client/react/contexts/locale/utils/use-init-locale-cookie.ts
456
- var useInitLocaleCookie = ({
457
- config,
458
- locale
459
- }) => {
460
- React6.useEffect(() => {
461
- if (typeof document === "undefined") return;
462
- const { cookie, routing } = config;
463
- const { firstVisit } = routing;
464
- const cookies = document.cookie.split(";").map((c) => c.trim());
465
- const isCookieExists = cookies.some((c) => c.startsWith(`${cookie.name}=`));
466
- if (isCookieExists) return;
467
- if (!firstVisit.redirect) return;
468
- if (cookie.disabled || !cookie.autoSetCookie) return;
469
- setLocaleCookieBrowser({ cookie, locale });
470
- }, []);
471
- };
472
- var LocaleContext = React6.createContext(void 0);
457
+ var LocaleContext = React7.createContext(void 0);
473
458
 
474
459
  // src/client/react/contexts/locale/utils/change-locale.ts
475
460
  var changeLocale = ({
476
461
  currentLocale,
477
462
  newLocale,
478
- loaderOptions,
463
+ loader,
479
464
  cookie,
480
465
  setLocale,
481
466
  refetchMessages
482
467
  }) => {
483
468
  if (typeof document === "undefined") return;
484
- const loaderType = loaderOptions?.type;
469
+ const { type } = loader || {};
485
470
  if (newLocale === currentLocale) return;
486
- if (loaderType === "local") {
471
+ if (type === "local") {
487
472
  console.warn(
488
- `[Intor] You are using dynamic local to switch languages. Please make sure to use the wrapped <Link> component to trigger a page reload, ensuring that the translation data is dynamically updated.`
473
+ `[Intor] You are using "loader type: local" to switch languages. Please make sure to use the wrapped <Link> component to trigger a page reload, ensuring that the translation data is dynamically updated.`
489
474
  );
490
475
  }
491
476
  setLocale(newLocale);
492
477
  setLocaleCookieBrowser({ cookie, locale: newLocale });
493
478
  document.documentElement.lang = newLocale;
494
- if (loaderType === "remote" && refetchMessages) {
479
+ if (type === "remote" && refetchMessages) {
495
480
  void refetchMessages(newLocale);
496
481
  }
497
482
  };
@@ -501,25 +486,24 @@ function LocaleProvider({
501
486
  }) {
502
487
  const { config } = useConfig();
503
488
  const { refetchMessages } = useMessages();
504
- const { loader: loaderOptions, cookie } = config;
505
- const [currentLocale, setCurrentLocale] = React6.useState(initialLocale);
506
- useInitLazyLoad({ loaderOptions, currentLocale });
489
+ const { loader, cookie } = config;
490
+ const [currentLocale, setCurrentLocale] = React7.useState(initialLocale);
507
491
  useInitLocaleCookie({ config, locale: initialLocale });
508
- const setLocale = React6.useCallback(
492
+ const setLocale = React7.useCallback(
509
493
  async (newLocale) => {
510
494
  changeLocale({
511
495
  currentLocale,
512
496
  newLocale,
513
- loaderOptions,
497
+ loader,
514
498
  cookie,
515
499
  setLocale: setCurrentLocale,
516
500
  refetchMessages
517
501
  });
518
502
  onLocaleChange?.(newLocale);
519
503
  },
520
- [currentLocale, loaderOptions, cookie, refetchMessages, onLocaleChange]
504
+ [currentLocale, loader, cookie, refetchMessages, onLocaleChange]
521
505
  );
522
- const value = React6.useMemo(
506
+ const value = React7.useMemo(
523
507
  () => ({
524
508
  locale: currentLocale,
525
509
  setLocale
@@ -529,66 +513,56 @@ function LocaleProvider({
529
513
  return /* @__PURE__ */ jsx(LocaleContext.Provider, { value, children });
530
514
  }
531
515
  function useLocale() {
532
- const context = React6.useContext(LocaleContext);
516
+ const context = React7.useContext(LocaleContext);
533
517
  if (!context)
534
518
  throw new Error("useLocale must be used within a LocaleProvider");
535
519
  return context;
536
520
  }
537
- var TranslateHandlersContext = React6.createContext(void 0);
521
+ var TranslateHandlersContext = React7.createContext(void 0);
538
522
  var TranslateHandlersProvider = ({
539
- children,
540
- handlers
523
+ handlers,
524
+ children
541
525
  }) => {
542
- const value = handlers;
543
- return /* @__PURE__ */ jsx(TranslateHandlersContext.Provider, { value, children });
526
+ return /* @__PURE__ */ jsx(TranslateHandlersContext.Provider, { value: { handlers }, children });
544
527
  };
545
528
  function useTranslateHandlers() {
546
- const context = React6.useContext(TranslateHandlersContext);
529
+ const context = React7.useContext(TranslateHandlersContext);
547
530
  return context;
548
531
  }
549
- var useInitLoadingState = (config) => {
550
- const lazyLoad = !!config.loader?.lazyLoad;
551
- const [isCsr, setIsCsr] = React6.useState(false);
552
- React6.useEffect(() => {
553
- setIsCsr(true);
554
- }, []);
555
- const isBeforeCSRLoading = lazyLoad && !isCsr;
556
- return isBeforeCSRLoading;
557
- };
558
- var TranslatorContext = React6.createContext(void 0);
559
- var EMPTY_OBJECT = Object.freeze({});
560
- function TranslatorProvider({ children }) {
532
+ var TranslatorContext = React7.createContext(void 0);
533
+ function TranslatorProvider({
534
+ value: { isLoading: externalIsLoading },
535
+ children
536
+ }) {
561
537
  const { config } = useConfig();
562
- const { messages, isLoading } = useMessages();
538
+ const { messages, isLoading: internalIsLoading } = useMessages();
563
539
  const { locale } = useLocale();
564
- const translatorHandlers = useTranslateHandlers();
540
+ const { handlers } = useTranslateHandlers();
565
541
  const { fallbackLocales, translator: translatorOptions } = config;
566
- const isBeforeCSRLoading = useInitLoadingState(config);
567
- const value = React6.useMemo(() => {
568
- const translator = new Translator({
569
- messages: messages || EMPTY_OBJECT,
542
+ const isLoading = Boolean(externalIsLoading ?? internalIsLoading);
543
+ const translator = React7.useMemo(() => {
544
+ return new Translator({
545
+ messages,
570
546
  locale,
547
+ isLoading,
571
548
  fallbackLocales,
572
549
  loadingMessage: translatorOptions?.loadingMessage,
573
550
  placeholder: translatorOptions?.placeholder,
574
- handlers: translatorHandlers
551
+ handlers
575
552
  });
576
- translator.setLoading(isBeforeCSRLoading || isLoading);
577
- return { translator };
578
553
  }, [
579
- fallbackLocales,
580
- isBeforeCSRLoading,
581
- isLoading,
582
- locale,
583
554
  messages,
584
- translatorHandlers,
555
+ locale,
556
+ isLoading,
557
+ fallbackLocales,
558
+ handlers,
585
559
  translatorOptions?.loadingMessage,
586
560
  translatorOptions?.placeholder
587
561
  ]);
588
- return /* @__PURE__ */ jsx(TranslatorContext.Provider, { value, children });
562
+ return /* @__PURE__ */ jsx(TranslatorContext.Provider, { value: { translator }, children });
589
563
  }
590
564
  function useTranslator() {
591
- const context = React6.useContext(TranslatorContext);
565
+ const context = React7.useContext(TranslatorContext);
592
566
  if (!context)
593
567
  throw new Error(
594
568
  "useTranslator must be used within IntorTranslatorProvider"
@@ -601,11 +575,12 @@ var IntorProvider = ({
601
575
  pathname = "",
602
576
  initialLocale,
603
577
  messages = config.messages,
604
- onLocaleChange
578
+ onLocaleChange,
579
+ isLoading
605
580
  },
606
581
  children
607
582
  }) => {
608
- return /* @__PURE__ */ jsx(ConfigProvider, { value: { config, pathname }, children: /* @__PURE__ */ jsx(MessagesProvider, { value: { messages }, children: /* @__PURE__ */ jsx(LocaleProvider, { value: { initialLocale, onLocaleChange }, children: /* @__PURE__ */ jsx(TranslatorProvider, { children }) }) }) });
583
+ return /* @__PURE__ */ jsx(ConfigProvider, { value: { config, pathname }, children: /* @__PURE__ */ jsx(MessagesProvider, { value: { messages }, children: /* @__PURE__ */ jsx(LocaleProvider, { value: { initialLocale, onLocaleChange }, children: /* @__PURE__ */ jsx(TranslatorProvider, { value: { isLoading }, children }) }) }) });
609
584
  };
610
585
 
611
586
  // src/client/react/hooks/use-translator.ts
@@ -17,14 +17,7 @@ var fs__default = /*#__PURE__*/_interopDefault(fs);
17
17
  var merge__default = /*#__PURE__*/_interopDefault(merge);
18
18
  var Keyv__default = /*#__PURE__*/_interopDefault(Keyv);
19
19
 
20
- // src/server/intor/utils/should-load-messages.ts
21
- var shouldLoadMessages = (loader) => {
22
- if (!loader) return false;
23
- const { type, lazyLoad } = loader;
24
- if (type === "local") return true;
25
- if (lazyLoad) return false;
26
- return true;
27
- };
20
+ // src/server/messages/load-local-messages/load-local-messages.ts
28
21
 
29
22
  // src/config/constants/cache.constants.ts
30
23
  var DEFAULT_CACHE_OPTIONS = {
@@ -641,7 +634,7 @@ var intor = async (config, i18nContext, loadMessagesOptions = {}) => {
641
634
  const source = isI18nContextFunction ? i18nContext.name : "static fallback";
642
635
  logger.debug(`I18n context resolved via ${source}.`, context);
643
636
  let loadedMessages;
644
- if (shouldLoadMessages(loader)) {
637
+ if (loader) {
645
638
  loadedMessages = await loadMessages({
646
639
  config,
647
640
  locale,
@@ -658,7 +651,7 @@ var intor = async (config, i18nContext, loadMessagesOptions = {}) => {
658
651
  static: { enabled: !!messages },
659
652
  loaded: {
660
653
  enabled: !!loadedMessages,
661
- ...loader ? { loaderType: loader.type, lazyLoad: !!loader.lazyLoad } : null
654
+ ...loader ? { loaderType: loader.type } : null
662
655
  },
663
656
  merged: mergedMessages
664
657
  });
@@ -4,8 +4,8 @@ import Keyv from 'keyv';
4
4
  import { Logger } from 'logry';
5
5
 
6
6
  type CookieRawOptions = {
7
- /** Completely disable cookie usage (no read, no write, no lookup by name) - default: false */
8
- disabled?: boolean;
7
+ /** Enable cookie usage (read/write) - default: true */
8
+ enabled?: boolean;
9
9
  /** Allow the system to automatically set cookies - default: true */
10
10
  autoSetCookie?: boolean;
11
11
  /** default: "intor.i18n.locale" */
@@ -53,7 +53,6 @@ type BaseLoaderOptions = {
53
53
  namespaces?: string[];
54
54
  routeNamespaces?: RouteNamespaces;
55
55
  concurrency?: number;
56
- lazyLoad?: boolean;
57
56
  };
58
57
  type LocalLoader = BaseLoaderOptions & {
59
58
  type: "local";
@@ -90,6 +89,7 @@ type RoutingRawOptions = {
90
89
  type RoutingResolvedOptions = Required<RoutingRawOptions>;
91
90
 
92
91
  type CacheRawOptions = {
92
+ /** default: process.env.NODE_ENV === "production" */
93
93
  enabled?: boolean;
94
94
  /** default: 60\*60\*1000 (1 hour) */
95
95
  ttl?: number;
@@ -4,8 +4,8 @@ import Keyv from 'keyv';
4
4
  import { Logger } from 'logry';
5
5
 
6
6
  type CookieRawOptions = {
7
- /** Completely disable cookie usage (no read, no write, no lookup by name) - default: false */
8
- disabled?: boolean;
7
+ /** Enable cookie usage (read/write) - default: true */
8
+ enabled?: boolean;
9
9
  /** Allow the system to automatically set cookies - default: true */
10
10
  autoSetCookie?: boolean;
11
11
  /** default: "intor.i18n.locale" */
@@ -53,7 +53,6 @@ type BaseLoaderOptions = {
53
53
  namespaces?: string[];
54
54
  routeNamespaces?: RouteNamespaces;
55
55
  concurrency?: number;
56
- lazyLoad?: boolean;
57
56
  };
58
57
  type LocalLoader = BaseLoaderOptions & {
59
58
  type: "local";
@@ -90,6 +89,7 @@ type RoutingRawOptions = {
90
89
  type RoutingResolvedOptions = Required<RoutingRawOptions>;
91
90
 
92
91
  type CacheRawOptions = {
92
+ /** default: process.env.NODE_ENV === "production" */
93
93
  enabled?: boolean;
94
94
  /** default: 60\*60\*1000 (1 hour) */
95
95
  ttl?: number;
@@ -7,14 +7,7 @@ import merge from 'lodash.merge';
7
7
  import Keyv from 'keyv';
8
8
  import { Translator } from 'intor-translator';
9
9
 
10
- // src/server/intor/utils/should-load-messages.ts
11
- var shouldLoadMessages = (loader) => {
12
- if (!loader) return false;
13
- const { type, lazyLoad } = loader;
14
- if (type === "local") return true;
15
- if (lazyLoad) return false;
16
- return true;
17
- };
10
+ // src/server/messages/load-local-messages/load-local-messages.ts
18
11
 
19
12
  // src/config/constants/cache.constants.ts
20
13
  var DEFAULT_CACHE_OPTIONS = {
@@ -631,7 +624,7 @@ var intor = async (config, i18nContext, loadMessagesOptions = {}) => {
631
624
  const source = isI18nContextFunction ? i18nContext.name : "static fallback";
632
625
  logger.debug(`I18n context resolved via ${source}.`, context);
633
626
  let loadedMessages;
634
- if (shouldLoadMessages(loader)) {
627
+ if (loader) {
635
628
  loadedMessages = await loadMessages({
636
629
  config,
637
630
  locale,
@@ -648,7 +641,7 @@ var intor = async (config, i18nContext, loadMessagesOptions = {}) => {
648
641
  static: { enabled: !!messages },
649
642
  loaded: {
650
643
  enabled: !!loadedMessages,
651
- ...loader ? { loaderType: loader.type, lazyLoad: !!loader.lazyLoad } : null
644
+ ...loader ? { loaderType: loader.type } : null
652
645
  },
653
646
  merged: mergedMessages
654
647
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "intor",
3
- "version": "2.2.12",
3
+ "version": "2.2.13",
4
4
  "description": "A modular and extensible i18n core designed for TypeScript and JavaScript projects. Intor enables custom translation logic with support for both frontend and backend environments, featuring runtime configuration, caching, adapters, and message loaders.",
5
5
  "author": "Yiming Liao",
6
6
  "license": "MIT",
@@ -80,7 +80,7 @@
80
80
  "knip": "knip --config .config/knip.config.ts"
81
81
  },
82
82
  "dependencies": {
83
- "intor-translator": "^1.1.2",
83
+ "intor-translator": "^1.1.5",
84
84
  "keyv": "^5.5.3",
85
85
  "lodash.merge": "^4.6.2",
86
86
  "logry": "^2.0.1",