diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/LocaleNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/LocaleNativeGenerator.java new file mode 100644 index 000000000..b8de954cf --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/LocaleNativeGenerator.java @@ -0,0 +1,57 @@ +/* + * 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.java.util; + +import java.io.IOException; +import org.teavm.codegen.SourceWriter; +import org.teavm.javascript.ni.Generator; +import org.teavm.javascript.ni.GeneratorContext; +import org.teavm.model.MethodReference; + +/** + * + * @author Alexey Andreev + */ +public class LocaleNativeGenerator implements Generator { + @Override + public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException { + switch (methodRef.getName()) { + case "getDisplayCountry": + writer.append("var result = ").appendClass("java.util.Locale").append(".$CLDR[$rt_ustr(") + .append(context.getParameterName(1)).append(")].territories[$rt_ustr(") + .append(context.getParameterName(2)).append(")];").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(") + .append(context.getParameterName(1)).append(")].languages[$rt_ustr(") + .append(context.getParameterName(2)).append(")];").softNewLine(); + writer.append("return result ? $rt_str(result) : null;").softNewLine(); + break; + case "getAvailableLocales": + generateAvailableLocales(writer); + break; + } + } + + private void generateAvailableLocales(SourceWriter writer) throws IOException { + writer.append("var locales = Object.keys(").appendClass("java.util.Locale").append(".$CLDR);").softNewLine(); + writer.append("var array = $rt_createArray(").appendClass("java.lang.String").append(", locales);") + .softNewLine(); + writer.append("for (var i = 0; i < locales.length; ++i) {").indent().softNewLine(); + writer.append("array.data[i] = locales[i];"); + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TLocale.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TLocale.java new file mode 100644 index 000000000..1607f7ab0 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TLocale.java @@ -0,0 +1,257 @@ +/* + * 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. + */ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.java.util; + +import java.util.Arrays; +import org.teavm.classlib.java.io.TSerializable; +import org.teavm.classlib.java.lang.TCloneable; +import org.teavm.javascript.ni.GeneratedBy; + +public final class TLocale implements TCloneable, TSerializable { + private static TLocale defaultLocale; + public static final TLocale CANADA = new TLocale("en", "CA"); + public static final TLocale CANADA_FRENCH = new TLocale("fr", "CA"); + public static final TLocale CHINA = new TLocale("zh", "CN"); + public static final TLocale CHINESE = new TLocale("zh", ""); + public static final TLocale ENGLISH = new TLocale("en", ""); + public static final TLocale FRANCE = new TLocale("fr", "FR"); + public static final TLocale FRENCH = new TLocale("fr", ""); + public static final TLocale GERMAN = new TLocale("de", ""); + public static final TLocale GERMANY = new TLocale("de", "DE"); + public static final TLocale ITALIAN = new TLocale("it", ""); + public static final TLocale ITALY = new TLocale("it", "IT"); + public static final TLocale JAPAN = new TLocale("ja", "JP"); + public static final TLocale JAPANESE = new TLocale("ja", ""); + public static final TLocale KOREA = new TLocale("ko", "KR"); + public static final TLocale KOREAN = new TLocale("ko", ""); + public static final TLocale PRC = new TLocale("zh", "CN"); + public static final TLocale SIMPLIFIED_CHINESE = new TLocale("zh", "CN"); + public static final TLocale TAIWAN = new TLocale("zh", "TW"); + public static final TLocale TRADITIONAL_CHINESE = new TLocale("zh", "TW"); + public static final TLocale UK = new TLocale("en", "GB"); + public static final TLocale US = new TLocale("en", "US"); + public static final TLocale ROOT = new TLocale("", ""); + private static TLocale[] availableLocales; + + static { + String localeName = getDefaultLocale(); + int countryIndex = localeName.indexOf('_'); + defaultLocale = new TLocale(localeName.substring(0, countryIndex), localeName.substring(countryIndex) + 1, ""); + readCLDR(); + } + + private transient String countryCode; + private transient String languageCode; + private transient String variantCode; + + // Redefined by JCLPlugin + private static native String getDefaultLocale(); + + // Redefined by JCLPlugin + private static native void readCLDR(); + + public TLocale(String language) { + this(language, "", ""); + } + + public TLocale(String language, String country) { + this(language, country, ""); + } + + public TLocale(String language, String country, String variant) { + if (language == null || country == null || variant == null) { + throw new NullPointerException(); + } + if (language.length() == 0 && country.length() == 0) { + languageCode = ""; + countryCode = ""; + variantCode = variant; + return; + } + languageCode = language; + countryCode = country; + variantCode = variant; + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + return null; + } + } + + @Override + public boolean equals(Object object) { + if (object == this) { + return true; + } + if (object instanceof TLocale) { + TLocale o = (TLocale) object; + return languageCode.equals(o.languageCode) && countryCode.equals(o.countryCode) && + variantCode.equals(o.variantCode); + } + return false; + } + + public static TLocale[] getAvailableLocales() { + if (availableLocales == null) { + availableLocales = getAvailableLocales(); + } + return Arrays.copyOf(availableLocales, availableLocales.length); + } + + @GeneratedBy(LocaleNativeGenerator.class) + private static native String[] getAvailableLocaleStrings(); + + public String getCountry() { + return countryCode; + } + + public static TLocale getDefault() { + return defaultLocale; + } + + public final String getDisplayCountry() { + return getDisplayCountry(getDefault()); + } + + public String getDisplayCountry(TLocale locale) { + String result = getDisplayCountry(locale.getLanguage() + "-" + locale.getCountry(), countryCode); + if (result == null) { + result = getDisplayCountry(locale.getLanguage(), countryCode); + } + return result != null ? result : countryCode; + } + + @GeneratedBy(LocaleNativeGenerator.class) + private static native String getDisplayCountry(String localeName, String country); + + public final String getDisplayLanguage() { + return getDisplayLanguage(getDefault()); + } + + public String getDisplayLanguage(TLocale locale) { + String result = getDisplayLanguage(locale.getLanguage() + "_" + locale.getCountry(), countryCode); + if (result == null) { + result = getDisplayLanguage(locale.getLanguage(), countryCode); + } + return result != null ? result : countryCode; + } + + @GeneratedBy(LocaleNativeGenerator.class) + private static native String getDisplayLanguage(String localeName, String country); + + public final String getDisplayName() { + return getDisplayName(getDefault()); + } + + public String getDisplayName(TLocale locale) { + int count = 0; + StringBuilder buffer = new StringBuilder(); + if (languageCode.length() > 0) { + buffer.append(getDisplayLanguage(locale)); + count++; + } + if (countryCode.length() > 0) { + if (count == 1) { + buffer.append(" ("); + } + buffer.append(getDisplayCountry(locale)); + count++; + } + if (variantCode.length() > 0) { + if (count == 1) { + buffer.append(" ("); + } else if (count == 2) { + buffer.append(","); + } + buffer.append(getDisplayVariant(locale)); + count++; + } + if (count > 1) { + buffer.append(")"); + } + return buffer.toString(); + } + + public final String getDisplayVariant() { + return getDisplayVariant(getDefault()); + } + + public String getDisplayVariant(TLocale locale) { + // TODO: use CLDR + return locale.getVariant(); + } + + public String getLanguage() { + return languageCode; + } + + public String getVariant() { + return variantCode; + } + + @Override + public synchronized int hashCode() { + return countryCode.hashCode() + languageCode.hashCode() + variantCode.hashCode(); + } + + public synchronized static void setDefault(TLocale locale) { + if (locale != null) { + defaultLocale = locale; + } else { + throw new NullPointerException(); + } + } + + @Override + public final String toString() { + StringBuilder result = new StringBuilder(); + result.append(languageCode); + if (countryCode.length() > 0) { + result.append('_'); + result.append(countryCode); + } + if (variantCode.length() > 0 && result.length() > 0) { + if (0 == countryCode.length()) { + result.append("__"); + } else { + result.append('_'); + } + result.append(variantCode); + } + return result.toString(); + } +} diff --git a/teavm-classlib/src/main/resources/org/teavm/classlib/impl/unicode/cldr-json.zip b/teavm-classlib/src/main/resources/org/teavm/classlib/impl/unicode/cldr-json.zip new file mode 100644 index 000000000..6f9f9e53c Binary files /dev/null and b/teavm-classlib/src/main/resources/org/teavm/classlib/impl/unicode/cldr-json.zip differ