chronolizer 0.2.0 → 0.4.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.
- package/README.md +170 -167
- package/dist/ast/constructors.d.mts +3 -8
- package/dist/ast/fold.d.mts +2 -1
- package/dist/ast/fold.mjs +38 -31
- package/dist/ast/normalize.mjs +4 -2
- package/dist/ast/schemas.d.mts +18 -25
- package/dist/ast/schemas.mjs +8 -17
- package/dist/filter/expression.mjs +27 -38
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/language/model.d.mts +33 -33
- package/dist/language/model.mjs +5 -8
- package/dist/language/registry.mjs +35 -33
- package/dist/locales/cs.mjs +253 -31
- package/dist/locales/de.mjs +366 -42
- package/dist/locales/en.mjs +215 -51
- package/dist/locales/es.mjs +498 -91
- package/dist/locales/fr.mjs +360 -65
- package/dist/locales/nl.mjs +302 -64
- package/dist/locales/pl.mjs +447 -135
- package/dist/locales/shared.mjs +192 -23
- package/dist/locales/tr.mjs +220 -41
- package/dist/natural/correction.d.mts +1 -1
- package/dist/natural/correction.mjs +31 -5
- package/dist/natural/format.mjs +1 -1
- package/dist/natural/parse.d.mts +1 -1
- package/dist/natural/parse.mjs +5 -4
- package/dist/natural/policy.mjs +2 -2
- package/dist/natural/suggest.mjs +19 -3
- package/dist/natural/suggestion.mjs +11 -5
- package/dist/resolve/resolve.mjs +2 -10
- package/package.json +1 -1
package/dist/locales/es.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { normalizeNaturalText } from "../natural/text.mjs";
|
|
|
4
4
|
import { defineLanguagePlugin, languagePluginsLayer } from "../language/registry.mjs";
|
|
5
5
|
import { correctWhitespaceSeparatedText } from "../natural/correction.mjs";
|
|
6
6
|
import { completeNaturalPhrases, fixedCalendarPeriodPhrases, naturalCount, prefixNaturalPhrases } from "../natural/suggestion.mjs";
|
|
7
|
-
import { calendarPeriodOffset, candidate, datedPeriods, datedQuarterPeriods, fixedDatePeriod, fixedMonthPeriod, fixedQuarterPeriod, fixedYearPeriod, fromNowRange, futurePeriod, futureRange, isoDate, joinedNowCandidate, joinedPeriodCandidate, monthOfRelativeYear, namedDatePeriod, openBoundaryCandidate, parseTrailingCount, periodEndDay, periodRange, periodStartDay, periodToDateRange, periodsFromPhrases, quarterOfRelativeYear, relativePeriod, relativeWeekend, remainingPeriodRange, renderPeriodRange, textAt, trailingPeriod, trailingRange, untilNowRange, validYear } from "./shared.mjs";
|
|
7
|
+
import { absoluteDatePeriod, calendarPeriodOffset, candidate, compileCountAliasNormalizer, compoundCountAliases, countAliasVocabulary, currentYearDatePeriods, datedPeriods, datedQuarterPeriods, decimalTens, decomposeShiftedPeriodRange, fixedDatePeriod, fixedMonthPeriod, fixedQuarterPeriod, fixedYearPeriod, fromNowRange, futurePeriod, futureRange, isoDate, joinedNowCandidate, joinedPeriodCandidate, monthOfRelativeYear, namedCurrentYearDatePeriod, namedDatePeriod, openBoundaryCandidate, parseTrailingCount, periodBoundaryCandidate, periodDay, periodEndDay, periodRange, periodStartDay, periodToDateRange, periodsFromPhrases, quarterOfRelativeYear, relativePeriod, relativeWeekday, relativeWeekend, remainingPeriodRange, renderPeriodRange, sequentialCountAliases, shiftPeriod, textAt, trailingPeriod, trailingRange, untilNowRange, validYear } from "./shared.mjs";
|
|
8
8
|
import { Effect, Option, String as String$1 } from "effect";
|
|
9
9
|
//#region src/locales/es.ts
|
|
10
10
|
const months = [
|
|
@@ -21,6 +21,99 @@ const months = [
|
|
|
21
21
|
"noviembre",
|
|
22
22
|
"diciembre"
|
|
23
23
|
];
|
|
24
|
+
const weekdays = [
|
|
25
|
+
"lunes",
|
|
26
|
+
"martes",
|
|
27
|
+
"miércoles",
|
|
28
|
+
"jueves",
|
|
29
|
+
"viernes",
|
|
30
|
+
"sábado",
|
|
31
|
+
"domingo"
|
|
32
|
+
];
|
|
33
|
+
const nextWeekdays = weekdays.flatMap((weekday, day) => [
|
|
34
|
+
{
|
|
35
|
+
phrase: `próximo ${weekday}`,
|
|
36
|
+
day,
|
|
37
|
+
canonical: `el próximo ${weekday}`
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
phrase: `el próximo ${weekday}`,
|
|
41
|
+
day,
|
|
42
|
+
canonical: `el próximo ${weekday}`
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
phrase: `proximo ${weekday}`,
|
|
46
|
+
day,
|
|
47
|
+
canonical: `el próximo ${weekday}`
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
phrase: `el proximo ${weekday}`,
|
|
51
|
+
day,
|
|
52
|
+
canonical: `el próximo ${weekday}`
|
|
53
|
+
}
|
|
54
|
+
]);
|
|
55
|
+
const spanishCountWords = [
|
|
56
|
+
["dos"],
|
|
57
|
+
["tres"],
|
|
58
|
+
["cuatro"],
|
|
59
|
+
["cinco"],
|
|
60
|
+
["seis"],
|
|
61
|
+
["siete"],
|
|
62
|
+
["ocho"],
|
|
63
|
+
["nueve"],
|
|
64
|
+
["diez"],
|
|
65
|
+
["once"],
|
|
66
|
+
["doce"],
|
|
67
|
+
["trece"],
|
|
68
|
+
["catorce"],
|
|
69
|
+
["quince"],
|
|
70
|
+
["dieciséis", "dieciseis"],
|
|
71
|
+
["diecisiete"],
|
|
72
|
+
["dieciocho"],
|
|
73
|
+
["diecinueve"],
|
|
74
|
+
["veinte"]
|
|
75
|
+
];
|
|
76
|
+
const spanishCountOnes = [
|
|
77
|
+
[1, "uno"],
|
|
78
|
+
[2, "dos"],
|
|
79
|
+
[3, "tres"],
|
|
80
|
+
[4, "cuatro"],
|
|
81
|
+
[5, "cinco"],
|
|
82
|
+
[6, "seis"],
|
|
83
|
+
[7, "siete"],
|
|
84
|
+
[8, "ocho"],
|
|
85
|
+
[9, "nueve"]
|
|
86
|
+
];
|
|
87
|
+
const spanishCountAliases = [...sequentialCountAliases(spanishCountWords, 2), ...compoundCountAliases(decimalTens([
|
|
88
|
+
"veinte",
|
|
89
|
+
"treinta",
|
|
90
|
+
"cuarenta",
|
|
91
|
+
"cincuenta",
|
|
92
|
+
"sesenta",
|
|
93
|
+
"setenta",
|
|
94
|
+
"ochenta",
|
|
95
|
+
"noventa"
|
|
96
|
+
]), spanishCountOnes, (ten, one, amount) => {
|
|
97
|
+
if (amount === 21) return [
|
|
98
|
+
"veintiuno",
|
|
99
|
+
"veintiún",
|
|
100
|
+
"veintiun",
|
|
101
|
+
"veintiuna"
|
|
102
|
+
];
|
|
103
|
+
if (amount === 22) return ["veintidós", "veintidos"];
|
|
104
|
+
if (amount === 23) return ["veintitrés", "veintitres"];
|
|
105
|
+
if (amount === 26) return ["veintiséis", "veintiseis"];
|
|
106
|
+
if (amount < 30) return [`veinti${one}`];
|
|
107
|
+
return (one === "uno" ? [
|
|
108
|
+
one,
|
|
109
|
+
"un",
|
|
110
|
+
"una"
|
|
111
|
+
] : [one]).map((variant) => `${ten} y ${variant}`);
|
|
112
|
+
})];
|
|
113
|
+
const normalizeSpanishCounts = compileCountAliasNormalizer(spanishCountAliases);
|
|
114
|
+
const spanishCountVocabulary = new Set(countAliasVocabulary(spanishCountAliases));
|
|
115
|
+
const correctSpanish = (input, vocabulary) => correctWhitespaceSeparatedText(input, vocabulary, spanishCountVocabulary);
|
|
116
|
+
const normalizeSpanish = (input, locale) => normalizeSpanishCounts(normalizeNaturalText(input, locale));
|
|
24
117
|
const monthAbbreviations = [
|
|
25
118
|
["ene"],
|
|
26
119
|
["feb"],
|
|
@@ -45,6 +138,7 @@ const units = [
|
|
|
45
138
|
unit: "day",
|
|
46
139
|
singular: "día",
|
|
47
140
|
plural: "días",
|
|
141
|
+
gender: "masculine",
|
|
48
142
|
current: "hoy",
|
|
49
143
|
previous: "ayer",
|
|
50
144
|
next: "mañana",
|
|
@@ -55,6 +149,7 @@ const units = [
|
|
|
55
149
|
unit: "week",
|
|
56
150
|
singular: "semana",
|
|
57
151
|
plural: "semanas",
|
|
152
|
+
gender: "feminine",
|
|
58
153
|
current: "esta semana",
|
|
59
154
|
previous: "la semana pasada",
|
|
60
155
|
next: "la próxima semana",
|
|
@@ -65,6 +160,7 @@ const units = [
|
|
|
65
160
|
unit: "month",
|
|
66
161
|
singular: "mes",
|
|
67
162
|
plural: "meses",
|
|
163
|
+
gender: "masculine",
|
|
68
164
|
current: "este mes",
|
|
69
165
|
previous: "el mes pasado",
|
|
70
166
|
next: "el próximo mes",
|
|
@@ -75,6 +171,7 @@ const units = [
|
|
|
75
171
|
unit: "quarter",
|
|
76
172
|
singular: "trimestre",
|
|
77
173
|
plural: "trimestres",
|
|
174
|
+
gender: "masculine",
|
|
78
175
|
current: "este trimestre",
|
|
79
176
|
previous: "el trimestre pasado",
|
|
80
177
|
next: "el próximo trimestre",
|
|
@@ -85,6 +182,7 @@ const units = [
|
|
|
85
182
|
unit: "year",
|
|
86
183
|
singular: "año",
|
|
87
184
|
plural: "años",
|
|
185
|
+
gender: "masculine",
|
|
88
186
|
current: "este año",
|
|
89
187
|
previous: "el año pasado",
|
|
90
188
|
next: "el próximo año",
|
|
@@ -92,21 +190,89 @@ const units = [
|
|
|
92
190
|
remaining: "resto del año"
|
|
93
191
|
}
|
|
94
192
|
];
|
|
95
|
-
const
|
|
193
|
+
const gendered = (entry, masculine, feminine) => entry.gender === "feminine" ? feminine : masculine;
|
|
194
|
+
const definiteArticle = (entry, plural = false) => gendered(entry, plural ? "los" : "el", plural ? "las" : "la");
|
|
195
|
+
const indefiniteArticle = (entry) => gendered(entry, "un", "una");
|
|
196
|
+
const withDe = (period) => period.startsWith("el ") ? `del ${period.slice(3)}` : `de ${period}`;
|
|
197
|
+
const afterDe = (period) => {
|
|
198
|
+
if (period.startsWith("del ")) return `el ${period.slice(4)}`;
|
|
199
|
+
return period.startsWith("de ") ? period.slice(3) : period;
|
|
200
|
+
};
|
|
201
|
+
const rollingAdjective = (entry, future, plural) => {
|
|
202
|
+
if (future) return gendered(entry, plural ? "próximos" : "próximo", plural ? "próximas" : "próxima");
|
|
203
|
+
return gendered(entry, plural ? "últimos" : "último", plural ? "últimas" : "última");
|
|
204
|
+
};
|
|
96
205
|
const unitAliases = [
|
|
97
|
-
[
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
[
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
[
|
|
108
|
-
|
|
109
|
-
|
|
206
|
+
[
|
|
207
|
+
"día",
|
|
208
|
+
"day",
|
|
209
|
+
false
|
|
210
|
+
],
|
|
211
|
+
[
|
|
212
|
+
"dia",
|
|
213
|
+
"day",
|
|
214
|
+
false
|
|
215
|
+
],
|
|
216
|
+
[
|
|
217
|
+
"días",
|
|
218
|
+
"day",
|
|
219
|
+
true
|
|
220
|
+
],
|
|
221
|
+
[
|
|
222
|
+
"dias",
|
|
223
|
+
"day",
|
|
224
|
+
true
|
|
225
|
+
],
|
|
226
|
+
[
|
|
227
|
+
"semana",
|
|
228
|
+
"week",
|
|
229
|
+
false
|
|
230
|
+
],
|
|
231
|
+
[
|
|
232
|
+
"semanas",
|
|
233
|
+
"week",
|
|
234
|
+
true
|
|
235
|
+
],
|
|
236
|
+
[
|
|
237
|
+
"mes",
|
|
238
|
+
"month",
|
|
239
|
+
false
|
|
240
|
+
],
|
|
241
|
+
[
|
|
242
|
+
"meses",
|
|
243
|
+
"month",
|
|
244
|
+
true
|
|
245
|
+
],
|
|
246
|
+
[
|
|
247
|
+
"trimestre",
|
|
248
|
+
"quarter",
|
|
249
|
+
false
|
|
250
|
+
],
|
|
251
|
+
[
|
|
252
|
+
"trimestres",
|
|
253
|
+
"quarter",
|
|
254
|
+
true
|
|
255
|
+
],
|
|
256
|
+
[
|
|
257
|
+
"año",
|
|
258
|
+
"year",
|
|
259
|
+
false
|
|
260
|
+
],
|
|
261
|
+
[
|
|
262
|
+
"ano",
|
|
263
|
+
"year",
|
|
264
|
+
false
|
|
265
|
+
],
|
|
266
|
+
[
|
|
267
|
+
"años",
|
|
268
|
+
"year",
|
|
269
|
+
true
|
|
270
|
+
],
|
|
271
|
+
[
|
|
272
|
+
"anos",
|
|
273
|
+
"year",
|
|
274
|
+
true
|
|
275
|
+
]
|
|
110
276
|
];
|
|
111
277
|
const periodAliases = [
|
|
112
278
|
...units.flatMap((entry) => [
|
|
@@ -129,6 +295,44 @@ const periodAliases = [
|
|
|
129
295
|
entry.next
|
|
130
296
|
]
|
|
131
297
|
]),
|
|
298
|
+
...units.filter((entry) => entry.unit !== "day").flatMap((entry) => [
|
|
299
|
+
[
|
|
300
|
+
`${entry.singular} actual`,
|
|
301
|
+
entry.unit,
|
|
302
|
+
0,
|
|
303
|
+
entry.current
|
|
304
|
+
],
|
|
305
|
+
[
|
|
306
|
+
`${definiteArticle(entry)} ${entry.singular} anterior`,
|
|
307
|
+
entry.unit,
|
|
308
|
+
-1,
|
|
309
|
+
entry.previous
|
|
310
|
+
],
|
|
311
|
+
[
|
|
312
|
+
`${entry.singular} anterior`,
|
|
313
|
+
entry.unit,
|
|
314
|
+
-1,
|
|
315
|
+
entry.previous
|
|
316
|
+
],
|
|
317
|
+
[
|
|
318
|
+
`${definiteArticle(entry)} ${entry.singular} siguiente`,
|
|
319
|
+
entry.unit,
|
|
320
|
+
1,
|
|
321
|
+
entry.next
|
|
322
|
+
],
|
|
323
|
+
[
|
|
324
|
+
`${entry.singular} siguiente`,
|
|
325
|
+
entry.unit,
|
|
326
|
+
1,
|
|
327
|
+
entry.next
|
|
328
|
+
],
|
|
329
|
+
[
|
|
330
|
+
`${rollingAdjective(entry, true, false)} ${entry.singular}`,
|
|
331
|
+
entry.unit,
|
|
332
|
+
1,
|
|
333
|
+
entry.next
|
|
334
|
+
]
|
|
335
|
+
]),
|
|
132
336
|
[
|
|
133
337
|
"semana pasada",
|
|
134
338
|
"week",
|
|
@@ -237,12 +441,36 @@ const periodAliases = [
|
|
|
237
441
|
-2,
|
|
238
442
|
"anteayer"
|
|
239
443
|
],
|
|
444
|
+
[
|
|
445
|
+
"día antes de ayer",
|
|
446
|
+
"day",
|
|
447
|
+
-2,
|
|
448
|
+
"anteayer"
|
|
449
|
+
],
|
|
450
|
+
[
|
|
451
|
+
"el día antes de ayer",
|
|
452
|
+
"day",
|
|
453
|
+
-2,
|
|
454
|
+
"anteayer"
|
|
455
|
+
],
|
|
240
456
|
[
|
|
241
457
|
"pasado mañana",
|
|
242
458
|
"day",
|
|
243
459
|
2,
|
|
244
460
|
"pasado mañana"
|
|
245
461
|
],
|
|
462
|
+
[
|
|
463
|
+
"día después de mañana",
|
|
464
|
+
"day",
|
|
465
|
+
2,
|
|
466
|
+
"pasado mañana"
|
|
467
|
+
],
|
|
468
|
+
[
|
|
469
|
+
"el día después de mañana",
|
|
470
|
+
"day",
|
|
471
|
+
2,
|
|
472
|
+
"pasado mañana"
|
|
473
|
+
],
|
|
246
474
|
[
|
|
247
475
|
"la semana anterior a la pasada",
|
|
248
476
|
"week",
|
|
@@ -327,17 +555,30 @@ const monthNumber = (value) => {
|
|
|
327
555
|
const short = monthAbbreviations.findIndex((aliases) => aliases.some((alias) => alias === normalized));
|
|
328
556
|
return short === -1 ? void 0 : short + 1;
|
|
329
557
|
};
|
|
558
|
+
const currentDateLabel = (day, month) => `${day} de ${textAt(months, month - 1)}`;
|
|
330
559
|
const parseNamedDate = (input) => {
|
|
331
|
-
const named = String$1.match(/^([0-3]?\d)(?: de)? ([a-záéíóúñ]+\.?)(?: de)? (\d{4})$/u)(input);
|
|
560
|
+
const named = String$1.match(/^(?:el (?:día )?)?([0-3]?\d)(?: de)? ([a-záéíóúñ]+\.?)(?:(?: de| del)? (\d{4}))$/u)(input);
|
|
332
561
|
if (Option.isSome(named)) return namedDatePeriod(textAt(named.value, 3), textAt(named.value, 2), textAt(named.value, 1), monthNumber, (day, month, year) => `${day} de ${textAt(months, month - 1)} de ${year}`);
|
|
333
562
|
const numeric = String$1.match(/^([0-3]?\d)[./-]([01]?\d)[./-](\d{4})$/u)(input);
|
|
334
|
-
if (Option.
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
563
|
+
if (Option.isSome(numeric)) {
|
|
564
|
+
const year = validYear(textAt(numeric.value, 3));
|
|
565
|
+
const month = Number(textAt(numeric.value, 2));
|
|
566
|
+
const day = Number(textAt(numeric.value, 1));
|
|
567
|
+
if (year !== void 0 && month >= 1 && month <= 12) {
|
|
568
|
+
const value = isoDate(year, month, day);
|
|
569
|
+
if (isIsoDate(value) && value !== "9999-12-31") return Option.some(fixedDatePeriod(value, `${day} de ${textAt(months, month - 1)} de ${year}`));
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
const current = String$1.match(/^(?:el (?:día )?)?([0-3]?\d)(?: de)? ([a-záéíóúñ]+\.?)$/u)(input);
|
|
573
|
+
if (Option.isSome(current)) return namedCurrentYearDatePeriod(textAt(current.value, 2), textAt(current.value, 1), monthNumber, currentDateLabel);
|
|
574
|
+
const relative = String$1.match(/^(?:el (?:día )?)?([0-3]?\d) (de .+|del .+)$/u)(input);
|
|
575
|
+
if (Option.isNone(relative)) return Option.none();
|
|
576
|
+
const periodText = afterDe(textAt(relative.value, 2));
|
|
577
|
+
const alias = periodAliases.find((entry) => entry[0] === periodText && entry[1] === "month");
|
|
578
|
+
if (alias === void 0) return Option.none();
|
|
579
|
+
const day = Number(textAt(relative.value, 1));
|
|
580
|
+
const month = relativePeriod(alias[1], alias[2], alias[3]);
|
|
581
|
+
return periodDay(month, day, `${day} ${withDe(alias[3])}`);
|
|
341
582
|
};
|
|
342
583
|
const quarterNumber = (value) => {
|
|
343
584
|
if ((value.startsWith("q") || value.startsWith("t")) && value.length === 2) return Number(value.slice(1));
|
|
@@ -365,12 +606,13 @@ const parseQuarter = (input) => {
|
|
|
365
606
|
const quarter = quarterNumber(textAt(standalone.value, 1));
|
|
366
607
|
return quarter === void 0 ? Option.none() : Option.some(quarterOfRelativeYear(quarter, 0, `T${quarter}`));
|
|
367
608
|
};
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
609
|
+
const parseDatedPeriod = (input) => {
|
|
610
|
+
const knownPeriod = Option.firstSomeOf([
|
|
611
|
+
absoluteDatePeriod(input, "es"),
|
|
612
|
+
parseNamedDate(input),
|
|
613
|
+
parseQuarter(input)
|
|
614
|
+
]);
|
|
615
|
+
if (Option.isSome(knownPeriod)) return knownPeriod;
|
|
374
616
|
const yearMatch = String$1.match(/^(?:(?:el )?año )?(\d{4})$/u)(input);
|
|
375
617
|
if (Option.isSome(yearMatch)) {
|
|
376
618
|
const year = validYear(textAt(yearMatch.value, 1));
|
|
@@ -380,7 +622,27 @@ const parseBasePeriod = (input) => {
|
|
|
380
622
|
if (Option.isSome(monthYear)) {
|
|
381
623
|
const month = monthNumber(textAt(monthYear.value, 1));
|
|
382
624
|
const year = validYear(textAt(monthYear.value, 2));
|
|
383
|
-
if (month !== void 0 && year !== void 0) return Option.some(fixedMonthPeriod(year, month, `${
|
|
625
|
+
if (month !== void 0 && year !== void 0) return Option.some(fixedMonthPeriod(year, month, `${textAt(months, month - 1)} de ${year}`));
|
|
626
|
+
}
|
|
627
|
+
return Option.none();
|
|
628
|
+
};
|
|
629
|
+
const parseBasePeriod = (input) => {
|
|
630
|
+
const datedPeriod = parseDatedPeriod(input);
|
|
631
|
+
if (Option.isSome(datedPeriod)) return datedPeriod;
|
|
632
|
+
const prefixedRelativeMonth = String$1.match(/^(pasado|próximo|proximo|este) ([a-záéíóúñ]+\.?)$/u)(input);
|
|
633
|
+
const suffixedRelativeMonth = String$1.match(/^([a-záéíóúñ]+\.?) (pasado|próximo|proximo)$/u)(input);
|
|
634
|
+
const shortRelativeMonth = Option.firstSomeOf([prefixedRelativeMonth, suffixedRelativeMonth]);
|
|
635
|
+
if (Option.isSome(shortRelativeMonth)) {
|
|
636
|
+
const prefixed = Option.isSome(prefixedRelativeMonth);
|
|
637
|
+
const month = monthNumber(textAt(shortRelativeMonth.value, prefixed ? 2 : 1));
|
|
638
|
+
if (month !== void 0) {
|
|
639
|
+
const modifier = textAt(shortRelativeMonth.value, prefixed ? 1 : 2);
|
|
640
|
+
const direction = relativeYearDirection(modifier);
|
|
641
|
+
let canonicalModifier = "este";
|
|
642
|
+
if (direction < 0) canonicalModifier = "pasado";
|
|
643
|
+
if (direction > 0) canonicalModifier = "próximo";
|
|
644
|
+
return Option.some(monthOfRelativeYear(month, direction, `${canonicalModifier} ${textAt(months, month - 1)}`));
|
|
645
|
+
}
|
|
384
646
|
}
|
|
385
647
|
const relativeMonth = String$1.match(/^([a-záéíóúñ]+\.?) (del año pasado|del ano pasado|del próximo año|del proximo año|de este año|de este ano)$/u)(input);
|
|
386
648
|
if (Option.isSome(relativeMonth)) {
|
|
@@ -389,11 +651,11 @@ const parseBasePeriod = (input) => {
|
|
|
389
651
|
const direction = relativeYearDirection(yearText);
|
|
390
652
|
if (month !== void 0) {
|
|
391
653
|
const canonicalYear = relativeYearName(direction);
|
|
392
|
-
return Option.some(monthOfRelativeYear(month, direction, `${
|
|
654
|
+
return Option.some(monthOfRelativeYear(month, direction, `${textAt(months, month - 1)} del ${canonicalYear}`));
|
|
393
655
|
}
|
|
394
656
|
}
|
|
395
657
|
const standaloneMonth = monthNumber(input);
|
|
396
|
-
if (standaloneMonth !== void 0) return Option.some(monthOfRelativeYear(standaloneMonth, 0,
|
|
658
|
+
if (standaloneMonth !== void 0) return Option.some(monthOfRelativeYear(standaloneMonth, 0, textAt(months, standaloneMonth - 1)));
|
|
397
659
|
const alias = periodAliases.find((entry) => entry[0] === input);
|
|
398
660
|
if (alias !== void 0) return Option.some(relativePeriod(alias[1], alias[2], alias[3]));
|
|
399
661
|
if ([
|
|
@@ -405,16 +667,34 @@ const parseBasePeriod = (input) => {
|
|
|
405
667
|
if (["el próximo fin de semana", "el proximo fin de semana"].includes(input)) return Option.some(relativeWeekend(1, "el próximo fin de semana"));
|
|
406
668
|
if (input === "el fin de semana anterior al pasado") return Option.some(relativeWeekend(-2, input));
|
|
407
669
|
if (input === "el fin de semana después del próximo") return Option.some(relativeWeekend(2, input));
|
|
408
|
-
|
|
670
|
+
const weekday = nextWeekdays.find((entry) => entry.phrase === input);
|
|
671
|
+
return weekday === void 0 ? Option.none() : Option.some(relativeWeekday(weekday.day, 1, weekday.canonical));
|
|
409
672
|
};
|
|
410
673
|
const parsePeriod = (input) => {
|
|
674
|
+
const shifted = String$1.match(/^(.+) (hace|dentro de|en) ([1-9]\d*) (día|dia|días|dias|semana|semanas|mes|meses|trimestre|trimestres|año|años|ano|anos)$/u)(input);
|
|
675
|
+
if (Option.isSome(shifted)) {
|
|
676
|
+
const amount = parseTrailingCount(textAt(shifted.value, 3));
|
|
677
|
+
const alias = unitAliases.find((unit) => unit[0] === textAt(shifted.value, 4));
|
|
678
|
+
const entry = alias === void 0 ? void 0 : units.find((unit) => unit.unit === alias[1]);
|
|
679
|
+
const period = parsePeriod(textAt(shifted.value, 1));
|
|
680
|
+
if (Option.isSome(amount) && entry !== void 0 && Option.isSome(period)) {
|
|
681
|
+
const past = textAt(shifted.value, 2) === "hace";
|
|
682
|
+
const direction = past ? -amount.value : amount.value;
|
|
683
|
+
const noun = amount.value === 1 ? entry.singular : entry.plural;
|
|
684
|
+
const canonical = `${period.value.canonical} ${past ? "hace" : "dentro de"} ${amount.value} ${noun}`;
|
|
685
|
+
return Option.some(shiftPeriod(period.value, direction, entry.unit, canonical));
|
|
686
|
+
}
|
|
687
|
+
}
|
|
411
688
|
const edge = String$1.match(/^(?:el )?(inicio|comienzo|principio|fin|final)(?: de| del) (.+)$/u)(input);
|
|
412
689
|
if (Option.isSome(edge)) {
|
|
413
690
|
const edgeName = textAt(edge.value, 1);
|
|
414
|
-
const
|
|
691
|
+
const periodText = textAt(edge.value, 2);
|
|
692
|
+
const basePeriod = parseBasePeriod(periodText);
|
|
693
|
+
const implicit = units.find((entry) => entry.singular === periodText);
|
|
694
|
+
const period = Option.isSome(basePeriod) || implicit === void 0 ? basePeriod : Option.some(relativePeriod(implicit.unit, 0, implicit.current));
|
|
415
695
|
if (Option.isSome(period)) {
|
|
416
696
|
const isEnd = edgeName === "fin" || edgeName === "final";
|
|
417
|
-
const canonical = `${isEnd ? "final" : "inicio"}
|
|
697
|
+
const canonical = `${isEnd ? "final" : "inicio"} ${withDe(period.value.canonical)}`;
|
|
418
698
|
return Option.some(isEnd ? periodEndDay(period.value, canonical) : periodStartDay(period.value, canonical));
|
|
419
699
|
}
|
|
420
700
|
}
|
|
@@ -425,45 +705,120 @@ const parsePeriod = (input) => {
|
|
|
425
705
|
"todo el ",
|
|
426
706
|
"toda la "
|
|
427
707
|
].find((prefix) => input.startsWith(prefix));
|
|
428
|
-
|
|
708
|
+
const base = parseBasePeriod(wrapper === void 0 ? input : input.slice(wrapper.length));
|
|
709
|
+
return Option.isSome(base) ? base : parseCalendarOffset(input);
|
|
710
|
+
};
|
|
711
|
+
const countedUnit = (value, amount) => {
|
|
712
|
+
const alias = unitAliases.find((entry) => entry[0] === value && entry[2] === (amount !== 1));
|
|
713
|
+
return alias === void 0 ? void 0 : units.find((entry) => entry.unit === alias[1]);
|
|
714
|
+
};
|
|
715
|
+
const writtenAmount = (value) => value === "un" || value === "una" ? Option.some(1) : parseTrailingCount(value);
|
|
716
|
+
const agreesWithArticle = (entry, article, plural = false) => article.length === 0 || article === definiteArticle(entry, plural);
|
|
717
|
+
const agreesWithIndefiniteArticle = (entry, article) => article === indefiniteArticle(entry);
|
|
718
|
+
const withoutAcute = (value) => value.normalize("NFD").replaceAll("́", "");
|
|
719
|
+
const agreesWithRollingModifier = (entry, modifier, future) => {
|
|
720
|
+
if (modifier === "anteriores" || modifier === "siguientes") return true;
|
|
721
|
+
if (!future && modifier === gendered(entry, "pasados", "pasadas")) return true;
|
|
722
|
+
const expected = rollingAdjective(entry, future, true);
|
|
723
|
+
return modifier === expected || modifier === withoutAcute(expected);
|
|
724
|
+
};
|
|
725
|
+
const agreesWithSingularModifier = (entry, modifier, future) => {
|
|
726
|
+
if (entry === void 0) return false;
|
|
727
|
+
if (future && modifier === "siguiente") return true;
|
|
728
|
+
const expected = rollingAdjective(entry, future, false);
|
|
729
|
+
return modifier === expected || modifier === withoutAcute(expected);
|
|
429
730
|
};
|
|
430
|
-
const countedUnit = (value) => unitAliases.find((entry) => entry[0] === value)?.[1];
|
|
431
731
|
const parseCalendarOffset = (input) => {
|
|
432
|
-
const
|
|
433
|
-
const future = String$1.match(/^(?:dentro de|en) ([1-9]\d*) (día|días|dias|semana|semanas|mes|meses|trimestre|trimestres|año|años|ano|anos)$/u)(input);
|
|
434
|
-
const match = Option.firstSomeOf([past, future]);
|
|
732
|
+
const match = String$1.match(/^(hace|dentro de|en) ([1-9]\d*|un|una) (día|dia|días|dias|semana|semanas|mes|meses|trimestre|trimestres|año|años|ano|anos)$/u)(input);
|
|
435
733
|
if (Option.isNone(match)) return Option.none();
|
|
436
|
-
const amount =
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
const
|
|
440
|
-
if (entry === void 0) return Option.none();
|
|
441
|
-
const
|
|
442
|
-
const
|
|
443
|
-
|
|
734
|
+
const amount = writtenAmount(textAt(match.value, 2));
|
|
735
|
+
if (Option.isNone(amount)) return Option.none();
|
|
736
|
+
const entry = countedUnit(textAt(match.value, 3), amount.value);
|
|
737
|
+
const amountText = textAt(match.value, 2);
|
|
738
|
+
if (entry === void 0 || (amountText === "un" || amountText === "una") && !agreesWithIndefiniteArticle(entry, amountText)) return Option.none();
|
|
739
|
+
const isPast = textAt(match.value, 1) === "hace";
|
|
740
|
+
const quantity = amount.value === 1 ? indefiniteArticle(entry) : String(amount.value);
|
|
741
|
+
const noun = amount.value === 1 ? entry.singular : entry.plural;
|
|
742
|
+
const canonical = `${isPast ? "hace" : "dentro de"} ${quantity} ${noun}`;
|
|
743
|
+
const direction = isPast ? -amount.value : amount.value;
|
|
744
|
+
return Option.some(relativePeriod(entry.unit, direction, canonical));
|
|
444
745
|
};
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
const
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
746
|
+
const rollingCanonical = (entry, amount, future) => {
|
|
747
|
+
if (amount > 1) return `${rollingAdjective(entry, future, true)} ${amount} ${entry.plural}`;
|
|
748
|
+
const article = indefiniteArticle(entry);
|
|
749
|
+
return future ? `desde ahora durante ${article} ${entry.singular}` : `desde hace ${article} ${entry.singular}`;
|
|
750
|
+
};
|
|
751
|
+
const rollingCandidate = (entry, amount, future) => candidate(future ? futureRange(amount, entry.unit) : trailingRange(amount, entry.unit), rollingCanonical(entry, amount, future));
|
|
752
|
+
const parseRollingSince = (input) => {
|
|
753
|
+
const since = String$1.match(/^desde hace ([1-9]\d*|un|una) (día|dia|días|dias|semana|semanas|mes|meses|trimestre|trimestres|año|años|ano|anos)$/u)(input);
|
|
754
|
+
if (Option.isSome(since)) {
|
|
755
|
+
const amount = writtenAmount(textAt(since.value, 1));
|
|
756
|
+
if (Option.isSome(amount)) {
|
|
757
|
+
const entry = countedUnit(textAt(since.value, 2), amount.value);
|
|
758
|
+
const amountText = textAt(since.value, 1);
|
|
759
|
+
if (entry !== void 0 && (amountText !== "un" && amountText !== "una" || agreesWithIndefiniteArticle(entry, amountText))) return Option.some(rollingCandidate(entry, amount.value, false));
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
return Option.none();
|
|
763
|
+
};
|
|
764
|
+
const parseSingularRolling = (input) => {
|
|
765
|
+
const futureSingular = String$1.match(/^desde ahora durante (un|una) (día|dia|semana|mes|trimestre|año|ano)$/u)(input);
|
|
766
|
+
if (Option.isSome(futureSingular)) {
|
|
767
|
+
const entry = countedUnit(textAt(futureSingular.value, 2), 1);
|
|
768
|
+
if (entry !== void 0 && agreesWithIndefiniteArticle(entry, textAt(futureSingular.value, 1))) return Option.some(rollingCandidate(entry, 1, true));
|
|
769
|
+
}
|
|
770
|
+
const lastSingular = String$1.match(/^(?:(?:durante|en) )?(?:este )?(?:(el|la) )?(último|ultimo|última|ultima) (día|dia|semana|mes|trimestre|año|ano)$/u)(input);
|
|
771
|
+
if (Option.isSome(lastSingular)) {
|
|
772
|
+
const entry = countedUnit(textAt(lastSingular.value, 3), 1);
|
|
773
|
+
const modifier = textAt(lastSingular.value, 2);
|
|
774
|
+
if (entry !== void 0 && agreesWithArticle(entry, textAt(lastSingular.value, 1)) && agreesWithSingularModifier(entry, modifier, false)) return Option.some(rollingCandidate(entry, 1, false));
|
|
775
|
+
}
|
|
776
|
+
const nextSingular = String$1.match(/^durante (el|la) (próximo|proximo|próxima|proxima|siguiente) (día|dia|semana|mes|trimestre|año|ano)$/u)(input);
|
|
777
|
+
if (Option.isSome(nextSingular)) {
|
|
778
|
+
const entry = countedUnit(textAt(nextSingular.value, 3), 1);
|
|
779
|
+
const modifier = textAt(nextSingular.value, 2);
|
|
780
|
+
if (entry !== void 0 && agreesWithArticle(entry, textAt(nextSingular.value, 1)) && agreesWithSingularModifier(entry, modifier, true)) return Option.some(rollingCandidate(entry, 1, true));
|
|
781
|
+
}
|
|
782
|
+
return Option.none();
|
|
783
|
+
};
|
|
784
|
+
const parseCountedRolling = (input) => {
|
|
785
|
+
const counted = String$1.match(/^(?:(?:durante|en) )?(?:(los|las) )?(últimos|ultimos|últimas|ultimas|pasados|pasadas|anteriores|próximos|proximos|próximas|proximas|siguientes) ([1-9]\d*) (día|dia|días|dias|semana|semanas|mes|meses|trimestre|trimestres|año|años|ano|anos)$/u)(input);
|
|
786
|
+
if (Option.isSome(counted)) {
|
|
787
|
+
const amount = parseTrailingCount(textAt(counted.value, 3));
|
|
788
|
+
if (Option.isSome(amount) && amount.value > 1) {
|
|
789
|
+
const entry = countedUnit(textAt(counted.value, 4), amount.value);
|
|
790
|
+
const modifier = textAt(counted.value, 2);
|
|
791
|
+
const future = modifier.startsWith("próxim") || modifier.startsWith("proxim") || modifier === "siguientes";
|
|
792
|
+
if (entry !== void 0 && agreesWithArticle(entry, textAt(counted.value, 1), true) && agreesWithRollingModifier(entry, modifier, future)) return Option.some(rollingCandidate(entry, amount.value, future));
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
const bare = String$1.match(/^([1-9]\d*) (día|dia|días|dias|semana|semanas|mes|meses|trimestre|trimestres|año|años|ano|anos)$/u)(input);
|
|
796
|
+
if (Option.isNone(bare)) return Option.none();
|
|
797
|
+
const amount = parseTrailingCount(textAt(bare.value, 1));
|
|
798
|
+
if (Option.isNone(amount)) return Option.none();
|
|
799
|
+
const entry = countedUnit(textAt(bare.value, 2), amount.value);
|
|
800
|
+
return entry === void 0 ? Option.none() : Option.some(rollingCandidate(entry, amount.value, false));
|
|
801
|
+
};
|
|
802
|
+
const parseRollingPeriod = (input) => Option.firstSomeOf([
|
|
803
|
+
parseRollingSince(input),
|
|
804
|
+
parseSingularRolling(input),
|
|
805
|
+
parseCountedRolling(input)
|
|
806
|
+
]);
|
|
807
|
+
const parseElidedDateRange = (input) => {
|
|
808
|
+
const joined = String$1.match(/^(?:(?:del|desde(?: el)?) ([0-3]?\d) (?:al|hasta(?: el)?)|entre(?: el)? ([0-3]?\d) y(?: el)?) ([0-3]?\d) (.+)$/u)(input);
|
|
809
|
+
const dashed = String$1.match(/^([0-3]?\d)[–—-]([0-3]?\d) (.+)$/u)(input);
|
|
810
|
+
const match = Option.firstSomeOf([joined, dashed]);
|
|
456
811
|
if (Option.isNone(match)) return Option.none();
|
|
457
|
-
const
|
|
458
|
-
const
|
|
459
|
-
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
return Option.
|
|
812
|
+
const isJoined = Option.isSome(joined);
|
|
813
|
+
const lowerDay = textAt(match.value, 1) || textAt(match.value, 2);
|
|
814
|
+
const upperDay = textAt(match.value, isJoined ? 3 : 2);
|
|
815
|
+
const period = afterDe(textAt(match.value, isJoined ? 4 : 3));
|
|
816
|
+
return joinedPeriodCandidate(`desde ${lowerDay} ${withDe(period)} hasta ${upperDay} ${withDe(period)}`, [["desde ", " hasta "]], parsePeriod, (lower, upper) => `desde ${lower} hasta ${upper}`);
|
|
817
|
+
};
|
|
818
|
+
const inclusiveBoundaryCandidate = (input) => {
|
|
819
|
+
const match = String$1.match(/^hasta (.+) inclusive$/u)(input);
|
|
820
|
+
if (Option.isNone(match)) return Option.none();
|
|
821
|
+
return parsePeriod(textAt(match.value, 1)).pipe(Option.map((value) => periodBoundaryCandidate(value, "through", `hasta ${value.canonical} inclusive`)));
|
|
467
822
|
};
|
|
468
823
|
const boundaryCandidate = (input) => openBoundaryCandidate(input, [
|
|
469
824
|
["hasta antes de ", "before"],
|
|
@@ -486,12 +841,12 @@ const parseSpanish = (input) => {
|
|
|
486
841
|
"a partir de ahora",
|
|
487
842
|
"de ahora en adelante"
|
|
488
843
|
].includes(input)) return Option.some(candidate(fromNowRange(), "desde ahora"));
|
|
489
|
-
const offset = parseCalendarOffset(input);
|
|
490
|
-
if (Option.isSome(offset)) return offset;
|
|
491
844
|
const rolling = parseRollingPeriod(input);
|
|
492
845
|
if (Option.isSome(rolling)) return rolling;
|
|
493
846
|
const toDate = toDatePhrases.find((entry) => entry.phrase === input);
|
|
494
847
|
if (toDate !== void 0) return Option.some(candidate(periodToDateRange(toDate.entry.unit), toDate.entry.toDate));
|
|
848
|
+
const elided = parseElidedDateRange(input);
|
|
849
|
+
if (Option.isSome(elided)) return elided;
|
|
495
850
|
const nowBounded = joinedNowCandidate(input, [
|
|
496
851
|
["desde ", " hasta ahora"],
|
|
497
852
|
["desde ", " hasta hoy"],
|
|
@@ -499,12 +854,17 @@ const parseSpanish = (input) => {
|
|
|
499
854
|
], [
|
|
500
855
|
"desde ahora hasta ",
|
|
501
856
|
"desde hoy hasta ",
|
|
502
|
-
"entre hoy y "
|
|
857
|
+
"entre hoy y ",
|
|
858
|
+
"entre hoy y el ",
|
|
859
|
+
"ahora hasta "
|
|
503
860
|
], parsePeriod, (period) => `desde ${period} hasta ahora`, (period) => `desde ahora hasta ${period}`);
|
|
504
861
|
if (Option.isSome(nowBounded)) return nowBounded;
|
|
505
862
|
const bounded = joinedPeriodCandidate(input, [
|
|
863
|
+
["desde el ", " hasta el "],
|
|
506
864
|
["desde ", " hasta "],
|
|
865
|
+
["del ", " al "],
|
|
507
866
|
["de ", " a "],
|
|
867
|
+
["entre el ", " y el "],
|
|
508
868
|
["entre ", " y "],
|
|
509
869
|
["", " - "],
|
|
510
870
|
["", " – "],
|
|
@@ -512,18 +872,32 @@ const parseSpanish = (input) => {
|
|
|
512
872
|
["", " hasta "]
|
|
513
873
|
], parsePeriod, (lower, upper) => `desde ${lower} hasta ${upper}`);
|
|
514
874
|
if (Option.isSome(bounded)) return bounded;
|
|
875
|
+
const inclusive = inclusiveBoundaryCandidate(input);
|
|
876
|
+
if (Option.isSome(inclusive)) return inclusive;
|
|
515
877
|
const boundary = boundaryCandidate(input);
|
|
516
878
|
if (Option.isSome(boundary)) return boundary;
|
|
517
|
-
return Option.map(
|
|
879
|
+
return parsePeriod(input).pipe(Option.map((period) => candidate(periodRange(period), period.canonical)));
|
|
518
880
|
};
|
|
519
|
-
const
|
|
520
|
-
...periodAliases.map((entry) => entry[0]),
|
|
881
|
+
const weekendPhrases = [
|
|
521
882
|
"este fin de semana",
|
|
522
883
|
"el fin de semana pasado",
|
|
523
884
|
"el próximo fin de semana",
|
|
524
885
|
"el fin de semana anterior al pasado",
|
|
525
|
-
"el fin de semana después del próximo"
|
|
526
|
-
|
|
886
|
+
"el fin de semana después del próximo"
|
|
887
|
+
];
|
|
888
|
+
const edgePeriodPhrases = [
|
|
889
|
+
...units.filter((entry) => entry.unit !== "day").flatMap((entry) => [
|
|
890
|
+
entry.current,
|
|
891
|
+
entry.previous,
|
|
892
|
+
entry.next
|
|
893
|
+
]),
|
|
894
|
+
...weekendPhrases,
|
|
895
|
+
...months
|
|
896
|
+
].flatMap((period) => [`inicio ${withDe(period)}`, `final ${withDe(period)}`]);
|
|
897
|
+
const staticPeriodPhrases = [
|
|
898
|
+
...periodAliases.map((entry) => entry[0]),
|
|
899
|
+
...weekendPhrases,
|
|
900
|
+
...edgePeriodPhrases,
|
|
527
901
|
...[
|
|
528
902
|
1,
|
|
529
903
|
2,
|
|
@@ -537,13 +911,19 @@ const staticPeriodPhrases = [
|
|
|
537
911
|
]),
|
|
538
912
|
...months.flatMap((month) => [
|
|
539
913
|
month,
|
|
914
|
+
`pasado ${month}`,
|
|
915
|
+
`próximo ${month}`,
|
|
916
|
+
`${month} pasado`,
|
|
917
|
+
`${month} próximo`,
|
|
540
918
|
`${month} del año pasado`,
|
|
541
919
|
`${month} del próximo año`
|
|
542
|
-
])
|
|
920
|
+
]),
|
|
921
|
+
...nextWeekdays.map((entry) => entry.phrase)
|
|
543
922
|
];
|
|
544
923
|
const staticPeriods = periodsFromPhrases(staticPeriodPhrases, parsePeriod);
|
|
545
924
|
const boundaryPrefixes = [
|
|
546
925
|
"desde ",
|
|
926
|
+
"a partir de ",
|
|
547
927
|
"antes de ",
|
|
548
928
|
"hasta ",
|
|
549
929
|
"después de "
|
|
@@ -553,10 +933,21 @@ const countedSuggestions = (input) => {
|
|
|
553
933
|
if (amount === void 0) return [];
|
|
554
934
|
return units.flatMap((entry) => {
|
|
555
935
|
const noun = amount === 1 ? entry.singular : entry.plural;
|
|
936
|
+
if (amount === 1) {
|
|
937
|
+
const article = indefiniteArticle(entry);
|
|
938
|
+
return [
|
|
939
|
+
`${amount} ${noun}`,
|
|
940
|
+
`${rollingAdjective(entry, false, false)} ${noun}`,
|
|
941
|
+
`desde hace ${article} ${noun}`,
|
|
942
|
+
`desde ahora durante ${article} ${noun}`,
|
|
943
|
+
`hace ${article} ${noun}`,
|
|
944
|
+
`dentro de ${article} ${noun}`
|
|
945
|
+
];
|
|
946
|
+
}
|
|
556
947
|
return [
|
|
557
|
-
|
|
948
|
+
`${rollingAdjective(entry, false, true)} ${amount} ${noun}`,
|
|
558
949
|
`${amount} ${noun}`,
|
|
559
|
-
|
|
950
|
+
`${rollingAdjective(entry, true, true)} ${amount} ${noun}`,
|
|
560
951
|
`hace ${amount} ${noun}`,
|
|
561
952
|
`dentro de ${amount} ${noun}`
|
|
562
953
|
];
|
|
@@ -565,6 +956,12 @@ const countedSuggestions = (input) => {
|
|
|
565
956
|
const spanishSuggestionPhrases = [
|
|
566
957
|
...units.map((entry) => entry.toDate),
|
|
567
958
|
...units.map((entry) => entry.remaining),
|
|
959
|
+
...units.flatMap((entry) => [
|
|
960
|
+
`${rollingAdjective(entry, false, false)} ${entry.singular}`,
|
|
961
|
+
`desde hace ${indefiniteArticle(entry)} ${entry.singular}`,
|
|
962
|
+
`desde ahora durante ${indefiniteArticle(entry)} ${entry.singular}`,
|
|
963
|
+
`durante ${definiteArticle(entry)} ${rollingAdjective(entry, true, false)} ${entry.singular}`
|
|
964
|
+
]),
|
|
568
965
|
...staticPeriodPhrases,
|
|
569
966
|
...prefixNaturalPhrases(staticPeriodPhrases, boundaryPrefixes),
|
|
570
967
|
"hasta ahora",
|
|
@@ -580,6 +977,17 @@ const suggestSpanish = (input, limit) => {
|
|
|
580
977
|
], limit);
|
|
581
978
|
};
|
|
582
979
|
const renderSpanish = (range) => {
|
|
980
|
+
const shifted = decomposeShiftedPeriodRange(range);
|
|
981
|
+
if (Option.isSome(shifted)) {
|
|
982
|
+
const base = renderSpanish(shifted.value.baseRange);
|
|
983
|
+
const entry = units.find((unit) => unit.unit === shifted.value.unit);
|
|
984
|
+
if (Option.isSome(base) && entry !== void 0) {
|
|
985
|
+
const amount = Math.abs(shifted.value.amount);
|
|
986
|
+
const noun = amount === 1 ? entry.singular : entry.plural;
|
|
987
|
+
const direction = shifted.value.amount < 0 ? "hace" : "dentro de";
|
|
988
|
+
return Option.some(`${base.value} ${direction} ${amount} ${noun}`);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
583
991
|
const offset = calendarPeriodOffset(range);
|
|
584
992
|
if (Option.isSome(offset) && Math.abs(offset.value.amount) > 1) {
|
|
585
993
|
const entry = units.find((unit) => unit.unit === offset.value.unit);
|
|
@@ -592,26 +1000,25 @@ const renderSpanish = (range) => {
|
|
|
592
1000
|
const future = futurePeriod(range);
|
|
593
1001
|
if (Option.isSome(future)) {
|
|
594
1002
|
const entry = units.find((unit) => unit.unit === future.value.unit);
|
|
595
|
-
if (entry !== void 0)
|
|
596
|
-
const noun = future.value.amount === 1 ? entry.singular : entry.plural;
|
|
597
|
-
return Option.some(`próximos ${future.value.amount} ${noun}`);
|
|
598
|
-
}
|
|
1003
|
+
if (entry !== void 0) return Option.some(rollingCanonical(entry, future.value.amount, true));
|
|
599
1004
|
}
|
|
600
1005
|
const trailing = trailingPeriod(range);
|
|
601
1006
|
if (Option.isSome(trailing)) {
|
|
602
1007
|
const entry = units.find((unit) => unit.unit === trailing.value.unit);
|
|
603
|
-
if (entry !== void 0)
|
|
604
|
-
const noun = trailing.value.amount === 1 ? entry.singular : entry.plural;
|
|
605
|
-
return Option.some(`últimos ${trailing.value.amount} ${noun}`);
|
|
606
|
-
}
|
|
1008
|
+
if (entry !== void 0) return Option.some(rollingCanonical(entry, trailing.value.amount, false));
|
|
607
1009
|
}
|
|
608
|
-
const periods = [
|
|
1010
|
+
const periods = [
|
|
1011
|
+
...staticPeriods,
|
|
1012
|
+
...currentYearDatePeriods(range, currentDateLabel),
|
|
1013
|
+
...periodsFromPhrases([...datedPeriods(range, months), ...datedQuarterPeriods(range)], parsePeriod)
|
|
1014
|
+
];
|
|
609
1015
|
return renderPeriodRange(range, [...units.map((entry) => candidate(periodToDateRange(entry.unit), entry.toDate)), ...units.map((entry) => candidate(remainingPeriodRange(entry.unit), entry.remaining))], periods, (period) => `desde ${period}`, (period) => `antes de ${period}`, (period) => `hasta ${period}`, (period) => `después de ${period}`, (lower, upper) => `desde ${lower} hasta ${upper}`, (period) => `desde ${period} hasta ahora`, (period) => `desde ahora hasta ${period}`, () => "hasta ahora", () => "desde ahora");
|
|
610
1016
|
};
|
|
611
1017
|
const SpanishContribution = new BaseLanguageContribution({
|
|
612
1018
|
locale: "es",
|
|
613
1019
|
vocabulary: [
|
|
614
1020
|
...months,
|
|
1021
|
+
...weekdays,
|
|
615
1022
|
...monthAbbreviations.flatMap((aliases) => aliases),
|
|
616
1023
|
...units.flatMap((entry) => [
|
|
617
1024
|
entry.singular,
|
|
@@ -645,8 +1052,8 @@ const SpanishContribution = new BaseLanguageContribution({
|
|
|
645
1052
|
"resto",
|
|
646
1053
|
"últimos"
|
|
647
1054
|
],
|
|
648
|
-
normalize:
|
|
649
|
-
correct:
|
|
1055
|
+
normalize: normalizeSpanish,
|
|
1056
|
+
correct: correctSpanish,
|
|
650
1057
|
parseExact: parseSpanish,
|
|
651
1058
|
suggest: suggestSpanish,
|
|
652
1059
|
render: renderSpanish
|