Further implementation of localized Calendar

This commit is contained in:
konsoletyper 2014-05-20 14:14:38 +04:00
parent 9df49fad0a
commit 5770df5413
8 changed files with 192 additions and 25 deletions

View File

@ -44,7 +44,9 @@ public class JCLPlugin implements TeaVMPlugin {
host.add(javacSupport);
Generator localeGen = new LocaleSettingsNativeGenerator(host.getClassLoader(), host.getProperties());
host.add(new MethodReference("java.util.Locale", "readCLDR", ValueType.VOID), localeGen);
host.add(new MethodReference("java.util.Locale", "readLanguagesFromCLDR", ValueType.VOID), localeGen);
host.add(new MethodReference("java.util.Locale", "readCountriesFromCLDR", ValueType.VOID), localeGen);
host.add(new MethodReference("java.util.Calendar", "readWeeksFromCLDR", ValueType.VOID), localeGen);
host.add(new MethodReference("java.util.Locale", "getDefaultLocale", ValueType.object("java.lang.String")),
localeGen);
}

View File

@ -23,4 +23,16 @@ public class CLDRHelper {
public static String getCode(String language, String country) {
return !country.isEmpty() ? language + "-" + country : language;
}
public static String getLikelySubtags(String localeCode) {
readLikelySubtagsFromCLDR();
String subtags = getLikelySubtagsImpl(localeCode);
return subtags != null ? subtags : localeCode;
}
// Defined by JCLPlugin
private static native void readLikelySubtagsFromCLDR();
// TODO: implement using CLDR
private static native String getLikelySubtagsImpl(String localeCode);
}

View File

@ -0,0 +1,51 @@
/*
* Copyright 2014 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.io.IOException;
import org.teavm.codegen.SourceWriter;
import org.teavm.dependency.DependencyChecker;
import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.MethodDependency;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev
*/
public class CLDRHelperNativeGenerator implements Generator, DependencyPlugin {
@Override
public void methodAchieved(DependencyChecker checker, MethodDependency method) {
switch (method.getMethod().getName()) {
case "getLikelySubtagsImpl":
method.getResult().propagate("java.lang.String");
break;
}
}
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
switch (methodRef.getName()) {
case "getLikelySubtagsImpl":
writer.append("var data = ").appendClass("java.util.Locale").append(".$CLDR.likelySubtags[$rt_ustr(")
.append(context.getParameterName(1)).append(")];").softNewLine();
writer.append("return data ? $rt_str(data) : null;").softNewLine();
break;
}
}
}

View File

@ -28,6 +28,20 @@ import org.teavm.model.MethodReference;
public class CalendarNativeGenerator implements Generator {
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
switch (methodRef.getName()) {
case "getFirstDayOfWeek":
generateWeekMethod(context, writer, "firstDay");
break;
case "getMinimalDaysInFirstWeek":
generateWeekMethod(context, writer, "minDays");
break;
}
}
private void generateWeekMethod(GeneratorContext context, SourceWriter writer, String property)
throws IOException {
writer.append("var result = ").appendClass("java.util.Locale").append(".$CLDR.").append(property)
.append("[$rt_ustr(").append(context.getParameterName(1)).append(")];").softNewLine();
writer.append("return result ? result : -1;").softNewLine();
}
}

View File

@ -32,17 +32,20 @@ public class LocaleNativeGenerator implements Generator, DependencyPlugin {
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
switch (methodRef.getName()) {
case "prepareCLDR":
writer.appendClass("java.util.Locale").append(".$CLDR = {};").softNewLine();
break;
case "getDisplayCountry":
writer.append("var result = ").appendClass("java.util.Locale").append(".$CLDR[$rt_ustr(")
writer.append("var result = ").appendClass("java.util.Locale").append(".$CLDR.territories[$rt_ustr(")
.append(context.getParameterName(1)).append(")];").softNewLine();
writer.append("result = result ? result.territories[$rt_ustr(")
writer.append("result = result ? result[$rt_ustr(")
.append(context.getParameterName(2)).append(")] : undefined;").softNewLine();
writer.append("return result ? $rt_str(result) : null").softNewLine();
break;
case "getDisplayLanguage":
writer.append("var result = ").appendClass("java.util.Locale").append(".$CLDR[$rt_ustr(")
writer.append("var result = ").appendClass("java.util.Locale").append(".$CLDR.languages[$rt_ustr(")
.append(context.getParameterName(1)).append(")];").softNewLine();
writer.append("result = result ? result.languages[$rt_ustr(")
writer.append("result = result ? result[$rt_ustr(")
.append(context.getParameterName(2)).append(")] : undefined;").softNewLine();
writer.append("return result ? $rt_str(result) : null;").softNewLine();
break;

View File

@ -181,8 +181,14 @@ public class LocaleSettingsNativeGenerator implements Generator {
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
init();
switch (methodRef.getName()) {
case "readCLDR":
generateReadCLDR(writer);
case "readLanguagesFromCLDR":
generateReadLanguagesFromCLDR(writer);
break;
case "readCountriesFromCLDR":
generateReadCountriesFromCLDR(writer);
break;
case "readWeeksFromCLDR":
generateReadWeeksFromCDLR(writer);
break;
case "getDefaultLocale":
generateGetDefaultLocale(writer);
@ -190,11 +196,16 @@ public class LocaleSettingsNativeGenerator implements Generator {
}
}
private void generateReadCLDR(SourceWriter writer) throws IOException {
writer.append("if (").appendClass("java.util.Locale").append("$CLDR").append("{").indent().softNewLine();
private void generateDefender(SourceWriter writer, String property) throws IOException {
writer.append("if (").appendClass("java.util.Locale").append(".$CLDR.").append(property)
.append(")").ws().append("{").indent().softNewLine();
writer.append("return;").softNewLine();
writer.outdent().append("}").softNewLine();
writer.appendClass("java.util.Locale").append(".$CLDR = {").indent().softNewLine();
}
private void generateReadLanguagesFromCLDR(SourceWriter writer) throws IOException {
generateDefender(writer, "languages");
writer.appendClass("java.util.Locale").append(".$CLDR.languages = {").indent().softNewLine();
boolean firstLocale = true;
for (Map.Entry<String, LocaleInfo> entry : knownLocales.entrySet()) {
if (!firstLocale) {
@ -204,7 +215,6 @@ public class LocaleSettingsNativeGenerator implements Generator {
writer.append('"').append(Renderer.escapeString(entry.getKey())).append('"').ws().append(":").ws()
.append('{').indent().softNewLine();
writer.append("\"languages\"").ws().append(':').ws().append('{').indent().softNewLine();
boolean first = true;
for (Map.Entry<String, String> langEntry : entry.getValue().languages.entrySet()) {
if (!first) {
@ -214,10 +224,24 @@ public class LocaleSettingsNativeGenerator implements Generator {
writer.append('"').append(Renderer.escapeString(langEntry.getKey())).append('"').ws().append(':')
.ws().append('"').append(Renderer.escapeString(langEntry.getValue())).append('"');
}
writer.outdent().append("},").softNewLine();
writer.outdent().append('}');
}
writer.outdent().append("}").softNewLine();
}
writer.append("\"territories\"").ws().append(':').ws().append('{').indent().softNewLine();
first = true;
private void generateReadCountriesFromCLDR(SourceWriter writer) throws IOException {
generateDefender(writer, "territories");
writer.appendClass("java.util.Locale").append(".$CLDR.territories = {").indent().softNewLine();
boolean firstLocale = true;
for (Map.Entry<String, LocaleInfo> entry : knownLocales.entrySet()) {
if (!firstLocale) {
writer.append(",").softNewLine();
}
firstLocale = false;
writer.append('"').append(Renderer.escapeString(entry.getKey())).append('"').ws().append(":").ws()
.append('{').indent().softNewLine();
boolean first = true;
for (Map.Entry<String, String> langEntry : entry.getValue().territories.entrySet()) {
if (!first) {
writer.append(',').softNewLine();
@ -226,13 +250,39 @@ public class LocaleSettingsNativeGenerator implements Generator {
writer.append('"').append(Renderer.escapeString(langEntry.getKey())).append('"').ws().append(':')
.ws().append('"').append(Renderer.escapeString(langEntry.getValue())).append('"');
}
writer.outdent().append('}');
writer.outdent().append('}');
}
writer.outdent().append("}").softNewLine();
}
private void generateReadWeeksFromCDLR(SourceWriter writer) throws IOException {
generateDefender(writer, "minDays");
writer.appendClass("java.util.Locale").append(".$CLDR.minDays = {").indent().softNewLine();
boolean firstLocale = true;
for (Map.Entry<String, Integer> entry : minDaysMap.entrySet()) {
if (!firstLocale) {
writer.append(",").softNewLine();
}
firstLocale = false;
writer.append('"').append(Renderer.escapeString(entry.getKey())).append('"').ws().append(':')
.ws().append('"').append(entry.getValue()).append('"');
}
writer.outdent().append("}").softNewLine();
writer.appendClass("java.util.Locale").append(".$CLDR.firstDay = {").indent().softNewLine();
firstLocale = true;
for (Map.Entry<String, Integer> entry : firstDayMap.entrySet()) {
if (!firstLocale) {
writer.append(",").softNewLine();
}
firstLocale = false;
writer.append('"').append(Renderer.escapeString(entry.getKey())).append('"').ws().append(':')
.ws().append('"').append(entry.getValue()).append('"');
}
writer.outdent().append("}").softNewLine();
}
private void generateGetDefaultLocale(SourceWriter writer) throws IOException {
String locale = properties.getProperty("java.util.Locale.default", "en_EN");
writer.append("return $rt_str(\"").append(Renderer.escapeString(locale)).append("\");").softNewLine();

View File

@ -36,6 +36,7 @@ import org.teavm.classlib.impl.unicode.CLDRHelper;
import org.teavm.classlib.java.io.TSerializable;
import org.teavm.classlib.java.lang.TCloneable;
import org.teavm.classlib.java.lang.TComparable;
import org.teavm.javascript.ni.GeneratedBy;
public abstract class TCalendar implements TSerializable, TCloneable, TComparable<TCalendar> {
protected boolean areFieldsSet;
@ -140,7 +141,6 @@ public abstract class TCalendar implements TSerializable, TCloneable, TComparabl
public static final int PM = 1;
@SuppressWarnings("nls")
private static String[] fieldNames = { "ERA=", "YEAR=", "MONTH=", "WEEK_OF_YEAR=", "WEEK_OF_MONTH=",
"DAY_OF_MONTH=", "DAY_OF_YEAR=", "DAY_OF_WEEK=", "DAY_OF_WEEK_IN_MONTH=", "AM_PM=", "HOUR=", "HOUR_OF_DAY",
"MINUTE=", "SECOND=", "MILLISECOND=", "ZONE_OFFSET=", "DST_OFFSET=" };
@ -154,19 +154,46 @@ public abstract class TCalendar implements TSerializable, TCloneable, TComparabl
isSet = new boolean[FIELD_COUNT];
areFieldsSet = isTimeSet = false;
setLenient(true);
initLocales();
String localeCode = CLDRHelper.getCode(locale.getLanguage(), locale.getCountry());
setFirstDayOfWeek(getFirstDayOfWeek(localeCode));
setMinimalDaysInFirstWeek(getMinimalDaysInFirstWeek(localeCode));
readWeeksFromCDLR();
setFirstDayOfWeek(resolveFirstDayOfWeek(locale));
setMinimalDaysInFirstWeek(resolveMinimalDaysInFirstWeek(locale));
}
// Generated by JCLPlugin
private static native void initLocales();
private static native void readWeeksFromCDLR();
// TODO: implement using CLDR
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(subtags.lastIndexOf('-') + 1) : "";
}
return country;
}
private static int resolveFirstDayOfWeek(TLocale locale) {
String country = resolveCountry(locale);
int day = getFirstDayOfWeek(country);
if (day < 0) {
day = getFirstDayOfWeek("001");
}
return day;
}
@GeneratedBy(LocaleSettingsNativeGenerator.class)
private static native int getFirstDayOfWeek(String localeCode);
// TODO: implement using CLDR
private static int resolveMinimalDaysInFirstWeek(TLocale locale) {
String country = resolveCountry(locale);
int days = getMinimalDaysInFirstWeek(country);
if (days < 0) {
days = getMinimalDaysInFirstWeek("001");
}
return days;
}
@GeneratedBy(LocaleSettingsNativeGenerator.class)
private static native int getMinimalDaysInFirstWeek(String localeCode);
abstract public void add(int field, int value);

View File

@ -68,7 +68,7 @@ public final class TLocale implements TCloneable, TSerializable {
String localeName = getDefaultLocale();
int countryIndex = localeName.indexOf('_');
defaultLocale = new TLocale(localeName.substring(0, countryIndex), localeName.substring(countryIndex) + 1, "");
readCLDR();
prepareCLDR();
}
private transient String countryCode;
@ -79,8 +79,14 @@ public final class TLocale implements TCloneable, TSerializable {
@PluggableDependency(LocaleNativeGenerator.class)
private static native String getDefaultLocale();
@GeneratedBy(LocaleNativeGenerator.class)
private static native void prepareCLDR();
// Redefined by JCLPlugin
private static native void readCLDR();
private static native void readCountriesFromCLDR();
// Redefined by JCLPlugin
private static native void readLanguagesFromCLDR();
public TLocale(String language) {
this(language, "", "");
@ -162,6 +168,7 @@ public final class TLocale implements TCloneable, TSerializable {
}
public String getDisplayCountry(TLocale locale) {
readCountriesFromCLDR();
String result = getDisplayCountry(locale.getLanguage() + "-" + locale.getCountry(), countryCode);
if (result == null) {
result = getDisplayCountry(locale.getLanguage(), countryCode);
@ -178,6 +185,7 @@ public final class TLocale implements TCloneable, TSerializable {
}
public String getDisplayLanguage(TLocale locale) {
readLanguagesFromCLDR();
String result = getDisplayLanguage(locale.getLanguage() + "-" + locale.getCountry(), languageCode);
if (result == null) {
result = getDisplayLanguage(locale.getLanguage(), languageCode);