chronolizer 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,8 +3,8 @@ import { BaseLanguageContribution } from "../language/model.mjs";
3
3
  import { normalizeNaturalText } from "../natural/text.mjs";
4
4
  import { defineLanguagePlugin, languagePluginsLayer } from "../language/registry.mjs";
5
5
  import { correctWhitespaceSeparatedText } from "../natural/correction.mjs";
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";
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";
8
8
  import { Effect, Option, String as String$1 } from "effect";
9
9
  //#region src/locales/pl.ts
10
10
  const months = [
@@ -86,8 +86,8 @@ const units = [
86
86
  current: "dzisiaj",
87
87
  previous: "wczoraj",
88
88
  next: "jutro",
89
- toDate: "dzisiaj do tej pory",
90
- remaining: "reszta dnia"
89
+ toDate: "od początku dnia",
90
+ remaining: "do końca tego dnia"
91
91
  },
92
92
  {
93
93
  unit: "week",
@@ -97,8 +97,8 @@ const units = [
97
97
  current: "ten tydzień",
98
98
  previous: "poprzedni tydzień",
99
99
  next: "następny tydzień",
100
- toDate: "tydzień do dziś",
101
- remaining: "reszta tygodnia"
100
+ toDate: "od początku tygodnia",
101
+ remaining: "do końca tego tygodnia"
102
102
  },
103
103
  {
104
104
  unit: "month",
@@ -108,8 +108,8 @@ const units = [
108
108
  current: "ten miesiąc",
109
109
  previous: "poprzedni miesiąc",
110
110
  next: "następny miesiąc",
111
- toDate: "miesiąc do dziś",
112
- remaining: "reszta miesiąca"
111
+ toDate: "od początku miesiąca",
112
+ remaining: "do końca tego miesiąca"
113
113
  },
114
114
  {
115
115
  unit: "quarter",
@@ -119,8 +119,8 @@ const units = [
119
119
  current: "ten kwartał",
120
120
  previous: "poprzedni kwartał",
121
121
  next: "następny kwartał",
122
- toDate: "kwartał do dziś",
123
- remaining: "reszta kwartału"
122
+ toDate: "od początku kwartału",
123
+ remaining: "do końca tego kwartału"
124
124
  },
125
125
  {
126
126
  unit: "year",
@@ -130,8 +130,8 @@ const units = [
130
130
  current: "ten rok",
131
131
  previous: "poprzedni rok",
132
132
  next: "następny rok",
133
- toDate: "rok do dziś",
134
- remaining: "reszta roku"
133
+ toDate: "od początku roku",
134
+ remaining: "do końca tego roku"
135
135
  }
136
136
  ];
137
137
  const title = (value) => `${value.slice(0, 1).toLocaleUpperCase("pl")}${value.slice(1)}`;
@@ -151,6 +151,64 @@ const unitAliases = [
151
151
  ["lata", "year"],
152
152
  ["lat", "year"]
153
153
  ];
154
+ const declinedUnits = [
155
+ [
156
+ "week",
157
+ "tydzień",
158
+ "tygodnia",
159
+ "tygodniem",
160
+ "tygodniu"
161
+ ],
162
+ [
163
+ "month",
164
+ "miesiąc",
165
+ "miesiąca",
166
+ "miesiącem",
167
+ "miesiącu"
168
+ ],
169
+ [
170
+ "quarter",
171
+ "kwartał",
172
+ "kwartału",
173
+ "kwartałem",
174
+ "kwartale"
175
+ ],
176
+ [
177
+ "year",
178
+ "rok",
179
+ "roku",
180
+ "rokiem",
181
+ "roku"
182
+ ]
183
+ ];
184
+ const relativeAdjectives = [
185
+ [
186
+ 0,
187
+ "ten",
188
+ "tego",
189
+ "tym"
190
+ ],
191
+ [
192
+ -1,
193
+ "poprzedni",
194
+ "poprzedniego",
195
+ "poprzednim"
196
+ ],
197
+ [
198
+ 1,
199
+ "następny",
200
+ "następnego",
201
+ "następnym"
202
+ ]
203
+ ];
204
+ const declinedPeriods = declinedUnits.flatMap(([unit, nominativeNoun, genitiveNoun, instrumentalNoun, locativeNoun]) => relativeAdjectives.map(([direction, nominative, genitive, oblique]) => [
205
+ `${nominative} ${nominativeNoun}`,
206
+ unit,
207
+ direction,
208
+ `${genitive} ${genitiveNoun}`,
209
+ `${oblique} ${instrumentalNoun}`,
210
+ `${oblique} ${locativeNoun}`
211
+ ]));
154
212
  const periodAliases = [
155
213
  ...units.flatMap((entry) => [
156
214
  [
@@ -220,77 +278,55 @@ const periodAliases = [
220
278
  1,
221
279
  "następny rok"
222
280
  ],
281
+ ...declinedPeriods.flatMap(([canonical, unit, direction, genitive, instrumental, locative]) => [
282
+ [
283
+ genitive,
284
+ unit,
285
+ direction,
286
+ canonical
287
+ ],
288
+ [
289
+ instrumental,
290
+ unit,
291
+ direction,
292
+ canonical
293
+ ],
294
+ [
295
+ locative,
296
+ unit,
297
+ direction,
298
+ canonical
299
+ ]
300
+ ]),
223
301
  [
224
- "tego tygodnia",
225
- "week",
226
- 0,
227
- "ten tydzień"
228
- ],
229
- [
230
- "poprzedniego tygodnia",
302
+ "zeszłym tygodniu",
231
303
  "week",
232
304
  -1,
233
305
  "poprzedni tydzień"
234
306
  ],
235
307
  [
236
- "następnego tygodnia",
237
- "week",
238
- 1,
239
- "następny tydzień"
240
- ],
241
- [
242
- "tego miesiąca",
243
- "month",
244
- 0,
245
- "ten miesiąc"
246
- ],
247
- [
248
- "poprzedniego miesiąca",
308
+ "zeszłym miesiącu",
249
309
  "month",
250
310
  -1,
251
311
  "poprzedni miesiąc"
252
312
  ],
253
313
  [
254
- "następnego miesiąca",
255
- "month",
256
- 1,
257
- "następny miesiąc"
258
- ],
259
- [
260
- "tego kwartału",
261
- "quarter",
262
- 0,
263
- "ten kwartał"
264
- ],
265
- [
266
- "poprzedniego kwartału",
314
+ "zeszłym kwartale",
267
315
  "quarter",
268
316
  -1,
269
317
  "poprzedni kwartał"
270
318
  ],
271
319
  [
272
- "następnego kwartału",
273
- "quarter",
274
- 1,
275
- "następny kwartał"
276
- ],
277
- [
278
- "tego roku",
279
- "year",
280
- 0,
281
- "ten rok"
282
- ],
283
- [
284
- "poprzedniego roku",
320
+ "zeszłym roku",
285
321
  "year",
286
322
  -1,
287
323
  "poprzedni rok"
288
324
  ],
289
325
  [
290
- "następnego roku",
291
- "year",
292
- 1,
293
- "następny rok"
326
+ "dziś",
327
+ "day",
328
+ 0,
329
+ "dzisiaj"
294
330
  ],
295
331
  [
296
332
  "przedwczoraj",
@@ -341,21 +377,33 @@ const periodAliases = [
341
377
  "rok po następnym"
342
378
  ]
343
379
  ];
344
- const toDatePhrases = units.flatMap((entry) => {
345
- const yearAliases = entry.unit === "year" ? [
346
- "od początku roku",
347
- "od początku roku do dziś",
348
- "w tym roku do dziś"
349
- ] : [];
350
- return [entry.toDate, ...yearAliases].map((phrase) => ({
380
+ const legacyToDatePhrases = [
381
+ "dzisiaj do tej pory",
382
+ "tydzień do dziś",
383
+ "miesiąc do dziś",
384
+ "kwartał do dziś",
385
+ "rok do dziś"
386
+ ];
387
+ const toDatePhrases = units.flatMap((entry, index) => {
388
+ const aliases = [entry.toDate, textAt(legacyToDatePhrases, index)];
389
+ if (entry.unit === "year") aliases.push("od początku roku do dziś", "w tym roku do dziś");
390
+ return aliases.map((phrase) => ({
391
+ entry,
392
+ phrase
393
+ }));
394
+ });
395
+ const remainingPhrases = units.flatMap((entry) => {
396
+ const implicit = entry.remaining.replace("tego ", "");
397
+ const legacy = entry.remaining.replace("do końca tego", "reszta");
398
+ return [
399
+ entry.remaining,
400
+ implicit,
401
+ legacy
402
+ ].map((phrase) => ({
351
403
  entry,
352
404
  phrase
353
405
  }));
354
406
  });
355
- const remainingPhrases = units.map((entry) => ({
356
- entry,
357
- phrase: entry.remaining
358
- }));
359
407
  const relativeYearDirection = (value) => {
360
408
  if (value.includes("poprzed")) return -1;
361
409
  if (value.includes("następn")) return 1;
@@ -374,23 +422,42 @@ const monthNumber = (value) => {
374
422
  return short === -1 ? void 0 : short + 1;
375
423
  };
376
424
  const dateLabel = (day, month, year) => `${day}. ${textAt(monthGenitives, month - 1)} ${year}`;
425
+ const currentDateLabel = (day, month) => `${day}. ${textAt(monthGenitives, month - 1)}`;
377
426
  const withMonthCase = (value, forms) => {
378
427
  const month = months.findIndex((name) => value.startsWith(title(name)) || value.startsWith(name));
379
428
  if (month === -1) return value;
380
429
  const name = textAt(months, month);
381
430
  return `${textAt(forms, month)}${value.slice(name.length)}`;
382
431
  };
432
+ const periodCaseIndexes = {
433
+ genitive: 3,
434
+ instrumental: 4,
435
+ locative: 5
436
+ };
437
+ const monthCases = {
438
+ genitive: monthGenitives,
439
+ instrumental: monthInstrumentals,
440
+ locative: monthLocatives
441
+ };
442
+ const withPeriodCase = (value, grammaticalCase) => {
443
+ const period = declinedPeriods.find((entry) => entry[0] === value);
444
+ return period === void 0 ? withMonthCase(value, monthCases[grammaticalCase]) : period[periodCaseIndexes[grammaticalCase]];
445
+ };
383
446
  const parseNamedDate = (input) => {
384
447
  const named = String$1.match(/^([0-3]?\d)\.?(?: )([a-ząćęłńóśźż]+\.?) (\d{4})$/u)(input);
385
448
  if (Option.isSome(named)) return namedDatePeriod(textAt(named.value, 3), textAt(named.value, 2), textAt(named.value, 1), monthNumber, dateLabel);
386
449
  const numeric = String$1.match(/^([0-3]?\d)(?:\. ?|[/-])([01]?\d)(?:\. ?|[/-])(\d{4})$/u)(input);
387
- if (Option.isNone(numeric)) return Option.none();
388
- const year = validYear(textAt(numeric.value, 3));
389
- const month = Number(textAt(numeric.value, 2));
390
- const day = Number(textAt(numeric.value, 1));
391
- if (year === void 0 || month < 1 || month > 12) return Option.none();
392
- const value = isoDate(year, month, day);
393
- return isIsoDate(value) && value !== "9999-12-31" ? Option.some(fixedDatePeriod(value, dateLabel(day, month, year))) : Option.none();
450
+ if (Option.isSome(numeric)) {
451
+ const year = validYear(textAt(numeric.value, 3));
452
+ const month = Number(textAt(numeric.value, 2));
453
+ const day = Number(textAt(numeric.value, 1));
454
+ if (year !== void 0 && month >= 1 && month <= 12) {
455
+ const value = isoDate(year, month, day);
456
+ if (isIsoDate(value) && value !== "9999-12-31") return Option.some(fixedDatePeriod(value, dateLabel(day, month, year)));
457
+ }
458
+ }
459
+ const current = String$1.match(/^([0-3]?\d)\.? ([a-ząćęłńóśźż]+\.?)$/u)(input);
460
+ return Option.isSome(current) ? namedCurrentYearDatePeriod(textAt(current.value, 2), textAt(current.value, 1), monthNumber, currentDateLabel) : Option.none();
394
461
  };
395
462
  const quarterNumber = (value) => {
396
463
  if (value.startsWith("q") && value.length === 2) return Number(value.slice(1));
@@ -418,7 +485,8 @@ const parseQuarter = (input) => {
418
485
  return quarter === void 0 ? Option.none() : Option.some(quarterOfRelativeYear(quarter, 0, `Q${quarter}`));
419
486
  };
420
487
  const parseBasePeriod = (input) => {
421
- if (isIsoDate(input) && input !== "9999-12-31") return Option.some(fixedDatePeriod(input, input));
488
+ const absoluteDate = absoluteDatePeriod(input, "pl");
489
+ if (Option.isSome(absoluteDate)) return absoluteDate;
422
490
  const namedDate = parseNamedDate(input);
423
491
  if (Option.isSome(namedDate)) return namedDate;
424
492
  const quarter = parseQuarter(input);
@@ -462,12 +530,13 @@ const parsePeriod = (input) => {
462
530
  const period = parseBasePeriod(textAt(edge.value, 2));
463
531
  if (Option.isSome(period)) {
464
532
  const isEnd = textAt(edge.value, 1) === "koniec";
465
- const canonical = `${isEnd ? "koniec" : "początek"} ${period.value.canonical}`;
533
+ const canonical = `${isEnd ? "koniec" : "początek"} ${withPeriodCase(period.value.canonical, "genitive")}`;
466
534
  return Option.some(isEnd ? periodEndDay(period.value, canonical) : periodStartDay(period.value, canonical));
467
535
  }
468
536
  }
469
537
  const wrapper = [
470
538
  "w ",
539
+ "we ",
471
540
  "przez ",
472
541
  "cały ",
473
542
  "całe "
@@ -477,10 +546,10 @@ const parsePeriod = (input) => {
477
546
  const countedUnit = (value) => unitAliases.find((entry) => entry[0] === value)?.[1];
478
547
  const countedUnitPattern = "dzień|dni|tydzień|tygodnie|tygodni|miesiąc|miesiące|miesięcy|kwartał|kwartały|kwartałów|rok|lata|lat";
479
548
  const countedPattern = (source) => new RegExp(source.replace("UNIT", countedUnitPattern), "u");
480
- const calendarPastPattern = countedPattern("^([1-9]\\d*) (UNIT) temu$");
481
- const calendarFuturePattern = countedPattern("^za ([1-9]\\d*) (UNIT)$");
482
- const rollingPastPatterns = [countedPattern("^(?:ostatni|ostatnie|ostatnich|miniony|minione|minionych) ([1-9]\\d*) (UNIT)$")];
483
- const rollingFuturePatterns = [countedPattern("^(?:następny|następne|następnych|kolejny|kolejne|kolejnych) ([1-9]\\d*) (UNIT)$")];
549
+ const calendarPastPattern = countedPattern("^(?:dokładnie )?(?:([1-9]\\d*) )?(UNIT) temu$");
550
+ const calendarFuturePattern = countedPattern("^za (?:([1-9]\\d*) )?(UNIT)$");
551
+ const rollingPastPatterns = [countedPattern("^(?:ostatni|ostatnie|ostatnich|miniony|minione|minionych) ([1-9]\\d*) (UNIT)$"), countedPattern("^w ciągu (?:ostatniego|ostatnich|minionego|minionych) ([1-9]\\d*) (UNIT)$")];
552
+ const rollingFuturePatterns = [countedPattern("^(?:następny|następne|następnych|kolejny|kolejne|kolejnych) ([1-9]\\d*) (UNIT)$"), countedPattern("^w ciągu (?:najbliższego|najbliższych) ([1-9]\\d*) (UNIT)$")];
484
553
  const rollingBarePattern = countedPattern("^([1-9]\\d*) (UNIT)$");
485
554
  const firstPatternMatch = (input, patterns) => Option.firstSomeOf(patterns.map((pattern) => String$1.match(pattern)(input)));
486
555
  const countNoun = (amount, entry) => {
@@ -494,11 +563,13 @@ const parseCalendarOffset = (input) => {
494
563
  const future = String$1.match(calendarFuturePattern)(input);
495
564
  const match = Option.firstSomeOf([past, future]);
496
565
  if (Option.isNone(match)) return Option.none();
497
- const amount = parseTrailingCount(textAt(match.value, 1));
498
- const unit = countedUnit(textAt(match.value, 2));
566
+ const amountText = textAt(match.value, 1);
567
+ const unitText = textAt(match.value, 2);
568
+ const amount = parseTrailingCount(amountText || "1");
569
+ const unit = countedUnit(unitText);
499
570
  if (Option.isNone(amount) || unit === void 0) return Option.none();
500
571
  const entry = units.find((item) => item.unit === unit);
501
- if (entry === void 0) return Option.none();
572
+ if (entry === void 0 || amountText.length === 0 && unitText !== entry.singular) return Option.none();
502
573
  const direction = Option.isSome(past) ? -amount.value : amount.value;
503
574
  const noun = countNoun(amount.value, entry);
504
575
  const canonical = direction < 0 ? `${amount.value} ${noun} temu` : `za ${amount.value} ${noun}`;
@@ -531,17 +602,47 @@ const parseRollingPeriod = (input) => {
531
602
  const modifier = rollingModifier(amount.value, isFuture);
532
603
  return Option.some(candidate(range, `${modifier} ${amount.value} ${countNoun(amount.value, entry)}`));
533
604
  };
605
+ const boundaries = [
606
+ [
607
+ "do początku ",
608
+ "before",
609
+ (period) => `przed ${withPeriodCase(period, "instrumental")}`
610
+ ],
611
+ [
612
+ "począwszy od ",
613
+ "since",
614
+ (period) => `od ${withPeriodCase(period, "genitive")}`
615
+ ],
616
+ [
617
+ "od ",
618
+ "since",
619
+ (period) => `od ${withPeriodCase(period, "genitive")}`
620
+ ],
621
+ [
622
+ "przed ",
623
+ "before",
624
+ (period) => `przed ${withPeriodCase(period, "instrumental")}`
625
+ ],
626
+ [
627
+ "do ",
628
+ "through",
629
+ (period) => `do ${withPeriodCase(period, "genitive")} włącznie`
630
+ ],
631
+ [
632
+ "po ",
633
+ "after",
634
+ (period) => `po ${withPeriodCase(period, "locative")}`
635
+ ]
636
+ ];
534
637
  const boundaryCandidate = (input) => {
535
638
  const included = String$1.match(/^do (.+) włącznie$/u)(input);
536
- if (Option.isSome(included)) return openBoundaryCandidate(`do ${textAt(included.value, 1)}`, [["do ", "through"]], parsePeriod);
537
- return openBoundaryCandidate(input, [
538
- ["do początku ", "before"],
539
- ["począwszy od ", "since"],
540
- ["od ", "since"],
541
- ["przed ", "before"],
542
- ["do ", "through"],
543
- ["po ", "after"]
544
- ], parsePeriod);
639
+ 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
+ for (const [prefix, boundary, canonical] of boundaries) {
641
+ if (!input.startsWith(prefix)) continue;
642
+ const period = parsePeriod(input.slice(prefix.length));
643
+ if (Option.isSome(period)) return Option.some(periodBoundaryCandidate(period.value, boundary, canonical(period.value.canonical)));
644
+ }
645
+ return Option.none();
545
646
  };
546
647
  const parsePolish = (input) => {
547
648
  const remaining = remainingPhrases.find((entry) => entry.phrase === input);
@@ -558,11 +659,31 @@ const parsePolish = (input) => {
558
659
  if (Option.isSome(rolling)) return rolling;
559
660
  const toDate = toDatePhrases.find((entry) => entry.phrase === input);
560
661
  if (toDate !== void 0) return Option.some(candidate(periodToDateRange(toDate.entry.unit), toDate.entry.toDate));
561
- const nowBounded = joinedNowCandidate(input, [["od ", " do dziś"], ["między ", " a dziś"]], ["od dziś do ", "między dziś a "], parsePeriod, (period) => `od ${period} do dziś`, (period) => `od dziś do ${period}`);
662
+ const elidedDayRange = String$1.match(/^(?:(?:między|pomiędzy) ([0-3]?\d)\.? a |([0-3]?\d)\.?[–—])([0-3]?\d)\.? ([a-ząćęłńóśźż]+\.?)(?: (\d{4}))?$/u)(input);
663
+ if (Option.isSome(elidedDayRange)) {
664
+ const lowerDay = textAt(elidedDayRange.value, 1) || textAt(elidedDayRange.value, 2);
665
+ const upperDay = textAt(elidedDayRange.value, 3);
666
+ const month = textAt(elidedDayRange.value, 4);
667
+ const year = textAt(elidedDayRange.value, 5);
668
+ const suffix = year.length === 0 ? "" : ` ${year}`;
669
+ const expanded = `między ${lowerDay} ${month}${suffix} a ${upperDay} ${month}${suffix}`;
670
+ const joined = joinedPeriodCandidate(expanded, [["między ", " a "], ["pomiędzy ", " a "]], parsePeriod, (lower, upper) => `od ${lower} do ${upper} włącznie`);
671
+ if (Option.isSome(joined)) return joined;
672
+ }
673
+ const nowBounded = joinedNowCandidate(input, [
674
+ ["od ", " do dziś"],
675
+ ["między ", " a dziś"],
676
+ ["pomiędzy ", " a dziś"]
677
+ ], [
678
+ "od dziś do ",
679
+ "między dziś a ",
680
+ "pomiędzy dziś a "
681
+ ], parsePeriod, (period) => `od ${period} do dziś`, (period) => `od dziś do ${period}`);
562
682
  if (Option.isSome(nowBounded)) return nowBounded;
563
683
  const bounded = joinedPeriodCandidate(input, [
564
684
  ["od ", " do "],
565
685
  ["między ", " a "],
686
+ ["pomiędzy ", " a "],
566
687
  ["", " - "],
567
688
  ["", " – "],
568
689
  ["", " — "]
@@ -570,16 +691,33 @@ const parsePolish = (input) => {
570
691
  if (Option.isSome(bounded)) return bounded;
571
692
  const boundary = boundaryCandidate(input);
572
693
  if (Option.isSome(boundary)) return boundary;
573
- return Option.map(parsePeriod(input), (period) => candidate(periodRange(period), period.canonical));
694
+ return parsePeriod(input).pipe(Option.map((period) => candidate(periodRange(period), period.canonical)));
574
695
  };
575
- const staticPeriodPhrases = [
576
- ...periodAliases.map((entry) => entry[0]),
696
+ const edgePhrases = [...declinedPeriods.map((entry) => entry[3]), ...monthGenitives].flatMap((phrase) => [`początek ${phrase}`, `koniec ${phrase}`]);
697
+ const canonicalPeriodPhrases = [
698
+ ...units.flatMap((entry) => [
699
+ entry.current,
700
+ entry.previous,
701
+ entry.next
702
+ ]),
703
+ "przedwczoraj",
704
+ "pojutrze",
705
+ "przedostatni tydzień",
706
+ "tydzień po następnym",
707
+ "przedostatni miesiąc",
708
+ "miesiąc po następnym",
709
+ "przedostatni rok",
710
+ "rok po następnym",
577
711
  "ten weekend",
578
712
  "poprzedni weekend",
579
713
  "następny weekend",
580
714
  "weekend przed poprzednim",
581
- "weekend po następnym",
582
- ...periodAliases.flatMap((entry) => [`początek ${entry[0]}`, `koniec ${entry[0]}`]),
715
+ "weekend po następnym"
716
+ ];
717
+ const staticPeriodPhrases = [
718
+ ...periodAliases.map((entry) => entry[0]),
719
+ ...canonicalPeriodPhrases,
720
+ ...edgePhrases,
583
721
  ...[
584
722
  1,
585
723
  2,
@@ -598,13 +736,24 @@ const staticPeriodPhrases = [
598
736
  ])
599
737
  ];
600
738
  const staticPeriods = periodsFromPhrases(staticPeriodPhrases, parsePeriod);
601
- const boundaryPrefixes = [
602
- "od ",
603
- "począwszy od ",
604
- "przed ",
605
- "do ",
606
- "po "
607
- ];
739
+ const monthBoundaryPhrases = months.flatMap((_, index) => {
740
+ const genitive = textAt(monthGenitives, index);
741
+ const instrumental = textAt(monthInstrumentals, index);
742
+ const locative = textAt(monthLocatives, index);
743
+ return [
744
+ `od ${genitive}`,
745
+ `począwszy od ${genitive}`,
746
+ `przed ${instrumental}`,
747
+ `do ${genitive} włącznie`,
748
+ `po ${locative}`
749
+ ];
750
+ });
751
+ const fixedBoundaryPhrases = (phrases) => phrases.flatMap((phrase) => [
752
+ `od ${withMonthCase(phrase, monthGenitives)}`,
753
+ `przed ${withMonthCase(phrase, monthInstrumentals)}`,
754
+ `do ${withMonthCase(phrase, monthGenitives)} włącznie`,
755
+ `po ${withMonthCase(phrase, monthLocatives)}`
756
+ ]);
608
757
  const countedSuggestions = (input) => {
609
758
  const amount = naturalCount(input);
610
759
  if (amount === void 0) return [];
@@ -620,20 +769,34 @@ const countedSuggestions = (input) => {
620
769
  });
621
770
  };
622
771
  const polishSuggestionPhrases = [
623
- ...units.map((entry) => entry.toDate),
624
- ...units.map((entry) => entry.remaining),
625
- ...staticPeriodPhrases,
626
- ...prefixNaturalPhrases(staticPeriodPhrases, boundaryPrefixes),
772
+ ...toDatePhrases.map((entry) => entry.phrase),
773
+ ...remainingPhrases.map((entry) => entry.phrase),
774
+ ...canonicalPeriodPhrases,
775
+ ...edgePhrases,
776
+ ...[
777
+ 1,
778
+ 2,
779
+ 3,
780
+ 4
781
+ ].flatMap((quarter) => [
782
+ `q${quarter}`,
783
+ `q${quarter} tego roku`,
784
+ `q${quarter} poprzedniego roku`,
785
+ `q${quarter} następnego roku`
786
+ ]),
787
+ ...months,
788
+ ...monthBoundaryPhrases,
627
789
  "do dziś",
628
790
  "od teraz"
629
791
  ];
630
792
  const suggestPolish = (input, limit) => {
631
- const fixed = fixedCalendarPeriodPhrases(input, months);
632
- return completeNaturalPhrases(input, [
793
+ const correctedInput = input.startsWith("do koniec") ? `do końca${input.slice(9)}` : input;
794
+ const fixed = fixedCalendarPeriodPhrases(correctedInput, months);
795
+ return completeNaturalPhrases(correctedInput, [
633
796
  ...polishSuggestionPhrases,
634
797
  ...fixed,
635
- ...prefixNaturalPhrases(fixed, boundaryPrefixes),
636
- ...countedSuggestions(input)
798
+ ...fixedBoundaryPhrases(fixed),
799
+ ...countedSuggestions(correctedInput)
637
800
  ], limit);
638
801
  };
639
802
  const renderPolish = (range) => {
@@ -656,8 +819,12 @@ const renderPolish = (range) => {
656
819
  const entry = units.find((unit) => unit.unit === trailing.value.unit);
657
820
  if (entry !== void 0) return Option.some(`${rollingModifier(trailing.value.amount, false)} ${trailing.value.amount} ${countNoun(trailing.value.amount, entry)}`);
658
821
  }
659
- const periods = [...staticPeriods, ...periodsFromPhrases([...datedPeriods(range, months), ...datedQuarterPeriods(range)], parsePeriod)];
660
- return renderPeriodRange(range, [...units.map((entry) => candidate(periodToDateRange(entry.unit), entry.toDate)), ...units.map((entry) => candidate(remainingPeriodRange(entry.unit), entry.remaining))], periods, (period) => `od ${withMonthCase(period, monthGenitives)}`, (period) => `przed ${withMonthCase(period, monthInstrumentals)}`, (period) => `do ${withMonthCase(period, monthGenitives)} włącznie`, (period) => `po ${withMonthCase(period, monthLocatives)}`, (lower, upper) => `od ${withMonthCase(lower, monthGenitives)} do ${withMonthCase(upper, monthGenitives)} włącznie`, (period) => `od ${withMonthCase(period, monthGenitives)} do dziś`, (period) => `od dziś do ${withMonthCase(period, monthGenitives)}`, () => "do dziś", () => "od teraz");
822
+ const periods = [
823
+ ...staticPeriods,
824
+ ...currentYearDatePeriods(range, currentDateLabel),
825
+ ...periodsFromPhrases([...datedPeriods(range, months), ...datedQuarterPeriods(range)], parsePeriod)
826
+ ];
827
+ return renderPeriodRange(range, [...units.map((entry) => candidate(periodToDateRange(entry.unit), entry.toDate)), ...units.map((entry) => candidate(remainingPeriodRange(entry.unit), entry.remaining))], periods, (period) => `od ${withPeriodCase(period, "genitive")}`, (period) => `przed ${withPeriodCase(period, "instrumental")}`, (period) => `do ${withPeriodCase(period, "genitive")} włącznie`, (period) => `po ${withPeriodCase(period, "locative")}`, (lower, upper) => `od ${withPeriodCase(lower, "genitive")} do ${withPeriodCase(upper, "genitive")} włącznie`, (period) => `od ${withPeriodCase(period, "genitive")} do dziś`, (period) => `od dziś do ${withPeriodCase(period, "genitive")}`, () => "do dziś", () => "od teraz");
661
828
  };
662
829
  const PolishContribution = new BaseLanguageContribution({
663
830
  locale: "pl",
@@ -677,23 +844,30 @@ const PolishContribution = new BaseLanguageContribution({
677
844
  ]),
678
845
  ...toDatePhrases.flatMap((entry) => entry.phrase.split(" ")),
679
846
  ...remainingPhrases.flatMap((entry) => entry.phrase.split(" ")),
847
+ ...periodAliases.flatMap((entry) => entry[0].split(" ")),
848
+ "ciągu",
849
+ "dokładnie",
680
850
  "dziś",
681
851
  "dotychczas",
682
852
  "koniec",
853
+ "końca",
683
854
  "kolejne",
684
855
  "między",
685
856
  "minione",
857
+ "najbliższych",
686
858
  "następne",
687
859
  "od",
688
860
  "ostatnie",
689
861
  "po",
690
862
  "początek",
691
863
  "począwszy",
864
+ "pomiędzy",
692
865
  "poprzedni",
693
866
  "przed",
694
867
  "teraz",
695
868
  "temu",
696
869
  "włącznie",
870
+ "we",
697
871
  "za"
698
872
  ],
699
873
  normalize: normalizeNaturalText,