feelin 4.3.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.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.rspec +2 -0
- data/CHANGELOG.md +10 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/feelin.gemspec +22 -0
- data/lib/feelin/js/node_modules/.package-lock.json +67 -0
- data/lib/feelin/js/node_modules/@lezer/common/LICENSE +21 -0
- data/lib/feelin/js/node_modules/@lezer/common/README.md +14 -0
- data/lib/feelin/js/node_modules/@lezer/common/dist/index.cjs +2181 -0
- data/lib/feelin/js/node_modules/@lezer/common/dist/index.d.cts +1137 -0
- data/lib/feelin/js/node_modules/@lezer/common/dist/index.d.ts +1137 -0
- data/lib/feelin/js/node_modules/@lezer/common/dist/index.js +2168 -0
- data/lib/feelin/js/node_modules/@lezer/common/package.json +32 -0
- data/lib/feelin/js/node_modules/@lezer/highlight/LICENSE +21 -0
- data/lib/feelin/js/node_modules/@lezer/highlight/README.md +14 -0
- data/lib/feelin/js/node_modules/@lezer/highlight/dist/index.cjs +915 -0
- data/lib/feelin/js/node_modules/@lezer/highlight/dist/index.d.cts +621 -0
- data/lib/feelin/js/node_modules/@lezer/highlight/dist/index.d.ts +623 -0
- data/lib/feelin/js/node_modules/@lezer/highlight/dist/index.js +904 -0
- data/lib/feelin/js/node_modules/@lezer/highlight/package.json +31 -0
- data/lib/feelin/js/node_modules/@lezer/lr/LICENSE +21 -0
- data/lib/feelin/js/node_modules/@lezer/lr/README.md +25 -0
- data/lib/feelin/js/node_modules/@lezer/lr/dist/constants.d.ts +45 -0
- data/lib/feelin/js/node_modules/@lezer/lr/dist/constants.js +5 -0
- data/lib/feelin/js/node_modules/@lezer/lr/dist/index.cjs +1890 -0
- data/lib/feelin/js/node_modules/@lezer/lr/dist/index.d.cts +303 -0
- data/lib/feelin/js/node_modules/@lezer/lr/dist/index.d.ts +303 -0
- data/lib/feelin/js/node_modules/@lezer/lr/dist/index.js +1883 -0
- data/lib/feelin/js/node_modules/@lezer/lr/package.json +32 -0
- data/lib/feelin/js/node_modules/feelin/LICENSE +21 -0
- data/lib/feelin/js/node_modules/feelin/README.md +65 -0
- data/lib/feelin/js/node_modules/feelin/dist/builtins.d.ts +355 -0
- data/lib/feelin/js/node_modules/feelin/dist/index.cjs +2072 -0
- data/lib/feelin/js/node_modules/feelin/dist/index.cjs.map +1 -0
- data/lib/feelin/js/node_modules/feelin/dist/index.d.ts +3 -0
- data/lib/feelin/js/node_modules/feelin/dist/index.esm.js +2063 -0
- data/lib/feelin/js/node_modules/feelin/dist/index.esm.js.map +1 -0
- data/lib/feelin/js/node_modules/feelin/dist/interpreter.d.ts +26 -0
- data/lib/feelin/js/node_modules/feelin/dist/parser.d.ts +4 -0
- data/lib/feelin/js/node_modules/feelin/dist/temporal.d.ts +6 -0
- data/lib/feelin/js/node_modules/feelin/dist/types.d.ts +35 -0
- data/lib/feelin/js/node_modules/feelin/dist/utils.d.ts +12 -0
- data/lib/feelin/js/node_modules/feelin/package.json +63 -0
- data/lib/feelin/js/node_modules/lezer-feel/LICENSE +21 -0
- data/lib/feelin/js/node_modules/lezer-feel/README.md +94 -0
- data/lib/feelin/js/node_modules/lezer-feel/dist/index.cjs +1328 -0
- data/lib/feelin/js/node_modules/lezer-feel/dist/index.cjs.map +1 -0
- data/lib/feelin/js/node_modules/lezer-feel/dist/index.d.ts +32 -0
- data/lib/feelin/js/node_modules/lezer-feel/dist/index.js +1323 -0
- data/lib/feelin/js/node_modules/lezer-feel/dist/index.js.map +1 -0
- data/lib/feelin/js/node_modules/lezer-feel/package.json +61 -0
- data/lib/feelin/js/node_modules/luxon/LICENSE.md +7 -0
- data/lib/feelin/js/node_modules/luxon/README.md +55 -0
- data/lib/feelin/js/node_modules/luxon/build/amd/luxon.js +8623 -0
- data/lib/feelin/js/node_modules/luxon/build/amd/luxon.js.map +1 -0
- data/lib/feelin/js/node_modules/luxon/build/cjs-browser/luxon.js +8621 -0
- data/lib/feelin/js/node_modules/luxon/build/cjs-browser/luxon.js.map +1 -0
- data/lib/feelin/js/node_modules/luxon/build/es6/luxon.js +8011 -0
- data/lib/feelin/js/node_modules/luxon/build/es6/luxon.js.map +1 -0
- data/lib/feelin/js/node_modules/luxon/build/global/luxon.js +8626 -0
- data/lib/feelin/js/node_modules/luxon/build/global/luxon.js.map +1 -0
- data/lib/feelin/js/node_modules/luxon/build/global/luxon.min.js +1 -0
- data/lib/feelin/js/node_modules/luxon/build/global/luxon.min.js.map +1 -0
- data/lib/feelin/js/node_modules/luxon/build/node/luxon.js +7679 -0
- data/lib/feelin/js/node_modules/luxon/build/node/luxon.js.map +1 -0
- data/lib/feelin/js/node_modules/luxon/package.json +87 -0
- data/lib/feelin/js/node_modules/luxon/src/datetime.js +2566 -0
- data/lib/feelin/js/node_modules/luxon/src/duration.js +990 -0
- data/lib/feelin/js/node_modules/luxon/src/errors.js +61 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/conversions.js +206 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/diff.js +95 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/digits.js +90 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/english.js +233 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/formats.js +176 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/formatter.js +409 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/invalid.js +14 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/locale.js +554 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/regexParser.js +335 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/tokenParser.js +505 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/util.js +316 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/zoneUtil.js +34 -0
- data/lib/feelin/js/node_modules/luxon/src/info.js +205 -0
- data/lib/feelin/js/node_modules/luxon/src/interval.js +665 -0
- data/lib/feelin/js/node_modules/luxon/src/luxon.js +26 -0
- data/lib/feelin/js/node_modules/luxon/src/package.json +4 -0
- data/lib/feelin/js/node_modules/luxon/src/settings.js +180 -0
- data/lib/feelin/js/node_modules/luxon/src/zone.js +97 -0
- data/lib/feelin/js/node_modules/luxon/src/zones/IANAZone.js +231 -0
- data/lib/feelin/js/node_modules/luxon/src/zones/fixedOffsetZone.js +150 -0
- data/lib/feelin/js/node_modules/luxon/src/zones/invalidZone.js +53 -0
- data/lib/feelin/js/node_modules/luxon/src/zones/systemZone.js +61 -0
- data/lib/feelin/js/node_modules/min-dash/LICENSE +21 -0
- data/lib/feelin/js/node_modules/min-dash/README.md +38 -0
- data/lib/feelin/js/node_modules/min-dash/dist/array.d.ts +12 -0
- data/lib/feelin/js/node_modules/min-dash/dist/collection.d.ts +174 -0
- data/lib/feelin/js/node_modules/min-dash/dist/fn.d.ts +37 -0
- data/lib/feelin/js/node_modules/min-dash/dist/index.cjs +910 -0
- data/lib/feelin/js/node_modules/min-dash/dist/index.d.ts +5 -0
- data/lib/feelin/js/node_modules/min-dash/dist/index.esm.js +872 -0
- data/lib/feelin/js/node_modules/min-dash/dist/lang.d.ts +29 -0
- data/lib/feelin/js/node_modules/min-dash/dist/min-dash.js +916 -0
- data/lib/feelin/js/node_modules/min-dash/dist/min-dash.min.js +1 -0
- data/lib/feelin/js/node_modules/min-dash/dist/object.d.ts +112 -0
- data/lib/feelin/js/node_modules/min-dash/package.json +72 -0
- data/lib/feelin/js/package-lock.json +72 -0
- data/lib/feelin/js/package.json +5 -0
- data/lib/feelin/version.rb +3 -0
- data/lib/feelin.rb +63 -0
- data/spec/feelin/feelin_spec.rb +38 -0
- data/spec/spec_helper.rb +2 -0
- metadata +198 -0
@@ -0,0 +1,554 @@
|
|
1
|
+
import { hasLocaleWeekInfo, hasRelative, padStart, roundTo, validateWeekSettings } from "./util.js";
|
2
|
+
import * as English from "./english.js";
|
3
|
+
import Settings from "../settings.js";
|
4
|
+
import DateTime from "../datetime.js";
|
5
|
+
import IANAZone from "../zones/IANAZone.js";
|
6
|
+
|
7
|
+
// todo - remap caching
|
8
|
+
|
9
|
+
let intlLFCache = {};
|
10
|
+
function getCachedLF(locString, opts = {}) {
|
11
|
+
const key = JSON.stringify([locString, opts]);
|
12
|
+
let dtf = intlLFCache[key];
|
13
|
+
if (!dtf) {
|
14
|
+
dtf = new Intl.ListFormat(locString, opts);
|
15
|
+
intlLFCache[key] = dtf;
|
16
|
+
}
|
17
|
+
return dtf;
|
18
|
+
}
|
19
|
+
|
20
|
+
let intlDTCache = {};
|
21
|
+
function getCachedDTF(locString, opts = {}) {
|
22
|
+
const key = JSON.stringify([locString, opts]);
|
23
|
+
let dtf = intlDTCache[key];
|
24
|
+
if (!dtf) {
|
25
|
+
dtf = new Intl.DateTimeFormat(locString, opts);
|
26
|
+
intlDTCache[key] = dtf;
|
27
|
+
}
|
28
|
+
return dtf;
|
29
|
+
}
|
30
|
+
|
31
|
+
let intlNumCache = {};
|
32
|
+
function getCachedINF(locString, opts = {}) {
|
33
|
+
const key = JSON.stringify([locString, opts]);
|
34
|
+
let inf = intlNumCache[key];
|
35
|
+
if (!inf) {
|
36
|
+
inf = new Intl.NumberFormat(locString, opts);
|
37
|
+
intlNumCache[key] = inf;
|
38
|
+
}
|
39
|
+
return inf;
|
40
|
+
}
|
41
|
+
|
42
|
+
let intlRelCache = {};
|
43
|
+
function getCachedRTF(locString, opts = {}) {
|
44
|
+
const { base, ...cacheKeyOpts } = opts; // exclude `base` from the options
|
45
|
+
const key = JSON.stringify([locString, cacheKeyOpts]);
|
46
|
+
let inf = intlRelCache[key];
|
47
|
+
if (!inf) {
|
48
|
+
inf = new Intl.RelativeTimeFormat(locString, opts);
|
49
|
+
intlRelCache[key] = inf;
|
50
|
+
}
|
51
|
+
return inf;
|
52
|
+
}
|
53
|
+
|
54
|
+
let sysLocaleCache = null;
|
55
|
+
function systemLocale() {
|
56
|
+
if (sysLocaleCache) {
|
57
|
+
return sysLocaleCache;
|
58
|
+
} else {
|
59
|
+
sysLocaleCache = new Intl.DateTimeFormat().resolvedOptions().locale;
|
60
|
+
return sysLocaleCache;
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
let intlResolvedOptionsCache = {};
|
65
|
+
function getCachedIntResolvedOptions(locString) {
|
66
|
+
if (!intlResolvedOptionsCache[locString]) {
|
67
|
+
intlResolvedOptionsCache[locString] = new Intl.DateTimeFormat(locString).resolvedOptions();
|
68
|
+
}
|
69
|
+
return intlResolvedOptionsCache[locString];
|
70
|
+
}
|
71
|
+
|
72
|
+
let weekInfoCache = {};
|
73
|
+
function getCachedWeekInfo(locString) {
|
74
|
+
let data = weekInfoCache[locString];
|
75
|
+
if (!data) {
|
76
|
+
const locale = new Intl.Locale(locString);
|
77
|
+
// browsers currently implement this as a property, but spec says it should be a getter function
|
78
|
+
data = "getWeekInfo" in locale ? locale.getWeekInfo() : locale.weekInfo;
|
79
|
+
weekInfoCache[locString] = data;
|
80
|
+
}
|
81
|
+
return data;
|
82
|
+
}
|
83
|
+
|
84
|
+
function parseLocaleString(localeStr) {
|
85
|
+
// I really want to avoid writing a BCP 47 parser
|
86
|
+
// see, e.g. https://github.com/wooorm/bcp-47
|
87
|
+
// Instead, we'll do this:
|
88
|
+
|
89
|
+
// a) if the string has no -u extensions, just leave it alone
|
90
|
+
// b) if it does, use Intl to resolve everything
|
91
|
+
// c) if Intl fails, try again without the -u
|
92
|
+
|
93
|
+
// private subtags and unicode subtags have ordering requirements,
|
94
|
+
// and we're not properly parsing this, so just strip out the
|
95
|
+
// private ones if they exist.
|
96
|
+
const xIndex = localeStr.indexOf("-x-");
|
97
|
+
if (xIndex !== -1) {
|
98
|
+
localeStr = localeStr.substring(0, xIndex);
|
99
|
+
}
|
100
|
+
|
101
|
+
const uIndex = localeStr.indexOf("-u-");
|
102
|
+
if (uIndex === -1) {
|
103
|
+
return [localeStr];
|
104
|
+
} else {
|
105
|
+
let options;
|
106
|
+
let selectedStr;
|
107
|
+
try {
|
108
|
+
options = getCachedDTF(localeStr).resolvedOptions();
|
109
|
+
selectedStr = localeStr;
|
110
|
+
} catch (e) {
|
111
|
+
const smaller = localeStr.substring(0, uIndex);
|
112
|
+
options = getCachedDTF(smaller).resolvedOptions();
|
113
|
+
selectedStr = smaller;
|
114
|
+
}
|
115
|
+
|
116
|
+
const { numberingSystem, calendar } = options;
|
117
|
+
return [selectedStr, numberingSystem, calendar];
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
121
|
+
function intlConfigString(localeStr, numberingSystem, outputCalendar) {
|
122
|
+
if (outputCalendar || numberingSystem) {
|
123
|
+
if (!localeStr.includes("-u-")) {
|
124
|
+
localeStr += "-u";
|
125
|
+
}
|
126
|
+
|
127
|
+
if (outputCalendar) {
|
128
|
+
localeStr += `-ca-${outputCalendar}`;
|
129
|
+
}
|
130
|
+
|
131
|
+
if (numberingSystem) {
|
132
|
+
localeStr += `-nu-${numberingSystem}`;
|
133
|
+
}
|
134
|
+
return localeStr;
|
135
|
+
} else {
|
136
|
+
return localeStr;
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
function mapMonths(f) {
|
141
|
+
const ms = [];
|
142
|
+
for (let i = 1; i <= 12; i++) {
|
143
|
+
const dt = DateTime.utc(2009, i, 1);
|
144
|
+
ms.push(f(dt));
|
145
|
+
}
|
146
|
+
return ms;
|
147
|
+
}
|
148
|
+
|
149
|
+
function mapWeekdays(f) {
|
150
|
+
const ms = [];
|
151
|
+
for (let i = 1; i <= 7; i++) {
|
152
|
+
const dt = DateTime.utc(2016, 11, 13 + i);
|
153
|
+
ms.push(f(dt));
|
154
|
+
}
|
155
|
+
return ms;
|
156
|
+
}
|
157
|
+
|
158
|
+
function listStuff(loc, length, englishFn, intlFn) {
|
159
|
+
const mode = loc.listingMode();
|
160
|
+
|
161
|
+
if (mode === "error") {
|
162
|
+
return null;
|
163
|
+
} else if (mode === "en") {
|
164
|
+
return englishFn(length);
|
165
|
+
} else {
|
166
|
+
return intlFn(length);
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
function supportsFastNumbers(loc) {
|
171
|
+
if (loc.numberingSystem && loc.numberingSystem !== "latn") {
|
172
|
+
return false;
|
173
|
+
} else {
|
174
|
+
return (
|
175
|
+
loc.numberingSystem === "latn" ||
|
176
|
+
!loc.locale ||
|
177
|
+
loc.locale.startsWith("en") ||
|
178
|
+
getCachedIntResolvedOptions(loc.locale).numberingSystem === "latn"
|
179
|
+
);
|
180
|
+
}
|
181
|
+
}
|
182
|
+
|
183
|
+
/**
|
184
|
+
* @private
|
185
|
+
*/
|
186
|
+
|
187
|
+
class PolyNumberFormatter {
|
188
|
+
constructor(intl, forceSimple, opts) {
|
189
|
+
this.padTo = opts.padTo || 0;
|
190
|
+
this.floor = opts.floor || false;
|
191
|
+
|
192
|
+
const { padTo, floor, ...otherOpts } = opts;
|
193
|
+
|
194
|
+
if (!forceSimple || Object.keys(otherOpts).length > 0) {
|
195
|
+
const intlOpts = { useGrouping: false, ...opts };
|
196
|
+
if (opts.padTo > 0) intlOpts.minimumIntegerDigits = opts.padTo;
|
197
|
+
this.inf = getCachedINF(intl, intlOpts);
|
198
|
+
}
|
199
|
+
}
|
200
|
+
|
201
|
+
format(i) {
|
202
|
+
if (this.inf) {
|
203
|
+
const fixed = this.floor ? Math.floor(i) : i;
|
204
|
+
return this.inf.format(fixed);
|
205
|
+
} else {
|
206
|
+
// to match the browser's numberformatter defaults
|
207
|
+
const fixed = this.floor ? Math.floor(i) : roundTo(i, 3);
|
208
|
+
return padStart(fixed, this.padTo);
|
209
|
+
}
|
210
|
+
}
|
211
|
+
}
|
212
|
+
|
213
|
+
/**
|
214
|
+
* @private
|
215
|
+
*/
|
216
|
+
|
217
|
+
class PolyDateFormatter {
|
218
|
+
constructor(dt, intl, opts) {
|
219
|
+
this.opts = opts;
|
220
|
+
this.originalZone = undefined;
|
221
|
+
|
222
|
+
let z = undefined;
|
223
|
+
if (this.opts.timeZone) {
|
224
|
+
// Don't apply any workarounds if a timeZone is explicitly provided in opts
|
225
|
+
this.dt = dt;
|
226
|
+
} else if (dt.zone.type === "fixed") {
|
227
|
+
// UTC-8 or Etc/UTC-8 are not part of tzdata, only Etc/GMT+8 and the like.
|
228
|
+
// That is why fixed-offset TZ is set to that unless it is:
|
229
|
+
// 1. Representing offset 0 when UTC is used to maintain previous behavior and does not become GMT.
|
230
|
+
// 2. Unsupported by the browser:
|
231
|
+
// - some do not support Etc/
|
232
|
+
// - < Etc/GMT-14, > Etc/GMT+12, and 30-minute or 45-minute offsets are not part of tzdata
|
233
|
+
const gmtOffset = -1 * (dt.offset / 60);
|
234
|
+
const offsetZ = gmtOffset >= 0 ? `Etc/GMT+${gmtOffset}` : `Etc/GMT${gmtOffset}`;
|
235
|
+
if (dt.offset !== 0 && IANAZone.create(offsetZ).valid) {
|
236
|
+
z = offsetZ;
|
237
|
+
this.dt = dt;
|
238
|
+
} else {
|
239
|
+
// Not all fixed-offset zones like Etc/+4:30 are present in tzdata so
|
240
|
+
// we manually apply the offset and substitute the zone as needed.
|
241
|
+
z = "UTC";
|
242
|
+
this.dt = dt.offset === 0 ? dt : dt.setZone("UTC").plus({ minutes: dt.offset });
|
243
|
+
this.originalZone = dt.zone;
|
244
|
+
}
|
245
|
+
} else if (dt.zone.type === "system") {
|
246
|
+
this.dt = dt;
|
247
|
+
} else if (dt.zone.type === "iana") {
|
248
|
+
this.dt = dt;
|
249
|
+
z = dt.zone.name;
|
250
|
+
} else {
|
251
|
+
// Custom zones can have any offset / offsetName so we just manually
|
252
|
+
// apply the offset and substitute the zone as needed.
|
253
|
+
z = "UTC";
|
254
|
+
this.dt = dt.setZone("UTC").plus({ minutes: dt.offset });
|
255
|
+
this.originalZone = dt.zone;
|
256
|
+
}
|
257
|
+
|
258
|
+
const intlOpts = { ...this.opts };
|
259
|
+
intlOpts.timeZone = intlOpts.timeZone || z;
|
260
|
+
this.dtf = getCachedDTF(intl, intlOpts);
|
261
|
+
}
|
262
|
+
|
263
|
+
format() {
|
264
|
+
if (this.originalZone) {
|
265
|
+
// If we have to substitute in the actual zone name, we have to use
|
266
|
+
// formatToParts so that the timezone can be replaced.
|
267
|
+
return this.formatToParts()
|
268
|
+
.map(({ value }) => value)
|
269
|
+
.join("");
|
270
|
+
}
|
271
|
+
return this.dtf.format(this.dt.toJSDate());
|
272
|
+
}
|
273
|
+
|
274
|
+
formatToParts() {
|
275
|
+
const parts = this.dtf.formatToParts(this.dt.toJSDate());
|
276
|
+
if (this.originalZone) {
|
277
|
+
return parts.map((part) => {
|
278
|
+
if (part.type === "timeZoneName") {
|
279
|
+
const offsetName = this.originalZone.offsetName(this.dt.ts, {
|
280
|
+
locale: this.dt.locale,
|
281
|
+
format: this.opts.timeZoneName,
|
282
|
+
});
|
283
|
+
return {
|
284
|
+
...part,
|
285
|
+
value: offsetName,
|
286
|
+
};
|
287
|
+
} else {
|
288
|
+
return part;
|
289
|
+
}
|
290
|
+
});
|
291
|
+
}
|
292
|
+
return parts;
|
293
|
+
}
|
294
|
+
|
295
|
+
resolvedOptions() {
|
296
|
+
return this.dtf.resolvedOptions();
|
297
|
+
}
|
298
|
+
}
|
299
|
+
|
300
|
+
/**
|
301
|
+
* @private
|
302
|
+
*/
|
303
|
+
class PolyRelFormatter {
|
304
|
+
constructor(intl, isEnglish, opts) {
|
305
|
+
this.opts = { style: "long", ...opts };
|
306
|
+
if (!isEnglish && hasRelative()) {
|
307
|
+
this.rtf = getCachedRTF(intl, opts);
|
308
|
+
}
|
309
|
+
}
|
310
|
+
|
311
|
+
format(count, unit) {
|
312
|
+
if (this.rtf) {
|
313
|
+
return this.rtf.format(count, unit);
|
314
|
+
} else {
|
315
|
+
return English.formatRelativeTime(unit, count, this.opts.numeric, this.opts.style !== "long");
|
316
|
+
}
|
317
|
+
}
|
318
|
+
|
319
|
+
formatToParts(count, unit) {
|
320
|
+
if (this.rtf) {
|
321
|
+
return this.rtf.formatToParts(count, unit);
|
322
|
+
} else {
|
323
|
+
return [];
|
324
|
+
}
|
325
|
+
}
|
326
|
+
}
|
327
|
+
|
328
|
+
const fallbackWeekSettings = {
|
329
|
+
firstDay: 1,
|
330
|
+
minimalDays: 4,
|
331
|
+
weekend: [6, 7],
|
332
|
+
};
|
333
|
+
|
334
|
+
/**
|
335
|
+
* @private
|
336
|
+
*/
|
337
|
+
export default class Locale {
|
338
|
+
static fromOpts(opts) {
|
339
|
+
return Locale.create(
|
340
|
+
opts.locale,
|
341
|
+
opts.numberingSystem,
|
342
|
+
opts.outputCalendar,
|
343
|
+
opts.weekSettings,
|
344
|
+
opts.defaultToEN
|
345
|
+
);
|
346
|
+
}
|
347
|
+
|
348
|
+
static create(locale, numberingSystem, outputCalendar, weekSettings, defaultToEN = false) {
|
349
|
+
const specifiedLocale = locale || Settings.defaultLocale;
|
350
|
+
// the system locale is useful for human-readable strings but annoying for parsing/formatting known formats
|
351
|
+
const localeR = specifiedLocale || (defaultToEN ? "en-US" : systemLocale());
|
352
|
+
const numberingSystemR = numberingSystem || Settings.defaultNumberingSystem;
|
353
|
+
const outputCalendarR = outputCalendar || Settings.defaultOutputCalendar;
|
354
|
+
const weekSettingsR = validateWeekSettings(weekSettings) || Settings.defaultWeekSettings;
|
355
|
+
return new Locale(localeR, numberingSystemR, outputCalendarR, weekSettingsR, specifiedLocale);
|
356
|
+
}
|
357
|
+
|
358
|
+
static resetCache() {
|
359
|
+
sysLocaleCache = null;
|
360
|
+
intlDTCache = {};
|
361
|
+
intlNumCache = {};
|
362
|
+
intlRelCache = {};
|
363
|
+
intlResolvedOptionsCache = {};
|
364
|
+
}
|
365
|
+
|
366
|
+
static fromObject({ locale, numberingSystem, outputCalendar, weekSettings } = {}) {
|
367
|
+
return Locale.create(locale, numberingSystem, outputCalendar, weekSettings);
|
368
|
+
}
|
369
|
+
|
370
|
+
constructor(locale, numbering, outputCalendar, weekSettings, specifiedLocale) {
|
371
|
+
const [parsedLocale, parsedNumberingSystem, parsedOutputCalendar] = parseLocaleString(locale);
|
372
|
+
|
373
|
+
this.locale = parsedLocale;
|
374
|
+
this.numberingSystem = numbering || parsedNumberingSystem || null;
|
375
|
+
this.outputCalendar = outputCalendar || parsedOutputCalendar || null;
|
376
|
+
this.weekSettings = weekSettings;
|
377
|
+
this.intl = intlConfigString(this.locale, this.numberingSystem, this.outputCalendar);
|
378
|
+
|
379
|
+
this.weekdaysCache = { format: {}, standalone: {} };
|
380
|
+
this.monthsCache = { format: {}, standalone: {} };
|
381
|
+
this.meridiemCache = null;
|
382
|
+
this.eraCache = {};
|
383
|
+
|
384
|
+
this.specifiedLocale = specifiedLocale;
|
385
|
+
this.fastNumbersCached = null;
|
386
|
+
}
|
387
|
+
|
388
|
+
get fastNumbers() {
|
389
|
+
if (this.fastNumbersCached == null) {
|
390
|
+
this.fastNumbersCached = supportsFastNumbers(this);
|
391
|
+
}
|
392
|
+
|
393
|
+
return this.fastNumbersCached;
|
394
|
+
}
|
395
|
+
|
396
|
+
listingMode() {
|
397
|
+
const isActuallyEn = this.isEnglish();
|
398
|
+
const hasNoWeirdness =
|
399
|
+
(this.numberingSystem === null || this.numberingSystem === "latn") &&
|
400
|
+
(this.outputCalendar === null || this.outputCalendar === "gregory");
|
401
|
+
return isActuallyEn && hasNoWeirdness ? "en" : "intl";
|
402
|
+
}
|
403
|
+
|
404
|
+
clone(alts) {
|
405
|
+
if (!alts || Object.getOwnPropertyNames(alts).length === 0) {
|
406
|
+
return this;
|
407
|
+
} else {
|
408
|
+
return Locale.create(
|
409
|
+
alts.locale || this.specifiedLocale,
|
410
|
+
alts.numberingSystem || this.numberingSystem,
|
411
|
+
alts.outputCalendar || this.outputCalendar,
|
412
|
+
validateWeekSettings(alts.weekSettings) || this.weekSettings,
|
413
|
+
alts.defaultToEN || false
|
414
|
+
);
|
415
|
+
}
|
416
|
+
}
|
417
|
+
|
418
|
+
redefaultToEN(alts = {}) {
|
419
|
+
return this.clone({ ...alts, defaultToEN: true });
|
420
|
+
}
|
421
|
+
|
422
|
+
redefaultToSystem(alts = {}) {
|
423
|
+
return this.clone({ ...alts, defaultToEN: false });
|
424
|
+
}
|
425
|
+
|
426
|
+
months(length, format = false) {
|
427
|
+
return listStuff(this, length, English.months, () => {
|
428
|
+
const intl = format ? { month: length, day: "numeric" } : { month: length },
|
429
|
+
formatStr = format ? "format" : "standalone";
|
430
|
+
if (!this.monthsCache[formatStr][length]) {
|
431
|
+
this.monthsCache[formatStr][length] = mapMonths((dt) => this.extract(dt, intl, "month"));
|
432
|
+
}
|
433
|
+
return this.monthsCache[formatStr][length];
|
434
|
+
});
|
435
|
+
}
|
436
|
+
|
437
|
+
weekdays(length, format = false) {
|
438
|
+
return listStuff(this, length, English.weekdays, () => {
|
439
|
+
const intl = format
|
440
|
+
? { weekday: length, year: "numeric", month: "long", day: "numeric" }
|
441
|
+
: { weekday: length },
|
442
|
+
formatStr = format ? "format" : "standalone";
|
443
|
+
if (!this.weekdaysCache[formatStr][length]) {
|
444
|
+
this.weekdaysCache[formatStr][length] = mapWeekdays((dt) =>
|
445
|
+
this.extract(dt, intl, "weekday")
|
446
|
+
);
|
447
|
+
}
|
448
|
+
return this.weekdaysCache[formatStr][length];
|
449
|
+
});
|
450
|
+
}
|
451
|
+
|
452
|
+
meridiems() {
|
453
|
+
return listStuff(
|
454
|
+
this,
|
455
|
+
undefined,
|
456
|
+
() => English.meridiems,
|
457
|
+
() => {
|
458
|
+
// In theory there could be aribitrary day periods. We're gonna assume there are exactly two
|
459
|
+
// for AM and PM. This is probably wrong, but it's makes parsing way easier.
|
460
|
+
if (!this.meridiemCache) {
|
461
|
+
const intl = { hour: "numeric", hourCycle: "h12" };
|
462
|
+
this.meridiemCache = [DateTime.utc(2016, 11, 13, 9), DateTime.utc(2016, 11, 13, 19)].map(
|
463
|
+
(dt) => this.extract(dt, intl, "dayperiod")
|
464
|
+
);
|
465
|
+
}
|
466
|
+
|
467
|
+
return this.meridiemCache;
|
468
|
+
}
|
469
|
+
);
|
470
|
+
}
|
471
|
+
|
472
|
+
eras(length) {
|
473
|
+
return listStuff(this, length, English.eras, () => {
|
474
|
+
const intl = { era: length };
|
475
|
+
|
476
|
+
// This is problematic. Different calendars are going to define eras totally differently. What I need is the minimum set of dates
|
477
|
+
// to definitely enumerate them.
|
478
|
+
if (!this.eraCache[length]) {
|
479
|
+
this.eraCache[length] = [DateTime.utc(-40, 1, 1), DateTime.utc(2017, 1, 1)].map((dt) =>
|
480
|
+
this.extract(dt, intl, "era")
|
481
|
+
);
|
482
|
+
}
|
483
|
+
|
484
|
+
return this.eraCache[length];
|
485
|
+
});
|
486
|
+
}
|
487
|
+
|
488
|
+
extract(dt, intlOpts, field) {
|
489
|
+
const df = this.dtFormatter(dt, intlOpts),
|
490
|
+
results = df.formatToParts(),
|
491
|
+
matching = results.find((m) => m.type.toLowerCase() === field);
|
492
|
+
return matching ? matching.value : null;
|
493
|
+
}
|
494
|
+
|
495
|
+
numberFormatter(opts = {}) {
|
496
|
+
// this forcesimple option is never used (the only caller short-circuits on it, but it seems safer to leave)
|
497
|
+
// (in contrast, the rest of the condition is used heavily)
|
498
|
+
return new PolyNumberFormatter(this.intl, opts.forceSimple || this.fastNumbers, opts);
|
499
|
+
}
|
500
|
+
|
501
|
+
dtFormatter(dt, intlOpts = {}) {
|
502
|
+
return new PolyDateFormatter(dt, this.intl, intlOpts);
|
503
|
+
}
|
504
|
+
|
505
|
+
relFormatter(opts = {}) {
|
506
|
+
return new PolyRelFormatter(this.intl, this.isEnglish(), opts);
|
507
|
+
}
|
508
|
+
|
509
|
+
listFormatter(opts = {}) {
|
510
|
+
return getCachedLF(this.intl, opts);
|
511
|
+
}
|
512
|
+
|
513
|
+
isEnglish() {
|
514
|
+
return (
|
515
|
+
this.locale === "en" ||
|
516
|
+
this.locale.toLowerCase() === "en-us" ||
|
517
|
+
getCachedIntResolvedOptions(this.intl).locale.startsWith("en-us")
|
518
|
+
);
|
519
|
+
}
|
520
|
+
|
521
|
+
getWeekSettings() {
|
522
|
+
if (this.weekSettings) {
|
523
|
+
return this.weekSettings;
|
524
|
+
} else if (!hasLocaleWeekInfo()) {
|
525
|
+
return fallbackWeekSettings;
|
526
|
+
} else {
|
527
|
+
return getCachedWeekInfo(this.locale);
|
528
|
+
}
|
529
|
+
}
|
530
|
+
|
531
|
+
getStartOfWeek() {
|
532
|
+
return this.getWeekSettings().firstDay;
|
533
|
+
}
|
534
|
+
|
535
|
+
getMinDaysInFirstWeek() {
|
536
|
+
return this.getWeekSettings().minimalDays;
|
537
|
+
}
|
538
|
+
|
539
|
+
getWeekendDays() {
|
540
|
+
return this.getWeekSettings().weekend;
|
541
|
+
}
|
542
|
+
|
543
|
+
equals(other) {
|
544
|
+
return (
|
545
|
+
this.locale === other.locale &&
|
546
|
+
this.numberingSystem === other.numberingSystem &&
|
547
|
+
this.outputCalendar === other.outputCalendar
|
548
|
+
);
|
549
|
+
}
|
550
|
+
|
551
|
+
toString() {
|
552
|
+
return `Locale(${this.locale}, ${this.numberingSystem}, ${this.outputCalendar})`;
|
553
|
+
}
|
554
|
+
}
|