From 639fbc1e37ea28bb9962b13444bf20361022e82d Mon Sep 17 00:00:00 2001 From: citgot Date: Wed, 10 Sep 2025 15:48:13 +0200 Subject: [PATCH 01/14] adding sv-se dir and copy of en-us dir content MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ändringar att checka in: ny fil: numbers/src/main/resources/config/sv-se/date_time.json ny fil: numbers/src/main/resources/config/sv-se/day.word ny fil: numbers/src/main/resources/config/sv-se/days.word ny fil: numbers/src/main/resources/config/sv-se/hour.word ny fil: numbers/src/main/resources/config/sv-se/hours.word ny fil: numbers/src/main/resources/config/sv-se/minute.word ny fil: numbers/src/main/resources/config/sv-se/minutes.word ny fil: numbers/src/main/resources/config/sv-se/second.word ny fil: numbers/src/main/resources/config/sv-se/seconds.word ny fil: numbers/src/main/resources/config/sv-se/tokenizer.json --- .../resources/config/sv-se/date_time.json | 129 +++ .../src/main/resources/config/sv-se/day.word | 1 + .../src/main/resources/config/sv-se/days.word | 1 + .../src/main/resources/config/sv-se/hour.word | 1 + .../main/resources/config/sv-se/hours.word | 1 + .../main/resources/config/sv-se/minute.word | 1 + .../main/resources/config/sv-se/minutes.word | 1 + .../main/resources/config/sv-se/second.word | 1 + .../main/resources/config/sv-se/seconds.word | 1 + .../resources/config/sv-se/tokenizer.json | 857 ++++++++++++++++++ 10 files changed, 994 insertions(+) create mode 100644 numbers/src/main/resources/config/sv-se/date_time.json create mode 100644 numbers/src/main/resources/config/sv-se/day.word create mode 100644 numbers/src/main/resources/config/sv-se/days.word create mode 100644 numbers/src/main/resources/config/sv-se/hour.word create mode 100644 numbers/src/main/resources/config/sv-se/hours.word create mode 100644 numbers/src/main/resources/config/sv-se/minute.word create mode 100644 numbers/src/main/resources/config/sv-se/minutes.word create mode 100644 numbers/src/main/resources/config/sv-se/second.word create mode 100644 numbers/src/main/resources/config/sv-se/seconds.word create mode 100644 numbers/src/main/resources/config/sv-se/tokenizer.json diff --git a/numbers/src/main/resources/config/sv-se/date_time.json b/numbers/src/main/resources/config/sv-se/date_time.json new file mode 100644 index 00000000..9c393b68 --- /dev/null +++ b/numbers/src/main/resources/config/sv-se/date_time.json @@ -0,0 +1,129 @@ +{ + "decade_format": { + "1": {"match": "^\\d$", "format": "{x}"}, + "2": {"match": "^1\\d$", "format": "{xx}"}, + "3": {"match": "^\\d0$", "format": "{x0}"}, + "4": {"match": "^[2-9]\\d$", "format": "{x0} {x}"}, + "default": "{number}" + }, + "hundreds_format": { + "1": {"match": "^\\d{3}$", "format": "{x_in_x00} hundred"}, + "default": "{number}" + }, + "thousand_format": { + "1": {"match": "^\\d00\\d$", "format": "{x_in_x000} thousand"}, + "2": {"match": "^1\\d00$", "format": "{xx_in_xx00} hundred"}, + "3": {"match": "^\\d{2}00$", "format": "{x0_in_x000} {x_in_x00} hundred"}, + "4": {"match": "^(1\\d{3})|(\\d0\\d{2})$", "format": "{xx_in_xx00}"}, + "5": {"match": "^\\d{4}$", "format": "{x0_in_x000} {x_in_x00}"}, + "default": "{number}" + }, + "year_format": { + "1": {"match": "^\\d\\d?$", "format": "{formatted_decade} {bc}"}, + "2": {"match": "^\\d00$", "format": "{formatted_hundreds} {bc}"}, + "3": {"match": "^\\d{3}$", "format": "{formatted_hundreds} {formatted_decade} {bc}"}, + "4": {"match": "^\\d{2}00$", "format": "{formatted_thousand} {bc}"}, + "5": {"match": "^\\d00\\d$", "format": "{formatted_thousand} {formatted_decade} {bc}"}, + "6": {"match": "^\\d{2}0\\d$", "format": "{formatted_thousand} oh {formatted_decade} {bc}"}, + "7": {"match": "^\\d{4}$", "format": "{formatted_thousand} {formatted_decade} {bc}"}, + "default": "{number} {bc}", + "bc": "b.c." + }, + "date_format": { + "date_full": "{weekday}, {month} {day}, {formatted_year}", + "date_full_no_year": "{weekday}, {month} {day}", + "date_full_no_year_month": "{weekday}, the {day}", + "today": "today", + "tomorrow": "tomorrow", + "yesterday": "yesterday" + }, + "date_time_format": { + "date_time": "{formatted_date} at {formatted_time}" + }, + "weekday": { + "0": "monday", + "1": "tuesday", + "2": "wednesday", + "3": "thursday", + "4": "friday", + "5": "saturday", + "6": "sunday" + }, + "date": { + "1": "first", + "2": "second", + "3": "third", + "4": "fourth", + "5": "fifth", + "6": "sixth", + "7": "seventh", + "8": "eighth", + "9": "ninth", + "10": "tenth", + "11": "eleventh", + "12": "twelfth", + "13": "thirteenth", + "14": "fourteenth", + "15": "fifteenth", + "16": "sixteenth", + "17": "seventeenth", + "18": "eighteenth", + "19": "nineteenth", + "20": "twentieth", + "21": "twenty-first", + "22": "twenty-second", + "23": "twenty-third", + "24": "twenty-fourth", + "25": "twenty-fifth", + "26": "twenty-sixth", + "27": "twenty-seventh", + "28": "twenty-eighth", + "29": "twenty-ninth", + "30": "thirtieth", + "31": "thirty-first" + }, + "month": { + "1": "january", + "2": "february", + "3": "march", + "4": "april", + "5": "may", + "6": "june", + "7": "july", + "8": "august", + "9": "september", + "10": "october", + "11": "november", + "12": "december" + }, + "number": { + "0": "zero", + "1": "one", + "2": "two", + "3": "three", + "4": "four", + "5": "five", + "6": "six", + "7": "seven", + "8": "eight", + "9": "nine", + "10": "ten", + "11": "eleven", + "12": "twelve", + "13": "thirteen", + "14": "fourteen", + "15": "fifteen", + "16": "sixteen", + "17": "seventeen", + "18": "eighteen", + "19": "nineteen", + "20": "twenty", + "30": "thirty", + "40": "forty", + "50": "fifty", + "60": "sixty", + "70": "seventy", + "80": "eighty", + "90": "ninety" + } +} diff --git a/numbers/src/main/resources/config/sv-se/day.word b/numbers/src/main/resources/config/sv-se/day.word new file mode 100644 index 00000000..0c303a41 --- /dev/null +++ b/numbers/src/main/resources/config/sv-se/day.word @@ -0,0 +1 @@ +day \ No newline at end of file diff --git a/numbers/src/main/resources/config/sv-se/days.word b/numbers/src/main/resources/config/sv-se/days.word new file mode 100644 index 00000000..5eb8de30 --- /dev/null +++ b/numbers/src/main/resources/config/sv-se/days.word @@ -0,0 +1 @@ +days \ No newline at end of file diff --git a/numbers/src/main/resources/config/sv-se/hour.word b/numbers/src/main/resources/config/sv-se/hour.word new file mode 100644 index 00000000..a13960e9 --- /dev/null +++ b/numbers/src/main/resources/config/sv-se/hour.word @@ -0,0 +1 @@ +hour \ No newline at end of file diff --git a/numbers/src/main/resources/config/sv-se/hours.word b/numbers/src/main/resources/config/sv-se/hours.word new file mode 100644 index 00000000..62c6decf --- /dev/null +++ b/numbers/src/main/resources/config/sv-se/hours.word @@ -0,0 +1 @@ +hours \ No newline at end of file diff --git a/numbers/src/main/resources/config/sv-se/minute.word b/numbers/src/main/resources/config/sv-se/minute.word new file mode 100644 index 00000000..50bc2f27 --- /dev/null +++ b/numbers/src/main/resources/config/sv-se/minute.word @@ -0,0 +1 @@ +minute \ No newline at end of file diff --git a/numbers/src/main/resources/config/sv-se/minutes.word b/numbers/src/main/resources/config/sv-se/minutes.word new file mode 100644 index 00000000..cde6523a --- /dev/null +++ b/numbers/src/main/resources/config/sv-se/minutes.word @@ -0,0 +1 @@ +minutes \ No newline at end of file diff --git a/numbers/src/main/resources/config/sv-se/second.word b/numbers/src/main/resources/config/sv-se/second.word new file mode 100644 index 00000000..2147e418 --- /dev/null +++ b/numbers/src/main/resources/config/sv-se/second.word @@ -0,0 +1 @@ +second \ No newline at end of file diff --git a/numbers/src/main/resources/config/sv-se/seconds.word b/numbers/src/main/resources/config/sv-se/seconds.word new file mode 100644 index 00000000..729866f9 --- /dev/null +++ b/numbers/src/main/resources/config/sv-se/seconds.word @@ -0,0 +1 @@ +seconds \ No newline at end of file diff --git a/numbers/src/main/resources/config/sv-se/tokenizer.json b/numbers/src/main/resources/config/sv-se/tokenizer.json new file mode 100644 index 00000000..c8da189d --- /dev/null +++ b/numbers/src/main/resources/config/sv-se/tokenizer.json @@ -0,0 +1,857 @@ +{ + "spaces": " \t\n\f\r:;_!?<>|=()[]{}»«*~^`'\"", + "characters_as_word": "%‰#-+.,/", + "raw_number_categories": [ + "number", + "raw" + ], + "plural_endings": [ + "s" + ], + "word_matches": [ + { + "categories": [ + "ignore", + "date_time_ignore" + ], + "values": [ + "and" + ] + }, + { + "categories": [ + "ignore", + "date_time_ignore", + "day_adder_the", + "ampm_before", + "bcad_after" + ], + "values": [ + "a" + ] + }, + { + "categories": [ + "ignore", + "date_time_ignore", + "day_adder_the" + ], + "values": [ + "an" + ] + }, + { + "categories": [ + "ignore", + "date_time_ignore", + "thousand_separator" + ], + "values": [ + "," + ] + }, + { + "categories": [ + "ordinal_suffix" + ], + "values": [ + "st", + "nd", + "rd", + "th" + ] + }, + { + "categories": [ + "point" + ], + "values": [ + "point" + ] + }, + { + "categories": [ + "point", + "post_oclock" + ], + "values": [ + "dot" + ] + }, + { + "categories": [ + "point", + "ignore", + "date_time_ignore" + ], + "values": [ + "." + ] + }, + { + "categories": [ + "fraction_separator" + ], + "values": [ + "over", + "divided" + ] + }, + { + "categories": [ + "fraction_separator", + "date_time_ignore" + ], + "values": [ + "/" + ] + }, + { + "categories": [ + "fraction_separator_secondary" + ], + "values": [ + "by" + ] + }, + { + "categories": [ + "sign", + "positive" + ], + "values": [ + "positive", + "plus", + "+" + ] + }, + { + "categories": [ + "sign", + "negative" + ], + "values": [ + "negative", + "minus" + ] + }, + { + "categories": [ + "ignore", + "date_time_ignore", + "sign", + "negative" + ], + "values": [ + "-" + ] + }, + { + "categories": [ + "duration_separator", + "date_time_ignore" + ], + "values": [ + "of" + ] + }, + { + "categories": [ + "yesterday" + ], + "values": [ + "yesterday" + ] + }, + { + "categories": [ + "today" + ], + "values": [ + "today" + ] + }, + { + "categories": [ + "tomorrow" + ], + "values": [ + "tomorrow", + "morrow" + ] + }, + { + "categories": [ + "day_adder_the", + "date_time_ignore", + "pre_hour", + "pre_special_hour" + ], + "values": [ + "the" + ] + }, + { + "categories": [ + "day_adder_day" + ], + "values": [ + "day" + ] + }, + { + "categories": [ + "pre_relative_indicator", + "post_relative_indicator", + "positive", + "day_adder_after", + "special_minute_after", + "pre_special_hour" + ], + "values": [ + "after" + ] + }, + { + "categories": [ + "day_adder_before", + "special_minute_before", + "bcad_before", + "pre_relative_indicator", + "post_relative_indicator", + "negative", + "pre_special_hour" + ], + "values": [ + "before" + ] + }, + { + "categories": [ + "date_time_ignore", + "special_minute_before" + ], + "values": [ + "to" + ] + }, + { + "categories": [ + "special_minute_after", + "pre_relative_indicator", + "negative" + ], + "values": [ + "past" + ] + }, + { + "categories": [ + "pre_hour" + ], + "values": [ + "hour", + "hours" + ] + }, + { + "categories": [ + "pre_hour", + "pre_special_hour" + ], + "values": [ + "at" + ] + }, + { + "categories": [ + "pre_special_hour" + ], + "values": [ + "this", + "these", + "those", + "that" + ] + }, + { + "categories": [ + "pre_special_hour", + "pre_relative_indicator", + "positive", + "pre_oclock" + ], + "values": [ + "on" + ] + }, + { + "categories": [ + "pre_relative_indicator", + "positive" + ], + "values": [ + "next", + "coming", + "upcoming", + "successive", + "succeeding" + ] + }, + { + "categories": [ + "date_time_ignore", + "pre_relative_indicator", + "positive" + ], + "values": [ + "in" + ] + }, + { + "categories": [ + "pre_relative_indicator", + "post_relative_indicator", + "positive" + ], + "values": [ + "following" + ] + }, + { + "categories": [ + "post_relative_indicator", + "negative" + ], + "values": [ + "ago" + ] + }, + { + "categories": [ + "pre_relative_indicator", + "negative" + ], + "values": [ + "previous", + "last", + "preceding", + "passed" + ] + }, + { + "categories": [ + "bcad_before" + ], + "values": [ + "b" + ] + }, + { + "categories": [ + "bcad_after" + ], + "values": [ + "anno" + ] + }, + { + "categories": [ + "bcad_identifier" + ], + "values": [ + "christ", + "domini", + "d" + ] + }, + { + "categories": [ + "bcad_identifier", + "bcad_after" + ], + "values": [ + "c", + "common", + "current" + ] + }, + { + "categories": [ + "bcad_before_combined" + ], + "values": [ + "bc", + "bce" + ] + }, + { + "categories": [ + "bcad_after_combined" + ], + "values": [ + "ad", + "ce" + ] + }, + { + "categories": [ + "bcad_identifier", + "bcad_era" + ], + "values": [ + "era", + "e" + ] + }, + { + "categories": [ + "ampm_before" + ], + "values": [ + "ante" + ] + }, + { + "categories": [ + "ampm_after" + ], + "values": [ + "post", + "p" + ] + }, + { + "categories": [ + "ampm_identifier" + ], + "values": [ + "meridiem", + "meridian", + "m" + ] + }, + { + "categories": [ + "ampm_before_combined" + ], + "values": [ + "am" + ] + }, + { + "categories": [ + "ampm_after_combined" + ], + "values": [ + "pm" + ] + }, + { + "categories": [ + "post_oclock" + ], + "values": [ + "clock" + ] + }, + { + "categories": [ + "oclock_combined" + ], + "values": [ + "oclock", + "exact", + "sharp" + ] + } + ], + "number_mappings": [ + { + "categories": [ + "number", + "digit", + "digit_after_point" + ], + "values": { + "nought": 0, + "zero": 0, + "one": 1, + "two": 2, + "three": 3, + "four": 4, + "five": 5, + "six": 6, + "seven": 7, + "eight": 8, + "nine": 9 + } + }, + { + "categories": [ + "number", + "digit_after_point" + ], + "values": { + "oh": 0 + } + }, + { + "categories": [ + "number", + "digit_after_point", + "pre_oclock" + ], + "values": { + "o": 0 + } + }, + { + "categories": [ + "number", + "teen" + ], + "values": { + "ten": 10, + "eleven": 11, + "twelve": 12, + "thirteen": 13, + "fourteen": 14, + "fifteen": 15, + "sixteen": 16, + "seventeen": 17, + "eighteen": 18, + "nineteen": 19 + } + }, + { + "categories": [ + "number", + "tens" + ], + "values": { + "twenty": 20, + "thirty": 30, + "forty": 40, + "fifty": 50, + "sixty": 60, + "seventy": 70, + "eighty": 80, + "ninety": 90 + } + }, + { + "categories": [ + "number", + "hundred" + ], + "values": { + "hundred": 100 + } + }, + { + "categories": [ + "number", + "multiplier" + ], + "values": { + "thousand": 1000, + "million": 1000000, + "billion": 1000000000, + "trillion": 1000000000000, + "quadrillion": 1000000000000000, + "quintillion": 1000000000000000000 + } + }, + { + "categories": [ + "number", + "ordinal", + "digit" + ], + "values": { + "first": 1, + "second": 2, + "third": 3, + "fourth": 4, + "fifth": 5, + "sixth": 6, + "seventh": 7, + "eighth": 8, + "ninth": 9 + } + }, + { + "categories": [ + "number", + "ordinal", + "teen" + ], + "values": { + "tenth": 10, + "eleventh": 11, + "twelfth": 12, + "thirteenth": 13, + "fourteenth": 14, + "fifteenth": 15, + "sixteenth": 16, + "seventeenth": 17, + "eighteenth": 18, + "nineteenth": 19 + } + }, + { + "categories": [ + "number", + "ordinal", + "tens" + ], + "values": { + "twentieth": 20, + "thirtieth": 30, + "fortieth": 40, + "fiftieth": 50, + "sixtieth": 60, + "seventieth": 70, + "eightieth": 80, + "ninetieth": 90 + } + }, + { + "categories": [ + "number", + "ordinal", + "hundred" + ], + "values": { + "hundredth": 100 + } + }, + { + "categories": [ + "number", + "ordinal", + "multiplier" + ], + "values": { + "thousandth": 1000, + "millionth": 1000000, + "billionth": 1000000000, + "trillionth": 1000000000000, + "quadrillionth": 1000000000000000, + "quintillionth": 1000000000000000000 + } + }, + { + "categories": [ + "number", + "suffix_multiplier" + ], + "values": { + "half": 0.5, + "halves": 0.5, + "quarter": 0.25, + "quarters": 0.25, + "pair": 2, + "pairs": 2, + "couple": 2, + "couples": 2, + "dozen": 12, + "dozens": 12, + "gross": 144, + "grosses": 144, + "score": 20, + "scores": 20, + "percent": 0.01, + "pct": 0.01, + "pc": 0.01, + "%": 0.01, + "permille": 0.001, + "permill": 0.001, + "permil": 0.001, + "‰": 0.001 + } + }, + { + "categories": [ + "month_name" + ], + "values": { + "january": 1, + "jan": 1, + "february": 2, + "feb": 2, + "march": 3, + "mar": 3, + "april": 4, + "apr": 4, + "may": 5, + "june": 6, + "jun": 6, + "july": 7, + "jul": 7, + "august": 8, + "aug": 8, + "september": 9, + "sep": 9, + "sept": 9, + "october": 10, + "oct": 10, + "november": 11, + "nov": 11, + "december": 12, + "dec": 12 + } + }, + { + "categories": [ + "day_of_week" + ], + "values": { + "monday": 0, + "mon": 0, + "tuesday": 1, + "tue": 1, + "wednesday": 2, + "wed": 2, + "thursday": 3, + "thu": 3, + "friday": 4, + "fri": 4, + "saturday": 5, + "sat": 5, + "sunday": 6, + "sun": 6 + } + }, + { + "categories": [ + "noon_midnight_like", + "moment_of_day" + ], + "values": { + "noon": 12, + "noons": 12, + "midday": 12, + "middays": 12, + "midnight": 0, + "midnights": 0 + } + }, + { + "categories": [ + "moment_of_day" + ], + "values": { + "night": 3, + "nights": 3, + "nighttime": 3, + "dawn": 6, + "dawning": 6, + "aurora": 6, + "morning": 9, + "mornings": 9, + "lunch": 12, + "lunches": 12, + "dinner": 20, + "dinners": 20, + "afternoon": 15, + "afternoons": 15, + "sunset": 18, + "dusk": 18, + "evening": 21, + "evenings": 21, + "tonight": 23 + } + } + ], + "duration_words": { + "1 NANOS": [ + "nanosecond", + "nanoseconds", + "ns" + ], + "1 MICROS": [ + "microsecond", + "microseconds", + "μs" + ], + "1 MILLIS": [ + "millisecond", + "milliseconds", + "ms" + ], + "1 SECONDS": [ + "second", + "seconds", + "s", + "sec", + "secs" + ], + "1 MINUTES": [ + "minute", + "minutes", + "m", + "min", + "mins" + ], + "1 HOURS": [ + "hour", + "hours", + "h", + "hr", + "hrs" + ], + "1 DAYS": [ + "day", + "days", + "d" + ], + "1 WEEKS": [ + "week", + "weeks", + "w" + ], + "1 MONTHS": [ + "month", + "months", + "mo", + "mon", + "mons" + ], + "1 YEARS": [ + "year", + "years", + "yr", + "yrs" + ], + "1 DECADES": [ + "decade", + "decades" + ], + "1 CENTURIES": [ + "century", + "centuries" + ], + "1 MILLENNIA": [ + "millenium", + "millennium", + "milleniums", + "millenniums", + "millenia", + "millennia" + ] + }, + "duration_restrict_after_number": [ + "ns", + "μs", + "ms", + "s", + "m", + "h", + "d", + "w", + "mo", + "yr" + ] +} \ No newline at end of file From ec89512ba7e1b4cea7847cb3c87beecad7cc42a1 Mon Sep 17 00:00:00 2001 From: citgot Date: Wed, 10 Sep 2025 15:50:33 +0200 Subject: [PATCH 02/14] Update numbers/src/main/resources/config/sv-se/day.word Translated to swedish --- numbers/src/main/resources/config/sv-se/day.word | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numbers/src/main/resources/config/sv-se/day.word b/numbers/src/main/resources/config/sv-se/day.word index 0c303a41..73e686aa 100644 --- a/numbers/src/main/resources/config/sv-se/day.word +++ b/numbers/src/main/resources/config/sv-se/day.word @@ -1 +1 @@ -day \ No newline at end of file +dag \ No newline at end of file From 6fb6b85fa4e330dd056c6d4f7b714567d40d01b0 Mon Sep 17 00:00:00 2001 From: citgot Date: Wed, 10 Sep 2025 15:51:01 +0200 Subject: [PATCH 03/14] Update numbers/src/main/resources/config/sv-se/days.word Translated to swedish --- numbers/src/main/resources/config/sv-se/days.word | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numbers/src/main/resources/config/sv-se/days.word b/numbers/src/main/resources/config/sv-se/days.word index 5eb8de30..594c6084 100644 --- a/numbers/src/main/resources/config/sv-se/days.word +++ b/numbers/src/main/resources/config/sv-se/days.word @@ -1 +1 @@ -days \ No newline at end of file +dagar \ No newline at end of file From 5754c8b612b2a757b1217ddbd5386aa0aa084137 Mon Sep 17 00:00:00 2001 From: citgot Date: Wed, 10 Sep 2025 15:51:25 +0200 Subject: [PATCH 04/14] Update numbers/src/main/resources/config/sv-se/hour.word Translated to swedish --- numbers/src/main/resources/config/sv-se/hour.word | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numbers/src/main/resources/config/sv-se/hour.word b/numbers/src/main/resources/config/sv-se/hour.word index a13960e9..4f92b0c1 100644 --- a/numbers/src/main/resources/config/sv-se/hour.word +++ b/numbers/src/main/resources/config/sv-se/hour.word @@ -1 +1 @@ -hour \ No newline at end of file +timme \ No newline at end of file From 6519b1766c6f14777313437ac9354a1d04e537a1 Mon Sep 17 00:00:00 2001 From: citgot Date: Wed, 10 Sep 2025 15:51:49 +0200 Subject: [PATCH 05/14] Update numbers/src/main/resources/config/sv-se/hours.word Translated to swedish --- numbers/src/main/resources/config/sv-se/hours.word | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numbers/src/main/resources/config/sv-se/hours.word b/numbers/src/main/resources/config/sv-se/hours.word index 62c6decf..d97697a0 100644 --- a/numbers/src/main/resources/config/sv-se/hours.word +++ b/numbers/src/main/resources/config/sv-se/hours.word @@ -1 +1 @@ -hours \ No newline at end of file +timmar \ No newline at end of file From 6ae76bbfd50546679e5977452d5ca6656c01a331 Mon Sep 17 00:00:00 2001 From: citgot Date: Wed, 10 Sep 2025 15:52:11 +0200 Subject: [PATCH 06/14] Update numbers/src/main/resources/config/sv-se/minute.word Translated to swedish --- numbers/src/main/resources/config/sv-se/minute.word | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numbers/src/main/resources/config/sv-se/minute.word b/numbers/src/main/resources/config/sv-se/minute.word index 50bc2f27..4b98366b 100644 --- a/numbers/src/main/resources/config/sv-se/minute.word +++ b/numbers/src/main/resources/config/sv-se/minute.word @@ -1 +1 @@ -minute \ No newline at end of file +minut \ No newline at end of file From 93034345bbf8b1b05617da8462edd98f424aaa46 Mon Sep 17 00:00:00 2001 From: citgot Date: Wed, 10 Sep 2025 15:52:34 +0200 Subject: [PATCH 07/14] Update numbers/src/main/resources/config/sv-se/minutes.word Translated to swedish --- numbers/src/main/resources/config/sv-se/minutes.word | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numbers/src/main/resources/config/sv-se/minutes.word b/numbers/src/main/resources/config/sv-se/minutes.word index cde6523a..caf1b024 100644 --- a/numbers/src/main/resources/config/sv-se/minutes.word +++ b/numbers/src/main/resources/config/sv-se/minutes.word @@ -1 +1 @@ -minutes \ No newline at end of file +minuter \ No newline at end of file From 6565ccb728a7b51f46c5f6a07ef013301e4aab5e Mon Sep 17 00:00:00 2001 From: citgot Date: Wed, 10 Sep 2025 15:53:00 +0200 Subject: [PATCH 08/14] Update numbers/src/main/resources/config/sv-se/second.word Translated to swedish --- numbers/src/main/resources/config/sv-se/second.word | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numbers/src/main/resources/config/sv-se/second.word b/numbers/src/main/resources/config/sv-se/second.word index 2147e418..300f8e50 100644 --- a/numbers/src/main/resources/config/sv-se/second.word +++ b/numbers/src/main/resources/config/sv-se/second.word @@ -1 +1 @@ -second \ No newline at end of file +sekund \ No newline at end of file From 577ab1b55cd25220d7080abdb8827f7345aa5ba5 Mon Sep 17 00:00:00 2001 From: citgot Date: Wed, 10 Sep 2025 15:53:22 +0200 Subject: [PATCH 09/14] Update numbers/src/main/resources/config/sv-se/seconds.word Translated to swedish --- numbers/src/main/resources/config/sv-se/seconds.word | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numbers/src/main/resources/config/sv-se/seconds.word b/numbers/src/main/resources/config/sv-se/seconds.word index 729866f9..aa5fc120 100644 --- a/numbers/src/main/resources/config/sv-se/seconds.word +++ b/numbers/src/main/resources/config/sv-se/seconds.word @@ -1 +1 @@ -seconds \ No newline at end of file +sekunder \ No newline at end of file From 9f2949ded907efaa019c39f369b8ba9ff262f334 Mon Sep 17 00:00:00 2001 From: citgot Date: Wed, 10 Sep 2025 15:56:21 +0200 Subject: [PATCH 10/14] Update numbers/src/main/resources/config/sv-se/date_time.json Translated to swedish (copied from lingua-franca repo) --- .../resources/config/sv-se/date_time.json | 190 +++++++++--------- 1 file changed, 95 insertions(+), 95 deletions(-) diff --git a/numbers/src/main/resources/config/sv-se/date_time.json b/numbers/src/main/resources/config/sv-se/date_time.json index 9c393b68..de4bf1e0 100644 --- a/numbers/src/main/resources/config/sv-se/date_time.json +++ b/numbers/src/main/resources/config/sv-se/date_time.json @@ -6,124 +6,124 @@ "4": {"match": "^[2-9]\\d$", "format": "{x0} {x}"}, "default": "{number}" }, - "hundreds_format": { - "1": {"match": "^\\d{3}$", "format": "{x_in_x00} hundred"}, + "hundreds_format": { + "1": {"match": "^\\d{3}$", "format": "{x_in_x00} hundra"}, "default": "{number}" }, - "thousand_format": { - "1": {"match": "^\\d00\\d$", "format": "{x_in_x000} thousand"}, - "2": {"match": "^1\\d00$", "format": "{xx_in_xx00} hundred"}, - "3": {"match": "^\\d{2}00$", "format": "{x0_in_x000} {x_in_x00} hundred"}, + "thousand_format": { + "1": {"match": "^\\d00\\d$", "format": "{x_in_x000} tusen"}, + "2": {"match": "^1\\d00$", "format": "{xx_in_xx00} hundra"}, + "3": {"match": "^\\d{2}00$", "format": "{x0_in_x000} {x_in_x00} hundra"}, "4": {"match": "^(1\\d{3})|(\\d0\\d{2})$", "format": "{xx_in_xx00}"}, "5": {"match": "^\\d{4}$", "format": "{x0_in_x000} {x_in_x00}"}, "default": "{number}" }, - "year_format": { + "year_format": { "1": {"match": "^\\d\\d?$", "format": "{formatted_decade} {bc}"}, "2": {"match": "^\\d00$", "format": "{formatted_hundreds} {bc}"}, "3": {"match": "^\\d{3}$", "format": "{formatted_hundreds} {formatted_decade} {bc}"}, "4": {"match": "^\\d{2}00$", "format": "{formatted_thousand} {bc}"}, "5": {"match": "^\\d00\\d$", "format": "{formatted_thousand} {formatted_decade} {bc}"}, - "6": {"match": "^\\d{2}0\\d$", "format": "{formatted_thousand} oh {formatted_decade} {bc}"}, + "6": {"match": "^\\d{2}0\\d$", "format": "{formatted_thousand} noll {formatted_decade} {bc}"}, "7": {"match": "^\\d{4}$", "format": "{formatted_thousand} {formatted_decade} {bc}"}, - "default": "{number} {bc}", - "bc": "b.c." + "default": "{year} {bc}", + "bc": "före kristus" }, - "date_format": { - "date_full": "{weekday}, {month} {day}, {formatted_year}", - "date_full_no_year": "{weekday}, {month} {day}", - "date_full_no_year_month": "{weekday}, the {day}", - "today": "today", - "tomorrow": "tomorrow", - "yesterday": "yesterday" + "date_format": { + "date_full": "{weekday}, den {day} {month}, {formatted_year}", + "date_full_no_year": "{weekday}, den {day} {month}", + "date_full_no_year_month": "{weekday}, den {day}", + "today": "idag", + "tomorrow": "imorgon", + "yesterday": "igår" }, - "date_time_format": { - "date_time": "{formatted_date} at {formatted_time}" + "date_time_format": { + "date_time": "{formatted_date} klockan {formatted_time}" }, - "weekday": { - "0": "monday", - "1": "tuesday", - "2": "wednesday", - "3": "thursday", - "4": "friday", - "5": "saturday", - "6": "sunday" + "weekday": { + "0": "måndag", + "1": "tisdag", + "2": "onsdag", + "3": "torsdag", + "4": "fredag", + "5": "lördag", + "6": "söndag" }, "date": { - "1": "first", - "2": "second", - "3": "third", - "4": "fourth", - "5": "fifth", - "6": "sixth", - "7": "seventh", - "8": "eighth", - "9": "ninth", - "10": "tenth", - "11": "eleventh", - "12": "twelfth", - "13": "thirteenth", - "14": "fourteenth", - "15": "fifteenth", - "16": "sixteenth", - "17": "seventeenth", - "18": "eighteenth", - "19": "nineteenth", - "20": "twentieth", - "21": "twenty-first", - "22": "twenty-second", - "23": "twenty-third", - "24": "twenty-fourth", - "25": "twenty-fifth", - "26": "twenty-sixth", - "27": "twenty-seventh", - "28": "twenty-eighth", - "29": "twenty-ninth", - "30": "thirtieth", - "31": "thirty-first" + "1": "första", + "2": "andra", + "3": "tredje", + "4": "fjärde", + "5": "femte", + "6": "sjätte", + "7": "sjunde", + "8": "åttonde", + "9": "nionde", + "10": "tionde", + "11": "elfte", + "12": "tolfte", + "13": "trettonde", + "14": "fjortonde", + "15": "femtonde", + "16": "sextonde", + "17": "sjuttonde", + "18": "artonde", + "19": "nittonde", + "20": "tjugonde", + "21": "tjugoförsta", + "22": "tjugoandra", + "23": "tjugotredje", + "24": "tjugofjärde", + "25": "tjugofemte", + "26": "tjugosjätte", + "27": "tjugosjunde", + "28": "tjugoåttonde", + "29": "tjugonionde", + "30": "trettionde", + "31": "trettiförsta" }, "month": { - "1": "january", - "2": "february", - "3": "march", + "1": "januari", + "2": "februari", + "3": "mars", "4": "april", - "5": "may", - "6": "june", - "7": "july", - "8": "august", + "5": "maj", + "6": "juni", + "7": "juli", + "8": "augusti", "9": "september", - "10": "october", + "10": "oktober", "11": "november", "12": "december" }, "number": { - "0": "zero", - "1": "one", - "2": "two", - "3": "three", - "4": "four", - "5": "five", - "6": "six", - "7": "seven", - "8": "eight", - "9": "nine", - "10": "ten", - "11": "eleven", - "12": "twelve", - "13": "thirteen", - "14": "fourteen", - "15": "fifteen", - "16": "sixteen", - "17": "seventeen", - "18": "eighteen", - "19": "nineteen", - "20": "twenty", - "30": "thirty", - "40": "forty", - "50": "fifty", - "60": "sixty", - "70": "seventy", - "80": "eighty", - "90": "ninety" + "0": "noll", + "1": "ett", + "2": "två", + "3": "tre", + "4": "fyra", + "5": "fem", + "6": "sex", + "7": "sju", + "8": "åtta", + "9": "nio", + "10": "tio", + "11": "elva", + "12": "tolv", + "13": "tretton", + "14": "fjorton", + "15": "femton", + "16": "sexton", + "17": "sjutton", + "18": "arton", + "19": "nitton", + "20": "tjugo", + "30": "trettio", + "40": "förtio", + "50": "femtio", + "60": "sextio", + "70": "sjuttio", + "80": "åttio", + "90": "nittio" } -} +} \ No newline at end of file From 5ee3ea80b474742585aa5acdd0430042f2159932 Mon Sep 17 00:00:00 2001 From: citgot Date: Wed, 10 Sep 2025 17:09:35 +0200 Subject: [PATCH 11/14] Update numbers/src/main/resources/config/sv-se/tokenizer.json Translated to swedish --- .../resources/config/sv-se/tokenizer.json | 621 ++++++++---------- 1 file changed, 276 insertions(+), 345 deletions(-) diff --git a/numbers/src/main/resources/config/sv-se/tokenizer.json b/numbers/src/main/resources/config/sv-se/tokenizer.json index c8da189d..570b2938 100644 --- a/numbers/src/main/resources/config/sv-se/tokenizer.json +++ b/numbers/src/main/resources/config/sv-se/tokenizer.json @@ -6,7 +6,11 @@ "raw" ], "plural_endings": [ - "s" + "r", + "n", + "or", + "ar", + "er" ], "word_matches": [ { @@ -15,7 +19,7 @@ "date_time_ignore" ], "values": [ - "and" + "och" ] }, { @@ -23,11 +27,11 @@ "ignore", "date_time_ignore", "day_adder_the", - "ampm_before", "bcad_after" ], "values": [ - "a" + "en", + "ett" ] }, { @@ -37,7 +41,8 @@ "day_adder_the" ], "values": [ - "an" + "en", + "ett" ] }, { @@ -47,7 +52,8 @@ "thousand_separator" ], "values": [ - "," + " ", + "." ] }, { @@ -55,10 +61,8 @@ "ordinal_suffix" ], "values": [ - "st", - "nd", - "rd", - "th" + ":a", + ":e" ] }, { @@ -66,7 +70,7 @@ "point" ], "values": [ - "point" + "punkt" ] }, { @@ -75,7 +79,7 @@ "post_oclock" ], "values": [ - "dot" + "prick" ] }, { @@ -85,7 +89,8 @@ "date_time_ignore" ], "values": [ - "." + ".", + "," ] }, { @@ -93,8 +98,8 @@ "fraction_separator" ], "values": [ - "over", - "divided" + "över", + "delat" ] }, { @@ -111,7 +116,7 @@ "fraction_separator_secondary" ], "values": [ - "by" + "med" ] }, { @@ -120,7 +125,6 @@ "positive" ], "values": [ - "positive", "plus", "+" ] @@ -131,7 +135,6 @@ "negative" ], "values": [ - "negative", "minus" ] }, @@ -152,7 +155,7 @@ "date_time_ignore" ], "values": [ - "of" + "av" ] }, { @@ -160,7 +163,7 @@ "yesterday" ], "values": [ - "yesterday" + "igår" ] }, { @@ -168,7 +171,7 @@ "today" ], "values": [ - "today" + "idag" ] }, { @@ -176,8 +179,7 @@ "tomorrow" ], "values": [ - "tomorrow", - "morrow" + "imorgon" ] }, { @@ -188,7 +190,7 @@ "pre_special_hour" ], "values": [ - "the" + "den" ] }, { @@ -196,7 +198,7 @@ "day_adder_day" ], "values": [ - "day" + "dag" ] }, { @@ -209,7 +211,7 @@ "pre_special_hour" ], "values": [ - "after" + "efter" ] }, { @@ -223,7 +225,7 @@ "pre_special_hour" ], "values": [ - "before" + "före" ] }, { @@ -232,7 +234,7 @@ "special_minute_before" ], "values": [ - "to" + "till" ] }, { @@ -242,7 +244,8 @@ "negative" ], "values": [ - "past" + "över", + "efter" ] }, { @@ -250,8 +253,8 @@ "pre_hour" ], "values": [ - "hour", - "hours" + "timme", + "timmar" ] }, { @@ -260,7 +263,8 @@ "pre_special_hour" ], "values": [ - "at" + "kl", + "klockan" ] }, { @@ -268,10 +272,9 @@ "pre_special_hour" ], "values": [ - "this", - "these", - "those", - "that" + "denna", + "detta", + "dessa" ] }, { @@ -282,7 +285,7 @@ "pre_oclock" ], "values": [ - "on" + "på" ] }, { @@ -291,11 +294,8 @@ "positive" ], "values": [ - "next", - "coming", - "upcoming", - "successive", - "succeeding" + "nästa", + "kommande" ] }, { @@ -305,7 +305,7 @@ "positive" ], "values": [ - "in" + "om" ] }, { @@ -315,7 +315,7 @@ "positive" ], "values": [ - "following" + "följande" ] }, { @@ -324,7 +324,7 @@ "negative" ], "values": [ - "ago" + "sedan" ] }, { @@ -333,10 +333,8 @@ "negative" ], "values": [ - "previous", - "last", - "preceding", - "passed" + "förra", + "föregående" ] }, { @@ -344,7 +342,7 @@ "bcad_before" ], "values": [ - "b" + "f.kr" ] }, { @@ -352,7 +350,7 @@ "bcad_after" ], "values": [ - "anno" + "e.kr" ] }, { @@ -360,7 +358,7 @@ "bcad_identifier" ], "values": [ - "christ", + "kristus", "domini", "d" ] @@ -372,8 +370,8 @@ ], "values": [ "c", - "common", - "current" + "gemensam", + "nuvarande" ] }, { @@ -404,55 +402,12 @@ "e" ] }, - { - "categories": [ - "ampm_before" - ], - "values": [ - "ante" - ] - }, - { - "categories": [ - "ampm_after" - ], - "values": [ - "post", - "p" - ] - }, - { - "categories": [ - "ampm_identifier" - ], - "values": [ - "meridiem", - "meridian", - "m" - ] - }, - { - "categories": [ - "ampm_before_combined" - ], - "values": [ - "am" - ] - }, - { - "categories": [ - "ampm_after_combined" - ], - "values": [ - "pm" - ] - }, { "categories": [ "post_oclock" ], "values": [ - "clock" + "prick" ] }, { @@ -460,9 +415,8 @@ "oclock_combined" ], "values": [ - "oclock", - "exact", - "sharp" + "exakt", + "prick" ] } ], @@ -474,36 +428,17 @@ "digit_after_point" ], "values": { - "nought": 0, - "zero": 0, - "one": 1, - "two": 2, - "three": 3, - "four": 4, - "five": 5, - "six": 6, - "seven": 7, - "eight": 8, - "nine": 9 - } - }, - { - "categories": [ - "number", - "digit_after_point" - ], - "values": { - "oh": 0 - } - }, - { - "categories": [ - "number", - "digit_after_point", - "pre_oclock" - ], - "values": { - "o": 0 + "noll": 0, + "ett": 1, + "en": 1, + "två": 2, + "tre": 3, + "fyra": 4, + "fem": 5, + "sex": 6, + "sju": 7, + "åtta": 8, + "nio": 9 } }, { @@ -512,16 +447,16 @@ "teen" ], "values": { - "ten": 10, - "eleven": 11, - "twelve": 12, - "thirteen": 13, - "fourteen": 14, - "fifteen": 15, - "sixteen": 16, - "seventeen": 17, - "eighteen": 18, - "nineteen": 19 + "tio": 10, + "elva": 11, + "tolv": 12, + "tretton": 13, + "fjorton": 14, + "femton": 15, + "sexton": 16, + "sjutton": 17, + "arton": 18, + "nitton": 19 } }, { @@ -530,14 +465,14 @@ "tens" ], "values": { - "twenty": 20, - "thirty": 30, - "forty": 40, - "fifty": 50, - "sixty": 60, - "seventy": 70, - "eighty": 80, - "ninety": 90 + "tjugo": 20, + "trettio": 30, + "fyrtio": 40, + "femtio": 50, + "sextio": 60, + "sjuttio": 70, + "åttio": 80, + "nittio": 90 } }, { @@ -546,7 +481,7 @@ "hundred" ], "values": { - "hundred": 100 + "hundra": 100 } }, { @@ -555,12 +490,15 @@ "multiplier" ], "values": { - "thousand": 1000, - "million": 1000000, - "billion": 1000000000, - "trillion": 1000000000000, - "quadrillion": 1000000000000000, - "quintillion": 1000000000000000000 + "tusen": 1000, + "miljon": 1000000, + "miljoner": 1000000, + "miljard": 1000000000, + "miljarder": 1000000000, + "biljon": 1000000000000, + "biljoner": 1000000000000, + "biljard": 1000000000000000, + "biljarder": 1000000000000000 } }, { @@ -570,15 +508,15 @@ "digit" ], "values": { - "first": 1, - "second": 2, - "third": 3, - "fourth": 4, - "fifth": 5, - "sixth": 6, - "seventh": 7, - "eighth": 8, - "ninth": 9 + "första": 1, + "andra": 2, + "tredje": 3, + "fjärde": 4, + "femte": 5, + "sjätte": 6, + "sjunde": 7, + "åttonde": 8, + "nionde": 9 } }, { @@ -588,16 +526,16 @@ "teen" ], "values": { - "tenth": 10, - "eleventh": 11, - "twelfth": 12, - "thirteenth": 13, - "fourteenth": 14, - "fifteenth": 15, - "sixteenth": 16, - "seventeenth": 17, - "eighteenth": 18, - "nineteenth": 19 + "tionde": 10, + "elfte": 11, + "tolfte": 12, + "trettonde": 13, + "fjortonde": 14, + "femtonde": 15, + "sextonde": 16, + "sjuttonde": 17, + "artonde": 18, + "nittonde": 19 } }, { @@ -607,14 +545,14 @@ "tens" ], "values": { - "twentieth": 20, - "thirtieth": 30, - "fortieth": 40, - "fiftieth": 50, - "sixtieth": 60, - "seventieth": 70, - "eightieth": 80, - "ninetieth": 90 + "tjugonde": 20, + "trettionde": 30, + "fyrtionde": 40, + "femtionde": 50, + "sextionde": 60, + "sjuttionde": 70, + "åttionde": 80, + "nittionde": 90 } }, { @@ -624,7 +562,7 @@ "hundred" ], "values": { - "hundredth": 100 + "hundrade": 100 } }, { @@ -634,12 +572,11 @@ "multiplier" ], "values": { - "thousandth": 1000, - "millionth": 1000000, - "billionth": 1000000000, - "trillionth": 1000000000000, - "quadrillionth": 1000000000000000, - "quintillionth": 1000000000000000000 + "tusende": 1000, + "miljonte": 1000000, + "miljardte": 1000000000, + "biljonte": 1000000000000, + "biljardte": 1000000000000000 } }, { @@ -648,27 +585,16 @@ "suffix_multiplier" ], "values": { - "half": 0.5, - "halves": 0.5, - "quarter": 0.25, - "quarters": 0.25, - "pair": 2, - "pairs": 2, - "couple": 2, - "couples": 2, - "dozen": 12, - "dozens": 12, - "gross": 144, - "grosses": 144, - "score": 20, - "scores": 20, - "percent": 0.01, - "pct": 0.01, - "pc": 0.01, + "halv": 0.5, + "hälft": 0.5, + "kvart": 0.25, + "par": 2, + "dussin": 12, + "gros": 144, + "tjog": 20, + "procent": 0.01, "%": 0.01, - "permille": 0.001, - "permill": 0.001, - "permil": 0.001, + "promille": 0.001, "‰": 0.001 } }, @@ -677,26 +603,26 @@ "month_name" ], "values": { - "january": 1, + "januari": 1, "jan": 1, - "february": 2, + "februari": 2, "feb": 2, - "march": 3, + "mars": 3, "mar": 3, "april": 4, "apr": 4, - "may": 5, - "june": 6, + "maj": 5, + "juni": 6, "jun": 6, - "july": 7, + "juli": 7, "jul": 7, - "august": 8, + "augusti": 8, "aug": 8, "september": 9, "sep": 9, "sept": 9, - "october": 10, - "oct": 10, + "oktober": 10, + "okt": 10, "november": 11, "nov": 11, "december": 12, @@ -708,20 +634,20 @@ "day_of_week" ], "values": { - "monday": 0, - "mon": 0, - "tuesday": 1, - "tue": 1, - "wednesday": 2, - "wed": 2, - "thursday": 3, - "thu": 3, - "friday": 4, - "fri": 4, - "saturday": 5, - "sat": 5, - "sunday": 6, - "sun": 6 + "måndag": 0, + "mån": 0, + "tisdag": 1, + "tis": 1, + "onsdag": 2, + "ons": 2, + "torsdag": 3, + "tor": 3, + "fredag": 4, + "fre": 4, + "lördag": 5, + "lör": 5, + "söndag": 6, + "sön": 6 } }, { @@ -730,12 +656,8 @@ "moment_of_day" ], "values": { - "noon": 12, - "noons": 12, - "midday": 12, - "middays": 12, - "midnight": 0, - "midnights": 0 + "middag": 12, + "midnatt": 0 } }, { @@ -743,115 +665,124 @@ "moment_of_day" ], "values": { - "night": 3, - "nights": 3, - "nighttime": 3, - "dawn": 6, - "dawning": 6, - "aurora": 6, - "morning": 9, - "mornings": 9, + "natt": 3, + "gryning": 6, + "morgon": 9, + "förmiddag": 10, "lunch": 12, - "lunches": 12, - "dinner": 20, - "dinners": 20, - "afternoon": 15, - "afternoons": 15, - "sunset": 18, - "dusk": 18, - "evening": 21, - "evenings": 21, - "tonight": 23 + "eftermiddag": 15, + "kväll": 18, + "skymning": 18, + "sen kväll": 21, + "ikväll": 21, + "ikväll": 23 } } ], - "duration_words": { - "1 NANOS": [ - "nanosecond", - "nanoseconds", - "ns" - ], - "1 MICROS": [ - "microsecond", - "microseconds", - "μs" - ], - "1 MILLIS": [ - "millisecond", - "milliseconds", - "ms" - ], - "1 SECONDS": [ - "second", - "seconds", - "s", - "sec", - "secs" - ], - "1 MINUTES": [ - "minute", - "minutes", - "m", - "min", - "mins" - ], - "1 HOURS": [ - "hour", - "hours", - "h", - "hr", - "hrs" - ], - "1 DAYS": [ - "day", - "days", - "d" - ], - "1 WEEKS": [ - "week", - "weeks", - "w" - ], - "1 MONTHS": [ - "month", - "months", - "mo", - "mon", - "mons" - ], - "1 YEARS": [ - "year", - "years", - "yr", - "yrs" - ], - "1 DECADES": [ - "decade", - "decades" - ], - "1 CENTURIES": [ - "century", - "centuries" - ], - "1 MILLENNIA": [ - "millenium", - "millennium", - "milleniums", - "millenniums", - "millenia", - "millennia" - ] - }, + "duration_words": [ + { + "categories": [ + "second" + ], + "values": [ + "sekund", + "sekunder", + "s" + ] + }, + { + "categories": [ + "minute" + ], + "values": [ + "minut", + "minuter", + "min" + ] + }, + { + "categories": [ + "hour" + ], + "values": [ + "timme", + "timmar", + "h" + ] + }, + { + "categories": [ + "day" + ], + "values": [ + "dag", + "dagar", + "dygn" + ] + }, + { + "categories": [ + "week" + ], + "values": [ + "vecka", + "veckor" + ] + }, + { + "categories": [ + "month" + ], + "values": [ + "månad", + "månader" + ] + }, + { + "categories": [ + "year" + ], + "values": [ + "år" + ] + }, + { + "categories": [ + "decade" + ], + "values": [ + "årtionde", + "decennium", + "decennier" + ] + }, + { + "categories": [ + "century" + ], + "values": [ + "århundrade", + "sekel", + "sekler" + ] + }, + { + "categories": [ + "millennium" + ], + "values": [ + "årtusende", + "millennium", + "millennier" + ] + } + ], "duration_restrict_after_number": [ - "ns", - "μs", - "ms", - "s", - "m", - "h", - "d", - "w", - "mo", - "yr" + "decennium", + "decennier", + "sekel", + "sekler", + "millennium", + "millennier" ] -} \ No newline at end of file +} From 7a2debda1230ab9516f255939282e7b811795d92 Mon Sep 17 00:00:00 2001 From: citgot Date: Wed, 10 Sep 2025 17:18:02 +0200 Subject: [PATCH 12/14] Added sv-se dir in test, added date_time_test.json --- .../config/sv-se/date_time_test.json | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 numbers/src/test/resources/config/sv-se/date_time_test.json diff --git a/numbers/src/test/resources/config/sv-se/date_time_test.json b/numbers/src/test/resources/config/sv-se/date_time_test.json new file mode 100644 index 00000000..ffde77b1 --- /dev/null +++ b/numbers/src/test/resources/config/sv-se/date_time_test.json @@ -0,0 +1,43 @@ +{ + "test_nice_year": { + "1": {"datetime_param": "1, 1, 31, 13, 22, 3", "bc": "True", "assertEqual": "one b.c." }, + "2": {"datetime_param": "10, 1, 31, 13, 22, 3", "bc": "True", "assertEqual": "ten b.c." }, + "3": {"datetime_param": "92, 1, 31, 13, 22, 3", "bc": "True", "assertEqual": "ninety two b.c." }, + "4": {"datetime_param": "803, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "eight hundred three" }, + "5": {"datetime_param": "811, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "eight hundred eleven" }, + "6": {"datetime_param": "454, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "four hundred fifty four" }, + "7": {"datetime_param": "1005, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "one thousand five" }, + "8": {"datetime_param": "1012, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "ten twelve" }, + "9": {"datetime_param": "1046, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "ten forty six" }, + "10": {"datetime_param": "1807, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "eighteen oh seven" }, + "11": {"datetime_param": "1717, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "seventeen seventeen" }, + "12": {"datetime_param": "1988, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "nineteen eighty eight"}, + "13": {"datetime_param": "2009, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "two thousand nine"}, + "14": {"datetime_param": "2018, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "twenty eighteen"}, + "15": {"datetime_param": "2021, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "twenty twenty one"}, + "16": {"datetime_param": "2030, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "twenty thirty"}, + "17": {"datetime_param": "2100, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "twenty one hundred" }, + "18": {"datetime_param": "1000, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "one thousand" }, + "19": {"datetime_param": "2000, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "two thousand" }, + "20": {"datetime_param": "3120, 1, 31, 13, 22, 3", "bc": "True", "assertEqual": "thirty one twenty b.c." }, + "21": {"datetime_param": "3241, 1, 31, 13, 22, 3", "bc": "True", "assertEqual": "thirty two forty one b.c." }, + "22": {"datetime_param": "5200, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "fifty two hundred" }, + "23": {"datetime_param": "1100, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "eleven hundred" }, + "24": {"datetime_param": "2100, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "twenty one hundred" } + }, + "test_nice_date": { + "1": {"datetime_param": "2017, 1, 31, 0, 2, 3", "now": "None", "assertEqual": "tuesday, january thirty-first, twenty seventeen"}, + "2": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2017, 1, 1, 0, 2, 3", "assertEqual": "sunday, february fourth, twenty eighteen"}, + "3": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2018, 1, 1, 0, 2, 3", "assertEqual": "sunday, february fourth"}, + "4": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2018, 2, 1, 0, 2, 3", "assertEqual": "sunday, the fourth"}, + "5": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2018, 2, 3, 0, 2, 3", "assertEqual": "tomorrow"}, + "6": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2018, 2, 4, 0, 2, 3", "assertEqual": "today"}, + "7": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2018, 2, 5, 0, 2, 3", "assertEqual": "yesterday"}, + "8": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2018, 2, 6, 0, 2, 3", "assertEqual": "sunday, february fourth"}, + "9": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2019, 2, 6, 0, 2, 3", "assertEqual": "sunday, february fourth, twenty eighteen"} + }, + "test_nice_date_time": { + "1": {"datetime_param": "2017, 1, 31, 13, 22, 3", "now": "None", "use_24hour": "False", "use_ampm": "True", "assertEqual": "tuesday, january thirty-first, twenty seventeen at one twenty two p.m."}, + "2": {"datetime_param": "2017, 1, 31, 13, 22, 3", "now": "None", "use_24hour": "True", "use_ampm": "False", "assertEqual": "tuesday, january thirty-first, twenty seventeen at thirteen twenty two"} + } +} From ab99b15a93f921b4d6c85f6d01639bd748ff96c8 Mon Sep 17 00:00:00 2001 From: citgot Date: Wed, 10 Sep 2025 17:23:18 +0200 Subject: [PATCH 13/14] Update numbers/src/test/resources/config/sv-se/date_time_test.json Translated to swedish --- .../config/sv-se/date_time_test.json | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/numbers/src/test/resources/config/sv-se/date_time_test.json b/numbers/src/test/resources/config/sv-se/date_time_test.json index ffde77b1..b09e3c52 100644 --- a/numbers/src/test/resources/config/sv-se/date_time_test.json +++ b/numbers/src/test/resources/config/sv-se/date_time_test.json @@ -1,43 +1,43 @@ { "test_nice_year": { - "1": {"datetime_param": "1, 1, 31, 13, 22, 3", "bc": "True", "assertEqual": "one b.c." }, - "2": {"datetime_param": "10, 1, 31, 13, 22, 3", "bc": "True", "assertEqual": "ten b.c." }, - "3": {"datetime_param": "92, 1, 31, 13, 22, 3", "bc": "True", "assertEqual": "ninety two b.c." }, - "4": {"datetime_param": "803, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "eight hundred three" }, - "5": {"datetime_param": "811, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "eight hundred eleven" }, - "6": {"datetime_param": "454, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "four hundred fifty four" }, - "7": {"datetime_param": "1005, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "one thousand five" }, - "8": {"datetime_param": "1012, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "ten twelve" }, - "9": {"datetime_param": "1046, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "ten forty six" }, - "10": {"datetime_param": "1807, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "eighteen oh seven" }, - "11": {"datetime_param": "1717, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "seventeen seventeen" }, - "12": {"datetime_param": "1988, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "nineteen eighty eight"}, - "13": {"datetime_param": "2009, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "two thousand nine"}, - "14": {"datetime_param": "2018, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "twenty eighteen"}, - "15": {"datetime_param": "2021, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "twenty twenty one"}, - "16": {"datetime_param": "2030, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "twenty thirty"}, - "17": {"datetime_param": "2100, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "twenty one hundred" }, - "18": {"datetime_param": "1000, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "one thousand" }, - "19": {"datetime_param": "2000, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "two thousand" }, - "20": {"datetime_param": "3120, 1, 31, 13, 22, 3", "bc": "True", "assertEqual": "thirty one twenty b.c." }, - "21": {"datetime_param": "3241, 1, 31, 13, 22, 3", "bc": "True", "assertEqual": "thirty two forty one b.c." }, - "22": {"datetime_param": "5200, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "fifty two hundred" }, - "23": {"datetime_param": "1100, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "eleven hundred" }, - "24": {"datetime_param": "2100, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "twenty one hundred" } + "1": {"datetime_param": "1, 1, 31, 13, 22, 3", "bc": "True", "assertEqual": "ett före kristus" }, + "2": {"datetime_param": "10, 1, 31, 13, 22, 3", "bc": "True", "assertEqual": "tio före kristus" }, + "3": {"datetime_param": "92, 1, 31, 13, 22, 3", "bc": "True", "assertEqual": "nittio två före kristus" }, + "4": {"datetime_param": "803, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "åtta hundra tre" }, + "5": {"datetime_param": "811, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "åtta hundra elva" }, + "6": {"datetime_param": "454, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "fyra hundra femtio fyra" }, + "7": {"datetime_param": "1005, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "ett tusen fem" }, + "8": {"datetime_param": "1012, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "tio tolv" }, + "9": {"datetime_param": "1046, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "tio förtio sex" }, + "10": {"datetime_param": "1807, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "arton noll sju" }, + "11": {"datetime_param": "1717, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "sjutton sjutton" }, + "12": {"datetime_param": "1988, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "nitton åttio åtta"}, + "13": {"datetime_param": "2009, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "två tusen nio"}, + "14": {"datetime_param": "2018, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "tjugo arton"}, + "15": {"datetime_param": "2021, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "tjugo tjugo ett"}, + "16": {"datetime_param": "2030, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "tjugo trettio"}, + "17": {"datetime_param": "2100, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "tjugo ett hundra" }, + "18": {"datetime_param": "1000, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "ett tusen" }, + "19": {"datetime_param": "2000, 1, 31, 13, 22, 3", "bc": "None", "assertEqual": "två tusen" }, + "20": {"datetime_param": "3120, 1, 31, 13, 22, 3", "bc": "True", "assertEqual": "trettio ett tjugo före kristus" }, + "21": {"datetime_param": "3241, 1, 31, 13, 22, 3", "bc": "True", "assertEqual": "trettio två förtio ett före kristus" }, + "22": {"datetime_param": "5200, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "femtio två hundra" }, + "23": {"datetime_param": "1100, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "elva hundra" }, + "24": {"datetime_param": "2100, 1, 31, 13, 22, 3", "bc": "False", "assertEqual": "tjugo ett hundra" } }, "test_nice_date": { - "1": {"datetime_param": "2017, 1, 31, 0, 2, 3", "now": "None", "assertEqual": "tuesday, january thirty-first, twenty seventeen"}, - "2": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2017, 1, 1, 0, 2, 3", "assertEqual": "sunday, february fourth, twenty eighteen"}, - "3": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2018, 1, 1, 0, 2, 3", "assertEqual": "sunday, february fourth"}, - "4": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2018, 2, 1, 0, 2, 3", "assertEqual": "sunday, the fourth"}, - "5": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2018, 2, 3, 0, 2, 3", "assertEqual": "tomorrow"}, - "6": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2018, 2, 4, 0, 2, 3", "assertEqual": "today"}, - "7": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2018, 2, 5, 0, 2, 3", "assertEqual": "yesterday"}, - "8": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2018, 2, 6, 0, 2, 3", "assertEqual": "sunday, february fourth"}, - "9": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2019, 2, 6, 0, 2, 3", "assertEqual": "sunday, february fourth, twenty eighteen"} + "1": {"datetime_param": "2017, 1, 31, 0, 2, 3", "now": "None", "assertEqual": "tisdag, den trettiförsta januari, tjugo sjutton"}, + "2": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2017, 1, 1, 0, 2, 3", "assertEqual": "söndag, den fjärde februari, tjugo arton"}, + "3": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2018, 1, 1, 0, 2, 3", "assertEqual": "söndag, den fjärde februari"}, + "4": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2018, 2, 1, 0, 2, 3", "assertEqual": "söndag, den fjärde"}, + "5": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2018, 2, 3, 0, 2, 3", "assertEqual": "imorgon"}, + "6": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2018, 2, 4, 0, 2, 3", "assertEqual": "idag"}, + "7": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2018, 2, 5, 0, 2, 3", "assertEqual": "igår"}, + "8": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2018, 2, 6, 0, 2, 3", "assertEqual": "söndag, den fjärde februari"}, + "9": {"datetime_param": "2018, 2, 4, 0, 2, 3", "now": "2019, 2, 6, 0, 2, 3", "assertEqual": "söndag, den fjärde februari, tjugo arton"} }, "test_nice_date_time": { - "1": {"datetime_param": "2017, 1, 31, 13, 22, 3", "now": "None", "use_24hour": "False", "use_ampm": "True", "assertEqual": "tuesday, january thirty-first, twenty seventeen at one twenty two p.m."}, - "2": {"datetime_param": "2017, 1, 31, 13, 22, 3", "now": "None", "use_24hour": "True", "use_ampm": "False", "assertEqual": "tuesday, january thirty-first, twenty seventeen at thirteen twenty two"} + "1": {"datetime_param": "2017, 1, 31, 13, 22, 3", "now": "None", "use_24hour": "False", "use_ampm": "True", "assertEqual": "tisdag, den trettiförsta januari, tjugo sjutton klockan tjugotvå minuter över ett på eftermiddagen"}, + "2": {"datetime_param": "2017, 1, 31, 13, 22, 3", "now": "None", "use_24hour": "True", "use_ampm": "False", "assertEqual": "tisdag, den trettiförsta januari, tjugo sjutton klockan tretton tjugotvå"} } -} +} \ No newline at end of file From b5ca660ce92c4a7ca5e9ebfe15d3c9a4f9671993 Mon Sep 17 00:00:00 2001 From: citgot Date: Thu, 16 Oct 2025 23:14:26 +0200 Subject: [PATCH 14/14] Added "numbers/src/main/java/org/dicio/numbers/lang/sv" directory and to Swedish translated Kotlin files --- .../lang/sv/SwedishDateTimeExtractor.kt | 415 ++++++++++++++++++ .../dicio/numbers/lang/sv/SwedishFormatter.kt | 357 +++++++++++++++ .../numbers/lang/sv/SwedishNumberExtractor.kt | 311 +++++++++++++ .../dicio/numbers/lang/sv/SwedishParser.kt | 40 ++ 4 files changed, 1123 insertions(+) create mode 100644 numbers/src/main/java/org/dicio/numbers/lang/sv/SwedishDateTimeExtractor.kt create mode 100644 numbers/src/main/java/org/dicio/numbers/lang/sv/SwedishFormatter.kt create mode 100644 numbers/src/main/java/org/dicio/numbers/lang/sv/SwedishNumberExtractor.kt create mode 100644 numbers/src/main/java/org/dicio/numbers/lang/sv/SwedishParser.kt diff --git a/numbers/src/main/java/org/dicio/numbers/lang/sv/SwedishDateTimeExtractor.kt b/numbers/src/main/java/org/dicio/numbers/lang/sv/SwedishDateTimeExtractor.kt new file mode 100644 index 00000000..a9826f44 --- /dev/null +++ b/numbers/src/main/java/org/dicio/numbers/lang/sv/SwedishDateTimeExtractor.kt @@ -0,0 +1,415 @@ +package org.dicio.numbers.lang.sv + +import org.dicio.numbers.parser.lexer.TokenStream +import org.dicio.numbers.unit.Duration +import org.dicio.numbers.util.DateTimeExtractorUtils +import org.dicio.numbers.util.DurationExtractorUtils +import org.dicio.numbers.util.NumberExtractorUtils +import org.dicio.numbers.util.Utils +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalTime +import java.time.temporal.ChronoUnit + +class SwedishDateTimeExtractor internal constructor( + private val ts: TokenStream, + shortScale: Boolean, + private val preferMonthBeforeDay: Boolean, + private val now: LocalDateTime +) { + private val numberExtractor = SwedishNumberExtractor(ts, shortScale) + private val durationExtractor = DurationExtractorUtils(ts, numberExtractor::numberNoOrdinal) + private val dateTimeExtractor = DateTimeExtractorUtils(ts, now, this::extractIntegerInRange) + + private fun extractIntegerInRange( + fromInclusive: Int, + toInclusive: Int, + allowOrdinal: Boolean = false + ): Int? { + return NumberExtractorUtils.extractOneIntegerInRange( + ts, fromInclusive, toInclusive + ) { NumberExtractorUtils.signBeforeNumber(ts) { numberExtractor.numberInteger(allowOrdinal) } } + } + + fun dateTime(): LocalDateTime? { + return ts.firstWhichUsesMostTokens({ dateTime(false) }, { dateTime(true) }) + } + + private fun dateTime(timeFirst: Boolean): LocalDateTime? { + var date: LocalDate? = null + var time: LocalTime? = null + + if (!timeFirst) { + date = relativeSpecialDay() + + if (date == null) { + val duration = Utils.firstNotNull( + this::relativeDuration, + dateTimeExtractor::relativeMonthDuration + ) + if (duration == null) { + date = date() + } else if (duration.nanos == 0L && duration.days != 0L) { + date = duration.applyAsOffsetToDateTime(now).toLocalDate() + } else if (duration.nanos != 0L && duration.days == 0L && duration.months == 0L && duration.years == 0L) { + time = duration.applyAsOffsetToDateTime(now).toLocalTime() + } else { + return duration.applyAsOffsetToDateTime(now) + } + } + } + + if (time == null) { + time = ts.tryOrSkipDateTimeIgnore(date != null) { this.timeWithAmpm() } + } + + if (date == null && time != null) { + val originalPosition = ts.position + val duration = ts.tryOrSkipDateTimeIgnore(true) { this.relativeDuration() } + if (duration == null) { + date = ts.tryOrSkipDateTimeIgnore( + true + ) { + Utils.firstNotNull(this::relativeSpecialDay, this::date) + } + } else if (duration.nanos == 0L && duration.days != 0L) { + date = duration.applyAsOffsetToDateTime(now).toLocalDate() + } else { + ts.position = originalPosition + } + } + + return if (date == null) { + time?.atDate(now.toLocalDate()) + } else { + if (time == null) date.atTime(now.toLocalTime()) else date.atTime(time) + } + } + + fun timeWithAmpm(): LocalTime? { + var time = time() + val pm: Boolean? + if (time == null) { + val momentOfDay = momentOfDay() ?: return null + + time = ts.tryOrSkipDateTimeIgnore(true) { this.time() } + if (time == null) { + return LocalTime.of(momentOfDay, 0) + } else { + pm = DateTimeExtractorUtils.isMomentOfDayPm(momentOfDay) + } + } else { + pm = ts.tryOrSkipDateTimeIgnore(true) { + Utils.firstNotNull( + dateTimeExtractor::ampm, + { momentOfDay()?.let(DateTimeExtractorUtils::isMomentOfDayPm) } + ) + } + } + + if (time.hour != 0 && pm != null) { + if (!pm && time.hour == 12) { + time = time.withHour(0) + } else if (pm && !DateTimeExtractorUtils.isMomentOfDayPm(time.hour)) { + time = time.withHour((time.hour + 12) % DateTimeExtractorUtils.HOURS_IN_DAY) + } + } + return time + } + + fun time(): LocalTime? { + val originalPosition = ts.position + val specialMinute = specialMinute() + + val hour = Utils.firstNotNull(this::noonMidnightLike, this::hour) + if (hour == null) { + ts.position = originalPosition + return null + } else if (specialMinute != null) { + return if (specialMinute < 0) { + LocalTime.of( + (hour + DateTimeExtractorUtils.HOURS_IN_DAY - 1) % DateTimeExtractorUtils.HOURS_IN_DAY, + 60 + specialMinute + ) // e.g. kvart i sex + } else { + LocalTime.of(hour, specialMinute) // e.g. halv åtta + } + } + var result = LocalTime.of(hour, 0) + + if (oClock()) { + return result // e.g. klockan tio + } + + val minute = ts.tryOrSkipDateTimeIgnore(true) { dateTimeExtractor.minute() } + if (minute == null) { + return result + } + result = result.withMinute(minute) + + val second = ts.tryOrSkipDateTimeIgnore(true) { dateTimeExtractor.second() } + if (second == null) { + return result + } + return result.withSecond(second) + } + + fun date(): LocalDate? { + var result = now.toLocalDate() + + val dayOfWeek = dateTimeExtractor.dayOfWeek() + val firstNum = ts.tryOrSkipDateTimeIgnore( + dayOfWeek != null + ) { extractIntegerInRange(1, 31, true) } + + if (firstNum == null && dayOfWeek != null) { + return result.plus((dayOfWeek - result.dayOfWeek.ordinal).toLong(), ChronoUnit.DAYS) + } + + val monthName = ts.tryOrSkipDateTimeIgnore( + firstNum != null + ) { dateTimeExtractor.monthName() } + if (monthName == null) { + result = if (firstNum == null) { + result.withDayOfMonth(1).withMonth(1) + } else { + val secondNumMax = if (firstNum <= 12) 31 else 12 + val secondNum = ts.tryOrSkipDateTimeIgnore( + true + ) { extractIntegerInRange(1, secondNumMax, true) } + + if (secondNum == null) { + return if (preferMonthBeforeDay && firstNum <= 12) { + result.withDayOfMonth(1).withMonth(firstNum) + } else { + result.withDayOfMonth(firstNum) + } + } else { + if ((preferMonthBeforeDay || secondNum > 12) && firstNum <= 12) { + result.withDayOfMonth(secondNum).withMonth(firstNum) + } else { + result.withDayOfMonth(firstNum).withMonth(secondNum) + } + } + } + } else { + result = result.withMonth(monthName) + + if (firstNum == null) { + val secondNum = ts.tryOrSkipDateTimeIgnore( + true + ) { extractIntegerInRange(1, 31, true) } + result = if (secondNum == null) { + result.withDayOfMonth(1) + } else { + result.withDayOfMonth(secondNum) + } + } else { + result = result.withDayOfMonth(firstNum) + } + } + val dayOrMonthFound = firstNum != null || monthName != null + + var bcad = ts.tryOrSkipDateTimeIgnore(dayOrMonthFound) { this.bcad() } + + val year = ts.tryOrSkipDateTimeIgnore( + dayOrMonthFound && bcad == null + ) { extractIntegerInRange(0, 999999999) } + if (year == null) { + if (dayOrMonthFound) { + return result + } + return null + } + + if (bcad == null) { + bcad = bcad() + } + return result.withYear(year * (if (bcad == null || bcad) 1 else -1)) + } + + + fun bcad(): Boolean? { + val bcad = dateTimeExtractor.bcad() + if (bcad != null && !bcad) { + // skip "era" in Swedish equivalents + val nextNotIgnore = ts.indexOfWithoutCategory("date_time_ignore", 0) + if (ts[nextNotIgnore].hasCategory("bcad_era")) { + ts.movePositionForwardBy(nextNotIgnore + 1) + } + } + return bcad + } + + fun noonMidnightLike(): Int? { + return noonMidnightLikeOrMomentOfDay("noon_midnight_like") + } + + fun momentOfDay(): Int? { + return noonMidnightLikeOrMomentOfDay("moment_of_day") + } + + private fun noonMidnightLikeOrMomentOfDay(category: String): Int? { + val originalPosition = ts.position + + var relativeIndicator = 0 + if (ts[0].hasCategory("pre_special_hour")) { + if (ts[0].hasCategory("pre_relative_indicator")) { + relativeIndicator = if (ts[0].hasCategory("negative")) -1 else 1 + ts.movePositionForwardBy(ts.indexOfWithoutCategory("date_time_ignore", 1)) + } else { + ts.movePositionForwardBy(1) + } + } + + if (ts[0].hasCategory(category)) { + ts.movePositionForwardBy(1) + return ((ts[-1].number!!.integerValue() + .toInt() + DateTimeExtractorUtils.HOURS_IN_DAY + relativeIndicator) + % DateTimeExtractorUtils.HOURS_IN_DAY) + } + + ts.position = originalPosition + return null + } + + fun hour(): Int? { + val originalPosition = ts.position + + ts.movePositionForwardBy(ts.indexOfWithoutCategory("pre_hour", 0)) + + val number = extractIntegerInRange(0, DateTimeExtractorUtils.HOURS_IN_DAY) + if (number == null) { + ts.position = originalPosition + return null + } + + return number % DateTimeExtractorUtils.HOURS_IN_DAY + } + + fun specialMinute(): Int? { + val originalPosition = ts.position + + ts.movePositionForwardBy(ts.indexOfWithoutCategory("pre_hour", 0)) + + val number = numberExtractor.numberNoOrdinal() + if (number != null) { + val minutes: Int + if (number.isDecimal && number.decimalValue() > 0.0 && number.decimalValue() < 1.0) { + minutes = Utils.roundToInt(number.decimalValue() * 60) + } else if (number.isInteger && number.integerValue() > 1 && number.integerValue() < 60) { + minutes = number.integerValue().toInt() + } else { + ts.position = originalPosition + return null + } + + val result = ts.tryOrSkipDateTimeIgnore(true) { + if (ts[0].hasCategory("special_minute_after")) { + // e.g. halv tolv (Swedish uses "half" differently - halv tolv = 11:30) + ts.movePositionForwardBy(1) + return@tryOrSkipDateTimeIgnore minutes + } else if (ts[0].hasCategory("special_minute_before")) { + // e.g. kvart i elva + ts.movePositionForwardBy(1) + return@tryOrSkipDateTimeIgnore -minutes + } else { + return@tryOrSkipDateTimeIgnore null + } + } + if (result != null) { + return result + } + } + + ts.position = originalPosition + return null + } + + fun oClock(): Boolean { + if (ts[0].hasCategory("pre_oclock")) { + val nextNotIgnore = ts.indexOfWithoutCategory("date_time_ignore", 1) + if (ts[nextNotIgnore].hasCategory("post_oclock")) { + ts.movePositionForwardBy(nextNotIgnore + 1) + return true + } + } else if (ts[0].hasCategory("oclock_combined")) { + ts.movePositionForwardBy(1) + return true + } + return false + } + + + private fun relativeSpecialDay(): LocalDate? { + val days = Utils.firstNotNull( + this::relativeYesterday, + dateTimeExtractor::relativeToday, + this::relativeTomorrow, + dateTimeExtractor::relativeDayOfWeekDuration + ) + if (days == null) { + return null + } + return now.toLocalDate().plusDays(days.toLong()) + } + + fun relativeYesterday(): Int? { + if (ts[0].hasCategory("day_adder_the") + && ts[1].hasCategory("day_adder_day") + && ts[2].hasCategory("day_adder_before") + && ts[3].hasCategory("yesterday") + ) { + ts.movePositionForwardBy(4) + return -2 // e.g. dagen före igår + } + + if (ts[0].hasCategory("day_adder_day") + && ts[1].hasCategory("day_adder_before") + && ts[2].hasCategory("yesterday") + ) { + ts.movePositionForwardBy(3) + return -2 // e.g. dagen före igår + } + + if (ts[0].hasCategory("yesterday")) { + ts.movePositionForwardBy(1) + return -1 // e.g. igår + } else { + return null + } + } + + fun relativeTomorrow(): Int? { + if (ts[0].hasCategory("day_adder_the") + && ts[1].hasCategory("day_adder_day") + && ts[2].hasCategory("day_adder_after") + && ts[3].hasCategory("tomorrow") + ) { + ts.movePositionForwardBy(4) + return 2 // e.g. dagen efter imorgon + } + + if (ts[0].hasCategory("day_adder_day") + && ts[1].hasCategory("day_adder_after") + && ts[2].hasCategory("tomorrow") + ) { + ts.movePositionForwardBy(3) + return 2 // e.g. dagen efter imorgon + } + + if (ts[0].hasCategory("tomorrow")) { + ts.movePositionForwardBy(1) + return 1 // e.g. imorgon + } else { + return null + } + } + + fun relativeDuration(): Duration? { + return dateTimeExtractor.relativeIndicatorDuration( + { durationExtractor.duration() }, + { duration -> duration.multiply(-1) } + ) + } +} diff --git a/numbers/src/main/java/org/dicio/numbers/lang/sv/SwedishFormatter.kt b/numbers/src/main/java/org/dicio/numbers/lang/sv/SwedishFormatter.kt new file mode 100644 index 00000000..ad8d353c --- /dev/null +++ b/numbers/src/main/java/org/dicio/numbers/lang/sv/SwedishFormatter.kt @@ -0,0 +1,357 @@ +package org.dicio.numbers.lang.sv + +import org.dicio.numbers.formatter.Formatter +import org.dicio.numbers.unit.MixedFraction +import org.dicio.numbers.util.Utils +import java.time.LocalTime +import java.time.format.DateTimeFormatter +import java.util.Locale +import kotlin.math.abs + +class SwedishFormatter : Formatter("config/sv-se") { + + override fun niceNumber(mixedFraction: MixedFraction, speech: Boolean): String { + if (speech) { + val sign = if (mixedFraction.negative) "minus " else "" + if (mixedFraction.numerator == 0) { + return sign + pronounceNumber(mixedFraction.whole.toDouble(), 0, true, false, false) + } + + var denominatorString = when (mixedFraction.denominator) { + 2 -> "halv" + 4 -> "kvarts" + else -> { + // use ordinal: only halv and kvarts are exceptions + pronounceNumber(mixedFraction.denominator.toDouble(), 0, true, false, true) + } + } + + val numeratorString: String + if (mixedFraction.numerator == 1) { + numeratorString = "en" + } else { + numeratorString = + pronounceNumber(mixedFraction.numerator.toDouble(), 0, true, false, false) + denominatorString += "ar" + } + + return if (mixedFraction.whole == 0L) { + "$sign$numeratorString $denominatorString" + } else { + (sign + pronounceNumber(mixedFraction.whole.toDouble(), 0, true, false, false) + + " och " + numeratorString + " " + denominatorString) + } + } else { + return niceNumberNotSpeech(mixedFraction) + } + } + + override fun pronounceNumber( + number: Double, + places: Int, + shortScale: Boolean, + scientific: Boolean, + ordinal: Boolean + ): String { + if (number == Double.POSITIVE_INFINITY) { + return "oändlighet" + } else if (number == Double.NEGATIVE_INFINITY) { + return "negativ oändlighet" + } else if (java.lang.Double.isNaN(number)) { + return "inte ett tal" + } + + // also using scientific mode if the number is too big to be spoken fully + if (scientific || abs(number) > 999999999999999934463.0) { + val scientificFormatted = String.format(Locale.ENGLISH, "%E", number) + val parts = scientificFormatted.split("E".toRegex(), limit = 2).toTypedArray() + val power = parts[1].toInt().toDouble() + + if (power != 0.0) { + val n = parts[0].toDouble() + return String.format( + "%s%s gånger tio upphöjt till %s%s", + if (n < 0) "negativ " else "", + pronounceNumber(abs(n), places, true, false, false), + if (power < 0) "negativ " else "", + pronounceNumber(abs(power), places, true, false, false) + ) + } + } + + val result = StringBuilder() + var varNumber = number + if (varNumber < 0) { + varNumber = -varNumber + if (places != 0 || varNumber >= 0.5) { + result.append(if (scientific) "negativ " else "minus ") + } + } + + val realPlaces = Utils.decimalPlacesNoFinalZeros(varNumber, places) + val numberIsWhole = realPlaces == 0 + val numberLong = varNumber.toLong() + (if (varNumber % 1 >= 0.5 && numberIsWhole) 1 else 0) + + // Sweden always uses long scale (miljard, biljon) + if (!ordinal && NUMBER_NAMES.containsKey(numberLong)) { + if (varNumber > 90) { + result.append("ett ") + } + result.append(NUMBER_NAMES[numberLong]) + } else { + // Sweden uses long scale + var ordi = ordinal && numberIsWhole + val groups = Utils.splitByModulus(numberLong, 1000000) + val groupNames = ArrayList() + for (i in groups.indices) { + val z = groups[i] + if (z == 0L) { + continue // skip 000000 groups + } + + var groupName: String + if (z < 1000) { + groupName = subThousand(z, i == 0 && ordi) + } else { + groupName = subThousand(z / 1000, false) + "tusen" + if (z % 1000 != 0L) { + groupName += subThousand(z % 1000, i == 0 && ordi) + } else if (i == 0 && ordi) { + if (z / 1000 == 1L) { + groupName = "tusende" // remove "ett" from "ett tusende" + } else { + groupName += "de" + } + } + } + + if (i != 0) { + val magnitude = Utils.longPow(1000000, i) + if (ordi) { + if (z == 1L) { + groupName = ORDINAL_NAMES_LONG_SCALE[magnitude]!! + } else { + groupName += ORDINAL_NAMES_LONG_SCALE[magnitude] + } + } else { + groupName += NUMBER_NAMES_LONG_SCALE[magnitude] + } + } + + groupNames.add(groupName) + ordi = false + } + + appendSplitGroups(result, groupNames) + } + + if (realPlaces > 0) { + if (varNumber < 1.0 && (result.isEmpty() || "minus ".contentEquals(result))) { + result.append("noll") + } + result.append(" komma") + + val fractionalPart = String.format("%." + realPlaces + "f", varNumber % 1) + for (i in 2 until fractionalPart.length) { + result.append(" ") + result.append(NUMBER_NAMES[(fractionalPart[i].code - '0'.code).toLong()]) + } + } + + return result.toString() + } + + override fun niceTime( + time: LocalTime, + speech: Boolean, + use24Hour: Boolean, + showAmPm: Boolean + ): String { + if (speech) { + if (use24Hour) { + val result = StringBuilder() + result.append("klockan ") + result.append(pronounceNumberDuration(time.hour.toLong())) + + if (time.minute == 0) { + // "klockan tretton" (nothing more) + } else { + result.append(" ") + if (time.minute < 10) { + result.append("noll ") + } + result.append(pronounceNumberDuration(time.minute.toLong())) + } + + return result.toString() + } else { + if (time.hour == 0 && time.minute == 0) { + return "midnatt" + } else if (time.hour == 12 && time.minute == 0) { + return "middag" + } + + val normalizedHour = (time.hour + 11) % 12 + 1 + val result = StringBuilder() + if (time.minute == 15) { + result.append("kvart över ") + result.append(pronounceNumberDuration(normalizedHour.toLong())) + } else if (time.minute == 30) { + result.append("halv ") + result.append(pronounceNumberDuration((normalizedHour % 12 + 1).toLong())) + } else if (time.minute == 45) { + result.append("kvart i ") + result.append(pronounceNumberDuration((normalizedHour % 12 + 1).toLong())) + } else { + result.append(pronounceNumberDuration(normalizedHour.toLong())) + + if (time.minute == 0) { + // nothing more to add + } else { + result.append(" ") + if (time.minute < 10) { + result.append("noll ") + } + result.append(pronounceNumberDuration(time.minute.toLong())) + } + } + + if (showAmPm) { + result.append(if (time.hour >= 12) " em" else " fm") + } + return result.toString() + } + } else { + if (use24Hour) { + return time.format(DateTimeFormatter.ofPattern("HH:mm", Locale("sv", "SE"))) + } else { + val result = time.format( + DateTimeFormatter.ofPattern( + if (showAmPm) "K:mm a" else "K:mm", Locale("sv", "SE") + ) + ) + return if (result.startsWith("0:")) { + "12:" + result.substring(2) + } else { + result + } + } + } + } + + + /** + * @param n must be 0 <= n <= 999 + * @param ordinal whether to return an ordinal number + * @return the string representation of a number smaller than 1000 + */ + private fun subThousand(n: Long, ordinal: Boolean): String { + if (ordinal && ORDINAL_NAMES.containsKey(n)) { + return ORDINAL_NAMES[n]!! + } else if (n < 100) { + if (!ordinal && NUMBER_NAMES.containsKey(n)) { + return NUMBER_NAMES[n]!! + } + + // n is surely => 20 from here on, since all n < 20 are in the maps + return (NUMBER_NAMES[n - n % 10] + + (if (n % 10 > 0) subThousand(n % 10, ordinal) else "")) + } else { + val hundredPart = if (n / 100 == 1L) "etthundra" else NUMBER_NAMES[n / 100] + "hundra" + return (hundredPart + + (if (n % 100 > 0) subThousand(n % 100, ordinal) + else (if (ordinal) "de" else ""))) + } + } + + /** + * @param result the StringBuilder to append the group names to + * @param groupNames the group names + */ + private fun appendSplitGroups(result: StringBuilder, groupNames: List) { + // Swedish does not use commas between groups like English + for (i in groupNames.size - 1 downTo 0) { + result.append(groupNames[i]) + } + } + + companion object { + val NUMBER_NAMES = mapOf( + 0L to "noll", + 1L to "ett", + 2L to "två", + 3L to "tre", + 4L to "fyra", + 5L to "fem", + 6L to "sex", + 7L to "sju", + 8L to "åtta", + 9L to "nio", + 10L to "tio", + 11L to "elva", + 12L to "tolv", + 13L to "tretton", + 14L to "fjorton", + 15L to "femton", + 16L to "sexton", + 17L to "sjutton", + 18L to "arton", + 19L to "nitton", + 20L to "tjugo", + 30L to "trettio", + 40L to "fyrtio", + 50L to "femtio", + 60L to "sextio", + 70L to "sjuttio", + 80L to "åttio", + 90L to "nittio", + 100L to "hundra", + 1000L to "tusen", + 1000000L to "miljon", + ) + + // Sverige använder long scale + val NUMBER_NAMES_LONG_SCALE = NUMBER_NAMES + mapOf( + 1000000000000L to "biljon", + 1000000000000000000L to "triljon", + ) + + val ORDINAL_NAMES = mapOf( + 1L to "första", + 2L to "andra", + 3L to "tredje", + 4L to "fjärde", + 5L to "femte", + 6L to "sjätte", + 7L to "sjunde", + 8L to "åttonde", + 9L to "nionde", + 10L to "tionde", + 11L to "elfte", + 12L to "tolfte", + 13L to "trettonde", + 14L to "fjortonde", + 15L to "femtonde", + 16L to "sextonde", + 17L to "sjuttonde", + 18L to "artonde", + 19L to "nittonde", + 20L to "tjugonde", + 30L to "trettionde", + 40L to "fyrtionde", + 50L to "femtionde", + 60L to "sextionde", + 70L to "sjuttionde", + 80L to "åttionde", + 90L to "nittionde", + 100L to "hundrade", + 1000L to "tusende", + 1000000L to "miljonte", + ) + + val ORDINAL_NAMES_LONG_SCALE = ORDINAL_NAMES + mapOf( + 1000000000000L to "biljonte", + 1000000000000000000L to "triljonte", + ) + } +} diff --git a/numbers/src/main/java/org/dicio/numbers/lang/sv/SwedishNumberExtractor.kt b/numbers/src/main/java/org/dicio/numbers/lang/sv/SwedishNumberExtractor.kt new file mode 100644 index 00000000..348cf376 --- /dev/null +++ b/numbers/src/main/java/org/dicio/numbers/lang/sv/SwedishNumberExtractor.kt @@ -0,0 +1,311 @@ +package org.dicio.numbers.lang.sv + +import org.dicio.numbers.parser.lexer.TokenStream +import org.dicio.numbers.unit.Number +import org.dicio.numbers.util.NumberExtractorUtils + +class SwedishNumberExtractor internal constructor( + private val ts: TokenStream, + private val shortScale: Boolean +) { + fun numberPreferOrdinal(): Number? { + var number = numberSuffixMultiplier() + if (number == null) { + number = numberSignPoint(true) + } + + return divideByDenominatorIfPossible(number) + } + + fun numberPreferFraction(): Number? { + var number = numberSuffixMultiplier() + if (number == null) { + number = numberSignPoint(false) + } + + number = divideByDenominatorIfPossible(number) + + if (number == null) { + number = numberSignPoint(true) + } + return number + } + + fun numberNoOrdinal(): Number? { + var number = numberSuffixMultiplier() + if (number == null) { + number = numberSignPoint(false) + } + + number = divideByDenominatorIfPossible(number) + + return number + } + + + fun divideByDenominatorIfPossible(numberToEdit: Number?): Number? { + if (numberToEdit == null) { + if (ts[0].isValue("en") || ts[0].isValue("ett")) { + val originalPosition = ts.position + ts.movePositionForwardBy(1) + + val denominator = numberInteger(true) + if (denominator != null && denominator.isOrdinal && denominator.moreThan(2)) { + return Number(1).divide(denominator) + } else { + ts.position = originalPosition + } + } + return null + } + + if (!numberToEdit.isOrdinal && !numberToEdit.isDecimal + && !ts[0].hasCategory("ignore") + ) { + val originalPosition = ts.position + val denominator = numberInteger(true) + if (denominator == null) { + if (ts[0].hasCategory("suffix_multiplier")) { + ts.movePositionForwardBy(1) + + val multiplier = ts[-1].number + if (multiplier!!.isDecimal && (1 / multiplier.decimalValue()).toLong() + .toDouble() + == (1 / multiplier.decimalValue()) + ) { + return numberToEdit.divide((1 / multiplier.decimalValue()).toLong()) + } + + return numberToEdit.multiply(multiplier) + } + } else if (denominator.isOrdinal && denominator.moreThan(2)) { + return numberToEdit.divide(denominator) + } else { + ts.position = originalPosition + } + } + return numberToEdit + } + + fun numberSuffixMultiplier(): Number? { + if (ts[0].hasCategory("suffix_multiplier")) { + ts.movePositionForwardBy(1) + return ts[-1].number + } else if ((ts[0].isValue("en") || ts[0].isValue("ett")) && ts[1].hasCategory("suffix_multiplier")) { + ts.movePositionForwardBy(2) + return ts[-1].number + } else { + return null + } + } + + fun numberSignPoint(allowOrdinal: Boolean): Number? { + return NumberExtractorUtils.signBeforeNumber(ts) { numberPoint(allowOrdinal) } + } + + fun numberPoint(allowOrdinal: Boolean): Number? { + var n = numberInteger(allowOrdinal) + if (n != null && n.isOrdinal) { + return n + } + + if (ts[0].hasCategory("point")) { + if (!ts[1].hasCategory("digit_after_point") + && (!NumberExtractorUtils.isRawNumber(ts[1]) || ts[2].hasCategory("ordinal_suffix")) + ) { + return n + } + + ts.movePositionForwardBy(1) + if (n == null) { + n = Number(0.0) + } + + var magnitude = 0.1 + if (ts[0].value.length > 1 && NumberExtractorUtils.isRawNumber(ts[0])) { + for (i in 0 until ts[0].value.length) { + n = n!!.plus((ts[0].value[i].code - '0'.code) * magnitude) + magnitude /= 10.0 + } + ts.movePositionForwardBy(1) + } else { + while (true) { + if (ts[0].hasCategory("digit_after_point") + || (ts[0].value.length == 1 && NumberExtractorUtils.isRawNumber( + ts[0] + ) + && !ts[1].hasCategory("ordinal_suffix")) + ) { + n = n!!.plus(ts[0].number!!.multiply(magnitude)) + magnitude /= 10.0 + } else { + break + } + ts.movePositionForwardBy(1) + } + } + } else if (n != null && ts[0].hasCategory("fraction_separator")) { + val originalPosition = ts.position + ts.movePositionForwardBy(1) + if (ts[0].hasCategory("fraction_separator_secondary")) { + ts.movePositionForwardBy(1) + } + + val denominator = numberInteger(false) + if (denominator == null || (denominator.isInteger && denominator.integerValue() == 0L) + || (denominator.isDecimal && denominator.decimalValue() == 0.0) + ) { + ts.position = originalPosition + } else { + return n.divide(denominator) + } + } + + return n + } + + fun numberInteger(allowOrdinal: Boolean): Number? { + if (ts[0].hasCategory("ignore") + && (!ts[0].isValue("en") && !ts[0].isValue("ett") || ts[1].hasCategory("ignore")) + ) { + return null + } + + // Sweden uses long scale + var n = NumberExtractorUtils.numberMadeOfGroups( + ts, + allowOrdinal, + ::numberGroupLongScale + ) + if (n == null) { + return NumberExtractorUtils.numberBigRaw(ts, allowOrdinal) + } else if (n.isOrdinal) { + return n + } + + if (n.lessThan(100)) { + val nextNotIgnore = ts.indexOfWithoutCategory("ignore", 0) + if (ts[nextNotIgnore].hasCategory("hundred")) { + val ordinal = ts[nextNotIgnore].hasCategory("ordinal") + if (allowOrdinal || !ordinal) { + ts.movePositionForwardBy(nextNotIgnore + 1) + return n.multiply(100).withOrdinal(ordinal) + } + } + } + + if (n.lessThan(1000)) { + if (NumberExtractorUtils.isRawNumber(ts[-1]) && ts[0].hasCategory("thousand_separator") && + ts[1].value.length == 3 && NumberExtractorUtils.isRawNumber(ts[1]) + ) { + val originalPosition = ts.position - 1 + + while (ts[0].hasCategory("thousand_separator") && ts[1].value.length == 3 && + NumberExtractorUtils.isRawNumber(ts[1]) + ) { + n = n!!.multiply(1000).plus(ts[1].number) + ts.movePositionForwardBy(2) + } + + if (ts[0].hasCategory("ordinal_suffix")) { + if (allowOrdinal) { + ts.movePositionForwardBy(1) + return n!!.withOrdinal(true) + } else { + ts.position = originalPosition + return null + } + } + } + } + + return n + } + + companion object { + @JvmStatic + fun numberGroupLongScale( + ts: TokenStream, + allowOrdinal: Boolean, + lastMultiplier: Double + ): Number? { + if (lastMultiplier < 1000000) { + return null + } + + val originalPosition = ts.position + var first = NumberExtractorUtils.numberGroupShortScale(ts, allowOrdinal, 1000000.0) + if (first == null) { + first = NumberExtractorUtils.numberLessThan1000(ts, allowOrdinal) + if (first != null && first.isOrdinal) { + return first + } + + if (first == null) { + val nextNotIgnore = ts.indexOfWithoutCategory("ignore", 0) + if (NumberExtractorUtils.isRawNumber(ts[nextNotIgnore]) + && ts[nextNotIgnore].number!!.lessThan(1000000) + ) { + val ordinal = ts[nextNotIgnore + 1].hasCategory("ordinal_suffix") + if (ordinal) { + if (!allowOrdinal) { + return null + } + ts.movePositionForwardBy(nextNotIgnore + 2) + return ts[-2].number!!.withOrdinal(true) + } + ts.movePositionForwardBy(nextNotIgnore + 1) + first = ts[-1].number + } + } + } else { + if (first.isOrdinal || first.lessThan(1000)) { + return first + } + + val second = NumberExtractorUtils.numberLessThan1000(ts, allowOrdinal) + if (second != null) { + first = first.plus(second) + if (second.isOrdinal) { + return first.withOrdinal(true) + } + } + } + + val nextNotIgnore = ts.indexOfWithoutCategory("ignore", 0) + val ordinal = ts[nextNotIgnore].hasCategory("ordinal") + if (ts[nextNotIgnore].hasCategory("multiplier") && (allowOrdinal || !ordinal) + && ts[nextNotIgnore].number!!.moreThan(1000) + ) { + val multiplier = shortMultiplierToLongScale(ts[nextNotIgnore].number) + if (multiplier!!.lessThan(lastMultiplier)) { + ts.movePositionForwardBy(nextNotIgnore + 1) + return if (first == null) { + multiplier.withOrdinal(ordinal) + } else { + multiplier.multiply(first).withOrdinal(ordinal) + } + } + } else { + return first + } + + ts.position = originalPosition + return null + } + + fun shortMultiplierToLongScale(shortScaleMultiplier: Number?): Number? { + return if (shortScaleMultiplier!!.integerValue() == 1000000000L) { + Number(1000000000000L) // miljard + } else if (shortScaleMultiplier.integerValue() == 1000000000000L) { + Number(1000000000000000000L) // biljon + } else if (shortScaleMultiplier.integerValue() == 1000000000000000L) { + Number(1e24) // biljard + } else if (shortScaleMultiplier.integerValue() == 1000000000000000000L) { + Number(1e30) // triljon + } else { + shortScaleMultiplier // miljon + } + } + } +} diff --git a/numbers/src/main/java/org/dicio/numbers/lang/sv/SwedishParser.kt b/numbers/src/main/java/org/dicio/numbers/lang/sv/SwedishParser.kt new file mode 100644 index 00000000..e86d7c23 --- /dev/null +++ b/numbers/src/main/java/org/dicio/numbers/lang/sv/SwedishParser.kt @@ -0,0 +1,40 @@ +package org.dicio.numbers.lang.sv + +import org.dicio.numbers.parser.Parser +import org.dicio.numbers.parser.lexer.TokenStream +import org.dicio.numbers.unit.Duration +import org.dicio.numbers.unit.Number +import org.dicio.numbers.util.DurationExtractorUtils +import java.time.LocalDateTime + +class SwedishParser : Parser("config/sv-se") { + override fun extractNumber( + tokenStream: TokenStream, + shortScale: Boolean, + preferOrdinal: Boolean + ): () -> Number? { + val numberExtractor = SwedishNumberExtractor(tokenStream, shortScale) + return if (preferOrdinal) { + numberExtractor::numberPreferOrdinal + } else { + numberExtractor::numberPreferFraction + } + } + + override fun extractDuration( + tokenStream: TokenStream, + shortScale: Boolean + ): () -> Duration? { + val numberExtractor = SwedishNumberExtractor(tokenStream, shortScale) + return DurationExtractorUtils(tokenStream, numberExtractor::numberNoOrdinal)::duration + } + + override fun extractDateTime( + tokenStream: TokenStream, + shortScale: Boolean, + preferMonthBeforeDay: Boolean, + now: LocalDateTime + ): () -> LocalDateTime? { + return SwedishDateTimeExtractor(tokenStream, shortScale, preferMonthBeforeDay, now)::dateTime + } +}