com.github.jknack.handlebars.maven.I18nJsPlugin.java Source code

Java tutorial

Introduction

Here is the source code for com.github.jknack.handlebars.maven.I18nJsPlugin.java

Source

/**
 * Copyright (c) 2012-2013 Edgar Espina
 *
 * This file is part of Handlebars.java.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * This copy of Woodstox XML processor is licensed under the
 * Apache (Software) License, version 2.0 ("the License").
 * See the License for details about distribution rights, and the
 * specific rights regarding derivate works.
 *
 * You may obtain a copy of the License at:
 *
 * http://www.apache.org/licenses/
 *
 * A copy is also included in the downloadable source code package
 * containing Woodstox, in file "ASL2.0", under the same directory
 * as this file.
 */
package com.github.jknack.handlebars.maven;

import static org.apache.commons.lang3.StringUtils.join;
import static org.apache.commons.lang3.Validate.notNull;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;

import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.codehaus.plexus.util.FileUtils;

import com.github.jknack.handlebars.Context;
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Options;
import com.github.jknack.handlebars.TagType;
import com.github.jknack.handlebars.Template;
import com.github.jknack.handlebars.helper.I18nHelper;

import edu.emory.mathcs.backport.java.util.Collections;

/**
 * Convert {@link ResourceBundle} to JavaScript using the I18n.js API.
 *
 * @author edgar.espina
 * @since 1.1.2
 */
@Mojo(name = "i18njs", defaultPhase = LifecyclePhase.PREPARE_PACKAGE, threadSafe = true)
public class I18nJsPlugin extends HandlebarsPlugin {

    /**
     * The resource bundle name. Example:
     * <ul>
     * <li><code>messages</code></li>
     * <li><code>com.github.app.messages</code></li>
     * </ul>
     * Default is: <code>messages</code>.
     */
    @Parameter
    private String bundle = "messages";

    /**
     * The output directory. JavaScript files will be save here.
     */
    @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}/js")
    private String output;

    /**
     * True if all the messages bundle should be merge into a single file. Default: false.
     */
    @Parameter(defaultValue = "false")
    private boolean merge;

    /**
     * True, if the output should be in the AMD format. Default is anonymous function.
     */
    @Parameter
    private boolean amd;

    /**
     * Character encoding. Default is: UTF-8.
     */
    @Parameter(defaultValue = "UTF-8")
    private String encoding = "UTF-8";

    @Override
    protected void doExecute() throws Exception {
        notNull(bundle, "The bundle's name parameter is required.");
        notNull(output, "The output parameter is required.");

        Handlebars handlebars = new Handlebars();
        Context context = Context.newContext(null);
        URL[] classpath = projectClasspath();

        new File(output).mkdirs();

        getLog().info("Converting bundles...");
        getLog().debug("Options:");
        getLog().debug("  output: " + output);
        getLog().debug("  merge: " + merge);
        getLog().debug("  amd: " + amd);
        getLog().debug("  classpath: " + join(classpath, File.pathSeparator));

        StringBuilder buffer = new StringBuilder();

        // 1. find all the bundles
        List<File> bundles = bundles(this.bundle, classpath);

        // 2. hash for i18njs helper
        Map<String, Object> hash = new HashMap<String, Object>();
        hash.put("wrap", false);
        if (classpath.length > 0) {
            hash.put("classLoader", new URLClassLoader(classpath, getClass().getClassLoader()));
        }
        // 3. get the base name from the bundle
        String basename = FileUtils.removePath(this.bundle.replace(".", FileUtils.FS));

        Collections.sort(bundles);
        for (File bundle : bundles) {
            // bundle name
            String bundleName = FileUtils.removeExtension(bundle.getName());
            getLog().debug("converting: " + bundle.getName());
            // extract locale from bundle name
            String locale = bundleName.substring(basename.length());
            if (locale.startsWith("_")) {
                locale = locale.substring(1);
            }
            // set bundle name
            hash.put("bundle", this.bundle);

            Options options = new Options.Builder(handlebars, I18nHelper.i18nJs.name(), TagType.VAR, context,
                    Template.EMPTY).setHash(hash).build();
            // convert to JS
            buffer.append(I18nHelper.i18nJs.apply(locale, options));

            if (!merge) {
                FileUtils.fileWrite(new File(output, bundleName + ".js"), encoding, wrap(bundleName, buffer, amd));
                buffer.setLength(0);
                getLog().debug("  => " + bundleName + ".js");
            } else {
                buffer.append("\n");
            }
        }
        if (merge && buffer.length() > 0) {
            FileUtils.fileWrite(new File(output, basename + ".js"), wrap(basename, buffer, amd));
            getLog().debug("  =>" + basename + ".js");
        }
    }

    /**
     * Wrap javaScript code using an anonymous function or the AMD format.
     *
     * @param filename The javascript file name.
     * @param body The javascript code.
     * @param amd True, for AMD.
     * @return Some javascript code.
     */
    private String wrap(final String filename, final CharSequence body, final boolean amd) {
        if (amd) {
            return String.format("define('%s', ['i18n'], function (I18n) {\n%s});\n", filename, body);
        }
        return String.format("(function() {\n%s})();\n", body.toString());
    }

    /**
     * List all the resource bundle found in the classpath.
     *
     * @param bundle The bundle's name.
     * @param classpath The project classpath.
     * @return Some resource bundles.
     * @throws Exception If something goes wrong.
     */
    private List<File> bundles(final String bundle, final URL[] classpath) throws Exception {
        Set<File> bundles = new LinkedHashSet<File>();
        for (URL url : classpath) {
            File dir = new File(url.toURI());
            bundles.addAll(FileUtils.getFiles(dir, bundle.replace(".", FileUtils.FS) + "*.properties", null));
        }
        return new ArrayList<File>(bundles);
    }

    /**
     * Set the resource bundle name. Example:
     * <ul>
     * <li><code>messages</code></li>
     * <li><code>com.github.app.messages</code></li>
     * </ul>
     * Default is: <code>messages</code>.
     *
     * @param bundle The bundle name.
     */
    public void setBundle(final String bundle) {
        this.bundle = bundle;
    }

    /**
     * Set output directory. The generate javascript bundles will be saved here.
     *
     * @param output The output directory.
     */
    public void setOutput(final String output) {
        this.output = output;
    }

    /**
     * If true, all the bundles will be merge them into a single file. Default: false.
     *
     * @param merge True for merging bundles.
     */
    public void setMerge(final boolean merge) {
        this.merge = merge;
    }

    /**
     * True, if the output should be in the AMD format. Default is anonymous function.
     *
     * @param amd True, if the output should be in the AMD format. Default is anonymous function.
     */
    public void setAmd(final boolean amd) {
        this.amd = amd;
    }
}