chronolizer 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -7
- package/dist/ast/constructors.d.mts +140 -0
- package/dist/ast/constructors.mjs +25 -0
- package/dist/ast/fold.d.mts +12 -0
- package/dist/ast/fold.mjs +51 -0
- package/dist/ast/normalize.d.mts +42 -0
- package/dist/ast/normalize.mjs +32 -0
- package/dist/ast/schemas.d.mts +87 -0
- package/dist/ast/schemas.mjs +74 -0
- package/dist/filter/codec.d.mts +92 -0
- package/dist/filter/codec.mjs +48 -0
- package/dist/filter/errors.d.mts +14 -0
- package/dist/filter/errors.mjs +10 -0
- package/dist/filter/expression.d.mts +8 -0
- package/dist/filter/expression.mjs +93 -0
- package/dist/filter/schema.d.mts +13 -0
- package/dist/filter/schema.mjs +11 -0
- package/dist/filter/transformation.d.mts +37 -0
- package/dist/filter/transformation.mjs +20 -0
- package/dist/index.d.mts +22 -969
- package/dist/index.mjs +22 -2305
- package/dist/language/errors.d.mts +38 -0
- package/dist/language/errors.mjs +30 -0
- package/dist/language/model.d.mts +239 -0
- package/dist/language/model.mjs +53 -0
- package/dist/language/registry.d.mts +17 -0
- package/dist/language/registry.mjs +134 -0
- package/dist/locales/cs.d.mts +10 -0
- package/dist/locales/cs.mjs +693 -0
- package/dist/locales/de.d.mts +10 -0
- package/dist/locales/de.mjs +828 -0
- package/dist/locales/en.d.mts +10 -0
- package/dist/locales/en.mjs +550 -0
- package/dist/locales/es.d.mts +10 -0
- package/dist/locales/es.mjs +660 -0
- package/dist/locales/fr.d.mts +10 -0
- package/dist/locales/fr.mjs +737 -0
- package/dist/locales/nl.d.mts +10 -0
- package/dist/locales/nl.mjs +652 -0
- package/dist/locales/pl.d.mts +10 -0
- package/dist/locales/pl.mjs +711 -0
- package/dist/locales/shared.mjs +289 -0
- package/dist/locales/tr.d.mts +10 -0
- package/dist/locales/tr.mjs +660 -0
- package/dist/natural/correction.d.mts +13 -0
- package/dist/natural/correction.mjs +73 -0
- package/dist/natural/format.d.mts +47 -0
- package/dist/natural/format.mjs +14 -0
- package/dist/natural/parse.d.mts +99 -0
- package/dist/natural/parse.mjs +66 -0
- package/dist/natural/policy.mjs +6 -0
- package/dist/natural/suggest.d.mts +53 -0
- package/dist/natural/suggest.mjs +24 -0
- package/dist/natural/suggestion.d.mts +4 -0
- package/dist/natural/suggestion.mjs +79 -0
- package/dist/natural/text.d.mts +5 -0
- package/dist/natural/text.mjs +5 -0
- package/dist/resolve/resolve.d.mts +79 -0
- package/dist/resolve/resolve.mjs +66 -0
- package/dist/resolve/schema.d.mts +59 -0
- package/dist/resolve/schema.mjs +28 -0
- package/package.json +15 -3
|
@@ -0,0 +1,693 @@
|
|
|
1
|
+
import { isIsoDate } from "../ast/schemas.mjs";
|
|
2
|
+
import { BaseLanguageContribution } from "../language/model.mjs";
|
|
3
|
+
import { normalizeNaturalText } from "../natural/text.mjs";
|
|
4
|
+
import { defineLanguagePlugin, languagePluginsLayer } from "../language/registry.mjs";
|
|
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";
|
|
8
|
+
import { Effect, Option, String as String$1 } from "effect";
|
|
9
|
+
//#region src/locales/cs.ts
|
|
10
|
+
const months = [
|
|
11
|
+
"leden",
|
|
12
|
+
"únor",
|
|
13
|
+
"březen",
|
|
14
|
+
"duben",
|
|
15
|
+
"květen",
|
|
16
|
+
"červen",
|
|
17
|
+
"červenec",
|
|
18
|
+
"srpen",
|
|
19
|
+
"září",
|
|
20
|
+
"říjen",
|
|
21
|
+
"listopad",
|
|
22
|
+
"prosinec"
|
|
23
|
+
];
|
|
24
|
+
const monthGenitives = [
|
|
25
|
+
"ledna",
|
|
26
|
+
"února",
|
|
27
|
+
"března",
|
|
28
|
+
"dubna",
|
|
29
|
+
"května",
|
|
30
|
+
"června",
|
|
31
|
+
"července",
|
|
32
|
+
"srpna",
|
|
33
|
+
"září",
|
|
34
|
+
"října",
|
|
35
|
+
"listopadu",
|
|
36
|
+
"prosince"
|
|
37
|
+
];
|
|
38
|
+
const monthInstrumentals = [
|
|
39
|
+
"lednem",
|
|
40
|
+
"únorem",
|
|
41
|
+
"březnem",
|
|
42
|
+
"dubnem",
|
|
43
|
+
"květnem",
|
|
44
|
+
"červnem",
|
|
45
|
+
"červencem",
|
|
46
|
+
"srpnem",
|
|
47
|
+
"zářím",
|
|
48
|
+
"říjnem",
|
|
49
|
+
"listopadem",
|
|
50
|
+
"prosincem"
|
|
51
|
+
];
|
|
52
|
+
const monthLocatives = [
|
|
53
|
+
"lednu",
|
|
54
|
+
"únoru",
|
|
55
|
+
"březnu",
|
|
56
|
+
"dubnu",
|
|
57
|
+
"květnu",
|
|
58
|
+
"červnu",
|
|
59
|
+
"červenci",
|
|
60
|
+
"srpnu",
|
|
61
|
+
"září",
|
|
62
|
+
"říjnu",
|
|
63
|
+
"listopadu",
|
|
64
|
+
"prosinci"
|
|
65
|
+
];
|
|
66
|
+
const monthAbbreviations = [
|
|
67
|
+
["led"],
|
|
68
|
+
["úno", "uno"],
|
|
69
|
+
["bře", "bre"],
|
|
70
|
+
["dub"],
|
|
71
|
+
["kvě", "kve"],
|
|
72
|
+
["čvn", "cvn"],
|
|
73
|
+
["čvc", "cvc"],
|
|
74
|
+
["srp"],
|
|
75
|
+
["zář", "zar"],
|
|
76
|
+
["říj", "rij"],
|
|
77
|
+
["lis"],
|
|
78
|
+
["pro"]
|
|
79
|
+
];
|
|
80
|
+
const units = [
|
|
81
|
+
{
|
|
82
|
+
unit: "day",
|
|
83
|
+
singular: "den",
|
|
84
|
+
few: "dny",
|
|
85
|
+
many: "dnů",
|
|
86
|
+
pastSingular: "dnem",
|
|
87
|
+
pastPlural: "dny",
|
|
88
|
+
current: "dnes",
|
|
89
|
+
previous: "včera",
|
|
90
|
+
next: "zítra",
|
|
91
|
+
toDate: "dnešek dosud",
|
|
92
|
+
remaining: "zbytek dne"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
unit: "week",
|
|
96
|
+
singular: "týden",
|
|
97
|
+
few: "týdny",
|
|
98
|
+
many: "týdnů",
|
|
99
|
+
pastSingular: "týdnem",
|
|
100
|
+
pastPlural: "týdny",
|
|
101
|
+
current: "tento týden",
|
|
102
|
+
previous: "minulý týden",
|
|
103
|
+
next: "příští týden",
|
|
104
|
+
toDate: "týden dosud",
|
|
105
|
+
remaining: "zbytek týdne"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
unit: "month",
|
|
109
|
+
singular: "měsíc",
|
|
110
|
+
few: "měsíce",
|
|
111
|
+
many: "měsíců",
|
|
112
|
+
pastSingular: "měsícem",
|
|
113
|
+
pastPlural: "měsíci",
|
|
114
|
+
current: "tento měsíc",
|
|
115
|
+
previous: "minulý měsíc",
|
|
116
|
+
next: "příští měsíc",
|
|
117
|
+
toDate: "měsíc dosud",
|
|
118
|
+
remaining: "zbytek měsíce"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
unit: "quarter",
|
|
122
|
+
singular: "čtvrtletí",
|
|
123
|
+
few: "čtvrtletí",
|
|
124
|
+
many: "čtvrtletí",
|
|
125
|
+
pastSingular: "čtvrtletím",
|
|
126
|
+
pastPlural: "čtvrtletími",
|
|
127
|
+
current: "toto čtvrtletí",
|
|
128
|
+
previous: "minulé čtvrtletí",
|
|
129
|
+
next: "příští čtvrtletí",
|
|
130
|
+
toDate: "čtvrtletí dosud",
|
|
131
|
+
remaining: "zbytek čtvrtletí"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
unit: "year",
|
|
135
|
+
singular: "rok",
|
|
136
|
+
few: "roky",
|
|
137
|
+
many: "let",
|
|
138
|
+
pastSingular: "rokem",
|
|
139
|
+
pastPlural: "lety",
|
|
140
|
+
current: "tento rok",
|
|
141
|
+
previous: "minulý rok",
|
|
142
|
+
next: "příští rok",
|
|
143
|
+
toDate: "rok dosud",
|
|
144
|
+
remaining: "zbytek roku"
|
|
145
|
+
}
|
|
146
|
+
];
|
|
147
|
+
const title = (value) => `${value.slice(0, 1).toLocaleUpperCase("cs")}${value.slice(1)}`;
|
|
148
|
+
const unitAliases = [
|
|
149
|
+
["den", "day"],
|
|
150
|
+
["dny", "day"],
|
|
151
|
+
["dnů", "day"],
|
|
152
|
+
["dnem", "day"],
|
|
153
|
+
["týden", "week"],
|
|
154
|
+
["týdny", "week"],
|
|
155
|
+
["týdnů", "week"],
|
|
156
|
+
["týdnem", "week"],
|
|
157
|
+
["měsíc", "month"],
|
|
158
|
+
["měsíce", "month"],
|
|
159
|
+
["měsíců", "month"],
|
|
160
|
+
["měsícem", "month"],
|
|
161
|
+
["měsíci", "month"],
|
|
162
|
+
["čtvrtletí", "quarter"],
|
|
163
|
+
["čtvrtletím", "quarter"],
|
|
164
|
+
["čtvrtletími", "quarter"],
|
|
165
|
+
["rok", "year"],
|
|
166
|
+
["roky", "year"],
|
|
167
|
+
["let", "year"],
|
|
168
|
+
["rokem", "year"],
|
|
169
|
+
["lety", "year"]
|
|
170
|
+
];
|
|
171
|
+
const periodAliases = [
|
|
172
|
+
...units.flatMap((entry) => [
|
|
173
|
+
[
|
|
174
|
+
entry.current,
|
|
175
|
+
entry.unit,
|
|
176
|
+
0,
|
|
177
|
+
entry.current
|
|
178
|
+
],
|
|
179
|
+
[
|
|
180
|
+
entry.previous,
|
|
181
|
+
entry.unit,
|
|
182
|
+
-1,
|
|
183
|
+
entry.previous
|
|
184
|
+
],
|
|
185
|
+
[
|
|
186
|
+
entry.next,
|
|
187
|
+
entry.unit,
|
|
188
|
+
1,
|
|
189
|
+
entry.next
|
|
190
|
+
]
|
|
191
|
+
]),
|
|
192
|
+
[
|
|
193
|
+
"tohoto týdne",
|
|
194
|
+
"week",
|
|
195
|
+
0,
|
|
196
|
+
"tento týden"
|
|
197
|
+
],
|
|
198
|
+
[
|
|
199
|
+
"minulého týdne",
|
|
200
|
+
"week",
|
|
201
|
+
-1,
|
|
202
|
+
"minulý týden"
|
|
203
|
+
],
|
|
204
|
+
[
|
|
205
|
+
"příštího týdne",
|
|
206
|
+
"week",
|
|
207
|
+
1,
|
|
208
|
+
"příští týden"
|
|
209
|
+
],
|
|
210
|
+
[
|
|
211
|
+
"tohoto měsíce",
|
|
212
|
+
"month",
|
|
213
|
+
0,
|
|
214
|
+
"tento měsíc"
|
|
215
|
+
],
|
|
216
|
+
[
|
|
217
|
+
"minulého měsíce",
|
|
218
|
+
"month",
|
|
219
|
+
-1,
|
|
220
|
+
"minulý měsíc"
|
|
221
|
+
],
|
|
222
|
+
[
|
|
223
|
+
"příštího měsíce",
|
|
224
|
+
"month",
|
|
225
|
+
1,
|
|
226
|
+
"příští měsíc"
|
|
227
|
+
],
|
|
228
|
+
[
|
|
229
|
+
"tohoto čtvrtletí",
|
|
230
|
+
"quarter",
|
|
231
|
+
0,
|
|
232
|
+
"toto čtvrtletí"
|
|
233
|
+
],
|
|
234
|
+
[
|
|
235
|
+
"minulého čtvrtletí",
|
|
236
|
+
"quarter",
|
|
237
|
+
-1,
|
|
238
|
+
"minulé čtvrtletí"
|
|
239
|
+
],
|
|
240
|
+
[
|
|
241
|
+
"příštího čtvrtletí",
|
|
242
|
+
"quarter",
|
|
243
|
+
1,
|
|
244
|
+
"příští čtvrtletí"
|
|
245
|
+
],
|
|
246
|
+
[
|
|
247
|
+
"tohoto roku",
|
|
248
|
+
"year",
|
|
249
|
+
0,
|
|
250
|
+
"tento rok"
|
|
251
|
+
],
|
|
252
|
+
[
|
|
253
|
+
"minulého roku",
|
|
254
|
+
"year",
|
|
255
|
+
-1,
|
|
256
|
+
"minulý rok"
|
|
257
|
+
],
|
|
258
|
+
[
|
|
259
|
+
"příštího roku",
|
|
260
|
+
"year",
|
|
261
|
+
1,
|
|
262
|
+
"příští rok"
|
|
263
|
+
],
|
|
264
|
+
[
|
|
265
|
+
"předevčírem",
|
|
266
|
+
"day",
|
|
267
|
+
-2,
|
|
268
|
+
"předevčírem"
|
|
269
|
+
],
|
|
270
|
+
[
|
|
271
|
+
"pozítří",
|
|
272
|
+
"day",
|
|
273
|
+
2,
|
|
274
|
+
"pozítří"
|
|
275
|
+
],
|
|
276
|
+
[
|
|
277
|
+
"předminulý týden",
|
|
278
|
+
"week",
|
|
279
|
+
-2,
|
|
280
|
+
"předminulý týden"
|
|
281
|
+
],
|
|
282
|
+
[
|
|
283
|
+
"přespříští týden",
|
|
284
|
+
"week",
|
|
285
|
+
2,
|
|
286
|
+
"přespříští týden"
|
|
287
|
+
],
|
|
288
|
+
[
|
|
289
|
+
"předminulý měsíc",
|
|
290
|
+
"month",
|
|
291
|
+
-2,
|
|
292
|
+
"předminulý měsíc"
|
|
293
|
+
],
|
|
294
|
+
[
|
|
295
|
+
"přespříští měsíc",
|
|
296
|
+
"month",
|
|
297
|
+
2,
|
|
298
|
+
"přespříští měsíc"
|
|
299
|
+
],
|
|
300
|
+
[
|
|
301
|
+
"předminulé čtvrtletí",
|
|
302
|
+
"quarter",
|
|
303
|
+
-2,
|
|
304
|
+
"předminulé čtvrtletí"
|
|
305
|
+
],
|
|
306
|
+
[
|
|
307
|
+
"přespříští čtvrtletí",
|
|
308
|
+
"quarter",
|
|
309
|
+
2,
|
|
310
|
+
"přespříští čtvrtletí"
|
|
311
|
+
],
|
|
312
|
+
[
|
|
313
|
+
"předminulý rok",
|
|
314
|
+
"year",
|
|
315
|
+
-2,
|
|
316
|
+
"předminulý rok"
|
|
317
|
+
],
|
|
318
|
+
[
|
|
319
|
+
"přespříští rok",
|
|
320
|
+
"year",
|
|
321
|
+
2,
|
|
322
|
+
"přespříští rok"
|
|
323
|
+
]
|
|
324
|
+
];
|
|
325
|
+
const toDatePhrases = units.flatMap((entry) => {
|
|
326
|
+
const yearAliases = entry.unit === "year" ? [
|
|
327
|
+
"od začátku roku",
|
|
328
|
+
"od počátku roku",
|
|
329
|
+
"od začátku roku do dneška",
|
|
330
|
+
"letos dosud"
|
|
331
|
+
] : [];
|
|
332
|
+
return [
|
|
333
|
+
entry.toDate,
|
|
334
|
+
`${entry.current} dosud`,
|
|
335
|
+
...yearAliases
|
|
336
|
+
].map((phrase) => ({
|
|
337
|
+
entry,
|
|
338
|
+
phrase
|
|
339
|
+
}));
|
|
340
|
+
});
|
|
341
|
+
const remainingPhrases = units.map((entry) => ({
|
|
342
|
+
entry,
|
|
343
|
+
phrase: entry.remaining
|
|
344
|
+
}));
|
|
345
|
+
const relativeYearDirection = (value) => {
|
|
346
|
+
if (value.includes("minul")) return -1;
|
|
347
|
+
if (value.includes("příšt")) return 1;
|
|
348
|
+
return 0;
|
|
349
|
+
};
|
|
350
|
+
const relativeYearName = (direction) => {
|
|
351
|
+
if (direction < 0) return "minulého roku";
|
|
352
|
+
if (direction > 0) return "příštího roku";
|
|
353
|
+
return "tohoto roku";
|
|
354
|
+
};
|
|
355
|
+
const monthNumber = (value) => {
|
|
356
|
+
const normalized = value.endsWith(".") ? value.slice(0, -1) : value;
|
|
357
|
+
const full = months.findIndex((month, index) => month === normalized || textAt(monthGenitives, index) === normalized || textAt(monthInstrumentals, index) === normalized || textAt(monthLocatives, index) === normalized);
|
|
358
|
+
if (full !== -1) return full + 1;
|
|
359
|
+
const short = monthAbbreviations.findIndex((aliases) => aliases.some((alias) => alias === normalized));
|
|
360
|
+
return short === -1 ? void 0 : short + 1;
|
|
361
|
+
};
|
|
362
|
+
const dateLabel = (day, month, year) => `${day}. ${textAt(monthGenitives, month - 1)} ${year}`;
|
|
363
|
+
const parseNamedDate = (input) => {
|
|
364
|
+
const named = String$1.match(/^([0-3]?\d)\.?(?: )([a-záčďéěíňóřšťúůýž]+\.?) (\d{4})$/u)(input);
|
|
365
|
+
if (Option.isSome(named)) return namedDatePeriod(textAt(named.value, 3), textAt(named.value, 2), textAt(named.value, 1), monthNumber, dateLabel);
|
|
366
|
+
const numeric = String$1.match(/^([0-3]?\d)(?:\. ?|[/-])([01]?\d)(?:\. ?|[/-])(\d{4})$/u)(input);
|
|
367
|
+
if (Option.isNone(numeric)) return Option.none();
|
|
368
|
+
const year = validYear(textAt(numeric.value, 3));
|
|
369
|
+
const month = Number(textAt(numeric.value, 2));
|
|
370
|
+
const day = Number(textAt(numeric.value, 1));
|
|
371
|
+
if (year === void 0 || month < 1 || month > 12) return Option.none();
|
|
372
|
+
const value = isoDate(year, month, day);
|
|
373
|
+
return isIsoDate(value) && value !== "9999-12-31" ? Option.some(fixedDatePeriod(value, dateLabel(day, month, year))) : Option.none();
|
|
374
|
+
};
|
|
375
|
+
const quarterNumber = (value) => {
|
|
376
|
+
if (value.startsWith("q") && value.length === 2) return Number(value.slice(1));
|
|
377
|
+
if (value === "1." || value === "první") return 1;
|
|
378
|
+
if (value === "2." || value === "druhé") return 2;
|
|
379
|
+
if (value === "3." || value === "třetí") return 3;
|
|
380
|
+
return value === "4." || value === "čtvrté" ? 4 : void 0;
|
|
381
|
+
};
|
|
382
|
+
const parseQuarter = (input) => {
|
|
383
|
+
const fixed = String$1.match(/^(q[1-4]|1\.|první|2\.|druhé|3\.|třetí|4\.|čtvrté)(?: čtvrtletí)? (\d{4})$/u)(input);
|
|
384
|
+
if (Option.isSome(fixed)) {
|
|
385
|
+
const quarter = quarterNumber(textAt(fixed.value, 1));
|
|
386
|
+
const year = validYear(textAt(fixed.value, 2));
|
|
387
|
+
if (quarter !== void 0 && year !== void 0) return Option.some(fixedQuarterPeriod(year, quarter, `Q${quarter} ${year}`));
|
|
388
|
+
}
|
|
389
|
+
const relative = String$1.match(/^(q[1-4]) (minulého roku|příštího roku|tohoto roku)$/u)(input);
|
|
390
|
+
if (Option.isSome(relative)) {
|
|
391
|
+
const quarter = quarterNumber(textAt(relative.value, 1));
|
|
392
|
+
const direction = relativeYearDirection(textAt(relative.value, 2));
|
|
393
|
+
if (quarter !== void 0) return Option.some(quarterOfRelativeYear(quarter, direction, `Q${quarter} ${relativeYearName(direction)}`));
|
|
394
|
+
}
|
|
395
|
+
const standalone = String$1.match(/^(q[1-4])$/u)(input);
|
|
396
|
+
if (Option.isNone(standalone)) return Option.none();
|
|
397
|
+
const quarter = quarterNumber(textAt(standalone.value, 1));
|
|
398
|
+
return quarter === void 0 ? Option.none() : Option.some(quarterOfRelativeYear(quarter, 0, `Q${quarter}`));
|
|
399
|
+
};
|
|
400
|
+
const parseBasePeriod = (input) => {
|
|
401
|
+
if (isIsoDate(input) && input !== "9999-12-31") return Option.some(fixedDatePeriod(input, input));
|
|
402
|
+
const namedDate = parseNamedDate(input);
|
|
403
|
+
if (Option.isSome(namedDate)) return namedDate;
|
|
404
|
+
const quarter = parseQuarter(input);
|
|
405
|
+
if (Option.isSome(quarter)) return quarter;
|
|
406
|
+
const yearMatch = String$1.match(/^(?:rok |roku )?(\d{4})$/u)(input);
|
|
407
|
+
if (Option.isSome(yearMatch)) {
|
|
408
|
+
const year = validYear(textAt(yearMatch.value, 1));
|
|
409
|
+
if (year !== void 0) return Option.some(fixedYearPeriod(year, String(year)));
|
|
410
|
+
}
|
|
411
|
+
const monthYear = String$1.match(/^([a-záčďéěíňóřšťúůýž]+\.?) (\d{4})$/u)(input);
|
|
412
|
+
if (Option.isSome(monthYear)) {
|
|
413
|
+
const month = monthNumber(textAt(monthYear.value, 1));
|
|
414
|
+
const year = validYear(textAt(monthYear.value, 2));
|
|
415
|
+
if (month !== void 0 && year !== void 0) return Option.some(fixedMonthPeriod(year, month, `${title(textAt(months, month - 1))} ${year}`));
|
|
416
|
+
}
|
|
417
|
+
const relativeMonth = String$1.match(/^([a-záčďéěíňóřšťúůýž]+\.?) (minulého roku|příštího roku|tohoto roku)$/u)(input);
|
|
418
|
+
const relativeMonthYearFirst = String$1.match(/^(minulého roku|příštího roku|tohoto roku) ([a-záčďéěíňóřšťúůýž]+\.?)$/u)(input);
|
|
419
|
+
const relativeMatch = Option.firstSomeOf([relativeMonth, relativeMonthYearFirst]);
|
|
420
|
+
if (Option.isSome(relativeMatch)) {
|
|
421
|
+
const yearFirst = Option.isSome(relativeMonthYearFirst);
|
|
422
|
+
const monthText = textAt(relativeMatch.value, yearFirst ? 2 : 1);
|
|
423
|
+
const yearText = textAt(relativeMatch.value, yearFirst ? 1 : 2);
|
|
424
|
+
const month = monthNumber(monthText);
|
|
425
|
+
const direction = relativeYearDirection(yearText);
|
|
426
|
+
if (month !== void 0) return Option.some(monthOfRelativeYear(month, direction, `${title(textAt(months, month - 1))} ${relativeYearName(direction)}`));
|
|
427
|
+
}
|
|
428
|
+
const standaloneMonth = monthNumber(input);
|
|
429
|
+
if (standaloneMonth !== void 0) return Option.some(monthOfRelativeYear(standaloneMonth, 0, title(textAt(months, standaloneMonth - 1))));
|
|
430
|
+
const alias = periodAliases.find((entry) => entry[0] === input);
|
|
431
|
+
if (alias !== void 0) return Option.some(relativePeriod(alias[1], alias[2], alias[3]));
|
|
432
|
+
if (["víkend", "tento víkend"].includes(input)) return Option.some(relativeWeekend(0, "tento víkend"));
|
|
433
|
+
if (["minulý víkend", "předchozí víkend"].includes(input)) return Option.some(relativeWeekend(-1, "minulý víkend"));
|
|
434
|
+
if (["příští víkend", "následující víkend"].includes(input)) return Option.some(relativeWeekend(1, "příští víkend"));
|
|
435
|
+
if (input === "předminulý víkend") return Option.some(relativeWeekend(-2, input));
|
|
436
|
+
if (input === "přespříští víkend") return Option.some(relativeWeekend(2, input));
|
|
437
|
+
return Option.none();
|
|
438
|
+
};
|
|
439
|
+
const parsePeriod = (input) => {
|
|
440
|
+
const edge = String$1.match(/^(začátek|počátek|konec) (.+)$/u)(input);
|
|
441
|
+
if (Option.isSome(edge)) {
|
|
442
|
+
const period = parseBasePeriod(textAt(edge.value, 2));
|
|
443
|
+
if (Option.isSome(period)) {
|
|
444
|
+
const isEnd = textAt(edge.value, 1) === "konec";
|
|
445
|
+
const canonical = `${isEnd ? "konec" : "začátek"} ${period.value.canonical}`;
|
|
446
|
+
return Option.some(isEnd ? periodEndDay(period.value, canonical) : periodStartDay(period.value, canonical));
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
const wrapper = [
|
|
450
|
+
"během ",
|
|
451
|
+
"v ",
|
|
452
|
+
"celý ",
|
|
453
|
+
"celé "
|
|
454
|
+
].find((prefix) => input.startsWith(prefix));
|
|
455
|
+
return parseBasePeriod(wrapper === void 0 ? input : input.slice(wrapper.length));
|
|
456
|
+
};
|
|
457
|
+
const countedUnit = (value) => unitAliases.find((entry) => entry[0] === value)?.[1];
|
|
458
|
+
const countedUnitPattern = "den|dny|dnů|dnem|týden|týdny|týdnů|týdnem|měsíc|měsíce|měsíců|měsícem|měsíci|čtvrtletí|čtvrtletím|čtvrtletími|rok|roky|let|rokem|lety";
|
|
459
|
+
const countedPattern = (source) => new RegExp(source.replace("UNIT", countedUnitPattern), "u");
|
|
460
|
+
const calendarPastPattern = countedPattern("^před ([1-9]\\d*) (UNIT)$");
|
|
461
|
+
const calendarFuturePatterns = [countedPattern("^za ([1-9]\\d*) (UNIT)$")];
|
|
462
|
+
const rollingPastPatterns = [countedPattern("^(?:poslední|posledních|uplynulé|uplynulých) ([1-9]\\d*) (UNIT)$")];
|
|
463
|
+
const rollingFuturePatterns = [countedPattern("^(?:příští|následující) ([1-9]\\d*) (UNIT)$")];
|
|
464
|
+
const rollingSincePattern = countedPattern("^za poslední ([1-9]\\d*) (UNIT)$");
|
|
465
|
+
const rollingBarePattern = countedPattern("^([1-9]\\d*) (UNIT)$");
|
|
466
|
+
const firstPatternMatch = (input, patterns) => Option.firstSomeOf(patterns.map((pattern) => String$1.match(pattern)(input)));
|
|
467
|
+
const countNoun = (amount, entry) => {
|
|
468
|
+
if (amount === 1) return entry.singular;
|
|
469
|
+
const lastTwo = amount % 100;
|
|
470
|
+
const last = amount % 10;
|
|
471
|
+
return last >= 2 && last <= 4 && (lastTwo < 12 || lastTwo > 14) ? entry.few : entry.many;
|
|
472
|
+
};
|
|
473
|
+
const parseCalendarOffset = (input) => {
|
|
474
|
+
const past = String$1.match(calendarPastPattern)(input);
|
|
475
|
+
const future = firstPatternMatch(input, calendarFuturePatterns);
|
|
476
|
+
const match = Option.firstSomeOf([past, future]);
|
|
477
|
+
if (Option.isNone(match)) return Option.none();
|
|
478
|
+
const amount = parseTrailingCount(textAt(match.value, 1));
|
|
479
|
+
const unit = countedUnit(textAt(match.value, 2));
|
|
480
|
+
if (Option.isNone(amount) || unit === void 0) return Option.none();
|
|
481
|
+
const entry = units.find((item) => item.unit === unit);
|
|
482
|
+
if (entry === void 0) return Option.none();
|
|
483
|
+
const direction = Option.isSome(past) ? -amount.value : amount.value;
|
|
484
|
+
const futureNoun = countNoun(amount.value, entry);
|
|
485
|
+
const pastNoun = amount.value === 1 ? entry.pastSingular : entry.pastPlural;
|
|
486
|
+
const canonical = direction < 0 ? `před ${amount.value} ${pastNoun}` : `za ${amount.value} ${futureNoun}`;
|
|
487
|
+
return Option.some(candidate(periodRange(relativePeriod(unit, direction, canonical)), canonical));
|
|
488
|
+
};
|
|
489
|
+
const parseRollingPeriod = (input) => {
|
|
490
|
+
const since = String$1.match(rollingSincePattern)(input);
|
|
491
|
+
const past = firstPatternMatch(input, rollingPastPatterns);
|
|
492
|
+
const bare = String$1.match(rollingBarePattern)(input);
|
|
493
|
+
const future = firstPatternMatch(input, rollingFuturePatterns);
|
|
494
|
+
const match = Option.firstSomeOf([
|
|
495
|
+
since,
|
|
496
|
+
past,
|
|
497
|
+
bare,
|
|
498
|
+
future
|
|
499
|
+
]);
|
|
500
|
+
if (Option.isNone(match)) return Option.none();
|
|
501
|
+
const amount = parseTrailingCount(textAt(match.value, 1));
|
|
502
|
+
const unit = countedUnit(textAt(match.value, 2));
|
|
503
|
+
if (Option.isNone(amount) || unit === void 0) return Option.none();
|
|
504
|
+
const entry = units.find((item) => item.unit === unit);
|
|
505
|
+
if (entry === void 0) return Option.none();
|
|
506
|
+
const isFuture = Option.isSome(future);
|
|
507
|
+
const range = isFuture ? futureRange(amount.value, unit) : trailingRange(amount.value, unit);
|
|
508
|
+
const modifier = isFuture ? "příští" : "poslední";
|
|
509
|
+
return Option.some(candidate(range, `${modifier} ${amount.value} ${countNoun(amount.value, entry)}`));
|
|
510
|
+
};
|
|
511
|
+
const boundaryCandidate = (input) => {
|
|
512
|
+
const included = String$1.match(/^do (.+) včetně$/u)(input);
|
|
513
|
+
if (Option.isSome(included)) return openBoundaryCandidate(`do ${textAt(included.value, 1)}`, [["do ", "through"]], parsePeriod);
|
|
514
|
+
return openBoundaryCandidate(input, [
|
|
515
|
+
["do začátku ", "before"],
|
|
516
|
+
["počínaje ", "since"],
|
|
517
|
+
["od ", "since"],
|
|
518
|
+
["před ", "before"],
|
|
519
|
+
["do ", "through"],
|
|
520
|
+
["po ", "after"]
|
|
521
|
+
], parsePeriod);
|
|
522
|
+
};
|
|
523
|
+
const parseCzech = (input) => {
|
|
524
|
+
const remaining = remainingPhrases.find((entry) => entry.phrase === input);
|
|
525
|
+
if (remaining !== void 0) return Option.some(candidate(remainingPeriodRange(remaining.entry.unit), remaining.entry.remaining));
|
|
526
|
+
if ([
|
|
527
|
+
"do dneška",
|
|
528
|
+
"dosud",
|
|
529
|
+
"do současnosti"
|
|
530
|
+
].includes(input)) return Option.some(candidate(untilNowRange(), "dosud"));
|
|
531
|
+
if ([
|
|
532
|
+
"od nynějška",
|
|
533
|
+
"ode dneška",
|
|
534
|
+
"od teď"
|
|
535
|
+
].includes(input)) return Option.some(candidate(fromNowRange(), "od nynějška"));
|
|
536
|
+
const offset = parseCalendarOffset(input);
|
|
537
|
+
if (Option.isSome(offset)) return offset;
|
|
538
|
+
const rolling = parseRollingPeriod(input);
|
|
539
|
+
if (Option.isSome(rolling)) return rolling;
|
|
540
|
+
const toDate = toDatePhrases.find((entry) => entry.phrase === input);
|
|
541
|
+
if (toDate !== void 0) return Option.some(candidate(periodToDateRange(toDate.entry.unit), toDate.entry.toDate));
|
|
542
|
+
const nowBounded = joinedNowCandidate(input, [["od ", " do dneška"], ["mezi ", " a dneškem"]], ["od dneška do ", "mezi dneškem a "], parsePeriod, (period) => `od ${period} do dneška`, (period) => `od dneška do ${period}`);
|
|
543
|
+
if (Option.isSome(nowBounded)) return nowBounded;
|
|
544
|
+
const bounded = joinedPeriodCandidate(input, [
|
|
545
|
+
["od ", " do "],
|
|
546
|
+
["mezi ", " a "],
|
|
547
|
+
["", " - "],
|
|
548
|
+
["", " – "],
|
|
549
|
+
["", " — "]
|
|
550
|
+
], parsePeriod, (lower, upper) => `od ${lower} do ${upper} včetně`);
|
|
551
|
+
if (Option.isSome(bounded)) return bounded;
|
|
552
|
+
const boundary = boundaryCandidate(input);
|
|
553
|
+
if (Option.isSome(boundary)) return boundary;
|
|
554
|
+
return Option.map(parsePeriod(input), (period) => candidate(periodRange(period), period.canonical));
|
|
555
|
+
};
|
|
556
|
+
const staticPeriodPhrases = [
|
|
557
|
+
...periodAliases.map((entry) => entry[0]),
|
|
558
|
+
"tento víkend",
|
|
559
|
+
"minulý víkend",
|
|
560
|
+
"příští víkend",
|
|
561
|
+
"předminulý víkend",
|
|
562
|
+
"přespříští víkend",
|
|
563
|
+
...periodAliases.flatMap((entry) => [`začátek ${entry[0]}`, `konec ${entry[0]}`]),
|
|
564
|
+
...[
|
|
565
|
+
1,
|
|
566
|
+
2,
|
|
567
|
+
3,
|
|
568
|
+
4
|
|
569
|
+
].flatMap((quarter) => [
|
|
570
|
+
`q${quarter}`,
|
|
571
|
+
`q${quarter} tohoto roku`,
|
|
572
|
+
`q${quarter} minulého roku`,
|
|
573
|
+
`q${quarter} příštího roku`
|
|
574
|
+
]),
|
|
575
|
+
...months.flatMap((month) => [
|
|
576
|
+
month,
|
|
577
|
+
`${month} minulého roku`,
|
|
578
|
+
`${month} příštího roku`
|
|
579
|
+
])
|
|
580
|
+
];
|
|
581
|
+
const staticPeriods = periodsFromPhrases(staticPeriodPhrases, parsePeriod);
|
|
582
|
+
const boundaryPrefixes = [
|
|
583
|
+
"od ",
|
|
584
|
+
"počínaje ",
|
|
585
|
+
"před ",
|
|
586
|
+
"do ",
|
|
587
|
+
"po "
|
|
588
|
+
];
|
|
589
|
+
const countedSuggestions = (input) => {
|
|
590
|
+
const amount = naturalCount(input);
|
|
591
|
+
if (amount === void 0) return [];
|
|
592
|
+
return units.flatMap((entry) => {
|
|
593
|
+
const noun = countNoun(amount, entry);
|
|
594
|
+
const pastNoun = amount === 1 ? entry.pastSingular : entry.pastPlural;
|
|
595
|
+
return [
|
|
596
|
+
`poslední ${amount} ${noun}`,
|
|
597
|
+
`uplynulé ${amount} ${noun}`,
|
|
598
|
+
`${amount} ${noun}`,
|
|
599
|
+
`příští ${amount} ${noun}`,
|
|
600
|
+
`následující ${amount} ${noun}`,
|
|
601
|
+
`před ${amount} ${pastNoun}`,
|
|
602
|
+
`za ${amount} ${noun}`
|
|
603
|
+
];
|
|
604
|
+
});
|
|
605
|
+
};
|
|
606
|
+
const czechSuggestionPhrases = [
|
|
607
|
+
...units.map((entry) => entry.toDate),
|
|
608
|
+
...units.map((entry) => entry.remaining),
|
|
609
|
+
...staticPeriodPhrases,
|
|
610
|
+
...prefixNaturalPhrases(staticPeriodPhrases, boundaryPrefixes),
|
|
611
|
+
"dosud",
|
|
612
|
+
"od nynějška"
|
|
613
|
+
];
|
|
614
|
+
const suggestCzech = (input, limit) => {
|
|
615
|
+
const fixed = fixedCalendarPeriodPhrases(input, months);
|
|
616
|
+
return completeNaturalPhrases(input, [
|
|
617
|
+
...czechSuggestionPhrases,
|
|
618
|
+
...fixed,
|
|
619
|
+
...prefixNaturalPhrases(fixed, boundaryPrefixes),
|
|
620
|
+
...countedSuggestions(input)
|
|
621
|
+
], limit);
|
|
622
|
+
};
|
|
623
|
+
const renderCzech = (range) => {
|
|
624
|
+
const offset = calendarPeriodOffset(range);
|
|
625
|
+
if (Option.isSome(offset) && Math.abs(offset.value.amount) > 1) {
|
|
626
|
+
const entry = units.find((unit) => unit.unit === offset.value.unit);
|
|
627
|
+
if (entry !== void 0) {
|
|
628
|
+
const amount = Math.abs(offset.value.amount);
|
|
629
|
+
const noun = countNoun(amount, entry);
|
|
630
|
+
const pastNoun = amount === 1 ? entry.pastSingular : entry.pastPlural;
|
|
631
|
+
return Option.some(offset.value.amount < 0 ? `před ${amount} ${pastNoun}` : `za ${amount} ${noun}`);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
const future = futurePeriod(range);
|
|
635
|
+
if (Option.isSome(future)) {
|
|
636
|
+
const entry = units.find((unit) => unit.unit === future.value.unit);
|
|
637
|
+
if (entry !== void 0) return Option.some(`příští ${future.value.amount} ${countNoun(future.value.amount, entry)}`);
|
|
638
|
+
}
|
|
639
|
+
const trailing = trailingPeriod(range);
|
|
640
|
+
if (Option.isSome(trailing)) {
|
|
641
|
+
const entry = units.find((unit) => unit.unit === trailing.value.unit);
|
|
642
|
+
if (entry !== void 0) return Option.some(`poslední ${trailing.value.amount} ${countNoun(trailing.value.amount, entry)}`);
|
|
643
|
+
}
|
|
644
|
+
const periods = [...staticPeriods, ...periodsFromPhrases([...datedPeriods(range, months), ...datedQuarterPeriods(range)], parsePeriod)];
|
|
645
|
+
return renderPeriodRange(range, [...units.map((entry) => candidate(periodToDateRange(entry.unit), entry.toDate)), ...units.map((entry) => candidate(remainingPeriodRange(entry.unit), entry.remaining))], periods, (period) => `od ${period}`, (period) => `před ${period}`, (period) => `do ${period} včetně`, (period) => `po ${period}`, (lower, upper) => `od ${lower} do ${upper} včetně`, (period) => `od ${period} do dneška`, (period) => `od dneška do ${period}`, () => "dosud", () => "od nynějška");
|
|
646
|
+
};
|
|
647
|
+
const CzechContribution = new BaseLanguageContribution({
|
|
648
|
+
locale: "cs",
|
|
649
|
+
vocabulary: [
|
|
650
|
+
...months,
|
|
651
|
+
...monthAbbreviations.flatMap((aliases) => aliases),
|
|
652
|
+
...units.flatMap((entry) => [
|
|
653
|
+
entry.singular,
|
|
654
|
+
entry.few,
|
|
655
|
+
entry.many,
|
|
656
|
+
entry.pastSingular,
|
|
657
|
+
entry.pastPlural,
|
|
658
|
+
...entry.current.split(" "),
|
|
659
|
+
...entry.previous.split(" "),
|
|
660
|
+
...entry.next.split(" ")
|
|
661
|
+
]),
|
|
662
|
+
...toDatePhrases.flatMap((entry) => entry.phrase.split(" ")),
|
|
663
|
+
...remainingPhrases.flatMap((entry) => entry.phrase.split(" ")),
|
|
664
|
+
"dosud",
|
|
665
|
+
"dneška",
|
|
666
|
+
"konec",
|
|
667
|
+
"mezi",
|
|
668
|
+
"minulý",
|
|
669
|
+
"následující",
|
|
670
|
+
"nynějška",
|
|
671
|
+
"od",
|
|
672
|
+
"počínaje",
|
|
673
|
+
"poslední",
|
|
674
|
+
"před",
|
|
675
|
+
"příští",
|
|
676
|
+
"uplynulé",
|
|
677
|
+
"včetně",
|
|
678
|
+
"začátek",
|
|
679
|
+
"zbytek"
|
|
680
|
+
],
|
|
681
|
+
normalize: normalizeNaturalText,
|
|
682
|
+
correct: correctWhitespaceSeparatedText,
|
|
683
|
+
parseExact: parseCzech,
|
|
684
|
+
suggest: suggestCzech,
|
|
685
|
+
render: renderCzech
|
|
686
|
+
});
|
|
687
|
+
const CzechLanguage = defineLanguagePlugin({
|
|
688
|
+
id: "chronolizer/language-cs",
|
|
689
|
+
effect: (context) => Effect.asVoid(context.register("chronolizer/language-cs", CzechContribution))
|
|
690
|
+
});
|
|
691
|
+
const CzechLanguageLayer = languagePluginsLayer([CzechLanguage]);
|
|
692
|
+
//#endregion
|
|
693
|
+
export { CzechContribution, CzechLanguage, CzechLanguageLayer };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { LanguageConflictError, LanguageRegistrationError } from "../language/errors.mjs";
|
|
2
|
+
import { BaseLanguageContribution, LanguagePlugin } from "../language/model.mjs";
|
|
3
|
+
import { LanguageRegistry } from "../language/registry.mjs";
|
|
4
|
+
import "../index.mjs";
|
|
5
|
+
//#region src/locales/de.d.ts
|
|
6
|
+
declare const GermanContribution: BaseLanguageContribution;
|
|
7
|
+
declare const GermanLanguage: LanguagePlugin;
|
|
8
|
+
declare const GermanLanguageLayer: import("effect/Layer").Layer<LanguageRegistry, LanguageConflictError | LanguageRegistrationError, never>;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { GermanContribution, GermanLanguage, GermanLanguageLayer };
|