@lingui/macro 3.10.1 → 3.12.0

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/global.d.ts CHANGED
@@ -1,13 +1,68 @@
1
- declare module '@lingui/macro' {
2
- import type { MessageDescriptor } from "@lingui/core"
1
+ declare module "@lingui/macro" {
2
+ import type { MessageDescriptor, I18n } from "@lingui/core"
3
3
 
4
4
  export type BasicType = {
5
5
  id?: string
6
6
  comment?: string
7
7
  }
8
8
 
9
+ /**
10
+ * Translates a message descriptor
11
+ *
12
+ * @example
13
+ * ```
14
+ * import { t } from "@lingui/macro";
15
+ * const message = t({
16
+ * id: "msg.hello",
17
+ * comment: "Greetings at the homepage",
18
+ * message: `Hello ${name}`,
19
+ * });
20
+ * ```
21
+ *
22
+ * @example
23
+ * ```
24
+ * import { t } from "@lingui/macro";
25
+ * const message = t({
26
+ * id: "msg.plural",
27
+ * message: plural(value, { one: "...", other: "..." }),
28
+ * });
29
+ * ```
30
+ *
31
+ * @param messageDescriptior The descriptor to translate
32
+ */
33
+ export function t(messageDescriptior: MessageDescriptor): string
34
+
35
+ /**
36
+ * Translates a template string using the global I18n instance
37
+ *
38
+ * @example
39
+ * ```
40
+ * import { t } from "@lingui/macro";
41
+ * const message = t`Hello ${name}`;
42
+ * ```
43
+ */
44
+ export function t(
45
+ literals: TemplateStringsArray,
46
+ ...placeholders: any[]
47
+ ): string
48
+
49
+ /**
50
+ * Translates a template string using a given I18n instance
51
+ *
52
+ * @example
53
+ * ```
54
+ * import { t } from "@lingui/macro";
55
+ * import { I18n } from "@lingui/core";
56
+ * const i18n = new I18n({
57
+ * locale: "nl",
58
+ * messages: { "Hello {0}": "Hallo {0}" },
59
+ * });
60
+ * const message = t(i18n)`Hello ${name}`;
61
+ * ```
62
+ */
9
63
  export function t(
10
- literals: TemplateStringsArray | MessageDescriptor,
64
+ i18n: I18n,
65
+ literals: TemplateStringsArray,
11
66
  ...placeholders: any[]
12
67
  ): string
13
68
 
@@ -21,20 +76,107 @@ declare module '@lingui/macro' {
21
76
  other?: T
22
77
  } & UnderscoreDigit<T>
23
78
 
24
- export function plural(arg: number | string, options: ChoiceOptions & BasicType): string
79
+ /**
80
+ * Pluralize a message
81
+ *
82
+ * @example
83
+ * ```
84
+ * import { plural } from "@lingui/macro";
85
+ * const message = plural(count, {
86
+ * one: "# Book",
87
+ * other: "# Books",
88
+ * });
89
+ * ```
90
+ *
91
+ * @param value Determines the plural form
92
+ * @param options Object with available plural forms
93
+ */
94
+ export function plural(
95
+ value: number | string,
96
+ options: ChoiceOptions & BasicType
97
+ ): string
98
+
99
+ /**
100
+ * Pluralize a message using ordinal forms
101
+ *
102
+ * Similar to `plural` but instead of using cardinal plural forms,
103
+ * it uses ordinal forms.
104
+ *
105
+ * @example
106
+ * ```
107
+ * import { selectOrdinal } from "@lingui/macro";
108
+ * const message = selectOrdinal(count, {
109
+ * one: "1st",
110
+ * two: "2nd",
111
+ * few: "3rd",
112
+ * other: "#th",
113
+ * });
114
+ * ```
115
+ *
116
+ * @param value Determines the plural form
117
+ * @param options Object with available plural forms
118
+ */
25
119
  export function selectOrdinal(
26
- arg: number | string,
120
+ value: number | string,
27
121
  options: ChoiceOptions & BasicType
28
122
  ): string
29
- export function select(arg: string, choices: Record<string, string> & BasicType): string
123
+
124
+ /**
125
+ * Selects a translation based on a value
126
+ *
127
+ * Select works like a switch statement. It will
128
+ * select one of the forms in `options` object which
129
+ * key matches exactly `value`.
130
+ *
131
+ * @example
132
+ * ```
133
+ * import { select } from "@lingui/macro";
134
+ * const message = select(gender, {
135
+ * male: "he",
136
+ * female: "she",
137
+ * other: "they",
138
+ * });
139
+ * ```
140
+ *
141
+ * @param value The key of choices to use
142
+ * @param choices
143
+ */
144
+ export function select(
145
+ value: string,
146
+ choices: Record<string, string> & BasicType
147
+ ): string
148
+
149
+ /**
150
+ * Defines multiple messages for extraction
151
+ */
30
152
  export function defineMessages<M extends Record<string, MessageDescriptor>>(
31
153
  messages: M
32
154
  ): M
33
- export function defineMessage(descriptor: MessageDescriptor): MessageDescriptor
155
+
156
+ /**
157
+ * Define a message for later use
158
+ *
159
+ * `defineMessage` can be used to add comments for translators,
160
+ * or to override the message ID.
161
+ *
162
+ * @example
163
+ * ```
164
+ * import { defineMessage } from "@lingui/macro";
165
+ * const message = defineMessage({
166
+ * comment: "Greetings on the welcome page",
167
+ * message: `Welcome, ${name}!`,
168
+ * });
169
+ * ```
170
+ *
171
+ * @param descriptor The message descriptor
172
+ */
173
+ export function defineMessage(
174
+ descriptor: MessageDescriptor
175
+ ): MessageDescriptor
34
176
 
35
177
  export type ChoiceProps = {
36
178
  value?: string | number
37
- } & ChoiceOptions<string>
179
+ } & ChoiceOptions<string>
38
180
 
39
181
  /**
40
182
  * The types should be changed after this PR is merged
@@ -60,4 +202,4 @@ declare module '@lingui/macro' {
60
202
  export const Plural: any
61
203
  export const Select: any
62
204
  export const SelectOrdinal: any
63
- }
205
+ }
package/index.d.ts CHANGED
@@ -1,12 +1,7 @@
1
1
  import type { ReactElement, ComponentType, ReactNode } from "react"
2
- import type { MessageDescriptor } from "@lingui/core"
2
+ import type { MessageDescriptor, I18n } from "@lingui/core"
3
3
  import type { TransRenderProps } from "@lingui/react"
4
4
 
5
- export function t(
6
- literals: TemplateStringsArray | MessageDescriptor,
7
- ...placeholders: any[]
8
- ): string
9
-
10
5
  export type UnderscoreDigit<T = string> = { [digit: string]: T }
11
6
  export type ChoiceOptions<T = string> = {
12
7
  offset?: number
@@ -17,15 +12,156 @@ export type ChoiceOptions<T = string> = {
17
12
  other?: T
18
13
  } & UnderscoreDigit<T>
19
14
 
20
- export function plural(arg: number | string, options: ChoiceOptions): string
15
+ /**
16
+ * Translates a message descriptor
17
+ *
18
+ * @example
19
+ * ```
20
+ * import { t } from "@lingui/macro";
21
+ * const message = t({
22
+ * id: "msg.hello",
23
+ * comment: "Greetings at the homepage",
24
+ * message: `Hello ${name}`,
25
+ * });
26
+ * ```
27
+ *
28
+ * @example
29
+ * ```
30
+ * import { t } from "@lingui/macro";
31
+ * const message = t({
32
+ * id: "msg.plural",
33
+ * message: plural(value, { one: "...", other: "..." }),
34
+ * });
35
+ * ```
36
+ *
37
+ * @param messageDescriptior The descriptor to translate
38
+ */
39
+ export function t(messageDescriptior: MessageDescriptor): string
40
+
41
+ /**
42
+ * Translates a template string using the global I18n instance
43
+ *
44
+ * @example
45
+ * ```
46
+ * import { t } from "@lingui/macro";
47
+ * const message = t`Hello ${name}`;
48
+ * ```
49
+ */
50
+ export function t(
51
+ literals: TemplateStringsArray,
52
+ ...placeholders: any[]
53
+ ): string
54
+
55
+ /**
56
+ * Translates a template string using a given I18n instance
57
+ *
58
+ * @example
59
+ * ```
60
+ * import { t } from "@lingui/macro";
61
+ * import { I18n } from "@lingui/core";
62
+ * const i18n = new I18n({
63
+ * locale: "nl",
64
+ * messages: { "Hello {0}": "Hallo {0}" },
65
+ * });
66
+ * const message = t(i18n)`Hello ${name}`;
67
+ * ```
68
+ */
69
+ export function t(
70
+ i18n: I18n,
71
+ literals: TemplateStringsArray,
72
+ ...placeholders: any[]
73
+ ): string
74
+
75
+ /**
76
+ * Pluralize a message
77
+ *
78
+ * @example
79
+ * ```
80
+ * import { plural } from "@lingui/macro";
81
+ * const message = plural(count, {
82
+ * one: "# Book",
83
+ * other: "# Books",
84
+ * });
85
+ * ```
86
+ *
87
+ * @param value Determines the plural form
88
+ * @param options Object with available plural forms
89
+ */
90
+ export function plural(value: number | string, options: ChoiceOptions): string
91
+
92
+ /**
93
+ * Pluralize a message using ordinal forms
94
+ *
95
+ * Similar to `plural` but instead of using cardinal plural forms,
96
+ * it uses ordinal forms.
97
+ *
98
+ * @example
99
+ * ```
100
+ * import { selectOrdinal } from "@lingui/macro";
101
+ * const message = selectOrdinal(count, {
102
+ * one: "1st",
103
+ * two: "2nd",
104
+ * few: "3rd",
105
+ * other: "#th",
106
+ * });
107
+ * ```
108
+ *
109
+ * @param value Determines the plural form
110
+ * @param options Object with available plural forms
111
+ */
21
112
  export function selectOrdinal(
22
- arg: number | string,
113
+ value: number | string,
23
114
  options: ChoiceOptions
24
115
  ): string
25
- export function select(arg: string, choices: Record<string, string>): string
116
+
117
+ /**
118
+ * Selects a translation based on a value
119
+ *
120
+ * Select works like a switch statement. It will
121
+ * select one of the forms in `options` object which
122
+ * key matches exactly `value`.
123
+ *
124
+ * @example
125
+ * ```
126
+ * import { select } from "@lingui/macro";
127
+ * const message = select(gender, {
128
+ * male: "he",
129
+ * female: "she",
130
+ * other: "they",
131
+ * });
132
+ * ```
133
+ *
134
+ * @param value The key of choices to use
135
+ * @param choices
136
+ */
137
+ export function select(value: string, choices: ChoiceOptions): string
138
+
139
+ /**
140
+ * Defines multiple messages for extraction
141
+ *
142
+ * @see {@link defineMessage} for more details
143
+ */
26
144
  export function defineMessages<M extends Record<string, MessageDescriptor>>(
27
145
  messages: M
28
146
  ): M
147
+
148
+ /**
149
+ * Define a message for later use
150
+ *
151
+ * `defineMessage` can be used to add comments for translators,
152
+ * or to override the message ID.
153
+ *
154
+ * @example
155
+ * ```
156
+ * import { defineMessage } from "@lingui/macro";
157
+ * const message = defineMessage({
158
+ * comment: "Greetings on the welcome page",
159
+ * message: `Welcome, ${name}!`,
160
+ * });
161
+ * ```
162
+ *
163
+ * @param descriptor The message descriptor
164
+ */
29
165
  export function defineMessage(descriptor: MessageDescriptor): MessageDescriptor
30
166
 
31
167
  export type TransProps = {
package/index.js CHANGED
@@ -55,6 +55,7 @@ function macro(_ref) {
55
55
  babel = _ref.babel;
56
56
  var jsxNodes = [];
57
57
  var jsNodes = [];
58
+ var needsI18nImport = false;
58
59
  Object.keys(references).forEach(function (tagName) {
59
60
  var nodes = references[tagName];
60
61
  var macroType = getMacroType(tagName);
@@ -79,7 +80,7 @@ function macro(_ref) {
79
80
  var macro = new _macroJs.default(babel, {
80
81
  i18nImportName: i18nImportName
81
82
  });
82
- macro.replacePath(path);
83
+ if (macro.replacePath(path)) needsI18nImport = true;
83
84
  });
84
85
  jsxNodes.filter(isRootPath(jsxNodes)).forEach(function (path) {
85
86
  if (alreadyVisited(path)) return;
@@ -87,7 +88,7 @@ function macro(_ref) {
87
88
  macro.replacePath(path);
88
89
  });
89
90
 
90
- if (jsNodes.length) {
91
+ if (needsI18nImport) {
91
92
  addImport(babel, state, i18nImportModule, i18nImportName);
92
93
  }
93
94
 
package/macroJs.js CHANGED
@@ -53,7 +53,7 @@ var MacroJs = /*#__PURE__*/function () {
53
53
  (0, _defineProperty2.default)(this, "types", void 0);
54
54
  (0, _defineProperty2.default)(this, "i18nImportName", void 0);
55
55
  (0, _defineProperty2.default)(this, "_expressionIndex", void 0);
56
- (0, _defineProperty2.default)(this, "replacePathWithMessage", function (path, _ref3) {
56
+ (0, _defineProperty2.default)(this, "replacePathWithMessage", function (path, _ref3, linguiInstance) {
57
57
  var id = _ref3.id,
58
58
  message = _ref3.message,
59
59
  values = _ref3.values,
@@ -87,7 +87,7 @@ var MacroJs = /*#__PURE__*/function () {
87
87
  args.push(_this.types.objectExpression(options));
88
88
  }
89
89
 
90
- var newNode = _this.types.callExpression(_this.types.memberExpression(_this.types.identifier(_this.i18nImportName), _this.types.identifier("_")), args); // preserve line number
90
+ var newNode = _this.types.callExpression(_this.types.memberExpression(linguiInstance !== null && linguiInstance !== void 0 ? linguiInstance : _this.types.identifier(_this.i18nImportName), _this.types.identifier("_")), args); // preserve line number
91
91
 
92
92
 
93
93
  newNode.loc = path.node.loc;
@@ -102,24 +102,51 @@ var MacroJs = /*#__PURE__*/function () {
102
102
  if (_this.isDefineMessage(path.node)) {
103
103
  _this.replaceDefineMessage(path);
104
104
 
105
- return;
105
+ return true;
106
+ } // t(i18nInstance)`Message` -> i18nInstance._('Message')
107
+
108
+
109
+ if (_this.types.isCallExpression(path.node) && _this.types.isTaggedTemplateExpression(path.parentPath.node) && _this.types.isIdentifier(path.node.arguments[0]) && _this.isIdentifier(path.node.callee, "t")) {
110
+ // Use the first argument as i18n instance instead of the default i18n instance
111
+ var i18nInstance = path.node.arguments[0];
112
+
113
+ var _tokens = _this.tokenizeNode(path.parentPath.node);
114
+
115
+ var _messageFormat = new _icu.default();
116
+
117
+ var _messageFormat$fromTo = _messageFormat.fromTokens(_tokens),
118
+ _messageRaw = _messageFormat$fromTo.message,
119
+ _values = _messageFormat$fromTo.values,
120
+ _id = _messageFormat$fromTo.id,
121
+ _comment = _messageFormat$fromTo.comment;
122
+
123
+ var _message = normalizeWhitespace(_messageRaw);
124
+
125
+ _this.replacePathWithMessage(path.parentPath, {
126
+ id: _id,
127
+ message: _message,
128
+ values: _values,
129
+ comment: _comment
130
+ }, i18nInstance);
131
+
132
+ return false;
106
133
  }
107
134
 
108
135
  if (_this.types.isCallExpression(path.node) && _this.isIdentifier(path.node.callee, "t")) {
109
136
  _this.replaceTAsFunction(path);
110
137
 
111
- return;
138
+ return true;
112
139
  }
113
140
 
114
141
  var tokens = _this.tokenizeNode(path.node);
115
142
 
116
143
  var messageFormat = new _icu.default();
117
144
 
118
- var _messageFormat$fromTo = messageFormat.fromTokens(tokens),
119
- messageRaw = _messageFormat$fromTo.message,
120
- values = _messageFormat$fromTo.values,
121
- id = _messageFormat$fromTo.id,
122
- comment = _messageFormat$fromTo.comment;
145
+ var _messageFormat$fromTo2 = messageFormat.fromTokens(tokens),
146
+ messageRaw = _messageFormat$fromTo2.message,
147
+ values = _messageFormat$fromTo2.values,
148
+ id = _messageFormat$fromTo2.id,
149
+ comment = _messageFormat$fromTo2.comment;
123
150
 
124
151
  var message = normalizeWhitespace(messageRaw);
125
152
 
@@ -129,6 +156,8 @@ var MacroJs = /*#__PURE__*/function () {
129
156
  values: values,
130
157
  comment: comment
131
158
  });
159
+
160
+ return true;
132
161
  });
133
162
  (0, _defineProperty2.default)(this, "replaceDefineMessage", function (path) {
134
163
  // reset the expression counter
@@ -166,9 +195,9 @@ var MacroJs = /*#__PURE__*/function () {
166
195
  if (tokens != null) {
167
196
  var messageFormat = new _icu.default();
168
197
 
169
- var _messageFormat$fromTo2 = messageFormat.fromTokens(tokens),
170
- messageRaw = _messageFormat$fromTo2.message,
171
- values = _messageFormat$fromTo2.values;
198
+ var _messageFormat$fromTo3 = messageFormat.fromTokens(tokens),
199
+ messageRaw = _messageFormat$fromTo3.message,
200
+ values = _messageFormat$fromTo3.values;
172
201
 
173
202
  var message = normalizeWhitespace(messageRaw);
174
203
  messageNode = _this.types.stringLiteral(message);
@@ -210,7 +239,9 @@ var MacroJs = /*#__PURE__*/function () {
210
239
  quasis: R.map(function (text) {
211
240
  // Don't output tokens without text.
212
241
  // if it's an unicode we keep the cooked value because it's the parsed value by babel (without unicode chars)
213
- var value = /\\u[a-fA-F0-9]{4}/g.test(text.value.raw) ? text.value.cooked : text.value.raw;
242
+ // This regex will detect if a string contains unicode chars, when they're we should interpolate them
243
+ // why? because platforms like react native doesn't parse them, just doing a JSON.parse makes them UTF-8 friendly
244
+ var value = /\\u[a-fA-F0-9]{4}|\\x[a-fA-F0-9]{2}/g.test(text.value.raw) ? text.value.cooked : text.value.raw;
214
245
  if (value === "") return null;
215
246
  return {
216
247
  type: "text",
package/macroJsx.js CHANGED
@@ -193,8 +193,10 @@ var MacroJSX = /*#__PURE__*/function () {
193
193
  var tokenize = R.pipe( // Don"t output tokens without text.
194
194
  R.evolve({
195
195
  quasis: R.map(function (text) {
196
- // Don"t output tokens without text.
197
- var value = /\\u[a-fA-F0-9]{4}/g.test(text.value.raw) ? text.value.cooked : text.value.raw;
196
+ // if it's an unicode we keep the cooked value because it's the parsed value by babel (without unicode chars)
197
+ // This regex will detect if a string contains unicode chars, when they're we should interpolate them
198
+ // why? because platforms like react native doesn't parse them, just doing a JSON.parse makes them UTF-8 friendly
199
+ var value = /\\u[a-fA-F0-9]{4}|\\x[a-fA-F0-9]{2}/g.test(text.value.raw) ? text.value.cooked : text.value.raw;
198
200
  if (value === "") return null;
199
201
  return _this.tokenizeText(_this.clearBackslashes(value));
200
202
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lingui/macro",
3
- "version": "3.10.1",
3
+ "version": "3.12.0",
4
4
  "description": "Macro for generating messages in ICU MessageFormat syntax",
5
5
  "main": "index.js",
6
6
  "author": {
@@ -30,7 +30,7 @@
30
30
  ],
31
31
  "dependencies": {
32
32
  "@babel/runtime": "^7.11.2",
33
- "@lingui/conf": "^3.10.1",
33
+ "@lingui/conf": "^3.12.0",
34
34
  "ramda": "^0.27.1"
35
35
  },
36
36
  "peerDependencies": {