From 47710a81c5aa349b01414bf7f1b9fdcebb4684cf Mon Sep 17 00:00:00 2001 From: Dmitrii Tikhomirov Date: Mon, 20 Jun 2022 10:15:26 -0700 Subject: [PATCH] Support .xtb translation autodiscovery (#172) This is the next commit in adding first-class support for xtb files for closure compilation from Java apps and libraries. If the newly added "auto" flag is set, the closure task will find the first .xtb file that matches the desired locale and use that. Future work will merge discovered xtb files, both across dependencies and locales. Co-authored-by: Colin Alworth --- .../j2cl/build/PropertyTrackingConfig.java | 6 - .../com/vertispan/j2cl/build/task/Config.java | 3 - .../src/it/translationsfile/pom.xml | 2 + .../src/it/translationsfile/tests/pom_cz.xml | 4 +- .../it/translationsfile/tests/pom_cz_auto.xml | 85 +++++++++++++ .../tests/pom_cz_in_resource.xml | 4 +- .../tests/pom_de_in_java_package-auto.xml | 86 +++++++++++++ .../tests/pom_de_in_java_package.xml | 4 +- .../translationsfile/tests/pom_executions.xml | 10 +- .../src/it/translationsfile/tests/pom_fr.xml | 4 +- .../tests/pom_fr_meta_inf.xml | 4 +- .../com/vertispan/j2cl/mojo/BuildMojo.java | 3 +- .../com/vertispan/j2cl/mojo/TestMojo.java | 2 +- .../j2cl/mojo/TranslationsFileConfig.java | 23 ++++ .../j2cl/mojo/Xpp3DomConfigValueProvider.java | 8 +- .../j2cl/build/provided/ClosureTask.java | 16 ++- .../provided/TranslationsFileProcessor.java | 113 ++++++++++++++++++ .../com/vertispan/j2cl/tools/Closure.java | 8 +- 18 files changed, 357 insertions(+), 28 deletions(-) create mode 100644 j2cl-maven-plugin/src/it/translationsfile/tests/pom_cz_auto.xml create mode 100644 j2cl-maven-plugin/src/it/translationsfile/tests/pom_de_in_java_package-auto.xml create mode 100644 j2cl-maven-plugin/src/main/java/com/vertispan/j2cl/mojo/TranslationsFileConfig.java create mode 100644 j2cl-tasks/src/main/java/com/vertispan/j2cl/build/provided/TranslationsFileProcessor.java diff --git a/build-caching/src/main/java/com/vertispan/j2cl/build/PropertyTrackingConfig.java b/build-caching/src/main/java/com/vertispan/j2cl/build/PropertyTrackingConfig.java index 76ada5d0..7f9b061c 100644 --- a/build-caching/src/main/java/com/vertispan/j2cl/build/PropertyTrackingConfig.java +++ b/build-caching/src/main/java/com/vertispan/j2cl/build/PropertyTrackingConfig.java @@ -141,12 +141,6 @@ public Collection getExterns() { return Collections.emptySet(); } - @Override - public Optional getTranslationsFile() { - ConfigValueProvider.ConfigNode node = config.findNode("translationsFile"); - return Optional.ofNullable(node).map(this::useFileConfig); - } - @Override public boolean getCheckAssertions() { return Boolean.parseBoolean(getString("checkAssertions")); diff --git a/build-caching/src/main/java/com/vertispan/j2cl/build/task/Config.java b/build-caching/src/main/java/com/vertispan/j2cl/build/task/Config.java index 4b4eccae..77c1efdb 100644 --- a/build-caching/src/main/java/com/vertispan/j2cl/build/task/Config.java +++ b/build-caching/src/main/java/com/vertispan/j2cl/build/task/Config.java @@ -5,7 +5,6 @@ import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Optional; public interface Config { String getString(String key); @@ -24,8 +23,6 @@ public interface Config { Collection getExterns(); - Optional getTranslationsFile(); - boolean getCheckAssertions(); boolean getRewritePolyfills(); diff --git a/j2cl-maven-plugin/src/it/translationsfile/pom.xml b/j2cl-maven-plugin/src/it/translationsfile/pom.xml index 15d22012..4dc3b62f 100644 --- a/j2cl-maven-plugin/src/it/translationsfile/pom.xml +++ b/j2cl-maven-plugin/src/it/translationsfile/pom.xml @@ -15,6 +15,8 @@ tests/pom_cz_in_resource.xml tests/pom_fr_meta_inf.xml tests/pom_executions.xml + tests/pom_cz_auto.xml + tests/pom_de_in_java_package-auto.xml diff --git a/j2cl-maven-plugin/src/it/translationsfile/tests/pom_cz.xml b/j2cl-maven-plugin/src/it/translationsfile/tests/pom_cz.xml index e3959f71..caf9b67d 100644 --- a/j2cl-maven-plugin/src/it/translationsfile/tests/pom_cz.xml +++ b/j2cl-maven-plugin/src/it/translationsfile/tests/pom_cz.xml @@ -71,7 +71,9 @@ - ${project.basedir}/MyTranslationBundle_cz.xtb + + ${project.basedir}/MyTranslationBundle_cz.xtb + cz Asi se něco stalo! diff --git a/j2cl-maven-plugin/src/it/translationsfile/tests/pom_cz_auto.xml b/j2cl-maven-plugin/src/it/translationsfile/tests/pom_cz_auto.xml new file mode 100644 index 00000000..36dd64c5 --- /dev/null +++ b/j2cl-maven-plugin/src/it/translationsfile/tests/pom_cz_auto.xml @@ -0,0 +1,85 @@ + + + 4.0.0 + + translation.test + cz-auto + jar + 1.0 + + + + com.google.jsinterop + base + 1.0.0 + + + + com.vertispan.j2cl + junit-annotations + @j2cl.version@ + test + + + + com.vertispan.j2cl + junit-emul + @j2cl.version@ + test + + + + com.vertispan.j2cl + junit-emul + @j2cl.version@ + sources + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + 1.8 + 1.8 + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + build + + + + test-js + + test + + + + ADVANCED + + + + + + true + + + cz + Asi se něco stalo! + + + + + + diff --git a/j2cl-maven-plugin/src/it/translationsfile/tests/pom_cz_in_resource.xml b/j2cl-maven-plugin/src/it/translationsfile/tests/pom_cz_in_resource.xml index 2c01e64f..cd66a332 100644 --- a/j2cl-maven-plugin/src/it/translationsfile/tests/pom_cz_in_resource.xml +++ b/j2cl-maven-plugin/src/it/translationsfile/tests/pom_cz_in_resource.xml @@ -71,7 +71,9 @@ - ${project.basedir}/src/main/resources/MyTranslationBundle_cz.xtb + + ${project.basedir}/src/main/resources/MyTranslationBundle_cz.xtb + cz Asi se něco stalo! diff --git a/j2cl-maven-plugin/src/it/translationsfile/tests/pom_de_in_java_package-auto.xml b/j2cl-maven-plugin/src/it/translationsfile/tests/pom_de_in_java_package-auto.xml new file mode 100644 index 00000000..2427f4cf --- /dev/null +++ b/j2cl-maven-plugin/src/it/translationsfile/tests/pom_de_in_java_package-auto.xml @@ -0,0 +1,86 @@ + + + 4.0.0 + + translation.test + de_in_java_package_auto + jar + 1.0 + + + + + com.google.jsinterop + base + 1.0.0 + + + + com.vertispan.j2cl + junit-annotations + @j2cl.version@ + test + + + + com.vertispan.j2cl + junit-emul + @j2cl.version@ + test + + + + com.vertispan.j2cl + junit-emul + @j2cl.version@ + sources + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + 1.8 + 1.8 + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + build + + + + test-js + + test + + + + ADVANCED + + + + + + true + + + de + Ich schätze, es ist etwas passiert! + + + + + + diff --git a/j2cl-maven-plugin/src/it/translationsfile/tests/pom_de_in_java_package.xml b/j2cl-maven-plugin/src/it/translationsfile/tests/pom_de_in_java_package.xml index f1952911..3ab5dcfd 100644 --- a/j2cl-maven-plugin/src/it/translationsfile/tests/pom_de_in_java_package.xml +++ b/j2cl-maven-plugin/src/it/translationsfile/tests/pom_de_in_java_package.xml @@ -72,7 +72,9 @@ - ${project.basedir}/src/main/java/example/test/MyTranslationBundle_de.xtb + + ${project.basedir}/src/main/java/example/test/MyTranslationBundle_de.xtb + de Ich schätze, es ist etwas passiert! diff --git a/j2cl-maven-plugin/src/it/translationsfile/tests/pom_executions.xml b/j2cl-maven-plugin/src/it/translationsfile/tests/pom_executions.xml index e71c0041..9d2d2eb8 100644 --- a/j2cl-maven-plugin/src/it/translationsfile/tests/pom_executions.xml +++ b/j2cl-maven-plugin/src/it/translationsfile/tests/pom_executions.xml @@ -65,7 +65,9 @@ test - ${project.basedir}/MyTranslationBundle_cz.xtb + + ${project.basedir}/MyTranslationBundle_cz.xtb + test-js-cz.js cz @@ -81,7 +83,9 @@ test-js-fr.js - ${project.basedir}/MyTranslationBundle_fr.xtb + + ${project.basedir}/MyTranslationBundle_fr.xtb + cz Je suppose qu'il s'est passé quelque chose ! @@ -96,7 +100,7 @@ test-js-de_in_java_package.js - ${project.basedir}/src/main/java/example/test/MyTranslationBundle_de.xtb + ${project.basedir}/src/main/java/example/test/MyTranslationBundle_de.xtb de Ich schätze, es ist etwas passiert! diff --git a/j2cl-maven-plugin/src/it/translationsfile/tests/pom_fr.xml b/j2cl-maven-plugin/src/it/translationsfile/tests/pom_fr.xml index 7b332a17..f7045ccd 100644 --- a/j2cl-maven-plugin/src/it/translationsfile/tests/pom_fr.xml +++ b/j2cl-maven-plugin/src/it/translationsfile/tests/pom_fr.xml @@ -71,7 +71,9 @@ - ${project.basedir}/MyTranslationBundle_fr.xtb + + ${project.basedir}/MyTranslationBundle_fr.xtb + cz Je suppose qu'il s'est passé quelque chose ! diff --git a/j2cl-maven-plugin/src/it/translationsfile/tests/pom_fr_meta_inf.xml b/j2cl-maven-plugin/src/it/translationsfile/tests/pom_fr_meta_inf.xml index 42a3e467..c1b63f30 100644 --- a/j2cl-maven-plugin/src/it/translationsfile/tests/pom_fr_meta_inf.xml +++ b/j2cl-maven-plugin/src/it/translationsfile/tests/pom_fr_meta_inf.xml @@ -71,7 +71,9 @@ - ${project.basedir}/src/main/resources/META-INF/MyTranslationBundle_fr.xtb + + ${project.basedir}/src/main/resources/META-INF/MyTranslationBundle_fr.xtb + cz Je suppose qu'il s'est passé quelque chose ! diff --git a/j2cl-maven-plugin/src/main/java/com/vertispan/j2cl/mojo/BuildMojo.java b/j2cl-maven-plugin/src/main/java/com/vertispan/j2cl/mojo/BuildMojo.java index ee263ec6..0b019f7d 100644 --- a/j2cl-maven-plugin/src/main/java/com/vertispan/j2cl/mojo/BuildMojo.java +++ b/j2cl-maven-plugin/src/main/java/com/vertispan/j2cl/mojo/BuildMojo.java @@ -13,6 +13,7 @@ import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugin.PluginParameterExpressionEvaluator; import org.apache.maven.plugin.descriptor.PluginDescriptor; +import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; @@ -138,7 +139,7 @@ public class BuildMojo extends AbstractBuildMojo { * Closure flag: "Source of translated messages. Currently only supports XTB." */ @Parameter - protected String translationsFile; + protected TranslationsFileConfig translationsFile; /** * Closure flag: "Determines the set of builtin externs to load. Options: BROWSER, CUSTOM. Defaults to BROWSER." diff --git a/j2cl-maven-plugin/src/main/java/com/vertispan/j2cl/mojo/TestMojo.java b/j2cl-maven-plugin/src/main/java/com/vertispan/j2cl/mojo/TestMojo.java index 957a6800..6d343173 100644 --- a/j2cl-maven-plugin/src/main/java/com/vertispan/j2cl/mojo/TestMojo.java +++ b/j2cl-maven-plugin/src/main/java/com/vertispan/j2cl/mojo/TestMojo.java @@ -248,7 +248,7 @@ public class TestMojo extends AbstractBuildMojo { * Closure flag: "Source of translated messages. Currently only supports XTB." */ @Parameter - protected String translationsFile; + protected TranslationsFileConfig translationsFile; @Override public void execute() throws MojoExecutionException, MojoFailureException { diff --git a/j2cl-maven-plugin/src/main/java/com/vertispan/j2cl/mojo/TranslationsFileConfig.java b/j2cl-maven-plugin/src/main/java/com/vertispan/j2cl/mojo/TranslationsFileConfig.java new file mode 100644 index 00000000..67ab2a10 --- /dev/null +++ b/j2cl-maven-plugin/src/main/java/com/vertispan/j2cl/mojo/TranslationsFileConfig.java @@ -0,0 +1,23 @@ +package com.vertispan.j2cl.mojo; + +public class TranslationsFileConfig { + + private boolean auto; + private String file; + + public boolean isAuto() { + return auto; + } + + public void setAuto(boolean auto) { + this.auto = auto; + } + + public String getFile() { + return file; + } + + public void setFile(String file) { + this.file = file; + } +} diff --git a/j2cl-maven-plugin/src/main/java/com/vertispan/j2cl/mojo/Xpp3DomConfigValueProvider.java b/j2cl-maven-plugin/src/main/java/com/vertispan/j2cl/mojo/Xpp3DomConfigValueProvider.java index 79d7e332..40f52053 100644 --- a/j2cl-maven-plugin/src/main/java/com/vertispan/j2cl/mojo/Xpp3DomConfigValueProvider.java +++ b/j2cl-maven-plugin/src/main/java/com/vertispan/j2cl/mojo/Xpp3DomConfigValueProvider.java @@ -205,7 +205,13 @@ private Xpp3Dom findNodeWithKey(Xpp3Dom config, String prefix, String remaining) if (index == -1) { return null;// failed to find it so far, must not be present } - return findNodeWithKey(config, prefix.substring(0, index), prefix.substring(index + 1) + '.' + remaining); + String nextRemaining; + if (remaining.isEmpty()) { + nextRemaining = prefix.substring(index + 1); + } else { + nextRemaining = prefix.substring(index + 1) + '.' + remaining; + } + return findNodeWithKey(config, prefix.substring(0, index), nextRemaining); } } diff --git a/j2cl-tasks/src/main/java/com/vertispan/j2cl/build/provided/ClosureTask.java b/j2cl-tasks/src/main/java/com/vertispan/j2cl/build/provided/ClosureTask.java index cab0b3b6..9f013611 100644 --- a/j2cl-tasks/src/main/java/com/vertispan/j2cl/build/provided/ClosureTask.java +++ b/j2cl-tasks/src/main/java/com/vertispan/j2cl/build/provided/ClosureTask.java @@ -27,6 +27,8 @@ public class ClosureTask extends TaskFactory { private static final Path PUBLIC = Paths.get("public"); private static final PathMatcher JS_SOURCES = withSuffix(".js"); + + private static final PathMatcher XTB = withSuffix(".xtb"); private static final PathMatcher NATIVE_JS_SOURCES = withSuffix(".native.js"); private static final PathMatcher EXTERNS_SOURCES = withSuffix(".externs.js"); @@ -176,7 +178,17 @@ public Task resolve(Project project, Config config) { CompilerOptions.LanguageMode languageOut = CompilerOptions.LanguageMode.fromString(config.getLanguageOut()); //TODO probably kill this, or at least make it work like an import via another task so we detect changes Collection externs = config.getExterns(); - Optional translationsfile = config.getTranslationsFile(); + + TranslationsFileProcessor translationsFileProcessor = TranslationsFileProcessor.get(config); + List xtbInputs = Stream.concat( + Stream.of(project), + scope(project.getDependencies(), Dependency.Scope.RUNTIME).stream() + ) + .map(p -> input(p, OutputTypes.BYTECODE)) + // Only include the .xtb + .map(i -> i.filter(XTB)) + .collect(Collectors.toList()); + boolean checkAssertions = config.getCheckAssertions(); boolean rewritePolyfills = config.getRewritePolyfills(); boolean sourcemapsEnabled = config.getSourcemapsEnabled(); @@ -240,7 +252,7 @@ public void execute(TaskContext context) throws Exception { entrypoint, defines, externs, - translationsfile, + translationsFileProcessor.getTranslationsFile(xtbInputs, context.log()), true,//TODO have this be passed in, checkAssertions, rewritePolyfills, diff --git a/j2cl-tasks/src/main/java/com/vertispan/j2cl/build/provided/TranslationsFileProcessor.java b/j2cl-tasks/src/main/java/com/vertispan/j2cl/build/provided/TranslationsFileProcessor.java new file mode 100644 index 00000000..f9a09271 --- /dev/null +++ b/j2cl-tasks/src/main/java/com/vertispan/j2cl/build/provided/TranslationsFileProcessor.java @@ -0,0 +1,113 @@ +package com.vertispan.j2cl.build.provided; + +import com.vertispan.j2cl.build.task.BuildLog; +import com.vertispan.j2cl.build.task.CachedPath; +import com.vertispan.j2cl.build.task.Config; +import com.vertispan.j2cl.build.task.Input; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public interface TranslationsFileProcessor { + public static TranslationsFileProcessor get(Config config) { + File file = config.getFile("translationsFile.file"); + boolean auto = Boolean.parseBoolean(config.getString("translationsFile.auto")); + + if ((auto || file != null) && !config.getCompilationLevel().equals("ADVANCED")) { + return new TranslationsFileNotDefined(true); + } + if (file != null) { + return (inputs, log) -> Optional.of(file); + } else if (auto) { + return new ProjectLookup(config); + } + return new TranslationsFileNotDefined(false); + } + + Optional getTranslationsFile(List inputs, BuildLog log); + + class TranslationsFileNotDefined implements TranslationsFileProcessor { + private final boolean shouldWarn; + + public TranslationsFileNotDefined(boolean shouldWarn) { + this.shouldWarn = shouldWarn; + } + + @Override + public Optional getTranslationsFile(List inputs, BuildLog log) { + if (shouldWarn) { + log.warn("translationsFile only works in the ADVANCED optimization level, in other levels the default messages values will be used"); + } + + return Optional.empty(); + } + } + + class ProjectLookup implements TranslationsFileProcessor { + private final String locale; + + public ProjectLookup(Config config) { + locale = config.getString("defines.goog.LOCALE"); + } + + @Override + public Optional getTranslationsFile(List inputs, BuildLog log) { + List temp = inputs.stream() + .map(Input::getFilesAndHashes) + .flatMap(Collection::stream) + .map(CachedPath::getAbsolutePath) + .map(Path::toFile) + .collect(Collectors.toList()); + + if (temp.isEmpty()) { + log.warn("no .xtb files was found"); + } + + try { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + + dbf.setNamespaceAware(false); + dbf.setValidating(false); + dbf.setFeature("http://xml.org/sax/features/namespaces", false); + dbf.setFeature("http://xml.org/sax/features/validation", false); + dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false); + dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + + DocumentBuilder db = dbf.newDocumentBuilder(); + + for (File xtb : temp) { + Document doc = db.parse(xtb); + doc.getDocumentElement().normalize(); + NodeList translationbundleNode = doc.getElementsByTagName("translationbundle"); + + if (translationbundleNode.getLength() == 0) { + throw new RuntimeException(String.format("%s file has no translationbundle declaration", xtb)); + } + + String lang = translationbundleNode.item(0).getAttributes().getNamedItem("lang").getNodeValue(); + + if (locale.equals(lang)) { + return Optional.of(xtb); + } + } + } catch (ParserConfigurationException | SAXException | IOException e) { + log.error("Error while reading xtb files ", e); + throw new RuntimeException(e); + } + log.warn("No matching locales for " + locale); + return Optional.empty(); + } + + } +} diff --git a/j2cl-tasks/src/main/java/com/vertispan/j2cl/tools/Closure.java b/j2cl-tasks/src/main/java/com/vertispan/j2cl/tools/Closure.java index 4529a6f3..c001ba8a 100644 --- a/j2cl-tasks/src/main/java/com/vertispan/j2cl/tools/Closure.java +++ b/j2cl-tasks/src/main/java/com/vertispan/j2cl/tools/Closure.java @@ -107,12 +107,8 @@ public boolean compile( } translationsFile.ifPresent(file -> { - if(compilationLevel.equals(CompilationLevel.ADVANCED_OPTIMIZATIONS)) { - jscompArgs.add("--translations_file"); - jscompArgs.add(file.getAbsolutePath()); - } else { - log.warn("translationsFile only works in the ADVANCED optimization level, in other levels the default messages values will be used"); - } + jscompArgs.add("--translations_file"); + jscompArgs.add(file.getAbsolutePath()); }); jscompArgs.add("--compilation_level");