@discord/intl 0.5.2 → 0.6.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/format.d.ts +3 -3
- package/dist/format.js +76 -107
- package/dist/formatters/ast.js +30 -77
- package/dist/formatters/markdown.js +18 -65
- package/dist/formatters/react.js +26 -72
- package/dist/formatters/string.js +15 -58
- package/dist/hash.js +11 -11
- package/dist/intl-manager.js +38 -89
- package/dist/message-loader.d.ts +8 -2
- package/dist/message-loader.js +93 -225
- package/dist/message.d.ts +3 -3
- package/dist/message.js +76 -135
- package/package.json +3 -2
- package/src/format.ts +39 -30
- package/src/intl-manager.ts +4 -2
- package/src/message-loader.ts +8 -2
- package/src/message.ts +48 -39
- package/dist/keyless-json.d.ts +0 -68
- package/dist/keyless-json.js +0 -107
- package/src/keyless-json.ts +0 -161
package/src/message.ts
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
AstNode,
|
|
3
|
+
FullFormatJsNode,
|
|
4
|
+
FormatJsNodeType,
|
|
5
|
+
compressFormatJsToAst,
|
|
6
|
+
isCompressedAst,
|
|
7
|
+
AstNodeIndices,
|
|
8
|
+
TagNode,
|
|
9
|
+
} from '@discord/intl-ast';
|
|
2
10
|
|
|
3
11
|
export class InternalIntlMessage {
|
|
4
12
|
locale: string;
|
|
5
|
-
ast:
|
|
13
|
+
ast: AstNode[];
|
|
6
14
|
|
|
7
|
-
constructor(messageOrAst:
|
|
15
|
+
constructor(messageOrAst: AstNode[] | FullFormatJsNode[], locale: string) {
|
|
8
16
|
this.locale = locale;
|
|
9
|
-
this.ast = messageOrAst;
|
|
17
|
+
this.ast = isCompressedAst(messageOrAst) ? messageOrAst : compressFormatJsToAst(messageOrAst);
|
|
10
18
|
}
|
|
11
19
|
|
|
12
20
|
/**
|
|
@@ -15,54 +23,55 @@ export class InternalIntlMessage {
|
|
|
15
23
|
*/
|
|
16
24
|
reserialize(): string {
|
|
17
25
|
const result = { value: '' };
|
|
18
|
-
|
|
26
|
+
serializeAst(this.ast, result);
|
|
19
27
|
return result.value;
|
|
20
28
|
}
|
|
21
29
|
}
|
|
22
30
|
|
|
23
31
|
// Accepting an object as the `result` parameter lets the same string get passed around and
|
|
24
32
|
// appended, rather than creating a bunch of intermediate strings.
|
|
25
|
-
function
|
|
33
|
+
function serializeAst(ast: AstNode[], result: { value: string }) {
|
|
26
34
|
for (const node of ast) {
|
|
27
|
-
switch (node.
|
|
35
|
+
switch (node[AstNodeIndices.Type]) {
|
|
28
36
|
case FormatJsNodeType.Literal:
|
|
29
|
-
result.value += node.
|
|
37
|
+
result.value += node[AstNodeIndices.Value];
|
|
30
38
|
return;
|
|
31
39
|
case FormatJsNodeType.Argument:
|
|
32
40
|
// Empties are an artifact of our parsing strategy, not necessary here.
|
|
33
41
|
if (result.value === '$_') return;
|
|
34
|
-
result.value += '{' + node.
|
|
42
|
+
result.value += '{' + node[AstNodeIndices.Value] + '}';
|
|
35
43
|
return;
|
|
36
44
|
case FormatJsNodeType.Date:
|
|
37
|
-
result.value += '{' + node.
|
|
38
|
-
if (node.
|
|
39
|
-
result.value += ', ' + node.
|
|
45
|
+
result.value += '{' + node[AstNodeIndices.Value] + ', date';
|
|
46
|
+
if (node[AstNodeIndices.Style] != null) {
|
|
47
|
+
result.value += ', ' + node[AstNodeIndices.Style];
|
|
40
48
|
}
|
|
41
49
|
result.value += '}';
|
|
42
50
|
return;
|
|
43
51
|
case FormatJsNodeType.Time:
|
|
44
|
-
result.value += '{' + node.
|
|
45
|
-
if (node.
|
|
46
|
-
result.value += ', ' + node.
|
|
52
|
+
result.value += '{' + node[AstNodeIndices.Value] + ', time';
|
|
53
|
+
if (node[AstNodeIndices.Style] != null) {
|
|
54
|
+
result.value += ', ' + node[AstNodeIndices.Style];
|
|
47
55
|
}
|
|
48
56
|
result.value += '}';
|
|
49
57
|
return;
|
|
50
58
|
case FormatJsNodeType.Number:
|
|
51
|
-
result.value += '{' + node.
|
|
52
|
-
if (node.
|
|
53
|
-
result.value += ', ' + node.
|
|
59
|
+
result.value += '{' + node[AstNodeIndices.Value] + ', number';
|
|
60
|
+
if (node[AstNodeIndices.Style] != null) {
|
|
61
|
+
result.value += ', ' + node[AstNodeIndices.Style];
|
|
54
62
|
}
|
|
55
63
|
result.value += '}';
|
|
56
64
|
return;
|
|
57
65
|
case FormatJsNodeType.Plural: {
|
|
58
|
-
const pluralType =
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
66
|
+
const pluralType =
|
|
67
|
+
node[AstNodeIndices.PluralType] == 'ordinal' ? 'selectordinal' : 'plural';
|
|
68
|
+
result.value += '{' + node[AstNodeIndices.Value] + ', ' + pluralType + ', ';
|
|
69
|
+
if (node[AstNodeIndices.Offset]) {
|
|
70
|
+
result.value += 'offset:' + node[AstNodeIndices.Offset];
|
|
62
71
|
}
|
|
63
|
-
for (const [name, arm] of Object.entries(node.
|
|
72
|
+
for (const [name, arm] of Object.entries(node[AstNodeIndices.Options])) {
|
|
64
73
|
result.value += ' ' + name + ' {';
|
|
65
|
-
|
|
74
|
+
serializeAst(arm.value, result);
|
|
66
75
|
result.value += '}';
|
|
67
76
|
}
|
|
68
77
|
return;
|
|
@@ -71,59 +80,59 @@ function serializeFormatJsAst(ast: FormatJsNode[], result: { value: string }) {
|
|
|
71
80
|
result.value += '#';
|
|
72
81
|
return;
|
|
73
82
|
case FormatJsNodeType.Select: {
|
|
74
|
-
result.value += '{' + node.
|
|
75
|
-
for (const [name, arm] of Object.entries(node.
|
|
83
|
+
result.value += '{' + node[AstNodeIndices.Value] + ', select, ';
|
|
84
|
+
for (const [name, arm] of Object.entries(node[AstNodeIndices.Options])) {
|
|
76
85
|
result.value += ' ' + name + ' {';
|
|
77
|
-
|
|
86
|
+
serializeAst(arm.value, result);
|
|
78
87
|
result.value += '}';
|
|
79
88
|
}
|
|
80
89
|
return;
|
|
81
90
|
}
|
|
82
91
|
case FormatJsNodeType.Tag:
|
|
83
|
-
|
|
92
|
+
serializeAstTag(node, result);
|
|
84
93
|
return;
|
|
85
94
|
}
|
|
86
95
|
}
|
|
87
96
|
}
|
|
88
97
|
|
|
89
|
-
function
|
|
90
|
-
switch (node.
|
|
98
|
+
function serializeAstTag(node: TagNode, result: { value: string }) {
|
|
99
|
+
switch (node[AstNodeIndices.Value]) {
|
|
91
100
|
case '$b':
|
|
92
101
|
result.value += '**';
|
|
93
|
-
|
|
102
|
+
serializeAst(node[AstNodeIndices.Children], result);
|
|
94
103
|
result.value += '**';
|
|
95
104
|
return;
|
|
96
105
|
case '$i':
|
|
97
106
|
result.value += '*';
|
|
98
|
-
|
|
107
|
+
serializeAst(node[AstNodeIndices.Children], result);
|
|
99
108
|
result.value += '*';
|
|
100
109
|
return;
|
|
101
110
|
case '$code':
|
|
102
111
|
result.value += '`';
|
|
103
|
-
|
|
112
|
+
serializeAst(node[AstNodeIndices.Children], result);
|
|
104
113
|
result.value += '`';
|
|
105
114
|
return;
|
|
106
115
|
case '$p':
|
|
107
|
-
|
|
116
|
+
serializeAst(node[AstNodeIndices.Children], result);
|
|
108
117
|
result.value += '\n\n';
|
|
109
118
|
return;
|
|
110
119
|
case '$link':
|
|
111
120
|
// The target is the first child of the link. We don't have to care if it's a placeholder
|
|
112
121
|
// or not, because the serialization will automatically remove the extra empty.
|
|
113
|
-
const [target, ...children] = node.
|
|
122
|
+
const [target, ...children] = node[AstNodeIndices.Children];
|
|
114
123
|
result.value += '[';
|
|
115
|
-
|
|
124
|
+
serializeAst(children, result);
|
|
116
125
|
result.value += '](';
|
|
117
126
|
if (target != null) {
|
|
118
|
-
|
|
127
|
+
serializeAst([target], result);
|
|
119
128
|
}
|
|
120
129
|
result.value += ')';
|
|
121
130
|
return;
|
|
122
131
|
default:
|
|
123
132
|
// Any other tag name is a hook, which just adds the `$[` on a link tag.
|
|
124
133
|
result.value += '$[';
|
|
125
|
-
|
|
126
|
-
result.value += '](' + node.
|
|
134
|
+
serializeAst(node[AstNodeIndices.Children], result);
|
|
135
|
+
result.value += '](' + node[AstNodeIndices.Value] + ')';
|
|
127
136
|
return;
|
|
128
137
|
}
|
|
129
138
|
}
|
package/dist/keyless-json.d.ts
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
export declare enum FormatJsNodeType {
|
|
2
|
-
Literal = 0,
|
|
3
|
-
Argument = 1,
|
|
4
|
-
Number = 2,
|
|
5
|
-
Date = 3,
|
|
6
|
-
Time = 4,
|
|
7
|
-
Select = 5,
|
|
8
|
-
Plural = 6,
|
|
9
|
-
Pound = 7,
|
|
10
|
-
Tag = 8
|
|
11
|
-
}
|
|
12
|
-
export interface FormatJsLiteral {
|
|
13
|
-
type: FormatJsNodeType.Literal;
|
|
14
|
-
value: string;
|
|
15
|
-
}
|
|
16
|
-
export interface FormatJsArgument {
|
|
17
|
-
type: FormatJsNodeType.Argument;
|
|
18
|
-
value: string;
|
|
19
|
-
}
|
|
20
|
-
export interface FormatJsNumber {
|
|
21
|
-
type: FormatJsNodeType.Number;
|
|
22
|
-
value: string;
|
|
23
|
-
style?: string;
|
|
24
|
-
}
|
|
25
|
-
export interface FormatJsDate {
|
|
26
|
-
type: FormatJsNodeType.Date;
|
|
27
|
-
value: string;
|
|
28
|
-
style?: string;
|
|
29
|
-
}
|
|
30
|
-
export interface FormatJsTime {
|
|
31
|
-
type: FormatJsNodeType.Time;
|
|
32
|
-
value: string;
|
|
33
|
-
style?: string;
|
|
34
|
-
}
|
|
35
|
-
export interface FormatJsSelect {
|
|
36
|
-
type: FormatJsNodeType.Select;
|
|
37
|
-
value: string;
|
|
38
|
-
options: Record<string, {
|
|
39
|
-
value: FormatJsNode[];
|
|
40
|
-
}>;
|
|
41
|
-
}
|
|
42
|
-
export type FormatJsPluralType = 'cardinal' | 'ordinal';
|
|
43
|
-
export interface FormatJsPlural {
|
|
44
|
-
type: FormatJsNodeType.Plural;
|
|
45
|
-
value: string;
|
|
46
|
-
options: Record<string, {
|
|
47
|
-
value: FormatJsNode[];
|
|
48
|
-
}>;
|
|
49
|
-
offset: number;
|
|
50
|
-
pluralType: FormatJsPluralType;
|
|
51
|
-
}
|
|
52
|
-
export interface FormatJsPound {
|
|
53
|
-
type: FormatJsNodeType.Pound;
|
|
54
|
-
}
|
|
55
|
-
export interface FormatJsTag {
|
|
56
|
-
type: FormatJsNodeType.Tag;
|
|
57
|
-
value: string;
|
|
58
|
-
children: FormatJsNode[];
|
|
59
|
-
}
|
|
60
|
-
export type FormatJsNode = FormatJsLiteral | FormatJsArgument | FormatJsNumber | FormatJsDate | FormatJsTime | FormatJsSelect | FormatJsPlural | FormatJsPound | FormatJsTag;
|
|
61
|
-
export declare const FORMAT_JS_POUND: FormatJsPound;
|
|
62
|
-
/**
|
|
63
|
-
* Hydrate the given keyless JSON into a FormatJS-compatible AST structure.
|
|
64
|
-
* The given object is reused as much as possible, meaning it cannot be safely
|
|
65
|
-
* used again after hydrating.
|
|
66
|
-
*/
|
|
67
|
-
export declare function hydrateFormatJsAst(keyless: Array<Array<any>>): FormatJsNode[];
|
|
68
|
-
export declare function hydrateMessages(messages: Record<string, any>): Record<string, any>;
|
package/dist/keyless-json.js
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __read = (this && this.__read) || function (o, n) {
|
|
3
|
-
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
4
|
-
if (!m) return o;
|
|
5
|
-
var i = m.call(o), r, ar = [], e;
|
|
6
|
-
try {
|
|
7
|
-
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
8
|
-
}
|
|
9
|
-
catch (error) { e = { error: error }; }
|
|
10
|
-
finally {
|
|
11
|
-
try {
|
|
12
|
-
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
13
|
-
}
|
|
14
|
-
finally { if (e) throw e.error; }
|
|
15
|
-
}
|
|
16
|
-
return ar;
|
|
17
|
-
};
|
|
18
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.FORMAT_JS_POUND = exports.FormatJsNodeType = void 0;
|
|
20
|
-
exports.hydrateFormatJsAst = hydrateFormatJsAst;
|
|
21
|
-
exports.hydrateMessages = hydrateMessages;
|
|
22
|
-
var FormatJsNodeType;
|
|
23
|
-
(function (FormatJsNodeType) {
|
|
24
|
-
FormatJsNodeType[FormatJsNodeType["Literal"] = 0] = "Literal";
|
|
25
|
-
FormatJsNodeType[FormatJsNodeType["Argument"] = 1] = "Argument";
|
|
26
|
-
FormatJsNodeType[FormatJsNodeType["Number"] = 2] = "Number";
|
|
27
|
-
FormatJsNodeType[FormatJsNodeType["Date"] = 3] = "Date";
|
|
28
|
-
FormatJsNodeType[FormatJsNodeType["Time"] = 4] = "Time";
|
|
29
|
-
FormatJsNodeType[FormatJsNodeType["Select"] = 5] = "Select";
|
|
30
|
-
FormatJsNodeType[FormatJsNodeType["Plural"] = 6] = "Plural";
|
|
31
|
-
FormatJsNodeType[FormatJsNodeType["Pound"] = 7] = "Pound";
|
|
32
|
-
FormatJsNodeType[FormatJsNodeType["Tag"] = 8] = "Tag";
|
|
33
|
-
})(FormatJsNodeType || (exports.FormatJsNodeType = FormatJsNodeType = {}));
|
|
34
|
-
// Using a static object here ensures there's only one allocation for it, which
|
|
35
|
-
// will likely appear in many, many messages. Freezing ensures that the shared
|
|
36
|
-
// object can't be accidentally modified if a consumer tries to transform the
|
|
37
|
-
// AST.
|
|
38
|
-
exports.FORMAT_JS_POUND = Object.freeze({ type: 7 });
|
|
39
|
-
function hydrateArray(elements) {
|
|
40
|
-
for (var i = 0; i < elements.length; i++) {
|
|
41
|
-
elements[i] = hydrateFormatJsAst(elements[i]);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
function hydratePlural(keyless) {
|
|
45
|
-
var _a = __read(keyless, 5), type = _a[0], value = _a[1], options = _a[2], offset = _a[3], pluralType = _a[4];
|
|
46
|
-
// This tries to be efficient about updating the value for each option
|
|
47
|
-
// with a parsed version, reusing the same receiving object, and even
|
|
48
|
-
// the inner key within it, just replacing the end value with the
|
|
49
|
-
// parsed version.
|
|
50
|
-
// This saves multiple allocations compared to building a new object
|
|
51
|
-
// from scratch, either for the whole options object or for each value.
|
|
52
|
-
for (var key in options) {
|
|
53
|
-
hydrateArray(options[key].value);
|
|
54
|
-
}
|
|
55
|
-
// `pluralType` is technically only valid on `Plural` nodes, even
|
|
56
|
-
// though the structure is identical to `Select`.
|
|
57
|
-
if (type === FormatJsNodeType.Plural) {
|
|
58
|
-
return { type: type, value: value, options: options, offset: offset, pluralType: pluralType };
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
return { type: type, value: value, options: options, offset: offset };
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
function hydrateSingle(keyless) {
|
|
65
|
-
var _a = __read(keyless, 1), type = _a[0];
|
|
66
|
-
switch (type) {
|
|
67
|
-
case FormatJsNodeType.Literal:
|
|
68
|
-
case FormatJsNodeType.Argument:
|
|
69
|
-
return { type: type, value: keyless[1] };
|
|
70
|
-
case FormatJsNodeType.Number:
|
|
71
|
-
case FormatJsNodeType.Date:
|
|
72
|
-
case FormatJsNodeType.Time:
|
|
73
|
-
return { type: type, value: keyless[1], style: keyless[2] };
|
|
74
|
-
case FormatJsNodeType.Select:
|
|
75
|
-
case FormatJsNodeType.Plural:
|
|
76
|
-
return hydratePlural(keyless);
|
|
77
|
-
case FormatJsNodeType.Pound:
|
|
78
|
-
return exports.FORMAT_JS_POUND;
|
|
79
|
-
case FormatJsNodeType.Tag: {
|
|
80
|
-
var _b = __read(keyless, 3), type_1 = _b[0], value = _b[1], children = _b[2];
|
|
81
|
-
hydrateArray(children);
|
|
82
|
-
return { type: type_1, value: value, children: children };
|
|
83
|
-
}
|
|
84
|
-
default:
|
|
85
|
-
throw new Error("FormatJS keyless JSON encountered an unknown type: ".concat(type));
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
function hydrateFormatJsAst(keyless) {
|
|
89
|
-
// If the first element of the array is itself an array, then we have a list
|
|
90
|
-
// of elements to parse rather than a single object.
|
|
91
|
-
if (Array.isArray(keyless[0])) {
|
|
92
|
-
hydrateArray(keyless);
|
|
93
|
-
return keyless;
|
|
94
|
-
}
|
|
95
|
-
else if (keyless.length === 0) {
|
|
96
|
-
// Some entries can be empty arrays, like an empty set of children, and those can
|
|
97
|
-
// be preserved.
|
|
98
|
-
return keyless;
|
|
99
|
-
}
|
|
100
|
-
return hydrateSingle(keyless);
|
|
101
|
-
}
|
|
102
|
-
function hydrateMessages(messages) {
|
|
103
|
-
for (var key in messages) {
|
|
104
|
-
messages[key] = hydrateFormatJsAst(messages[key]);
|
|
105
|
-
}
|
|
106
|
-
return messages;
|
|
107
|
-
}
|
package/src/keyless-json.ts
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
export enum FormatJsNodeType {
|
|
2
|
-
Literal = 0,
|
|
3
|
-
Argument,
|
|
4
|
-
Number,
|
|
5
|
-
Date,
|
|
6
|
-
Time,
|
|
7
|
-
Select,
|
|
8
|
-
Plural,
|
|
9
|
-
Pound,
|
|
10
|
-
Tag,
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface FormatJsLiteral {
|
|
14
|
-
type: FormatJsNodeType.Literal;
|
|
15
|
-
value: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface FormatJsArgument {
|
|
19
|
-
type: FormatJsNodeType.Argument;
|
|
20
|
-
value: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface FormatJsNumber {
|
|
24
|
-
type: FormatJsNodeType.Number;
|
|
25
|
-
value: string;
|
|
26
|
-
style?: string;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface FormatJsDate {
|
|
30
|
-
type: FormatJsNodeType.Date;
|
|
31
|
-
value: string;
|
|
32
|
-
style?: string;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface FormatJsTime {
|
|
36
|
-
type: FormatJsNodeType.Time;
|
|
37
|
-
value: string;
|
|
38
|
-
style?: string;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface FormatJsSelect {
|
|
42
|
-
type: FormatJsNodeType.Select;
|
|
43
|
-
value: string;
|
|
44
|
-
options: Record<string, { value: FormatJsNode[] }>;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export type FormatJsPluralType = 'cardinal' | 'ordinal';
|
|
48
|
-
|
|
49
|
-
export interface FormatJsPlural {
|
|
50
|
-
type: FormatJsNodeType.Plural;
|
|
51
|
-
value: string;
|
|
52
|
-
options: Record<string, { value: FormatJsNode[] }>;
|
|
53
|
-
offset: number;
|
|
54
|
-
pluralType: FormatJsPluralType;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface FormatJsPound {
|
|
58
|
-
type: FormatJsNodeType.Pound;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export interface FormatJsTag {
|
|
62
|
-
type: FormatJsNodeType.Tag;
|
|
63
|
-
value: string;
|
|
64
|
-
children: FormatJsNode[];
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export type FormatJsNode =
|
|
68
|
-
| FormatJsLiteral
|
|
69
|
-
| FormatJsArgument
|
|
70
|
-
| FormatJsNumber
|
|
71
|
-
| FormatJsDate
|
|
72
|
-
| FormatJsTime
|
|
73
|
-
| FormatJsSelect
|
|
74
|
-
| FormatJsPlural
|
|
75
|
-
| FormatJsPound
|
|
76
|
-
| FormatJsTag;
|
|
77
|
-
|
|
78
|
-
// Using a static object here ensures there's only one allocation for it, which
|
|
79
|
-
// will likely appear in many, many messages. Freezing ensures that the shared
|
|
80
|
-
// object can't be accidentally modified if a consumer tries to transform the
|
|
81
|
-
// AST.
|
|
82
|
-
export const FORMAT_JS_POUND: FormatJsPound = Object.freeze({ type: 7 });
|
|
83
|
-
|
|
84
|
-
function hydrateArray(elements: Array<Array<any>>) {
|
|
85
|
-
for (let i = 0; i < elements.length; i++) {
|
|
86
|
-
elements[i] = hydrateFormatJsAst(elements[i]);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function hydratePlural(keyless: Array<any>): FormatJsNode {
|
|
91
|
-
const [type, value, options, offset, pluralType] = keyless;
|
|
92
|
-
// This tries to be efficient about updating the value for each option
|
|
93
|
-
// with a parsed version, reusing the same receiving object, and even
|
|
94
|
-
// the inner key within it, just replacing the end value with the
|
|
95
|
-
// parsed version.
|
|
96
|
-
// This saves multiple allocations compared to building a new object
|
|
97
|
-
// from scratch, either for the whole options object or for each value.
|
|
98
|
-
for (const key in options) {
|
|
99
|
-
hydrateArray(options[key].value);
|
|
100
|
-
}
|
|
101
|
-
// `pluralType` is technically only valid on `Plural` nodes, even
|
|
102
|
-
// though the structure is identical to `Select`.
|
|
103
|
-
if (type === FormatJsNodeType.Plural) {
|
|
104
|
-
return { type, value, options, offset, pluralType };
|
|
105
|
-
} else {
|
|
106
|
-
return { type, value, options, offset };
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function hydrateSingle(keyless: Array<any>): FormatJsNode {
|
|
111
|
-
const [type] = keyless;
|
|
112
|
-
switch (type) {
|
|
113
|
-
case FormatJsNodeType.Literal:
|
|
114
|
-
case FormatJsNodeType.Argument:
|
|
115
|
-
return { type, value: keyless[1] };
|
|
116
|
-
case FormatJsNodeType.Number:
|
|
117
|
-
case FormatJsNodeType.Date:
|
|
118
|
-
case FormatJsNodeType.Time:
|
|
119
|
-
return { type, value: keyless[1], style: keyless[2] };
|
|
120
|
-
case FormatJsNodeType.Select:
|
|
121
|
-
case FormatJsNodeType.Plural:
|
|
122
|
-
return hydratePlural(keyless);
|
|
123
|
-
case FormatJsNodeType.Pound:
|
|
124
|
-
return FORMAT_JS_POUND;
|
|
125
|
-
case FormatJsNodeType.Tag: {
|
|
126
|
-
const [type, value, children] = keyless;
|
|
127
|
-
hydrateArray(children);
|
|
128
|
-
return { type, value, children: children };
|
|
129
|
-
}
|
|
130
|
-
default:
|
|
131
|
-
throw new Error(`FormatJS keyless JSON encountered an unknown type: ${type}`);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Hydrate the given keyless JSON into a FormatJS-compatible AST structure.
|
|
137
|
-
* The given object is reused as much as possible, meaning it cannot be safely
|
|
138
|
-
* used again after hydrating.
|
|
139
|
-
*/
|
|
140
|
-
export function hydrateFormatJsAst(keyless: Array<Array<any>>): FormatJsNode[];
|
|
141
|
-
export function hydrateFormatJsAst(keyless: Array<any>): FormatJsNode | FormatJsNode[] {
|
|
142
|
-
// If the first element of the array is itself an array, then we have a list
|
|
143
|
-
// of elements to parse rather than a single object.
|
|
144
|
-
if (Array.isArray(keyless[0])) {
|
|
145
|
-
hydrateArray(keyless);
|
|
146
|
-
return keyless;
|
|
147
|
-
} else if (keyless.length === 0) {
|
|
148
|
-
// Some entries can be empty arrays, like an empty set of children, and those can
|
|
149
|
-
// be preserved.
|
|
150
|
-
return keyless;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return hydrateSingle(keyless);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export function hydrateMessages(messages: Record<string, any>) {
|
|
157
|
-
for (const key in messages) {
|
|
158
|
-
messages[key] = hydrateFormatJsAst(messages[key]);
|
|
159
|
-
}
|
|
160
|
-
return messages;
|
|
161
|
-
}
|