Add support of ISO 3166

This commit is contained in:
Alexey Andreev 2015-05-29 18:43:43 +04:00
parent eb4e74a778
commit 1cc1d60f9e
6 changed files with 152 additions and 12 deletions

View File

@ -0,0 +1,108 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.impl.currency;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.teavm.model.MethodReference;
import org.teavm.platform.metadata.*;
/**
*
* @author Alexey Andreev
*/
public class CountriesGenerator implements MetadataGenerator {
@Override
public Resource generateMetadata(MetadataGeneratorContext context, MethodReference method) {
try (InputStream input = context.getClassLoader().getResourceAsStream(
"org/teavm/classlib/impl/currency/iso3166.csv")) {
if (input == null) {
throw new AssertionError("ISO 3166 table was not found");
}
try (BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"))) {
return readIso3166(context, reader);
}
} catch (IOException e) {
throw new RuntimeException("Error reading ISO 3166 table", e);
}
}
private ResourceMap<StringResource> readIso3166(MetadataGeneratorContext context, BufferedReader reader)
throws IOException {
ResourceMap<StringResource> result = context.createResourceMap();
int index = 0;
while (true) {
String line = reader.readLine();
if (line == null) {
break;
}
if (index++ == 0 || line.trim().isEmpty()) {
continue;
}
String[] cells = readCsvRow(index - 1, line);
StringResource currency = context.createResource(StringResource.class);
currency.setValue(cells[7]);
result.put(cells[10], currency);
}
return result;
}
private String[] readCsvRow(int rowIndex, String row) {
List<String> values = new ArrayList<>();
int index = 0;
while (index < row.length()) {
char c = row.charAt(index);
int next = index;
if (c == '"') {
++index;
StringBuilder sb = new StringBuilder();
while (index < row.length()) {
next = row.indexOf('"', index);
if (next == -1) {
throw new IllegalStateException("Syntax error at row " + rowIndex +
": closing quote not found");
}
if (next + 1 == row.length() || row.charAt(next + 1) != '"') {
sb.append(row.substring(index, next));
index = next + 1;
break;
}
index = next + 2;
}
if (index < row.length() && row.charAt(index) != ',') {
throw new IllegalStateException("Syntax error at row " + rowIndex + ": closing quote must be " +
"followed by either line separator or comma");
}
values.add(sb.toString());
} else {
next = row.indexOf(',', index);
if (next == -1) {
values.add(row.substring(index));
index = row.length();
} else {
values.add(row.substring(index, next));
++next;
index = next;
}
}
}
return values.toArray(new String[values.size()]);
}
}

View File

