intl-template 1.0.0-alpha.4 → 1.0.0-alpha.5
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/intl.js +52 -100
- package/dist/intl.js.map +1 -1
- package/package.json +1 -1
- package/tsconfig.json +1 -1
package/dist/intl.js
CHANGED
|
@@ -1,54 +1,24 @@
|
|
|
1
|
-
var __extends = (this && this.__extends) || (function () {
|
|
2
|
-
var extendStatics = function (d, b) {
|
|
3
|
-
extendStatics = Object.setPrototypeOf ||
|
|
4
|
-
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
5
|
-
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
6
|
-
return extendStatics(d, b);
|
|
7
|
-
};
|
|
8
|
-
return function (d, b) {
|
|
9
|
-
if (typeof b !== "function" && b !== null)
|
|
10
|
-
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
11
|
-
extendStatics(d, b);
|
|
12
|
-
function __() { this.constructor = d; }
|
|
13
|
-
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
14
|
-
};
|
|
15
|
-
})();
|
|
16
1
|
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
17
2
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
18
3
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
19
4
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
20
5
|
};
|
|
21
|
-
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
22
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
23
|
-
if (ar || !(i in from)) {
|
|
24
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
25
|
-
ar[i] = from[i];
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
29
|
-
};
|
|
30
6
|
var _Translation_templates;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
function Runes() {
|
|
34
|
-
return _super !== null && _super.apply(this, arguments) || this;
|
|
35
|
-
}
|
|
36
|
-
Runes.prototype.toString = function () {
|
|
7
|
+
export class Runes extends Array {
|
|
8
|
+
toString() {
|
|
37
9
|
return this.join("");
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
}(Array));
|
|
41
|
-
export { Runes };
|
|
10
|
+
}
|
|
11
|
+
}
|
|
42
12
|
/**
|
|
43
13
|
* Parses a template string and extracts the template parts and order of slots.
|
|
44
14
|
* @param {string} templateString - The template string to parse.
|
|
45
15
|
* @returns {{ template: string[], order: number[] }}
|
|
46
16
|
*/
|
|
47
17
|
export function parseTemplate(templateString) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
parts.forEach(
|
|
18
|
+
const order = [];
|
|
19
|
+
const template = [];
|
|
20
|
+
const parts = templateString.split(/({\d*})/);
|
|
21
|
+
parts.forEach((part) => {
|
|
52
22
|
if (part.match(/^{\d*}$/)) {
|
|
53
23
|
if (part === '{}') {
|
|
54
24
|
order.push(order.length);
|
|
@@ -62,22 +32,21 @@ export function parseTemplate(templateString) {
|
|
|
62
32
|
template.push(part);
|
|
63
33
|
}
|
|
64
34
|
});
|
|
65
|
-
return { template
|
|
35
|
+
return { template, order };
|
|
66
36
|
}
|
|
67
37
|
/**
|
|
68
38
|
* Represents a Translation object that handles string translation based on locale and templates.
|
|
69
39
|
*/
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
var _this = this;
|
|
40
|
+
export class Translation {
|
|
41
|
+
constructor(locale) {
|
|
73
42
|
/**
|
|
74
43
|
* Templates object that stores the translation templates for each locale.
|
|
75
44
|
* @type {Proxy}
|
|
76
45
|
*/
|
|
77
46
|
_Translation_templates.set(this, new Proxy({}, {
|
|
78
|
-
get
|
|
47
|
+
get(templates, locale) {
|
|
79
48
|
return new Proxy(templates[locale] || {}, {
|
|
80
|
-
set
|
|
49
|
+
set(region, key, value) {
|
|
81
50
|
if (typeof value !== "string") {
|
|
82
51
|
throw new Error("Template must be a string.");
|
|
83
52
|
}
|
|
@@ -86,9 +55,8 @@ var Translation = /** @class */ (function () {
|
|
|
86
55
|
}
|
|
87
56
|
});
|
|
88
57
|
},
|
|
89
|
-
set
|
|
90
|
-
templates[locale] = Object.entries(regionTemplates).reduce(
|
|
91
|
-
var key = _a[0], value = _a[1];
|
|
58
|
+
set(templates, locale, regionTemplates) {
|
|
59
|
+
templates[locale] = Object.entries(regionTemplates).reduce((region, [key, value]) => {
|
|
92
60
|
region[key] = parseTemplate(value);
|
|
93
61
|
return region;
|
|
94
62
|
}, {});
|
|
@@ -104,36 +72,32 @@ var Translation = /** @class */ (function () {
|
|
|
104
72
|
* @returns {Runes} - The translated string with dynamic parts inserted.
|
|
105
73
|
* @throws {Error} - If the length of the template parts does not match the length of the template.
|
|
106
74
|
*/
|
|
107
|
-
this.translate =
|
|
75
|
+
this.translate = (locale, strings, ...parts) => {
|
|
108
76
|
var _a, _b, _c;
|
|
109
|
-
var parts = [];
|
|
110
|
-
for (var _i = 2; _i < arguments.length; _i++) {
|
|
111
|
-
parts[_i - 2] = arguments[_i];
|
|
112
|
-
}
|
|
113
77
|
if (typeof strings === "string") {
|
|
114
78
|
strings = strings.split("{}");
|
|
115
79
|
}
|
|
116
|
-
|
|
117
|
-
|
|
80
|
+
const key = strings.join("{}");
|
|
81
|
+
let translation = (_a = __classPrivateFieldGet(this, _Translation_templates, "f")) === null || _a === void 0 ? void 0 : _a[locale];
|
|
118
82
|
if (!translation) {
|
|
119
|
-
translation = __classPrivateFieldGet(
|
|
83
|
+
translation = __classPrivateFieldGet(this, _Translation_templates, "f")[this.defaultLocale];
|
|
120
84
|
}
|
|
121
|
-
|
|
85
|
+
let { template, order } = (translation === null || translation === void 0 ? void 0 : translation[key]) || {};
|
|
122
86
|
if (!template) {
|
|
123
87
|
if (((_c = (_b = import.meta) === null || _b === void 0 ? void 0 : _b.env) === null || _c === void 0 ? void 0 : _c.MODE) === "development") {
|
|
124
|
-
console.warn(
|
|
88
|
+
console.warn(`not match translate key, ${key}`, { translation, locale, strings, parts });
|
|
125
89
|
}
|
|
126
90
|
template = strings.slice();
|
|
127
|
-
order = parts.map(
|
|
91
|
+
order = parts.map((_, i) => i);
|
|
128
92
|
}
|
|
129
93
|
if (parts.length !== template.length - 1) {
|
|
130
|
-
throw new Error(
|
|
94
|
+
throw new Error(`translate template parts length does not match. locale: ${locale}, key: ${key}`);
|
|
131
95
|
}
|
|
132
|
-
|
|
96
|
+
const runes = template.reduce((runes, template, idx) => {
|
|
133
97
|
runes.push(template);
|
|
134
|
-
|
|
98
|
+
const orderIdx = order[idx];
|
|
135
99
|
if (orderIdx >= 0) {
|
|
136
|
-
|
|
100
|
+
const part = parts[orderIdx];
|
|
137
101
|
if (typeof part === "function") {
|
|
138
102
|
runes.push(part(locale));
|
|
139
103
|
}
|
|
@@ -152,65 +116,53 @@ var Translation = /** @class */ (function () {
|
|
|
152
116
|
* @param {*} matchString
|
|
153
117
|
* @returns {Runes}
|
|
154
118
|
*/
|
|
155
|
-
this.translateByRegEx =
|
|
156
|
-
|
|
157
|
-
return
|
|
119
|
+
this.translateByRegEx = (locale, regexString, matchString) => {
|
|
120
|
+
const { parts, strings } = regexTemplate(regexString, matchString);
|
|
121
|
+
return this.translate(locale, strings, ...parts);
|
|
158
122
|
};
|
|
159
|
-
this.l10n =
|
|
160
|
-
|
|
161
|
-
for (var _i = 1; _i < arguments.length; _i++) {
|
|
162
|
-
parts[_i - 1] = arguments[_i];
|
|
163
|
-
}
|
|
164
|
-
return translation.translate.apply(translation, __spreadArray([_this.defaultLocale, strings], parts, false));
|
|
123
|
+
this.l10n = (strings, ...parts) => {
|
|
124
|
+
return translation.translate(this.defaultLocale, strings, ...parts);
|
|
165
125
|
};
|
|
166
|
-
this.l10nRegExp =
|
|
167
|
-
return translation.translateByRegEx(
|
|
126
|
+
this.l10nRegExp = (regexString, matchString) => {
|
|
127
|
+
return translation.translateByRegEx(this.defaultLocale, regexString, matchString);
|
|
168
128
|
};
|
|
169
129
|
this.defaultLocale = locale;
|
|
170
130
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
return true;
|
|
182
|
-
},
|
|
183
|
-
enumerable: false,
|
|
184
|
-
configurable: true
|
|
185
|
-
});
|
|
186
|
-
return Translation;
|
|
187
|
-
}());
|
|
188
|
-
export { Translation };
|
|
131
|
+
get templates() {
|
|
132
|
+
return __classPrivateFieldGet(this, _Translation_templates, "f");
|
|
133
|
+
}
|
|
134
|
+
set templates(value) {
|
|
135
|
+
Object.entries(value).forEach(([locale, regionTemplates]) => {
|
|
136
|
+
__classPrivateFieldGet(this, _Translation_templates, "f")[locale] = regionTemplates;
|
|
137
|
+
});
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
189
141
|
_Translation_templates = new WeakMap();
|
|
190
|
-
|
|
142
|
+
const translation = new Translation();
|
|
191
143
|
export default translation;
|
|
192
|
-
export
|
|
193
|
-
export
|
|
144
|
+
export const l10n = translation.l10n;
|
|
145
|
+
export const l10nRegExp = translation.l10nRegExp;
|
|
194
146
|
/**
|
|
195
147
|
* @param {string} regexString
|
|
196
148
|
* @param {string} matchString
|
|
197
149
|
* @returns {{ strings: Array<string>, parts: Array<string> }}
|
|
198
150
|
*/
|
|
199
151
|
export function regexTemplate(regexString, matchString) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
152
|
+
let parts = [];
|
|
153
|
+
const strings = [];
|
|
154
|
+
const matches = new RegExp(regexString).exec(matchString);
|
|
203
155
|
if (!matches) {
|
|
204
|
-
return { parts: [], strings
|
|
156
|
+
return { parts: [], strings };
|
|
205
157
|
}
|
|
206
158
|
parts = matches.slice(1);
|
|
207
159
|
regexString
|
|
208
160
|
.split(/(\([^)]+\))/) // split by regex group
|
|
209
|
-
.forEach(
|
|
161
|
+
.forEach(part => {
|
|
210
162
|
if (!part.startsWith("(") || !part.endsWith(")")) {
|
|
211
163
|
strings.push(part);
|
|
212
164
|
}
|
|
213
165
|
});
|
|
214
|
-
return { strings
|
|
166
|
+
return { strings, parts };
|
|
215
167
|
}
|
|
216
168
|
//# sourceMappingURL=intl.js.map
|
package/dist/intl.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intl.js","sourceRoot":"","sources":["../src/intl.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"intl.js","sourceRoot":"","sources":["../src/intl.js"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED