Add localization for time zones

This commit is contained in:
Alexey Andreev 2015-05-18 19:53:45 +04:00
parent 55212cbfe6
commit 7a2c2606aa
9 changed files with 213 additions and 38 deletions

View File

@ -129,7 +129,9 @@ public class DateTimeZoneProvider {
}
}
if (scoreTable.get(0).tz.previousTransition(time) == time) {
if (scoreTable.size() == 1 || scoreTable.get(0).tz.previousTransition(time) == time) {
return scoreTable.get(0).tz;
} else if (scoreTable.size() > 1 && scoreTable.get(0).value + 48 * 7 < scoreTable.get(1).value) {
return scoreTable.get(0).tz;
}

View File

@ -90,6 +90,34 @@ public class CLDRHelper {
return result;
}
public static String getTimeZoneName(String language, String country, String id) {
String locale = getCode(language, country);
if (!getTimeZoneLocalizationMap().has(locale)) {
return null;
}
TimeZoneLocalization localization = getTimeZoneLocalizationMap().get(locale);
int separator = id.indexOf('/');
if (separator < 0) {
return null;
}
String area = id.substring(0, separator);
String territory = id.substring(separator + 1);
if (!localization.getTimeZones().has(area)) {
return null;
}
ResourceMap<StringResource> timeZones = localization.getTimeZones().get(area);
if (!timeZones.has(territory)) {
return null;
}
return timeZones.get(territory).getValue();
}
@MetadataProvider(TimeZoneLocalizationGenerator.class)
public static native ResourceMap<TimeZoneLocalization> getTimeZoneLocalizationMap();
@MetadataProvider(LanguageMetadataGenerator.class)
public static native ResourceMap<ResourceMap<StringResource>> getLanguagesMap();

View File

@ -36,6 +36,7 @@ public class CLDRLocale {
CLDRDateFormats dateFormats;
CLDRDateFormats timeFormats;
CLDRDateFormats dateTimeFormats;
CLDRTimeZone[] timeZones;
public Map<String, String> getLanguages() {
return Collections.unmodifiableMap(languages);
@ -80,4 +81,8 @@ public class CLDRLocale {
public CLDRDateFormats getDateTimeFormats() {
return dateTimeFormats;
}
public CLDRTimeZone[] getTimeZones() {
return timeZones.clone();
}
}

View File

@ -111,6 +111,9 @@ public class CLDRReader {
case "territories.json":
readCountries(localeName, localeInfo, input);
break;
case "timeZoneNames.json":
readTimeZones(localeName, localeInfo, input);
break;
case "ca-gregorian.json": {
JsonObject root = (JsonObject)new JsonParser().parse(new InputStreamReader(input));
readEras(localeName, localeInfo, root);
@ -155,6 +158,36 @@ public class CLDRReader {
}
}
private void readTimeZones(String localeCode, CLDRLocale locale, InputStream input) {
JsonObject root = (JsonObject)new JsonParser().parse(new InputStreamReader(input));
JsonObject zonesJson = root.get("main").getAsJsonObject().get(localeCode).getAsJsonObject()
.get("dates").getAsJsonObject().get("timeZoneNames").getAsJsonObject().get("zone")
.getAsJsonObject();
List<CLDRTimeZone> timeZones = new ArrayList<>();
for (Map.Entry<String, JsonElement> area : zonesJson.entrySet()) {
String areaName = area.getKey();
for (Map.Entry<String, JsonElement> location : area.getValue().getAsJsonObject().entrySet()) {
String locationName = location.getKey();
JsonElement city = location.getValue().getAsJsonObject().get("exemplarCity");
if (city != null) {
CLDRTimeZone tz = new CLDRTimeZone(areaName, locationName, city.getAsString());
timeZones.add(tz);
} else {
for (Map.Entry<String, JsonElement> sublocation : location.getValue()
.getAsJsonObject().entrySet()) {
city = location.getValue().getAsJsonObject().get("exemplarCity");
if (city != null) {
CLDRTimeZone tz = new CLDRTimeZone(areaName, locationName + "/" + sublocation.getKey(),
city.getAsString());
timeZones.add(tz);
}
}
}
}
}
locale.timeZones = timeZones.toArray(new CLDRTimeZone[timeZones.size()]);
}
private void readEras(String localeCode, CLDRLocale locale, JsonObject root) {
JsonObject erasJson = root.get("main").getAsJsonObject().get(localeCode).getAsJsonObject()
.get("dates").getAsJsonObject().get("calendars").getAsJsonObject()

View File

@ -0,0 +1,44 @@
/*
* 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.unicode;
/**
*
* @author Alexey Andreev
*/
public class CLDRTimeZone {
String area;
String location;
String name;
CLDRTimeZone(String area, String location, String name) {
this.area = area;
this.location = location;
this.name = name;
}
public String getArea() {
return area;
}
public String getLocation() {
return location;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,30 @@
/*
* 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.unicode;
import org.teavm.platform.metadata.Resource;
import org.teavm.platform.metadata.ResourceMap;
import org.teavm.platform.metadata.StringResource;
/**
*
* @author Alexey Andreev
*/
public interface TimeZoneLocalization extends Resource {
ResourceMap<ResourceMap<StringResource>> getTimeZones();
void setTimeZones(ResourceMap<ResourceMap<StringResource>> timeZones);
}

View File

@ -0,0 +1,51 @@
/*
* 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.unicode;
import java.util.Map;
import org.teavm.model.MethodReference;
import org.teavm.platform.metadata.*;
/**
*
* @author Alexey Andreev
*/
public class TimeZoneLocalizationGenerator implements MetadataGenerator {
@Override
public Resource generateMetadata(MetadataGeneratorContext context, MethodReference method) {
CLDRReader cldr = context.getService(CLDRReader.class);
ResourceMap<TimeZoneLocalization> localizations = context.createResourceMap();
for (Map.Entry<String, CLDRLocale> locale : cldr.getKnownLocales().entrySet()) {
TimeZoneLocalization localization = context.createResource(TimeZoneLocalization.class);
ResourceMap<ResourceMap<StringResource>> map = context.createResourceMap();
localization.setTimeZones(map);
localizations.put(locale.getKey(), localization);
for (CLDRTimeZone tz : locale.getValue().getTimeZones()) {
ResourceMap<StringResource> area;
if (!map.has(tz.getArea())) {
area = context.createResourceMap();
map.put(tz.getArea(), area);
}
area = map.get(tz.getArea());
StringResource name = context.createResource(StringResource.class);
name.setValue(tz.getName());
area.put(tz.getLocation(), name);
}
}
return localizations;
}
}

View File

@ -22,6 +22,7 @@ import java.util.Arrays;
import org.teavm.classlib.impl.tz.DateTimeZone;
import org.teavm.classlib.impl.tz.DateTimeZoneProvider;
import org.teavm.classlib.impl.tz.FixedDateTimeZone;
import org.teavm.classlib.impl.unicode.CLDRHelper;
/**
* {@code TimeZone} represents a time zone offset, taking into account
@ -84,11 +85,11 @@ public abstract class TTimeZone implements Serializable, Cloneable {
*/
public static final int LONG = 1;
private static TTimeZone Default;
private static TTimeZone defaultTz;
static TTimeZone GMT = new TIANATimeZone(new FixedDateTimeZone("GMT", 0, 0));
private String ID;
private String id;
/**
* Constructs a new instance of this class.
@ -97,7 +98,7 @@ public abstract class TTimeZone implements Serializable, Cloneable {
}
TTimeZone(String id) {
this.ID = id;
this.id = id;
}
/**
@ -155,10 +156,10 @@ public abstract class TTimeZone implements Serializable, Cloneable {
* @return the default time zone.
*/
public static TTimeZone getDefault() {
if (Default == null) {
Default = new TIANATimeZone(DateTimeZoneProvider.detectTimezone());
if (defaultTz == null) {
defaultTz = new TIANATimeZone(DateTimeZoneProvider.detectTimezone());
}
return (TTimeZone) Default.clone();
return (TTimeZone) defaultTz.clone();
}
/**
@ -216,8 +217,11 @@ public abstract class TTimeZone implements Serializable, Cloneable {
* @return the {@code TimeZone} name.
*/
public String getDisplayName(boolean daylightTime, int style, TLocale locale) {
// TODO: implement via CLDR
return null;
String name = CLDRHelper.getTimeZoneName(locale.getLanguage(), locale.getCountry(), id);
if (name == null) {
name = id;
}
return name;
}
/**
@ -226,7 +230,7 @@ public abstract class TTimeZone implements Serializable, Cloneable {
* @return the time zone ID string.
*/
public String getID() {
return ID;
return id;
}
/**
@ -416,7 +420,7 @@ public abstract class TTimeZone implements Serializable, Cloneable {
* a {@code TimeZone} object.
*/
public static void setDefault(TTimeZone timezone) {
Default = timezone != null ? (TTimeZone)timezone.clone() : null;
defaultTz = timezone != null ? (TTimeZone)timezone.clone() : null;
}
/**
@ -429,7 +433,7 @@ public abstract class TTimeZone implements Serializable, Cloneable {
if (name == null) {
throw new NullPointerException();
}
ID = name;
id = name;
}
/**

View File

@ -22,9 +22,9 @@ import static org.junit.Assert.assertNotSame;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
import org.junit.Test;
import org.teavm.classlib.impl.tz.DateTimeZoneProvider;
/**
*
@ -36,6 +36,9 @@ public class TimeZoneTest {
@Test
public void test_getDefault() {
assertNotSame("returns identical", TimeZone.getDefault(), TimeZone.getDefault());
for (int i = 0; i < 30; ++i) {
DateTimeZoneProvider.detectTimezone();
}
}
@Test
@ -100,12 +103,6 @@ public class TimeZoneTest {
.getTimeZone("GMT-00").getID());
}
@Test
public void test_getDisplayNameLjava_util_Locale() {
TimeZone timezone = TimeZone.getTimeZone("Asia/Shanghai");
assertEquals("\u4e2d\u56fd\u6807\u51c6\u65f6\u95f4", timezone.getDisplayName(Locale.CHINA));
}
@Test
public void test_GetTimezoneOffset() {
TimeZone tz = TimeZone.getTimeZone("America/Toronto");
@ -114,23 +111,4 @@ public class TimeZoneTest {
date = new GregorianCalendar(1999, 8, 1).getTime();
assertEquals(-240 * 60_000, tz.getOffset(date.getTime()));
}
@Test
public void test_getDisplayName() {
TimeZone defaultZone = TimeZone.getDefault();
Locale defaulLocal = Locale.getDefault();
String defaultName = defaultZone.getDisplayName();
String expectedName = defaultZone.getDisplayName(defaulLocal);
assertEquals("getDispalyName() did not return the default Locale suitable name", expectedName, defaultName);
}
@Test
public void test_getDisplayName_ZI() {
TimeZone defaultZone = TimeZone.getDefault();
Locale defaultLocale = Locale.getDefault();
String actualName = defaultZone.getDisplayName(false, TimeZone.LONG);
String expectedName = defaultZone.getDisplayName(false, TimeZone.LONG, defaultLocale);
assertEquals("getDisplayName(daylight,style) did not return the default locale suitable name", expectedName,
actualName);
}
}