@ -17,6 +17,8 @@ package org.teavm.classlib.impl.currency;
import org.teavm.platform.metadata.MetadataProvider; import org.teavm.platform.metadata.MetadataProvider;
import org.teavm.platform.metadata.ResourceArray; import org.teavm.platform.metadata.ResourceArray;
import org.teavm.platform.metadata.ResourceMap;
import org.teavm.platform.metadata.StringResource;
/** /**
* *
@ -25,4 +27,7 @@ import org.teavm.platform.metadata.ResourceArray;
public final class CurrencyHelper { public final class CurrencyHelper {
@MetadataProvider(CurrenciesGenerator.class) @MetadataProvider(CurrenciesGenerator.class)
public static native ResourceArray<CurrencyResource> getCurrencies(); public static native ResourceArray<CurrencyResource> getCurrencies();
@MetadataProvider(CountriesGenerator.class)
public static native ResourceMap<StringResource> getCountryToCurrencyMap();
} }

View File

@ -33,6 +33,15 @@ public class CLDRHelper {
return map.has(localeCode) ? map.get(localeCode).getValue() : localeCode; return map.has(localeCode) ? map.get(localeCode).getValue() : localeCode;
} }
public static String resolveCountry(String language, String country) {
if (country.isEmpty()) {
String subtags = getLikelySubtags(language);
int index = subtags.lastIndexOf('_');
country = index > 0 ? subtags.substring(index + 1) : "";
}
return country;
}
@MetadataProvider(LikelySubtagsMetadataGenerator.class) @MetadataProvider(LikelySubtagsMetadataGenerator.class)
private static native ResourceMap<StringResource> getLikelySubtagsMap(); private static native ResourceMap<StringResource> getLikelySubtagsMap();

View File

@ -175,21 +175,11 @@ public abstract class TCalendar implements TSerializable, TCloneable, TComparabl
cacheFor = locale; cacheFor = locale;
} }
private static String resolveCountry(TLocale locale) {
String country = locale.getCountry();
if (country.isEmpty()) {
String subtags = CLDRHelper.getLikelySubtags(locale.getLanguage());
int index = subtags.lastIndexOf('_');
country = index > 0 ? subtags.substring(index + 1) : "";
}
return country;
}
private static int resolveFirstDayOfWeek(TLocale locale) { private static int resolveFirstDayOfWeek(TLocale locale) {
if (locale == cacheFor && firstDayOfWeekCache >= 0) { if (locale == cacheFor && firstDayOfWeekCache >= 0) {
return firstDayOfWeekCache; return firstDayOfWeekCache;
} }
String country = resolveCountry(locale); String country = CLDRHelper.resolveCountry(locale.getLanguage(), locale.getCountry());
ResourceMap<IntResource> dayMap = CLDRHelper.getFirstDayOfWeek(); ResourceMap<IntResource> dayMap = CLDRHelper.getFirstDayOfWeek();
firstDayOfWeekCache = dayMap.has(country) ? dayMap.get(country).getValue() : dayMap.get("001").getValue(); firstDayOfWeekCache = dayMap.has(country) ? dayMap.get(country).getValue() : dayMap.get("001").getValue();
return firstDayOfWeekCache; return firstDayOfWeekCache;
@ -199,7 +189,7 @@ public abstract class TCalendar implements TSerializable, TCloneable, TComparabl
if (locale == cacheFor && minimalDaysInFirstWeekCache >= 0) { if (locale == cacheFor && minimalDaysInFirstWeekCache >= 0) {
return minimalDaysInFirstWeekCache; return minimalDaysInFirstWeekCache;
} }
String country = resolveCountry(locale); String country = CLDRHelper.resolveCountry(locale.getLanguage(), locale.getCountry());
ResourceMap<IntResource> dayMap = CLDRHelper.getMinimalDaysInFirstWeek(); ResourceMap<IntResource> dayMap = CLDRHelper.getMinimalDaysInFirstWeek();
minimalDaysInFirstWeekCache = dayMap.has(country) ? dayMap.get(country).getValue() : minimalDaysInFirstWeekCache = dayMap.has(country) ? dayMap.get(country).getValue() :
dayMap.get("001").getValue(); dayMap.get("001").getValue();

View File

@ -21,8 +21,11 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import org.teavm.classlib.impl.currency.CurrencyHelper; import org.teavm.classlib.impl.currency.CurrencyHelper;
import org.teavm.classlib.impl.currency.CurrencyResource; import org.teavm.classlib.impl.currency.CurrencyResource;
import org.teavm.classlib.impl.unicode.CLDRHelper;
import org.teavm.classlib.java.io.TSerializable; import org.teavm.classlib.java.io.TSerializable;
import org.teavm.platform.metadata.ResourceArray; import org.teavm.platform.metadata.ResourceArray;
import org.teavm.platform.metadata.ResourceMap;
import org.teavm.platform.metadata.StringResource;
/** /**
* *
@ -60,6 +63,18 @@ public final class TCurrency implements TSerializable {
return currency; return currency;
} }
public static TCurrency getInstance(TLocale locale) {
if (locale == null) {
throw new NullPointerException();
}
String coutry = CLDRHelper.resolveCountry(locale.getLanguage(), locale.getCountry());
ResourceMap<StringResource> countryMap = CurrencyHelper.getCountryToCurrencyMap();
if (!countryMap.has(coutry)) {
return null;
}
return getInstance(countryMap.get(coutry).getValue());
}
public static Set<TCurrency> getAvailableCurrencies() { public static Set<TCurrency> getAvailableCurrencies() {
initCurrencies(); initCurrencies();
return new HashSet<>(currencies.values()); return new HashSet<>(currencies.values());

View File

@ -17,6 +17,7 @@ package org.teavm.classlib.java.util;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.util.Currency; import java.util.Currency;
import java.util.Locale;
import org.junit.Test; import org.junit.Test;
/** /**
@ -32,6 +33,18 @@ public class CurrencyTest {
assertEquals(643, currency.getNumericCode()); assertEquals(643, currency.getNumericCode());
} }
@Test
public void findsByLocale() {
Currency currency = Currency.getInstance(new Locale("ru", "RU"));
assertEquals("RUB", currency.getCurrencyCode());
currency = Currency.getInstance(new Locale("en", "US"));
assertEquals("USD", currency.getCurrencyCode());
currency = Currency.getInstance(new Locale("en", "GB"));
assertEquals("GBP", currency.getCurrencyCode());
}
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void rejectsWrongCode() { public void rejectsWrongCode() {
Currency.getInstance("WWW"); Currency.getInstance("WWW");