Skip to content

Commit

Permalink
Added Japanese support (#148)
Browse files Browse the repository at this point in the history
* add japanese test

* Add Japanese integer support

* Add Japanese long support

* Add Japanese long support

* Add JapaneseNumberChunkingTest

* Add Japanese BigDecimal support

* Fix JapaneseNumberChunkingTest

* Fix README for Japanese support

* Fix Container name
  • Loading branch information
tabatad authored Nov 24, 2023
1 parent 2c7d26d commit 3f6438b
Show file tree
Hide file tree
Showing 15 changed files with 413 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ With Tradukisto, you can now transform numbers into their word equivalents easy
* 🇩🇪 German
* 🇮🇳 Hindi
* 🇮🇹 Italian
* 🇯🇵 Japanese (KANJI)
* 🇰🇿 Kazakh
* 🇱🇻 Latvian
* 🇵🇱 Polish
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@
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;
import static pl.allegro.finance.tradukisto.internal.Container.japaneseKanjiContainer;

public enum LongValueConverters {

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

private final LongToStringConverter converter;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import static pl.allegro.finance.tradukisto.internal.Container.frenchContainer;
import static pl.allegro.finance.tradukisto.internal.Container.germanContainer;
import static pl.allegro.finance.tradukisto.internal.Container.italianContainer;
import static pl.allegro.finance.tradukisto.internal.Container.japaneseKanjiContainer;
import static pl.allegro.finance.tradukisto.internal.Container.kazakhContainer;
import static pl.allegro.finance.tradukisto.internal.Container.latvianContainer;
import static pl.allegro.finance.tradukisto.internal.Container.polishContainer;
Expand Down Expand Up @@ -53,7 +54,8 @@ public enum MoneyConverters {
DUTCH_BANKING_MONEY_VALUE(dutchContainer().getBankingMoneyConverter()),
SPANISH_BANKING_MONEY_VALUE(spanishContainer().getBankingMoneyConverter()),
HINDI_BANKING_MONEY_VALUE(Container.hindiContainer().getBankingMoneyConverter()),
SWEDISH_BANKING_MONEY_VALUE(swedishContainer().getBankingMoneyConverter());
SWEDISH_BANKING_MONEY_VALUE(swedishContainer().getBankingMoneyConverter()),
JAPANESE_BANKING_MONEY_VALUE(japaneseKanjiContainer().getBankingMoneyConverter());

private final BigDecimalToStringConverter converter;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ public enum ValueConverters {
SLOVENE_INTEGER(Container.sloveneContainer().getIntegerConverter(), "sl"),
SPANISH_INTEGER(Container.spanishContainer().getIntegerConverter(), "es"),
HINDI_INTEGER(Container.hindiContainer().getIntegerConverter(), "hi"),
SWEDISH_INTEGER(Container.swedishContainer().getIntegerConverter(), "sv");
SWEDISH_INTEGER(Container.swedishContainer().getIntegerConverter(), "sv"),
JAPANESE_INTEGER(Container.japaneseKanjiContainer().getIntegerConverter(), "ja");

private final IntegerToStringConverter converter;
private final List<String> languageCodes;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
import pl.allegro.finance.tradukisto.internal.languages.italian.ItalianIntegerToWordsConverter;
import pl.allegro.finance.tradukisto.internal.languages.italian.ItalianThousandToWordsConverter;
import pl.allegro.finance.tradukisto.internal.languages.italian.ItalianValues;
import pl.allegro.finance.tradukisto.internal.languages.japanese.JapaneseNumberToWordsConverter;
import pl.allegro.finance.tradukisto.internal.languages.japanese.JapaneseThousandToWordsConverter;
import pl.allegro.finance.tradukisto.internal.languages.japanese.JapaneseValues;
import pl.allegro.finance.tradukisto.internal.languages.kazakh.KazakhValues;
import pl.allegro.finance.tradukisto.internal.languages.latvian.LatvianValues;
import pl.allegro.finance.tradukisto.internal.languages.polish.PolishValues;
Expand Down Expand Up @@ -319,6 +322,31 @@ public static Container swedishContainer() {
return new Container(swedishNumberToWordsConverter, swedishNumberToWordsConverter, swedishBigDecimalConverter);
}

public static Container japaneseKanjiContainer() {
JapaneseValues japaneseValues = new JapaneseValues();

JapaneseThousandToWordsConverter japaneseThousandToWordsConverter = new JapaneseThousandToWordsConverter(
japaneseValues.baseNumbers()
);

IntegerToStringConverter integerToStringConverter = new JapaneseNumberToWordsConverter(
japaneseThousandToWordsConverter,
japaneseValues.pluralForms()
);

LongToStringConverter longToStringConverter = new JapaneseNumberToWordsConverter(
japaneseThousandToWordsConverter,
japaneseValues.pluralForms()
);

BigDecimalToBankingMoneyConverter bigDecimalToBankingMoneyConverter = new BigDecimalToBankingMoneyConverter(
integerToStringConverter,
japaneseValues.currency()
);

return new Container(integerToStringConverter, longToStringConverter, bigDecimalToBankingMoneyConverter);
}

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,38 @@
package pl.allegro.finance.tradukisto.internal.languages.japanese;

import pl.allegro.finance.tradukisto.internal.converters.NumberToWordsConverter;
import pl.allegro.finance.tradukisto.internal.languages.PluralForms;
import pl.allegro.finance.tradukisto.internal.support.Assert;
import pl.allegro.finance.tradukisto.internal.support.JapaneseNumberChunking;
import pl.allegro.finance.tradukisto.internal.support.NumberChunking;

import java.util.List;

public class JapaneseNumberToWordsConverter extends NumberToWordsConverter {

private final NumberChunking numberChunking = new JapaneseNumberChunking();

private final List<PluralForms> pluralForms;

public JapaneseNumberToWordsConverter(JapaneseThousandToWordsConverter japaneseThousandToWordsConverter, List<PluralForms> pluralForms) {
super(japaneseThousandToWordsConverter, pluralForms);
this.pluralForms = pluralForms;
}

@Override
public String asWords(Long value) {
Assert.isTrue(value >= 0, () -> String.format("can't convert negative numbers for value %d", value));

List<Integer> valueChunks = numberChunking.chunk(value);
List<PluralForms> formsToUse = getRequiredFormsInReversedOrder(valueChunks.size());

return joinValueChunksWithForms(valueChunks.iterator(), formsToUse.iterator());
}

@Override
protected String joinParts(List<String> result) {
return result.isEmpty()
? hundredsToWordsConverter.asWords(0, pluralForms.get(0).genderType())
: String.join("", result).trim();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package pl.allegro.finance.tradukisto.internal.languages.japanese;

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

public class JapanesePluralForms implements PluralForms {

private final String form;

public JapanesePluralForms(String form) {
this.form = form;
}

@Override
public String formFor(Integer value) {
return form;
}

@Override
public GenderType genderType() {
return GenderType.NON_APPLICABLE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package pl.allegro.finance.tradukisto.internal.languages.japanese;

import pl.allegro.finance.tradukisto.internal.IntegerToStringConverter;
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 JapaneseThousandToWordsConverter implements IntegerToStringConverter {

private final Map<Integer, GenderForms> baseValues;

public JapaneseThousandToWordsConverter(Map<Integer, GenderForms> baseValues) {
this.baseValues = baseValues;
}

@Override
public String asWords(Integer value) {
if (baseValues.containsKey(value)) {
return baseValues.get(value).formFor(GenderType.NON_APPLICABLE);
}
if (Range.closed(11, 99).contains(value)) {
return twoDigitsNumberAsString(value);
}
if (Range.closed(101, 999).contains(value)) {
return threeDigitsNumberAsString(value);
}
if (Range.closed(1001, 9999).contains(value)) {
return fourDigitsNumberAsString(value);
}
throw new IllegalArgumentException(format("Can't convert %d", value));
}

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

private String threeDigitsNumberAsString(Integer value) {
Integer units = value % 100;
Integer hundreds = value - units;
return format("%s%s", asWords(hundreds), asWords(units));
}

private String fourDigitsNumberAsString(Integer value) {
Integer units = value % 1000;
Integer thousands = value - units;
return format("%s%s", asWords(thousands), asWords(units));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package pl.allegro.finance.tradukisto.internal.languages.japanese;

import pl.allegro.finance.tradukisto.internal.BaseValues;
import pl.allegro.finance.tradukisto.internal.languages.GenderForms;
import pl.allegro.finance.tradukisto.internal.languages.PluralForms;

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

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

public class JapaneseValues implements BaseValues {

@Override
public Map<Integer, GenderForms> baseNumbers() {
return baseNumbersBuilder()
.put(0, "零")
.put(1, "一")
.put(2, "二")
.put(3, "三")
.put(4, "四")
.put(5, "五")
.put(6, "六")
.put(7, "七")
.put(8, "八")
.put(9, "九")
.put(10, "十")
.put(20, "二十")
.put(30, "三十")
.put(40, "四十")
.put(50, "五十")
.put(60, "六十")
.put(70, "七十")
.put(80, "八十")
.put(90, "九十")
.put(100, "百")
.put(200, "二百")
.put(300, "三百")
.put(400, "四百")
.put(500, "五百")
.put(600, "六百")
.put(700, "七百")
.put(800, "八百")
.put(900, "九百")
.put(1000, "千")
.put(2000, "二千")
.put(3000, "三千")
.put(4000, "四千")
.put(5000, "五千")
.put(6000, "六千")
.put(7000, "七千")
.put(8000, "八千")
.put(9000, "九千")
.build();
}

@Override
public List<PluralForms> pluralForms() {
return Arrays.asList(
new JapanesePluralForms(""),
new JapanesePluralForms("万"),
new JapanesePluralForms("億"),
new JapanesePluralForms("兆"),
new JapanesePluralForms("京")
);
}

@Override
public String currency() {
return "円";
}

@Override
public char twoDigitsNumberSeparator() {
return ' ';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package pl.allegro.finance.tradukisto.internal.support;

import java.util.LinkedList;
import java.util.List;

public class JapaneseNumberChunking extends NumberChunking {

private static final int JAPANESE_SPLIT_FACTOR = 1_0000;

@Override
public List<Integer> chunk(Long value) {
LinkedList<Integer> result = new LinkedList<>();

while (value > 0) {
result.addFirst((int) (value % JAPANESE_SPLIT_FACTOR));
value /= JAPANESE_SPLIT_FACTOR;
}

return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ 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
import static pl.allegro.finance.tradukisto.LongValueConverters.JAPANESE_KANJI_LONG

class LongValueConvertersTest extends Specification {

Expand All @@ -21,6 +22,7 @@ class LongValueConvertersTest extends Specification {
"Polish" | POLISH_LONG || "jeden trylion"
"Hindi" | HINDI_LONG || "दस शंख"
"Swedish" | SWEDISH_LONG || "en triljon"
"Japanese"| JAPANESE_KANJI_LONG || "百京"
}

def "should throw exception when null given"() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import static pl.allegro.finance.tradukisto.MoneyConverters.FRENCH_BANKING_MONEY
import static pl.allegro.finance.tradukisto.MoneyConverters.GERMAN_BANKING_MONEY_VALUE
import static pl.allegro.finance.tradukisto.MoneyConverters.HINDI_BANKING_MONEY_VALUE
import static pl.allegro.finance.tradukisto.MoneyConverters.ITALIAN_BANKING_MONEY_VALUE
import static pl.allegro.finance.tradukisto.MoneyConverters.JAPANESE_BANKING_MONEY_VALUE
import static pl.allegro.finance.tradukisto.MoneyConverters.KAZAKH_BANKING_MONEY_VALUE
import static pl.allegro.finance.tradukisto.MoneyConverters.LATVIAN_BANKING_MONEY_VALUE
import static pl.allegro.finance.tradukisto.MoneyConverters.POLISH_BANKING_MONEY_VALUE
Expand Down Expand Up @@ -44,6 +45,7 @@ class MoneyConvertersTest extends Specification {
"French" | FRENCH_BANKING_MONEY_VALUE || "mille deux cent trente-quatre € 56/100"
"German" | GERMAN_BANKING_MONEY_VALUE || "eintausendzweihundertvierunddreißig € 56/100"
"Italian" | ITALIAN_BANKING_MONEY_VALUE || "milleduecentotrentaquattro € 56/100"
"Japanese" | JAPANESE_BANKING_MONEY_VALUE || "千二百三十四 円 56/100"
"Kazakh" | KAZAKH_BANKING_MONEY_VALUE || "бір мың екі жүз отыз төрт KZT 56/100"
"Latvian" | LATVIAN_BANKING_MONEY_VALUE || "viens tūkstotis divi simti trīsdesmit četri EUR 56/100"
"Polish" | POLISH_BANKING_MONEY_VALUE || "jeden tysiąc dwieście trzydzieści cztery PLN 56/100"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import static pl.allegro.finance.tradukisto.ValueConverters.FRENCH_INTEGER
import static pl.allegro.finance.tradukisto.ValueConverters.GERMAN_INTEGER
import static pl.allegro.finance.tradukisto.ValueConverters.HINDI_INTEGER
import static pl.allegro.finance.tradukisto.ValueConverters.ITALIAN_INTEGER
import static pl.allegro.finance.tradukisto.ValueConverters.JAPANESE_INTEGER
import static pl.allegro.finance.tradukisto.ValueConverters.KAZAKH_INTEGER
import static pl.allegro.finance.tradukisto.ValueConverters.LATVIAN_INTEGER
import static pl.allegro.finance.tradukisto.ValueConverters.POLISH_INTEGER
Expand Down Expand Up @@ -44,6 +45,7 @@ class ValueConvertersTest extends Specification {
"French" | FRENCH_INTEGER || "mille deux cent trente-quatre"
"German" | GERMAN_INTEGER || "eintausendzweihundertvierunddreißig"
"Italian" | ITALIAN_INTEGER || "milleduecentotrentaquattro"
"Japanese" | JAPANESE_INTEGER || "千二百三十四"
"Kazakh" | KAZAKH_INTEGER || "бір мың екі жүз отыз төрт"
"Latvian" | LATVIAN_INTEGER || "viens tūkstotis divi simti trīsdesmit četri"
"Polish" | POLISH_INTEGER || "jeden tysiąc dwieście trzydzieści cztery"
Expand Down Expand Up @@ -103,6 +105,8 @@ class ValueConvertersTest extends Specification {
new Locale("nl") || DUTCH_INTEGER
new Locale("hi") || HINDI_INTEGER
new Locale("sv") || SWEDISH_INTEGER
new Locale("ja") || JAPANESE_INTEGER
Locale.JAPANESE || JAPANESE_INTEGER
}

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

def "should return supplied default converter when languageCode is unknown"() {
Expand Down
Loading

0 comments on commit 3f6438b

Please sign in to comment.