[Lutinutil-commits] r1537 - in maven-i18n-plugin/trunk: . src/main/java/org src/main/java/org/nuiton src/main/java/org/nuiton/i18n src/main/java/org/nuiton/i18n/plugin src/main/java/org/nuiton/i18n/plugin/parser src/main/java/org/nuiton/i18n/plugin/parser/event src/main/java/org/nuiton/i18n/plugin/parser/impl src/site
Author: tchemit Date: 2009-05-13 20:32:34 +0000 (Wed, 13 May 2009) New Revision: 1537 Added: maven-i18n-plugin/trunk/src/main/java/org/nuiton/ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/AbstractI18nPlugin.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/Bundle.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/Generate.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/Getter.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/I18nArtifact.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/I18nLogger.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/PluginHelper.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/SourceEntry.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/AbstractI18nParser.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/Parser.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/ParserEvent.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/ParserException.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/event/ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/event/KeysModifier.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJava.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaActionConfig.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaTabConfig.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJaxx.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserSwixat.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserValidation.java maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserXml.java Modified: maven-i18n-plugin/trunk/pom.xml maven-i18n-plugin/trunk/src/site/site.xml Log: maven-i18n-plugin migrates to nuiton Modified: maven-i18n-plugin/trunk/pom.xml =================================================================== --- maven-i18n-plugin/trunk/pom.xml 2009-05-13 20:31:49 UTC (rev 1536) +++ maven-i18n-plugin/trunk/pom.xml 2009-05-13 20:32:34 UTC (rev 1537) @@ -10,8 +10,12 @@ <groupId>org.codelutin</groupId> <artifactId>lutinproject</artifactId> <version>3.5.4</version> + <!--groupId>org.nuiton</groupId> + <artifactId>mavenpom</artifactId> + <version>1.0.0-SNAPSHOT</version--> </parent> + <groupId>org.nuiton</groupId> <artifactId>maven-i18n-plugin</artifactId> <version>1.0.0-SNAPSHOT</version> @@ -19,20 +23,37 @@ <dependencies> <dependency> - <groupId>org.codelutin</groupId> - <artifactId>lutinprocessor</artifactId> + <groupId>org.nuiton</groupId> + <artifactId>nuitonprocessor</artifactId> <version>${processor.version}</version> <scope>compile</scope> </dependency> <dependency> - <groupId>org.codelutin</groupId> - <artifactId>lutinpluginutil</artifactId> - <version>${lutinpluginutil.version}</version> + <groupId>org.nuiton</groupId> + <artifactId>maven-helper-plugin</artifactId> + <version>${helper.version}</version> <scope>compile</scope> </dependency> + <!-- tests dependencies --> + <dependency> + <groupId>org.nuiton</groupId> + <artifactId>maven-helper-plugin</artifactId> + <version>${helper.version}</version> + <scope>test</scope> + <classifier>tests</classifier> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.6</version> + <scope>test</scope> + </dependency> + + <dependency> <groupId>org.apache.maven.shared</groupId> <artifactId>maven-dependency-tree</artifactId> <version>1.2</version> @@ -93,15 +114,18 @@ <properties> - <!-- id du projet du labs --> - <labs.id>12</labs.id> + <redmine.project>nuitonutil</redmine.project> - <!-- nom du projet sur le labs --> - <labs.project>lutinutil</labs.project> + <processor.version>1.0.0-SNAPSHOT</processor.version> + <!-- assuprimer du de l'utilisation de mavenpom --> + <labs.id>12</labs.id> + <labs.project>lutinutil</labs.project> <maven.version>2.0.10</maven.version> - <processor.version>0.18</processor.version> - <lutinpluginutil.version>0.5</lutinpluginutil.version> + <helper.version>1.0.0-SNAPSHOT</helper.version> + <helper.licenseName>lgpl_v3</helper.licenseName> + <site.home.url>http://lutinutil.labs.libre-entreprise.org</site.home.url> + <repository.home.url>http://lutinbuilder.labs.libre-entreprise.org/maven2</repository.home.url> <lutinutil.version>1.0.6</lutinutil.version> </properties> @@ -141,9 +165,9 @@ </build> + <!--Site--> <reporting> <plugins> - <!--Site report's plugin--> <plugin> <artifactId>maven-plugin-plugin</artifactId> </plugin> @@ -155,6 +179,7 @@ <!-- ************************************************************* --> <!--Source control management--> + <!-- a supprimer au passage a mavenpom --> <scm> <url>${maven.scm.url}</url> <connection>${maven.scm.connection}</connection> @@ -178,36 +203,4 @@ </repository> </repositories> - <profiles> - <!-- perform only on a release stage when using the maven-release-plugin --> - <profile> - <id>release-profile</id> - <activation> - <property> - <name>performRelease</name> - <value>true</value> - </property> - </activation> - <build> - <plugins> - <!-- always add license and third-party files to classpath --> - <plugin> - <groupId>org.codelutin</groupId> - <artifactId>maven-license-switcher-plugin</artifactId> - <version>0.8</version> - <executions> - <execution> - <id>attach-licenses</id> - <goals> - <goal>license</goal> - <goal>third-party</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - </profiles> - </project> \ No newline at end of file Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/AbstractI18nPlugin.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/AbstractI18nPlugin.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/AbstractI18nPlugin.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/AbstractI18nPlugin.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,188 @@ +/* + * *##% Plugin maven pour lutini18n + * Copyright (C) 2007 - 2008 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>. ##%* */ +package org.nuiton.i18n.plugin; + +import org.apache.maven.plugin.AbstractMojo; +import org.nuiton.i18n.plugin.parser.ParserEvent; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import org.codelutin.i18n.I18n; + +/** + * Classe permettant d'obenir les parametres pendant les différentes phases + * du plugin. + * + * @author julien + */ +public abstract class AbstractI18nPlugin extends AbstractMojo { + + /** + * Le nombre de getters détectés pendant le cycle de vie du build. + */ + private static int NB_GETTER_FILES = 0; + /** + * Répertoire de stockage des fichiers i18n pour la recuperation des fichiers + * de traduction entre librairie + */ + protected static final String DIRECTORY_INSTALL = "i18n" + File.separatorChar; + /** + * Nom du projet. + * + * @parameter expression="${i18n.artifactId}" default-value="${project.artifactId}" + * @readonly + */ + protected String artifactId; + /** + * Langues des bundles generes. + * <p/> + * + * @parameter expression="${i18n.bundles}" default-value="fr_FR,en_GB" + * @required + */ + protected String bundles; + /** + * Repertoire sources des fichiers i18n. + * + * @parameter expression="${i18n.src}" default-value="${basedir}/src/main/resources/i18n" + * @required + */ + protected File src; + /** + * Repertoire des fichiers generes i18n. + * + * @parameter expression="${i18n.out}" default-value="${basedir}/target/generated-sources/i18n" + * @required + */ + protected File out; + /** + * encoding a utiliser pour charger et sauver les bundles + * + * @parameter expression="${i18n.encoding}" default-value="${project.build.sourceEncoding}" + * @required + */ + protected String encoding; + /** + * Met les fichiers generes dans le repertoire des sources i18n. + * <p/> + * Note: Par défaut active, pour pouvoir paquager avec les bundles mis a jour. + * + * @parameter expression="${i18n.genSrc}" default-value="true" + */ + protected boolean genSrc; + /** + * Active la modification de cle. + * <p/> + * Note: par defaut, on ne l'active pas (build sur serveur non ui). + * + * @parameter expression="${i18n.keysModifier}" default-value="false" + */ + protected boolean keysModifier; + /** + * verbose flag + * <p/> + * Note: si non renseigne, on utilise la propiété <code>maven.verbose</code>. + * + * @parameter expression="${i18n.verbose}" default-value="${maven.verbose}" + */ + protected boolean verbose; + /** + * conserve les anciens fichiers de traduction avec un suffix ~ + * <p/> + * Note: par defaut, on ne l'active pas. + * + * @parameter expression="${i18n.keepBackup}" default-value="false" + */ + protected boolean keepBackup; + /** + * ne conserve que les clef scannees (et donc traite tous les fichiers) + * + * <p/> + * Note : par default, on ne l'active car rescanne tous les fichiers. + *s + * @parameter expression="${i18n.strictMode}" default-value="false" + */ + protected boolean strictMode; + /** Liste des évènements */ + protected List<ParserEvent> events = new ArrayList<ParserEvent>(); + protected Locale[] locales; + /**logger verbeux */ + protected I18nLogger verboseLog; + + /** + * Ajoute un évènement + * + * @param parserEvent l'évènement d'ajout + */ + protected void addParserEvent(ParserEvent parserEvent) { + this.events.add(parserEvent); + } + + /** + * Supprime un évènement + * + * @param parserEvent l'évènement de suppression + */ + protected void removeParserEvent(ParserEvent parserEvent) { + this.events.remove(parserEvent); + } + + public void init() { + + verboseLog = new I18nLogger(this); + + if (verbose) { + getLog().info("config - verbose mode is on"); + } + locales = I18n.parseLocales(bundles); +// bundlesToUse = bundles.split(","); +// for (int i = 0, j = bundlesToUse.length; i < j; i++) { +// bundlesToUse[i] = bundlesToUse[i].trim(); +// } + } + + public String getArtifactId() { + return artifactId; + } + + /** + * + * @return <code>true</code> si des getters ont etes enregistres pendant + * le cycle de vie, <code>false</code> sinon. + */ + protected boolean needGeneration() { + boolean needGeneration = NB_GETTER_FILES > 0; + return needGeneration; + } + + /** + * Prend en compte qu'un getter a été détecté. + * + * 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++; + } + + protected I18nLogger getVerboseLog() { + return verboseLog; + } +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/AbstractI18nPlugin.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:mergeinfo + Name: svn:eol-style + native Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/Bundle.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/Bundle.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/Bundle.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/Bundle.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,327 @@ +/* + * *##% Plugin maven pour lutini18n + * Copyright (C) 2007 - 2008 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>. ##%* */ +package org.nuiton.i18n.plugin; + +import java.net.MalformedURLException; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.factory.ArtifactFactory; +import org.apache.maven.artifact.metadata.ArtifactMetadataSource; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.resolver.ArtifactCollector; +import org.apache.maven.artifact.resolver.filter.ArtifactFilter; +import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter; +import org.apache.maven.model.Resource; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.MavenProjectBuilder; +import org.apache.maven.shared.dependency.tree.DependencyNode; +import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder; +import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException; +import org.codelutin.i18n.bundle.I18nBundleEntry; +import org.codelutin.i18n.bundle.I18nBundleFactory; +import org.nuiton.i18n.plugin.PluginHelper.I18nProperties; +import org.nuiton.util.DependencyUtil; +import org.codelutin.util.StringUtil; + +/** + * Créer un bundle pour une application finale. + * + * Cela génère un merge de tous les fichiers i18n utilisés en un seul. + * + * On utilise la dépendance sur les artifacts pour connaitre l'ordre le chargement + * des bundles. + * + * Si dans un bundle childs, la valeur de la clef est vide, on conserve alors celui + * du parent, + * + * Ainsi on obtient un bundle dont toutes les clefs sont traduites. + * + * Le but aussi d'utiliser un unique bundle est de gagner du temps au runtime + * car la recherche des bundles devient trop couteuse en temps lorsque l'on a de + * nombreuses dépendances (au dessus de 100 deps cela peut prendre plusieurs + * secondes, ce qui 'est pas acceptable). + * + * On a ajoute un second mode d'initialisation dans la clesse I18n pour n'utiliser + * qu'un seul bundle et courcircuiter le chargement couteux... + * * + * + * @author chemit + * @goal bundle + * @phase generate-resources + * @execute goal=gen + * @requiresProject true + * @requiresDependencyResolution runtime + * + * @since 0.12 + */ +public class Bundle extends AbstractI18nPlugin { + + /** + * Repertoire ou generer les bundles. + * + * @parameter expression="${i18n.bundleOutputDir}" default-value="${basedir}/target/generated-sources/java/META-INF" + * @required + */ + protected File bundleOutputDir; + /** + * Nom du bundle a generer. + * + * @parameter expression="${i18n.bundleOutputName}" default-value="${project.artifactId}-i18n" + * @required + */ + protected String bundleOutputName; + /** + * Dependance du projet. + * + * @parameter default-value="${project}" + * @required + */ + protected MavenProject project; + /** + * Local Repository. + * + * @parameter expression="${localRepository}" + * @required + * @readonly + */ + protected ArtifactRepository localRepository; + /** + * Remote repositories used for the project. + * + * @parameter expression="${project.remoteArtifactRepositories}" + * @required + * @readonly + */ + protected List<?> remoteRepositories; + /** + * Dependency tree builder component. + * + * @component + */ + protected DependencyTreeBuilder dependencyTreeBuilder; + /** + * Artifact Factory component. + * + * @component + */ + protected ArtifactFactory factory; + /** + * Artifact metadata source component. + * + * @component + */ + protected ArtifactMetadataSource artifactMetadataSource; + /** + * Artifact collector component. + * + * @component + */ + protected ArtifactCollector collector; + /** + * Maven Project Builder component. + * + * @component + */ + protected MavenProjectBuilder mavenProjectBuilder; + protected I18nArtifact[] i18nArtifacts; + protected ClassLoader loader; + protected URL[] urls; + + @Override + public void init() { + super.init(); + + if (locales == null || locales.length == 0) { + throw new IllegalStateException("il faut au moins une locale declaree (utiliser la propriete 'bundles')"); + } + + if (!bundleOutputDir.exists()) { + bundleOutputDir.mkdirs(); + } + + try { + // calcul des artifacts qui ont un bundle i18n et trie selon les + // dependances + + i18nArtifacts = detectI18nArtifacts(); + + getLog().info("detected " + i18nArtifacts.length + " i18n artifact(s) : "); + for (I18nArtifact a : i18nArtifacts) { + getLog().info(" - " + a.getArtifact()); + } + } catch (Exception ex) { + throw new RuntimeException(ex); + } + + // ajout de repertoire de generation (le parent en fait) + // dans les resources du projet + + String newresourceDir = bundleOutputDir.getParentFile().getAbsolutePath(); + + List<?> resources = project.getResources(); + boolean shouldAdd = true; + for (Object o : resources) { + Resource r = (Resource) o; + if (!r.getDirectory().equals(newresourceDir)) { + continue; + } + + r.addInclude("**/*.properties"); + shouldAdd = false; + break; + } + if (shouldAdd) { + Resource r = new Resource(); + r.setDirectory(newresourceDir); + r.addInclude("**/*.properties"); + //if (verbose) { + getLog().info("add resource " + r); + //} + project.addResource(r); + } + } + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + + if ("pom".equals(project.getPackaging()) || "site".equals(project.getPackaging())) { + return; + } + + long t00 = System.nanoTime(); + + init(); + + Locale defaultLocale = locales[0]; + try { + for (Locale locale : locales) { + + long t0 = System.nanoTime(); + + File bundleOut = PluginHelper.getI18nFile(bundleOutputDir, bundleOutputName, locale, false); + + getLog().info("prepare bundle " + bundleOut.getAbsolutePath()); + + I18nProperties propertiesOut = new I18nProperties(encoding, false); + + for (I18nArtifact artifact : i18nArtifacts) { + I18nBundleEntry[] bundleEntries = artifact.getBundleEntries(locale, defaultLocale); + for (I18nBundleEntry bundleEntry : bundleEntries) { + + bundleEntry.load(propertiesOut); + + if (verbose) { + getLog().info("loaded " + bundleEntry.getPath() + " in " + StringUtil.convertTime(t0, System.nanoTime())); + } + } + } + propertiesOut.store(bundleOut); + if (verbose) { + getLog().info("bundle created in " + StringUtil.convertTime(t0, System.nanoTime()) + " (detected sentences : " + propertiesOut.size() + ")"); + } + } + + // ecriture du ficher des definitions i18n (permet de faire une + // recherche extact sur un fichier puis d'en deduire les bundles a + // charger + String f = String.format(I18nBundleFactory.UNIQUE_BUNDLE_DEF, bundleOutputName); + File defOut = new File(bundleOutputDir, f); + getLog().info("prepare i18n definition " + defOut.getAbsolutePath()); + Properties p = new Properties(); + p.setProperty(I18nBundleFactory.BUNDLE_DEF_LOCALES, bundles); + p.store(new FileOutputStream(defOut), null); + + if (verbose) { + getLog().info("done in " + StringUtil.convertTime(t00, System.nanoTime())); + } + } catch (IOException e) { + getLog().error("File Error I/O ", e); + throw new MojoFailureException("File Error I/O "); + } + } + + /** + * Detecte les {@link I18nArtifact} et les retourne dans l'ordre de chargement + * dans le système i18n, i.e l'ordre des dependances entre artifacts. + * + * @return les artifacts i18nables triés par leur ordre de chargement dans le système i18n. + * + * @throws java.net.MalformedURLException + * @throws java.io.IOException + * @throws org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException + */ + protected I18nArtifact[] detectI18nArtifacts() throws MalformedURLException, IOException, DependencyTreeBuilderException { + + Map<Artifact, I18nArtifact> dico = new java.util.HashMap<Artifact, I18nArtifact>(); + + I18nArtifact i18nArtifact; + for (Object o : project.getArtifacts()) { + i18nArtifact = new I18nArtifact((Artifact) o); + if (i18nArtifact.detectBundles()) { + if (verbose) { + getLog().info("detected artifact " + i18nArtifact.getArtifact()); + } + dico.put(i18nArtifact.getArtifact(), i18nArtifact); + } else { + if (getLog().isDebugEnabled()) { + getLog().debug("reject artifact " + i18nArtifact.getArtifact()); + } + } + } + + ArtifactFilter artifactFilter = new ScopeArtifactFilter(Artifact.SCOPE_RUNTIME); + + DependencyNode rootNode = dependencyTreeBuilder.buildDependencyTree(project, localRepository, factory, + artifactMetadataSource, artifactFilter, collector); + + List<Artifact> artifacts = new java.util.ArrayList<Artifact>(dico.keySet()); + + DependencyUtil.sortArtifacts(rootNode, artifacts, verbose); + + // l'artifact du projet est traite en dernier car s'il possède des + // bundles alors ils doivent etre charge en dernier + + Artifact projectArtifact = project.getArtifact(); + i18nArtifact = new I18nArtifact(projectArtifact, src.getParentFile()); + + if (i18nArtifact.detectBundles()) { + if (verbose) { + getLog().info("detected artifact " + i18nArtifact.getArtifact()); + } + artifacts.add(i18nArtifact.getArtifact()); + dico.put(i18nArtifact.getArtifact(), i18nArtifact); + } + + I18nArtifact[] result = new I18nArtifact[artifacts.size()]; + int i = 0; + for (Artifact artifact : artifacts) { + result[i++] = dico.get(artifact); + } + return result; + } +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/Bundle.java ___________________________________________________________________ Name: svn:mergeinfo + Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/Generate.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/Generate.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/Generate.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/Generate.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,113 @@ +/* + * *##% Plugin maven pour lutini18n + * Copyright (C) 2007 - 2008 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>. ##%* */ + +package org.nuiton.i18n.plugin; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.nuiton.i18n.plugin.PluginHelper.I18nProperties; +import org.nuiton.util.FileUtil; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Locale; + +/** + * Merge des fichiers de propriétés avec les anciens. + * + * @author julien + * @goal gen + * @phase generate-resources + * @execute goal=get + */ +public class Generate extends AbstractI18nPlugin { + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + + init(); + + if (!needGeneration()) { + getLog().info("Nothing to generate - all files are up to date."); + return; + } + + for (Locale bundle : locales) { + try { + // Merge + File bundleSrc = PluginHelper.getI18nFile(src, artifactId, bundle, false); + File bundleOut = PluginHelper.getI18nFile(out, artifactId, bundle, false); + + if (bundleSrc.exists()) { + + I18nProperties propertiesSrc = new I18nProperties(encoding).load(bundleSrc); + + I18nProperties propertiesOut = new I18nProperties(encoding); + + if (!strictMode) { + // push back in bundle out, all the bundle src keys + propertiesOut.putAll(propertiesSrc); + } + propertiesOut.load(bundleOut); + + // Parcours des clés + for (Object key : propertiesOut.keySet()) { + Object oldKey = propertiesOut.get(key); + Object value = propertiesSrc.get(oldKey); + + // Récupération de la clé si elle a été renommée + if (!key.equals(oldKey) && value == null) { + value = propertiesSrc.get(key); + } + + if (value != null) { + propertiesOut.put(key, value); + } else { + propertiesOut.put(key, ""); + } + } + + //fixme : on devrait laisser le fichier en utf8 ? + //propertiesOut.store(bundleOut); + propertiesOut.store(new FileOutputStream(bundleOut)); + + // Sauvegarde avant copie + if (genSrc && keepBackup) { + FileUtil.copy(bundleSrc, PluginHelper.getI18nFileBackup(src, artifactId, bundle)); + } + + getLog().info("merge bundle " + bundleSrc.getAbsolutePath()); + } + + if (genSrc) { + // Copie des fichiers dans les sources + FileUtil.copy(bundleOut, bundleSrc); + if (verbose) { + getVerboseLog().infoAction("copy", bundleSrc.getAbsolutePath()); + } + } + + } catch (IOException e) { + getLog().error("File Error I/O ", e); + throw new MojoFailureException("File Error I/O "); + } + } + } + +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/Generate.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:mergeinfo + Name: svn:eol-style + native Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/Getter.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/Getter.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/Getter.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/Getter.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,106 @@ +/* + * *##% Plugin maven pour lutini18n + * Copyright (C) 2007 - 2008 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>. ##%* */ + +package org.nuiton.i18n.plugin; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.codehaus.plexus.util.DirectoryScanner; +import org.nuiton.i18n.plugin.PluginHelper.I18nProperties; +import org.nuiton.util.FileUtil; + +import java.io.File; +import java.io.IOException; +import java.util.Locale; + +/** + * Recupere les différents fichiers des parsers en un fichier de proprietes. + * + * @author julien + * @goal get + * @phase generate-resources + */ +public class Getter extends AbstractI18nPlugin { + + /* + * (non-Javadoc) + * @see org.apache.maven.plugin.AbstractMojo#execute() + */ + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + + init(); + + if (!needGeneration()) { + if (verbose) { + getLog().info("Nothing to generate - all files are up to date."); + } + return; + } + + try { + File bundleGetters = new File(out.getAbsolutePath() + File.separatorChar + artifactId + ".properties"); + bundleGetters.createNewFile(); + + DirectoryScanner ds = new DirectoryScanner(); + ds.setBasedir(out); + ds.setIncludes(new String[]{"*.getter"}); + ds.scan(); + String[] files = ds.getIncludedFiles(); + + // Fusion des fichiers propriétés des différents parsers + for (String file : files) { + File bundleGetter = PluginHelper.getGetterFile(out, file, false); + concactProperties(bundleGetter, bundleGetters); + if (genSrc) { + bundleGetter.delete(); + } + getLog().info("create bundle " + bundleGetter.getAbsolutePath()); + } + + // Création des bundles + for (Locale bundle : locales) { + File bundleOut = PluginHelper.getI18nFile(out, artifactId, bundle, false); + FileUtil.copy(bundleGetters, bundleOut); + if (verbose) { + getVerboseLog().infoAction("generate", bundleOut.getAbsolutePath()); + } + } + + bundleGetters.delete(); + } catch (IOException e) { + getLog().error("File Error I/O ", e); + throw new MojoFailureException("File Error I/O"); + } + } + + /** + * Concatene deux fichiers de proprietes + * + * @param in le fichier entrant + * @param out le fichier sortant + * @throws IOException si problème pendant la sauvegarde ou fichier non trouvé. + */ + protected void concactProperties(File in, File out) throws IOException { + I18nProperties propertiesIn = new I18nProperties(encoding).load(in); + + I18nProperties propertiesOut = new I18nProperties(encoding).load(out); + propertiesOut.putAll(propertiesIn); + propertiesOut.store(out); + } +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/Getter.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:mergeinfo + Name: svn:eol-style + native Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/I18nArtifact.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/I18nArtifact.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/I18nArtifact.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/I18nArtifact.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,77 @@ +package org.nuiton.i18n.plugin; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import java.util.Locale; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.maven.artifact.Artifact; +import org.codelutin.i18n.bundle.I18nBundle; +import org.codelutin.i18n.bundle.I18nBundleEntry; +import org.codelutin.i18n.bundle.I18nBundleFactory; + +/** + * + * @author chemit + * @since 0.12 + */ +public class I18nArtifact { + + static final Log log = LogFactory.getLog(I18nArtifact.class); + protected final Artifact artifact; + protected final URL url; + protected I18nBundle[] bundles; + + public I18nArtifact(Artifact artifact) throws MalformedURLException { + this.artifact = artifact; + this.url = artifact.getFile().toURI().toURL(); + } + + public I18nArtifact(Artifact artifact, File file) throws MalformedURLException { + this.artifact = artifact; + this.url = file.toURI().toURL(); + } + + public Artifact getArtifact() { + return artifact; + } + + public URL getUrl() { + return url; + } + + public I18nBundleEntry[] getBundleEntries(Locale l, Locale defaultLocale) { + if (bundles == null) { + throw new NullPointerException("le bundleManager n'a pas ete initialise!"); + } + return I18nBundleFactory.getBundleEntries(l, defaultLocale, bundles); + } + + public boolean detectBundles() throws IOException { + + URL[] i18nUrls = I18nBundleFactory.getURLs(url); + + if (i18nUrls == null || i18nUrls.length == 0) { + // aucune url sur un fichier de traduction trouve + // l'artifact n'est pas i18n. + if (log.isDebugEnabled()) { + log.debug("no i18n url for artifact " + artifact); + } + return false; + } + + List<I18nBundle> listBundles = I18nBundleFactory.detectBundles(i18nUrls); + + if (listBundles.isEmpty()) { + // pas de bundle instancie (cela ne devrait jamias arrive...) + return false; + } + + this.bundles = listBundles.toArray(new I18nBundle[listBundles.size()]); + + return true; + } +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/I18nArtifact.java ___________________________________________________________________ Name: svn:mergeinfo + Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/I18nLogger.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/I18nLogger.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/I18nLogger.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/I18nLogger.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,98 @@ +package org.nuiton.i18n.plugin; + +import org.apache.maven.plugin.logging.SystemStreamLog; + +import java.beans.Introspector; +import java.io.File; + +/** + * Le logger utilisé par les mojo. + * + * @author chemit + * @since 0.9 + */ +public class I18nLogger extends SystemStreamLog { + + /** l'entrée en cours de traitement (pour les parseurs) */ + private SourceEntry entry; + + /** le fichier en cours de traitement (pour les parseurs) */ + protected File file; + + /** le prefix du mojo courant a ajouter dans les logs. */ + protected String parser; + + public I18nLogger(AbstractI18nPlugin parser) { + this.parser = "i18n:" + Introspector.decapitalize(parser.getClass().getSimpleName()) + " on " + parser.getArtifactId(); + } + + @Override + public void info(CharSequence content) { + print(0, "INFO", null, content.toString()); + } + + @Override + public void debug(CharSequence content) { + print(0, "DEBUG", null, content.toString()); + } + + public void infoEntry(String action, CharSequence content) { + print(0, "INFO", action, entry.toString() + (content == null ? "" : " - " + content.toString())); + } + + public void infoFile(String action, String content) { + print(2, "INFO", action, file.toString() + (content == null ? "" : " - " + content)); + } + + public void infoAction(String action, String content) { + print(2, "INFO", action, (content == null ? "" : " - " + content)); + } + + private void print(int start, String prefix, String context, String content) { + StringBuilder sb = new StringBuilder(); + sb.append("[").append(prefix).append("] [").append(parser).append("] "); + + for (int i = 0; i < start; i++) { + sb.append(' '); + } + if (context != null) { + sb.append("<").append(context).append("> "); + } + sb.append(content); + System.out.println(sb.toString()); + } + + public void setEntry(SourceEntry entry) { + this.entry = entry; + } + + /** + * Construit une chaine de log formatée. + * + * @param msg le prefix du message + * @param nbFiles le nombre de fichiers actuellement traités + * @param time le time de traitement de ce fichier + * @param all le temps de traitement de tous les fichiers + * @return la chaine de log formatée + */ + public String getLogEntry(String msg, int nbFiles, long time, long all) { + long now = System.nanoTime(); + long delta = now - time; + String s = msg; + if (time > 0) { + s += " (" + PluginHelper.convertTime(delta) + ")"; + } + if (all > 0) { + s += "(total time:" + PluginHelper.convertTime(now - all) + ")"; + } + if (nbFiles > 0) { + s += " ( ~ " + PluginHelper.convertTime(((now - all) / (nbFiles))) + " / file)"; + } + return s; + } + + public void setFile(File file) { + this.file = file; + } + +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/I18nLogger.java ___________________________________________________________________ Name: svn:mergeinfo + Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/PluginHelper.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/PluginHelper.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/PluginHelper.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/PluginHelper.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,278 @@ +/** + * *##% Plugin maven pour lutini18n + * Copyright (C) 2007 - 2008 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>. ##%* + */ +package org.nuiton.i18n.plugin; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.text.MessageFormat; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Locale; +import java.util.Properties; +import java.util.Vector; + +/** + * Une classe pour mutualiser toutes les méthodes utiles dans ce plugin. + * <p/> + * Note : On a dupliqué ici du code de la librairie lutinutil, pour casser la dépendance ver ce projet qui utilise ce plugin + * et donc introduit un cycle dans le graphe des dépendances, ce qui n'est pas souhaitable. + * + * @author chemit + */ +public class PluginHelper { + + /** + * @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</code> pour creer le fichier si non present + * @return le fichier i18n + * @throws java.io.IOException si probleme lors de la creation du fichier + */ + public static File getI18nFile(File root, String artifactId, Locale locale, boolean create) throws IOException { + File file = new File(root.getAbsolutePath() + File.separatorChar + artifactId + "-" + locale.toString() + ".properties"); + if (create && !file.exists()) { + if (!file.exists()) { + file.getParentFile().mkdirs(); + } + file.createNewFile(); + } + return file; + } + + /** + * @param root le repertoire ou sont stockes les fichiers getter + * @param getter le nom du getter + * @param create <code>true</code> pour creer le fichier si non present + * @return le fichier i18n + * @throws java.io.IOException si probleme lors de la creation du fichier + */ + public static File getGetterFile(File root, String getter, boolean create) throws IOException { + File file = new File(root.getAbsolutePath() + File.separatorChar + getter); + if (create && !file.exists()) { + if (!file.exists()) { + file.getParentFile().mkdirs(); + } + file.createNewFile(); + } + return file; + } + + /** + * @param root le repertoire ou sont stockes les fichiers getter + * @param getter le nom du getter + * @return le fichier i18n + */ + public static File getGetterFileBackup(File root, String getter) { + return new File(root.getAbsolutePath() + File.separatorChar + getter + '~'); + } + + /** + * @param root le reertoire ou sont stockes les fichiers i18n + * @param artifactId le nom de l'artifact + * @param bundle le nom du bundle + * @return le fichier i18n de backup + */ + public static File getI18nFileBackup(File root, String artifactId, Locale bundle) { + return new File(root.getAbsolutePath() + File.separatorChar + artifactId + "-" + bundle.toString() + ".properties~"); + } + + /** + * Permet de convertir une liste non typee, en une liste typee. + * <p/> + * La liste en entree en juste bien castee. + * <p/> + * On effectue une verification sur le typage des elements de la liste. + * <p/> + * Note : <b>Aucune liste n'est creee, ni recopiee</b> + * + * @param <O> le type des objets de la liste + * @param list la liste a convertir + * @param type le type des elements de la liste + * @return la liste typee + * @throws IllegalArgumentException si un element de la liste en entree n'est + * pas en adequation avec le type voulue. + */ + @SuppressWarnings({"unchecked"}) + static public <O> List<O> toGenericList(List<?> list, Class<O> type) throws IllegalArgumentException { + if (list.isEmpty()) { + return (List<O>) list; + } + for (Object o : list) { + if (!(type.isAssignableFrom(o.getClass()))) { + throw new IllegalArgumentException("can not cast List with object of type " + o.getClass() + " to " + type + " type!"); + } + } + return (List<O>) list; + } + static final protected double[] timeFactors = {1000000, 1000, 60, 60, 24}; + static final protected String[] timeUnites = {"ns", "ms", "s", "m", "h", "d"}; + + static public String convertTime(long value) { + return convert(value, timeFactors, timeUnites); + } + + static public String convertTime(long value, long value2) { + return convertTime(value2 - value); + } + + static public String convert(long value, double[] factors, String[] unites) { + long sign = value == 0 ? 1 : value / Math.abs(value); + int i = 0; + double tmp = Math.abs(value); + while (i < factors.length && i < unites.length && tmp > factors[i]) { + tmp = tmp / factors[i++]; + } + + tmp *= sign; + String result; + result = MessageFormat.format("{0,number,0.###}{1}", tmp, + unites[i]); + return result; + } + + /** + * Permet d'avoir les fichiers de proprietes tries. + * + * @author julien + * @author chemit + */ + public static class I18nProperties extends Properties { + + private static final long serialVersionUID = -1147150444452577558L; + /** l'encoding a utiliser pour lire et ecrire le properties. */ + protected String encoding; + /** un drapeau pour savoir s'il faut enlever l'entete generere */ + protected boolean removeHeader; + + public I18nProperties(String encoding) { + this(encoding, true); + } + + public I18nProperties(String encoding, boolean removeHeader) { + super(); + this.encoding = encoding; + this.removeHeader = removeHeader; + } + + public I18nProperties(Properties defaults) { + super(defaults); + } + + @Override + public synchronized Enumeration<Object> keys() { + List<Object> objects = Collections.list(super.keys()); + Vector<Object> result; + try { + // Attention, si les clef ne sont pas des string, ca ne marchera pas + List<String> list = toGenericList(objects, String.class); + Collections.sort(list); + result = new Vector<Object>(list); + } catch (IllegalArgumentException e) { + // keys are not string !!! + // can not sort keys + result = new Vector<Object>(objects); + } + return result.elements(); + } + + /** + * Charge le properties a partir d'un fichier. + * + * @param src le fichier src a charger en utilisant l'encoding declare + * @return l'instance du properties + * @throws IOException if any io pb + */ + public I18nProperties load(File src) throws IOException { + super.load(new InputStreamReader(new FileInputStream(src), encoding)); + return this; + } + + /** + * Sauvegarde le properties dans un fichier, sans commentaire et en utilisant l'encoding declare. + * + * @param dst the fichier de destination + * @throws IOException if any io pb + */ + public void store(File dst) throws IOException { + if (removeHeader) { + super.store(new OutputStreamWriter(new PropertiesDateRemoveFilterStream(new FileOutputStream(dst)), encoding), null); + } else { + super.store(new FileOutputStream(dst), null); + } + } + + /** + * Sauvegarde le properties dans un fichier, sans commentaire en laissant java encode en unicode. + * + * @param dst le fichier de destination + * @throws IOException if any io pb + */ + public void store(OutputStream dst) throws IOException { + if (removeHeader) { + super.store(new PropertiesDateRemoveFilterStream(dst), null); + } else { + super.store(dst, null); + } + } + } + + /** + * Un ecrivain qui supprime la premiere ligne rencontree dans le flux. + * + * + * <b>Note: </b> Attention, les performance d'utilisation de cet ecrivain + * est problèmatique, car sur de gros fichiers (>1000 entrees) les + * performances se degradent serieusement : pour 1200 entrees on arrive à + * plus de 5 secondes, alors que sans on a 76 ms! ... + * + * FIXME : implanter quelque chose de plus performant dans tous les cas + */ + public static class PropertiesDateRemoveFilterStream extends FilterOutputStream { + + private boolean firstLineOver; + char endChar; + + public PropertiesDateRemoveFilterStream(OutputStream out) { + super(out); + firstLineOver = false; + String lineSeparator = System.getProperty("line.separator"); + endChar = lineSeparator.charAt(lineSeparator.length() - 1); + } + + @Override + public void write(int b) throws IOException { + if (!firstLineOver) { + char c = (char) b; + if (c == endChar) { + firstLineOver = true; + } + } else { + out.write(b); + } + } + } +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/PluginHelper.java ___________________________________________________________________ Name: svn:mergeinfo + Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/SourceEntry.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/SourceEntry.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/SourceEntry.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/SourceEntry.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,261 @@ +/* +* *##% Plugin maven pour lutini18n + * Copyright (C) 2007 - 2008 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>. ##%* */ +package org.nuiton.i18n.plugin; + +import org.apache.maven.plugin.logging.Log; +import org.codehaus.plexus.util.DirectoryScanner; +import org.nuiton.util.FileUpdater; + +import java.io.File; +import java.lang.annotation.Annotation; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * A simple model for a sourceEntry represents by a basedir and includes and/or exlucdes pattern. + * <p/> + * The class offers the usefull method : + * {@link #getIncludedFiles(File, String[], String[])} + * <p/> + * to obtain the list of files from + * the {@link #basedir} directory which respects the {@link #includes} and/or + * {@link #excludes} patterns using an internal {@link DirectoryScanner} object. + * <p/> + * Note : <b>The class does not extends <code>DirectoryScanner</code> since we DO not want + * to expose his methods.</b> + * + * @author tony + */ +public class SourceEntry { + /** + * If you want to restrict use of the entry, set the class name goal to + * this property via {@link #setSpecificGoal(String)}. + * <p/> + * If let to <code>null</code>, all goals can use this entry. + */ + protected String specificGoal = null; + + protected File basedir; + + protected String[] includes; + protected String[] excludes; + /** Files to be find */ + protected String[] files; + + protected String[] skipFiles; + + protected String skipMessage; + + protected FileUpdater updater; + + public String[] getExcludes() { + return excludes; + } + + public void setExcludes(String[] excludes) { + this.excludes = excludes; + } + + public String[] getIncludes() { + return includes; + } + + public void setIncludes(String[] includes) { + this.includes = includes; + } + + public File getBasedir() { + return basedir; + } + + public void setBasedir(File basedir) { + this.basedir = basedir; + } + + public String getSpecificGoal() { + return specificGoal; + } + + public void setSpecificGoal(String specificGoal) { + this.specificGoal = specificGoal; + } + + public boolean useForGoal(String goal) { + return specificGoal == null || specificGoal.equalsIgnoreCase(goal); + } + + public boolean hasSrc() { + return basedir != null; + } + + public boolean hasIncludes() { + return includes != null && includes.length > 0; + } + + public boolean hasExcludes() { + return excludes != null && excludes.length > 0; + } + + /** + * Test if a file is up to date and not to be treated. + * <p/> + * + * @param file the file path to test + * @return <code>true</code> if file is up to date and do not need to be parsed + * @see FileUpdater + */ + public final boolean isFileUptodate(File file) { + return updater != null && updater.isFileUpToDate(file); + } + + public String[] getIncludedFiles(File defaultBasedir, String[] defaultIncludes, String[] defaultExcludes) { + // normalized entry + if (!hasSrc()) { + setBasedir(defaultBasedir); + } + if (!hasIncludes()) { + setIncludes(defaultIncludes); + } + if (!hasExcludes()) { + setExcludes(defaultExcludes); + } + // init directory scanner + DirectoryScanner ds = new DirectoryScanner(); + ds.setBasedir(getBasedir()); + ds.setIncludes(getIncludes()); + if (hasExcludes()) { + ds.setExcludes(getExcludes()); + } + // scan + ds.scan(); + // get found files + String[] foundFiles; + foundFiles = ds.getIncludedFiles(); + return foundFiles; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("basedir:").append(basedir); + if (includes != null) { + sb.append(", includes:").append(Arrays.toString(includes)); + } + if (excludes != null) { + sb.append(", excludes:").append(Arrays.toString(excludes)); + } + return sb.toString(); + } + + public String[] getIncludedFiles(File basedir, String[] defaultIncludes, String[] defaultExcludes, URLClassLoader loader, List<String> annotationClass, Log log) { + List<String> result = new ArrayList<String>(); + + for (String s : getIncludedFiles(basedir, defaultIncludes, defaultExcludes)) { + if (filterByAnnotation(s, loader, annotationClass, log)) { + result.add(s); + } + } + return result.toArray(new String[result.size()]); + } + + protected boolean filterByAnnotation(String file, URLClassLoader loader, List<String> annotationClass, Log log) { + + + Annotation annotation = getAnnotation(file, loader, annotationClass, log); + + boolean result = annotation != null; + + if (result && log.isDebugEnabled()) { + log.debug("find i18n annotated file : " + file); + } + return result; + } + + protected String getFQN(String file) { + String filePath = file; + filePath = filePath.substring(0, filePath.length() - ".java".length()); + String replaceEx = File.separator.equals("\\") ? "\\\\" : File.separator; + return filePath.replaceAll(replaceEx, "."); + } + + public Class<?> getClass(String file, URLClassLoader loader, Log log) { + String fqn = getFQN(file); + try { + return loader.loadClass(fqn); + + } catch (Throwable e) { + log.warn("could not find class " + fqn + " " + e); + return null; + } + } + + public Annotation getAnnotation(String file, URLClassLoader loader, List<String> annotationClass, Log log) { + + Class<?> currentClass = getClass(file, loader, log); + + try { + Annotation[] annos = currentClass.getAnnotations(); + if (annos != null && annos.length > 0) { + for (Annotation anno : annos) { + if (annotationClass.contains(anno.annotationType().getName())) { + return anno; + } + } + } + } catch (Throwable e) { + log.warn("could not find annotation for " + file + " " + e); + } + return null; + + } + + public Class<?> getClass(File file, URLClassLoader loader, Log log) { + String f = file.getAbsolutePath().substring(basedir.getAbsolutePath().length() + 1); + return getClass(f, loader, log); + } + + public Annotation getAnnotation(File file, URLClassLoader loader, List<String> annotationClass, Log log) { + String f = file.getAbsolutePath().substring(basedir.getAbsolutePath().length() + 1); + return getAnnotation(f, loader, annotationClass, log); + } + + public String getSkipMessage() { + return skipMessage; + } + + public String[] getFiles() { + return files; + } + + public String[] getSkipFiles() { + return skipFiles; + } + + public int getFoudFiles() { + return skipFiles.length + files.length; + } + + public FileUpdater getUpdater() { + return updater; + } + + public void setUpdater(FileUpdater updater) { + this.updater = updater; + } +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/SourceEntry.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:mergeinfo + Name: svn:eol-style + native Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/AbstractI18nParser.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/parser/AbstractI18nParser.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/AbstractI18nParser.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/AbstractI18nParser.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,378 @@ +/* +* *##% Plugin maven pour lutini18n + * Copyright (C) 2007 - 2008 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>. ##%* */ +package org.nuiton.i18n.plugin.parser; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.nuiton.i18n.plugin.AbstractI18nPlugin; +import org.nuiton.i18n.plugin.I18nLogger; +import org.nuiton.i18n.plugin.PluginHelper; +import org.nuiton.i18n.plugin.PluginHelper.I18nProperties; +import org.nuiton.i18n.plugin.SourceEntry; +import org.nuiton.i18n.plugin.parser.event.KeysModifier; +import org.nuiton.util.FileUpdater; +import org.nuiton.util.FileUtil; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Abstract implementation for parsing goal. + * + * @author tony + */ +public abstract class AbstractI18nParser extends AbstractI18nPlugin implements Parser { + + /** @return the outGetter to use for the instance (java.getter,...) */ + protected abstract String getOutGetter(); + + /** @return the starting regex expression to catch keys in key modifier */ + protected abstract String getKeyModifierStart(); + + /** @return the ending regex expression to catch keys in key modifier */ + protected abstract String getKeyModifierEnd(); + + /** @return the default includes to add to directory scanner */ + protected abstract String[] getDefaultIncludes(); + + /** @return the default excludes to add to directory scanner */ + protected abstract String[] getDefaultExcludes(); + + /** @return the default src directory to use in directory scanner */ + protected abstract File getDefaultBasedir(); + + public abstract FileUpdater newFileUpdater(SourceEntry entry); + + /** + * treate default entry + * + * @parameter expression="${i18n.treateDefaultEntry}" default-value="true" + */ + protected boolean treateDefaultEntry; + + /** + * Source entries (src+includes+excludes) . + * + * @parameter expression="${i18n.entries}" + */ + protected MySourceEntry[] entries; + + /** + * flag to display touched files while parsing. + * <p/> + * Note: the value will be always <code>true</code> if {@link #verbose} is set + * at <code>true</code>. + * + * @parameter expression="${i18n.showTouchedFiles}" default-value="${maven.verbose}" + * @since 0.9 + */ + protected boolean showTouchedFiles; + /** + * flag to save at eachfile treated the getter file + * + * @parameter expression="${i18n.safeMode}" default-value="false" + * @since 0.9 + */ + protected boolean safeMode; + + protected I18nProperties result; + + protected I18nProperties oldParser; + + protected I18nProperties oldLanguage; + protected int fileTreated = 0; + protected long t0; + + protected boolean touchFile; + protected List<File> treadedFiles; + + @Override + public void init() { + super.init(); + t0 = System.nanoTime(); + result = new I18nProperties(encoding); + oldParser = new I18nProperties(encoding); + oldLanguage = new I18nProperties(encoding); + out.mkdirs(); + // evenements + if (keysModifier) { + addParserEvent(KeysModifier.getInstance(getKeyModifierStart(), getKeyModifierEnd(), encoding)); + } + treadedFiles = new ArrayList<File>(); + if (verbose) { + showTouchedFiles = true; + } + } + + + /* + * (non-Javadoc) + * @see org.apache.maven.plugin.AbstractMojo#execute() + */ + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + + init(); + if (entries == null || entries.length == 0 && !treateDefaultEntry) { + // nothing to do + return; + } + + if (safeMode) { + getLog().info("config - safeMode is on (could be slower)."); + } + if (strictMode) { + getLog().info("config - strictMode is on (all files will be parsed)."); + } + + try { + // Reprise sur un ancien parsing + File oldParserFile = PluginHelper.getGetterFile(out, getOutGetter(), true); + File saveFile = PluginHelper.getGetterFileBackup(out, getOutGetter()); + + oldParser.load(oldParserFile); + FileUtil.copy(oldParserFile, saveFile); + + // Anciennes cles disponnibles + //fixme : pourquoi on utilise un bundle precis ? le premier ici, je ne comprends pas + File oldLanguageFile = PluginHelper.getI18nFile(src, artifactId, locales[0], true); + + oldLanguage.load(oldLanguageFile); + + // Parsing + parse(); + + // Suppression du fichier sauvegarder + saveFile.delete(); + + int i = treadedFiles.size(); + if (fileTreated == 0) { + getLog().info("Nothing to generate - all files are up to date."); + } else { + getLog().info(getVerboseLog().getLogEntry("parsing is done. [treated file(s) : " + i + '/' + fileTreated + "]", fileTreated, 0, t0)); + addGetter(); + } + + } catch (Exception e) { + getLog().error("Error code parsing ", e); + throw new MojoFailureException("Error code parsing"); + } + + } + + /** + * launch the parse on every given entries. + * + * @throws IOException if any io pb + */ + @Override + public void parse() throws IOException { + if (treateDefaultEntry) { + addDefaultEntry(); + } + long t00 = System.nanoTime(); + for (MySourceEntry entry : this.entries) { + I18nLogger vLog = getVerboseLog(); + + vLog.setEntry(entry); + + boolean skip = entry.init(this); + + if (skip) { + if (verbose) { + getLog().info("skip - " + entry.getSkipMessage()); + } + continue; + } + + long t000 = System.nanoTime(); + int nbFiles = entry.getFiles().length; + if (verbose) { + vLog.infoEntry("start", vLog.getLogEntry("[incoming file(s) : " + entry.getFoudFiles() + "]", 0, 0, 0)); + } + + // launch parser for found files + parseEntry(entry); + + if (verbose) { + // log skipped files + for (String skipFile : entry.getSkipFiles()) { + vLog.setFile( new File(entry.getBasedir(), skipFile)); + vLog.infoFile("skip", null); + } + } + fileTreated += nbFiles; + if (verbose) { + vLog.infoEntry("end", vLog.getLogEntry("[treated file(s) : " + nbFiles + "]", nbFiles, t000, t00)); + } + t00 = System.nanoTime(); + } + } + + + /** + * Add the default entry to entries given in configuration. + * <p/> + * This is a convinient method to simplify the configuration of the plugin. + */ + protected void addDefaultEntry() { + List<MySourceEntry> list; + + if (entries == null || entries.length == 0) { + list = new ArrayList<MySourceEntry>(); + } else { + list = new ArrayList<MySourceEntry>(Arrays.asList(entries)); + } + list.add(new MySourceEntry()); + entries = list.toArray(new MySourceEntry[list.size()]); + } + + /** + * launch parsing on a given entry. + * + * @param entry currentEntry to treate + * @throws IOException if any io pb. + */ + protected final void parseEntry(SourceEntry entry) throws IOException { + long t00 = System.nanoTime(); + String[] files = entry.getFiles(); + int beforeEntryResultSize = result.size(); + for (int i = 0, max = files.length; i < max; i++) { + String file1 = files[i]; + long t000 = System.nanoTime(); + String fileName = entry.getBasedir().getAbsolutePath() + File.separator + file1; + File file = new File(fileName); + for (ParserEvent event : events) { + event.eventChangeFile(file); + } + I18nLogger vLog = getVerboseLog(); + vLog.setFile(file); + + touchFile = false; + int size = result.size(); + if (verbose) { + vLog.infoFile("parse", null); + } + parseFile(file); + + //TC-20090214 pour des questions de performance, on ne sauvegarde pas + // a chaque traitement de fichier, les clefs mais une fois pour chaque + // source entry + // Detection de nouvelles cles, sauvegarde du fichier pour pouvoir le restaurer en cas de plantage + if (safeMode) { + if (size != result.size()) { + saveGetterFile(); + } + } + if (touchFile) { + if (showTouchedFiles) { + vLog.infoFile("touch", null); + } + treadedFiles.add(file); + if (getLog().isDebugEnabled()) { + vLog.debug(vLog.getLogEntry(fileName, i, t000, t00)); + } + } + for (ParserEvent event : events) { + event.eventNextFile(file); + } + } + + if (!safeMode && beforeEntryResultSize < result.size()) { + // Detection de nouvelles cles, sauvegarde du fichier + saveGetterFile(); + } + } + + /** + * Save the result in the getter file. + * + * @throws IOException if any io pb + */ + protected void saveGetterFile() throws IOException { + File getterFile = PluginHelper.getGetterFile(out, getOutGetter(), false); + result.store(getterFile); + } + + + public static class MySourceEntry extends SourceEntry { + + public boolean init(AbstractI18nParser mojo) { + if (!useForGoal(mojo.getClass().getSimpleName())) { + // skip not for this goal + skipMessage = "exclude for this goal."; + return true; + } + + String[] filesForEntry = getFilesForEntry(mojo); + + if (filesForEntry.length == 0) { + // skip no file found + skipMessage = "no file found."; + return true; + } + setUpdater(mojo.newFileUpdater(this)); + + if (mojo.strictMode || updater == null) { + // mojo strict mode or not updater, so force all files + skipFiles = new String[0]; + this.files = filesForEntry; + return false; + } + + List<String> listFiles = new ArrayList<String>(); + List<String> listSkipFiles = new ArrayList<String>(); + + // test if have any file + for (String foundFile : filesForEntry) { + File file = new File(getBasedir(), foundFile); + if (isFileUptodate(file)) { + listSkipFiles.add(foundFile); + } else { + listFiles.add(foundFile); + } + } + boolean todo = !listFiles.isEmpty(); + if (!todo) { + // skip, no file out-of -date + skipMessage = "all files are up to date."; + this.skipFiles = listSkipFiles.toArray(new String[listSkipFiles.size()]); + this.files = new String[0]; + return true; + } + this.skipFiles = listSkipFiles.toArray(new String[listSkipFiles.size()]); + this.files = listFiles.toArray(new String[listFiles.size()]); + return false; + } + + + /** + * Obtain all the relative path of files to treate for a given entry. + * + * @param mojo the given mojo + * @return the list of relative path of files for the given entry + */ + protected String[] getFilesForEntry(AbstractI18nParser mojo) { + return getIncludedFiles(mojo.getDefaultBasedir(), mojo.getDefaultIncludes(), mojo.getDefaultExcludes()); + } + + } +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/AbstractI18nParser.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:mergeinfo + Name: svn:eol-style + native Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/Parser.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/parser/Parser.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/Parser.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/Parser.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,55 @@ +/* + * *##% Plugin maven pour lutini18n + * Copyright (C) 2007 - 2008 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>. ##%* */ + +package org.nuiton.i18n.plugin.parser; + +import java.io.File; +import java.io.IOException; + +/** + * Interface type pour la définition d'un nouveau parser. + * <p/> + * Une implantation abstraite est proposée : {@link AbstractI18nParser}. + * + * @author julien + */ +public interface Parser { + + /** + * Lancement du parser + * + * @throws java.io.IOException if any io pb + */ + public void parse() throws IOException; + + /** + * Parse sur un fichier + * + * @param file le fichier à parser + */ + public void parseFile(File file); + + /** + * Parse une partie du fichier + * + * @param file le fichier à parser + * @param args ? TODO + */ + public void parseLine(File file, String args); + +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/Parser.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:mergeinfo + Name: svn:eol-style + native Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/ParserEvent.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/parser/ParserEvent.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/ParserEvent.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/ParserEvent.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,59 @@ +/* + * *##% Plugin maven pour lutini18n + * Copyright (C) 2007 - 2008 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>. ##%* */ + +package org.nuiton.i18n.plugin.parser; + +import java.io.File; + +/** + * Permet d'ajouter des évènements sur les parsers + * + * @author julien + */ +public interface ParserEvent { + + /** + * M�thode appelée quand on change de fichier parsé + * + * @param file + */ + public void eventChangeFile(File file); + + /** + * Méthode appelée après le parsing du fichier + * + * @param file + */ + public void eventNextFile(File file); + + /** + * M�thode appelée quand on change de clé + * + * @param keyI18n + * @param newKey + */ + public void eventChangeKey(String keyI18n, boolean newKey); + + /** + * M�thode appelée pour récupérer la nouvelle valeur de clé + * + * @return + */ + public String eventGetRealKey(); + +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/ParserEvent.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:mergeinfo + Name: svn:eol-style + native Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/ParserException.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/parser/ParserException.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/ParserException.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/ParserException.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,45 @@ +/* + * *##% Plugin maven pour lutini18n + * Copyright (C) 2007 - 2008 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>. ##%* */ + +package org.nuiton.i18n.plugin.parser; + +/** + * Permet la gestion des exceptions dans les parsers et dans les évènements + * + * @author julien + */ +public class ParserException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public ParserException() { + super(); + } + + public ParserException(String message, Throwable cause) { + super(message, cause); + } + + public ParserException(String message) { + super(message); + } + + public ParserException(Throwable cause) { + super(cause); + } +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/ParserException.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:mergeinfo + Name: svn:eol-style + native Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/event/KeysModifier.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/parser/event/KeysModifier.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/event/KeysModifier.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/event/KeysModifier.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,219 @@ +/* + * *##% Plugin maven pour lutini18n + * Copyright (C) 2007 - 2008 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>. ##%* */ + +package org.nuiton.i18n.plugin.parser.event; + +import org.nuiton.i18n.plugin.parser.ParserEvent; +import org.nuiton.i18n.plugin.parser.ParserException; +import org.nuiton.util.FileUtil; + +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JTextField; +import java.awt.Container; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * IHM permettant de modifier les clés de traduction en direct dans les fichiers + * parsés et les fichiers de propriétés. + * + * @author julien + */ +public class KeysModifier extends JFrame implements ParserEvent { + + private static final long serialVersionUID = 1L; + + // Modification des clés dans le fichier + protected List<String> newKeys; + protected boolean needModifiedFile; + protected String patternLeft; + protected String patternRight; + protected String encoding; + + // Interface + protected JLabel name = new JLabel(); + protected JLabel path = new JLabel(); + protected JTextField key = new JTextField(); + protected JTextField pattern = new JTextField(".*"); + protected JCheckBox onlyNewKey = new JCheckBox(); + + + protected JButton next = new JButton("Next >>"); + private static KeysModifier keysModifier; + + /** + * Récupération d'une instance de l'interface + * + * @param patternLeft left pattern + * @param patternRight right pattern + * @param encoding encoding + * @return the shared instance with new config + */ + public static KeysModifier getInstance(String patternLeft, String patternRight, String encoding) { + if (keysModifier == null) { + keysModifier = new KeysModifier(); + } + + + keysModifier.encoding = encoding; + keysModifier.patternLeft = patternLeft; + keysModifier.patternRight = patternRight; + + return keysModifier; + } + + /** Contructeur de l'interface */ + private KeysModifier() { + setLayout(new GridLayout(9, 2, 10, 10)); + + Container pane = getContentPane(); + pane.add(new JLabel("--- File information ---")); + pane.add(new JLabel()); + + pane.add(new JLabel("Name :")); + pane.add(name); + + pane.add(new JLabel("Path : ")); + pane.add(path); + + pane.add(new JLabel("--- Files language ---")); + pane.add(new JLabel()); + + pane.add(new JLabel("Key :")); + pane.add(key); + + pane.add(new JLabel("--- Filters ---")); + pane.add(new JLabel()); + + pane.add(new JLabel("Pattern :")); + pane.add(pattern); + + pane.add(new JLabel("Only new key :")); + pane.add(onlyNewKey); + + pane.add(new JLabel()); + pane.add(next); + + next.addActionListener(new EventNextKey()); + addWindowListener(new EventWindows()); + + setTitle("Keys modifier"); + setSize(800, 400); +// pack(); + setVisible(true); + } + + @Override + public void eventChangeFile(File file) { + name.setText(file.getName()); + path.setText(file.getPath()); + key.setText(""); + repaint(); + + newKeys = new ArrayList<String>(); + needModifiedFile = false; + } + + @Override + public void eventNextFile(File file) { + if (needModifiedFile) { + String content; + int region = 0; + + try { + content = FileUtil.readAsString(file, encoding); + } catch (IOException e) { + throw new ParserException(e); + } + + for (Iterator<String> iterator = newKeys.iterator(); iterator.hasNext();) { + String oldKey = iterator.next(); + String realKey = iterator.next(); + Pattern p = Pattern.compile("(" + patternLeft + ")(" + Pattern.quote(oldKey) + ")(" + patternRight + ")"); + Matcher matcher = p.matcher(content); + matcher.region(region, content.length()); + matcher.find(); + region = matcher.start(); + content = matcher.replaceFirst("$1" + realKey + "$3"); + } + + try { + FileUtil.writeString(file, content, encoding); + } catch (IOException e) { + throw new ParserException(e); + } + } + } + + @Override + public synchronized void eventChangeKey(String keyI18n, boolean newKey) { + key.setText(keyI18n); + newKeys.add(key.getText()); + repaint(); + if (isVisible() && keyI18n.matches(pattern.getText()) && (!onlyNewKey.isSelected() || newKey)) { + try { + wait(); + } catch (InterruptedException e) { + throw new ParserException(e); + } + } + } + + @Override + public String eventGetRealKey() { + newKeys.add(key.getText()); + needModifiedFile |= !newKeys.get(newKeys.size() - 1).equals(newKeys.get(newKeys.size() - 2)); + return key.getText(); + } + + /** Action sur le boutton pour passer � la cl� suivante */ + class EventNextKey implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + eventNextKey(); + } + } + + /** Action sur la fermeture de la frame */ + class EventWindows extends WindowAdapter { + + @Override + public void windowClosing(WindowEvent e) { + setVisible(false); + eventNextKey(); + } + } + + /** Permet de passer à la clé suivante */ + public synchronized void eventNextKey() { + notifyAll(); + } +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/event/KeysModifier.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:mergeinfo + Name: svn:eol-style + native Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJava.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/parser/impl/ParserJava.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJava.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJava.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,164 @@ +/* + * *##% Plugin maven pour lutini18n + * Copyright (C) 2007 - 2008 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>. ##%* */ + +package org.nuiton.i18n.plugin.parser.impl; + +import org.apache.maven.project.MavenProject; +import org.nuiton.i18n.plugin.SourceEntry; +import org.nuiton.i18n.plugin.parser.AbstractI18nParser; +import org.nuiton.i18n.plugin.parser.ParserEvent; +import org.nuiton.i18n.plugin.parser.ParserException; +import org.nuiton.util.FileUpdater; +import org.nuiton.util.FileUpdaterHelper; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.io.LineNumberReader; +import org.nuiton.processor.filters.I18nFilter; + +/** + * Récupération des chaine a traduire depuis les fichiers java. + * + * @author julien + * @goal parserJava + * @phase generate-resources + */ +public class ParserJava extends AbstractI18nParser { + + /** + * Source entries (src+includes+excludes) . + * + * @parameter expression="${i18n.defaultIncludes}" default-value="**\\/*.java" + */ + protected String defaultIncludes; + + /** + * default src for an entry. + * + * @parameter expression="${i18n.defaultBasedir}" default-value="${basedir}/src/main/java" + */ + protected File defaultBasedir; + + /** + * Dependance du projet. + * + * @parameter default-value="${project}" + * @readonly + */ + protected MavenProject project; + + /** + * Repertoire sources des fichiers i18n. + * + * @parameter expression="${i18n.cp}" default-value="${basedir}/target/classes" + * @required + */ + protected File cp; + + @Override + public String[] getDefaultIncludes() { + return new String[]{defaultIncludes}; + } + + @Override + public String[] getDefaultExcludes() { + return new String[]{}; + } + + @Override + public File getDefaultBasedir() { + return defaultBasedir; + } + + @Override + public FileUpdater newFileUpdater(SourceEntry entry) { + return FileUpdaterHelper.newJavaFileUpdater(entry.getBasedir(), cp); + } + + @Override + protected String getKeyModifierStart() { + return "_\\(\\s*\""; + } + + @Override + protected String getKeyModifierEnd() { + return "\"\\s*(\\)|,|\\+|$)"; + } + + @Override + protected String getOutGetter() { + return "java.getter"; + } + + protected I18nFilter filter; + + @Override + public void init() { + super.init(); + filter = new I18nFilter(); + } + + @Override + public void parseFile(File srcFile) { + LineNumberReader lnr=null; + String line=null; + try { + lnr = new LineNumberReader(new InputStreamReader(new FileInputStream(srcFile))); + + while (lnr.ready()) { + line = lnr.readLine(); + parseLine(srcFile, line); + } + + } catch (Exception e) { + if (line!=null) { + getLog().error("could not parse line "+line); + } + throw new ParserException(e); + } + } + + /* + * (non-Javadoc) + * @see org.codelutin.i18n.plugin.core.Parser#parseLine(java.io.File, java.lang.String) + */ + @Override + public void parseLine(File srcFile, String line) { + String keysSet = filter.parse(line); + + if (!keysSet.equals(I18nFilter.EMPTY_STRING)) { + touchFile = true; + // Found a set of i18n Strings, split it. + String[] keys = keysSet.split("="); + for (String key : keys) { + String keyModified = key; + for (ParserEvent event : events) { + event.eventChangeKey(key, !oldLanguage.containsKey(key)); + keyModified = event.eventGetRealKey(); + } + if (oldParser.containsKey(key)) { + result.put(keyModified, oldParser.get(key)); + } else { + result.put(keyModified, key); + } + } + } + } + +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJava.java ___________________________________________________________________ Name: svn:executable + * Name: svn:keywords + Author Date Id Revision Name: svn:mergeinfo + Name: svn:eol-style + native Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaActionConfig.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/parser/impl/ParserJavaActionConfig.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaActionConfig.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaActionConfig.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,87 @@ +/* +* *##% Plugin maven pour lutini18n + * Copyright (C) 2007 - 2008 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>. ##%* */ +package org.nuiton.i18n.plugin.parser.impl; + +import org.nuiton.i18n.plugin.parser.ParserEvent; + +import java.io.File; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Un parseur java pour scanner les annotations ActionConfig + * + * @author chemit + * @goal parserJavaActionConfig + * @phase generate-resources + */ +public class ParserJavaActionConfig extends ParserJava { + + protected static final Pattern MATCH_PATTERN = Pattern.compile("(name|shortDescription|longDescription|name2|shortDescription2|longDescription2)\\s*=\\s*\"([\\w|\\.]+)\"(|\\s*|\\s*,\\s*$)"); + + @Override + protected String getKeyModifierStart() { + return "[\\w|\\.]+\\s*=\\s*\""; + } + + @Override + protected String getKeyModifierEnd() { + return "\"\\s*(\\)|,|\\+|$)"; + } + + @Override + protected String getOutGetter() { + return "java-action-config.getter"; + } + + /* + * (non-Javadoc) + * @see org.codelutin.i18n.plugin.extension.XmlParser#extract(java.lang.String) + */ + + public String extract(String i18nString) { + Matcher matcher = MATCH_PATTERN.matcher(i18nString.trim()); + if (matcher.matches()) { + return matcher.group(2); + } + return null; + } + + /* + * (non-Javadoc) + * @see org.codelutin.i18n.plugin.core.Parser#parseLine(java.io.File, java.lang.String) + */ + @Override + public void parseLine(File srcFile, String line) { + String key = extract(line); + if (key != null) { + touchFile = true; + String keyModified = key; + for (ParserEvent event : events) { + event.eventChangeKey(key, !oldLanguage.containsKey(key)); + keyModified = event.eventGetRealKey(); + } + if (oldParser.containsKey(key)) { + result.put(keyModified, oldParser.get(key)); + } else { + result.put(keyModified, key); + } + } + } + +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaActionConfig.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:mergeinfo + Name: svn:eol-style + native Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaTabConfig.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/parser/impl/ParserJavaTabConfig.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaTabConfig.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaTabConfig.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,35 @@ +/** + * *##% Plugin maven pour lutini18n + * Copyright (C) 2007 - 2008 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>. ##%* + */ +package org.nuiton.i18n.plugin.parser.impl; + +/** + * Un parseur java pour scanner les annotations TabContentConfig. + * + * @author chemit + * @goal parserJavaTabConfig + * @phase generate-resources + */ +public class ParserJavaTabConfig extends ParserJavaActionConfig { + + @Override + protected String getOutGetter() { + return "java-tab-config.getter"; + } + +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaTabConfig.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:mergeinfo + Name: svn:eol-style + native Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJaxx.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/parser/impl/ParserJaxx.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJaxx.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJaxx.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,110 @@ +/* + * *##% Plugin maven pour lutini18n + * Copyright (C) 2007 - 2008 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>. ##%* */ + +package org.nuiton.i18n.plugin.parser.impl; + +import org.nuiton.i18n.plugin.SourceEntry; +import org.nuiton.util.FileUpdater; +import org.nuiton.util.FileUpdaterHelper; + +import java.io.File; + +/** + * Récupération des chaine à traduire depuis les fichiers xml Jaxx. + * + * @author julien + * @goal parserJaxx + * @phase generate-resources + */ +public class ParserJaxx extends ParserXml { + + /** + * Source entries (src+includes+excludes) . + * + * @parameter expression="${i18n.defaultIncludes}" default-value="**\\/*.jaxx" + */ + protected String defaultIncludes; + + /** + * Where jaxx files should have been generated. + * + * @parameter expression="${i18n.defaultGenerateBasedir}" default-value="${basedir}/target/generated-sources/java" + */ + protected File defaultGenerateBasedir; + + /** + * Regles xml. + * + * @parameter expression="${i18n.rulesJaxx}" default-value="jaxx.rules" + */ + protected String rulesJaxx; + + @Override + public String[] getDefaultIncludes() { + return new String[]{defaultIncludes}; + } + + @Override + public String[] getDefaultExcludes() { + return new String[]{}; + } + + @Override + public FileUpdater newFileUpdater(SourceEntry entry) { + return FileUpdaterHelper.newJavaFileUpdater(entry.getBasedir(), defaultGenerateBasedir); + } + + @Override + protected String getOutGetter() { + return "jaxx.getter"; + } + + @Override + protected String getKeyModifierStart() { + return "=\\s*[\"\']"; + } + + @Override + protected String getKeyModifierEnd() { + return "[\"\']"; + } + + @Override + protected String getFileRules() { + return rulesJaxx; + } + + @Override + protected String getCoreFileRules() { + return "jaxx.rules"; + } + + public void setRulesJaxx(String rulesJaxx) { + this.rulesJaxx = rulesJaxx; + } + + /* + * (non-Javadoc) + * @see org.codelutin.i18n.plugin.extension.XmlParser#extract(java.lang.String) + */ + @Override + public String extract(String i18nString) { + return i18nString.length() == 0 ? null : i18nString; + } + +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJaxx.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:mergeinfo + Name: svn:eol-style + native Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserSwixat.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/parser/impl/ParserSwixat.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserSwixat.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserSwixat.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,102 @@ +/* + * *##% Plugin maven pour lutini18n + * Copyright (C) 2007 - 2008 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>. ##%* */ + +package org.nuiton.i18n.plugin.parser.impl; + +import org.nuiton.i18n.plugin.SourceEntry; +import org.nuiton.util.FileUpdater; + +/** + * Recuperation des chaines à traduire depuis les fichiers xml Swixat. + * + * @author julien + * @goal parserSwixat + * @phase generate-resources + */ +public class ParserSwixat extends ParserXml { + + /** + * Source entries (src+includes) . + * + * @parameter expression="${i18n.defaultIncludes}" default-value="**\\/*.xml" + */ + protected String defaultIncludes; + + /** + * Source entries (src+excludes) . + * + * @parameter expression="${i18n.defaultIncludes}" default-value="**\\/context.xml" + */ + protected String defaultExcludes; + + /** + * Regles xml. + * + * @parameter expression="${i18n.rulesSwixat}" default-value="swixat.rules" + */ + protected String rulesSwixat; + + @Override + public String[] getDefaultIncludes() { + return new String[]{defaultIncludes}; + } + + @Override + public String[] getDefaultExcludes() { + return new String[]{defaultExcludes}; + } + + @Override + public FileUpdater newFileUpdater(SourceEntry entry) { + return null; + } + + @Override + protected String getKeyModifierStart() { + return "=\\s*[\"\']"; + } + + @Override + protected String getKeyModifierEnd() { + return "[\"\']"; + } + + @Override + protected String getOutGetter() { + return "swixat.getter"; + } + + @Override + protected String getFileRules() { + return rulesSwixat; + } + + @Override + protected String getCoreFileRules() { + return "swixat.rules"; + } + + /* + * (non-Javadoc) + * @see org.codelutin.i18n.plugin.extension.XmlParser#extract(java.lang.String) + */ + @Override + public String extract(String i18nString) { + return i18nString; + } +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserSwixat.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:mergeinfo + Name: svn:eol-style + native Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserValidation.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/parser/impl/ParserValidation.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserValidation.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserValidation.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,140 @@ +/* + * *##% Plugin maven pour lutini18n + * Copyright (C) 2007 - 2008 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>. ##%* */ + +package org.nuiton.i18n.plugin.parser.impl; + +import org.nuiton.i18n.plugin.SourceEntry; +import org.nuiton.util.FileUpdater; +import org.nuiton.util.MirroredFileUpdater; + +import java.io.File; + +/** + * Récupération des chaine à traduire depuis les fichiers xml de validation. + * <p/> + * Le goal doit etre execute avant que les resources soient copiees dans target/classes + * pour rendre operatne le file updater (sinon lesfichiers sont toujours a jour...) + * + * @author chemit + * @goal parserValidation + * @phase generate-resources + */ +public class ParserValidation extends ParserXml { + + /** + * Source entries (src+includes+excludes) . + * + * @parameter expression="${i18n.defaultIncludes}" default-value="**\\/**-validation.xml" + */ + protected String defaultIncludes; + + /** + * Where jaxx files should have been generated. + * + * @parameter expression="${i18n.cp}" default-value="${basedir}/target/classes" + */ + protected File cp; + + /** + * Regles xml. + * + * @parameter expression="${i18n.rulesValidation}" default-value="validation.rules" + */ + protected String rulesValidation; + + /** + * default src for an entry. + * + * @parameter expression="${i18n.defaultBasedir}" default-value="${basedir}/src/main/resources" + * @required + */ + protected File defaultBasedir; + + @Override + public String[] getDefaultIncludes() { + return new String[]{defaultIncludes}; + } + + @Override + public String[] getDefaultExcludes() { + return new String[]{}; + } + + @Override + public File getDefaultBasedir() { + return defaultBasedir; + } + + @Override + public FileUpdater newFileUpdater(SourceEntry entry) { + return new MirroredFileUpdater("","",entry.getBasedir(), this.cp) { + @Override + public File getMirrorFile(File f) { + String file = f.getAbsolutePath().substring(this.prefixSourceDirecotory); + return new File(this.destinationDirectory + File.separator + file); + } + }; + } + + @Override + protected String getOutGetter() { + return "validation.getter"; + } + + @Override + protected String getKeyModifierStart() { + return "=\\s*[\"\']"; + } + + @Override + protected String getKeyModifierEnd() { + return "[\"\']"; + } + + @Override + protected String getFileRules() { + return rulesValidation; + } + + @Override + protected String getCoreFileRules() { + return "validation.rules"; + } + + public void setRulesJaxx(String rulesJaxx) { + this.rulesValidation = rulesJaxx; + } + + @Override + public String extract(String i18nString) { + String s = null; + if (!i18nString.trim().isEmpty()) { + s = i18nString.trim(); + int end = s.indexOf("##"); + if (end >0) { + // remove params from key + s = s.substring(0,end); + } + } + if (getLog().isDebugEnabled()) { + getLog().debug(i18nString + " = " + s); + } + return s; + } + +} \ No newline at end of file Copied: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserXml.java (from rev 1522, maven-i18n-plugin/trunk/src/main/java/org/codelutin/i18n/plugin/parser/impl/ParserXml.java) =================================================================== --- maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserXml.java (rev 0) +++ maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserXml.java 2009-05-13 20:32:34 UTC (rev 1537) @@ -0,0 +1,224 @@ +/* + * *##% Plugin maven pour lutini18n + * Copyright (C) 2007 - 2008 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>. ##%* */ + +package org.nuiton.i18n.plugin.parser.impl; + +import org.nuiton.i18n.plugin.parser.AbstractI18nParser; +import org.nuiton.i18n.plugin.parser.ParserEvent; +import org.nuiton.i18n.plugin.parser.ParserException; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathFactory; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +/** + * Récupération des chaines à traduire depuis les fichiers xml. + * + * @author julien + */ +public abstract class ParserXml extends AbstractI18nParser { + + /** Taille du buffer pour les lectures/écritures */ + protected static final int BUFFER_SIZE = 8 * 1024; + + /** + * default src for an entry. + * + * @parameter expression="${i18n.defaultBasedir}" default-value="${basedir}/src/main/uimodel" + * @required + */ + protected File defaultBasedir; + + protected String rules; + protected XPathFactory factory; + protected XPath xpath; + + /** + * Fonction d'extraction de la chaine + * + * @param i18nString le clef i18n + * @return la chaine + */ + public abstract String extract(String i18nString); + + /** @return le fichier des rules */ + protected abstract String getFileRules(); + + /** @return le fichier des rules de base à toujours charger */ + protected abstract String getCoreFileRules(); + + @Override + public void init() { + super.init(); + this.factory = XPathFactory.newInstance(); + this.rules = getRules(getFileRules()); + this.xpath = factory.newXPath(); + } + + @Override + public void parseFile(File file) { + NodeList list; + InputSource inputSource = new InputSource(file.getAbsolutePath()); // TODO: A deplacer pour les performances + + try { + int size = result.size(); + + // Recherche des clés à partir d'un xpath + XPathExpression expression = xpath.compile(rules); + list = (NodeList) expression.evaluate(inputSource, XPathConstants.NODESET); + + for (int index = 0; index < list.getLength(); index++) { + Node node = list.item(index); + parseLine(file, node.getTextContent()); + } + if (safeMode) { + // Détection de nouvelles clés, sauvegarde du fichier pour pouvoir le restaurer en cas de plantage + if (size != result.size()) { + saveGetterFile(); + } + } + } catch (Exception e) { + throw new ParserException(e); + } + } + + @Override + public void parseLine(File file, String key) { + key = extract(key); + if (key != null) { + touchFile = true; + String keyModified = key; + for (ParserEvent event : events) { + event.eventChangeKey(key, !oldLanguage.containsKey(key)); + keyModified = event.eventGetRealKey(); + } + + if (oldParser.containsKey(key)) { + result.put(keyModified, oldParser.get(key)); + } else { + result.put(keyModified, key); + } + } + } + + @Override + public File getDefaultBasedir() { + return defaultBasedir; + } + + /** + * Récupère le xpath à partir d'un fichier + * + * @param fileRules le nom du fichier contant les règles + * @return le xpath à partir d'un fichier + */ + private String getRules(String fileRules) { + StringBuilder buffer = new StringBuilder(); + + try { + String readInputStream; + + // load core rules + readInputStream = loadRulesFile(getCoreFileRules()); + if (verbose) { + getLog().info("core rules : " + getCoreFileRules()); + } + buffer.append(readInputStream); + + if (!fileRules.equals(getCoreFileRules())) { + // add custom rules + readInputStream = loadRulesFile(fileRules); + if (verbose) { + getLog().info("custom rules : " + fileRules); + } + buffer.append(" | ").append(readInputStream); + } + } catch (IOException e) { + throw new ParserException(e); + } + + return buffer.toString(); + } + + private String loadRulesFile(String fileRules) throws IOException { + File f = new File(fileRules); + + InputStream inputStream; + if (f.exists()) { + // load from a file + try { + inputStream = new FileInputStream(f); + } catch (FileNotFoundException e) { + throw new ParserException(e); + } + } else { + // load from classpath + ClassLoader classLoader = getClass().getClassLoader(); + inputStream = classLoader.getResourceAsStream(fileRules); + } + if (inputStream == null) { + throw new ParserException("could not found file of rules : " + fileRules); + } + + inputStream = new BufferedInputStream(inputStream); + + try { + // Lecture + String readInputStream; + readInputStream = readInputStream(inputStream); + return readInputStream; + } catch (IOException e) { + throw new ParserException(e); + } finally { + inputStream.close(); + } + } + + /** + * Permet la lecture d'un InputStream et Suppressions. + * + * @param in le flux entrant + * @return le contenu du flux + * @throws IOException si problème de lecture dans flux entrant + */ + private String readInputStream(InputStream in) throws IOException { + StringBuilder sb = new StringBuilder(); + byte[] buffer = new byte[BUFFER_SIZE]; + while (in.read(buffer, 0, BUFFER_SIZE) != -1) { + String tmp = new String(buffer); + sb.append(tmp); + } + in.close(); + // Suppression + String txt = sb.toString().trim(); + txt = txt.replaceAll("#.*\n", ""); // suppression des commentaires + txt = txt.replaceAll("\\s+", " | "); // contruction du xpath avec des ou + txt = txt.replaceAll("(^ \\| )|( \\| $)", ""); // suppression des ou de début ee fin + return txt; + } +} Property changes on: maven-i18n-plugin/trunk/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserXml.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:mergeinfo + Name: svn:eol-style + native Modified: maven-i18n-plugin/trunk/src/site/site.xml =================================================================== --- maven-i18n-plugin/trunk/src/site/site.xml 2009-05-13 20:31:49 UTC (rev 1536) +++ maven-i18n-plugin/trunk/src/site/site.xml 2009-05-13 20:32:34 UTC (rev 1537) @@ -4,9 +4,9 @@ <publishDate format="dd/MM/yyyy"/> <skin> - <groupId>org.codelutin</groupId> - <artifactId>maven-lutin-skin</artifactId> - <version>0.2.3</version> + <groupId>org.codelutin</groupId> + <artifactId>maven-lutin-skin</artifactId> + <version>0.2.3</version> </skin> <bannerLeft> @@ -29,12 +29,13 @@ <body> <links> <item name="Labs" href="http://labs.libre-entreprise.org/"/> + <item name="Nuiton" href="http://www.nuiton.org"/> <item name="${project.organization.name}" href="${project.organization.url}"/> </links> <menu name="Utilisateur"> <item name="Introduction" href="index.html"/> - <item name="Goals" href="plugin-info.html"> + <item name="Goals" href="plugin-info.html"> <item name="parserJava" href="parserJava-mojo.html"/> <item name="parserJaxx" href="parserJaxx-mojo.html"/> <item name="parserSwixat" href="parserSwixat-mojo.html"/> @@ -46,20 +47,14 @@ <item name="bundle" href="bundle-mojo.html"/> <item name="help" href="help-mojo.html"/> </item> - <item name="Usage" href="usage.html"/> - <item name="FAQ" href="faq.html"/> </menu> - <menu name="Examples"> - <item name="To be done" /> - <!--item name="To be done" href="/examples/describe-configuration.html"/--> - </menu> <menu name="Téléchargement"> - <item href="${labs.builder.url}/org/codelutin/${project.artifactId}/${project.version}/${project.build.finalName}.jar" + <item href="${repository.home.url}/org/nuiton/${project.artifactId}/${project.version}/${project.build.finalName}.jar" name="Librairie (jar)"/> - <item href="${labs.builder.url}/org/codelutin/${project.artifactId}/${project.version}/${project.build.finalName}-javadoc.jar" + <item href="${repository.home.url}/org/nuiton/${project.artifactId}/${project.version}/${project.build.finalName}-javadoc.jar" name="Javadoc (jar)"/> - <item href="${labs.builder.url}/org/codelutin/${project.artifactId}/${project.version}/${project.build.finalName}-sources.jar" + <item href="${repository.home.url}/org/nuiton/${project.artifactId}/${project.version}/${project.build.finalName}-sources.jar" name="Sources (jar)"/> </menu>
participants (1)
-
tchemit@users.labs.libre-entreprise.org