@discord/intl 0.1.2 → 0.2.0-canary.641ab2f
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/format.d.ts +30 -0
- package/dist/format.js +214 -0
- package/dist/formatters/ast.d.ts +67 -0
- package/dist/formatters/ast.js +148 -0
- package/dist/formatters/index.d.ts +4 -0
- package/dist/formatters/index.js +14 -0
- package/dist/formatters/markdown.d.ts +13 -0
- package/dist/formatters/markdown.js +80 -0
- package/dist/formatters/react.d.ts +28 -0
- package/dist/formatters/react.js +111 -0
- package/dist/formatters/string.d.ts +21 -0
- package/dist/formatters/string.js +90 -0
- package/dist/index.d.ts +7 -6
- package/dist/index.js +19 -4
- package/dist/intl-manager.d.ts +25 -63
- package/dist/intl-manager.js +61 -89
- package/dist/keyless-json.d.ts +8 -1
- package/dist/message-loader.d.ts +38 -6
- package/dist/message-loader.js +117 -22
- package/dist/message.d.ts +3 -38
- package/dist/message.js +1 -132
- package/dist/types.d.ts +41 -45
- package/package.json +1 -2
- package/src/format.ts +224 -0
- package/src/formatters/ast.ts +155 -0
- package/src/formatters/index.ts +9 -0
- package/src/formatters/markdown.ts +54 -0
- package/src/formatters/react.ts +100 -0
- package/src/formatters/string.ts +62 -0
- package/src/index.ts +7 -7
- package/src/intl-manager.ts +73 -161
- package/src/keyless-json.ts +7 -0
- package/src/message-loader.ts +91 -24
- package/src/message.ts +4 -96
- package/src/types.d.ts +41 -45
- package/dist/react.d.ts +0 -38
- package/dist/react.js +0 -80
- package/src/react.ts +0 -80
package/src/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { InternalIntlMessage } from './message';
|
|
2
2
|
import type { IntlMessageGetterAdditions } from './message-loader';
|
|
3
|
+
import { FormatBuilderConstructor } from './format';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Use this function to define messages as part of the `@discord/intl`
|
|
@@ -11,14 +12,6 @@ import type { IntlMessageGetterAdditions } from './message-loader';
|
|
|
11
12
|
*/
|
|
12
13
|
export declare function defineMessages(messages: object): object;
|
|
13
14
|
|
|
14
|
-
/**
|
|
15
|
-
* A map of tag names to render functions to apply when the tags are
|
|
16
|
-
* encountered while formatting a message. Each `IntlManager` can be
|
|
17
|
-
* constructed with a different map of these elements, for example to allow
|
|
18
|
-
* one manager to render React output while another renders accessibility text.
|
|
19
|
-
*/
|
|
20
|
-
export type RichTextElementMap = Record<string, (chunks: any[]) => any>;
|
|
21
|
-
|
|
22
15
|
/**
|
|
23
16
|
* Placeholder type representing that this property is a Hook to be rendered
|
|
24
17
|
* while formatting.
|
|
@@ -46,19 +39,8 @@ export type IntlTime = string | number | Date | null | undefined;
|
|
|
46
39
|
* strings, and are able to skip multiple formatting steps to work more
|
|
47
40
|
* efficiently. This type represents those messages distinctly.
|
|
48
41
|
*/
|
|
49
|
-
type PlainIntlMessage = string;
|
|
50
|
-
|
|
51
|
-
* A richly-formatted message that injects dynamic values while formatting,
|
|
52
|
-
* with the types of those values defined by the `FormatValues` object. All
|
|
53
|
-
* messages of this type must have at least one value in the object, otherwise
|
|
54
|
-
* the message should be typed as a `PlainIntlMessage`.
|
|
55
|
-
*/
|
|
56
|
-
type TypedIntlMessage<FormatValues extends object> = InternalIntlMessage & {
|
|
57
|
-
__values: FormatValues;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
type AnyIntlMessage<FormatValues extends object | undefined = undefined> =
|
|
61
|
-
FormatValues extends undefined ? PlainIntlMessage : TypedIntlMessage<FormatValues>;
|
|
42
|
+
export type PlainIntlMessage = string;
|
|
43
|
+
export type AnyIntlMessage = PlainIntlMessage | InternalIntlMessage;
|
|
62
44
|
|
|
63
45
|
export interface IntlMessageGetter extends IntlMessageGetterAdditions {
|
|
64
46
|
(locale: string): InternalIntlMessage | PlainIntlMessage;
|
|
@@ -85,8 +67,8 @@ export interface TypedIntlMessageGetter<FormatValues extends object | undefined>
|
|
|
85
67
|
// from the declared type. The latter of these is definitely semantically
|
|
86
68
|
// correct, but the former is more just an annoying part of the type system
|
|
87
69
|
// because of this returned type being nested within this interface and the
|
|
88
|
-
// strict
|
|
89
|
-
(locale: string): InternalIntlMessage
|
|
70
|
+
// strict subtyping that TypeScript uses.
|
|
71
|
+
(locale: string): InternalIntlMessage;
|
|
90
72
|
|
|
91
73
|
/**
|
|
92
74
|
* A phantom type (not part of the actual typing of the object) that ensures
|
|
@@ -183,7 +165,7 @@ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
|
|
|
183
165
|
* checked against the provided message types, and error messages will be
|
|
184
166
|
* accurate as a result.
|
|
185
167
|
*/
|
|
186
|
-
type FormatValuesFor<T> =
|
|
168
|
+
export type FormatValuesFor<T> =
|
|
187
169
|
// `[]` syntax forces TypeScript to not distribute the possible union of
|
|
188
170
|
// types, meaning this represents "_all_ values of T are an extension of
|
|
189
171
|
// the parent type", which in this case represents messages with no
|
|
@@ -209,12 +191,18 @@ type FormatValuesFor<T> =
|
|
|
209
191
|
* the caller to inject React elements within a string, while an AST formatter
|
|
210
192
|
* might require a specific object shape, or allow any plain object.
|
|
211
193
|
*/
|
|
212
|
-
interface FunctionTypeMap {
|
|
194
|
+
export interface FunctionTypeMap {
|
|
213
195
|
link: any;
|
|
214
196
|
hook: any;
|
|
215
197
|
handler: any;
|
|
216
198
|
}
|
|
217
199
|
|
|
200
|
+
export interface FunctionTypes<Result, HandlerType = (content: Result[]) => Result | Result[]> {
|
|
201
|
+
link: undefined | ((content: Result[]) => Result | Result[]);
|
|
202
|
+
hook: undefined | ((content: Result[]) => Result | Result[]);
|
|
203
|
+
handler: undefined | HandlerType;
|
|
204
|
+
}
|
|
205
|
+
|
|
218
206
|
type ReplaceKeepingNullability<T, P> = P | Exclude<T, NonNullable<T>>;
|
|
219
207
|
|
|
220
208
|
/**
|
|
@@ -226,6 +214,8 @@ type ReplaceKeepingNullability<T, P> = P | Exclude<T, NonNullable<T>>;
|
|
|
226
214
|
type MapFunctionTypes<T, FunctionTypes extends FunctionTypeMap> = {
|
|
227
215
|
[K in keyof T]: ReplaceKeepingNullability<
|
|
228
216
|
T[K],
|
|
217
|
+
// TODO: replace these types with string literal types in the generated
|
|
218
|
+
// file, turning this whole chain into `FunctionTypes[T[K]] ?? T[K]`.
|
|
229
219
|
NonNullable<T[K]> extends LinkFunction
|
|
230
220
|
? FunctionTypes['link']
|
|
231
221
|
: NonNullable<T[K]> extends HookFunction
|
|
@@ -251,7 +241,7 @@ type CheckStrictAny<Check, Yes, No> = (Check extends never ? true : false) exten
|
|
|
251
241
|
* // Result is `{name: string}`
|
|
252
242
|
* ```
|
|
253
243
|
*/
|
|
254
|
-
type IntlMessageGetterInnerType<T extends IntlMessageGetter> =
|
|
244
|
+
export type IntlMessageGetterInnerType<T extends IntlMessageGetter> =
|
|
255
245
|
T extends TypedIntlMessageGetter<infer U> ? U : never;
|
|
256
246
|
|
|
257
247
|
/**
|
|
@@ -260,13 +250,12 @@ type IntlMessageGetterInnerType<T extends IntlMessageGetter> =
|
|
|
260
250
|
* types from `FunctionTypes`. The result is the set of required values
|
|
261
251
|
* necessary to format the message of type `T` with the calling formatter.
|
|
262
252
|
*/
|
|
263
|
-
type RequiredFormatValues<
|
|
253
|
+
export type RequiredFormatValues<
|
|
264
254
|
Values extends IntlMessageGetter,
|
|
265
|
-
DefaultElements,
|
|
266
255
|
FunctionTypes extends FunctionTypeMap,
|
|
267
256
|
> =
|
|
268
257
|
IntlMessageGetterInnerType<Values> extends undefined
|
|
269
|
-
?
|
|
258
|
+
? {}
|
|
270
259
|
: CheckStrictAny<
|
|
271
260
|
IntlMessageGetterInnerType<Values>,
|
|
272
261
|
// If `T` is explicitly `any`, then individual properties can't be typed and
|
|
@@ -277,23 +266,30 @@ type RequiredFormatValues<
|
|
|
277
266
|
// value and turn every property into the mapped `LinkFunction` type, which
|
|
278
267
|
// is almost always going to be wrong.
|
|
279
268
|
any,
|
|
280
|
-
MapFunctionTypes<
|
|
281
|
-
Omit<FormatValuesFor<IntlMessageGetterInnerType<Values>>, keyof DefaultElements>,
|
|
282
|
-
FunctionTypes
|
|
283
|
-
>
|
|
269
|
+
MapFunctionTypes<FormatValuesFor<IntlMessageGetterInnerType<Values>>, FunctionTypes>
|
|
284
270
|
>;
|
|
285
271
|
|
|
286
|
-
export interface
|
|
287
|
-
$_:
|
|
288
|
-
$b:
|
|
289
|
-
$i:
|
|
290
|
-
$p:
|
|
291
|
-
$link:
|
|
292
|
-
$code:
|
|
272
|
+
export interface RichTextFormattingMap<T = any> {
|
|
273
|
+
$_: T;
|
|
274
|
+
$b: T;
|
|
275
|
+
$i: T;
|
|
276
|
+
$p: T;
|
|
277
|
+
$link: T;
|
|
278
|
+
$code: T;
|
|
293
279
|
}
|
|
294
280
|
|
|
295
|
-
export type
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
FunctionTypeMap
|
|
299
|
-
|
|
281
|
+
export type RichTextTagNames = keyof RichTextFormattingMap;
|
|
282
|
+
|
|
283
|
+
export interface FormatterImplementation<
|
|
284
|
+
FunctionTypes extends FunctionTypeMap,
|
|
285
|
+
Result,
|
|
286
|
+
BuilderResult = Result,
|
|
287
|
+
> {
|
|
288
|
+
format: (
|
|
289
|
+
message: AnyIntlMessage,
|
|
290
|
+
values: object,
|
|
291
|
+
builder?: FormatBuilderConstructor<BuilderResult>,
|
|
292
|
+
) => Result;
|
|
293
|
+
builder: FormatBuilderConstructor<BuilderResult extends (infer T)[] ? T : BuilderResult>;
|
|
294
|
+
__$functionTypes?: FunctionTypes;
|
|
295
|
+
}
|
package/dist/react.d.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { IntlManager } from './intl-manager';
|
|
3
|
-
import type { IntlMessageGetter, RequiredFormatValues, RichTextElementMap, TypedIntlMessageGetter } from './types';
|
|
4
|
-
type ReactHandlerEvent = React.MouseEvent | React.KeyboardEvent;
|
|
5
|
-
type ReactClickHandler = (e: ReactHandlerEvent) => void;
|
|
6
|
-
type ReactFunctionTypes = {
|
|
7
|
-
link: undefined | ((content: React.ReactNode | React.ReactNode[], key: string) => React.ReactNode);
|
|
8
|
-
hook: undefined | ((content: React.ReactNode | React.ReactNode[], key: string) => React.ReactNode);
|
|
9
|
-
handler: undefined | ReactClickHandler | {
|
|
10
|
-
onClick: ReactClickHandler;
|
|
11
|
-
} | {
|
|
12
|
-
onContextMenu: ReactClickHandler;
|
|
13
|
-
} | {
|
|
14
|
-
onClick: ReactClickHandler;
|
|
15
|
-
onContextMenu: ReactClickHandler;
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
export declare class IntlManagerReact<DefaultElements extends RichTextElementMap> extends IntlManager<DefaultElements, ReactFunctionTypes> {
|
|
19
|
-
/**
|
|
20
|
-
* A reactive component form of `intl.format` that automatically updates when
|
|
21
|
-
* the application's locale changes and when new data is loaded for the
|
|
22
|
-
* subject message.
|
|
23
|
-
*/
|
|
24
|
-
IntlMessage: <T extends IntlMessageGetter>(props: {
|
|
25
|
-
message: T;
|
|
26
|
-
values?: RequiredFormatValues<T, DefaultElements, ReactFunctionTypes> | never;
|
|
27
|
-
}) => string | React.FunctionComponentElement<{
|
|
28
|
-
children?: React.ReactNode | undefined;
|
|
29
|
-
}>;
|
|
30
|
-
/**
|
|
31
|
-
* Format the given message as a React component, allowing it to listen for
|
|
32
|
-
* and respond to updates about the current locale and other relevant
|
|
33
|
-
* information.
|
|
34
|
-
*/
|
|
35
|
-
format<T extends TypedIntlMessageGetter<undefined>>(message: T): React.ReactElement;
|
|
36
|
-
format<T extends IntlMessageGetter>(message: T, values: RequiredFormatValues<T, DefaultElements, ReactFunctionTypes>): React.ReactElement;
|
|
37
|
-
}
|
|
38
|
-
export {};
|
package/dist/react.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __extends = (this && this.__extends) || (function () {
|
|
3
|
-
var extendStatics = function (d, b) {
|
|
4
|
-
extendStatics = Object.setPrototypeOf ||
|
|
5
|
-
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
6
|
-
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
7
|
-
return extendStatics(d, b);
|
|
8
|
-
};
|
|
9
|
-
return function (d, b) {
|
|
10
|
-
if (typeof b !== "function" && b !== null)
|
|
11
|
-
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
12
|
-
extendStatics(d, b);
|
|
13
|
-
function __() { this.constructor = d; }
|
|
14
|
-
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
15
|
-
};
|
|
16
|
-
})();
|
|
17
|
-
var __read = (this && this.__read) || function (o, n) {
|
|
18
|
-
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
19
|
-
if (!m) return o;
|
|
20
|
-
var i = m.call(o), r, ar = [], e;
|
|
21
|
-
try {
|
|
22
|
-
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
23
|
-
}
|
|
24
|
-
catch (error) { e = { error: error }; }
|
|
25
|
-
finally {
|
|
26
|
-
try {
|
|
27
|
-
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
28
|
-
}
|
|
29
|
-
finally { if (e) throw e.error; }
|
|
30
|
-
}
|
|
31
|
-
return ar;
|
|
32
|
-
};
|
|
33
|
-
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
34
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
35
|
-
if (ar || !(i in from)) {
|
|
36
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
37
|
-
ar[i] = from[i];
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
41
|
-
};
|
|
42
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
-
exports.IntlManagerReact = void 0;
|
|
44
|
-
var React = require("react");
|
|
45
|
-
var intl_manager_1 = require("./intl-manager");
|
|
46
|
-
var IntlManagerReact = /** @class */ (function (_super) {
|
|
47
|
-
__extends(IntlManagerReact, _super);
|
|
48
|
-
function IntlManagerReact() {
|
|
49
|
-
var _this = _super.apply(this, __spreadArray([], __read(arguments), false)) || this;
|
|
50
|
-
/**
|
|
51
|
-
* A reactive component form of `intl.format` that automatically updates when
|
|
52
|
-
* the application's locale changes and when new data is loaded for the
|
|
53
|
-
* subject message.
|
|
54
|
-
*/
|
|
55
|
-
_this.IntlMessage = function (props) {
|
|
56
|
-
var message = props.message, values = props.values;
|
|
57
|
-
// Use the locale from this point in the application, which may be
|
|
58
|
-
// different from the global locale.
|
|
59
|
-
var locale = React.useSyncExternalStore(_this.onLocaleChange, function () { return _this.currentLocale; });
|
|
60
|
-
// TODO(faulty): This can and should be replaced with
|
|
61
|
-
// `use(messagesLoadedPromise)` once `use` is shipped to stable.
|
|
62
|
-
// Source the actual message to render for that locale from its loader.
|
|
63
|
-
React.useSyncExternalStore(message.onChange, function () { return message(locale); });
|
|
64
|
-
// If there are no object parts in the message, it has no formatting and can just be returned as
|
|
65
|
-
// a plain string.
|
|
66
|
-
if (typeof message === 'string')
|
|
67
|
-
return message;
|
|
68
|
-
var parts = _this.formatToParts(message, values);
|
|
69
|
-
if (parts.length === 1 && typeof parts[0] === 'string')
|
|
70
|
-
return parts[0];
|
|
71
|
-
return React.createElement(React.Fragment, undefined, _this.formatToParts(message, values));
|
|
72
|
-
};
|
|
73
|
-
return _this;
|
|
74
|
-
}
|
|
75
|
-
IntlManagerReact.prototype.format = function (message, values) {
|
|
76
|
-
return React.createElement((this.IntlMessage), { message: message, values: values });
|
|
77
|
-
};
|
|
78
|
-
return IntlManagerReact;
|
|
79
|
-
}(intl_manager_1.IntlManager));
|
|
80
|
-
exports.IntlManagerReact = IntlManagerReact;
|
package/src/react.ts
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
|
|
3
|
-
import { IntlManager } from './intl-manager';
|
|
4
|
-
|
|
5
|
-
import type {
|
|
6
|
-
IntlMessageGetter,
|
|
7
|
-
RequiredFormatValues,
|
|
8
|
-
RichTextElementMap,
|
|
9
|
-
TypedIntlMessageGetter,
|
|
10
|
-
} from './types';
|
|
11
|
-
|
|
12
|
-
type ReactHandlerEvent = React.MouseEvent | React.KeyboardEvent;
|
|
13
|
-
type ReactClickHandler = (e: ReactHandlerEvent) => void;
|
|
14
|
-
|
|
15
|
-
type ReactFunctionTypes = {
|
|
16
|
-
// TODO: Allowing `undefined` on these is a migration artifact that should be
|
|
17
|
-
// removed. Functions, like all other values, should be required when
|
|
18
|
-
// formatting to avoid unexpected missing behavior.
|
|
19
|
-
link:
|
|
20
|
-
| undefined
|
|
21
|
-
| ((content: React.ReactNode | React.ReactNode[], key: string) => React.ReactNode);
|
|
22
|
-
|
|
23
|
-
hook:
|
|
24
|
-
| undefined
|
|
25
|
-
| ((content: React.ReactNode | React.ReactNode[], key: string) => React.ReactNode);
|
|
26
|
-
handler:
|
|
27
|
-
| undefined
|
|
28
|
-
| ReactClickHandler
|
|
29
|
-
| { onClick: ReactClickHandler }
|
|
30
|
-
| { onContextMenu: ReactClickHandler }
|
|
31
|
-
| { onClick: ReactClickHandler; onContextMenu: ReactClickHandler };
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export class IntlManagerReact<DefaultElements extends RichTextElementMap> extends IntlManager<
|
|
35
|
-
DefaultElements,
|
|
36
|
-
ReactFunctionTypes
|
|
37
|
-
> {
|
|
38
|
-
/**
|
|
39
|
-
* A reactive component form of `intl.format` that automatically updates when
|
|
40
|
-
* the application's locale changes and when new data is loaded for the
|
|
41
|
-
* subject message.
|
|
42
|
-
*/
|
|
43
|
-
IntlMessage = <T extends IntlMessageGetter>(props: {
|
|
44
|
-
message: T;
|
|
45
|
-
values?: RequiredFormatValues<T, DefaultElements, ReactFunctionTypes> | never;
|
|
46
|
-
}) => {
|
|
47
|
-
const { message, values } = props;
|
|
48
|
-
// Use the locale from this point in the application, which may be
|
|
49
|
-
// different from the global locale.
|
|
50
|
-
const locale = React.useSyncExternalStore(this.onLocaleChange, () => this.currentLocale);
|
|
51
|
-
// TODO(faulty): This can and should be replaced with
|
|
52
|
-
// `use(messagesLoadedPromise)` once `use` is shipped to stable.
|
|
53
|
-
// Source the actual message to render for that locale from its loader.
|
|
54
|
-
React.useSyncExternalStore(message.onChange, () => message(locale));
|
|
55
|
-
// If there are no object parts in the message, it has no formatting and can just be returned as
|
|
56
|
-
// a plain string.
|
|
57
|
-
if (typeof message === 'string') return message;
|
|
58
|
-
|
|
59
|
-
const parts = this.formatToParts(message, values);
|
|
60
|
-
if (parts.length === 1 && typeof parts[0] === 'string') return parts[0];
|
|
61
|
-
return React.createElement(React.Fragment, undefined, this.formatToParts(message, values));
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Format the given message as a React component, allowing it to listen for
|
|
66
|
-
* and respond to updates about the current locale and other relevant
|
|
67
|
-
* information.
|
|
68
|
-
*/
|
|
69
|
-
format<T extends TypedIntlMessageGetter<undefined>>(message: T): React.ReactElement;
|
|
70
|
-
format<T extends IntlMessageGetter>(
|
|
71
|
-
message: T,
|
|
72
|
-
values: RequiredFormatValues<T, DefaultElements, ReactFunctionTypes>,
|
|
73
|
-
): React.ReactElement;
|
|
74
|
-
format<T extends IntlMessageGetter>(
|
|
75
|
-
message: T,
|
|
76
|
-
values?: RequiredFormatValues<T, DefaultElements, ReactFunctionTypes>,
|
|
77
|
-
): React.ReactElement {
|
|
78
|
-
return React.createElement(this.IntlMessage<T>, { message, values });
|
|
79
|
-
}
|
|
80
|
-
}
|