diff --git a/teavm-classlib/pom.xml b/teavm-classlib/pom.xml index 4c97ebc99..199365cb0 100644 --- a/teavm-classlib/pom.xml +++ b/teavm-classlib/pom.xml @@ -61,6 +61,9 @@ false 1 + + en, en_US, en_GB, ru, ru_RU + 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 index b8de954cf..2ec52ee30 100644 --- 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 @@ -17,6 +17,9 @@ package org.teavm.classlib.java.util; 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; @@ -25,7 +28,7 @@ import org.teavm.model.MethodReference; * * @author Alexey Andreev */ -public class LocaleNativeGenerator implements Generator { +public class LocaleNativeGenerator implements Generator, DependencyPlugin { @Override public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException { switch (methodRef.getName()) { @@ -37,11 +40,12 @@ public class LocaleNativeGenerator implements Generator { 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(); + .append(context.getParameterName(1)).append(")];").softNewLine(); + writer.append("result = result ? result.languages[$rt_ustr(") + .append(context.getParameterName(2)).append(")] : undefined;").softNewLine(); writer.append("return result ? $rt_str(result) : null;").softNewLine(); break; - case "getAvailableLocales": + case "getAvailableLocaleStrings": generateAvailableLocales(writer); break; } @@ -52,6 +56,23 @@ public class LocaleNativeGenerator implements Generator { 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];"); + writer.append("array.data[i] = $rt_str(locales[i]);").softNewLine(); + writer.outdent().append("}").softNewLine(); + writer.append("return array;").softNewLine(); + } + + @Override + public void methodAchieved(DependencyChecker checker, MethodDependency method) { + switch (method.getMethod().getName()) { + case "getDefaultLocale": + case "getDisplayCountry": + case "getDisplayLanguage": + method.getResult().propagate("java.lang.String"); + break; + case "getAvailableLocaleStrings": + method.getResult().propagate("[java.lang.String"); + method.getResult().getArrayItem().propagate("java.lang.String"); + break; + } } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/LocaleSettingsNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/LocaleSettingsNativeGenerator.java index d0a75cd14..a8b74194a 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/LocaleSettingsNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/LocaleSettingsNativeGenerator.java @@ -39,12 +39,19 @@ public class LocaleSettingsNativeGenerator implements Generator { private Set availableLocales = new LinkedHashSet<>(); private Set availableLanguages = new LinkedHashSet<>(); private Set availableCountries = new LinkedHashSet<>(); + private boolean initialized; public LocaleSettingsNativeGenerator(ClassLoader classLoader, Properties properties) { this.classLoader = classLoader; this.properties = properties; - findAvailableLocales(); - readCLDR(); + } + + private synchronized void init() { + if (!initialized) { + initialized = true; + findAvailableLocales(); + readCLDR(); + } } private void findAvailableLocales() { @@ -67,7 +74,7 @@ public class LocaleSettingsNativeGenerator implements Generator { private void readCLDR() { try (ZipInputStream input = new ZipInputStream(classLoader.getResourceAsStream( - "/org/teavm/classlib/impl/unicode/cldr-json.zip"))) { + "org/teavm/classlib/impl/unicode/cldr-json.zip"))) { while (true) { ZipEntry entry = input.getNextEntry(); if (entry == null) { @@ -82,6 +89,9 @@ public class LocaleSettingsNativeGenerator implements Generator { if (localeName.startsWith("/")) { localeName = localeName.substring(1); } + if (!availableLocales.contains(localeName)) { + continue; + } LocaleInfo localeInfo = knownLocales.get(localeName); if (localeInfo == null) { localeInfo = new LocaleInfo(); @@ -127,6 +137,7 @@ public class LocaleSettingsNativeGenerator implements Generator { @Override public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException { + init(); switch (methodRef.getName()) { case "readCLDR": generateReadCLDR(writer); @@ -138,7 +149,43 @@ public class LocaleSettingsNativeGenerator implements Generator { } private void generateReadCLDR(SourceWriter writer) throws IOException { - writer.appendClass("java.util.Locale").append(".$CLDR = {"); + writer.appendClass("java.util.Locale").append(".$CLDR = {").indent().softNewLine(); + boolean firstLocale = true; + for (Map.Entry entry : knownLocales.entrySet()) { + if (!firstLocale) { + writer.append(",").softNewLine(); + } + firstLocale = false; + 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 langEntry : entry.getValue().languages.entrySet()) { + if (!first) { + writer.append(',').softNewLine(); + } + first = false; + writer.append('"').append(Renderer.escapeString(langEntry.getKey())).append('"').ws().append(':') + .ws().append('"').append(Renderer.escapeString(langEntry.getValue())).append('"'); + } + writer.outdent().append("},").softNewLine(); + + writer.append("\"territories\"").ws().append(':').ws().append('{').indent().softNewLine(); + first = true; + for (Map.Entry langEntry : entry.getValue().territories.entrySet()) { + if (!first) { + writer.append(',').softNewLine(); + } + first = false; + 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 generateGetDefaultLocale(SourceWriter writer) throws IOException { 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 index 1607f7ab0..18625a98d 100644 --- 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 @@ -35,6 +35,7 @@ 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.dependency.PluggableDependency; import org.teavm.javascript.ni.GeneratedBy; public final class TLocale implements TCloneable, TSerializable { @@ -75,6 +76,7 @@ public final class TLocale implements TCloneable, TSerializable { private transient String variantCode; // Redefined by JCLPlugin + @PluggableDependency(LocaleNativeGenerator.class) private static native String getDefaultLocale(); // Redefined by JCLPlugin @@ -127,12 +129,24 @@ public final class TLocale implements TCloneable, TSerializable { public static TLocale[] getAvailableLocales() { if (availableLocales == null) { - availableLocales = getAvailableLocales(); + String[] strings = getAvailableLocaleStrings(); + availableLocales = new TLocale[strings.length]; + for (int i = 0; i < strings.length; ++i) { + String string = strings[i]; + int countryIndex = string.indexOf('-'); + if (countryIndex > 0) { + availableLocales[i] = new TLocale(string.substring(0, countryIndex), + string.substring(countryIndex)); + } else { + availableLocales[i] = new TLocale(string); + } + } } return Arrays.copyOf(availableLocales, availableLocales.length); } @GeneratedBy(LocaleNativeGenerator.class) + @PluggableDependency(LocaleNativeGenerator.class) private static native String[] getAvailableLocaleStrings(); public String getCountry() { @@ -156,6 +170,7 @@ public final class TLocale implements TCloneable, TSerializable { } @GeneratedBy(LocaleNativeGenerator.class) + @PluggableDependency(LocaleNativeGenerator.class) private static native String getDisplayCountry(String localeName, String country); public final String getDisplayLanguage() { @@ -163,14 +178,15 @@ public final class TLocale implements TCloneable, TSerializable { } public String getDisplayLanguage(TLocale locale) { - String result = getDisplayLanguage(locale.getLanguage() + "_" + locale.getCountry(), countryCode); + String result = getDisplayLanguage(locale.getLanguage() + "-" + locale.getCountry(), languageCode); if (result == null) { - result = getDisplayLanguage(locale.getLanguage(), countryCode); + result = getDisplayLanguage(locale.getLanguage(), languageCode); } - return result != null ? result : countryCode; + return result != null ? result : languageCode; } @GeneratedBy(LocaleNativeGenerator.class) + @PluggableDependency(LocaleNativeGenerator.class) private static native String getDisplayLanguage(String localeName, String country); public final String getDisplayName() { diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/util/LocaleTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/util/LocaleTest.java new file mode 100644 index 000000000..6557f8175 --- /dev/null +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/util/LocaleTest.java @@ -0,0 +1,41 @@ +/* + * 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 static org.junit.Assert.*; +import java.util.Locale; +import org.junit.Test; + +/** + * + * @author Alexey Andreev + */ +public class LocaleTest { + @Test + public void availableLocalesFound() { + assertNotEquals(0, Locale.getAvailableLocales().length); + } + + @Test + public void localeNamesProvided() { + Locale english = new Locale("en", "US"); + Locale russian = new Locale("ru", "RU"); + assertEquals("English", english.getDisplayLanguage(english)); + assertEquals("Russian", russian.getDisplayLanguage(english)); + assertEquals("английский", english.getDisplayLanguage(russian)); + assertEquals("русский", russian.getDisplayLanguage(russian)); + } +} diff --git a/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java b/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java index b0794db1c..1bb62251d 100644 --- a/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java +++ b/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java @@ -100,6 +100,9 @@ public class BuildJavascriptTestMojo extends AbstractMojo { private List additionalScriptLocalPaths = new ArrayList<>(); + @Parameter + private Properties properties; + public void setProject(MavenProject project) { this.project = project; } @@ -140,6 +143,10 @@ public class BuildJavascriptTestMojo extends AbstractMojo { this.transformers = transformers; } + public void setProperties(Properties properties) { + this.properties = properties; + } + @Override public void execute() throws MojoExecutionException, MojoFailureException { if (System.getProperty("maven.test.skip", "false").equals("true") || @@ -330,6 +337,7 @@ public class BuildJavascriptTestMojo extends AbstractMojo { .setClassSource(classSource) .setExecutor(executor) .build(); + vm.setProperties(properties); vm.setMinifying(minifying); vm.installPlugins(); new TestExceptionPlugin().install(vm);