chronolizer 0.4.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 +4 -2
- 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 +2 -3
- package/dist/language/registry.mjs +4 -2
- package/dist/locales/cs.mjs +9 -20
- package/dist/locales/de.mjs +199 -495
- package/dist/locales/en.mjs +13 -13
- package/dist/locales/es.mjs +10 -19
- package/dist/locales/fr.mjs +20 -35
- package/dist/locales/nl.mjs +8 -19
- package/dist/locales/pl.mjs +8 -19
- package/dist/locales/shared.mjs +7 -7
- package/dist/locales/tr.mjs +9 -21
- package/dist/natural/correction.mjs +70 -27
- package/dist/natural/parse.mjs +1 -1
- package/dist/natural/suggest.mjs +9 -1
- package/dist/natural/suggestion.mjs +44 -26
- package/dist/resolve/resolve.mjs +1 -2
- 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, compileCountAliasNormalizer, compoundCountAliases, countAliasVocabulary, currentYearDatePeriods, datedPeriods, datedQuarterPeriods, decimalTens, decomposeShiftedPeriodRange,
|
|
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,6 +20,20 @@ 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
|
+
];
|
|
24
37
|
const germanCountWords = [
|
|
25
38
|
"zwei",
|
|
26
39
|
"drei",
|
|
@@ -56,11 +69,14 @@ const germanCountAliases = [...sequentialCountAliases(germanCountWords.map((word
|
|
|
56
69
|
const normalizeGermanCounts = compileCountAliasNormalizer(germanCountAliases);
|
|
57
70
|
const germanCountVocabulary = new Set(countAliasVocabulary(germanCountAliases));
|
|
58
71
|
const correctGerman = (input, vocabulary) => correctWhitespaceSeparatedText(input, vocabulary, germanCountVocabulary);
|
|
59
|
-
const normalizeGerman = (input, locale) => normalizeGermanCounts(normalizeNaturalText(input, locale));
|
|
60
72
|
const monthAbbreviations = [
|
|
61
73
|
["jan"],
|
|
62
74
|
["feb"],
|
|
63
|
-
[
|
|
75
|
+
[
|
|
76
|
+
"mär",
|
|
77
|
+
"mrz",
|
|
78
|
+
"maerz"
|
|
79
|
+
],
|
|
64
80
|
["apr"],
|
|
65
81
|
["mai"],
|
|
66
82
|
["jun"],
|
|
@@ -215,390 +231,45 @@ const currentBoundaryPhrases = unitPhrases.flatMap((entry) => [
|
|
|
215
231
|
entry,
|
|
216
232
|
phrase
|
|
217
233
|
})));
|
|
218
|
-
const
|
|
219
|
-
[
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
],
|
|
226
|
-
[
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
"letzte woche"
|
|
232
|
-
],
|
|
233
|
-
[
|
|
234
|
-
"nächste woche",
|
|
235
|
-
"week",
|
|
236
|
-
1,
|
|
237
|
-
"nächster woche",
|
|
238
|
-
"nächste woche"
|
|
239
|
-
],
|
|
240
|
-
[
|
|
241
|
-
"dieser monat",
|
|
242
|
-
"month",
|
|
243
|
-
0,
|
|
244
|
-
"diesem monat",
|
|
245
|
-
"diesen monat"
|
|
246
|
-
],
|
|
247
|
-
[
|
|
248
|
-
"letzter monat",
|
|
249
|
-
"month",
|
|
250
|
-
-1,
|
|
251
|
-
"letztem monat",
|
|
252
|
-
"letzten monat"
|
|
253
|
-
],
|
|
254
|
-
[
|
|
255
|
-
"nächster monat",
|
|
256
|
-
"month",
|
|
257
|
-
1,
|
|
258
|
-
"nächstem monat",
|
|
259
|
-
"nächsten monat"
|
|
260
|
-
],
|
|
261
|
-
[
|
|
262
|
-
"dieses quartal",
|
|
263
|
-
"quarter",
|
|
264
|
-
0,
|
|
265
|
-
"diesem quartal",
|
|
266
|
-
"dieses quartal"
|
|
267
|
-
],
|
|
268
|
-
[
|
|
269
|
-
"letztes quartal",
|
|
270
|
-
"quarter",
|
|
271
|
-
-1,
|
|
272
|
-
"letztem quartal",
|
|
273
|
-
"letztes quartal"
|
|
274
|
-
],
|
|
275
|
-
[
|
|
276
|
-
"nächstes quartal",
|
|
277
|
-
"quarter",
|
|
278
|
-
1,
|
|
279
|
-
"nächstem quartal",
|
|
280
|
-
"nächstes quartal"
|
|
281
|
-
],
|
|
282
|
-
[
|
|
283
|
-
"dieses jahr",
|
|
284
|
-
"year",
|
|
285
|
-
0,
|
|
286
|
-
"diesem jahr",
|
|
287
|
-
"dieses jahr"
|
|
288
|
-
],
|
|
289
|
-
[
|
|
290
|
-
"letztes jahr",
|
|
291
|
-
"year",
|
|
292
|
-
-1,
|
|
293
|
-
"letztem jahr",
|
|
294
|
-
"letztes jahr"
|
|
295
|
-
],
|
|
296
|
-
[
|
|
297
|
-
"nächstes jahr",
|
|
298
|
-
"year",
|
|
299
|
-
1,
|
|
300
|
-
"nächstem jahr",
|
|
301
|
-
"nächstes jahr"
|
|
302
|
-
]
|
|
303
|
-
];
|
|
304
|
-
const relativeAliases = [
|
|
305
|
-
...unitPhrases.flatMap((entry) => [
|
|
306
|
-
[
|
|
307
|
-
entry.currentGenitive,
|
|
308
|
-
entry.unit,
|
|
309
|
-
0,
|
|
310
|
-
entry.current
|
|
311
|
-
],
|
|
312
|
-
[
|
|
313
|
-
entry.previousGenitive,
|
|
314
|
-
entry.unit,
|
|
315
|
-
-1,
|
|
316
|
-
entry.previous
|
|
317
|
-
],
|
|
318
|
-
[
|
|
319
|
-
entry.nextGenitive,
|
|
320
|
-
entry.unit,
|
|
321
|
-
1,
|
|
322
|
-
entry.next
|
|
323
|
-
]
|
|
324
|
-
]),
|
|
325
|
-
...declinedBoundaryPeriods.map(([canonical, unit, direction, dative]) => [
|
|
326
|
-
dative,
|
|
327
|
-
unit,
|
|
328
|
-
direction,
|
|
329
|
-
canonical
|
|
330
|
-
]),
|
|
331
|
-
[
|
|
332
|
-
"vorgestern",
|
|
333
|
-
"day",
|
|
334
|
-
-2,
|
|
335
|
-
"vorgestern"
|
|
336
|
-
],
|
|
337
|
-
[
|
|
338
|
-
"vorletzten tag",
|
|
339
|
-
"day",
|
|
340
|
-
-2,
|
|
341
|
-
"vorletzter tag"
|
|
342
|
-
],
|
|
343
|
-
[
|
|
344
|
-
"übernächsten tag",
|
|
345
|
-
"day",
|
|
346
|
-
2,
|
|
347
|
-
"übernächster tag"
|
|
348
|
-
],
|
|
349
|
-
[
|
|
350
|
-
"vorletzte woche",
|
|
351
|
-
"week",
|
|
352
|
-
-2,
|
|
353
|
-
"vorletzte woche"
|
|
354
|
-
],
|
|
355
|
-
[
|
|
356
|
-
"übernächste woche",
|
|
357
|
-
"week",
|
|
358
|
-
2,
|
|
359
|
-
"übernächste woche"
|
|
360
|
-
],
|
|
361
|
-
[
|
|
362
|
-
"vorletzten monat",
|
|
363
|
-
"month",
|
|
364
|
-
-2,
|
|
365
|
-
"vorletzter monat"
|
|
366
|
-
],
|
|
367
|
-
[
|
|
368
|
-
"übernächsten monat",
|
|
369
|
-
"month",
|
|
370
|
-
2,
|
|
371
|
-
"übernächster monat"
|
|
372
|
-
],
|
|
373
|
-
[
|
|
374
|
-
"vorletztes quartal",
|
|
375
|
-
"quarter",
|
|
376
|
-
-2,
|
|
377
|
-
"vorletztes quartal"
|
|
378
|
-
],
|
|
379
|
-
[
|
|
380
|
-
"übernächstes quartal",
|
|
381
|
-
"quarter",
|
|
382
|
-
2,
|
|
383
|
-
"übernächstes quartal"
|
|
384
|
-
],
|
|
385
|
-
[
|
|
386
|
-
"vorletztes jahr",
|
|
387
|
-
"year",
|
|
388
|
-
-2,
|
|
389
|
-
"vorletztes jahr"
|
|
390
|
-
],
|
|
391
|
-
[
|
|
392
|
-
"übernächstes jahr",
|
|
393
|
-
"year",
|
|
394
|
-
2,
|
|
395
|
-
"übernächstes jahr"
|
|
396
|
-
],
|
|
397
|
-
[
|
|
398
|
-
"letzten tag",
|
|
399
|
-
"day",
|
|
400
|
-
-1,
|
|
401
|
-
"gestern"
|
|
402
|
-
],
|
|
403
|
-
[
|
|
404
|
-
"vergangenen tag",
|
|
405
|
-
"day",
|
|
406
|
-
-1,
|
|
407
|
-
"gestern"
|
|
408
|
-
],
|
|
409
|
-
[
|
|
410
|
-
"vorherigen tag",
|
|
411
|
-
"day",
|
|
412
|
-
-1,
|
|
413
|
-
"gestern"
|
|
414
|
-
],
|
|
415
|
-
[
|
|
416
|
-
"diesen tag",
|
|
417
|
-
"day",
|
|
418
|
-
0,
|
|
419
|
-
"heute"
|
|
420
|
-
],
|
|
421
|
-
[
|
|
422
|
-
"heutigen tag",
|
|
423
|
-
"day",
|
|
424
|
-
0,
|
|
425
|
-
"heute"
|
|
426
|
-
],
|
|
427
|
-
[
|
|
428
|
-
"nächsten tag",
|
|
429
|
-
"day",
|
|
430
|
-
1,
|
|
431
|
-
"morgen"
|
|
432
|
-
],
|
|
433
|
-
[
|
|
434
|
-
"kommenden tag",
|
|
435
|
-
"day",
|
|
436
|
-
1,
|
|
437
|
-
"morgen"
|
|
438
|
-
],
|
|
439
|
-
[
|
|
440
|
-
"vergangene woche",
|
|
441
|
-
"week",
|
|
442
|
-
-1,
|
|
443
|
-
"letzte woche"
|
|
444
|
-
],
|
|
445
|
-
[
|
|
446
|
-
"vorherige woche",
|
|
447
|
-
"week",
|
|
448
|
-
-1,
|
|
449
|
-
"letzte woche"
|
|
450
|
-
],
|
|
451
|
-
[
|
|
452
|
-
"aktuelle woche",
|
|
453
|
-
"week",
|
|
454
|
-
0,
|
|
455
|
-
"diese woche"
|
|
456
|
-
],
|
|
457
|
-
[
|
|
458
|
-
"laufende woche",
|
|
459
|
-
"week",
|
|
460
|
-
0,
|
|
461
|
-
"diese woche"
|
|
462
|
-
],
|
|
463
|
-
[
|
|
464
|
-
"kommende woche",
|
|
465
|
-
"week",
|
|
466
|
-
1,
|
|
467
|
-
"nächste woche"
|
|
468
|
-
],
|
|
469
|
-
[
|
|
470
|
-
"folgende woche",
|
|
471
|
-
"week",
|
|
472
|
-
1,
|
|
473
|
-
"nächste woche"
|
|
474
|
-
],
|
|
475
|
-
[
|
|
476
|
-
"letzten monat",
|
|
477
|
-
"month",
|
|
478
|
-
-1,
|
|
479
|
-
"letzter monat"
|
|
480
|
-
],
|
|
481
|
-
[
|
|
482
|
-
"vergangenen monat",
|
|
483
|
-
"month",
|
|
484
|
-
-1,
|
|
485
|
-
"letzter monat"
|
|
486
|
-
],
|
|
487
|
-
[
|
|
488
|
-
"vorherigen monat",
|
|
489
|
-
"month",
|
|
490
|
-
-1,
|
|
491
|
-
"letzter monat"
|
|
492
|
-
],
|
|
493
|
-
[
|
|
494
|
-
"diesen monat",
|
|
495
|
-
"month",
|
|
496
|
-
0,
|
|
497
|
-
"dieser monat"
|
|
498
|
-
],
|
|
499
|
-
[
|
|
500
|
-
"aktuellen monat",
|
|
501
|
-
"month",
|
|
502
|
-
0,
|
|
503
|
-
"dieser monat"
|
|
504
|
-
],
|
|
505
|
-
[
|
|
506
|
-
"laufenden monat",
|
|
507
|
-
"month",
|
|
508
|
-
0,
|
|
509
|
-
"dieser monat"
|
|
510
|
-
],
|
|
511
|
-
[
|
|
512
|
-
"nächsten monat",
|
|
513
|
-
"month",
|
|
514
|
-
1,
|
|
515
|
-
"nächster monat"
|
|
516
|
-
],
|
|
517
|
-
[
|
|
518
|
-
"kommenden monat",
|
|
519
|
-
"month",
|
|
520
|
-
1,
|
|
521
|
-
"nächster monat"
|
|
522
|
-
],
|
|
523
|
-
[
|
|
524
|
-
"folgenden monat",
|
|
525
|
-
"month",
|
|
526
|
-
1,
|
|
527
|
-
"nächster monat"
|
|
528
|
-
],
|
|
529
|
-
[
|
|
530
|
-
"vergangenes quartal",
|
|
531
|
-
"quarter",
|
|
532
|
-
-1,
|
|
533
|
-
"letztes quartal"
|
|
534
|
-
],
|
|
535
|
-
[
|
|
536
|
-
"vorheriges quartal",
|
|
537
|
-
"quarter",
|
|
538
|
-
-1,
|
|
539
|
-
"letztes quartal"
|
|
540
|
-
],
|
|
541
|
-
[
|
|
542
|
-
"aktuelles quartal",
|
|
543
|
-
"quarter",
|
|
544
|
-
0,
|
|
545
|
-
"dieses quartal"
|
|
546
|
-
],
|
|
547
|
-
[
|
|
548
|
-
"laufendes quartal",
|
|
549
|
-
"quarter",
|
|
550
|
-
0,
|
|
551
|
-
"dieses quartal"
|
|
552
|
-
],
|
|
553
|
-
[
|
|
554
|
-
"kommendes quartal",
|
|
555
|
-
"quarter",
|
|
556
|
-
1,
|
|
557
|
-
"nächstes quartal"
|
|
558
|
-
],
|
|
559
|
-
[
|
|
560
|
-
"folgendes quartal",
|
|
561
|
-
"quarter",
|
|
562
|
-
1,
|
|
563
|
-
"nächstes quartal"
|
|
564
|
-
],
|
|
565
|
-
[
|
|
566
|
-
"vergangenes jahr",
|
|
567
|
-
"year",
|
|
568
|
-
-1,
|
|
569
|
-
"letztes jahr"
|
|
570
|
-
],
|
|
571
|
-
[
|
|
572
|
-
"vorheriges jahr",
|
|
573
|
-
"year",
|
|
574
|
-
-1,
|
|
575
|
-
"letztes jahr"
|
|
576
|
-
],
|
|
577
|
-
[
|
|
578
|
-
"aktuelles jahr",
|
|
579
|
-
"year",
|
|
580
|
-
0,
|
|
581
|
-
"dieses jahr"
|
|
582
|
-
],
|
|
583
|
-
[
|
|
584
|
-
"laufendes jahr",
|
|
585
|
-
"year",
|
|
586
|
-
0,
|
|
587
|
-
"dieses jahr"
|
|
588
|
-
],
|
|
589
|
-
[
|
|
590
|
-
"kommendes jahr",
|
|
591
|
-
"year",
|
|
592
|
-
1,
|
|
593
|
-
"nächstes jahr"
|
|
594
|
-
],
|
|
595
|
-
[
|
|
596
|
-
"folgendes jahr",
|
|
597
|
-
"year",
|
|
598
|
-
1,
|
|
599
|
-
"nächstes jahr"
|
|
600
|
-
]
|
|
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]
|
|
601
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
|
+
};
|
|
602
273
|
const monthNumber = (value) => {
|
|
603
274
|
const normalized = value.endsWith(".") ? value.slice(0, -1) : value;
|
|
604
275
|
const fullIndex = months.findIndex((month) => month === normalized);
|
|
@@ -606,11 +277,26 @@ const monthNumber = (value) => {
|
|
|
606
277
|
const shortIndex = monthAbbreviations.findIndex((aliases) => aliases.some((alias) => alias === normalized));
|
|
607
278
|
return shortIndex === -1 ? void 0 : shortIndex + 1;
|
|
608
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
|
+
};
|
|
609
292
|
const currentDateLabel = (day, month) => `${day}. ${title(textAt(months, month - 1))}`;
|
|
610
293
|
const withRelativeCase = (canonical, grammaticalCase) => {
|
|
611
|
-
const
|
|
612
|
-
if (
|
|
613
|
-
|
|
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)}`;
|
|
614
300
|
};
|
|
615
301
|
const withRelativeGenitive = (canonical) => {
|
|
616
302
|
for (const entry of unitPhrases) {
|
|
@@ -624,15 +310,7 @@ const parseNamedDate = (input) => {
|
|
|
624
310
|
const named = String$1.match(/^([0-3]?\d)\.? ([a-zäöüß]+\.?) (\d{4})$/u)(input);
|
|
625
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}`);
|
|
626
312
|
const numeric = String$1.match(/^([0-3]?\d)\.([01]?\d)\.(\d{4})$/u)(input);
|
|
627
|
-
if (Option.isSome(numeric)) {
|
|
628
|
-
const year = validYear(textAt(numeric.value, 3));
|
|
629
|
-
const day = Number(textAt(numeric.value, 1));
|
|
630
|
-
const month = Number(textAt(numeric.value, 2));
|
|
631
|
-
if (year !== void 0 && month >= 1 && month <= 12) {
|
|
632
|
-
const value = isoDate(year, month, day);
|
|
633
|
-
if (isIsoDate(value) && value !== "9999-12-31") return Option.some(fixedDatePeriod(value, `${day}. ${title(textAt(months, month - 1))} ${year}`));
|
|
634
|
-
}
|
|
635
|
-
}
|
|
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}`);
|
|
636
314
|
const current = String$1.match(/^([0-3]?\d)\.? ([a-zäöüß]+\.?)$/u)(input);
|
|
637
315
|
return Option.isSome(current) ? namedCurrentYearDatePeriod(textAt(current.value, 2), textAt(current.value, 1), monthNumber, currentDateLabel) : Option.none();
|
|
638
316
|
};
|
|
@@ -699,12 +377,16 @@ const parseDatedPeriod = (input) => {
|
|
|
699
377
|
return Option.none();
|
|
700
378
|
};
|
|
701
379
|
const parseRelativeMonth = (input) => {
|
|
702
|
-
const prefixedRelativeMonth = String$1.match(/^(
|
|
380
|
+
const prefixedRelativeMonth = String$1.match(/^(letzt|dies|nächst)(?:er|en|em) ([a-zäöüß]+\.?)$/u)(input);
|
|
703
381
|
if (Option.isSome(prefixedRelativeMonth)) {
|
|
704
382
|
const month = monthNumber(textAt(prefixedRelativeMonth.value, 2));
|
|
705
383
|
if (month !== void 0) {
|
|
706
|
-
const
|
|
707
|
-
const
|
|
384
|
+
const direction = relativeDirection(textAt(prefixedRelativeMonth.value, 1));
|
|
385
|
+
const modifier = textAt([
|
|
386
|
+
"letzter",
|
|
387
|
+
"dieser",
|
|
388
|
+
"nächster"
|
|
389
|
+
], direction + 1);
|
|
708
390
|
return Option.some(monthOfRelativeYear(month, direction, `${modifier} ${title(textAt(months, month - 1))}`));
|
|
709
391
|
}
|
|
710
392
|
}
|
|
@@ -736,28 +418,58 @@ const parseBasePeriod = (input) => {
|
|
|
736
418
|
if (input === relative.next) direction = 1;
|
|
737
419
|
return Option.some(relativePeriod(relative.unit, direction, canonicalRelative(input)));
|
|
738
420
|
}
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
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
|
+
});
|
|
742
459
|
};
|
|
743
460
|
const parsePeriod = (input) => {
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
const
|
|
747
|
-
const
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
if (Option.isSome(amount) && entry !== void 0 && Option.isSome(period)) {
|
|
755
|
-
const past = textAt(shifted.value, 2) === "vor";
|
|
756
|
-
const direction = past ? -amount.value : amount.value;
|
|
757
|
-
const noun = amount.value === 1 ? entry.noun : entry.dative;
|
|
758
|
-
const canonical = `${period.value.canonical} ${past ? "vor" : "in"} ${amount.value} ${title(noun)}`;
|
|
759
|
-
return Option.some(shiftPeriod(period.value, direction, entry.unit, canonical));
|
|
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
|
+
}
|
|
760
471
|
}
|
|
472
|
+
separator = input.indexOf(" ", offsetStart);
|
|
761
473
|
}
|
|
762
474
|
const edge = String$1.match(/^(anfang|beginn|ende) (.+)$/u)(input);
|
|
763
475
|
if (Option.isSome(edge)) {
|
|
@@ -814,50 +526,19 @@ const boundaryCandidate = (input) => Option.map(openBoundaryCandidate(input, [
|
|
|
814
526
|
["bis ", "before"],
|
|
815
527
|
["ab ", "since"]
|
|
816
528
|
], parsePeriod), (result) => candidate(result.range, canonicalRelative(input)));
|
|
817
|
-
const
|
|
818
|
-
if (amount === 1) return value === entry.noun;
|
|
819
|
-
return value === (dative ? entry.dative : entry.plural);
|
|
820
|
-
});
|
|
821
|
-
const parseCalendarOffset = (input) => {
|
|
822
|
-
const singular = String$1.match(/^(vor|in) (einem tag|einer woche|einem monat|einem quartal|einem jahr)$/u)(input);
|
|
823
|
-
if (Option.isSome(singular)) {
|
|
824
|
-
const entry = unitPhrases.find((unit) => unit.indefiniteDative === textAt(singular.value, 2));
|
|
825
|
-
if (entry !== void 0) {
|
|
826
|
-
const isPast = textAt(singular.value, 1) === "vor";
|
|
827
|
-
const direction = isPast ? -1 : 1;
|
|
828
|
-
const canonical = `${isPast ? "vor" : "in"} ${canonicalRelative(entry.indefiniteDative)}`;
|
|
829
|
-
return Option.some(relativePeriod(entry.unit, direction, canonical));
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
const prefixed = String$1.match(/^(vor|in) ([1-9]\d*) (tag|tagen|woche|wochen|monat|monaten|quartal|quartalen|jahr|jahren)$/u)(input);
|
|
833
|
-
const prior = String$1.match(/^([1-9]\d*) (tag|tage|woche|wochen|monat|monate|quartal|quartale|jahr|jahre) zuvor$/u)(input);
|
|
834
|
-
const match = Option.firstSomeOf([prefixed, prior]);
|
|
835
|
-
if (Option.isNone(match)) return Option.none();
|
|
836
|
-
const amountText = textAt(match.value, Option.isSome(prefixed) ? 2 : 1);
|
|
837
|
-
const unitText = textAt(match.value, Option.isSome(prefixed) ? 3 : 2);
|
|
838
|
-
const amount = parseTrailingCount(amountText);
|
|
839
|
-
if (Option.isNone(amount)) return Option.none();
|
|
840
|
-
const entry = countedUnit(unitText, amount.value, Option.isSome(prefixed));
|
|
841
|
-
if (entry === void 0) return Option.none();
|
|
842
|
-
const isPast = Option.isSome(prior) || Option.isSome(prefixed) && textAt(match.value, 1) === "vor";
|
|
843
|
-
const direction = isPast ? -amount.value : amount.value;
|
|
844
|
-
const directionName = isPast ? "vor" : "in";
|
|
845
|
-
const noun = amount.value === 1 ? entry.noun : entry.dative;
|
|
846
|
-
const canonical = `${directionName} ${amount.value} ${title(noun)}`;
|
|
847
|
-
return Option.some(relativePeriod(entry.unit, direction, canonical));
|
|
848
|
-
};
|
|
529
|
+
const parseCalendarOffset = (input) => parseCalendarOffsetValue(input).pipe(Option.map((offset) => relativePeriod(offset.entry.unit, offset.amount, offset.canonical)));
|
|
849
530
|
const parseRollingPeriod = (input) => {
|
|
850
|
-
const past = String$1.match(/^(?:(?:die letzten|letzten|letzte|vergangene|vorherige) )?([1-9]\d*) (
|
|
851
|
-
const pastDative = String$1.match(/^(?:(?:in den letzten|in den vergangenen|in den vorherigen) |seit )([1-9]\d*) (
|
|
852
|
-
const singularSince = String$1.match(/^seit (
|
|
853
|
-
const pastGenitive = String$1.match(/^während der letzten ([1-9]\d*) (
|
|
854
|
-
const future = String$1.match(/^(?:die nächsten|nächsten|nächste|kommende) ([1-9]\d*) (
|
|
855
|
-
const futureDative = String$1.match(/^(?:in den nächsten|in den kommenden|innerhalb von) ([1-9]\d*) (
|
|
856
|
-
const singularFuture = String$1.match(/^innerhalb (
|
|
857
|
-
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);
|
|
858
539
|
const match = Option.firstSomeOf([
|
|
859
|
-
past,
|
|
860
540
|
pastDative,
|
|
541
|
+
past,
|
|
861
542
|
singularSince,
|
|
862
543
|
pastGenitive,
|
|
863
544
|
future,
|
|
@@ -894,6 +575,37 @@ const parseElidedDateRange = (input) => {
|
|
|
894
575
|
const suffix = year.length === 0 ? "" : ` ${year}`;
|
|
895
576
|
return joinedPeriodCandidate(`von ${lowerDay}. ${month}${suffix} bis ${upperDay}. ${month}${suffix}`, [["von ", " bis "]], parsePeriod, (lower, upper) => `von ${lower} bis ${upper}`);
|
|
896
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
|
+
};
|
|
897
609
|
const parseGerman = (input) => {
|
|
898
610
|
const remaining = remainingPeriodPhrases.find((entry) => entry.phrase === input);
|
|
899
611
|
if (remaining !== void 0) return Option.some(candidate(remainingPeriodRange(remaining.entry.unit), `Rest ${canonicalRelative(remaining.entry.genitive)}`));
|
|
@@ -907,6 +619,8 @@ const parseGerman = (input) => {
|
|
|
907
619
|
if (Option.isSome(currentBoundary)) return currentBoundary;
|
|
908
620
|
const elided = parseElidedDateRange(input);
|
|
909
621
|
if (Option.isSome(elided)) return elided;
|
|
622
|
+
const inheritedYear = sharedRelativeYearRange(input);
|
|
623
|
+
if (Option.isSome(inheritedYear)) return inheritedYear;
|
|
910
624
|
const nowBounded = joinedNowCandidate(input, [
|
|
911
625
|
["von ", " bis heute"],
|
|
912
626
|
["vom ", " bis heute"],
|
|
@@ -918,28 +632,7 @@ const parseGerman = (input) => {
|
|
|
918
632
|
"jetzt bis "
|
|
919
633
|
], parsePeriod, (period) => `von ${period} bis heute`, (period) => `von heute bis ${period}`);
|
|
920
634
|
if (Option.isSome(nowBounded)) return nowBounded;
|
|
921
|
-
const bounded = joinedPeriodCandidate(input,
|
|
922
|
-
["von ", " bis einschließlich "],
|
|
923
|
-
["vom ", " bis einschließlich "],
|
|
924
|
-
["von ", " bis zum "],
|
|
925
|
-
["vom ", " bis zum "],
|
|
926
|
-
["von ", " bis "],
|
|
927
|
-
["vom ", " bis "],
|
|
928
|
-
["zwischen ", " und "],
|
|
929
|
-
["", " bis einschließlich "],
|
|
930
|
-
["", " bis "],
|
|
931
|
-
["", " - "],
|
|
932
|
-
["", " – "],
|
|
933
|
-
["", " — "],
|
|
934
|
-
["zwischen ", "-"],
|
|
935
|
-
["", "-"],
|
|
936
|
-
["zwischen ", "–"],
|
|
937
|
-
["", "–"],
|
|
938
|
-
["zwischen ", "—"],
|
|
939
|
-
["", "—"],
|
|
940
|
-
["zwischen ", "~"],
|
|
941
|
-
["", "~"]
|
|
942
|
-
], parsePeriod, (lower, upper) => `von ${lower} bis ${upper}`);
|
|
635
|
+
const bounded = joinedPeriodCandidate(input, boundedJoins, parsePeriod, (lower, upper) => `von ${lower} bis ${upper}`);
|
|
943
636
|
if (Option.isSome(bounded)) return bounded;
|
|
944
637
|
const boundary = boundaryCandidate(input);
|
|
945
638
|
if (Option.isSome(boundary)) return boundary;
|
|
@@ -978,7 +671,8 @@ const staticPeriodPhrases = [
|
|
|
978
671
|
`letzter ${month}`,
|
|
979
672
|
`nächster ${month}`,
|
|
980
673
|
`${month} letzten jahres`,
|
|
981
|
-
`${month} nächsten jahres
|
|
674
|
+
`${month} nächsten jahres`,
|
|
675
|
+
`${month} vor einem jahr`
|
|
982
676
|
]),
|
|
983
677
|
...nextWeekdays.map((entry) => entry.phrase)
|
|
984
678
|
];
|
|
@@ -1017,12 +711,20 @@ const germanSuggestionPhrases = [
|
|
|
1017
711
|
]),
|
|
1018
712
|
...staticPeriodPhrases,
|
|
1019
713
|
...currentBoundaryPhrases.map((entry) => entry.phrase),
|
|
1020
|
-
...
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
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
|
+
})),
|
|
1026
728
|
...prefixNaturalPhrases(months, boundaryPrefixes),
|
|
1027
729
|
"bis heute",
|
|
1028
730
|
"ab jetzt"
|
|
@@ -1043,9 +745,9 @@ const renderGerman = (range) => {
|
|
|
1043
745
|
const entry = unitPhrases.find((unit) => unit.unit === shifted.value.unit);
|
|
1044
746
|
if (Option.isSome(base) && entry !== void 0) {
|
|
1045
747
|
const amount = Math.abs(shifted.value.amount);
|
|
1046
|
-
const
|
|
748
|
+
const offset = amount === 1 ? canonicalRelative(entry.indefiniteDative) : `${amount} ${title(entry.dative)}`;
|
|
1047
749
|
const direction = shifted.value.amount < 0 ? "vor" : "in";
|
|
1048
|
-
return Option.some(`${base.value} ${direction} ${
|
|
750
|
+
return Option.some(`${base.value} ${direction} ${offset}`);
|
|
1049
751
|
}
|
|
1050
752
|
}
|
|
1051
753
|
const offset = calendarPeriodOffset(range);
|
|
@@ -1069,7 +771,7 @@ const renderGerman = (range) => {
|
|
|
1069
771
|
...currentYearDatePeriods(range, currentDateLabel),
|
|
1070
772
|
...periodsFromPhrases([...dated, ...dated.flatMap((phrase) => [`anfang ${phrase}`, `ende ${phrase}`])], parsePeriod)
|
|
1071
773
|
];
|
|
1072
|
-
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");
|
|
1073
775
|
};
|
|
1074
776
|
const GermanContribution = new BaseLanguageContribution({
|
|
1075
777
|
locale: "de",
|
|
@@ -1085,7 +787,7 @@ const GermanContribution = new BaseLanguageContribution({
|
|
|
1085
787
|
...toDatePhrases.flatMap((entry) => entry.phrase.split(" ")),
|
|
1086
788
|
...remainingPeriodPhrases.flatMap((entry) => entry.phrase.split(" ")),
|
|
1087
789
|
...currentBoundaryPhrases.flatMap((entry) => entry.phrase.split(" ")),
|
|
1088
|
-
...
|
|
790
|
+
...relativeModifierVocabulary,
|
|
1089
791
|
...unitPhrases.flatMap((entry) => [
|
|
1090
792
|
entry.noun,
|
|
1091
793
|
entry.plural,
|
|
@@ -1123,6 +825,8 @@ const GermanContribution = new BaseLanguageContribution({
|
|
|
1123
825
|
"letzten",
|
|
1124
826
|
"nach",
|
|
1125
827
|
"nächste",
|
|
828
|
+
"auflaufend",
|
|
829
|
+
"per",
|
|
1126
830
|
"nächsten",
|
|
1127
831
|
"seit",
|
|
1128
832
|
"vor",
|