[i18n] branch develop updated (40f58c1 -> 0ed5ca8)
This is an automated email from the git hooks/post-receive script. New change to branch develop in repository i18n. See http://git.nuiton.org/i18n.git from 40f58c1 refs #3350: Review site new 29266eb refs #3356 add new csv package with the 3 new mojos + deprecates csv generation in bundle mojo new c620165 refs #3356 improve merge mojo + add mini doc new 4c6a79c refs #3356 : add the generated csv file in the classpath new f44c18d fixes #3357: Remove deprecated Tapestry mojo new 772ea4f refs #3356 : improve the way of storing the generated csv file + fix doc new aa99cc4 fixes #3358: Sanity mojo parameters new 0ed5ca8 Merge branch 'feature/3356' into develop The 7 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference. Detailed log of new commits: commit 0ed5ca8ae4141433a6c35ca8c8d495fb534891f1 Merge: 40f58c1 aa99cc4 Author: Tony CHEMIT <chemit@codelutin.com> Date: Sun Jul 27 13:07:03 2014 +0200 Merge branch 'feature/3356' into develop commit aa99cc4eaa80f6b993f7ce9b808f678a6ea325aa Author: Tony CHEMIT <chemit@codelutin.com> Date: Sun Jul 27 13:05:35 2014 +0200 fixes #3358: Sanity mojo parameters commit 772ea4ffb86e9816c9a26bd5fa7d16f8ea41ef57 Author: Tony CHEMIT <chemit@codelutin.com> Date: Sun Jul 27 13:05:11 2014 +0200 refs #3356 : improve the way of storing the generated csv file + fix doc commit f44c18d1d2d727adb4f8154fbc4ae480418a2efe Author: Tony CHEMIT <chemit@codelutin.com> Date: Sun Jul 27 13:04:02 2014 +0200 fixes #3357: Remove deprecated Tapestry mojo commit 4c6a79c97731e0a8fab3de633597d45d8d7c921b Author: Tony CHEMIT <chemit@codelutin.com> Date: Sat Jul 26 19:34:54 2014 +0200 refs #3356 : add the generated csv file in the classpath commit c620165255300efd898a95f09bb8c4f4e393e5d3 Author: Tony CHEMIT <chemit@codelutin.com> Date: Sat Jul 26 17:36:25 2014 +0200 refs #3356 improve merge mojo + add mini doc commit 29266eb190010eaa383505dd2b6afc9d0e5fd59e Author: Tony CHEMIT <chemit@codelutin.com> Date: Sat Jul 26 16:54:09 2014 +0200 refs #3356 add new csv package with the 3 new mojos + deprecates csv generation in bundle mojo Summary of changes: i18n-maven-plugin/pom.xml | 5 + .../i18n/plugin/AbstractI18nGenerateMojo.java | 66 +++++ .../org/nuiton/i18n/plugin/AbstractI18nMojo.java | 111 +------- .../java/org/nuiton/i18n/plugin/GenerateMojo.java | 35 ++- .../java/org/nuiton/i18n/plugin/GetterMojo.java | 14 +- .../main/java/org/nuiton/i18n/plugin/I18nUtil.java | 41 +++ .../i18n/plugin/bundle/AbstractI18nBundleMojo.java | 5 +- .../plugin/bundle/AbstractMakeI18nBundleMojo.java | 284 --------------------- .../org/nuiton/i18n/plugin/bundle/BundleMojo.java | 245 +++++++++++++++++- .../plugin/bundle/CollectI18nArtifactsMojo.java | 4 + .../i18n/plugin/bundle/TapestryBundleMojo.java | 190 -------------- .../plugin/bundle/csv/AbstractCsvBundleMojo.java | 22 ++ .../plugin/bundle/csv/GenerateCsvBundleMojo.java | 255 ++++++++++++++++++ .../i18n/plugin/bundle/csv/I18nBundleModel.java | 44 ++++ .../i18n/plugin/bundle/csv/I18nBundleModelRow.java | 35 +++ .../plugin/bundle/csv/MergeBackCsvBundleMojo.java | 125 +++++++++ .../i18n/plugin/bundle/csv/SplitCsvBundleMojo.java | 124 +++++++++ .../i18n/plugin/parser/AbstractI18nParserMojo.java | 34 ++- i18n-maven-plugin/src/site/apt/index.apt | 6 + i18n-maven-plugin/src/site/apt/usages.apt | 30 +++ pom.xml | 6 + 21 files changed, 1070 insertions(+), 611 deletions(-) create mode 100644 i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/AbstractI18nGenerateMojo.java create mode 100644 i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/I18nUtil.java delete mode 100644 i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/AbstractMakeI18nBundleMojo.java delete mode 100644 i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/TapestryBundleMojo.java create mode 100644 i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/AbstractCsvBundleMojo.java create mode 100644 i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/GenerateCsvBundleMojo.java create mode 100644 i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/I18nBundleModel.java create mode 100644 i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/I18nBundleModelRow.java create mode 100644 i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/MergeBackCsvBundleMojo.java create mode 100644 i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/SplitCsvBundleMojo.java -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository i18n. See http://git.nuiton.org/i18n.git commit 29266eb190010eaa383505dd2b6afc9d0e5fd59e Author: Tony CHEMIT <chemit@codelutin.com> Date: Sat Jul 26 16:54:09 2014 +0200 refs #3356 add new csv package with the 3 new mojos + deprecates csv generation in bundle mojo --- i18n-maven-plugin/pom.xml | 5 + .../org/nuiton/i18n/plugin/bundle/BundleMojo.java | 12 ++ .../plugin/bundle/csv/AbstractCsvBundleMojo.java | 33 ++++ .../plugin/bundle/csv/GenerateCsvBundleMojo.java | 211 +++++++++++++++++++++ .../i18n/plugin/bundle/csv/I18nBundleModel.java | 44 +++++ .../i18n/plugin/bundle/csv/I18nBundleModelRow.java | 35 ++++ .../plugin/bundle/csv/MergeBackCsvBundleMojo.java | 84 ++++++++ .../i18n/plugin/bundle/csv/SplitCsvBundleMojo.java | 113 +++++++++++ pom.xml | 6 + 9 files changed, 543 insertions(+) diff --git a/i18n-maven-plugin/pom.xml b/i18n-maven-plugin/pom.xml index 5458e59..ca94a48 100644 --- a/i18n-maven-plugin/pom.xml +++ b/i18n-maven-plugin/pom.xml @@ -52,6 +52,11 @@ </dependency> <dependency> + <groupId>org.nuiton</groupId> + <artifactId>nuiton-csv</artifactId> + </dependency> + + <dependency> <groupId>org.antlr</groupId> <artifactId>antlr4-runtime</artifactId> </dependency> diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/BundleMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/BundleMojo.java index 72268c8..78f9097 100644 --- a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/BundleMojo.java +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/BundleMojo.java @@ -100,8 +100,10 @@ public class BundleMojo extends AbstractMakeI18nBundleMojo { * Useful to translate from a language to another one. * * @since 2.5 + * @deprecated since 3.3, prefer use the new mojo generate-csv-bundle instead */ @Parameter(property = "i18n.generateCsvFile", defaultValue = "false") + @Deprecated protected boolean generateCsvFile; /** @@ -109,9 +111,11 @@ public class BundleMojo extends AbstractMakeI18nBundleMojo { * {@link #generateCsvFile} is on. * * @since 2.5 + * @deprecated since 3.3, prefer use the new mojo generate-csv-bundle instead */ @Parameter(property = "i18n.bundleCsvFile", defaultValue = "${basedir}/target/${project.artifactId}-i18n.csv") + @Deprecated protected File bundleCsvFile; /** @@ -119,8 +123,10 @@ public class BundleMojo extends AbstractMakeI18nBundleMojo { * {@link #generateCsvFile} is on. * * @since 2.5 + * @deprecated since 3.3, prefer use the new mojo generate-csv-bundle instead */ @Parameter(property = "i18n.bundleCsvSeparator", defaultValue = "\t") + @Deprecated protected String bundleCsvSeparator; /** @@ -151,6 +157,12 @@ public class BundleMojo extends AbstractMakeI18nBundleMojo { addResourceDir(bundleOutputDir, "**/*.properties"); if (generateCsvFile) { + getLog().warn(""); + getLog().warn("--------------------------------------------------------------------------------------------"); + getLog().warn("Please use now the i18n:generate-csv-bundle mojo."); + getLog().warn("The csv bundle generation will be removed from this mojo soon."); + getLog().warn("--------------------------------------------------------------------------------------------"); + getLog().warn(""); addResourceDir(bundleOutputDir, "**/*.csv"); } diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/AbstractCsvBundleMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/AbstractCsvBundleMojo.java new file mode 100644 index 0000000..e9786fd --- /dev/null +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/AbstractCsvBundleMojo.java @@ -0,0 +1,33 @@ +package org.nuiton.i18n.plugin.bundle.csv; + +import org.apache.maven.plugins.annotations.Parameter; +import org.nuiton.i18n.plugin.AbstractI18nMojo; + +import java.io.File; + +/** + * Created on 7/26/14. + * + * @author Tony Chemit - chemit@codelutin.com + * @since 3.3 + */ +public abstract class AbstractCsvBundleMojo extends AbstractI18nMojo { + + /** + * Location of the csv file to split. + * + * @since 3.3 + */ + @Parameter(property = "i18n.bundleCsvFile", + defaultValue = "${basedir}/target/${project.artifactId}-i18n.csv") + protected File bundleCsvFile; + + /** + * Char separator in the csv bundle file. + * + * @since 3.3 + */ + @Parameter(property = "i18n.bundleCsvSeparator", defaultValue = "\t") + protected char bundleCsvSeparator; + +} diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/GenerateCsvBundleMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/GenerateCsvBundleMojo.java new file mode 100644 index 0000000..e7fc82d --- /dev/null +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/GenerateCsvBundleMojo.java @@ -0,0 +1,211 @@ +package org.nuiton.i18n.plugin.bundle.csv; + +import org.apache.commons.lang3.StringUtils; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.nuiton.csv.Export; +import org.nuiton.io.SortedProperties; + +import java.io.File; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TreeMap; + +/** + * To generate a csv file from the full bundle of the module. + * + * The csv file will have a first column with i18n keys, and a + * column for each locale defined in {@link #locales}. + * + * Created on 7/26/14. + * + * @author Tony Chemit - chemit@codelutin.com + * @since 3.3 + */ +@Mojo(name = "generate-csv-bundle", + defaultPhase = LifecyclePhase.GENERATE_RESOURCES, + requiresProject = true, + requiresDependencyResolution = ResolutionScope.RUNTIME) +public class GenerateCsvBundleMojo extends AbstractCsvBundleMojo { + + /** + * Name of the bundle to generate. + * + * @since 1.0.2 + */ + @Parameter(property = "i18n.bundleOutputName", defaultValue = "${project.artifactId}-i18n", required = true) + protected String bundleOutputName; + + /** + * Encoding used to load any i18n property files. + * <p/> + * If not defined, will use the {@link #encoding} parameter. + * + * @since 2.4 + */ + @Parameter(property = "i18n.bundleInputEncoding") + protected String bundleInputEncoding; + + /** + * Encoding used to write any i18n property files. + * <p/> + * If not defined, will use the {@link #encoding} parameter. + * + * @since 2.4 + */ + @Parameter(property = "i18n.bundleOutputEncoding") + protected String bundleOutputEncoding; + + /** + * Root directory where to generate aggregated bundles (this directory will + * be added as resources of the project). + * + * @since 1.0.0 + */ + @Parameter(property = "i18n.bundleOutputDir", defaultValue = "${basedir}/target/generated-sources/resources", required = true) + protected File bundleOutputDir; + + /** + * Package name of the generate aggregated bundles. + * <p/> + * <strong>Note:</strong> By default we use the <code>META-INF</code> package + * since it is the favorite package of <code>I18n</code> runtime initializer. + * <p/> + * The package name is dotted as it will be stored as folder like in Java + * language. + * <p/> + * Example : + * <pre> + * package name : foo.bar + * directory : foo/bar + * </pre> + * + * @since 2.3.2 + */ + @Parameter(property = "i18n.bundleOutputPackage", defaultValue = "META-INF", required = true) + protected String bundleOutputPackage; + + /** + * The definitive directory where to generate the bundles (includes the + * package of bundle). + * + * @since 2.3.2 + */ + protected File outputFolder; + + @Override + public void init() throws Exception { + super.init(); + + // get the definitive folder where to generate bundles (including + // bundle package) + + outputFolder = getBundleOutputFolder(); + + if (isVerbose()) { + getLog().info("Will generates bundles in " + outputFolder); + } + createDirectoryIfNecessary(outputFolder); + + if (StringUtils.isEmpty(bundleInputEncoding)) { + + // use the default encoding + bundleInputEncoding = getEncoding(); + if (getLog().isDebugEnabled()) { + getLog().debug("Use as input encoding the default one : " + + bundleInputEncoding); + } + } + + if (StringUtils.isEmpty(bundleOutputEncoding)) { + + // use the default encoding + bundleOutputEncoding = getEncoding(); + + if (getLog().isDebugEnabled()) { + getLog().debug("Use as output encoding the default one : " + + bundleOutputEncoding); + } + } + } + + @Override + protected void doAction() throws Exception { + + if (!silent) { + getLog().info("config - locales : " + Arrays.toString(locales)); + getLog().info("config - bundle dir : " + outputFolder); + getLog().info("config - bundle name : " + bundleOutputName); + getLog().info("config - csv separator : " + bundleCsvSeparator); + getLog().info("config - csv file : " + bundleCsvFile); + getLog().info("config - input encoding : " + bundleInputEncoding); + getLog().info("config - output encoding : " + bundleOutputEncoding); + } + + // fill rows to export + + Map<String, I18nBundleModelRow> rowsByKey = new TreeMap<String, I18nBundleModelRow>(); + + for (Locale locale : locales) { + + File bundleFile = getI18nFile(outputFolder, + bundleOutputName, + locale, + false + ); + + SortedProperties properties = new SortedProperties(bundleOutputEncoding); + properties.load(bundleFile); + + for (Object o : properties.keySet()) { + String key = (String) o; + I18nBundleModelRow row = rowsByKey.get(key); + if (row == null) { + row = new I18nBundleModelRow(); + row.setKey(key); + rowsByKey.put(key, row); + } + row.setLocaleValue(locale, (String) properties.get(o)); + } + } + + List<I18nBundleModelRow> rows = new LinkedList<I18nBundleModelRow>(rowsByKey.values()); + if (!isSilent()) { + + getLog().info(String.format("Found %d translations.", rows.size())); + } + + // do the export + + if (!bundleCsvFile.exists()) { + createNewFile(bundleCsvFile); + } + + if (!isSilent()) { + getLog().info("Generate csv bundle file at " + bundleCsvFile); + } + + I18nBundleModel exportModel = new I18nBundleModel(bundleCsvSeparator, locales); + + Export.exportToFile(exportModel, rows, bundleCsvFile, Charset.forName(encoding)); + + } + + + protected File getBundleOutputFolder() { + File result = bundleOutputDir; + if (StringUtils.isNotEmpty(bundleOutputPackage)) { + String[] paths = bundleOutputPackage.split("\\."); + for (String path : paths) { + result = new File(result, path); + } + } + return result; + } +} diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/I18nBundleModel.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/I18nBundleModel.java new file mode 100644 index 0000000..020a65b --- /dev/null +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/I18nBundleModel.java @@ -0,0 +1,44 @@ +package org.nuiton.i18n.plugin.bundle.csv; + +import org.nuiton.csv.ValueGetterSetter; +import org.nuiton.csv.ext.AbstractImportExportModel; + +import java.util.Locale; + +/** + * Created on 7/26/14. + * + * @author Tony Chemit - chemit@codelutin.com + * @since 3.3 + */ +public class I18nBundleModel extends AbstractImportExportModel<I18nBundleModelRow> { + + public I18nBundleModel(char separator, Locale[] locales) { + super(separator); + + newMandatoryColumn("key"); + newColumnForExport("key"); + + for (final Locale locale : locales) { + + ValueGetterSetter<I18nBundleModelRow, String> getterSetter = new ValueGetterSetter<I18nBundleModelRow, String>() { + @Override + public String get(I18nBundleModelRow row) throws Exception { + return row.getLocaleValue(locale); + } + + @Override + public void set(I18nBundleModelRow row, String s) throws Exception { + row.setLocaleValue(locale, s); + } + }; + newColumnForExport(locale.getCountry(), getterSetter); + newMandatoryColumn(locale.getCountry(), getterSetter); + } + } + + @Override + public I18nBundleModelRow newEmptyInstance() { + return new I18nBundleModelRow(); + } +} diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/I18nBundleModelRow.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/I18nBundleModelRow.java new file mode 100644 index 0000000..0c78852 --- /dev/null +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/I18nBundleModelRow.java @@ -0,0 +1,35 @@ +package org.nuiton.i18n.plugin.bundle.csv; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +/** +* Created on 7/26/14. +* +* @author Tony Chemit - chemit@codelutin.com +* @since 3.3 +*/ +public class I18nBundleModelRow { + + String key; + + Map<Locale, String> localeValue = new HashMap<Locale, String>(); + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public void setLocaleValue(Locale locale, String s) { + localeValue.put(locale, s); + } + + public String getLocaleValue(Locale locale) { + return localeValue.get(locale); + } + +} diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/MergeBackCsvBundleMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/MergeBackCsvBundleMojo.java new file mode 100644 index 0000000..3272a02 --- /dev/null +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/MergeBackCsvBundleMojo.java @@ -0,0 +1,84 @@ +package org.nuiton.i18n.plugin.bundle.csv; + +import com.google.common.collect.Lists; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.nuiton.csv.Import; +import org.nuiton.io.SortedProperties; + +import java.io.File; +import java.io.FileInputStream; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.Locale; + +/** + * To merge back from a csv bundle to a module i18n bundle files. + * <p/> + * Created on 7/26/14. + * + * @author Tony Chemit - chemit@codelutin.com + * @since 3.3 + */ +@Mojo(name = "merge-back-csv-bundle", + defaultPhase = LifecyclePhase.GENERATE_RESOURCES, + requiresProject = true, + requiresDependencyResolution = ResolutionScope.RUNTIME) +public class MergeBackCsvBundleMojo extends AbstractCsvBundleMojo { + + @Override + protected void doAction() throws Exception { + + if (!silent) { + getLog().info("config - locales : " + Arrays.toString(locales)); + getLog().info("config - csv separator : " + bundleCsvSeparator); + getLog().info("config - csv file : " + bundleCsvFile); + getLog().info("config - merge directory : " + src); + + } + + LinkedList<I18nBundleModelRow> rows; + + I18nBundleModel importModel = new I18nBundleModel(bundleCsvSeparator, locales); + FileInputStream inputStream = FileUtils.openInputStream(bundleCsvFile); + Import<I18nBundleModelRow> newImport; + try { + newImport = Import.newImport(importModel, inputStream); + + rows = Lists.newLinkedList(newImport); + inputStream.close(); + newImport.close(); + } finally { + IOUtils.closeQuietly(inputStream); + } + + for (Locale locale : locales) { + + File bundleFile = getI18nFile(src, + artifactId, + locale, + false); + + SortedProperties properties = new SortedProperties(encoding); + + // load old values + properties.load(bundleFile, encoding); + + // push back values from csv file + for (I18nBundleModelRow row : rows) { + properties.put(row.getKey(), row.getLocaleValue(locale)); + } + + if (!isSilent()) { + getLog().info(String.format("Merge locale bundle %s in %s", locale, bundleFile)); + } + properties.store(bundleFile); + + } + + } + +} diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/SplitCsvBundleMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/SplitCsvBundleMojo.java new file mode 100644 index 0000000..dfcc5c0 --- /dev/null +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/SplitCsvBundleMojo.java @@ -0,0 +1,113 @@ +package org.nuiton.i18n.plugin.bundle.csv; + +import com.google.common.collect.Lists; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.nuiton.csv.Import; +import org.nuiton.io.SortedProperties; + +import java.io.File; +import java.io.FileInputStream; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.Locale; + +/** + * To split a previously csv i18n file into simple i18n bundles for the locales defined in {@link #locales}. + * <p/> + * The order of {@link #locales} will be used to extract for each locale i18n bundle (means the order defined + * in the csv file is not used). Make sure to use exactly the same order. + * <p/> + * Created on 7/26/14. + * + * @author Tony Chemit - chemit@codelutin.com + * @since 3.3 + */ +@Mojo(name = "split-csv-bundle", + defaultPhase = LifecyclePhase.GENERATE_RESOURCES, + requiresProject = true, + requiresDependencyResolution = ResolutionScope.RUNTIME) +public class SplitCsvBundleMojo extends AbstractCsvBundleMojo { + + /** + * Name of the bundle to generate. + * + * @since 1.0.2 + */ + @Parameter(property = "i18n.bundleOutputName", defaultValue = "${project.artifactId}-i18n", required = true) + protected String bundleOutputName; + + /** + * Root directory where to generate aggregated bundles (this directory will + * be added as resources of the project). + * + * @since 1.0.0 + */ + @Parameter(property = "i18n.bundleOutputDir", defaultValue = "${project.build.directory}", required = true) + protected File bundleOutputDir; + + @Override + protected void doAction() throws Exception { + + if (!silent) { + getLog().info("config - locales : " + Arrays.toString(locales)); + getLog().info("config - bundle directory : " + bundleOutputDir); + getLog().info("config - bundle name : " + bundleOutputName); + getLog().info("config - csv separator : " + bundleCsvSeparator); + getLog().info("config - csv file : " + bundleCsvFile); + + } + + LinkedList<I18nBundleModelRow> rows; + + I18nBundleModel importModel = new I18nBundleModel(bundleCsvSeparator, locales); + FileInputStream inputStream = FileUtils.openInputStream(bundleCsvFile); + Import<I18nBundleModelRow> newImport; + try { + newImport = Import.newImport(importModel, inputStream); + + rows = Lists.newLinkedList(newImport); + inputStream.close(); + newImport.close(); + } finally { + IOUtils.closeQuietly(inputStream); + } + + for (Locale locale : locales) { + + File bundleFile = getI18nFile(bundleOutputDir, + artifactId, + locale, + false); + + SortedProperties properties = new SortedProperties(encoding); + + for (I18nBundleModelRow row : rows) { + properties.put(row.getKey(), row.getLocaleValue(locale)); + } + + if (!isSilent()) { + getLog().info(String.format("Extract locale bundle %s to %s", locale, bundleFile)); + } + properties.store(bundleFile); + + } + + } + + @Override + public void init() throws Exception { + super.init(); + + if (isVerbose()) { + getLog().info("Will split bundles in " + bundleOutputDir); + } + createDirectoryIfNecessary(bundleOutputDir); + + } + +} diff --git a/pom.xml b/pom.xml index 74f4392..10390eb 100644 --- a/pom.xml +++ b/pom.xml @@ -122,6 +122,12 @@ </dependency> <dependency> + <groupId>org.nuiton</groupId> + <artifactId>nuiton-csv</artifactId> + <version>3.0-rc-1</version> + </dependency> + + <dependency> <groupId>org.antlr</groupId> <artifactId>antlr4-runtime</artifactId> <version>${antlrVersion}</version> -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository i18n. See http://git.nuiton.org/i18n.git commit c620165255300efd898a95f09bb8c4f4e393e5d3 Author: Tony CHEMIT <chemit@codelutin.com> Date: Sat Jul 26 17:36:25 2014 +0200 refs #3356 improve merge mojo + add mini doc --- .../plugin/bundle/csv/MergeBackCsvBundleMojo.java | 26 ++++++++++++++++++- i18n-maven-plugin/src/site/apt/index.apt | 6 +++++ i18n-maven-plugin/src/site/apt/usages.apt | 30 ++++++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/MergeBackCsvBundleMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/MergeBackCsvBundleMojo.java index 3272a02..40b5a5f 100644 --- a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/MergeBackCsvBundleMojo.java +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/MergeBackCsvBundleMojo.java @@ -5,6 +5,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.nuiton.csv.Import; import org.nuiton.io.SortedProperties; @@ -29,6 +30,16 @@ import java.util.Locale; requiresDependencyResolution = ResolutionScope.RUNTIME) public class MergeBackCsvBundleMojo extends AbstractCsvBundleMojo { + /** + * To accept to add new keys in the original i18n bundle. + * <p/> + * The option is {@code false} by default, since merging operation should not add any new keys. + * + * @since 3.3 + */ + @Parameter(property = "i18n.mergeNewKeys", defaultValue = "false") + protected boolean mergeNewKeys; + @Override protected void doAction() throws Exception { @@ -40,6 +51,8 @@ public class MergeBackCsvBundleMojo extends AbstractCsvBundleMojo { } + // load i18n csv file + LinkedList<I18nBundleModelRow> rows; I18nBundleModel importModel = new I18nBundleModel(bundleCsvSeparator, locales); @@ -55,6 +68,8 @@ public class MergeBackCsvBundleMojo extends AbstractCsvBundleMojo { IOUtils.closeQuietly(inputStream); } + // start the merge + for (Locale locale : locales) { File bundleFile = getI18nFile(src, @@ -69,12 +84,21 @@ public class MergeBackCsvBundleMojo extends AbstractCsvBundleMojo { // push back values from csv file for (I18nBundleModelRow row : rows) { - properties.put(row.getKey(), row.getLocaleValue(locale)); + + String key = row.getKey(); + + boolean keyIsPresent = properties.containsKey(key); + if (mergeNewKeys || keyIsPresent) { + + properties.put(key, row.getLocaleValue(locale)); + } + } if (!isSilent()) { getLog().info(String.format("Merge locale bundle %s in %s", locale, bundleFile)); } + properties.store(bundleFile); } diff --git a/i18n-maven-plugin/src/site/apt/index.apt b/i18n-maven-plugin/src/site/apt/index.apt index 8d3ad9c..f546f61 100644 --- a/i18n-maven-plugin/src/site/apt/index.apt +++ b/i18n-maven-plugin/src/site/apt/index.apt @@ -54,6 +54,12 @@ Goals Overview * {{{./tapestry-bundle-mojo.html} i18n:tapestry-bundle}} generate unique i18n bundle for tapestry application. + * {{{./generate-csv-bunle-mojo.html} i18n:help}} generate a single csv file with i18n sentences for some locales. + + * {{{./split-csv-bunle-mojo.html} i18n:help}} split back a csv i18n file into i18n bundle files (one file for each locale) + + * {{{./merge-back-csv-bunle-mojo.html} i18n:help}} merge back a csv i18n file into i18n bundle files + * {{{./help-mojo.html} i18n:help}} display help. Usage diff --git a/i18n-maven-plugin/src/site/apt/usages.apt b/i18n-maven-plugin/src/site/apt/usages.apt index a39612d..ffbf520 100644 --- a/i18n-maven-plugin/src/site/apt/usages.apt +++ b/i18n-maven-plugin/src/site/apt/usages.apt @@ -231,6 +231,36 @@ mymodule/ </plugin> ----------------------------------------------------------------------------- +Csv Bundle (since 3.3) + +* Generate a csv bundle + + You can generate a single csv file with the bundles via the generate-csv-file (after a bundle invocation). + +----------------------------------------------------------------------------- +<plugin> + <groupId>org.nuiton.i18n</groupId> + <artifactId>i18n-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>bundle</goal> + <goal>generate-csv-file</goal> + </goals> + </execution> + </executions> +</plugin> +----------------------------------------------------------------------------- + + You can then give the csv file to people to edit it. + +* Split or merge a csv bundle + + Having them the csv file filled by people you can then split it back to some i18n bundle files with + the split-csv-file mojo. + + Event better you can merge it back to the i18n files of a module using the <<merge-back-csv-file>> mojo. + And there is more for you! There is some other interesting properties in the plugin, for example it is -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository i18n. See http://git.nuiton.org/i18n.git commit 4c6a79c97731e0a8fab3de633597d45d8d7c921b Author: Tony CHEMIT <chemit@codelutin.com> Date: Sat Jul 26 19:34:54 2014 +0200 refs #3356 : add the generated csv file in the classpath --- .../plugin/bundle/csv/GenerateCsvBundleMojo.java | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/GenerateCsvBundleMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/GenerateCsvBundleMojo.java index e7fc82d..4250d9e 100644 --- a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/GenerateCsvBundleMojo.java +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/GenerateCsvBundleMojo.java @@ -19,10 +19,10 @@ import java.util.TreeMap; /** * To generate a csv file from the full bundle of the module. - * + * <p/> * The csv file will have a first column with i18n keys, and a * column for each locale defined in {@link #locales}. - * + * <p/> * Created on 7/26/14. * * @author Tony Chemit - chemit@codelutin.com @@ -68,7 +68,7 @@ public class GenerateCsvBundleMojo extends AbstractCsvBundleMojo { * * @since 1.0.0 */ - @Parameter(property = "i18n.bundleOutputDir", defaultValue = "${basedir}/target/generated-sources/resources", required = true) + @Parameter(property = "i18n.bundleOutputDir", defaultValue = "${project.build.directory}/generated-sources/resources", required = true) protected File bundleOutputDir; /** @@ -92,6 +92,14 @@ public class GenerateCsvBundleMojo extends AbstractCsvBundleMojo { protected String bundleOutputPackage; /** + * To add the generated csv file in the classpath. + * + * @since 3.3 + */ + @Parameter(property = "i18n.addInClassPath", defaultValue = "true") + protected boolean addInClassPath; + + /** * The definitive directory where to generate the bundles (includes the * package of bundle). * @@ -133,6 +141,14 @@ public class GenerateCsvBundleMojo extends AbstractCsvBundleMojo { bundleOutputEncoding); } } + + if (addInClassPath) { + + if (isVerbose()) { + getLog().info("Will add **/*.csv in classpath"); + } + addResourceDir(bundleOutputDir, "**/*.csv"); + } } @Override -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository i18n. See http://git.nuiton.org/i18n.git commit f44c18d1d2d727adb4f8154fbc4ae480418a2efe Author: Tony CHEMIT <chemit@codelutin.com> Date: Sun Jul 27 13:04:02 2014 +0200 fixes #3357: Remove deprecated Tapestry mojo --- .../i18n/plugin/bundle/TapestryBundleMojo.java | 190 --------------------- 1 file changed, 190 deletions(-) diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/TapestryBundleMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/TapestryBundleMojo.java deleted file mode 100644 index 86dda54..0000000 --- a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/TapestryBundleMojo.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * #%L - * I18n :: Maven Plugin - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2007 - 2010 CodeLutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/lgpl-3.0.html>. - * #L% - */ - -package org.nuiton.i18n.plugin.bundle; - -import org.apache.maven.plugins.annotations.Execute; -import org.apache.maven.plugins.annotations.LifecyclePhase; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.ResolutionScope; -import org.nuiton.i18n.bundle.I18nBundleEntry; -import org.nuiton.i18n.bundle.I18nBundleUtil; -import org.nuiton.io.SortedProperties; -import org.nuiton.plugin.PluginHelper; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.nio.charset.Charset; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.Locale; -import java.util.Map; - - -/** - * Generates a unique bundle for a tapestry application. - * <p/> - * <b>Note :</b> The mojo has nothing specific to tapestry and should be renamed - * (or removed since the {@code bundle} mojo do the same with more options)... - * - * @author tchemit <chemit@codelutin.com> - * @since 1.2 - * @deprecated since 2.4, will not be replaced, use the simple {@code bundle} - * goal instead - */ -@Deprecated -@Mojo(name = "tapestry-bundle", - defaultPhase = LifecyclePhase.GENERATE_RESOURCES, - requiresProject = true, - requiresDependencyResolution = ResolutionScope.RUNTIME) -@Execute(goal = "collect-i18n-artifacts") -public class TapestryBundleMojo extends AbstractMakeI18nBundleMojo { - - @Override - protected void doAction() throws Exception { - long t00 = System.nanoTime(); - - if (!silent) { - getLog().info("config - bundle name : " + bundleOutputName); - getLog().info("config - basedir : " + bundleOutputDir); - getLog().info("config - locales : " + Arrays.toString(locales)); - } - - Map<Locale, String> bundleDico = - new LinkedHashMap<Locale, String>(locales.length); - - for (Locale locale : locales) { - - long t0 = System.nanoTime(); - - File bundleOut = getBundleFile( - outputFolder, - bundleOutputName, - locale, - false - ); - - if (!silent) { - getLog().info("generate bundle for locale " + locale + - " in file " + bundleOut.getName()); - } - - SortedProperties propertiesOut = - new SortedProperties(encoding, false); - StringBuilder buffer = new StringBuilder(); - - URL[] urls = getCollectI18nResources(locale); - if (urls.length == 0) { - getLog().warn("no bundle for locale " + locale); - continue; - } - - Charset loadEncoding = Charset.forName(encoding); - for (URL url : urls) { - long t000 = System.nanoTime(); - I18nBundleEntry bundleEntry = - new I18nBundleEntry(url, locale, null); - bundleEntry.load(propertiesOut, loadEncoding); - String strPath = bundleEntry.getPath().toString(); - int index = strPath.indexOf("i18n/"); - - buffer.append(',').append(strPath.substring(index)); - if (verbose) { - getLog().info( - "loaded " + bundleEntry.getPath() + " in " + - PluginHelper.convertTime(t000, System.nanoTime())); - } - } - - if (buffer.length() > 0) { - bundleDico.put(locale, buffer.substring(1)); - if (!silent) { - getLog().info( - "bundles for locale : " + bundleDico.get(locale)); - } - } - propertiesOut.store(bundleOut); - if (!silent && verbose) { - getLog().info( - "bundle created in " + - PluginHelper.convertTime(t0, System.nanoTime()) + - " (detected sentences : " + propertiesOut.size() + ")"); - } - if (checkBundle) { - checkBundle(locale, propertiesOut, showEmpty, unsafeMapping); - } - } - - failsIfWarning(); - - if (generateDefaultLocale) { - generateDefaultBundle(); - } - - if (!silent && verbose) { - getLog().info("done in " + - PluginHelper.convertTime(t00, System.nanoTime())); - } - } - - /** - * @param root le repertoire ou sont stockes les fichiers i18n - * @param artifactId le nom de l'artifact - * @param locale le nom du bundle - * @param create {@code true} pour creer le fichier si non present - * @return le fichier i18n - * @throws IOException si probleme lors de la creation du fichier - */ - @Override - protected File getBundleFile(File root, - String artifactId, - Locale locale, - boolean create) throws IOException { - String path = root.getAbsolutePath() + File.separatorChar + artifactId; - if (locale != null) { - path += "_" + locale.getLanguage(); - } - path += ".properties"; - File file = new File( - path); - if (create && !file.exists()) { - createNewFile(file); - } - return file; - } - - @Override - protected URL[] getCollectI18nResources(Locale locale) throws IOException { - File file = getCollectOutputFile(locale, false); - if (!file.exists()) { - return I18nBundleUtil.EMPTY_URL_ARRAY; - } - URL[] urls = PluginHelper.getLinesAsURL(file); - return urls; - } - - -} -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository i18n. See http://git.nuiton.org/i18n.git commit 772ea4ffb86e9816c9a26bd5fa7d16f8ea41ef57 Author: Tony CHEMIT <chemit@codelutin.com> Date: Sun Jul 27 13:05:11 2014 +0200 refs #3356 : improve the way of storing the generated csv file + fix doc --- .../plugin/bundle/csv/GenerateCsvBundleMojo.java | 120 +++++++++++++-------- i18n-maven-plugin/src/site/apt/usages.apt | 8 +- 2 files changed, 78 insertions(+), 50 deletions(-) diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/GenerateCsvBundleMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/GenerateCsvBundleMojo.java index 4250d9e..2f9ed92 100644 --- a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/GenerateCsvBundleMojo.java +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/GenerateCsvBundleMojo.java @@ -6,6 +6,7 @@ import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.nuiton.csv.Export; +import org.nuiton.i18n.plugin.I18nUtil; import org.nuiton.io.SortedProperties; import java.io.File; @@ -35,29 +36,23 @@ import java.util.TreeMap; public class GenerateCsvBundleMojo extends AbstractCsvBundleMojo { /** - * Name of the bundle to generate. - * - * @since 1.0.2 + * Name of the bundle to use. */ @Parameter(property = "i18n.bundleOutputName", defaultValue = "${project.artifactId}-i18n", required = true) protected String bundleOutputName; /** - * Encoding used to load any i18n property files. + * Encoding used to read any i18n property files. * <p/> * If not defined, will use the {@link #encoding} parameter. - * - * @since 2.4 */ @Parameter(property = "i18n.bundleInputEncoding") protected String bundleInputEncoding; /** - * Encoding used to write any i18n property files. + * Encoding used to write any files. * <p/> * If not defined, will use the {@link #encoding} parameter. - * - * @since 2.4 */ @Parameter(property = "i18n.bundleOutputEncoding") protected String bundleOutputEncoding; @@ -65,14 +60,12 @@ public class GenerateCsvBundleMojo extends AbstractCsvBundleMojo { /** * Root directory where to generate aggregated bundles (this directory will * be added as resources of the project). - * - * @since 1.0.0 */ @Parameter(property = "i18n.bundleOutputDir", defaultValue = "${project.build.directory}/generated-sources/resources", required = true) protected File bundleOutputDir; /** - * Package name of the generate aggregated bundles. + * Package name of the generate aggregated bundles. * <p/> * <strong>Note:</strong> By default we use the <code>META-INF</code> package * since it is the favorite package of <code>I18n</code> runtime initializer. @@ -85,39 +78,53 @@ public class GenerateCsvBundleMojo extends AbstractCsvBundleMojo { * package name : foo.bar * directory : foo/bar * </pre> - * - * @since 2.3.2 */ @Parameter(property = "i18n.bundleOutputPackage", defaultValue = "META-INF", required = true) protected String bundleOutputPackage; /** * To add the generated csv file in the classpath. - * - * @since 3.3 + * <p/> + * If {@link #bundleCsvDirectory} is filled, then will add the generated csv file at the root of class-path, + * otherwise will add add it in the {@link #bundleOutputPackage} package. */ @Parameter(property = "i18n.addInClassPath", defaultValue = "true") protected boolean addInClassPath; /** - * The definitive directory where to generate the bundles (includes the - * package of bundle). - * - * @since 2.3.2 + * Location of the csv file to split. + */ + @Parameter(property = "i18n.bundleCsvFile", defaultValue = "${i18n.bundleOutputName}-i18n.csv", required = true) + protected String bundleCsvFileName; + + /** + * If you want to specify where to generate the csv file. + * <p/> + * If not filled, then will generate it in the same directory where bundles are stored. + */ + @Parameter(property = "i18n.bundleCsvDirectory") + protected File bundleCsvDirectory; + + /** + * The definitive directory where to load the bundles (includes the package of bundle). */ protected File outputFolder; + /** + * The definitive file where to write the csv file. + */ + protected File bundleCsvFile; + @Override public void init() throws Exception { super.init(); - // get the definitive folder where to generate bundles (including - // bundle package) + // get the definitive folder where to generate bundles (including bundle package) outputFolder = getBundleOutputFolder(); if (isVerbose()) { - getLog().info("Will generates bundles in " + outputFolder); + getLog().info("Will load bundles from " + outputFolder); } createDirectoryIfNecessary(outputFolder); @@ -142,26 +149,54 @@ public class GenerateCsvBundleMojo extends AbstractCsvBundleMojo { } } - if (addInClassPath) { + if (bundleCsvDirectory == null) { if (isVerbose()) { - getLog().info("Will add **/*.csv in classpath"); + getLog().info("Will generate csv bundle in bundle directory " + outputFolder); } - addResourceDir(bundleOutputDir, "**/*.csv"); + bundleCsvDirectory = outputFolder; + + if (addInClassPath) { + + if (isVerbose()) { + getLog().info("Will add " + bundleCsvFileName + " in classpath"); + } + addResourceDir(bundleOutputDir, "**/" + bundleCsvFileName); + } + } else { + if (isVerbose()) { + getLog().info("Will generate csv bundle in given directory " + bundleCsvDirectory); + } + + if (addInClassPath) { + + if (isVerbose()) { + getLog().info("Will add " + bundleCsvFileName + " in classpath"); + } + addResourceDir(bundleCsvDirectory, bundleCsvFileName); + } + } + createDirectoryIfNecessary(outputFolder); + + bundleCsvFile = new File(bundleCsvDirectory, bundleCsvFileName); + + if (!bundleCsvFile.exists()) { + createNewFile(bundleCsvFile); } + } @Override protected void doAction() throws Exception { - if (!silent) { - getLog().info("config - locales : " + Arrays.toString(locales)); - getLog().info("config - bundle dir : " + outputFolder); - getLog().info("config - bundle name : " + bundleOutputName); - getLog().info("config - csv separator : " + bundleCsvSeparator); - getLog().info("config - csv file : " + bundleCsvFile); - getLog().info("config - input encoding : " + bundleInputEncoding); - getLog().info("config - output encoding : " + bundleOutputEncoding); + if (!isSilent()) { + getLog().info("config - locales : " + Arrays.toString(locales)); + getLog().info("config - bundle dir : " + outputFolder); + getLog().info("config - bundle name : " + bundleOutputName); + getLog().info("config - csv separator : " + bundleCsvSeparator); + getLog().info("config - csv file name : " + bundleCsvFileName); + getLog().info("config - input encoding : " + bundleInputEncoding); + getLog().info("config - output encoding : " + bundleOutputEncoding); } // fill rows to export @@ -170,11 +205,10 @@ public class GenerateCsvBundleMojo extends AbstractCsvBundleMojo { for (Locale locale : locales) { - File bundleFile = getI18nFile(outputFolder, - bundleOutputName, - locale, - false - ); + File bundleFile = I18nUtil.getI18nFile(outputFolder, + bundleOutputName, + locale, + false); SortedProperties properties = new SortedProperties(bundleOutputEncoding); properties.load(bundleFile); @@ -193,16 +227,11 @@ public class GenerateCsvBundleMojo extends AbstractCsvBundleMojo { List<I18nBundleModelRow> rows = new LinkedList<I18nBundleModelRow>(rowsByKey.values()); if (!isSilent()) { - - getLog().info(String.format("Found %d translations.", rows.size())); + getLog().info(String.format("Found %d translations to export.", rows.size())); } // do the export - if (!bundleCsvFile.exists()) { - createNewFile(bundleCsvFile); - } - if (!isSilent()) { getLog().info("Generate csv bundle file at " + bundleCsvFile); } @@ -213,7 +242,6 @@ public class GenerateCsvBundleMojo extends AbstractCsvBundleMojo { } - protected File getBundleOutputFolder() { File result = bundleOutputDir; if (StringUtils.isNotEmpty(bundleOutputPackage)) { diff --git a/i18n-maven-plugin/src/site/apt/usages.apt b/i18n-maven-plugin/src/site/apt/usages.apt index ffbf520..c8b4518 100644 --- a/i18n-maven-plugin/src/site/apt/usages.apt +++ b/i18n-maven-plugin/src/site/apt/usages.apt @@ -235,7 +235,7 @@ Csv Bundle (since 3.3) * Generate a csv bundle - You can generate a single csv file with the bundles via the generate-csv-file (after a bundle invocation). + You can generate a single csv file with the bundles via the generate-csv-bundle (after a bundle invocation). ----------------------------------------------------------------------------- <plugin> @@ -245,7 +245,7 @@ Csv Bundle (since 3.3) <execution> <goals> <goal>bundle</goal> - <goal>generate-csv-file</goal> + <goal>generate-csv-bundle</goal> </goals> </execution> </executions> @@ -257,9 +257,9 @@ Csv Bundle (since 3.3) * Split or merge a csv bundle Having them the csv file filled by people you can then split it back to some i18n bundle files with - the split-csv-file mojo. + the <<split-csv-bundle>> mojo. - Event better you can merge it back to the i18n files of a module using the <<merge-back-csv-file>> mojo. + Event better you can merge it back to the i18n files of a module using the <<merge-back-csv-bundle>> mojo. And there is more for you! -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository i18n. See http://git.nuiton.org/i18n.git commit aa99cc4eaa80f6b993f7ce9b808f678a6ea325aa Author: Tony CHEMIT <chemit@codelutin.com> Date: Sun Jul 27 13:05:35 2014 +0200 fixes #3358: Sanity mojo parameters --- .../i18n/plugin/AbstractI18nGenerateMojo.java | 66 +++++ .../org/nuiton/i18n/plugin/AbstractI18nMojo.java | 111 +------- .../java/org/nuiton/i18n/plugin/GenerateMojo.java | 35 ++- .../java/org/nuiton/i18n/plugin/GetterMojo.java | 14 +- .../main/java/org/nuiton/i18n/plugin/I18nUtil.java | 41 +++ .../i18n/plugin/bundle/AbstractI18nBundleMojo.java | 5 +- .../plugin/bundle/AbstractMakeI18nBundleMojo.java | 284 --------------------- .../org/nuiton/i18n/plugin/bundle/BundleMojo.java | 233 ++++++++++++++++- .../plugin/bundle/CollectI18nArtifactsMojo.java | 4 + .../plugin/bundle/csv/AbstractCsvBundleMojo.java | 11 - .../plugin/bundle/csv/MergeBackCsvBundleMojo.java | 29 ++- .../i18n/plugin/bundle/csv/SplitCsvBundleMojo.java | 29 ++- .../i18n/plugin/parser/AbstractI18nParserMojo.java | 34 ++- 13 files changed, 449 insertions(+), 447 deletions(-) diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/AbstractI18nGenerateMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/AbstractI18nGenerateMojo.java new file mode 100644 index 0000000..99f5c13 --- /dev/null +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/AbstractI18nGenerateMojo.java @@ -0,0 +1,66 @@ +package org.nuiton.i18n.plugin; + +import org.apache.maven.plugins.annotations.Parameter; + +import java.io.File; +import java.io.IOException; + +/** + * Created on 7/27/14. + * + * @author Tony Chemit - chemit@codelutin.com + * @since 3.3 + */ +public abstract class AbstractI18nGenerateMojo extends AbstractI18nMojo { + + /** Le nombre de getters détectés pendant le cycle de vie du build. */ + private static int NB_GETTER_FILES; + + /** + * Name to use as prefix of generated files. + * <p/> + * <b>Note :</b> By default, use the artifact id. + */ + @Parameter(property = "i18n.artifactId", defaultValue = "${project.artifactId}", readonly = true) + protected String artifactId; + + /** Directory where to generate i18n files. */ + @Parameter(property = "i18n.out", defaultValue = "${basedir}/target/generated-sources/i18n", required = true) + protected File out; + + /** + * @return {@code true} si des getters ont etes enregistres pendant le + * cycle de vie, {@code false} sinon. + */ + protected boolean needGeneration() { + boolean needGeneration = NB_GETTER_FILES > 0; + return needGeneration; + } + + /** + * Prend en compte qu'un getter a été détecté. + * <p/> + * Cela veut dire qu'un goal de parser a détecté des clefs. Il faudra donc + * activer les goal get et gen. + */ + protected void addGetter() { + NB_GETTER_FILES++; + } + + /** + * @param root le repertoire ou sont stockes les fichiers getter + * @param getter le nom du getter + * @param create {@code true} pour creer le fichier si non present + * @return le fichier i18n + * @throws IOException si probleme lors de la creation du fichier + */ + protected File getGetterFile(File root, String getter, boolean create) + throws IOException { + File file = new File( + root.getAbsolutePath() + File.separatorChar + getter); + if (create && !file.exists()) { + createNewFile(file); + } + return file; + } +} diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/AbstractI18nMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/AbstractI18nMojo.java index 44924de..0cbeafe 100644 --- a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/AbstractI18nMojo.java +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/AbstractI18nMojo.java @@ -50,9 +50,6 @@ import java.util.TreeSet; */ public abstract class AbstractI18nMojo extends AbstractPlugin implements PluginWithEncoding { - /** Le nombre de getters détectés pendant le cycle de vie du build. */ - private static int NB_GETTER_FILES; - /** * Dependance du projet. * @@ -62,14 +59,6 @@ public abstract class AbstractI18nMojo extends AbstractPlugin implements PluginW protected MavenProject project; /** - * Name to use as prefix of generated files. - * <p/> - * <b>Note :</b> By default, use the artifact id. - */ - @Parameter(property = "i18n.artifactId", defaultValue = "${project.artifactId}", readonly = true) - protected String artifactId; - - /** * Locales to treate, separated by comma. * <p/> * Example : @@ -78,28 +67,11 @@ public abstract class AbstractI18nMojo extends AbstractPlugin implements PluginW @Parameter(property = "i18n.bundles", defaultValue = "fr_FR,en_GB", required = true) protected String bundles; - /** Directory where to find project i18n files. */ - @Parameter(property = "i18n.src", defaultValue = "${basedir}/src/main/resources/i18n", required = true) - protected File src; - - /** Directory where to generate i18n files. */ - @Parameter(property = "i18n.out", defaultValue = "${basedir}/target/generated-sources/i18n", required = true) - protected File out; - /** Encoding used to load and store properties. */ @Parameter(property = "i18n.encoding", defaultValue = "${project.build.sourceEncoding}", required = true) protected String encoding; /** - * To update generated files to user i18n files. - * <p/> - * <b>Note :</b> By default, this is active, in order to have a project uptodate - * with last i18n bundles detected. - */ - @Parameter(property = "i18n.genSrc", defaultValue = "true") - protected boolean genSrc; - - /** * Verbose flag. * <p/> * <b>Note :</b> if not setted, we used the {@code maven.verbose} property. @@ -115,15 +87,6 @@ public abstract class AbstractI18nMojo extends AbstractPlugin implements PluginW @Parameter(property = "i18n.silent", defaultValue = "false") protected boolean silent; - /** - * Strict mode to only keep in user i18n detected i18n keys and remove obsolete keys. - * <p/> - * <b>Note :</b> By default not active. Use this with care since it can - * delete keys. Moreover if this flag is activated, then all files will be parsed. - */ - @Parameter(property = "i18n.strictMode", defaultValue = "false") - protected boolean strictMode; - /** locales to process */ protected Locale[] locales; @@ -132,7 +95,8 @@ public abstract class AbstractI18nMojo extends AbstractPlugin implements PluginW protected boolean checkPackaging() { // nothing to do on a pom module - return !acceptPackaging(Packaging.pom); + boolean result = !acceptPackaging(Packaging.pom); + return result; } @Override @@ -146,75 +110,10 @@ public abstract class AbstractI18nMojo extends AbstractPlugin implements PluginW locales = I18nUtil.parseLocales(bundles); if (locales == null || locales.length == 0) { throw new IllegalStateException( - "Il faut au moins une locale declaree (utiliser " + - "la propriete 'bundles')"); + "You need at least one locale, please fill the 'bundles' property."); } } - public String getArtifactId() { - return artifactId; - } - - /** - * @return {@code true} si des getters ont etes enregistres pendant le - * cycle de vie, {@code false} sinon. - */ - protected boolean needGeneration() { - boolean needGeneration = NB_GETTER_FILES > 0; - return needGeneration; - } - - /** - * Prend en compte qu'un getter a été détecté. - * <p/> - * Cela veut dire qu'un goal de parser a détecté des clefs. Il faudra donc - * activer les goal get et gen. - */ - protected void addGetter() { - NB_GETTER_FILES++; - } - - /** - * @param root le repertoire ou sont stockes les fichiers i18n - * @param artifactId le nom de l'artifact - * @param locale le nom de la locale (peut-être nulle) - * @param create {@code true} pour creer le fichier si non present - * @return le fichier i18n - * @throws IOException si probleme lors de la creation du fichier - */ - public File getI18nFile(File root, - String artifactId, - Locale locale, - boolean create) throws IOException { - String path = root.getAbsolutePath() + File.separatorChar + artifactId; - if (locale != null) { - path += "_" + locale.toString(); - } - path += ".properties"; - File file = new File(path); - if (create && !file.exists()) { - createNewFile(file); - } - return file; - } - - /** - * @param root le repertoire ou sont stockes les fichiers getter - * @param getter le nom du getter - * @param create {@code true} pour creer le fichier si non present - * @return le fichier i18n - * @throws IOException si probleme lors de la creation du fichier - */ - public File getGetterFile(File root, String getter, boolean create) - throws IOException { - File file = new File( - root.getAbsolutePath() + File.separatorChar + getter); - if (create && !file.exists()) { - createNewFile(file); - } - return file; - } - protected void checkBundle(Locale locale, Properties propertiesOut, boolean showEmpty, @@ -301,10 +200,6 @@ public abstract class AbstractI18nMojo extends AbstractPlugin implements PluginW return silent; } - public boolean isStrictMode() { - return strictMode; - } - @Override public String getEncoding() { return encoding; diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/GenerateMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/GenerateMojo.java index 55dea47..84df835 100644 --- a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/GenerateMojo.java +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/GenerateMojo.java @@ -43,7 +43,29 @@ import java.util.Locale; */ @Mojo(name = "gen", defaultPhase = LifecyclePhase.GENERATE_RESOURCES) @Execute(goal = "get") -public class GenerateMojo extends AbstractI18nMojo { +public class GenerateMojo extends AbstractI18nGenerateMojo { + + /** Directory where to find project i18n files. */ + @Parameter(property = "i18n.src", defaultValue = "${basedir}/src/main/resources/i18n", required = true) + protected File src; + + /** + * To update generated files to user i18n files. + * <p/> + * <b>Note :</b> By default, this is active, in order to have a project uptodate + * with last i18n bundles detected. + */ + @Parameter(property = "i18n.genSrc", defaultValue = "true") + protected boolean genSrc; + + /** + * Strict mode to only keep in user i18n detected i18n keys and remove obsolete keys. + * <p/> + * <b>Note :</b> By default not active. Use this with care since it can + * delete keys. Moreover if this flag is activated, then all files will be parsed. + */ + @Parameter(property = "i18n.strictMode", defaultValue = "false") + protected boolean strictMode; /** * A flag to check that bundles are complete (no missing i18n translations). @@ -81,11 +103,12 @@ public class GenerateMojo extends AbstractI18nMojo { @Override protected boolean checkSkip() { + boolean result = true; if (!needGeneration()) { getLog().info("No getter detected - all files are up to date."); - return false; + result = false; } - return true; + return result; } @Override @@ -100,9 +123,9 @@ public class GenerateMojo extends AbstractI18nMojo { getLog().info("prepare bundle for locale " + locale); } // Merge - File bundleSrc = getI18nFile(src, artifactId, locale, false); - File bundleOut = getI18nFile(out, artifactId, locale, false); - File bundleGetterOut = getI18nFile( + File bundleSrc = I18nUtil.getI18nFile(src, artifactId, locale, false); + File bundleOut = I18nUtil.getI18nFile(out, artifactId, locale, false); + File bundleGetterOut = I18nUtil.getI18nFile( out, artifactId + GetterMojo.FROM_GETTERS, locale, false); SortedProperties propertiesSrc = new SortedProperties(encoding); diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/GetterMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/GetterMojo.java index a4b90fc..82bcb80 100644 --- a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/GetterMojo.java +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/GetterMojo.java @@ -39,10 +39,10 @@ import java.util.Locale; /** * Recupere les différents fichiers des parsers en un fichier de proprietes. * - * @author julien + * @author Julien Ruchaud - ruchaud@codelutin.com */ @Mojo(name = "get", defaultPhase = LifecyclePhase.GENERATE_RESOURCES) -public class GetterMojo extends AbstractI18nMojo { +public class GetterMojo extends AbstractI18nGenerateMojo { /** * To keep generated getter files. @@ -57,11 +57,13 @@ public class GetterMojo extends AbstractI18nMojo { @Override protected boolean checkSkip() { + boolean result = true; + if (!needGeneration()) { getLog().info("No getter detected - all files are up to date."); - return false; + result = false; } - return true; + return result; } @Override @@ -69,7 +71,7 @@ public class GetterMojo extends AbstractI18nMojo { if (!silent) { getLog().info("config - basedir : " + out.getAbsolutePath()); - getLog().info("config - locales : " + Arrays.toString(locales)); + getLog().info("config - locales : " + Arrays.toString(locales)); } File bundleGetters = new File(out.getAbsoluteFile(), @@ -118,7 +120,7 @@ public class GetterMojo extends AbstractI18nMojo { if (getLog().isDebugEnabled()) { getLog().debug("generate bundle for locale " + locale); } - File bundleOut = getI18nFile(out, artifactId + FROM_GETTERS, locale, false); + File bundleOut = I18nUtil.getI18nFile(out, artifactId + FROM_GETTERS, locale, false); copyFile(bundleGetters, bundleOut); if (!silent && verbose) { getLog().info("generate bundle " + locale); diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/I18nUtil.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/I18nUtil.java new file mode 100644 index 0000000..90a98c9 --- /dev/null +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/I18nUtil.java @@ -0,0 +1,41 @@ +package org.nuiton.i18n.plugin; + +import org.nuiton.plugin.PluginHelper; + +import java.io.File; +import java.io.IOException; +import java.util.Locale; + +/** + * Place here some useful methods. + * + * Created on 7/27/14. + * + * @author Tony Chemit - chemit@codelutin.com + * @since 3.3 + */ +public class I18nUtil { + /** + * @param root le repertoire ou sont stockes les fichiers i18n + * @param artifactId le nom de l'artifact + * @param locale le nom de la locale (peut-être nulle) + * @param create {@code true} pour creer le fichier si non present + * @return le fichier i18n + * @throws IOException si probleme lors de la creation du fichier + */ + public static File getI18nFile(File root, + String artifactId, + Locale locale, + boolean create) throws IOException { + String path = root.getAbsolutePath() + File.separatorChar + artifactId; + if (locale != null) { + path += "_" + locale.toString(); + } + path += ".properties"; + File file = new File(path); + if (create && !file.exists()) { + PluginHelper.createNewFile(file); + } + return file; + } +} diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/AbstractI18nBundleMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/AbstractI18nBundleMojo.java index b855267..8458d45 100644 --- a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/AbstractI18nBundleMojo.java +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/AbstractI18nBundleMojo.java @@ -27,6 +27,7 @@ package org.nuiton.i18n.plugin.bundle; import org.apache.maven.plugins.annotations.Parameter; import org.nuiton.i18n.plugin.AbstractI18nMojo; +import org.nuiton.i18n.plugin.I18nUtil; import java.io.File; import java.io.IOException; @@ -83,8 +84,8 @@ public abstract class AbstractI18nBundleMojo extends AbstractI18nMojo { */ protected File getCollectOutputFile(Locale locale, boolean create) throws IOException { - File bundleOut = getI18nFile(collectOutputDir, collectOutputName, - locale, create); + File bundleOut = I18nUtil.getI18nFile(collectOutputDir, collectOutputName, + locale, create); return bundleOut; } diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/AbstractMakeI18nBundleMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/AbstractMakeI18nBundleMojo.java deleted file mode 100644 index 6ea4bf3..0000000 --- a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/AbstractMakeI18nBundleMojo.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * #%L - * I18n :: Maven Plugin - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2007 - 2010 CodeLutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/lgpl-3.0.html>. - * #L% - */ -package org.nuiton.i18n.plugin.bundle; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugins.annotations.Parameter; - -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.SortedSet; - -/** - * Common mojo to all final bundle maker. - * - * @author tchemit <chemit@codelutin.com> - * @since 2.0 - */ -public abstract class AbstractMakeI18nBundleMojo extends AbstractI18nBundleMojo { - - /** - * Encoding used to load any i18n property files. - * <p/> - * If not defined, will use the {@link #encoding} parameter. - * - * @since 2.4 - */ - @Parameter(property = "i18n.bundleInputEncoding") - protected String bundleInputEncoding; - - /** - * Encoding used to write any i18n property files. - * <p/> - * If not defined, will use the {@link #encoding} parameter. - * - * @since 2.4 - */ - @Parameter(property = "i18n.bundleOutputEncoding") - protected String bundleOutputEncoding; - - /** - * Root directory where to generate aggregated bundles (this directory will - * be added as resources of the project). - * - * @since 1.0.0 - */ - @Parameter(property = "i18n.bundleOutputDir", defaultValue = "${basedir}/target/generated-sources/resources", required = true) - protected File bundleOutputDir; - - /** - * Package name of the generate aggregated bundles. - * <p/> - * <strong>Note:</strong> By default we use the <code>META-INF</code> package - * since it is the favorite package of <code>I18n</code> runtime initializer. - * <p/> - * The package name is dotted as it will be stored as folder like in Java - * language. - * <p/> - * Example : - * <pre> - * package name : foo.bar - * directory : foo/bar - * </pre> - * - * @since 2.3.2 - */ - @Parameter(property = "i18n.bundleOutputPackage", defaultValue = "META-INF", required = true) - protected String bundleOutputPackage; - - /** - * Name of the bundle to generate. - * - * @since 1.0.2 - */ - @Parameter(property = "i18n.bundleOutputName", defaultValue = "${project.artifactId}-i18n", required = true) - protected String bundleOutputName; - - /** - * A flag to generate a bundle with the first locale defined as a default - * bundle (with no locale specialization). - * - * @since 2.1 - */ - @Parameter(property = "i18n.generateDefaultLocale", defaultValue = "false") - protected boolean generateDefaultLocale; - - /** - * A flag to check that bundles are complete (no missing i18n translations). - * <p/> - * <b>Note :</b> This behaviour will be activated is {@link #failsIfWarning} is on. - * - * @since 1.0.0 - */ - @Parameter(property = "i18n.checkBundle", defaultValue = "true") - protected boolean checkBundle; - - /** - * A flag to show missing i18n translation. - * <p/> - * <b>Note :</b> Need the {@link #checkBundle} to be activated). - * - * @since 1.0.0 - */ - @Parameter(property = "i18n.showEmpty", defaultValue = "false") - protected boolean showEmpty; - - /** - * A flag to make the build fails if there is some warnings while generating - * bundle, says when it misses some translations. - * <p/> - * <b>Note :</b> This parameter should be used in a release profile to - * ensure bundles are complete. - * - * @since 2.0 - */ - @Parameter(property = "i18n.failsIfWarning", defaultValue = "false") - protected boolean failsIfWarning; - - /** to keep all none translated i18n keys by locale. */ - protected Map<Locale, SortedSet<String>> unsafeMapping; - - /** - * The definitive directory where to generate the bundles (includes the - * package of bundle). - * - * @since 2.3.2 - */ - protected File outputFolder; - - @Override - public void init() throws Exception { - super.init(); - - if (failsIfWarning) { - - // check bundle if wants to fail on unsafe bundles - checkBundle = true; - - unsafeMapping = new HashMap<Locale, SortedSet<String>>(); - } else { - unsafeMapping = null; - } - - // get the definitive folder where to generate bundles (including - // bundle package) - - outputFolder = getBundleOutputFolder(); - - if (isVerbose()) { - getLog().info("Will generates bundles in " + outputFolder); - } - createDirectoryIfNecessary(outputFolder); - - if (StringUtils.isEmpty(bundleInputEncoding)) { - - // use the default encoding - bundleInputEncoding = getEncoding(); - if (getLog().isDebugEnabled()) { - getLog().debug("Use as input encoding the default one : " + - bundleInputEncoding); - } - } - - if (StringUtils.isEmpty(bundleOutputEncoding)) { - - // use the default encoding - bundleOutputEncoding = getEncoding(); - - if (getLog().isDebugEnabled()) { - getLog().debug("Use as output encoding the default one : " + - bundleOutputEncoding); - } - } - } - - protected void failsIfWarning() throws MojoFailureException { - if (!failsIfWarning) { - - // no check - return; - } - - if (unsafeMapping != null && !unsafeMapping.isEmpty()) { - - // there is at least one not complete bundle, faisl the build - throw new MojoFailureException( - "Bundles for locale(s) " + unsafeMapping.keySet() + - " are not complete. Use the -Di18n.showEmpty to see " + - "missing translations."); - } - } - - /** - * Gets the bundle file for the given parameters. - * - * @param root the root directory where bundles are stored - * @param artifactId the artifactId (says the prefix of bundle) - * @param locale the locale used in bundle ({@code null} means no locale specialized) - * @param create a flag to create the file if none existing - * @return the bundle file - * @throws IOException if any IO problem while creating it (if needed). - * @since 2.1 - */ - protected abstract File getBundleFile(File root, - String artifactId, - Locale locale, - boolean create) throws IOException; - - /** - * Generates the default bundle, says the bundle with no locale specialized. - * <p/> - * This bundle is a copy of the bundle of the first locale (which in fact - * is considered as the main locale). - * - * @throws IOException if any IO problem while the copy. - * @since 2.1 - */ - protected void generateDefaultBundle() throws IOException { - - File bundleFirstLocale = getBundleFile(outputFolder, - bundleOutputName, - locales[0], - false - ); - - File bundleWithoutLocale = getBundleFile(outputFolder, - bundleOutputName, - null, - false - ); - - if (!isSilent()) { - getLog().info("Generate default bundle at " + bundleWithoutLocale); - } - - FileUtils.copyFile(bundleFirstLocale, bundleWithoutLocale); - } - - protected File getBundleOutputFolder() { - File result = bundleOutputDir; - if (StringUtils.isNotEmpty(bundleOutputPackage)) { - String[] paths = bundleOutputPackage.split("\\."); - for (String path : paths) { - result = new File(result, path); - } - } - return result; - } - - public String getBundleOutputEncoding() { - return bundleOutputEncoding; - } - - public String getBundleInputEncoding() { - return bundleInputEncoding; - } - -} diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/BundleMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/BundleMojo.java index 78f9097..85f76bb 100644 --- a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/BundleMojo.java +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/BundleMojo.java @@ -25,9 +25,11 @@ package org.nuiton.i18n.plugin.bundle; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Execute; import org.apache.maven.plugins.annotations.LifecyclePhase; @@ -37,6 +39,7 @@ import org.apache.maven.plugins.annotations.ResolutionScope; import org.nuiton.i18n.bundle.I18nBundleEntry; import org.nuiton.i18n.bundle.I18nBundleUtil; import org.nuiton.i18n.init.DefaultI18nInitializer; +import org.nuiton.i18n.plugin.I18nUtil; import org.nuiton.io.SortedProperties; import org.nuiton.plugin.PluginHelper; @@ -49,6 +52,7 @@ import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -57,6 +61,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; +import java.util.SortedSet; /** * Generate an aggregate i18n bundle for all dependencies of the project. @@ -80,7 +85,116 @@ import java.util.Set; requiresProject = true, requiresDependencyResolution = ResolutionScope.RUNTIME) @Execute(goal = "collect-i18n-artifacts") -public class BundleMojo extends AbstractMakeI18nBundleMojo { +public class BundleMojo extends AbstractI18nBundleMojo { + + /** + * Encoding used to load any i18n property files. + * <p/> + * If not defined, will use the {@link #encoding} parameter. + * + * @since 2.4 + */ + @Parameter(property = "i18n.bundleInputEncoding") + protected String bundleInputEncoding; + + /** + * Encoding used to write any i18n property files. + * <p/> + * If not defined, will use the {@link #encoding} parameter. + * + * @since 2.4 + */ + @Parameter(property = "i18n.bundleOutputEncoding") + protected String bundleOutputEncoding; + + /** + * Root directory where to generate aggregated bundles (this directory will + * be added as resources of the project). + * + * @since 1.0.0 + */ + @Parameter(property = "i18n.bundleOutputDir", defaultValue = "${basedir}/target/generated-sources/resources", required = true) + protected File bundleOutputDir; + + /** + * Package name of the generate aggregated bundles. + * <p/> + * <strong>Note:</strong> By default we use the <code>META-INF</code> package + * since it is the favorite package of <code>I18n</code> runtime initializer. + * <p/> + * The package name is dotted as it will be stored as folder like in Java + * language. + * <p/> + * Example : + * <pre> + * package name : foo.bar + * directory : foo/bar + * </pre> + * + * @since 2.3.2 + */ + @Parameter(property = "i18n.bundleOutputPackage", defaultValue = "META-INF", required = true) + protected String bundleOutputPackage; + + /** + * Name of the bundle to generate. + * + * @since 1.0.2 + */ + @Parameter(property = "i18n.bundleOutputName", defaultValue = "${project.artifactId}-i18n", required = true) + protected String bundleOutputName; + + /** + * A flag to generate a bundle with the first locale defined as a default + * bundle (with no locale specialization). + * + * @since 2.1 + */ + @Parameter(property = "i18n.generateDefaultLocale", defaultValue = "false") + protected boolean generateDefaultLocale; + + /** + * A flag to check that bundles are complete (no missing i18n translations). + * <p/> + * <b>Note :</b> This behaviour will be activated is {@link #failsIfWarning} is on. + * + * @since 1.0.0 + */ + @Parameter(property = "i18n.checkBundle", defaultValue = "true") + protected boolean checkBundle; + + /** + * A flag to show missing i18n translation. + * <p/> + * <b>Note :</b> Need the {@link #checkBundle} to be activated). + * + * @since 1.0.0 + */ + @Parameter(property = "i18n.showEmpty", defaultValue = "false") + protected boolean showEmpty; + + /** + * A flag to make the build fails if there is some warnings while generating + * bundle, says when it misses some translations. + * <p/> + * <b>Note :</b> This parameter should be used in a release profile to + * ensure bundles are complete. + * + * @since 2.0 + */ + @Parameter(property = "i18n.failsIfWarning", defaultValue = "false") + protected boolean failsIfWarning; + + /** to keep all none translated i18n keys by locale. */ + protected Map<Locale, SortedSet<String>> unsafeMapping; + + /** + * The definitive directory where to generate the bundles (includes the + * package of bundle). + * + * @since 2.3.2 + */ + protected File outputFolder; /** * A flag to generate the i18n definition file. @@ -152,6 +266,47 @@ public class BundleMojo extends AbstractMakeI18nBundleMojo { public void init() throws Exception { super.init(); + if (failsIfWarning) { + + // check bundle if wants to fail on unsafe bundles + checkBundle = true; + + unsafeMapping = new HashMap<Locale, SortedSet<String>>(); + } else { + unsafeMapping = null; + } + + // get the definitive folder where to generate bundles (including + // bundle package) + + outputFolder = getBundleOutputFolder(); + + if (isVerbose()) { + getLog().info("Will generates bundles in " + outputFolder); + } + createDirectoryIfNecessary(outputFolder); + + if (StringUtils.isEmpty(bundleInputEncoding)) { + + // use the default encoding + bundleInputEncoding = getEncoding(); + if (getLog().isDebugEnabled()) { + getLog().debug("Use as input encoding the default one : " + + bundleInputEncoding); + } + } + + if (StringUtils.isEmpty(bundleOutputEncoding)) { + + // use the default encoding + bundleOutputEncoding = getEncoding(); + + if (getLog().isDebugEnabled()) { + getLog().debug("Use as output encoding the default one : " + + bundleOutputEncoding); + } + } + // add root bundle directory as resources of the project addResourceDir(bundleOutputDir, "**/*.properties"); @@ -212,10 +367,10 @@ public class BundleMojo extends AbstractMakeI18nBundleMojo { long t0 = System.nanoTime(); - File bundleOut = getI18nFile(outputFolder, - bundleOutputName, - locale, - false + File bundleOut = I18nUtil.getI18nFile(outputFolder, + bundleOutputName, + locale, + false ); SortedProperties propertiesOut = @@ -305,12 +460,11 @@ public class BundleMojo extends AbstractMakeI18nBundleMojo { } } - @Override protected File getBundleFile(File root, String artifactId, Locale locale, boolean create) throws IOException { - return getI18nFile(root, artifactId, locale, create); + return I18nUtil.getI18nFile(root, artifactId, locale, create); } protected void generateDefinitionFile(String version, @@ -427,4 +581,69 @@ public class BundleMojo extends AbstractMakeI18nBundleMojo { } } + protected void failsIfWarning() throws MojoFailureException { + if (!failsIfWarning) { + + // no check + return; + } + + if (unsafeMapping != null && !unsafeMapping.isEmpty()) { + + // there is at least one not complete bundle, faisl the build + throw new MojoFailureException( + "Bundles for locale(s) " + unsafeMapping.keySet() + + " are not complete. Use the -Di18n.showEmpty to see " + + "missing translations."); + } + } + + /** + * Generates the default bundle, says the bundle with no locale specialized. + * <p/> + * This bundle is a copy of the bundle of the first locale (which in fact + * is considered as the main locale). + * + * @throws IOException if any IO problem while the copy. + * @since 2.1 + */ + protected void generateDefaultBundle() throws IOException { + + File bundleFirstLocale = getBundleFile(outputFolder, + bundleOutputName, + locales[0], + false + ); + + File bundleWithoutLocale = getBundleFile(outputFolder, + bundleOutputName, + null, + false + ); + + if (!isSilent()) { + getLog().info("Generate default bundle at " + bundleWithoutLocale); + } + + FileUtils.copyFile(bundleFirstLocale, bundleWithoutLocale); + } + + protected File getBundleOutputFolder() { + File result = bundleOutputDir; + if (StringUtils.isNotEmpty(bundleOutputPackage)) { + String[] paths = bundleOutputPackage.split("\\."); + for (String path : paths) { + result = new File(result, path); + } + } + return result; + } + + public String getBundleOutputEncoding() { + return bundleOutputEncoding; + } + + public String getBundleInputEncoding() { + return bundleInputEncoding; + } } diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/CollectI18nArtifactsMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/CollectI18nArtifactsMojo.java index 80b15e0..fc5a539 100644 --- a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/CollectI18nArtifactsMojo.java +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/CollectI18nArtifactsMojo.java @@ -68,6 +68,10 @@ import java.util.Map; requiresDependencyResolution = ResolutionScope.RUNTIME) public class CollectI18nArtifactsMojo extends AbstractI18nBundleMojo { + /** Directory where to find project i18n files. */ + @Parameter(property = "i18n.src", defaultValue = "${basedir}/src/main/resources/i18n", required = true) + protected File src; + /** * Local Repository. * diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/AbstractCsvBundleMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/AbstractCsvBundleMojo.java index e9786fd..fc4201f 100644 --- a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/AbstractCsvBundleMojo.java +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/AbstractCsvBundleMojo.java @@ -3,8 +3,6 @@ package org.nuiton.i18n.plugin.bundle.csv; import org.apache.maven.plugins.annotations.Parameter; import org.nuiton.i18n.plugin.AbstractI18nMojo; -import java.io.File; - /** * Created on 7/26/14. * @@ -14,15 +12,6 @@ import java.io.File; public abstract class AbstractCsvBundleMojo extends AbstractI18nMojo { /** - * Location of the csv file to split. - * - * @since 3.3 - */ - @Parameter(property = "i18n.bundleCsvFile", - defaultValue = "${basedir}/target/${project.artifactId}-i18n.csv") - protected File bundleCsvFile; - - /** * Char separator in the csv bundle file. * * @since 3.3 diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/MergeBackCsvBundleMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/MergeBackCsvBundleMojo.java index 40b5a5f..5f39276 100644 --- a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/MergeBackCsvBundleMojo.java +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/MergeBackCsvBundleMojo.java @@ -8,6 +8,7 @@ import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.nuiton.csv.Import; +import org.nuiton.i18n.plugin.I18nUtil; import org.nuiton.io.SortedProperties; import java.io.File; @@ -34,12 +35,28 @@ public class MergeBackCsvBundleMojo extends AbstractCsvBundleMojo { * To accept to add new keys in the original i18n bundle. * <p/> * The option is {@code false} by default, since merging operation should not add any new keys. - * - * @since 3.3 */ @Parameter(property = "i18n.mergeNewKeys", defaultValue = "false") protected boolean mergeNewKeys; + /** Directory where to find project i18n files. */ + @Parameter(property = "i18n.src", defaultValue = "${project.basedir}/src/main/resources/i18n", required = true) + protected File src; + + /** + * Name to use as prefix of generated files. + * <p/> + * <strong>Note :</strong> By default, use the artifact id. + */ + @Parameter(property = "i18n.artifactId", defaultValue = "${project.artifactId}", readonly = true) + protected String artifactId; + + /** + * Location of the csv file to split. + */ + @Parameter(property = "i18n.bundleCsvFile", required = true) + protected File bundleCsvFile; + @Override protected void doAction() throws Exception { @@ -72,10 +89,10 @@ public class MergeBackCsvBundleMojo extends AbstractCsvBundleMojo { for (Locale locale : locales) { - File bundleFile = getI18nFile(src, - artifactId, - locale, - false); + File bundleFile = I18nUtil.getI18nFile(src, + artifactId, + locale, + false); SortedProperties properties = new SortedProperties(encoding); diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/SplitCsvBundleMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/SplitCsvBundleMojo.java index dfcc5c0..a0237d9 100644 --- a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/SplitCsvBundleMojo.java +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/bundle/csv/SplitCsvBundleMojo.java @@ -8,6 +8,7 @@ import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.nuiton.csv.Import; +import org.nuiton.i18n.plugin.I18nUtil; import org.nuiton.io.SortedProperties; import java.io.File; @@ -35,8 +36,6 @@ public class SplitCsvBundleMojo extends AbstractCsvBundleMojo { /** * Name of the bundle to generate. - * - * @since 1.0.2 */ @Parameter(property = "i18n.bundleOutputName", defaultValue = "${project.artifactId}-i18n", required = true) protected String bundleOutputName; @@ -44,17 +43,29 @@ public class SplitCsvBundleMojo extends AbstractCsvBundleMojo { /** * Root directory where to generate aggregated bundles (this directory will * be added as resources of the project). - * - * @since 1.0.0 */ @Parameter(property = "i18n.bundleOutputDir", defaultValue = "${project.build.directory}", required = true) protected File bundleOutputDir; + /** + * Name to use as prefix of generated files. + * <p/> + * <string>Note :</string> By default, use the artifact id. + */ + @Parameter(property = "i18n.artifactId", defaultValue = "${project.artifactId}", readonly = true) + protected String artifactId; + + /** + * Location of the csv file to split. + */ + @Parameter(property = "i18n.bundleCsvFile", required = true) + protected File bundleCsvFile; + @Override protected void doAction() throws Exception { if (!silent) { - getLog().info("config - locales : " + Arrays.toString(locales)); + getLog().info("config - locales : " + Arrays.toString(locales)); getLog().info("config - bundle directory : " + bundleOutputDir); getLog().info("config - bundle name : " + bundleOutputName); getLog().info("config - csv separator : " + bundleCsvSeparator); @@ -79,10 +90,10 @@ public class SplitCsvBundleMojo extends AbstractCsvBundleMojo { for (Locale locale : locales) { - File bundleFile = getI18nFile(bundleOutputDir, - artifactId, - locale, - false); + File bundleFile = I18nUtil.getI18nFile(bundleOutputDir, + artifactId, + locale, + false); SortedProperties properties = new SortedProperties(encoding); diff --git a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/parser/AbstractI18nParserMojo.java b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/parser/AbstractI18nParserMojo.java index c4b0ca4..7b93389 100644 --- a/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/parser/AbstractI18nParserMojo.java +++ b/i18n-maven-plugin/src/main/java/org/nuiton/i18n/plugin/parser/AbstractI18nParserMojo.java @@ -26,7 +26,8 @@ package org.nuiton.i18n.plugin.parser; import org.apache.maven.plugins.annotations.Parameter; -import org.nuiton.i18n.plugin.AbstractI18nMojo; +import org.nuiton.i18n.plugin.AbstractI18nGenerateMojo; +import org.nuiton.i18n.plugin.I18nUtil; import org.nuiton.io.FileUpdater; import org.nuiton.io.SortedProperties; import org.nuiton.plugin.PluginHelper; @@ -41,7 +42,7 @@ import java.util.regex.Pattern; * * @author tchemit <chemit@codelutin.com> */ -public abstract class AbstractI18nParserMojo extends AbstractI18nMojo implements I18nParserConfiguration { +public abstract class AbstractI18nParserMojo extends AbstractI18nGenerateMojo implements I18nParserConfiguration { /** @return the outGetter to use for the instance (java.getter,...) */ protected abstract String getOutGetter(); @@ -68,6 +69,19 @@ public abstract class AbstractI18nParserMojo extends AbstractI18nMojo implements */ public abstract FileUpdater newFileUpdater(SourceEntry entry); + /** Directory where to find project i18n files. */ + @Parameter(property = "i18n.src", defaultValue = "${basedir}/src/main/resources/i18n", required = true) + protected File src; + + /** + * Strict mode to only keep in user i18n detected i18n keys and remove obsolete keys. + * <p/> + * <b>Note :</b> By default not active. Use this with care since it can + * delete keys. Moreover if this flag is activated, then all files will be parsed. + */ + @Parameter(property = "i18n.strictMode", defaultValue = "false") + protected boolean strictMode; + /** Build directory (used to know if files in sources are up-to-date). */ @Parameter(property = "i18n.cp", defaultValue = "${basedir}/target/classes") protected File cp; @@ -112,7 +126,7 @@ public abstract class AbstractI18nParserMojo extends AbstractI18nMojo implements /** * A regex pattern to accept incoming keys. - * + * <p/> * Only incoming keys which match the pattern will be kept. * * @since 2.5 @@ -132,10 +146,10 @@ public abstract class AbstractI18nParserMojo extends AbstractI18nMojo implements ParserExecutor parserExecutor; - @Override - public boolean isStrictMode() { - return strictMode; - } +// @Override +// public boolean isStrictMode() { +// return strictMode; +// } public boolean isForce() { return force; @@ -210,7 +224,7 @@ public abstract class AbstractI18nParserMojo extends AbstractI18nMojo implements // Anciennes cles disponnibles //fixme : pourquoi on utilise un bundle precis ? le premier ici, // je ne comprends pas - File oldLanguageFile = getI18nFile(src, artifactId, locales[0], true); + File oldLanguageFile = I18nUtil.getI18nFile(src, artifactId, locales[0], true); oldLanguage.load(oldLanguageFile); @@ -299,6 +313,10 @@ public abstract class AbstractI18nParserMojo extends AbstractI18nMojo implements return result; } + public boolean isStrictMode() { + return strictMode; + } + /** * Add the default entry to entries given in configuration. * <p/> -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository i18n. See http://git.nuiton.org/i18n.git commit 0ed5ca8ae4141433a6c35ca8c8d495fb534891f1 Merge: 40f58c1 aa99cc4 Author: Tony CHEMIT <chemit@codelutin.com> Date: Sun Jul 27 13:07:03 2014 +0200 Merge branch 'feature/3356' into develop i18n-maven-plugin/pom.xml | 5 + .../i18n/plugin/AbstractI18nGenerateMojo.java | 66 +++++ .../org/nuiton/i18n/plugin/AbstractI18nMojo.java | 111 +------- .../java/org/nuiton/i18n/plugin/GenerateMojo.java | 35 ++- .../java/org/nuiton/i18n/plugin/GetterMojo.java | 14 +- .../main/java/org/nuiton/i18n/plugin/I18nUtil.java | 41 +++ .../i18n/plugin/bundle/AbstractI18nBundleMojo.java | 5 +- .../plugin/bundle/AbstractMakeI18nBundleMojo.java | 284 --------------------- .../org/nuiton/i18n/plugin/bundle/BundleMojo.java | 245 +++++++++++++++++- .../plugin/bundle/CollectI18nArtifactsMojo.java | 4 + .../i18n/plugin/bundle/TapestryBundleMojo.java | 190 -------------- .../plugin/bundle/csv/AbstractCsvBundleMojo.java | 22 ++ .../plugin/bundle/csv/GenerateCsvBundleMojo.java | 255 ++++++++++++++++++ .../i18n/plugin/bundle/csv/I18nBundleModel.java | 44 ++++ .../i18n/plugin/bundle/csv/I18nBundleModelRow.java | 35 +++ .../plugin/bundle/csv/MergeBackCsvBundleMojo.java | 125 +++++++++ .../i18n/plugin/bundle/csv/SplitCsvBundleMojo.java | 124 +++++++++ .../i18n/plugin/parser/AbstractI18nParserMojo.java | 34 ++- i18n-maven-plugin/src/site/apt/index.apt | 6 + i18n-maven-plugin/src/site/apt/usages.apt | 30 +++ pom.xml | 6 + 21 files changed, 1070 insertions(+), 611 deletions(-) -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
participants (1)
-
nuiton.org scm