chronolizer 0.3.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 +46 -45
- package/dist/filter/expression.mjs +24 -18
- package/dist/language/model.mjs +1 -1
- package/dist/language/registry.mjs +32 -12
- package/dist/locales/cs.mjs +186 -17
- package/dist/locales/de.mjs +133 -20
- package/dist/locales/en.mjs +151 -35
- package/dist/locales/es.mjs +178 -19
- package/dist/locales/fr.mjs +150 -19
- package/dist/locales/nl.mjs +118 -19
- package/dist/locales/pl.mjs +156 -18
- package/dist/locales/shared.mjs +64 -1
- package/dist/locales/tr.mjs +138 -24
- 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.mjs +5 -4
- package/dist/natural/suggest.mjs +19 -3
- package/dist/natural/suggestion.mjs +11 -5
- package/dist/resolve/resolve.mjs +1 -1
- package/package.json +1 -1
package/dist/locales/nl.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 { absoluteDatePeriod, calendarPeriodOffset, candidate, currentYearDatePeriods, datedPeriods, datedQuarterPeriods, fixedDatePeriod, fixedMonthPeriod, fixedQuarterPeriod, fixedYearPeriod, fromNowRange, futurePeriod, futureRange, isoDate, joinedNowCandidate, joinedPeriodCandidate, monthOfRelativeYear, namedCurrentYearDatePeriod, namedDatePeriod, openBoundaryCandidate, parseTrailingCount, periodDay, 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, 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/nl.ts
|
|
10
10
|
const months = [
|
|
@@ -21,6 +21,54 @@ const months = [
|
|
|
21
21
|
"november",
|
|
22
22
|
"december"
|
|
23
23
|
];
|
|
24
|
+
const weekdays = [
|
|
25
|
+
"maandag",
|
|
26
|
+
"dinsdag",
|
|
27
|
+
"woensdag",
|
|
28
|
+
"donderdag",
|
|
29
|
+
"vrijdag",
|
|
30
|
+
"zaterdag",
|
|
31
|
+
"zondag"
|
|
32
|
+
];
|
|
33
|
+
const nextWeekdayPhrases = weekdays.map((weekday) => `volgende ${weekday}`);
|
|
34
|
+
const dutchCountWords = [
|
|
35
|
+
"twee",
|
|
36
|
+
"drie",
|
|
37
|
+
"vier",
|
|
38
|
+
"vijf",
|
|
39
|
+
"zes",
|
|
40
|
+
"zeven",
|
|
41
|
+
"acht",
|
|
42
|
+
"negen",
|
|
43
|
+
"tien",
|
|
44
|
+
"elf",
|
|
45
|
+
"twaalf",
|
|
46
|
+
"dertien",
|
|
47
|
+
"veertien",
|
|
48
|
+
"vijftien",
|
|
49
|
+
"zestien",
|
|
50
|
+
"zeventien",
|
|
51
|
+
"achttien",
|
|
52
|
+
"negentien",
|
|
53
|
+
"twintig"
|
|
54
|
+
];
|
|
55
|
+
const dutchCountOnes = [[1, "een"], ...dutchCountWords.slice(0, 8).map((word, index) => [index + 2, word])];
|
|
56
|
+
const dutchCountAliases = [...sequentialCountAliases(dutchCountWords.map((word) => [word]), 2), ...compoundCountAliases(decimalTens([
|
|
57
|
+
"twintig",
|
|
58
|
+
"dertig",
|
|
59
|
+
"veertig",
|
|
60
|
+
"vijftig",
|
|
61
|
+
"zestig",
|
|
62
|
+
"zeventig",
|
|
63
|
+
"tachtig",
|
|
64
|
+
"negentig"
|
|
65
|
+
]), dutchCountOnes, (ten, one) => {
|
|
66
|
+
return [`${one === "twee" || one === "drie" ? `${one}ën` : `${one}en`}${ten}`];
|
|
67
|
+
})];
|
|
68
|
+
const normalizeDutchCounts = compileCountAliasNormalizer(dutchCountAliases);
|
|
69
|
+
const dutchCountVocabulary = new Set(countAliasVocabulary(dutchCountAliases));
|
|
70
|
+
const correctDutch = (input, vocabulary) => correctWhitespaceSeparatedText(input, vocabulary, dutchCountVocabulary);
|
|
71
|
+
const normalizeDutch = (input, locale) => normalizeDutchCounts(normalizeNaturalText(input, locale));
|
|
24
72
|
const monthAbbreviations = [
|
|
25
73
|
["jan"],
|
|
26
74
|
["feb"],
|
|
@@ -395,13 +443,13 @@ const parseQuarter = (input) => {
|
|
|
395
443
|
const quarter = quarterNumber(textAt(standalone.value, 1));
|
|
396
444
|
return quarter === void 0 ? Option.none() : Option.some(quarterOfRelativeYear(quarter, 0, `K${quarter}`));
|
|
397
445
|
};
|
|
398
|
-
const
|
|
399
|
-
const
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
if (Option.isSome(
|
|
446
|
+
const parseDatedPeriod = (input) => {
|
|
447
|
+
const knownPeriod = Option.firstSomeOf([
|
|
448
|
+
absoluteDatePeriod(input, "nl"),
|
|
449
|
+
parseNamedDate(input),
|
|
450
|
+
parseQuarter(input)
|
|
451
|
+
]);
|
|
452
|
+
if (Option.isSome(knownPeriod)) return knownPeriod;
|
|
405
453
|
const yearMatch = String$1.match(/^(?:het jaar |jaar )?(\d{4})$/u)(input);
|
|
406
454
|
if (Option.isSome(yearMatch)) {
|
|
407
455
|
const year = validYear(textAt(yearMatch.value, 1));
|
|
@@ -413,6 +461,20 @@ const parseBasePeriod = (input) => {
|
|
|
413
461
|
const year = validYear(textAt(monthYear.value, 2));
|
|
414
462
|
if (month !== void 0 && year !== void 0) return Option.some(fixedMonthPeriod(year, month, `${textAt(months, month - 1)} ${year}`));
|
|
415
463
|
}
|
|
464
|
+
return Option.none();
|
|
465
|
+
};
|
|
466
|
+
const parseBasePeriod = (input) => {
|
|
467
|
+
const datedPeriod = parseDatedPeriod(input);
|
|
468
|
+
if (Option.isSome(datedPeriod)) return datedPeriod;
|
|
469
|
+
const prefixedRelativeMonth = String$1.match(/^(vorige|deze|volgende) ([a-z]+\.?)$/u)(input);
|
|
470
|
+
if (Option.isSome(prefixedRelativeMonth)) {
|
|
471
|
+
const month = monthNumber(textAt(prefixedRelativeMonth.value, 2));
|
|
472
|
+
if (month !== void 0) {
|
|
473
|
+
const modifier = textAt(prefixedRelativeMonth.value, 1);
|
|
474
|
+
const direction = relativeYearDirection(modifier);
|
|
475
|
+
return Option.some(monthOfRelativeYear(month, direction, `${modifier} ${textAt(months, month - 1)}`));
|
|
476
|
+
}
|
|
477
|
+
}
|
|
416
478
|
const relativeMonth = String$1.match(/^([a-z]+\.?)(?: van)? (vorig jaar|volgend jaar|dit jaar)$/u)(input);
|
|
417
479
|
const relativeMonthYearFirst = String$1.match(/^(vorig jaar|volgend jaar|dit jaar) ([a-z]+\.?)$/u)(input);
|
|
418
480
|
const relativeMatch = Option.firstSomeOf([relativeMonth, relativeMonthYearFirst]);
|
|
@@ -445,13 +507,33 @@ const parseBasePeriod = (input) => {
|
|
|
445
507
|
].includes(input)) return Option.some(relativeWeekend(1, "volgend weekend"));
|
|
446
508
|
if (input === "het weekend voor het vorige") return Option.some(relativeWeekend(-2, input));
|
|
447
509
|
if (input === "het weekend na het volgende") return Option.some(relativeWeekend(2, input));
|
|
448
|
-
|
|
510
|
+
const weekday = nextWeekdayPhrases.indexOf(input);
|
|
511
|
+
return weekday === -1 ? Option.none() : Option.some(relativeWeekday(weekday, 1, nextWeekdayPhrases[weekday] ?? input));
|
|
449
512
|
};
|
|
450
513
|
const parsePeriod = (input) => {
|
|
514
|
+
const shifted = String$1.match(/^(.+) (?:(?:over|binnen) ([1-9]\d*) (dag|dagen|week|weken|maand|maanden|kwartaal|kwartalen|jaar|jaren)|([1-9]\d*) (dag|dagen|week|weken|maand|maanden|kwartaal|kwartalen|jaar|jaren) (geleden|later))$/u)(input);
|
|
515
|
+
if (Option.isSome(shifted)) {
|
|
516
|
+
const suffixAmount = textAt(shifted.value, 4);
|
|
517
|
+
const amount = parseTrailingCount(suffixAmount || textAt(shifted.value, 2));
|
|
518
|
+
const unitText = textAt(shifted.value, suffixAmount.length > 0 ? 5 : 3);
|
|
519
|
+
const alias = unitAliases.find((unit) => unit[0] === unitText);
|
|
520
|
+
const entry = alias === void 0 ? void 0 : units.find((unit) => unit.unit === alias[1]);
|
|
521
|
+
const period = parsePeriod(textAt(shifted.value, 1));
|
|
522
|
+
if (Option.isSome(amount) && entry !== void 0 && Option.isSome(period)) {
|
|
523
|
+
const past = textAt(shifted.value, 6) === "geleden";
|
|
524
|
+
const direction = past ? -amount.value : amount.value;
|
|
525
|
+
const noun = amount.value === 1 ? entry.singular : entry.plural;
|
|
526
|
+
const canonical = past ? `${period.value.canonical} ${amount.value} ${noun} geleden` : `${period.value.canonical} over ${amount.value} ${noun}`;
|
|
527
|
+
return Option.some(shiftPeriod(period.value, direction, entry.unit, canonical));
|
|
528
|
+
}
|
|
529
|
+
}
|
|
451
530
|
const edge = String$1.match(/^(?:het )?(begin|eind|einde)(?: van)? (.+)$/u)(input);
|
|
452
531
|
if (Option.isSome(edge)) {
|
|
453
532
|
const edgeName = textAt(edge.value, 1);
|
|
454
|
-
const
|
|
533
|
+
const periodText = textAt(edge.value, 2);
|
|
534
|
+
const basePeriod = parseBasePeriod(periodText);
|
|
535
|
+
const implicit = units.find((entry) => `${entry.article} ${entry.singular}` === periodText);
|
|
536
|
+
const period = Option.isSome(basePeriod) || implicit === void 0 ? basePeriod : Option.some(relativePeriod(implicit.unit, 0, implicit.current));
|
|
455
537
|
if (Option.isSome(period)) {
|
|
456
538
|
const isEnd = edgeName === "eind" || edgeName === "einde";
|
|
457
539
|
const canonical = `${isEnd ? "eind" : "begin"} van ${period.value.canonical}`;
|
|
@@ -465,7 +547,8 @@ const parsePeriod = (input) => {
|
|
|
465
547
|
"de hele ",
|
|
466
548
|
"het hele "
|
|
467
549
|
].find((prefix) => input.startsWith(prefix));
|
|
468
|
-
|
|
550
|
+
const base = parseBasePeriod(wrapper === void 0 ? input : input.slice(wrapper.length));
|
|
551
|
+
return Option.isSome(base) ? base : parseCalendarOffset(input);
|
|
469
552
|
};
|
|
470
553
|
const countedUnit = (value, amount) => {
|
|
471
554
|
const expected = amount === 1 ? "singular" : "plural";
|
|
@@ -528,7 +611,7 @@ const singularCalendarOffsets = units.flatMap((entry) => [
|
|
|
528
611
|
]);
|
|
529
612
|
const parseCalendarOffset = (input) => {
|
|
530
613
|
const singular = singularCalendarOffsets.find((entry) => entry.phrase === input);
|
|
531
|
-
if (singular !== void 0) return Option.some(
|
|
614
|
+
if (singular !== void 0) return Option.some(relativePeriod(singular.entry.unit, singular.direction, singular.phrase));
|
|
532
615
|
const past = String$1.match(calendarPastPattern)(input);
|
|
533
616
|
const future = firstPatternMatch(input, calendarFuturePatterns);
|
|
534
617
|
const match = Option.firstSomeOf([past, future]);
|
|
@@ -540,7 +623,7 @@ const parseCalendarOffset = (input) => {
|
|
|
540
623
|
const direction = Option.isSome(past) ? -amount.value : amount.value;
|
|
541
624
|
const noun = amount.value === 1 ? entry.singular : entry.plural;
|
|
542
625
|
const canonical = direction < 0 ? `${amount.value} ${noun} geleden` : `over ${amount.value} ${noun}`;
|
|
543
|
-
return Option.some(
|
|
626
|
+
return Option.some(relativePeriod(entry.unit, direction, canonical));
|
|
544
627
|
};
|
|
545
628
|
const parseRollingPeriod = (input) => {
|
|
546
629
|
const singular = singularRollingPhrases.find((entry) => entry.phrase === input);
|
|
@@ -604,8 +687,6 @@ const parseDutch = (input) => {
|
|
|
604
687
|
"sinds nu",
|
|
605
688
|
"voortaan"
|
|
606
689
|
].includes(input)) return Option.some(candidate(fromNowRange(), "vanaf nu"));
|
|
607
|
-
const offset = parseCalendarOffset(input);
|
|
608
|
-
if (Option.isSome(offset)) return offset;
|
|
609
690
|
const rolling = parseRollingPeriod(input);
|
|
610
691
|
if (Option.isSome(rolling)) return rolling;
|
|
611
692
|
const toDate = toDatePhrases.find((entry) => entry.phrase === input);
|
|
@@ -619,7 +700,8 @@ const parseDutch = (input) => {
|
|
|
619
700
|
], [
|
|
620
701
|
"vanaf nu tot en met ",
|
|
621
702
|
"van vandaag tot en met ",
|
|
622
|
-
"tussen vandaag en "
|
|
703
|
+
"tussen vandaag en ",
|
|
704
|
+
"nu tot en met "
|
|
623
705
|
], parsePeriod, (period) => `vanaf ${period} tot nu toe`, (period) => `vanaf nu tot en met ${period}`);
|
|
624
706
|
if (Option.isSome(nowBounded)) return nowBounded;
|
|
625
707
|
const bounded = joinedPeriodCandidate(input, [
|
|
@@ -670,9 +752,12 @@ const staticPeriodPhrases = [
|
|
|
670
752
|
]),
|
|
671
753
|
...months.flatMap((month) => [
|
|
672
754
|
month,
|
|
755
|
+
`vorige ${month}`,
|
|
756
|
+
`volgende ${month}`,
|
|
673
757
|
`${month} vorig jaar`,
|
|
674
758
|
`${month} volgend jaar`
|
|
675
|
-
])
|
|
759
|
+
]),
|
|
760
|
+
...nextWeekdayPhrases
|
|
676
761
|
];
|
|
677
762
|
const staticPeriods = periodsFromPhrases(staticPeriodPhrases, parsePeriod);
|
|
678
763
|
const boundaryPrefixes = [
|
|
@@ -719,6 +804,16 @@ const suggestDutch = (input, limit) => {
|
|
|
719
804
|
], limit);
|
|
720
805
|
};
|
|
721
806
|
const renderDutch = (range) => {
|
|
807
|
+
const shifted = decomposeShiftedPeriodRange(range);
|
|
808
|
+
if (Option.isSome(shifted)) {
|
|
809
|
+
const base = renderDutch(shifted.value.baseRange);
|
|
810
|
+
const entry = units.find((unit) => unit.unit === shifted.value.unit);
|
|
811
|
+
if (Option.isSome(base) && entry !== void 0) {
|
|
812
|
+
const amount = Math.abs(shifted.value.amount);
|
|
813
|
+
const noun = amount === 1 ? entry.singular : entry.plural;
|
|
814
|
+
return Option.some(shifted.value.amount < 0 ? `${base.value} ${amount} ${noun} geleden` : `${base.value} over ${amount} ${noun}`);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
722
817
|
const offset = calendarPeriodOffset(range);
|
|
723
818
|
if (Option.isSome(offset) && Math.abs(offset.value.amount) > 1) {
|
|
724
819
|
const entry = units.find((unit) => unit.unit === offset.value.unit);
|
|
@@ -749,6 +844,7 @@ const DutchContribution = new BaseLanguageContribution({
|
|
|
749
844
|
locale: "nl",
|
|
750
845
|
vocabulary: [
|
|
751
846
|
...months,
|
|
847
|
+
...weekdays,
|
|
752
848
|
...monthAbbreviations.flatMap((aliases) => aliases),
|
|
753
849
|
...units.flatMap((entry) => [
|
|
754
850
|
entry.singular,
|
|
@@ -763,10 +859,13 @@ const DutchContribution = new BaseLanguageContribution({
|
|
|
763
859
|
"begin",
|
|
764
860
|
"binnen",
|
|
765
861
|
"eind",
|
|
862
|
+
"en",
|
|
766
863
|
"geleden",
|
|
767
864
|
"komende",
|
|
768
865
|
"laatste",
|
|
866
|
+
"met",
|
|
769
867
|
"na",
|
|
868
|
+
"nu",
|
|
770
869
|
"over",
|
|
771
870
|
"rest",
|
|
772
871
|
"sinds",
|
|
@@ -776,8 +875,8 @@ const DutchContribution = new BaseLanguageContribution({
|
|
|
776
875
|
"volgend",
|
|
777
876
|
"voor"
|
|
778
877
|
],
|
|
779
|
-
normalize:
|
|
780
|
-
correct:
|
|
878
|
+
normalize: normalizeDutch,
|
|
879
|
+
correct: correctDutch,
|
|
781
880
|
parseExact: parseDutch,
|
|
782
881
|
suggest: suggestDutch,
|
|
783
882
|
render: renderDutch
|
package/dist/locales/pl.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 } from "../natural/suggestion.mjs";
|
|
7
|
-
import { absoluteDatePeriod, calendarPeriodOffset, candidate, currentYearDatePeriods, datedPeriods, datedQuarterPeriods, fixedDatePeriod, fixedMonthPeriod, fixedQuarterPeriod, fixedYearPeriod, fromNowRange, futurePeriod, futureRange, isoDate, joinedNowCandidate, joinedPeriodCandidate, monthOfRelativeYear, namedCurrentYearDatePeriod, namedDatePeriod, parseTrailingCount, periodBoundaryCandidate, 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, parseTrailingCount, periodBoundaryCandidate, 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/pl.ts
|
|
10
10
|
const months = [
|
|
@@ -21,6 +21,95 @@ const months = [
|
|
|
21
21
|
"listopad",
|
|
22
22
|
"grudzień"
|
|
23
23
|
];
|
|
24
|
+
const weekdays = [
|
|
25
|
+
"poniedziałek",
|
|
26
|
+
"wtorek",
|
|
27
|
+
"środa",
|
|
28
|
+
"czwartek",
|
|
29
|
+
"piątek",
|
|
30
|
+
"sobota",
|
|
31
|
+
"niedziela"
|
|
32
|
+
];
|
|
33
|
+
const weekdayGenitives = [
|
|
34
|
+
"poniedziałku",
|
|
35
|
+
"wtorku",
|
|
36
|
+
"środy",
|
|
37
|
+
"czwartku",
|
|
38
|
+
"piątku",
|
|
39
|
+
"soboty",
|
|
40
|
+
"niedzieli"
|
|
41
|
+
];
|
|
42
|
+
const nextWeekdays = weekdays.flatMap((weekday, day) => {
|
|
43
|
+
const feminine = day === 2 || day >= 5;
|
|
44
|
+
const canonical = `${feminine ? "następna" : "następny"} ${weekday}`;
|
|
45
|
+
return [{
|
|
46
|
+
phrase: canonical,
|
|
47
|
+
day,
|
|
48
|
+
canonical
|
|
49
|
+
}, {
|
|
50
|
+
phrase: `${feminine ? "następnej" : "następnego"} ${textAt(weekdayGenitives, day)}`,
|
|
51
|
+
day,
|
|
52
|
+
canonical
|
|
53
|
+
}];
|
|
54
|
+
});
|
|
55
|
+
const polishCountWords = [
|
|
56
|
+
[
|
|
57
|
+
"dwa",
|
|
58
|
+
"dwie",
|
|
59
|
+
"dwóch"
|
|
60
|
+
],
|
|
61
|
+
["trzy"],
|
|
62
|
+
["cztery"],
|
|
63
|
+
["pięć"],
|
|
64
|
+
["sześć"],
|
|
65
|
+
["siedem"],
|
|
66
|
+
["osiem"],
|
|
67
|
+
["dziewięć"],
|
|
68
|
+
["dziesięć"],
|
|
69
|
+
["jedenaście"],
|
|
70
|
+
["dwanaście"],
|
|
71
|
+
["trzynaście"],
|
|
72
|
+
["czternaście"],
|
|
73
|
+
["piętnaście"],
|
|
74
|
+
["szesnaście"],
|
|
75
|
+
["siedemnaście"],
|
|
76
|
+
["osiemnaście"],
|
|
77
|
+
["dziewiętnaście"],
|
|
78
|
+
["dwadzieścia"]
|
|
79
|
+
];
|
|
80
|
+
const polishCountOnes = [
|
|
81
|
+
[1, "jeden"],
|
|
82
|
+
[2, "dwa"],
|
|
83
|
+
[3, "trzy"],
|
|
84
|
+
[4, "cztery"],
|
|
85
|
+
[5, "pięć"],
|
|
86
|
+
[6, "sześć"],
|
|
87
|
+
[7, "siedem"],
|
|
88
|
+
[8, "osiem"],
|
|
89
|
+
[9, "dziewięć"]
|
|
90
|
+
];
|
|
91
|
+
const polishCountAliases = [
|
|
92
|
+
...sequentialCountAliases([[
|
|
93
|
+
"jeden",
|
|
94
|
+
"jedna",
|
|
95
|
+
"jedno"
|
|
96
|
+
]], 1),
|
|
97
|
+
...sequentialCountAliases(polishCountWords, 2),
|
|
98
|
+
...compoundCountAliases(decimalTens([
|
|
99
|
+
"dwadzieścia",
|
|
100
|
+
"trzydzieści",
|
|
101
|
+
"czterdzieści",
|
|
102
|
+
"pięćdziesiąt",
|
|
103
|
+
"sześćdziesiąt",
|
|
104
|
+
"siedemdziesiąt",
|
|
105
|
+
"osiemdziesiąt",
|
|
106
|
+
"dziewięćdziesiąt"
|
|
107
|
+
]), polishCountOnes, (ten, one) => [`${ten} ${one}`])
|
|
108
|
+
];
|
|
109
|
+
const normalizePolishCounts = compileCountAliasNormalizer(polishCountAliases);
|
|
110
|
+
const polishCountVocabulary = new Set(countAliasVocabulary(polishCountAliases));
|
|
111
|
+
const correctPolish = (input, vocabulary) => correctWhitespaceSeparatedText(input, vocabulary, polishCountVocabulary);
|
|
112
|
+
const normalizePolish = (input, locale) => normalizePolishCounts(normalizeNaturalText(input, locale));
|
|
24
113
|
const monthGenitives = [
|
|
25
114
|
"stycznia",
|
|
26
115
|
"lutego",
|
|
@@ -484,13 +573,13 @@ const parseQuarter = (input) => {
|
|
|
484
573
|
const quarter = quarterNumber(textAt(standalone.value, 1));
|
|
485
574
|
return quarter === void 0 ? Option.none() : Option.some(quarterOfRelativeYear(quarter, 0, `Q${quarter}`));
|
|
486
575
|
};
|
|
487
|
-
const
|
|
488
|
-
const
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
if (Option.isSome(
|
|
576
|
+
const parseDatedPeriod = (input) => {
|
|
577
|
+
const knownPeriod = Option.firstSomeOf([
|
|
578
|
+
absoluteDatePeriod(input, "pl"),
|
|
579
|
+
parseNamedDate(input),
|
|
580
|
+
parseQuarter(input)
|
|
581
|
+
]);
|
|
582
|
+
if (Option.isSome(knownPeriod)) return knownPeriod;
|
|
494
583
|
const yearMatch = String$1.match(/^(?:rok |roku )?(\d{4})$/u)(input);
|
|
495
584
|
if (Option.isSome(yearMatch)) {
|
|
496
585
|
const year = validYear(textAt(yearMatch.value, 1));
|
|
@@ -502,6 +591,20 @@ const parseBasePeriod = (input) => {
|
|
|
502
591
|
const year = validYear(textAt(monthYear.value, 2));
|
|
503
592
|
if (month !== void 0 && year !== void 0) return Option.some(fixedMonthPeriod(year, month, `${title(textAt(months, month - 1))} ${year}`));
|
|
504
593
|
}
|
|
594
|
+
return Option.none();
|
|
595
|
+
};
|
|
596
|
+
const parseBasePeriod = (input) => {
|
|
597
|
+
const datedPeriod = parseDatedPeriod(input);
|
|
598
|
+
if (Option.isSome(datedPeriod)) return datedPeriod;
|
|
599
|
+
const prefixedRelativeMonth = String$1.match(/^(poprzedni|ten|następny) ([a-ząćęłńóśźż]+\.?)$/u)(input);
|
|
600
|
+
if (Option.isSome(prefixedRelativeMonth)) {
|
|
601
|
+
const month = monthNumber(textAt(prefixedRelativeMonth.value, 2));
|
|
602
|
+
if (month !== void 0) {
|
|
603
|
+
const modifier = textAt(prefixedRelativeMonth.value, 1);
|
|
604
|
+
const direction = relativeYearDirection(modifier);
|
|
605
|
+
return Option.some(monthOfRelativeYear(month, direction, `${modifier} ${textAt(months, month - 1)}`));
|
|
606
|
+
}
|
|
607
|
+
}
|
|
505
608
|
const relativeMonth = String$1.match(/^([a-ząćęłńóśźż]+\.?) (poprzedniego roku|następnego roku|tego roku)$/u)(input);
|
|
506
609
|
const relativeMonthYearFirst = String$1.match(/^(poprzedniego roku|następnego roku|tego roku) ([a-ząćęłńóśźż]+\.?)$/u)(input);
|
|
507
610
|
const relativeMatch = Option.firstSomeOf([relativeMonth, relativeMonthYearFirst]);
|
|
@@ -522,12 +625,31 @@ const parseBasePeriod = (input) => {
|
|
|
522
625
|
if (["następny weekend", "przyszły weekend"].includes(input)) return Option.some(relativeWeekend(1, "następny weekend"));
|
|
523
626
|
if (input === "weekend przed poprzednim") return Option.some(relativeWeekend(-2, input));
|
|
524
627
|
if (input === "weekend po następnym") return Option.some(relativeWeekend(2, input));
|
|
525
|
-
|
|
628
|
+
const weekday = nextWeekdays.find((entry) => entry.phrase === input);
|
|
629
|
+
return weekday === void 0 ? Option.none() : Option.some(relativeWeekday(weekday.day, 1, weekday.canonical));
|
|
526
630
|
};
|
|
527
631
|
const parsePeriod = (input) => {
|
|
632
|
+
const shifted = String$1.match(/^(.+) (?:([1-9]\d*) (dzień|dni|tydzień|tygodnie|tygodni|miesiąc|miesiące|miesięcy|kwartał|kwartały|kwartałów|rok|lata|lat) (temu)|za ([1-9]\d*) (dzień|dni|tydzień|tygodnie|tygodni|miesiąc|miesiące|miesięcy|kwartał|kwartały|kwartałów|rok|lata|lat))$/u)(input);
|
|
633
|
+
if (Option.isSome(shifted)) {
|
|
634
|
+
const past = textAt(shifted.value, 4) === "temu";
|
|
635
|
+
const amount = parseTrailingCount(textAt(shifted.value, past ? 2 : 5));
|
|
636
|
+
const alias = unitAliases.find((unit) => unit[0] === textAt(shifted.value, past ? 3 : 6));
|
|
637
|
+
const entry = alias === void 0 ? void 0 : units.find((unit) => unit.unit === alias[1]);
|
|
638
|
+
const period = parsePeriod(textAt(shifted.value, 1));
|
|
639
|
+
if (Option.isSome(amount) && entry !== void 0 && Option.isSome(period)) {
|
|
640
|
+
const direction = past ? -amount.value : amount.value;
|
|
641
|
+
const noun = countNoun(amount.value, entry);
|
|
642
|
+
const canonical = past ? `${period.value.canonical} ${amount.value} ${noun} temu` : `${period.value.canonical} za ${amount.value} ${noun}`;
|
|
643
|
+
return Option.some(shiftPeriod(period.value, direction, entry.unit, canonical));
|
|
644
|
+
}
|
|
645
|
+
}
|
|
528
646
|
const edge = String$1.match(/^(początek|koniec) (.+)$/u)(input);
|
|
529
647
|
if (Option.isSome(edge)) {
|
|
530
|
-
const
|
|
648
|
+
const periodText = textAt(edge.value, 2);
|
|
649
|
+
const basePeriod = parseBasePeriod(periodText);
|
|
650
|
+
const implicitUnit = declinedUnits.find((entry) => entry[2] === periodText)?.[0];
|
|
651
|
+
const implicit = units.find((entry) => entry.unit === implicitUnit);
|
|
652
|
+
const period = Option.isSome(basePeriod) || implicit === void 0 ? basePeriod : Option.some(relativePeriod(implicit.unit, 0, implicit.current));
|
|
531
653
|
if (Option.isSome(period)) {
|
|
532
654
|
const isEnd = textAt(edge.value, 1) === "koniec";
|
|
533
655
|
const canonical = `${isEnd ? "koniec" : "początek"} ${withPeriodCase(period.value.canonical, "genitive")}`;
|
|
@@ -541,7 +663,8 @@ const parsePeriod = (input) => {
|
|
|
541
663
|
"cały ",
|
|
542
664
|
"całe "
|
|
543
665
|
].find((prefix) => input.startsWith(prefix));
|
|
544
|
-
|
|
666
|
+
const base = parseBasePeriod(wrapper === void 0 ? input : input.slice(wrapper.length));
|
|
667
|
+
return Option.isSome(base) ? base : parseCalendarOffset(input);
|
|
545
668
|
};
|
|
546
669
|
const countedUnit = (value) => unitAliases.find((entry) => entry[0] === value)?.[1];
|
|
547
670
|
const countedUnitPattern = "dzień|dni|tydzień|tygodnie|tygodni|miesiąc|miesiące|miesięcy|kwartał|kwartały|kwartałów|rok|lata|lat";
|
|
@@ -573,7 +696,7 @@ const parseCalendarOffset = (input) => {
|
|
|
573
696
|
const direction = Option.isSome(past) ? -amount.value : amount.value;
|
|
574
697
|
const noun = countNoun(amount.value, entry);
|
|
575
698
|
const canonical = direction < 0 ? `${amount.value} ${noun} temu` : `za ${amount.value} ${noun}`;
|
|
576
|
-
return Option.some(
|
|
699
|
+
return Option.some(relativePeriod(unit, direction, canonical));
|
|
577
700
|
};
|
|
578
701
|
const rollingModifier = (amount, future) => {
|
|
579
702
|
if (amount === 1) return future ? "następny" : "ostatni";
|
|
@@ -635,6 +758,7 @@ const boundaries = [
|
|
|
635
758
|
]
|
|
636
759
|
];
|
|
637
760
|
const boundaryCandidate = (input) => {
|
|
761
|
+
if (input.startsWith("do koniec ")) return Option.none();
|
|
638
762
|
const included = String$1.match(/^do (.+) włącznie$/u)(input);
|
|
639
763
|
if (Option.isSome(included)) return parsePeriod(textAt(included.value, 1)).pipe(Option.map((value) => periodBoundaryCandidate(value, "through", `do ${withPeriodCase(value.canonical, "genitive")} włącznie`)));
|
|
640
764
|
for (const [prefix, boundary, canonical] of boundaries) {
|
|
@@ -653,8 +777,6 @@ const parsePolish = (input) => {
|
|
|
653
777
|
"do teraz"
|
|
654
778
|
].includes(input)) return Option.some(candidate(untilNowRange(), "do dziś"));
|
|
655
779
|
if (["od teraz", "od dziś"].includes(input)) return Option.some(candidate(fromNowRange(), "od teraz"));
|
|
656
|
-
const offset = parseCalendarOffset(input);
|
|
657
|
-
if (Option.isSome(offset)) return offset;
|
|
658
780
|
const rolling = parseRollingPeriod(input);
|
|
659
781
|
if (Option.isSome(rolling)) return rolling;
|
|
660
782
|
const toDate = toDatePhrases.find((entry) => entry.phrase === input);
|
|
@@ -677,7 +799,8 @@ const parsePolish = (input) => {
|
|
|
677
799
|
], [
|
|
678
800
|
"od dziś do ",
|
|
679
801
|
"między dziś a ",
|
|
680
|
-
"pomiędzy dziś a "
|
|
802
|
+
"pomiędzy dziś a ",
|
|
803
|
+
"teraz do "
|
|
681
804
|
], parsePeriod, (period) => `od ${period} do dziś`, (period) => `od dziś do ${period}`);
|
|
682
805
|
if (Option.isSome(nowBounded)) return nowBounded;
|
|
683
806
|
const bounded = joinedPeriodCandidate(input, [
|
|
@@ -731,9 +854,12 @@ const staticPeriodPhrases = [
|
|
|
731
854
|
]),
|
|
732
855
|
...months.flatMap((month) => [
|
|
733
856
|
month,
|
|
857
|
+
`poprzedni ${month}`,
|
|
858
|
+
`następny ${month}`,
|
|
734
859
|
`${month} poprzedniego roku`,
|
|
735
860
|
`${month} następnego roku`
|
|
736
|
-
])
|
|
861
|
+
]),
|
|
862
|
+
...nextWeekdays.map((entry) => entry.phrase)
|
|
737
863
|
];
|
|
738
864
|
const staticPeriods = periodsFromPhrases(staticPeriodPhrases, parsePeriod);
|
|
739
865
|
const monthBoundaryPhrases = months.flatMap((_, index) => {
|
|
@@ -800,6 +926,16 @@ const suggestPolish = (input, limit) => {
|
|
|
800
926
|
], limit);
|
|
801
927
|
};
|
|
802
928
|
const renderPolish = (range) => {
|
|
929
|
+
const shifted = decomposeShiftedPeriodRange(range);
|
|
930
|
+
if (Option.isSome(shifted)) {
|
|
931
|
+
const base = renderPolish(shifted.value.baseRange);
|
|
932
|
+
const entry = units.find((unit) => unit.unit === shifted.value.unit);
|
|
933
|
+
if (Option.isSome(base) && entry !== void 0) {
|
|
934
|
+
const amount = Math.abs(shifted.value.amount);
|
|
935
|
+
const noun = countNoun(amount, entry);
|
|
936
|
+
return Option.some(shifted.value.amount < 0 ? `${base.value} ${amount} ${noun} temu` : `${base.value} za ${amount} ${noun}`);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
803
939
|
const offset = calendarPeriodOffset(range);
|
|
804
940
|
if (Option.isSome(offset) && Math.abs(offset.value.amount) > 1) {
|
|
805
941
|
const entry = units.find((unit) => unit.unit === offset.value.unit);
|
|
@@ -830,6 +966,8 @@ const PolishContribution = new BaseLanguageContribution({
|
|
|
830
966
|
locale: "pl",
|
|
831
967
|
vocabulary: [
|
|
832
968
|
...months,
|
|
969
|
+
...weekdays,
|
|
970
|
+
...weekdayGenitives,
|
|
833
971
|
...monthGenitives,
|
|
834
972
|
...monthInstrumentals,
|
|
835
973
|
...monthLocatives,
|
|
@@ -870,8 +1008,8 @@ const PolishContribution = new BaseLanguageContribution({
|
|
|
870
1008
|
"we",
|
|
871
1009
|
"za"
|
|
872
1010
|
],
|
|
873
|
-
normalize:
|
|
874
|
-
correct:
|
|
1011
|
+
normalize: normalizePolish,
|
|
1012
|
+
correct: correctPolish,
|
|
875
1013
|
parseExact: parsePolish,
|
|
876
1014
|
suggest: suggestPolish,
|
|
877
1015
|
render: renderPolish
|
package/dist/locales/shared.mjs
CHANGED
|
@@ -6,6 +6,43 @@ import { NaturalCandidate } from "../language/model.mjs";
|
|
|
6
6
|
import { Match, Option, RegExp as RegExp$1, Schema, String as String$1 } from "effect";
|
|
7
7
|
//#region src/locales/shared.ts
|
|
8
8
|
const textAt = (values, index) => values[index] ?? "";
|
|
9
|
+
const sequentialCountAliases = (words, start) => words.flatMap((aliases, index) => aliases.map((phrase) => [phrase, start + index]));
|
|
10
|
+
const decimalTens = (words) => words.map((word, index) => [20 + index * 10, word]);
|
|
11
|
+
const compoundCountAliases = (tens, ones, join) => tens.flatMap(([tensAmount, tensWord]) => ones.flatMap(([oneAmount, oneWord]) => {
|
|
12
|
+
const amount = tensAmount + oneAmount;
|
|
13
|
+
return join(tensWord, oneWord, amount).map((phrase) => [phrase, amount]);
|
|
14
|
+
}));
|
|
15
|
+
const countAliasVocabulary = (aliases) => [...new Set(aliases.flatMap(([phrase]) => phrase.split(" ")))];
|
|
16
|
+
const compileCountAliasNormalizer = (aliases) => {
|
|
17
|
+
const distinct = /* @__PURE__ */ new Map();
|
|
18
|
+
for (const [phrase, amount] of aliases) if (!distinct.has(phrase)) distinct.set(phrase, amount);
|
|
19
|
+
const byFirstWord = /* @__PURE__ */ new Map();
|
|
20
|
+
for (const [phrase, amount] of distinct) {
|
|
21
|
+
const parts = phrase.split(" ");
|
|
22
|
+
const first = parts[0] ?? "";
|
|
23
|
+
const entries = byFirstWord.get(first) ?? [];
|
|
24
|
+
byFirstWord.set(first, [...entries, {
|
|
25
|
+
amount,
|
|
26
|
+
parts
|
|
27
|
+
}]);
|
|
28
|
+
}
|
|
29
|
+
for (const [first, entries] of byFirstWord) byFirstWord.set(first, [...entries].sort((left, right) => right.parts.length - left.parts.length));
|
|
30
|
+
return (input) => {
|
|
31
|
+
const words = input.split(" ");
|
|
32
|
+
const output = [];
|
|
33
|
+
for (let index = 0; index < words.length;) {
|
|
34
|
+
const alias = (byFirstWord.get(words[index] ?? "") ?? []).find((entry) => entry.parts.every((part, offset) => words[index + offset] === part));
|
|
35
|
+
if (alias === void 0) {
|
|
36
|
+
output.push(words[index] ?? "");
|
|
37
|
+
index += 1;
|
|
38
|
+
} else {
|
|
39
|
+
output.push(String(alias.amount));
|
|
40
|
+
index += alias.parts.length;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return output.join(" ");
|
|
44
|
+
};
|
|
45
|
+
};
|
|
9
46
|
const Period = Schema.Struct({
|
|
10
47
|
start: InstantExpr,
|
|
11
48
|
end: InstantExpr,
|
|
@@ -18,6 +55,22 @@ const isNow = Schema.is(Now);
|
|
|
18
55
|
const isShift = Schema.is(Shift);
|
|
19
56
|
const isStartOf = Schema.is(StartOf);
|
|
20
57
|
const periodRange = (period) => boundedRange(greaterThanOrEqual(period.start), lessThan(period.end));
|
|
58
|
+
const shiftPeriod = (period, amount, unit, canonical) => Period.make({
|
|
59
|
+
start: shift(period.start, amount, unit),
|
|
60
|
+
end: shift(period.end, amount, unit),
|
|
61
|
+
canonical
|
|
62
|
+
});
|
|
63
|
+
const decomposeShiftedPeriodRange = (range) => {
|
|
64
|
+
if (!isGreaterThanOrEqual(range.lower) || !isLessThan(range.upper)) return Option.none();
|
|
65
|
+
const start = range.lower.value;
|
|
66
|
+
const end = range.upper.value;
|
|
67
|
+
if (!isShift(start) || !isShift(end) || start.amount === 0 || start.amount !== end.amount || start.unit !== end.unit) return Option.none();
|
|
68
|
+
return Option.some({
|
|
69
|
+
amount: start.amount,
|
|
70
|
+
unit: start.unit,
|
|
71
|
+
baseRange: boundedRange(greaterThanOrEqual(start.base), lessThan(end.base))
|
|
72
|
+
});
|
|
73
|
+
};
|
|
21
74
|
const periodToDateRange = (unit) => boundedRange(greaterThanOrEqual(startOf(now(), unit)), lessThanOrEqual(now()));
|
|
22
75
|
const fromNowRange = () => lowerOpenRange(greaterThanOrEqual(now()));
|
|
23
76
|
const untilNowRange = () => upperOpenRange(lessThanOrEqual(now()));
|
|
@@ -49,6 +102,16 @@ const periodPreviousDay = (period, canonical) => Period.make({
|
|
|
49
102
|
end: period.start,
|
|
50
103
|
canonical
|
|
51
104
|
});
|
|
105
|
+
const relativeWeekday = (day, direction, canonical) => {
|
|
106
|
+
const weekBase = direction === 0 ? now() : shift(now(), direction, "week");
|
|
107
|
+
const weekStart = startOf(weekBase, "week");
|
|
108
|
+
const start = day === 0 ? weekStart : shift(weekStart, day, "day");
|
|
109
|
+
return Period.make({
|
|
110
|
+
start,
|
|
111
|
+
end: shift(start, 1, "day"),
|
|
112
|
+
canonical
|
|
113
|
+
});
|
|
114
|
+
};
|
|
52
115
|
const relativeWeekend = (direction, canonical) => {
|
|
53
116
|
const weekBase = direction === 0 ? now() : shift(now(), direction, "week");
|
|
54
117
|
const weekStart = startOf(weekBase, "week");
|
|
@@ -392,4 +455,4 @@ const renderPeriodRange = (range, toDate, periods, since, before, through, after
|
|
|
392
455
|
return Option.none();
|
|
393
456
|
};
|
|
394
457
|
//#endregion
|
|
395
|
-
export { Period, absoluteDatePeriod, calendarPeriodOffset, candidate, currentYearDatePeriods, datedPeriods, datedQuarterPeriods, fixedDatePeriod, fixedMonthPeriod, fixedQuarterPeriod, fixedYearPeriod, formatAbsoluteDate, fromNowRange, futurePeriod, futureRange, isoDate, joinedNowCandidate, joinedPeriodCandidate, monthOfRelativeYear, namedCurrentYearDatePeriod, namedDatePeriod, openBoundaryCandidate, parseTrailingCount, periodBoundaryCandidate, periodDay, periodEndDay, periodPreviousDay, periodRange, periodStartDay, periodToDateRange, periodsFromPhrases, quarterOfRelativeYear, relativePeriod, relativeWeekend, remainingPeriodRange, renderPeriodRange, textAt, trailingPeriod, trailingRange, untilNowRange, validYear };
|
|
458
|
+
export { Period, absoluteDatePeriod, calendarPeriodOffset, candidate, compileCountAliasNormalizer, compoundCountAliases, countAliasVocabulary, currentYearDatePeriods, datedPeriods, datedQuarterPeriods, decimalTens, decomposeShiftedPeriodRange, fixedDatePeriod, fixedMonthPeriod, fixedQuarterPeriod, fixedYearPeriod, formatAbsoluteDate, fromNowRange, futurePeriod, futureRange, isoDate, joinedNowCandidate, joinedPeriodCandidate, monthOfRelativeYear, namedCurrentYearDatePeriod, namedDatePeriod, openBoundaryCandidate, parseTrailingCount, periodBoundaryCandidate, periodDay, periodEndDay, periodPreviousDay, periodRange, periodStartDay, periodToDateRange, periodsFromPhrases, quarterOfRelativeYear, relativePeriod, relativeWeekday, relativeWeekend, remainingPeriodRange, renderPeriodRange, sequentialCountAliases, shiftPeriod, textAt, trailingPeriod, trailingRange, untilNowRange, validYear };
|