-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
141 lines (123 loc) · 5.44 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import { LocaleKey } from 'intl-schematic';
import { createPlugin } from 'intl-schematic/plugins';
declare module 'intl-schematic/plugins' {
export interface PluginRegistry<LocaleDoc, Key, PluginInfo, ContextualPlugins> {
ArraysPlugin: {
// Any attempt to externalize these types leads to a rat race between a type simplifier and a type inferer
args: [
references?: keyof Exclude<LocaleDoc[Key][number], string> extends infer Keys extends LocaleKey<LocaleDoc>
? {
[key in Keys]:
GetPluginNameFromContext<LocaleDoc, key, ContextualPlugins> extends infer PluginName extends keyof PluginRegistry
? PluginRegistry<LocaleDoc, key,
ContextualPlugins[PluginName]['info'],
ContextualPlugins
>[PluginName]['args']
: unknown;
} : {
// In case if references for the key weren't recognized,
// show all locale keys and parameter types as options to the user
[key in LocaleKey<LocaleDoc>]?:
GetPluginNameFromContext<LocaleDoc, key, ContextualPlugins> extends infer PluginName extends keyof PluginRegistry
? PluginRegistry<LocaleDoc, key,
ContextualPlugins[PluginName]['info'],
ContextualPlugins
>[PluginName]['args']
: unknown;
},
separator?: string | ((translatedArray: string[], defaultSeparator: string) => string),
];
// Extracts referenced keys from arrays and detects their processors and signatures
// to display them to the user
signature: {
[key in keyof Exclude<LocaleDoc[Key][number], string> & LocaleKey<LocaleDoc>]:
GetPluginNameFromContext<LocaleDoc, key, ContextualPlugins> extends infer PluginName
? PluginName extends keyof PluginRegistry
? PluginRegistry<LocaleDoc, key,
ContextualPlugins[PluginName]['info'],
ContextualPlugins
>[PluginName] extends PluginRecord<any, any, infer Signature>
? [PluginName, Signature]
: PluginName
: PluginName
: LocaleDoc[key];
};
};
}
}
function match(value: unknown): value is Array<string | Record<string, unknown>> {
return Array.isArray(value);
}
/**
* Process an array record of this format:
* `["Some text", { "translation-key": "" }]`
*
* If a referenced key matches with another plugin,
* it's possible to reference a raw parameter for the plugin:
* ```
* // Will reference the parameter at index 0 passed into the translation function for this key
* ["Some text", { "translation-key": "" }, "0:translation-key"]
* ```
*
* Will find all translation keys referenced, resolve them
* and join all elements using a custom separator (space by-default).
*
* @param defaultSeparator a string to join the array elements by, default is space
*/
export const ArraysPlugin = (defaultSeparator = ' ') => createPlugin('ArraysPlugin', match, {
translate(
referenceParamsByKey?: Record<string, unknown[]>,
separator: string | ((arr: string[], dSeparator: string) => string) = defaultSeparator
) {
const startsWithIndex = /^.*?:/;
const safeReferences = referenceParamsByKey ?? {};
const processReference = (referencedKey: string): string[] => {
if (startsWithIndex.test(referencedKey)) {
const [argIndexName, inputKey] = referencedKey.split(':');
const argIndex = isNaN(Number(argIndexName)) ? 0 : Number(argIndexName);
const references = normalizeRefs(safeReferences, inputKey);
return [String(references[argIndex])];
}
const result = referencedKey in (safeReferences)
? this.translate(
referencedKey,
...normalizeRefs(safeReferences, referencedKey)
)
: this.translate(referencedKey);
if (typeof result === 'string') {
return [result];
}
return [];
}
const result = this.value.reduce<string[]>((arr, refK) => {
if (typeof refK === 'string') {
return [...arr, ...processReference(refK)];
}
const refParamKey = Object.keys(refK)[0];
if (typeof safeReferences[refParamKey] === 'undefined' && refParamKey in refK) {
safeReferences[refParamKey] = normalizeRefs(refK, refParamKey);
} else if (refParamKey in refK) {
const referenceParams = normalizeRefs(safeReferences, refParamKey);
const inlineParams = normalizeRefs(refK, refParamKey);
safeReferences[refParamKey] = referenceParams
.map((param, i) => {
const inlineParam = inlineParams[i];
return typeof param === 'object' && typeof inlineParam === 'object'
? { ...inlineParam, ...param }
: (param ?? inlineParam);
});
}
return [...arr, ...processReference(refParamKey)];
}, []);
if (typeof separator === 'string') {
return result.join(separator);
}
return separator(result, defaultSeparator);
function normalizeRefs(referenceMap: Record<string, unknown>, referenceKey: string) {
const reference = referenceMap[referenceKey];
return Array.isArray(reference)
? reference as unknown[]
: reference == null ? [] : [reference];
}
}
});