Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Swedish support for number to word conversion #139

Merged
merged 4 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ With Tradukisto, you can now transform numbers into their word equivalents easy
* 🇵🇱 Polish
* 🇷🇺 Russian
* 🇸🇰 Slovak
* 🇸🇪 Swedish
* 🇺🇦 Ukrainian
* 🇷🇸 Serbian (Latin)
* 🇷🇸 Serbian (Cyrillic)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
import static pl.allegro.finance.tradukisto.internal.Container.englishContainer;
import static pl.allegro.finance.tradukisto.internal.Container.polishContainer;
import static pl.allegro.finance.tradukisto.internal.Container.hindiContainer;
import static pl.allegro.finance.tradukisto.internal.Container.swedishContainer;

public enum LongValueConverters {

CROATIAN_LONG(croatianContainer().getLongConverter()),
ENGLISH_LONG(englishContainer().getLongConverter()),
POLISH_LONG(polishContainer().getLongConverter()),
HINDI_LONG(hindiContainer().getLongConverter());
HINDI_LONG(hindiContainer().getLongConverter()),
SWEDISH_LONG(swedishContainer().getLongConverter());

private final LongToStringConverter converter;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
import static pl.allegro.finance.tradukisto.internal.Container.serbianCyrillicContainer;
import static pl.allegro.finance.tradukisto.internal.Container.serbianContainer;
import static pl.allegro.finance.tradukisto.internal.Container.slovakContainer;
import static pl.allegro.finance.tradukisto.internal.Container.swedishContainer;
import static pl.allegro.finance.tradukisto.internal.Container.turkishContainer;
import static pl.allegro.finance.tradukisto.internal.Container.ukrainianContainer;
import static pl.allegro.finance.tradukisto.internal.Container.bulgarianContainer;
import static pl.allegro.finance.tradukisto.internal.Container.dutchContainer;

public enum MoneyConverters {

BRAZILIAN_PORTUGUESE_BANKING_MONEY_VALUE(brazilianPortugueseContainer().getBankingMoneyConverter()),
Expand All @@ -46,7 +48,8 @@ public enum MoneyConverters {
FRENCH_BANKING_MONEY_VALUE(frenchContainer().getBankingMoneyConverter()),
BULGARIAN_BANKING_MONEY_VALUE(bulgarianContainer().getBankingMoneyConverter()),
DUTCH_BANKING_MONEY_VALUE(dutchContainer().getBankingMoneyConverter()),
HINDI_BANKING_MONEY_VALUE(Container.hindiContainer().getBankingMoneyConverter());
HINDI_BANKING_MONEY_VALUE(Container.hindiContainer().getBankingMoneyConverter()),
SWEDISH_BANKING_MONEY_VALUE(swedishContainer().getBankingMoneyConverter());

private final BigDecimalToStringConverter converter;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ public enum ValueConverters {
FRENCH_INTEGER(Container.frenchContainer().getIntegerConverter(), "fr"),
TURKISH_INTEGER(Container.turkishContainer().getIntegerConverter(), "tr"),
DUTCH_INTEGER(Container.dutchContainer().getIntegerConverter(), "nl"),
HINDI_INTEGER(Container.hindiContainer().getIntegerConverter(), "hi");
HINDI_INTEGER(Container.hindiContainer().getIntegerConverter(), "hi"),
SWEDISH_INTEGER(Container.swedishContainer().getIntegerConverter(), "sv");

private final IntegerToStringConverter converter;
private final List<String> languageCodes;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
import pl.allegro.finance.tradukisto.internal.languages.serbian.SerbianValues;
import pl.allegro.finance.tradukisto.internal.languages.slovak.SlovakValues;
import pl.allegro.finance.tradukisto.internal.languages.slovak.SlovakValuesForSmallNumbers;
import pl.allegro.finance.tradukisto.internal.languages.swedish.SwedishHundredToWordsConverter;
import pl.allegro.finance.tradukisto.internal.languages.swedish.SwedishValues;
import pl.allegro.finance.tradukisto.internal.languages.turkish.TurkishBigDecimalToBankingMoneyConverter;
import pl.allegro.finance.tradukisto.internal.languages.turkish.TurkishIntegerToWordsConverter;
import pl.allegro.finance.tradukisto.internal.languages.turkish.TurkishSmallNumbersToWordsConverter;
Expand Down Expand Up @@ -245,6 +247,23 @@ public static Container hindiContainer() {
return new Container(integerToStringConverter, longValueConverters, bigDecimalConverter);
}

public static Container swedishContainer() {
SwedishValues swedishBaseValues = new SwedishValues();

SwedishHundredToWordsConverter swedishHundredsToStringConverter =
new SwedishHundredToWordsConverter(swedishBaseValues.baseNumbers());

NumberToWordsConverter swedishNumberToWordsConverter = new NumberToWordsConverter(
swedishHundredsToStringConverter,
swedishBaseValues.pluralForms());

BigDecimalToStringConverter swedishBigDecimalConverter = new BigDecimalToBankingMoneyConverter(
swedishNumberToWordsConverter,
swedishBaseValues.currency());

return new Container(swedishNumberToWordsConverter, swedishNumberToWordsConverter, swedishBigDecimalConverter);
}

private final IntegerToStringConverter integerConverter;
private final LongToStringConverter longConverter;
private final BigDecimalToStringConverter bigDecimalConverter;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package pl.allegro.finance.tradukisto.internal.languages.swedish;

import pl.allegro.finance.tradukisto.internal.GenderAwareIntegerToStringConverter;
import pl.allegro.finance.tradukisto.internal.languages.GenderForms;
import pl.allegro.finance.tradukisto.internal.languages.GenderType;
import pl.allegro.finance.tradukisto.internal.support.Range;

import java.util.Map;

import static java.lang.String.format;

public class SwedishHundredToWordsConverter implements GenderAwareIntegerToStringConverter {

private final Map<Integer, GenderForms> swedishBaseValues;

public SwedishHundredToWordsConverter(Map<Integer, GenderForms> swedishBaseValues) {
this.swedishBaseValues = swedishBaseValues;
}

@Override
public String asWords(Integer value, GenderType swedishGenderType) {
if (this.swedishBaseValues.containsKey(value)) {
return this.swedishBaseValues.get(value).formFor(swedishGenderType);
} else if (Range.closed(21, 99).contains(value)) {
return twoDigitsNumberAsString(value, swedishGenderType);
} else if (Range.closed(101, 999).contains(value)) {
return threeDigitsNumberAsString(value, swedishGenderType);
}
throw new IllegalArgumentException(format("Can't convert %d", value));
}

private String twoDigitsNumberAsString(Integer value, GenderType genderType) {
Integer units = value % 10;
Integer tens = value - units;
return format("%s%s", asWords(tens, genderType), asWords(units, genderType));
}

private String threeDigitsNumberAsString(Integer value, GenderType genderType) {
Integer tensWithUnits = value % 100;
Integer hundreds = value - tensWithUnits;
return format("%s och %s", asWords(hundreds, genderType), asWords(tensWithUnits, genderType));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package pl.allegro.finance.tradukisto.internal.languages.swedish;

import pl.allegro.finance.tradukisto.internal.languages.GenderForms;
import pl.allegro.finance.tradukisto.internal.languages.GenderType;
import pl.allegro.finance.tradukisto.internal.languages.PluralForms;
import pl.allegro.finance.tradukisto.internal.languages.RegularPluralForms;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import static pl.allegro.finance.tradukisto.internal.languages.GenderForms.genderForms;
import static pl.allegro.finance.tradukisto.internal.support.BaseNumbersBuilder.baseNumbersBuilder;

public class SwedishValues {

// Note: Swedish uses 'common' and 'neuter' gender types, but these seem to transfer nicely for numbers to existing
// masculine and feminine gender types for common, and neuter and non-applicable gender types for neuter.
// Regarding base numbers, only 1 has multiple gender types: 1 and 100 being neuter ('ett'), otherwise common ('en')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for explaination, it is really helpful

public Map<Integer, GenderForms> baseNumbers() {
return baseNumbersBuilder()
.put(0, "noll")
.put(1, genderForms("en", "en", "ett", "ett"))
.put(2, "två")
.put(3, "tre")
.put(4, "fyra")
.put(5, "fem")
.put(6, "sex")
.put(7, "sju")
.put(8, "åtta")
.put(9, "nio")
.put(10, "tio")
.put(11, "elva")
.put(12, "tolv")
.put(13, "tretton")
.put(14, "fjorton")
.put(15, "femton")
.put(16, "sexton")
.put(17, "sjutton")
.put(18, "arton")
.put(19, "nitton")
.put(20, "tjugo")
.put(30, "trettio")
.put(40, "fyrtio")
.put(50, "femtio")
.put(60, "sextio")
.put(70, "sjuttio")
.put(80, "åttio")
.put(90, "nittio")
.put(100, "ett hundra")
.put(200, "två hundra")
.put(300, "tre hundra")
.put(400, "fyra hundra")
.put(500, "fem hundra")
.put(600, "sex hundra")
.put(700, "sju hundra")
.put(800, "åtta hundra")
.put(900, "nio hundra")
.build();
}

public List<PluralForms> pluralForms() {
// Note: in Swedish there are common and neuter gender types. In this case, common is equivalent to feminine
return Arrays.asList(
new RegularPluralForms("", "", GenderType.NON_APPLICABLE),
new RegularPluralForms("tusen", "tusen", GenderType.NEUTER), // thousand
new RegularPluralForms("miljon", "miljoner", GenderType.FEMININE), // million
new RegularPluralForms("miljard", "miljarder", GenderType.FEMININE), // billion
new RegularPluralForms("biljon", "biljoner", GenderType.FEMININE), // trillion
new RegularPluralForms("biljard", "biljarder", GenderType.FEMININE), // quadrillion
new RegularPluralForms("triljon", "triljoner", GenderType.FEMININE)); // quintillion
}

public String currency() {
return "kr";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import spock.lang.Unroll
import static pl.allegro.finance.tradukisto.LongValueConverters.ENGLISH_LONG
import static pl.allegro.finance.tradukisto.LongValueConverters.HINDI_LONG
import static pl.allegro.finance.tradukisto.LongValueConverters.POLISH_LONG
import static pl.allegro.finance.tradukisto.LongValueConverters.SWEDISH_LONG

class LongValueConvertersTest extends Specification {

Expand All @@ -19,6 +20,7 @@ class LongValueConvertersTest extends Specification {
"English" | ENGLISH_LONG || "one quintillion"
"Polish" | POLISH_LONG || "jeden trylion"
"Hindi" | HINDI_LONG || "दस शंख"
"Swedish" | SWEDISH_LONG || "en triljon"
}

def "should throw exception when null given"() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import static pl.allegro.finance.tradukisto.MoneyConverters.RUSSIAN_BANKING_MONE
import static pl.allegro.finance.tradukisto.MoneyConverters.SERBIAN_BANKING_MONEY_VALUE
import static pl.allegro.finance.tradukisto.MoneyConverters.SERBIAN_CYRILLIC_BANKING_MONEY_VALUE
import static pl.allegro.finance.tradukisto.MoneyConverters.SLOVAK_BANKING_MONEY_VALUE
import static pl.allegro.finance.tradukisto.MoneyConverters.SWEDISH_BANKING_MONEY_VALUE
import static pl.allegro.finance.tradukisto.MoneyConverters.TURKISH_BANKING_MONEY_VALUE
import static pl.allegro.finance.tradukisto.MoneyConverters.UKRAINIAN_BANKING_MONEY_VALUE
import static pl.allegro.finance.tradukisto.MoneyConverters.DUTCH_BANKING_MONEY_VALUE
Expand Down Expand Up @@ -48,6 +49,7 @@ class MoneyConvertersTest extends Specification {
"Serbian Latin" | SERBIAN_BANKING_MONEY_VALUE || "jedna hiljada dvesta trideset četiri RSD 56/100"
"Slovak" | SLOVAK_BANKING_MONEY_VALUE || "jeden tisíc dvesto tridsať štyri € 56/100"
"Russian" | RUSSIAN_BANKING_MONEY_VALUE || "одна тысяча двести тридцать четыре руб. 56/100"
"Swedish" | SWEDISH_BANKING_MONEY_VALUE || "ett tusen två hundra och trettiofyra kr 56/100"
"Turkish" | TURKISH_BANKING_MONEY_VALUE || "BinİkiYüzOtuzDörtTL,ElliAltıKr."
"Ukrainian" | UKRAINIAN_BANKING_MONEY_VALUE || "одна тисяча двісті тридцять чотири ₴ 56/100"
"Hindi" | HINDI_BANKING_MONEY_VALUE || "एक हजार दो सौ चौंतीस ₹,छप्पन p"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import static pl.allegro.finance.tradukisto.ValueConverters.RUSSIAN_INTEGER
import static pl.allegro.finance.tradukisto.ValueConverters.SERBIAN_CYRILLIC_INTEGER
import static pl.allegro.finance.tradukisto.ValueConverters.SERBIAN_INTEGER
import static pl.allegro.finance.tradukisto.ValueConverters.SLOVAK_INTEGER
import static pl.allegro.finance.tradukisto.ValueConverters.SWEDISH_INTEGER
import static pl.allegro.finance.tradukisto.ValueConverters.TURKISH_INTEGER
import static pl.allegro.finance.tradukisto.ValueConverters.UKRAINIAN_INTEGER
import static pl.allegro.finance.tradukisto.ValueConverters.DUTCH_INTEGER
Expand Down Expand Up @@ -48,6 +49,7 @@ class ValueConvertersTest extends Specification {
"Serbian Latin" | SERBIAN_INTEGER || "jedna hiljada dvesta trideset četiri"
"Slovak" | SLOVAK_INTEGER || "jeden tisíc dvesto tridsať štyri"
"Russian" | RUSSIAN_INTEGER || "одна тысяча двести тридцать четыре"
"Swedish" | SWEDISH_INTEGER || "ett tusen två hundra och trettiofyra"
"Turkish" | TURKISH_INTEGER || "Bin İki Yüz Otuz Dört"
"Ukrainian" | UKRAINIAN_INTEGER || "одна тисяча двісті тридцять чотири"
"Hindi" | HINDI_INTEGER || "एक हजार दो सौ चौंतीस"
Expand Down Expand Up @@ -94,6 +96,7 @@ class ValueConvertersTest extends Specification {
new Locale("uk") || UKRAINIAN_INTEGER
new Locale("nl") || DUTCH_INTEGER
new Locale("hi") || HINDI_INTEGER
new Locale("sv") || SWEDISH_INTEGER
}

def "should return supplied default converter when locale is unknown"() {
Expand Down Expand Up @@ -140,6 +143,7 @@ class ValueConvertersTest extends Specification {
"tr" || TURKISH_INTEGER
"uk" || UKRAINIAN_INTEGER
"hi" || HINDI_INTEGER
"sv" || SWEDISH_INTEGER
}

def "should return supplied default converter when languageCode is unknown"() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package pl.allegro.finance.tradukisto.internal.languages.swedish;

import pl.allegro.finance.tradukisto.internal.languages.GenderType
import spock.lang.Specification

import static pl.allegro.finance.tradukisto.internal.languages.GenderForms.genderForm
import static pl.allegro.finance.tradukisto.internal.languages.GenderForms.genderForms

class SwedishHundredToWordsConverterTest extends Specification {

def "should convert a single value from the list of base values"() {
given:
def converter = new SwedishHundredToWordsConverter([1: genderForms("en",
"en",
"ett",
"ett")])

expect:
converter.asWords(1, GenderType.NON_APPLICABLE) == "ett"
}

def "should convert a two digit number from the list of base values"() {
given:
def converter = new SwedishHundredToWordsConverter([20: genderForm("tjugo"),
1 : genderForms("en",
"en",
"ett",
"ett")])

expect:
converter.asWords(21, GenderType.NON_APPLICABLE) == "tjugoett"
}

def "should convert a three digit number from the list of base values"() {
given:
def converter = new SwedishHundredToWordsConverter([900: genderForm("nio hundra"),
90 : genderForm("nittio"),
9 : genderForm("nio")])

expect:
converter.asWords(999, GenderType.NON_APPLICABLE) == "nio hundra och nittionio"
}


def "should throw IllegalArgumentException when given number is not supported"() {
given:
def converter = new SwedishHundredToWordsConverter([1: genderForm("ett")])

when:
converter.asWords(2, GenderType.NON_APPLICABLE)

then:
def exception = thrown(IllegalArgumentException)
exception.message == "Can't convert 2"
}
}
Loading