@lingui/react 4.3.0 → 4.4.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.cjs CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const React = require('react');
4
+ const shim = require('use-sync-external-store/shim');
4
5
 
5
6
  const LinguiContext = React.createContext(null);
6
7
  function useLingui() {
@@ -17,33 +18,44 @@ const I18nProvider = ({
17
18
  defaultComponent,
18
19
  children
19
20
  }) => {
20
- const latestKnownLocale = React.useRef(i18n.locale);
21
21
  const makeContext = React.useCallback(
22
22
  () => ({
23
23
  i18n,
24
- defaultComponent
24
+ defaultComponent,
25
+ _: i18n.t.bind(i18n)
25
26
  }),
26
27
  [i18n, defaultComponent]
27
28
  );
28
- const [context, setContext] = React.useState(makeContext());
29
- React.useEffect(() => {
30
- const updateContext = () => {
31
- latestKnownLocale.current = i18n.locale;
32
- setContext(makeContext());
33
- };
34
- const unsubscribe = i18n.on("change", updateContext);
35
- if (latestKnownLocale.current !== i18n.locale) {
36
- updateContext();
37
- }
38
- return unsubscribe;
39
- }, [i18n, makeContext]);
40
- if (!latestKnownLocale.current) {
29
+ const context = React.useRef(makeContext());
30
+ const subscribe = React.useCallback(
31
+ (onStoreChange) => {
32
+ const renderWithFreshContext = () => {
33
+ context.current = makeContext();
34
+ onStoreChange();
35
+ };
36
+ const propsChanged = context.current.i18n !== i18n || context.current.defaultComponent !== defaultComponent;
37
+ if (propsChanged) {
38
+ renderWithFreshContext();
39
+ }
40
+ return i18n.on("change", renderWithFreshContext);
41
+ },
42
+ [makeContext, i18n, defaultComponent]
43
+ );
44
+ const getSnapshot = React.useCallback(() => {
45
+ return context.current;
46
+ }, []);
47
+ const contextObject = shim.useSyncExternalStore(
48
+ subscribe,
49
+ getSnapshot,
50
+ getSnapshot
51
+ );
52
+ if (!contextObject.i18n.locale) {
41
53
  process.env.NODE_ENV === "development" && console.log(
42
54
  "I18nProvider rendered `null`. A call to `i18n.activate` needs to happen in order for translations to be activated and for the I18nProvider to render.This is not an error but an informational message logged only in development."
43
55
  );
44
56
  return null;
45
57
  }
46
- return /* @__PURE__ */ React.createElement(LinguiContext.Provider, { value: context }, children);
58
+ return /* @__PURE__ */ React.createElement(LinguiContext.Provider, { value: contextObject }, children);
47
59
  };
48
60
 
49
61
  const tagRe = /<([a-zA-Z0-9]+)>(.*?)<\/\1>|<([a-zA-Z0-9]+)\/>/;
@@ -76,7 +88,7 @@ function formatElements(value, elements = {}) {
76
88
  if (before)
77
89
  tree.push(before);
78
90
  for (const [index, children, after] of getElements(parts)) {
79
- let element = elements[index];
91
+ let element = typeof index !== "undefined" ? elements[index] : void 0;
80
92
  if (!element || voidElementTags[element.type] && children) {
81
93
  if (!element) {
82
94
  console.error(
@@ -110,21 +122,26 @@ function getElements(parts) {
110
122
  if (!parts.length)
111
123
  return [];
112
124
  const [paired, children, unpaired, after] = parts.slice(0, 4);
113
- return [[paired || unpaired, children || "", after]].concat(
114
- getElements(parts.slice(4, parts.length))
115
- );
125
+ const triple = [paired || unpaired, children || "", after];
126
+ return [triple].concat(getElements(parts.slice(4, parts.length)));
116
127
  }
117
128
  const makeCounter = (count = 0, prefix = "") => () => `${prefix}_${count++}`;
118
129
 
119
- function Trans(props) {
120
- const { i18n, defaultComponent } = useLingui();
121
- const { render, component, id, message, formats } = props;
130
+ function TransNoContext(props) {
131
+ const {
132
+ render,
133
+ component,
134
+ id,
135
+ message,
136
+ formats,
137
+ lingui: { i18n, defaultComponent }
138
+ } = props;
122
139
  const values = { ...props.values };
123
140
  const components = { ...props.components };
124
141
  if (values) {
125
142
  Object.keys(values).forEach((key) => {
126
143
  const value = values[key];
127
- const valueIsReactEl = React.isValidElement(value) || Array.isArray(value) && value.every((el) => React.isValidElement(el));
144
+ const valueIsReactEl = React.isValidElement(value) || Array.isArray(value) && value.every(React.isValidElement);
128
145
  if (!valueIsReactEl)
129
146
  return;
130
147
  const index = Object.keys(components).length;
@@ -170,6 +187,11 @@ const RenderFragment = ({ children }) => {
170
187
  return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
171
188
  };
172
189
 
190
+ function Trans(props) {
191
+ const lingui = useLingui();
192
+ return React.createElement(TransNoContext, { ...props, lingui });
193
+ }
194
+
173
195
  exports.I18nProvider = I18nProvider;
174
196
  exports.LinguiContext = LinguiContext;
175
197
  exports.Trans = Trans;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import React, { ComponentType, FunctionComponent } from 'react';
2
- import { I18n } from '@lingui/core';
2
+ import { MessageOptions, I18n } from '@lingui/core';
3
3
 
4
4
  type TransRenderProps = {
5
5
  id: string;
@@ -10,7 +10,7 @@ type TransRenderProps = {
10
10
  };
11
11
  type TransRenderCallbackOrComponent = {
12
12
  component?: undefined;
13
- render?: (props: TransRenderProps) => React.ReactElement<any, any> | null;
13
+ render?: ((props: TransRenderProps) => React.ReactElement<any, any>) | null;
14
14
  } | {
15
15
  component?: React.ComponentType<TransRenderProps> | null;
16
16
  render?: undefined;
@@ -22,21 +22,23 @@ type TransProps = {
22
22
  components?: {
23
23
  [key: string]: React.ElementType | any;
24
24
  };
25
- formats?: Record<string, unknown>;
25
+ formats?: MessageOptions["formats"];
26
26
  comment?: string;
27
27
  children?: React.ReactNode;
28
28
  } & TransRenderCallbackOrComponent;
29
- declare function Trans(props: TransProps): React.ReactElement<any, any> | null;
30
29
 
31
30
  type I18nContext = {
32
31
  i18n: I18n;
32
+ _: I18n["_"];
33
33
  defaultComponent?: ComponentType<TransRenderProps>;
34
34
  };
35
- type I18nProviderProps = I18nContext & {
35
+ type I18nProviderProps = Omit<I18nContext, "_"> & {
36
36
  children?: React.ReactNode;
37
37
  };
38
- declare const LinguiContext: React.Context<I18nContext>;
38
+ declare const LinguiContext: React.Context<I18nContext | null>;
39
39
  declare function useLingui(): I18nContext;
40
40
  declare const I18nProvider: FunctionComponent<I18nProviderProps>;
41
41
 
42
+ declare function Trans(props: TransProps): React.ReactElement<any, any> | null;
43
+
42
44
  export { I18nContext, I18nProvider, I18nProviderProps, LinguiContext, Trans, TransProps, TransRenderCallbackOrComponent, TransRenderProps, useLingui };
package/dist/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
- import React from 'react';
1
+ import React, { useCallback, useRef } from 'react';
2
+ import { useSyncExternalStore } from 'use-sync-external-store/shim';
2
3
 
3
4
  const LinguiContext = React.createContext(null);
4
5
  function useLingui() {
@@ -15,33 +16,44 @@ const I18nProvider = ({
15
16
  defaultComponent,
16
17
  children
17
18
  }) => {
18
- const latestKnownLocale = React.useRef(i18n.locale);
19
- const makeContext = React.useCallback(
19
+ const makeContext = useCallback(
20
20
  () => ({
21
21
  i18n,
22
- defaultComponent
22
+ defaultComponent,
23
+ _: i18n.t.bind(i18n)
23
24
  }),
24
25
  [i18n, defaultComponent]
25
26
  );
26
- const [context, setContext] = React.useState(makeContext());
27
- React.useEffect(() => {
28
- const updateContext = () => {
29
- latestKnownLocale.current = i18n.locale;
30
- setContext(makeContext());
31
- };
32
- const unsubscribe = i18n.on("change", updateContext);
33
- if (latestKnownLocale.current !== i18n.locale) {
34
- updateContext();
35
- }
36
- return unsubscribe;
37
- }, [i18n, makeContext]);
38
- if (!latestKnownLocale.current) {
27
+ const context = useRef(makeContext());
28
+ const subscribe = useCallback(
29
+ (onStoreChange) => {
30
+ const renderWithFreshContext = () => {
31
+ context.current = makeContext();
32
+ onStoreChange();
33
+ };
34
+ const propsChanged = context.current.i18n !== i18n || context.current.defaultComponent !== defaultComponent;
35
+ if (propsChanged) {
36
+ renderWithFreshContext();
37
+ }
38
+ return i18n.on("change", renderWithFreshContext);
39
+ },
40
+ [makeContext, i18n, defaultComponent]
41
+ );
42
+ const getSnapshot = useCallback(() => {
43
+ return context.current;
44
+ }, []);
45
+ const contextObject = useSyncExternalStore(
46
+ subscribe,
47
+ getSnapshot,
48
+ getSnapshot
49
+ );
50
+ if (!contextObject.i18n.locale) {
39
51
  process.env.NODE_ENV === "development" && console.log(
40
52
  "I18nProvider rendered `null`. A call to `i18n.activate` needs to happen in order for translations to be activated and for the I18nProvider to render.This is not an error but an informational message logged only in development."
41
53
  );
42
54
  return null;
43
55
  }
44
- return /* @__PURE__ */ React.createElement(LinguiContext.Provider, { value: context }, children);
56
+ return /* @__PURE__ */ React.createElement(LinguiContext.Provider, { value: contextObject }, children);
45
57
  };
46
58
 
47
59
  const tagRe = /<([a-zA-Z0-9]+)>(.*?)<\/\1>|<([a-zA-Z0-9]+)\/>/;
@@ -74,7 +86,7 @@ function formatElements(value, elements = {}) {
74
86
  if (before)
75
87
  tree.push(before);
76
88
  for (const [index, children, after] of getElements(parts)) {
77
- let element = elements[index];
89
+ let element = typeof index !== "undefined" ? elements[index] : void 0;
78
90
  if (!element || voidElementTags[element.type] && children) {
79
91
  if (!element) {
80
92
  console.error(
@@ -108,21 +120,26 @@ function getElements(parts) {
108
120
  if (!parts.length)
109
121
  return [];
110
122
  const [paired, children, unpaired, after] = parts.slice(0, 4);
111
- return [[paired || unpaired, children || "", after]].concat(
112
- getElements(parts.slice(4, parts.length))
113
- );
123
+ const triple = [paired || unpaired, children || "", after];
124
+ return [triple].concat(getElements(parts.slice(4, parts.length)));
114
125
  }
115
126
  const makeCounter = (count = 0, prefix = "") => () => `${prefix}_${count++}`;
116
127
 
117
- function Trans(props) {
118
- const { i18n, defaultComponent } = useLingui();
119
- const { render, component, id, message, formats } = props;
128
+ function TransNoContext(props) {
129
+ const {
130
+ render,
131
+ component,
132
+ id,
133
+ message,
134
+ formats,
135
+ lingui: { i18n, defaultComponent }
136
+ } = props;
120
137
  const values = { ...props.values };
121
138
  const components = { ...props.components };
122
139
  if (values) {
123
140
  Object.keys(values).forEach((key) => {
124
141
  const value = values[key];
125
- const valueIsReactEl = React.isValidElement(value) || Array.isArray(value) && value.every((el) => React.isValidElement(el));
142
+ const valueIsReactEl = React.isValidElement(value) || Array.isArray(value) && value.every(React.isValidElement);
126
143
  if (!valueIsReactEl)
127
144
  return;
128
145
  const index = Object.keys(components).length;
@@ -168,4 +185,9 @@ const RenderFragment = ({ children }) => {
168
185
  return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
169
186
  };
170
187
 
188
+ function Trans(props) {
189
+ const lingui = useLingui();
190
+ return React.createElement(TransNoContext, { ...props, lingui });
191
+ }
192
+
171
193
  export { I18nProvider, LinguiContext, Trans, useLingui };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lingui/react",
3
- "version": "4.3.0",
3
+ "version": "4.4.1",
4
4
  "sideEffects": false,
5
5
  "description": "React components for translations",
6
6
  "main": "./dist/index.cjs",
@@ -63,17 +63,19 @@
63
63
  },
64
64
  "dependencies": {
65
65
  "@babel/runtime": "^7.20.13",
66
- "@lingui/core": "4.3.0"
66
+ "@lingui/core": "4.4.1",
67
+ "use-sync-external-store": "^1.2.0"
67
68
  },
68
69
  "devDependencies": {
69
70
  "@lingui/jest-mocks": "*",
70
71
  "@testing-library/react": "^14.0.0",
71
72
  "@types/react": "^18.2.13",
73
+ "@types/use-sync-external-store": "^0.0.3",
72
74
  "eslint-plugin-react": "^7.32.2",
73
75
  "eslint-plugin-react-hooks": "^4.6.0",
74
76
  "react": "^18.2.0",
75
77
  "react-dom": "^18.2.0",
76
78
  "unbuild": "^1.1.2"
77
79
  },
78
- "gitHead": "da6c52629e978c24ec83f2a6c22e4dfc910808b4"
80
+ "gitHead": "e7103c9f06a493e5871086e121f037309b0b742c"
79
81
  }