chronolizer 0.3.0 → 0.4.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/README.md +50 -47
- package/dist/ast/fold.mjs +8 -10
- package/dist/ast/normalize.mjs +7 -16
- package/dist/filter/codec.mjs +5 -6
- package/dist/filter/expression.mjs +26 -21
- package/dist/language/model.mjs +1 -1
- package/dist/language/registry.mjs +34 -12
- package/dist/locales/cs.mjs +194 -36
- package/dist/locales/de.mjs +307 -490
- package/dist/locales/en.mjs +162 -46
- package/dist/locales/es.mjs +187 -37
- package/dist/locales/fr.mjs +168 -52
- package/dist/locales/nl.mjs +125 -37
- package/dist/locales/pl.mjs +163 -36
- package/dist/locales/shared.mjs +68 -5
- package/dist/locales/tr.mjs +144 -42
- package/dist/natural/correction.d.mts +1 -1
- package/dist/natural/correction.mjs +97 -28
- package/dist/natural/format.mjs +1 -1
- package/dist/natural/parse.mjs +6 -5
- package/dist/natural/suggest.mjs +27 -3
- package/dist/natural/suggestion.mjs +50 -26
- package/dist/resolve/resolve.mjs +2 -3
- package/package.json +2 -1
package/dist/locales/es.mjs
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { isIsoDate } from "../ast/schemas.mjs";
|
|
2
1
|
import { BaseLanguageContribution } from "../language/model.mjs";
|
|
3
2
|
import { normalizeNaturalText } from "../natural/text.mjs";
|
|
4
3
|
import { defineLanguagePlugin, languagePluginsLayer } from "../language/registry.mjs";
|
|
5
4
|
import { correctWhitespaceSeparatedText } from "../natural/correction.mjs";
|
|
6
5
|
import { completeNaturalPhrases, fixedCalendarPeriodPhrases, naturalCount, prefixNaturalPhrases } from "../natural/suggestion.mjs";
|
|
7
|
-
import { absoluteDatePeriod, calendarPeriodOffset, candidate, currentYearDatePeriods, datedPeriods, datedQuarterPeriods,
|
|
6
|
+
import { absoluteDatePeriod, calendarPeriodOffset, candidate, compileCountAliasNormalizer, compoundCountAliases, countAliasVocabulary, currentYearDatePeriods, datedPeriods, datedQuarterPeriods, decimalTens, decomposeShiftedPeriodRange, fixedMonthPeriod, fixedQuarterPeriod, fixedYearPeriod, fromNowRange, futurePeriod, futureRange, 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
7
|
import { Effect, Option, String as String$1 } from "effect";
|
|
9
8
|
//#region src/locales/es.ts
|
|
10
9
|
const months = [
|
|
@@ -21,6 +20,99 @@ const months = [
|
|
|
21
20
|
"noviembre",
|
|
22
21
|
"diciembre"
|
|
23
22
|
];
|
|
23
|
+
const weekdays = [
|
|
24
|
+
"lunes",
|
|
25
|
+
"martes",
|
|
26
|
+
"miércoles",
|
|
27
|
+
"jueves",
|
|
28
|
+
"viernes",
|
|
29
|
+
"sábado",
|
|
30
|
+
"domingo"
|
|
31
|
+
];
|
|
32
|
+
const nextWeekdays = weekdays.flatMap((weekday, day) => [
|
|
33
|
+
{
|
|
34
|
+
phrase: `próximo ${weekday}`,
|
|
35
|
+
day,
|
|
36
|
+
canonical: `el próximo ${weekday}`
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
phrase: `el próximo ${weekday}`,
|
|
40
|
+
day,
|
|
41
|
+
canonical: `el próximo ${weekday}`
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
phrase: `proximo ${weekday}`,
|
|
45
|
+
day,
|
|
46
|
+
canonical: `el próximo ${weekday}`
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
phrase: `el proximo ${weekday}`,
|
|
50
|
+
day,
|
|
51
|
+
canonical: `el próximo ${weekday}`
|
|
52
|
+
}
|
|
53
|
+
]);
|
|
54
|
+
const spanishCountWords = [
|
|
55
|
+
["dos"],
|
|
56
|
+
["tres"],
|
|
57
|
+
["cuatro"],
|
|
58
|
+
["cinco"],
|
|
59
|
+
["seis"],
|
|
60
|
+
["siete"],
|
|
61
|
+
["ocho"],
|
|
62
|
+
["nueve"],
|
|
63
|
+
["diez"],
|
|
64
|
+
["once"],
|
|
65
|
+
["doce"],
|
|
66
|
+
["trece"],
|
|
67
|
+
["catorce"],
|
|
68
|
+
["quince"],
|
|
69
|
+
["dieciséis", "dieciseis"],
|
|
70
|
+
["diecisiete"],
|
|
71
|
+
["dieciocho"],
|
|
72
|
+
["diecinueve"],
|
|
73
|
+
["veinte"]
|
|
74
|
+
];
|
|
75
|
+
const spanishCountOnes = [
|
|
76
|
+
[1, "uno"],
|
|
77
|
+
[2, "dos"],
|
|
78
|
+
[3, "tres"],
|
|
79
|
+
[4, "cuatro"],
|
|
80
|
+
[5, "cinco"],
|
|
81
|
+
[6, "seis"],
|
|
82
|
+
[7, "siete"],
|
|
83
|
+
[8, "ocho"],
|
|
84
|
+
[9, "nueve"]
|
|
85
|
+
];
|
|
86
|
+
const spanishCountAliases = [...sequentialCountAliases(spanishCountWords, 2), ...compoundCountAliases(decimalTens([
|
|
87
|
+
"veinte",
|
|
88
|
+
"treinta",
|
|
89
|
+
"cuarenta",
|
|
90
|
+
"cincuenta",
|
|
91
|
+
"sesenta",
|
|
92
|
+
"setenta",
|
|
93
|
+
"ochenta",
|
|
94
|
+
"noventa"
|
|
95
|
+
]), spanishCountOnes, (ten, one, amount) => {
|
|
96
|
+
if (amount === 21) return [
|
|
97
|
+
"veintiuno",
|
|
98
|
+
"veintiún",
|
|
99
|
+
"veintiun",
|
|
100
|
+
"veintiuna"
|
|
101
|
+
];
|
|
102
|
+
if (amount === 22) return ["veintidós", "veintidos"];
|
|
103
|
+
if (amount === 23) return ["veintitrés", "veintitres"];
|
|
104
|
+
if (amount === 26) return ["veintiséis", "veintiseis"];
|
|
105
|
+
if (amount < 30) return [`veinti${one}`];
|
|
106
|
+
return (one === "uno" ? [
|
|
107
|
+
one,
|
|
108
|
+
"un",
|
|
109
|
+
"una"
|
|
110
|
+
] : [one]).map((variant) => `${ten} y ${variant}`);
|
|
111
|
+
})];
|
|
112
|
+
const normalizeSpanishCounts = compileCountAliasNormalizer(spanishCountAliases);
|
|
113
|
+
const spanishCountVocabulary = new Set(countAliasVocabulary(spanishCountAliases));
|
|
114
|
+
const correctSpanish = (input, vocabulary) => correctWhitespaceSeparatedText(input, vocabulary, spanishCountVocabulary);
|
|
115
|
+
const normalizeSpanish = (input, locale) => normalizeSpanishCounts(normalizeNaturalText(input, locale));
|
|
24
116
|
const monthAbbreviations = [
|
|
25
117
|
["ene"],
|
|
26
118
|
["feb"],
|
|
@@ -467,15 +559,7 @@ const parseNamedDate = (input) => {
|
|
|
467
559
|
const named = String$1.match(/^(?:el (?:día )?)?([0-3]?\d)(?: de)? ([a-záéíóúñ]+\.?)(?:(?: de| del)? (\d{4}))$/u)(input);
|
|
468
560
|
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}`);
|
|
469
561
|
const numeric = String$1.match(/^([0-3]?\d)[./-]([01]?\d)[./-](\d{4})$/u)(input);
|
|
470
|
-
if (Option.isSome(numeric)) {
|
|
471
|
-
const year = validYear(textAt(numeric.value, 3));
|
|
472
|
-
const month = Number(textAt(numeric.value, 2));
|
|
473
|
-
const day = Number(textAt(numeric.value, 1));
|
|
474
|
-
if (year !== void 0 && month >= 1 && month <= 12) {
|
|
475
|
-
const value = isoDate(year, month, day);
|
|
476
|
-
if (isIsoDate(value) && value !== "9999-12-31") return Option.some(fixedDatePeriod(value, `${day} de ${textAt(months, month - 1)} de ${year}`));
|
|
477
|
-
}
|
|
478
|
-
}
|
|
562
|
+
if (Option.isSome(numeric)) return namedDatePeriod(textAt(numeric.value, 3), textAt(numeric.value, 2), textAt(numeric.value, 1), Number, (day, month, year) => `${day} de ${textAt(months, month - 1)} de ${year}`);
|
|
479
563
|
const current = String$1.match(/^(?:el (?:día )?)?([0-3]?\d)(?: de)? ([a-záéíóúñ]+\.?)$/u)(input);
|
|
480
564
|
if (Option.isSome(current)) return namedCurrentYearDatePeriod(textAt(current.value, 2), textAt(current.value, 1), monthNumber, currentDateLabel);
|
|
481
565
|
const relative = String$1.match(/^(?:el (?:día )?)?([0-3]?\d) (de .+|del .+)$/u)(input);
|
|
@@ -513,13 +597,13 @@ const parseQuarter = (input) => {
|
|
|
513
597
|
const quarter = quarterNumber(textAt(standalone.value, 1));
|
|
514
598
|
return quarter === void 0 ? Option.none() : Option.some(quarterOfRelativeYear(quarter, 0, `T${quarter}`));
|
|
515
599
|
};
|
|
516
|
-
const
|
|
517
|
-
const
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
if (Option.isSome(
|
|
600
|
+
const parseDatedPeriod = (input) => {
|
|
601
|
+
const knownPeriod = Option.firstSomeOf([
|
|
602
|
+
absoluteDatePeriod(input, "es"),
|
|
603
|
+
parseNamedDate(input),
|
|
604
|
+
parseQuarter(input)
|
|
605
|
+
]);
|
|
606
|
+
if (Option.isSome(knownPeriod)) return knownPeriod;
|
|
523
607
|
const yearMatch = String$1.match(/^(?:(?:el )?año )?(\d{4})$/u)(input);
|
|
524
608
|
if (Option.isSome(yearMatch)) {
|
|
525
609
|
const year = validYear(textAt(yearMatch.value, 1));
|
|
@@ -531,6 +615,26 @@ const parseBasePeriod = (input) => {
|
|
|
531
615
|
const year = validYear(textAt(monthYear.value, 2));
|
|
532
616
|
if (month !== void 0 && year !== void 0) return Option.some(fixedMonthPeriod(year, month, `${textAt(months, month - 1)} de ${year}`));
|
|
533
617
|
}
|
|
618
|
+
return Option.none();
|
|
619
|
+
};
|
|
620
|
+
const parseBasePeriod = (input) => {
|
|
621
|
+
const datedPeriod = parseDatedPeriod(input);
|
|
622
|
+
if (Option.isSome(datedPeriod)) return datedPeriod;
|
|
623
|
+
const prefixedRelativeMonth = String$1.match(/^(pasado|próximo|proximo|este) ([a-záéíóúñ]+\.?)$/u)(input);
|
|
624
|
+
const suffixedRelativeMonth = String$1.match(/^([a-záéíóúñ]+\.?) (pasado|próximo|proximo)$/u)(input);
|
|
625
|
+
const shortRelativeMonth = Option.firstSomeOf([prefixedRelativeMonth, suffixedRelativeMonth]);
|
|
626
|
+
if (Option.isSome(shortRelativeMonth)) {
|
|
627
|
+
const prefixed = Option.isSome(prefixedRelativeMonth);
|
|
628
|
+
const month = monthNumber(textAt(shortRelativeMonth.value, prefixed ? 2 : 1));
|
|
629
|
+
if (month !== void 0) {
|
|
630
|
+
const modifier = textAt(shortRelativeMonth.value, prefixed ? 1 : 2);
|
|
631
|
+
const direction = relativeYearDirection(modifier);
|
|
632
|
+
let canonicalModifier = "este";
|
|
633
|
+
if (direction < 0) canonicalModifier = "pasado";
|
|
634
|
+
if (direction > 0) canonicalModifier = "próximo";
|
|
635
|
+
return Option.some(monthOfRelativeYear(month, direction, `${canonicalModifier} ${textAt(months, month - 1)}`));
|
|
636
|
+
}
|
|
637
|
+
}
|
|
534
638
|
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);
|
|
535
639
|
if (Option.isSome(relativeMonth)) {
|
|
536
640
|
const month = monthNumber(textAt(relativeMonth.value, 1));
|
|
@@ -554,13 +658,31 @@ const parseBasePeriod = (input) => {
|
|
|
554
658
|
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"));
|
|
555
659
|
if (input === "el fin de semana anterior al pasado") return Option.some(relativeWeekend(-2, input));
|
|
556
660
|
if (input === "el fin de semana después del próximo") return Option.some(relativeWeekend(2, input));
|
|
557
|
-
|
|
661
|
+
const weekday = nextWeekdays.find((entry) => entry.phrase === input);
|
|
662
|
+
return weekday === void 0 ? Option.none() : Option.some(relativeWeekday(weekday.day, 1, weekday.canonical));
|
|
558
663
|
};
|
|
559
664
|
const parsePeriod = (input) => {
|
|
665
|
+
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);
|
|
666
|
+
if (Option.isSome(shifted)) {
|
|
667
|
+
const amount = parseTrailingCount(textAt(shifted.value, 3));
|
|
668
|
+
const alias = unitAliases.find((unit) => unit[0] === textAt(shifted.value, 4));
|
|
669
|
+
const entry = alias === void 0 ? void 0 : units.find((unit) => unit.unit === alias[1]);
|
|
670
|
+
const period = parsePeriod(textAt(shifted.value, 1));
|
|
671
|
+
if (Option.isSome(amount) && entry !== void 0 && Option.isSome(period)) {
|
|
672
|
+
const past = textAt(shifted.value, 2) === "hace";
|
|
673
|
+
const direction = past ? -amount.value : amount.value;
|
|
674
|
+
const noun = amount.value === 1 ? entry.singular : entry.plural;
|
|
675
|
+
const canonical = `${period.value.canonical} ${past ? "hace" : "dentro de"} ${amount.value} ${noun}`;
|
|
676
|
+
return Option.some(shiftPeriod(period.value, direction, entry.unit, canonical));
|
|
677
|
+
}
|
|
678
|
+
}
|
|
560
679
|
const edge = String$1.match(/^(?:el )?(inicio|comienzo|principio|fin|final)(?: de| del) (.+)$/u)(input);
|
|
561
680
|
if (Option.isSome(edge)) {
|
|
562
681
|
const edgeName = textAt(edge.value, 1);
|
|
563
|
-
const
|
|
682
|
+
const periodText = textAt(edge.value, 2);
|
|
683
|
+
const basePeriod = parseBasePeriod(periodText);
|
|
684
|
+
const implicit = units.find((entry) => entry.singular === periodText);
|
|
685
|
+
const period = Option.isSome(basePeriod) || implicit === void 0 ? basePeriod : Option.some(relativePeriod(implicit.unit, 0, implicit.current));
|
|
564
686
|
if (Option.isSome(period)) {
|
|
565
687
|
const isEnd = edgeName === "fin" || edgeName === "final";
|
|
566
688
|
const canonical = `${isEnd ? "final" : "inicio"} ${withDe(period.value.canonical)}`;
|
|
@@ -574,7 +696,8 @@ const parsePeriod = (input) => {
|
|
|
574
696
|
"todo el ",
|
|
575
697
|
"toda la "
|
|
576
698
|
].find((prefix) => input.startsWith(prefix));
|
|
577
|
-
|
|
699
|
+
const base = parseBasePeriod(wrapper === void 0 ? input : input.slice(wrapper.length));
|
|
700
|
+
return Option.isSome(base) ? base : parseCalendarOffset(input);
|
|
578
701
|
};
|
|
579
702
|
const countedUnit = (value, amount) => {
|
|
580
703
|
const alias = unitAliases.find((entry) => entry[0] === value && entry[2] === (amount !== 1));
|
|
@@ -597,7 +720,7 @@ const agreesWithSingularModifier = (entry, modifier, future) => {
|
|
|
597
720
|
return modifier === expected || modifier === withoutAcute(expected);
|
|
598
721
|
};
|
|
599
722
|
const parseCalendarOffset = (input) => {
|
|
600
|
-
const match = String$1.match(/^(hace|dentro de|en) ([1-9]\d*|un|una) (
|
|
723
|
+
const match = String$1.match(/^(hace|dentro de|en) ([1-9]\d*|un|una) ([^ ]+)$/u)(input);
|
|
601
724
|
if (Option.isNone(match)) return Option.none();
|
|
602
725
|
const amount = writtenAmount(textAt(match.value, 2));
|
|
603
726
|
if (Option.isNone(amount)) return Option.none();
|
|
@@ -609,7 +732,7 @@ const parseCalendarOffset = (input) => {
|
|
|
609
732
|
const noun = amount.value === 1 ? entry.singular : entry.plural;
|
|
610
733
|
const canonical = `${isPast ? "hace" : "dentro de"} ${quantity} ${noun}`;
|
|
611
734
|
const direction = isPast ? -amount.value : amount.value;
|
|
612
|
-
return Option.some(
|
|
735
|
+
return Option.some(relativePeriod(entry.unit, direction, canonical));
|
|
613
736
|
};
|
|
614
737
|
const rollingCanonical = (entry, amount, future) => {
|
|
615
738
|
if (amount > 1) return `${rollingAdjective(entry, future, true)} ${amount} ${entry.plural}`;
|
|
@@ -617,8 +740,8 @@ const rollingCanonical = (entry, amount, future) => {
|
|
|
617
740
|
return future ? `desde ahora durante ${article} ${entry.singular}` : `desde hace ${article} ${entry.singular}`;
|
|
618
741
|
};
|
|
619
742
|
const rollingCandidate = (entry, amount, future) => candidate(future ? futureRange(amount, entry.unit) : trailingRange(amount, entry.unit), rollingCanonical(entry, amount, future));
|
|
620
|
-
const
|
|
621
|
-
const since = String$1.match(/^desde hace ([1-9]\d*|un|una) (
|
|
743
|
+
const parseRollingSince = (input) => {
|
|
744
|
+
const since = String$1.match(/^desde hace ([1-9]\d*|un|una) ([^ ]+)$/u)(input);
|
|
622
745
|
if (Option.isSome(since)) {
|
|
623
746
|
const amount = writtenAmount(textAt(since.value, 1));
|
|
624
747
|
if (Option.isSome(amount)) {
|
|
@@ -627,40 +750,51 @@ const parseRollingPeriod = (input) => {
|
|
|
627
750
|
if (entry !== void 0 && (amountText !== "un" && amountText !== "una" || agreesWithIndefiniteArticle(entry, amountText))) return Option.some(rollingCandidate(entry, amount.value, false));
|
|
628
751
|
}
|
|
629
752
|
}
|
|
630
|
-
|
|
753
|
+
return Option.none();
|
|
754
|
+
};
|
|
755
|
+
const parseSingularRolling = (input) => {
|
|
756
|
+
const futureSingular = String$1.match(/^desde ahora durante (un|una) ([^ ]+)$/u)(input);
|
|
631
757
|
if (Option.isSome(futureSingular)) {
|
|
632
758
|
const entry = countedUnit(textAt(futureSingular.value, 2), 1);
|
|
633
759
|
if (entry !== void 0 && agreesWithIndefiniteArticle(entry, textAt(futureSingular.value, 1))) return Option.some(rollingCandidate(entry, 1, true));
|
|
634
760
|
}
|
|
635
|
-
const lastSingular = String$1.match(/^(?:(?:durante|en) )?(?:este )?(?:(el|la) )?(
|
|
761
|
+
const lastSingular = String$1.match(/^(?:(?:durante|en) )?(?:este )?(?:(el|la) )?([uú]ltim[oa]) ([^ ]+)$/u)(input);
|
|
636
762
|
if (Option.isSome(lastSingular)) {
|
|
637
763
|
const entry = countedUnit(textAt(lastSingular.value, 3), 1);
|
|
638
764
|
const modifier = textAt(lastSingular.value, 2);
|
|
639
765
|
if (entry !== void 0 && agreesWithArticle(entry, textAt(lastSingular.value, 1)) && agreesWithSingularModifier(entry, modifier, false)) return Option.some(rollingCandidate(entry, 1, false));
|
|
640
766
|
}
|
|
641
|
-
const nextSingular = String$1.match(/^durante (el|la) (
|
|
767
|
+
const nextSingular = String$1.match(/^durante (el|la) (pr[oó]xim[oa]|siguiente) ([^ ]+)$/u)(input);
|
|
642
768
|
if (Option.isSome(nextSingular)) {
|
|
643
769
|
const entry = countedUnit(textAt(nextSingular.value, 3), 1);
|
|
644
770
|
const modifier = textAt(nextSingular.value, 2);
|
|
645
771
|
if (entry !== void 0 && agreesWithArticle(entry, textAt(nextSingular.value, 1)) && agreesWithSingularModifier(entry, modifier, true)) return Option.some(rollingCandidate(entry, 1, true));
|
|
646
772
|
}
|
|
647
|
-
|
|
773
|
+
return Option.none();
|
|
774
|
+
};
|
|
775
|
+
const parseCountedRolling = (input) => {
|
|
776
|
+
const counted = String$1.match(/^(?:(?:durante|en) )?(?:(los|las) )?([uú]ltim(?:os|as)|pasad(?:os|as)|anteriores|pr[oó]xim(?:os|as)|siguientes) ([1-9]\d*) ([^ ]+)$/u)(input);
|
|
648
777
|
if (Option.isSome(counted)) {
|
|
649
778
|
const amount = parseTrailingCount(textAt(counted.value, 3));
|
|
650
779
|
if (Option.isSome(amount) && amount.value > 1) {
|
|
651
780
|
const entry = countedUnit(textAt(counted.value, 4), amount.value);
|
|
652
781
|
const modifier = textAt(counted.value, 2);
|
|
653
|
-
const future = modifier.
|
|
782
|
+
const future = modifier.includes("xim") || modifier === "siguientes";
|
|
654
783
|
if (entry !== void 0 && agreesWithArticle(entry, textAt(counted.value, 1), true) && agreesWithRollingModifier(entry, modifier, future)) return Option.some(rollingCandidate(entry, amount.value, future));
|
|
655
784
|
}
|
|
656
785
|
}
|
|
657
|
-
const bare = String$1.match(/^([1-9]\d*) (
|
|
786
|
+
const bare = String$1.match(/^([1-9]\d*) ([^ ]+)$/u)(input);
|
|
658
787
|
if (Option.isNone(bare)) return Option.none();
|
|
659
788
|
const amount = parseTrailingCount(textAt(bare.value, 1));
|
|
660
789
|
if (Option.isNone(amount)) return Option.none();
|
|
661
790
|
const entry = countedUnit(textAt(bare.value, 2), amount.value);
|
|
662
791
|
return entry === void 0 ? Option.none() : Option.some(rollingCandidate(entry, amount.value, false));
|
|
663
792
|
};
|
|
793
|
+
const parseRollingPeriod = (input) => Option.firstSomeOf([
|
|
794
|
+
parseRollingSince(input),
|
|
795
|
+
parseSingularRolling(input),
|
|
796
|
+
parseCountedRolling(input)
|
|
797
|
+
]);
|
|
664
798
|
const parseElidedDateRange = (input) => {
|
|
665
799
|
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);
|
|
666
800
|
const dashed = String$1.match(/^([0-3]?\d)[–—-]([0-3]?\d) (.+)$/u)(input);
|
|
@@ -698,8 +832,6 @@ const parseSpanish = (input) => {
|
|
|
698
832
|
"a partir de ahora",
|
|
699
833
|
"de ahora en adelante"
|
|
700
834
|
].includes(input)) return Option.some(candidate(fromNowRange(), "desde ahora"));
|
|
701
|
-
const offset = parseCalendarOffset(input);
|
|
702
|
-
if (Option.isSome(offset)) return offset;
|
|
703
835
|
const rolling = parseRollingPeriod(input);
|
|
704
836
|
if (Option.isSome(rolling)) return rolling;
|
|
705
837
|
const toDate = toDatePhrases.find((entry) => entry.phrase === input);
|
|
@@ -714,7 +846,8 @@ const parseSpanish = (input) => {
|
|
|
714
846
|
"desde ahora hasta ",
|
|
715
847
|
"desde hoy hasta ",
|
|
716
848
|
"entre hoy y ",
|
|
717
|
-
"entre hoy y el "
|
|
849
|
+
"entre hoy y el ",
|
|
850
|
+
"ahora hasta "
|
|
718
851
|
], parsePeriod, (period) => `desde ${period} hasta ahora`, (period) => `desde ahora hasta ${period}`);
|
|
719
852
|
if (Option.isSome(nowBounded)) return nowBounded;
|
|
720
853
|
const bounded = joinedPeriodCandidate(input, [
|
|
@@ -769,9 +902,14 @@ const staticPeriodPhrases = [
|
|
|
769
902
|
]),
|
|
770
903
|
...months.flatMap((month) => [
|
|
771
904
|
month,
|
|
905
|
+
`pasado ${month}`,
|
|
906
|
+
`próximo ${month}`,
|
|
907
|
+
`${month} pasado`,
|
|
908
|
+
`${month} próximo`,
|
|
772
909
|
`${month} del año pasado`,
|
|
773
910
|
`${month} del próximo año`
|
|
774
|
-
])
|
|
911
|
+
]),
|
|
912
|
+
...nextWeekdays.map((entry) => entry.phrase)
|
|
775
913
|
];
|
|
776
914
|
const staticPeriods = periodsFromPhrases(staticPeriodPhrases, parsePeriod);
|
|
777
915
|
const boundaryPrefixes = [
|
|
@@ -830,6 +968,17 @@ const suggestSpanish = (input, limit) => {
|
|
|
830
968
|
], limit);
|
|
831
969
|
};
|
|
832
970
|
const renderSpanish = (range) => {
|
|
971
|
+
const shifted = decomposeShiftedPeriodRange(range);
|
|
972
|
+
if (Option.isSome(shifted)) {
|
|
973
|
+
const base = renderSpanish(shifted.value.baseRange);
|
|
974
|
+
const entry = units.find((unit) => unit.unit === shifted.value.unit);
|
|
975
|
+
if (Option.isSome(base) && entry !== void 0) {
|
|
976
|
+
const amount = Math.abs(shifted.value.amount);
|
|
977
|
+
const noun = amount === 1 ? entry.singular : entry.plural;
|
|
978
|
+
const direction = shifted.value.amount < 0 ? "hace" : "dentro de";
|
|
979
|
+
return Option.some(`${base.value} ${direction} ${amount} ${noun}`);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
833
982
|
const offset = calendarPeriodOffset(range);
|
|
834
983
|
if (Option.isSome(offset) && Math.abs(offset.value.amount) > 1) {
|
|
835
984
|
const entry = units.find((unit) => unit.unit === offset.value.unit);
|
|
@@ -860,6 +1009,7 @@ const SpanishContribution = new BaseLanguageContribution({
|
|
|
860
1009
|
locale: "es",
|
|
861
1010
|
vocabulary: [
|
|
862
1011
|
...months,
|
|
1012
|
+
...weekdays,
|
|
863
1013
|
...monthAbbreviations.flatMap((aliases) => aliases),
|
|
864
1014
|
...units.flatMap((entry) => [
|
|
865
1015
|
entry.singular,
|
|
@@ -893,8 +1043,8 @@ const SpanishContribution = new BaseLanguageContribution({
|
|
|
893
1043
|
"resto",
|
|
894
1044
|
"últimos"
|
|
895
1045
|
],
|
|
896
|
-
normalize:
|
|
897
|
-
correct:
|
|
1046
|
+
normalize: normalizeSpanish,
|
|
1047
|
+
correct: correctSpanish,
|
|
898
1048
|
parseExact: parseSpanish,
|
|
899
1049
|
suggest: suggestSpanish,
|
|
900
1050
|
render: renderSpanish
|