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/de.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, 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/de.ts
|
|
10
9
|
const months = [
|
|
@@ -21,10 +20,63 @@ const months = [
|
|
|
21
20
|
"november",
|
|
22
21
|
"dezember"
|
|
23
22
|
];
|
|
23
|
+
const minimumMonthDays = [
|
|
24
|
+
31,
|
|
25
|
+
28,
|
|
26
|
+
31,
|
|
27
|
+
30,
|
|
28
|
+
31,
|
|
29
|
+
30,
|
|
30
|
+
31,
|
|
31
|
+
31,
|
|
32
|
+
30,
|
|
33
|
+
31,
|
|
34
|
+
30,
|
|
35
|
+
31
|
|
36
|
+
];
|
|
37
|
+
const germanCountWords = [
|
|
38
|
+
"zwei",
|
|
39
|
+
"drei",
|
|
40
|
+
"vier",
|
|
41
|
+
"fünf",
|
|
42
|
+
"sechs",
|
|
43
|
+
"sieben",
|
|
44
|
+
"acht",
|
|
45
|
+
"neun",
|
|
46
|
+
"zehn",
|
|
47
|
+
"elf",
|
|
48
|
+
"zwölf",
|
|
49
|
+
"dreizehn",
|
|
50
|
+
"vierzehn",
|
|
51
|
+
"fünfzehn",
|
|
52
|
+
"sechzehn",
|
|
53
|
+
"siebzehn",
|
|
54
|
+
"achtzehn",
|
|
55
|
+
"neunzehn",
|
|
56
|
+
"zwanzig"
|
|
57
|
+
];
|
|
58
|
+
const germanCountOnes = [[1, "ein"], ...germanCountWords.slice(0, 8).map((word, index) => [index + 2, word])];
|
|
59
|
+
const germanCountAliases = [...sequentialCountAliases(germanCountWords.map((word) => [word]), 2), ...compoundCountAliases(decimalTens([
|
|
60
|
+
"zwanzig",
|
|
61
|
+
"dreißig",
|
|
62
|
+
"vierzig",
|
|
63
|
+
"fünfzig",
|
|
64
|
+
"sechzig",
|
|
65
|
+
"siebzig",
|
|
66
|
+
"achtzig",
|
|
67
|
+
"neunzig"
|
|
68
|
+
]), germanCountOnes, (ten, one) => [`${one}und${ten}`])];
|
|
69
|
+
const normalizeGermanCounts = compileCountAliasNormalizer(germanCountAliases);
|
|
70
|
+
const germanCountVocabulary = new Set(countAliasVocabulary(germanCountAliases));
|
|
71
|
+
const correctGerman = (input, vocabulary) => correctWhitespaceSeparatedText(input, vocabulary, germanCountVocabulary);
|
|
24
72
|
const monthAbbreviations = [
|
|
25
73
|
["jan"],
|
|
26
74
|
["feb"],
|
|
27
|
-
[
|
|
75
|
+
[
|
|
76
|
+
"mär",
|
|
77
|
+
"mrz",
|
|
78
|
+
"maerz"
|
|
79
|
+
],
|
|
28
80
|
["apr"],
|
|
29
81
|
["mai"],
|
|
30
82
|
["jun"],
|
|
@@ -118,6 +170,24 @@ const unitPhrases = [
|
|
|
118
170
|
}
|
|
119
171
|
];
|
|
120
172
|
const title = (value) => `${value.slice(0, 1).toLocaleUpperCase("de")}${value.slice(1)}`;
|
|
173
|
+
const weekdays = [
|
|
174
|
+
"montag",
|
|
175
|
+
"dienstag",
|
|
176
|
+
"mittwoch",
|
|
177
|
+
"donnerstag",
|
|
178
|
+
"freitag",
|
|
179
|
+
"samstag",
|
|
180
|
+
"sonntag"
|
|
181
|
+
];
|
|
182
|
+
const nextWeekdays = weekdays.flatMap((weekday, day) => [{
|
|
183
|
+
phrase: `nächster ${weekday}`,
|
|
184
|
+
day,
|
|
185
|
+
canonical: `nächster ${title(weekday)}`
|
|
186
|
+
}, {
|
|
187
|
+
phrase: `nächsten ${weekday}`,
|
|
188
|
+
day,
|
|
189
|
+
canonical: `nächster ${title(weekday)}`
|
|
190
|
+
}]);
|
|
121
191
|
const canonicalToDate = (entry) => `seit ${title(entry.compound)}beginn`;
|
|
122
192
|
const canonicalRelative = (value) => {
|
|
123
193
|
const separator = value.lastIndexOf(" ");
|
|
@@ -161,390 +231,45 @@ const currentBoundaryPhrases = unitPhrases.flatMap((entry) => [
|
|
|
161
231
|
entry,
|
|
162
232
|
phrase
|
|
163
233
|
})));
|
|
164
|
-
const
|
|
165
|
-
[
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
],
|
|
172
|
-
[
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
"letzte woche"
|
|
178
|
-
],
|
|
179
|
-
[
|
|
180
|
-
"nächste woche",
|
|
181
|
-
"week",
|
|
182
|
-
1,
|
|
183
|
-
"nächster woche",
|
|
184
|
-
"nächste woche"
|
|
185
|
-
],
|
|
186
|
-
[
|
|
187
|
-
"dieser monat",
|
|
188
|
-
"month",
|
|
189
|
-
0,
|
|
190
|
-
"diesem monat",
|
|
191
|
-
"diesen monat"
|
|
192
|
-
],
|
|
193
|
-
[
|
|
194
|
-
"letzter monat",
|
|
195
|
-
"month",
|
|
196
|
-
-1,
|
|
197
|
-
"letztem monat",
|
|
198
|
-
"letzten monat"
|
|
199
|
-
],
|
|
200
|
-
[
|
|
201
|
-
"nächster monat",
|
|
202
|
-
"month",
|
|
203
|
-
1,
|
|
204
|
-
"nächstem monat",
|
|
205
|
-
"nächsten monat"
|
|
206
|
-
],
|
|
207
|
-
[
|
|
208
|
-
"dieses quartal",
|
|
209
|
-
"quarter",
|
|
210
|
-
0,
|
|
211
|
-
"diesem quartal",
|
|
212
|
-
"dieses quartal"
|
|
213
|
-
],
|
|
214
|
-
[
|
|
215
|
-
"letztes quartal",
|
|
216
|
-
"quarter",
|
|
217
|
-
-1,
|
|
218
|
-
"letztem quartal",
|
|
219
|
-
"letztes quartal"
|
|
220
|
-
],
|
|
221
|
-
[
|
|
222
|
-
"nächstes quartal",
|
|
223
|
-
"quarter",
|
|
224
|
-
1,
|
|
225
|
-
"nächstem quartal",
|
|
226
|
-
"nächstes quartal"
|
|
227
|
-
],
|
|
228
|
-
[
|
|
229
|
-
"dieses jahr",
|
|
230
|
-
"year",
|
|
231
|
-
0,
|
|
232
|
-
"diesem jahr",
|
|
233
|
-
"dieses jahr"
|
|
234
|
-
],
|
|
235
|
-
[
|
|
236
|
-
"letztes jahr",
|
|
237
|
-
"year",
|
|
238
|
-
-1,
|
|
239
|
-
"letztem jahr",
|
|
240
|
-
"letztes jahr"
|
|
241
|
-
],
|
|
242
|
-
[
|
|
243
|
-
"nächstes jahr",
|
|
244
|
-
"year",
|
|
245
|
-
1,
|
|
246
|
-
"nächstem jahr",
|
|
247
|
-
"nächstes jahr"
|
|
248
|
-
]
|
|
249
|
-
];
|
|
250
|
-
const relativeAliases = [
|
|
251
|
-
...unitPhrases.flatMap((entry) => [
|
|
252
|
-
[
|
|
253
|
-
entry.currentGenitive,
|
|
254
|
-
entry.unit,
|
|
255
|
-
0,
|
|
256
|
-
entry.current
|
|
257
|
-
],
|
|
258
|
-
[
|
|
259
|
-
entry.previousGenitive,
|
|
260
|
-
entry.unit,
|
|
261
|
-
-1,
|
|
262
|
-
entry.previous
|
|
263
|
-
],
|
|
264
|
-
[
|
|
265
|
-
entry.nextGenitive,
|
|
266
|
-
entry.unit,
|
|
267
|
-
1,
|
|
268
|
-
entry.next
|
|
269
|
-
]
|
|
270
|
-
]),
|
|
271
|
-
...declinedBoundaryPeriods.map(([canonical, unit, direction, dative]) => [
|
|
272
|
-
dative,
|
|
273
|
-
unit,
|
|
274
|
-
direction,
|
|
275
|
-
canonical
|
|
276
|
-
]),
|
|
277
|
-
[
|
|
278
|
-
"vorgestern",
|
|
279
|
-
"day",
|
|
280
|
-
-2,
|
|
281
|
-
"vorgestern"
|
|
282
|
-
],
|
|
283
|
-
[
|
|
284
|
-
"vorletzten tag",
|
|
285
|
-
"day",
|
|
286
|
-
-2,
|
|
287
|
-
"vorletzter tag"
|
|
288
|
-
],
|
|
289
|
-
[
|
|
290
|
-
"übernächsten tag",
|
|
291
|
-
"day",
|
|
292
|
-
2,
|
|
293
|
-
"übernächster tag"
|
|
294
|
-
],
|
|
295
|
-
[
|
|
296
|
-
"vorletzte woche",
|
|
297
|
-
"week",
|
|
298
|
-
-2,
|
|
299
|
-
"vorletzte woche"
|
|
300
|
-
],
|
|
301
|
-
[
|
|
302
|
-
"übernächste woche",
|
|
303
|
-
"week",
|
|
304
|
-
2,
|
|
305
|
-
"übernächste woche"
|
|
306
|
-
],
|
|
307
|
-
[
|
|
308
|
-
"vorletzten monat",
|
|
309
|
-
"month",
|
|
310
|
-
-2,
|
|
311
|
-
"vorletzter monat"
|
|
312
|
-
],
|
|
313
|
-
[
|
|
314
|
-
"übernächsten monat",
|
|
315
|
-
"month",
|
|
316
|
-
2,
|
|
317
|
-
"übernächster monat"
|
|
318
|
-
],
|
|
319
|
-
[
|
|
320
|
-
"vorletztes quartal",
|
|
321
|
-
"quarter",
|
|
322
|
-
-2,
|
|
323
|
-
"vorletztes quartal"
|
|
324
|
-
],
|
|
325
|
-
[
|
|
326
|
-
"übernächstes quartal",
|
|
327
|
-
"quarter",
|
|
328
|
-
2,
|
|
329
|
-
"übernächstes quartal"
|
|
330
|
-
],
|
|
331
|
-
[
|
|
332
|
-
"vorletztes jahr",
|
|
333
|
-
"year",
|
|
334
|
-
-2,
|
|
335
|
-
"vorletztes jahr"
|
|
336
|
-
],
|
|
337
|
-
[
|
|
338
|
-
"übernächstes jahr",
|
|
339
|
-
"year",
|
|
340
|
-
2,
|
|
341
|
-
"übernächstes jahr"
|
|
342
|
-
],
|
|
343
|
-
[
|
|
344
|
-
"letzten tag",
|
|
345
|
-
"day",
|
|
346
|
-
-1,
|
|
347
|
-
"gestern"
|
|
348
|
-
],
|
|
349
|
-
[
|
|
350
|
-
"vergangenen tag",
|
|
351
|
-
"day",
|
|
352
|
-
-1,
|
|
353
|
-
"gestern"
|
|
354
|
-
],
|
|
355
|
-
[
|
|
356
|
-
"vorherigen tag",
|
|
357
|
-
"day",
|
|
358
|
-
-1,
|
|
359
|
-
"gestern"
|
|
360
|
-
],
|
|
361
|
-
[
|
|
362
|
-
"diesen tag",
|
|
363
|
-
"day",
|
|
364
|
-
0,
|
|
365
|
-
"heute"
|
|
366
|
-
],
|
|
367
|
-
[
|
|
368
|
-
"heutigen tag",
|
|
369
|
-
"day",
|
|
370
|
-
0,
|
|
371
|
-
"heute"
|
|
372
|
-
],
|
|
373
|
-
[
|
|
374
|
-
"nächsten tag",
|
|
375
|
-
"day",
|
|
376
|
-
1,
|
|
377
|
-
"morgen"
|
|
378
|
-
],
|
|
379
|
-
[
|
|
380
|
-
"kommenden tag",
|
|
381
|
-
"day",
|
|
382
|
-
1,
|
|
383
|
-
"morgen"
|
|
384
|
-
],
|
|
385
|
-
[
|
|
386
|
-
"vergangene woche",
|
|
387
|
-
"week",
|
|
388
|
-
-1,
|
|
389
|
-
"letzte woche"
|
|
390
|
-
],
|
|
391
|
-
[
|
|
392
|
-
"vorherige woche",
|
|
393
|
-
"week",
|
|
394
|
-
-1,
|
|
395
|
-
"letzte woche"
|
|
396
|
-
],
|
|
397
|
-
[
|
|
398
|
-
"aktuelle woche",
|
|
399
|
-
"week",
|
|
400
|
-
0,
|
|
401
|
-
"diese woche"
|
|
402
|
-
],
|
|
403
|
-
[
|
|
404
|
-
"laufende woche",
|
|
405
|
-
"week",
|
|
406
|
-
0,
|
|
407
|
-
"diese woche"
|
|
408
|
-
],
|
|
409
|
-
[
|
|
410
|
-
"kommende woche",
|
|
411
|
-
"week",
|
|
412
|
-
1,
|
|
413
|
-
"nächste woche"
|
|
414
|
-
],
|
|
415
|
-
[
|
|
416
|
-
"folgende woche",
|
|
417
|
-
"week",
|
|
418
|
-
1,
|
|
419
|
-
"nächste woche"
|
|
420
|
-
],
|
|
421
|
-
[
|
|
422
|
-
"letzten monat",
|
|
423
|
-
"month",
|
|
424
|
-
-1,
|
|
425
|
-
"letzter monat"
|
|
426
|
-
],
|
|
427
|
-
[
|
|
428
|
-
"vergangenen monat",
|
|
429
|
-
"month",
|
|
430
|
-
-1,
|
|
431
|
-
"letzter monat"
|
|
432
|
-
],
|
|
433
|
-
[
|
|
434
|
-
"vorherigen monat",
|
|
435
|
-
"month",
|
|
436
|
-
-1,
|
|
437
|
-
"letzter monat"
|
|
438
|
-
],
|
|
439
|
-
[
|
|
440
|
-
"diesen monat",
|
|
441
|
-
"month",
|
|
442
|
-
0,
|
|
443
|
-
"dieser monat"
|
|
444
|
-
],
|
|
445
|
-
[
|
|
446
|
-
"aktuellen monat",
|
|
447
|
-
"month",
|
|
448
|
-
0,
|
|
449
|
-
"dieser monat"
|
|
450
|
-
],
|
|
451
|
-
[
|
|
452
|
-
"laufenden monat",
|
|
453
|
-
"month",
|
|
454
|
-
0,
|
|
455
|
-
"dieser monat"
|
|
456
|
-
],
|
|
457
|
-
[
|
|
458
|
-
"nächsten monat",
|
|
459
|
-
"month",
|
|
460
|
-
1,
|
|
461
|
-
"nächster monat"
|
|
462
|
-
],
|
|
463
|
-
[
|
|
464
|
-
"kommenden monat",
|
|
465
|
-
"month",
|
|
466
|
-
1,
|
|
467
|
-
"nächster monat"
|
|
468
|
-
],
|
|
469
|
-
[
|
|
470
|
-
"folgenden monat",
|
|
471
|
-
"month",
|
|
472
|
-
1,
|
|
473
|
-
"nächster monat"
|
|
474
|
-
],
|
|
475
|
-
[
|
|
476
|
-
"vergangenes quartal",
|
|
477
|
-
"quarter",
|
|
478
|
-
-1,
|
|
479
|
-
"letztes quartal"
|
|
480
|
-
],
|
|
481
|
-
[
|
|
482
|
-
"vorheriges quartal",
|
|
483
|
-
"quarter",
|
|
484
|
-
-1,
|
|
485
|
-
"letztes quartal"
|
|
486
|
-
],
|
|
487
|
-
[
|
|
488
|
-
"aktuelles quartal",
|
|
489
|
-
"quarter",
|
|
490
|
-
0,
|
|
491
|
-
"dieses quartal"
|
|
492
|
-
],
|
|
493
|
-
[
|
|
494
|
-
"laufendes quartal",
|
|
495
|
-
"quarter",
|
|
496
|
-
0,
|
|
497
|
-
"dieses quartal"
|
|
498
|
-
],
|
|
499
|
-
[
|
|
500
|
-
"kommendes quartal",
|
|
501
|
-
"quarter",
|
|
502
|
-
1,
|
|
503
|
-
"nächstes quartal"
|
|
504
|
-
],
|
|
505
|
-
[
|
|
506
|
-
"folgendes quartal",
|
|
507
|
-
"quarter",
|
|
508
|
-
1,
|
|
509
|
-
"nächstes quartal"
|
|
510
|
-
],
|
|
511
|
-
[
|
|
512
|
-
"vergangenes jahr",
|
|
513
|
-
"year",
|
|
514
|
-
-1,
|
|
515
|
-
"letztes jahr"
|
|
516
|
-
],
|
|
517
|
-
[
|
|
518
|
-
"vorheriges jahr",
|
|
519
|
-
"year",
|
|
520
|
-
-1,
|
|
521
|
-
"letztes jahr"
|
|
522
|
-
],
|
|
523
|
-
[
|
|
524
|
-
"aktuelles jahr",
|
|
525
|
-
"year",
|
|
526
|
-
0,
|
|
527
|
-
"dieses jahr"
|
|
528
|
-
],
|
|
529
|
-
[
|
|
530
|
-
"laufendes jahr",
|
|
531
|
-
"year",
|
|
532
|
-
0,
|
|
533
|
-
"dieses jahr"
|
|
534
|
-
],
|
|
535
|
-
[
|
|
536
|
-
"kommendes jahr",
|
|
537
|
-
"year",
|
|
538
|
-
1,
|
|
539
|
-
"nächstes jahr"
|
|
540
|
-
],
|
|
541
|
-
[
|
|
542
|
-
"folgendes jahr",
|
|
543
|
-
"year",
|
|
544
|
-
1,
|
|
545
|
-
"nächstes jahr"
|
|
546
|
-
]
|
|
234
|
+
const relativeModifierStems = [
|
|
235
|
+
["vorletzt", -2],
|
|
236
|
+
["übernächst", 2],
|
|
237
|
+
["vergangen", -1],
|
|
238
|
+
["vorherig", -1],
|
|
239
|
+
["letzt", -1],
|
|
240
|
+
["heutig", 0],
|
|
241
|
+
["dies", 0],
|
|
242
|
+
["aktuell", 0],
|
|
243
|
+
["laufend", 0],
|
|
244
|
+
["nächst", 1],
|
|
245
|
+
["kommend", 1],
|
|
246
|
+
["folgend", 1]
|
|
547
247
|
];
|
|
248
|
+
const relativeModifierVocabulary = relativeModifierStems.flatMap(([stem]) => [
|
|
249
|
+
"e",
|
|
250
|
+
"er",
|
|
251
|
+
"es",
|
|
252
|
+
"en",
|
|
253
|
+
"em"
|
|
254
|
+
].map((ending) => `${stem}${ending}`));
|
|
255
|
+
const relativeUnitCanonical = (entry, direction) => {
|
|
256
|
+
if (direction === -1) return entry.previous;
|
|
257
|
+
if (direction === 0) return entry.current;
|
|
258
|
+
if (direction === 1) return entry.next;
|
|
259
|
+
return `${direction < 0 ? "vor" : "in"} 2 ${title(entry.dative)}`;
|
|
260
|
+
};
|
|
261
|
+
const parseModifiedUnit = (input) => {
|
|
262
|
+
const match = String$1.match(/^([a-zäöüß]+) ([a-zäöüß]+)$/u)(input);
|
|
263
|
+
if (Option.isNone(match)) return Option.none();
|
|
264
|
+
const modifier = relativeModifierStems.find(([stem]) => textAt(match.value, 1).startsWith(stem));
|
|
265
|
+
const entry = unitPhrases.find((unit) => [
|
|
266
|
+
unit.noun,
|
|
267
|
+
unit.plural,
|
|
268
|
+
unit.dative,
|
|
269
|
+
unit.compound
|
|
270
|
+
].includes(textAt(match.value, 2)));
|
|
271
|
+
return modifier === void 0 || entry === void 0 ? Option.none() : Option.some(relativePeriod(entry.unit, modifier[1], canonicalRelative(relativeUnitCanonical(entry, modifier[1]))));
|
|
272
|
+
};
|
|
548
273
|
const monthNumber = (value) => {
|
|
549
274
|
const normalized = value.endsWith(".") ? value.slice(0, -1) : value;
|
|
550
275
|
const fullIndex = months.findIndex((month) => month === normalized);
|
|
@@ -552,11 +277,26 @@ const monthNumber = (value) => {
|
|
|
552
277
|
const shortIndex = monthAbbreviations.findIndex((aliases) => aliases.some((alias) => alias === normalized));
|
|
553
278
|
return shortIndex === -1 ? void 0 : shortIndex + 1;
|
|
554
279
|
};
|
|
280
|
+
const normalizeGerman = (input, locale) => {
|
|
281
|
+
const normalized = normalizeGermanCounts(normalizeNaturalText(input, locale));
|
|
282
|
+
if (normalized.endsWith(" auflaufend")) return `seit ${normalized.slice(0, -11)}`;
|
|
283
|
+
const fullMonth = String$1.match(/^(?:([a-zäöüß]+\.?) per )?(?:(0?1)\.-)?([0-3]?\d)\.([01]?\d)\.?$/u)(normalized);
|
|
284
|
+
if (Option.isNone(fullMonth)) return normalized;
|
|
285
|
+
const named = textAt(fullMonth.value, 1);
|
|
286
|
+
const lower = textAt(fullMonth.value, 2);
|
|
287
|
+
if (named.length === 0 && lower.length === 0) return normalized;
|
|
288
|
+
const numericMonth = Number(textAt(fullMonth.value, 4));
|
|
289
|
+
const month = named.length === 0 ? numericMonth : monthNumber(named);
|
|
290
|
+
return month !== void 0 && month === numericMonth && Number(textAt(fullMonth.value, 3)) === minimumMonthDays[month - 1] ? textAt(months, month - 1) : normalized;
|
|
291
|
+
};
|
|
555
292
|
const currentDateLabel = (day, month) => `${day}. ${title(textAt(months, month - 1))}`;
|
|
556
293
|
const withRelativeCase = (canonical, grammaticalCase) => {
|
|
557
|
-
const
|
|
558
|
-
if (
|
|
559
|
-
|
|
294
|
+
const separator = canonical.indexOf(" ");
|
|
295
|
+
if (separator === -1) return canonical;
|
|
296
|
+
const modifier = canonical.slice(0, separator);
|
|
297
|
+
if (!relativeModifierStems.some(([stem]) => modifier.startsWith(stem))) return canonical;
|
|
298
|
+
if (grammaticalCase === "dative") return `${modifier.endsWith("e") ? `${modifier}r` : `${modifier.slice(0, -2)}em`}${canonical.slice(separator)}`;
|
|
299
|
+
return `${modifier.endsWith("er") ? `${modifier.slice(0, -2)}en` : modifier}${canonical.slice(separator)}`;
|
|
560
300
|
};
|
|
561
301
|
const withRelativeGenitive = (canonical) => {
|
|
562
302
|
for (const entry of unitPhrases) {
|
|
@@ -570,15 +310,7 @@ const parseNamedDate = (input) => {
|
|
|
570
310
|
const named = String$1.match(/^([0-3]?\d)\.? ([a-zäöüß]+\.?) (\d{4})$/u)(input);
|
|
571
311
|
if (Option.isSome(named)) return namedDatePeriod(textAt(named.value, 3), textAt(named.value, 2), textAt(named.value, 1), monthNumber, (day, month, year) => `${day}. ${title(textAt(months, month - 1))} ${year}`);
|
|
572
312
|
const numeric = String$1.match(/^([0-3]?\d)\.([01]?\d)\.(\d{4})$/u)(input);
|
|
573
|
-
if (Option.isSome(numeric)) {
|
|
574
|
-
const year = validYear(textAt(numeric.value, 3));
|
|
575
|
-
const day = Number(textAt(numeric.value, 1));
|
|
576
|
-
const month = Number(textAt(numeric.value, 2));
|
|
577
|
-
if (year !== void 0 && month >= 1 && month <= 12) {
|
|
578
|
-
const value = isoDate(year, month, day);
|
|
579
|
-
if (isIsoDate(value) && value !== "9999-12-31") return Option.some(fixedDatePeriod(value, `${day}. ${title(textAt(months, month - 1))} ${year}`));
|
|
580
|
-
}
|
|
581
|
-
}
|
|
313
|
+
if (Option.isSome(numeric)) return namedDatePeriod(textAt(numeric.value, 3), textAt(numeric.value, 2), textAt(numeric.value, 1), Number, (day, month, year) => `${day}. ${title(textAt(months, month - 1))} ${year}`);
|
|
582
314
|
const current = String$1.match(/^([0-3]?\d)\.? ([a-zäöüß]+\.?)$/u)(input);
|
|
583
315
|
return Option.isSome(current) ? namedCurrentYearDatePeriod(textAt(current.value, 2), textAt(current.value, 1), monthNumber, currentDateLabel) : Option.none();
|
|
584
316
|
};
|
|
@@ -595,8 +327,8 @@ const quarterNumber = (value) => {
|
|
|
595
327
|
return index === -1 ? void 0 : index + 1;
|
|
596
328
|
};
|
|
597
329
|
const relativeDirection = (value) => {
|
|
598
|
-
if (value
|
|
599
|
-
if (value
|
|
330
|
+
if (value.startsWith("letzt")) return -1;
|
|
331
|
+
if (value.startsWith("nächst")) return 1;
|
|
600
332
|
return 0;
|
|
601
333
|
};
|
|
602
334
|
const parseQuarter = (input) => {
|
|
@@ -624,13 +356,13 @@ const parseQuarter = (input) => {
|
|
|
624
356
|
const quarter = quarterNumber(textAt(standalone.value, 1));
|
|
625
357
|
return quarter === void 0 ? Option.none() : Option.some(quarterOfRelativeYear(quarter, 0, `Q${quarter}`));
|
|
626
358
|
};
|
|
627
|
-
const
|
|
628
|
-
const
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
if (Option.isSome(
|
|
359
|
+
const parseDatedPeriod = (input) => {
|
|
360
|
+
const knownPeriod = Option.firstSomeOf([
|
|
361
|
+
absoluteDatePeriod(input, "de"),
|
|
362
|
+
parseNamedDate(input),
|
|
363
|
+
parseQuarter(input)
|
|
364
|
+
]);
|
|
365
|
+
if (Option.isSome(knownPeriod)) return knownPeriod;
|
|
634
366
|
const yearMatch = String$1.match(/^(?:(?:das )?(?:kalender)?jahr )?(\d{4})$/u)(input);
|
|
635
367
|
if (Option.isSome(yearMatch)) {
|
|
636
368
|
const year = validYear(textAt(yearMatch.value, 1));
|
|
@@ -642,6 +374,22 @@ const parseBasePeriod = (input) => {
|
|
|
642
374
|
const year = validYear(textAt(monthYear.value, 2));
|
|
643
375
|
if (month !== void 0 && year !== void 0) return Option.some(fixedMonthPeriod(year, month, `${title(textAt(months, month - 1))} ${year}`));
|
|
644
376
|
}
|
|
377
|
+
return Option.none();
|
|
378
|
+
};
|
|
379
|
+
const parseRelativeMonth = (input) => {
|
|
380
|
+
const prefixedRelativeMonth = String$1.match(/^(letzt|dies|nächst)(?:er|en|em) ([a-zäöüß]+\.?)$/u)(input);
|
|
381
|
+
if (Option.isSome(prefixedRelativeMonth)) {
|
|
382
|
+
const month = monthNumber(textAt(prefixedRelativeMonth.value, 2));
|
|
383
|
+
if (month !== void 0) {
|
|
384
|
+
const direction = relativeDirection(textAt(prefixedRelativeMonth.value, 1));
|
|
385
|
+
const modifier = textAt([
|
|
386
|
+
"letzter",
|
|
387
|
+
"dieser",
|
|
388
|
+
"nächster"
|
|
389
|
+
], direction + 1);
|
|
390
|
+
return Option.some(monthOfRelativeYear(month, direction, `${modifier} ${title(textAt(months, month - 1))}`));
|
|
391
|
+
}
|
|
392
|
+
}
|
|
645
393
|
const relativeMonth = String$1.match(/^([a-zäöüß]+\.?) (letzten|dieses|nächsten) jahres$/u)(input);
|
|
646
394
|
if (Option.isSome(relativeMonth)) {
|
|
647
395
|
const directionText = textAt(relativeMonth.value, 2);
|
|
@@ -651,11 +399,18 @@ const parseBasePeriod = (input) => {
|
|
|
651
399
|
}
|
|
652
400
|
const standaloneMonth = monthNumber(input);
|
|
653
401
|
if (standaloneMonth !== void 0) return Option.some(monthOfRelativeYear(standaloneMonth, 0, title(textAt(months, standaloneMonth - 1))));
|
|
402
|
+
return Option.none();
|
|
403
|
+
};
|
|
404
|
+
const parseBasePeriod = (input) => {
|
|
405
|
+
const knownPeriod = Option.firstSomeOf([parseDatedPeriod(input), parseRelativeMonth(input)]);
|
|
406
|
+
if (Option.isSome(knownPeriod)) return knownPeriod;
|
|
654
407
|
if (input === "wochenende" || input === "dieses wochenende" || input === "am wochenende") return Option.some(relativeWeekend(0, "dieses Wochenende"));
|
|
655
408
|
if (input === "letztes wochenende" || input === "vergangenes wochenende") return Option.some(relativeWeekend(-1, "letztes Wochenende"));
|
|
656
409
|
if (input === "nächstes wochenende" || input === "kommendes wochenende") return Option.some(relativeWeekend(1, "nächstes Wochenende"));
|
|
657
410
|
if (input === "vorletztes wochenende") return Option.some(relativeWeekend(-2, "vorletztes Wochenende"));
|
|
658
411
|
if (input === "übernächstes wochenende") return Option.some(relativeWeekend(2, "übernächstes Wochenende"));
|
|
412
|
+
const weekday = nextWeekdays.find((entry) => entry.phrase === input);
|
|
413
|
+
if (weekday !== void 0) return Option.some(relativeWeekday(weekday.day, 1, weekday.canonical));
|
|
659
414
|
const relative = unitPhrases.find((entry) => entry.current === input || entry.previous === input || entry.next === input);
|
|
660
415
|
if (relative !== void 0) {
|
|
661
416
|
let direction = 0;
|
|
@@ -663,15 +418,66 @@ const parseBasePeriod = (input) => {
|
|
|
663
418
|
if (input === relative.next) direction = 1;
|
|
664
419
|
return Option.some(relativePeriod(relative.unit, direction, canonicalRelative(input)));
|
|
665
420
|
}
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
421
|
+
if (input === "vorgestern") return Option.some(relativePeriod("day", -2, "vorgestern"));
|
|
422
|
+
return parseModifiedUnit(input);
|
|
423
|
+
};
|
|
424
|
+
const countedUnit = (value, amount, dative = false) => unitPhrases.find((entry) => {
|
|
425
|
+
if (amount === 1) return value === entry.noun;
|
|
426
|
+
return value === (dative ? entry.dative : entry.plural);
|
|
427
|
+
});
|
|
428
|
+
const parseCalendarOffsetValue = (input) => {
|
|
429
|
+
const singular = String$1.match(/^(vor|in) (ein[^ ]* [^ ]+)$/u)(input);
|
|
430
|
+
if (Option.isSome(singular)) {
|
|
431
|
+
const entry = unitPhrases.find((unit) => unit.indefiniteDative === textAt(singular.value, 2));
|
|
432
|
+
if (entry !== void 0) {
|
|
433
|
+
const past = textAt(singular.value, 1) === "vor";
|
|
434
|
+
return Option.some({
|
|
435
|
+
amount: past ? -1 : 1,
|
|
436
|
+
canonical: `${past ? "vor" : "in"} ${canonicalRelative(entry.indefiniteDative)}`,
|
|
437
|
+
entry
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
const prefixed = String$1.match(/^(vor|in) ([1-9]\d*) ([^ ]+)$/u)(input);
|
|
442
|
+
const prior = String$1.match(/^([1-9]\d*) ([^ ]+) zuvor$/u)(input);
|
|
443
|
+
const match = Option.firstSomeOf([prefixed, prior]);
|
|
444
|
+
if (Option.isNone(match)) return Option.none();
|
|
445
|
+
const amountText = textAt(match.value, Option.isSome(prefixed) ? 2 : 1);
|
|
446
|
+
const unitText = textAt(match.value, Option.isSome(prefixed) ? 3 : 2);
|
|
447
|
+
const amount = parseTrailingCount(amountText);
|
|
448
|
+
if (Option.isNone(amount)) return Option.none();
|
|
449
|
+
const entry = countedUnit(unitText, amount.value, Option.isSome(prefixed));
|
|
450
|
+
if (entry === void 0) return Option.none();
|
|
451
|
+
const past = Option.isSome(prior) || Option.isSome(prefixed) && textAt(match.value, 1) === "vor";
|
|
452
|
+
const direction = past ? "vor" : "in";
|
|
453
|
+
const noun = amount.value === 1 ? entry.noun : entry.dative;
|
|
454
|
+
return Option.some({
|
|
455
|
+
amount: past ? -amount.value : amount.value,
|
|
456
|
+
canonical: `${direction} ${amount.value} ${title(noun)}`,
|
|
457
|
+
entry
|
|
458
|
+
});
|
|
669
459
|
};
|
|
670
460
|
const parsePeriod = (input) => {
|
|
461
|
+
let separator = input.indexOf(" ");
|
|
462
|
+
while (separator !== -1) {
|
|
463
|
+
const offsetStart = separator + 1;
|
|
464
|
+
const firstOffsetCharacter = input[offsetStart] ?? "";
|
|
465
|
+
if (input.startsWith("vor ", offsetStart) || input.startsWith("in ", offsetStart) || firstOffsetCharacter >= "1" && firstOffsetCharacter <= "9" && input.endsWith(" zuvor")) {
|
|
466
|
+
const offset = parseCalendarOffsetValue(input.slice(offsetStart));
|
|
467
|
+
if (Option.isSome(offset)) {
|
|
468
|
+
const period = parsePeriod(input.slice(0, separator));
|
|
469
|
+
if (Option.isSome(period)) return Option.some(shiftPeriod(period.value, offset.value.amount, offset.value.entry.unit, `${period.value.canonical} ${offset.value.canonical}`));
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
separator = input.indexOf(" ", offsetStart);
|
|
473
|
+
}
|
|
671
474
|
const edge = String$1.match(/^(anfang|beginn|ende) (.+)$/u)(input);
|
|
672
475
|
if (Option.isSome(edge)) {
|
|
673
476
|
const edgeName = textAt(edge.value, 1);
|
|
674
|
-
const
|
|
477
|
+
const periodText = textAt(edge.value, 2);
|
|
478
|
+
const basePeriod = parseBasePeriod(periodText);
|
|
479
|
+
const implicit = unitPhrases.find((entry) => entry.genitive === periodText);
|
|
480
|
+
const period = Option.isSome(basePeriod) || implicit === void 0 ? basePeriod : Option.some(relativePeriod(implicit.unit, 0, implicit.current));
|
|
675
481
|
if (Option.isSome(period)) {
|
|
676
482
|
const canonical = `${edgeName === "ende" ? "Ende" : "Anfang"} ${withRelativeGenitive(period.value.canonical)}`;
|
|
677
483
|
return Option.some(edgeName === "ende" ? periodEndDay(period.value, canonical) : periodStartDay(period.value, canonical));
|
|
@@ -683,7 +489,8 @@ const parsePeriod = (input) => {
|
|
|
683
489
|
"für ",
|
|
684
490
|
"während "
|
|
685
491
|
].find((prefix) => input.startsWith(prefix));
|
|
686
|
-
|
|
492
|
+
const base = parseBasePeriod(wrapper === void 0 ? input : input.slice(wrapper.length));
|
|
493
|
+
return Option.isSome(base) ? base : parseCalendarOffset(input);
|
|
687
494
|
};
|
|
688
495
|
const currentBoundaryCandidate = (input) => {
|
|
689
496
|
const match = currentBoundaryPhrases.find((entry) => entry.phrase === input);
|
|
@@ -719,50 +526,19 @@ const boundaryCandidate = (input) => Option.map(openBoundaryCandidate(input, [
|
|
|
719
526
|
["bis ", "before"],
|
|
720
527
|
["ab ", "since"]
|
|
721
528
|
], parsePeriod), (result) => candidate(result.range, canonicalRelative(input)));
|
|
722
|
-
const
|
|
723
|
-
if (amount === 1) return value === entry.noun;
|
|
724
|
-
return value === (dative ? entry.dative : entry.plural);
|
|
725
|
-
});
|
|
726
|
-
const parseCalendarOffset = (input) => {
|
|
727
|
-
const singular = String$1.match(/^(vor|in) (einem tag|einer woche|einem monat|einem quartal|einem jahr)$/u)(input);
|
|
728
|
-
if (Option.isSome(singular)) {
|
|
729
|
-
const entry = unitPhrases.find((unit) => unit.indefiniteDative === textAt(singular.value, 2));
|
|
730
|
-
if (entry !== void 0) {
|
|
731
|
-
const isPast = textAt(singular.value, 1) === "vor";
|
|
732
|
-
const direction = isPast ? -1 : 1;
|
|
733
|
-
const canonical = `${isPast ? "vor" : "in"} ${canonicalRelative(entry.indefiniteDative)}`;
|
|
734
|
-
return Option.some(candidate(periodRange(relativePeriod(entry.unit, direction, canonical)), canonical));
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
const prefixed = String$1.match(/^(vor|in) ([1-9]\d*) (tag|tagen|woche|wochen|monat|monaten|quartal|quartalen|jahr|jahren)$/u)(input);
|
|
738
|
-
const prior = String$1.match(/^([1-9]\d*) (tag|tage|woche|wochen|monat|monate|quartal|quartale|jahr|jahre) zuvor$/u)(input);
|
|
739
|
-
const match = Option.firstSomeOf([prefixed, prior]);
|
|
740
|
-
if (Option.isNone(match)) return Option.none();
|
|
741
|
-
const amountText = textAt(match.value, Option.isSome(prefixed) ? 2 : 1);
|
|
742
|
-
const unitText = textAt(match.value, Option.isSome(prefixed) ? 3 : 2);
|
|
743
|
-
const amount = parseTrailingCount(amountText);
|
|
744
|
-
if (Option.isNone(amount)) return Option.none();
|
|
745
|
-
const entry = countedUnit(unitText, amount.value, Option.isSome(prefixed));
|
|
746
|
-
if (entry === void 0) return Option.none();
|
|
747
|
-
const isPast = Option.isSome(prior) || Option.isSome(prefixed) && textAt(match.value, 1) === "vor";
|
|
748
|
-
const direction = isPast ? -amount.value : amount.value;
|
|
749
|
-
const directionName = isPast ? "vor" : "in";
|
|
750
|
-
const noun = amount.value === 1 ? entry.noun : entry.dative;
|
|
751
|
-
const canonical = `${directionName} ${amount.value} ${title(noun)}`;
|
|
752
|
-
return Option.some(candidate(periodRange(relativePeriod(entry.unit, direction, canonical)), canonical));
|
|
753
|
-
};
|
|
529
|
+
const parseCalendarOffset = (input) => parseCalendarOffsetValue(input).pipe(Option.map((offset) => relativePeriod(offset.entry.unit, offset.amount, offset.canonical)));
|
|
754
530
|
const parseRollingPeriod = (input) => {
|
|
755
|
-
const past = String$1.match(/^(?:(?:die letzten|letzten|letzte|vergangene|vorherige) )?([1-9]\d*) (
|
|
756
|
-
const pastDative = String$1.match(/^(?:(?:in den letzten|in den vergangenen|in den vorherigen) |seit )([1-9]\d*) (
|
|
757
|
-
const singularSince = String$1.match(/^seit (
|
|
758
|
-
const pastGenitive = String$1.match(/^während der letzten ([1-9]\d*) (
|
|
759
|
-
const future = String$1.match(/^(?:die nächsten|nächsten|nächste|kommende) ([1-9]\d*) (
|
|
760
|
-
const futureDative = String$1.match(/^(?:in den nächsten|in den kommenden|innerhalb von) ([1-9]\d*) (
|
|
761
|
-
const singularFuture = String$1.match(/^innerhalb (
|
|
762
|
-
const futureGenitive = String$1.match(/^innerhalb der nächsten ([1-9]\d*) (
|
|
531
|
+
const past = String$1.match(/^(?:(?:die letzten|letzten|letzte|vergangene|vorherige) )?([1-9]\d*) ([^ ]+)$/u)(input);
|
|
532
|
+
const pastDative = String$1.match(/^(?:(?:in den letzten|in den vergangenen|in den vorherigen) |seit )([1-9]\d*) ([^ ]+)$/u)(input);
|
|
533
|
+
const singularSince = String$1.match(/^seit (ein[^ ]* [^ ]+)$/u)(input);
|
|
534
|
+
const pastGenitive = String$1.match(/^während der letzten ([1-9]\d*) ([^ ]+)$/u)(input);
|
|
535
|
+
const future = String$1.match(/^(?:die nächsten|nächsten|nächste|kommende) ([1-9]\d*) ([^ ]+)$/u)(input);
|
|
536
|
+
const futureDative = String$1.match(/^(?:in den nächsten|in den kommenden|innerhalb von) ([1-9]\d*) ([^ ]+)$/u)(input);
|
|
537
|
+
const singularFuture = String$1.match(/^innerhalb (ein[^ ]* [^ ]+)$/u)(input);
|
|
538
|
+
const futureGenitive = String$1.match(/^innerhalb der nächsten ([1-9]\d*) ([^ ]+)$/u)(input);
|
|
763
539
|
const match = Option.firstSomeOf([
|
|
764
|
-
past,
|
|
765
540
|
pastDative,
|
|
541
|
+
past,
|
|
766
542
|
singularSince,
|
|
767
543
|
pastGenitive,
|
|
768
544
|
future,
|
|
@@ -799,13 +575,42 @@ const parseElidedDateRange = (input) => {
|
|
|
799
575
|
const suffix = year.length === 0 ? "" : ` ${year}`;
|
|
800
576
|
return joinedPeriodCandidate(`von ${lowerDay}. ${month}${suffix} bis ${upperDay}. ${month}${suffix}`, [["von ", " bis "]], parsePeriod, (lower, upper) => `von ${lower} bis ${upper}`);
|
|
801
577
|
};
|
|
578
|
+
const boundedJoins = [
|
|
579
|
+
["von ", " bis einschließlich "],
|
|
580
|
+
["vom ", " bis einschließlich "],
|
|
581
|
+
["von ", " bis zum "],
|
|
582
|
+
["vom ", " bis zum "],
|
|
583
|
+
["von ", " bis "],
|
|
584
|
+
["vom ", " bis "],
|
|
585
|
+
["zwischen ", " und "],
|
|
586
|
+
["", " bis einschließlich "],
|
|
587
|
+
["", " bis "],
|
|
588
|
+
["", " - "],
|
|
589
|
+
["", " – "],
|
|
590
|
+
["", " — "],
|
|
591
|
+
["zwischen ", "-"],
|
|
592
|
+
["", "-"],
|
|
593
|
+
["zwischen ", "–"],
|
|
594
|
+
["", "–"],
|
|
595
|
+
["zwischen ", "—"],
|
|
596
|
+
["", "—"],
|
|
597
|
+
["zwischen ", "~"],
|
|
598
|
+
["", "~"]
|
|
599
|
+
];
|
|
600
|
+
const sharedRelativeYearRange = (input) => {
|
|
601
|
+
const match = String$1.match(/^(.+) (letzten|dieses|nächsten) jahres$/u)(input);
|
|
602
|
+
if (Option.isNone(match)) return Option.none();
|
|
603
|
+
const year = `${textAt(match.value, 2)} jahres`;
|
|
604
|
+
return joinedPeriodCandidate(textAt(match.value, 1), boundedJoins, (periodInput) => {
|
|
605
|
+
const inherited = parsePeriod(`${periodInput} ${year}`);
|
|
606
|
+
return Option.isSome(inherited) ? inherited : parsePeriod(periodInput);
|
|
607
|
+
}, (lower, upper) => `von ${lower} bis ${upper}`);
|
|
608
|
+
};
|
|
802
609
|
const parseGerman = (input) => {
|
|
803
610
|
const remaining = remainingPeriodPhrases.find((entry) => entry.phrase === input);
|
|
804
611
|
if (remaining !== void 0) return Option.some(candidate(remainingPeriodRange(remaining.entry.unit), `Rest ${canonicalRelative(remaining.entry.genitive)}`));
|
|
805
612
|
if (["bis heute", "bis jetzt"].includes(input)) return Option.some(candidate(untilNowRange(), "bis heute"));
|
|
806
613
|
if (["ab jetzt", "von jetzt an"].includes(input)) return Option.some(candidate(fromNowRange(), "ab jetzt"));
|
|
807
|
-
const offset = parseCalendarOffset(input);
|
|
808
|
-
if (Option.isSome(offset)) return offset;
|
|
809
614
|
const rolling = parseRollingPeriod(input);
|
|
810
615
|
if (Option.isSome(rolling)) return rolling;
|
|
811
616
|
const toDate = toDatePhrases.find((entry) => entry.phrase === input);
|
|
@@ -814,34 +619,20 @@ const parseGerman = (input) => {
|
|
|
814
619
|
if (Option.isSome(currentBoundary)) return currentBoundary;
|
|
815
620
|
const elided = parseElidedDateRange(input);
|
|
816
621
|
if (Option.isSome(elided)) return elided;
|
|
622
|
+
const inheritedYear = sharedRelativeYearRange(input);
|
|
623
|
+
if (Option.isSome(inheritedYear)) return inheritedYear;
|
|
817
624
|
const nowBounded = joinedNowCandidate(input, [
|
|
818
625
|
["von ", " bis heute"],
|
|
819
626
|
["vom ", " bis heute"],
|
|
820
627
|
["zwischen ", " und heute"]
|
|
821
|
-
], [
|
|
628
|
+
], [
|
|
629
|
+
"von heute bis ",
|
|
630
|
+
"zwischen heute und ",
|
|
631
|
+
"heute bis ",
|
|
632
|
+
"jetzt bis "
|
|
633
|
+
], parsePeriod, (period) => `von ${period} bis heute`, (period) => `von heute bis ${period}`);
|
|
822
634
|
if (Option.isSome(nowBounded)) return nowBounded;
|
|
823
|
-
const bounded = joinedPeriodCandidate(input,
|
|
824
|
-
["von ", " bis einschließlich "],
|
|
825
|
-
["vom ", " bis einschließlich "],
|
|
826
|
-
["von ", " bis zum "],
|
|
827
|
-
["vom ", " bis zum "],
|
|
828
|
-
["von ", " bis "],
|
|
829
|
-
["vom ", " bis "],
|
|
830
|
-
["zwischen ", " und "],
|
|
831
|
-
["", " bis einschließlich "],
|
|
832
|
-
["", " bis "],
|
|
833
|
-
["", " - "],
|
|
834
|
-
["", " – "],
|
|
835
|
-
["", " — "],
|
|
836
|
-
["zwischen ", "-"],
|
|
837
|
-
["", "-"],
|
|
838
|
-
["zwischen ", "–"],
|
|
839
|
-
["", "–"],
|
|
840
|
-
["zwischen ", "—"],
|
|
841
|
-
["", "—"],
|
|
842
|
-
["zwischen ", "~"],
|
|
843
|
-
["", "~"]
|
|
844
|
-
], parsePeriod, (lower, upper) => `von ${lower} bis ${upper}`);
|
|
635
|
+
const bounded = joinedPeriodCandidate(input, boundedJoins, parsePeriod, (lower, upper) => `von ${lower} bis ${upper}`);
|
|
845
636
|
if (Option.isSome(bounded)) return bounded;
|
|
846
637
|
const boundary = boundaryCandidate(input);
|
|
847
638
|
if (Option.isSome(boundary)) return boundary;
|
|
@@ -877,9 +668,13 @@ const staticPeriodPhrases = [
|
|
|
877
668
|
]),
|
|
878
669
|
...months.flatMap((month) => [
|
|
879
670
|
month,
|
|
671
|
+
`letzter ${month}`,
|
|
672
|
+
`nächster ${month}`,
|
|
880
673
|
`${month} letzten jahres`,
|
|
881
|
-
`${month} nächsten jahres
|
|
882
|
-
|
|
674
|
+
`${month} nächsten jahres`,
|
|
675
|
+
`${month} vor einem jahr`
|
|
676
|
+
]),
|
|
677
|
+
...nextWeekdays.map((entry) => entry.phrase)
|
|
883
678
|
];
|
|
884
679
|
const staticPeriods = periodsFromPhrases(staticPeriodPhrases, parsePeriod);
|
|
885
680
|
const boundaryPrefixes = [
|
|
@@ -916,12 +711,20 @@ const germanSuggestionPhrases = [
|
|
|
916
711
|
]),
|
|
917
712
|
...staticPeriodPhrases,
|
|
918
713
|
...currentBoundaryPhrases.map((entry) => entry.phrase),
|
|
919
|
-
...
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
714
|
+
...unitPhrases.flatMap((entry) => [
|
|
715
|
+
entry.current,
|
|
716
|
+
entry.previous,
|
|
717
|
+
entry.next
|
|
718
|
+
].flatMap((period) => {
|
|
719
|
+
const dative = withRelativeCase(canonicalRelative(period), "dative");
|
|
720
|
+
const accusative = withRelativeCase(canonicalRelative(period), "accusative");
|
|
721
|
+
return [
|
|
722
|
+
`seit ${dative}`,
|
|
723
|
+
`vor ${dative}`,
|
|
724
|
+
`bis einschließlich ${accusative}`,
|
|
725
|
+
`nach ${dative}`
|
|
726
|
+
];
|
|
727
|
+
})),
|
|
925
728
|
...prefixNaturalPhrases(months, boundaryPrefixes),
|
|
926
729
|
"bis heute",
|
|
927
730
|
"ab jetzt"
|
|
@@ -936,6 +739,17 @@ const suggestGerman = (input, limit) => {
|
|
|
936
739
|
], limit);
|
|
937
740
|
};
|
|
938
741
|
const renderGerman = (range) => {
|
|
742
|
+
const shifted = decomposeShiftedPeriodRange(range);
|
|
743
|
+
if (Option.isSome(shifted)) {
|
|
744
|
+
const base = renderGerman(shifted.value.baseRange);
|
|
745
|
+
const entry = unitPhrases.find((unit) => unit.unit === shifted.value.unit);
|
|
746
|
+
if (Option.isSome(base) && entry !== void 0) {
|
|
747
|
+
const amount = Math.abs(shifted.value.amount);
|
|
748
|
+
const offset = amount === 1 ? canonicalRelative(entry.indefiniteDative) : `${amount} ${title(entry.dative)}`;
|
|
749
|
+
const direction = shifted.value.amount < 0 ? "vor" : "in";
|
|
750
|
+
return Option.some(`${base.value} ${direction} ${offset}`);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
939
753
|
const offset = calendarPeriodOffset(range);
|
|
940
754
|
if (Option.isSome(offset) && Math.abs(offset.value.amount) > 1) {
|
|
941
755
|
const entry = unitPhrases.find((unit) => unit.unit === offset.value.unit);
|
|
@@ -957,12 +771,13 @@ const renderGerman = (range) => {
|
|
|
957
771
|
...currentYearDatePeriods(range, currentDateLabel),
|
|
958
772
|
...periodsFromPhrases([...dated, ...dated.flatMap((phrase) => [`anfang ${phrase}`, `ende ${phrase}`])], parsePeriod)
|
|
959
773
|
];
|
|
960
|
-
return renderPeriodRange(range, [...unitPhrases.map((entry) => candidate(periodToDateRange(entry.unit), canonicalToDate(entry))), ...unitPhrases.map((entry) => candidate(remainingPeriodRange(entry.unit), `Rest ${canonicalRelative(entry.genitive)}`))], periods, (period) => `seit ${withRelativeCase(period, "dative")}`, (period) => `vor ${withRelativeCase(period, "dative")}`, (period) => `bis einschließlich ${withRelativeCase(period, "accusative")}`, (period) => `nach ${withRelativeCase(period, "dative")}`, (lower, upper) => `von ${lower} bis ${upper}`, (period) => `von ${period} bis heute`, (period) => `von heute bis ${period}`, () => "bis heute", () => "ab jetzt");
|
|
774
|
+
return renderPeriodRange(range, [...unitPhrases.map((entry) => candidate(periodToDateRange(entry.unit), canonicalToDate(entry))), ...unitPhrases.map((entry) => candidate(remainingPeriodRange(entry.unit), `Rest ${canonicalRelative(entry.genitive)}`))], periods, (period) => `seit ${withRelativeCase(period, "dative")}`, (period) => `vor ${withRelativeCase(period, "dative")}`, (period) => `bis einschließlich ${withRelativeCase(period, "accusative")}`, (period) => `nach ${withRelativeCase(period, "dative")}`, (lower, upper) => `von ${withRelativeCase(lower, "dative")} bis ${withRelativeCase(upper, "accusative")}`, (period) => `von ${period} bis heute`, (period) => `von heute bis ${period}`, () => "bis heute", () => "ab jetzt");
|
|
961
775
|
};
|
|
962
776
|
const GermanContribution = new BaseLanguageContribution({
|
|
963
777
|
locale: "de",
|
|
964
778
|
vocabulary: [
|
|
965
779
|
...months,
|
|
780
|
+
...weekdays,
|
|
966
781
|
...quarterNames,
|
|
967
782
|
"q1",
|
|
968
783
|
"q2",
|
|
@@ -972,7 +787,7 @@ const GermanContribution = new BaseLanguageContribution({
|
|
|
972
787
|
...toDatePhrases.flatMap((entry) => entry.phrase.split(" ")),
|
|
973
788
|
...remainingPeriodPhrases.flatMap((entry) => entry.phrase.split(" ")),
|
|
974
789
|
...currentBoundaryPhrases.flatMap((entry) => entry.phrase.split(" ")),
|
|
975
|
-
...
|
|
790
|
+
...relativeModifierVocabulary,
|
|
976
791
|
...unitPhrases.flatMap((entry) => [
|
|
977
792
|
entry.noun,
|
|
978
793
|
entry.plural,
|
|
@@ -1010,6 +825,8 @@ const GermanContribution = new BaseLanguageContribution({
|
|
|
1010
825
|
"letzten",
|
|
1011
826
|
"nach",
|
|
1012
827
|
"nächste",
|
|
828
|
+
"auflaufend",
|
|
829
|
+
"per",
|
|
1013
830
|
"nächsten",
|
|
1014
831
|
"seit",
|
|
1015
832
|
"vor",
|
|
@@ -1024,8 +841,8 @@ const GermanContribution = new BaseLanguageContribution({
|
|
|
1024
841
|
"zwischen",
|
|
1025
842
|
"zuvor"
|
|
1026
843
|
],
|
|
1027
|
-
normalize:
|
|
1028
|
-
correct:
|
|
844
|
+
normalize: normalizeGerman,
|
|
845
|
+
correct: correctGerman,
|
|
1029
846
|
parseExact: parseGerman,
|
|
1030
847
|
suggest: suggestGerman,
|
|
1031
848
|
render: renderGerman
|