The Source for Java Technology Collaboration
User: Password:



Kohsuke Kawaguchi

Kohsuke Kawaguchi's Blog

Internationalization of Hudson --- Help wanted!

Posted by kohsuke on December 28, 2007 at 09:45 PM | Comments (11)

I just posted a new version of Hudson (1.164), which includes the first cut of i18n and localization to Japanese by using it. Localization is an area where the barrier of entry for contributions is low (and there's almost infinite amount of work), so I'm writing this entry to explain how it works in the hope of soliciting contributions.

Here's the way it works. In view scripts of Hudson, which is written in Jelly, message resource references can appear like this:

<a href="configure">${%Configure Hudson}</a>

The text between '${%' and '}' is the message resource key name, and its translations can be defined in the corresponding property file (for example, foo_ja.properties if the view script is foo.jelly):

Configure\ Hudson=Hudsonの設定

You might have noticed that I chose the key name that can be used as the English message, and this is by design. When property files don't define the message for a particular key, the key itself is used as the message. This eliminates the need of introducing identifiers for every single message, and thus it reduces cognitive overhead for developers.

For messages that have parameters, a reference in view scripts would be something like ${%title(expression1,expression2,...)} and its definition in the property file would be something like title=abc{0}def{1}>. In this case, a property file is required, even for the default locale. This also makes it easier to work on property files, as they read more like translations where English comes left and translation comes right.

On top of this, I wrote a Maven plugin that scans all view scripts and generate empty resource property files for the locale of your choice. So let's say if you are interested in working on French translation, you can just run the following command, and it'll generate all *_fr.properties files with all the place-holder entries:

$ cd path/to/hudson/workspace
$ mvn stapler:i18n -Dlocale=fr

From here, you'd just open *_fr.properties files, work on translations, and send modified files to me, and that's it! I'm still working on putting '${%...}' around all the messages, but the stapler:i18n mojo works incrementally, so when there are more messages, you rerun the mojo and it'll just add missing entries to the existing files without clobbering what you already wrote.

For messages used inside Java code, I wrote a little tool called localizer that reads property files and generates Java methods to format messages. In this scheme, I first write message resource property files (let's say Messages.properties) like this:

foo=error at {0} with {1}

When you build Hudson, Maven automatically generates the following class, thanks to the localizer maven plugin:

public class Messages {

    private final static ResourceBundleHolder holder = new ResourceBundleHolder(Messages.class);

    /**
     * error at {0} with {1}
     */
    public static String foo(Object arg1, Object arg2) {
        return holder.format("foo",arg1,arg2);
    }

    /**
     * error at {0} with {1}
     */
    public static Localizable _foo(Object arg1, Object arg2) {
        return new Localizable(holder, "foo", arg1, arg2);
    }
}

In this way, you can get auto-completion and type-safe access to message properties, and javadoc popup in your IDE can tell you which message you are going to get. The method signature also enforces the right number of arguments. I've been doing something very similar in Metro and I liked it, so this is a re-implementation of that with proper Maven/Ant integration.

If you are interested in helping us localize Hudson, please let us know.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Hi Kohsuke, I see potentially one problem with your approach. What if it is necessary to change the text of the English message, won't that break everything? For example, if you changed "Configure Hudson" to "Hudson Configuration", wouldn't that prevent Hudson from being able to find the equivalent French or Spanish message (unless you go through and change the key in every language file)?

    Posted by: dwdyer on December 29, 2007 at 04:09 AM

  • Latest cvs checkout, in hudson/hudson/:
    mvn stapler:i18n -Dlocale=fr
    [INFO] The plugin 'org.apache.maven.plugins:maven-stapler-plugin' does not exist or no valid version could be found
    What am I missing ?

    Posted by: pbleser on December 29, 2007 at 11:44 AM

  • Same here: stapler does not seem to be available in a known maven repository. Do we need to add a super-secret repository to our settings.xml?

    Posted by: elefevre on December 30, 2007 at 08:35 AM

  • dwdyer, good point. I guess I never thought about that, but in the past experience message changes like that has been somewhat limited. And a part of the problem is the bigger problem of keeping all messages in sync, which is a problem regardless of how you do it.

    I'm writing an IntelliJ plugin to assist some of this, and I guess a good feature is a refactoring that also renames property names.

    I can also write another Maven mojo to check for resources that are no longer used in view files, which can be used to mechanically find out-of-sync messages.

    Posted by: kohsuke on January 02, 2008 at 09:17 AM

  • pbleser, it looks like my "mvn release" failed. I just run it again to post 1.5. Sorry about that. You can run "mvn -cpu" to force Maven to check for updates. 1.5 should appear here shortly.

    Posted by: kohsuke on January 02, 2008 at 09:23 AM

  • Kohsuke, I did try "mvn -cpu stapler:i18n -Dlocale=fr", but I still get the error message "The plugin 'org.apache.maven.plugins:maven-stapler-plugin' does not exist or no valid version could be found". I notice that there is no version 1.5 in the page you are pointing too, though there is a 1.6. Surely, typing just "stapler:i18n" should pick-up version 1.6.

    Then again, the error message seems to give another path (org.apache.maven.plugins) than the real one (org.kohsuke.stapler). Is this a normal thing?

    Many thanks for your time. Eric

    Posted by: elefevre on January 03, 2008 at 06:06 AM

  • elefevre, I think we should move the trouble-shooting to dev@hudson.dev.java.net. It looks like Maven is looking for a wrong plugin, and that normally happens when you run this on a module that doesn't have a proper configuration. Which directory are you running this on?

    Posted by: kohsuke on January 03, 2008 at 08:35 PM

  • I captured this in Hudson Wiki

    Posted by: kohsuke on January 03, 2008 at 09:13 PM

  • Yes, we should have moved this to the dev mailing list.
    Well, too late, I cracked it! ;-)

    The thing was to move to the 'core' directory, as you explained on Hudson Wiki. About 30 properties files were generated. Yay!

    Posted by: elefevre on January 04, 2008 at 03:17 AM

  • I just want to inform you about Turkish localization. Now I am working on it, as soon as I finished, I'll request permission to commit my changes... By the way, can it be optional, I mean can there be flags on top side of hudson for the languages which localization is done on, and by clicking on them, you can change your Hudson language? Just an idea...

    Posted by: oguzdag on March 06, 2008 at 12:42 AM

  • See the wiki. I use Firefox quick locale switcher extension to do the testing. Eventually it's a good idea to let the user choose the locale explicitly, perhaps in the user configuraiton screen.

    Posted by: kohsuke on March 06, 2008 at 09:46 AM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds