Question

We are using gettext for I18N in our Java programs.

Is there a way to use gettext for JSF xhtml files?

Currently we are using Java properties files in JSF:

<p:column headerText="#{msg['bargains.columns.percent']}">
Was it helpful?

Solution

You can write a named bean like this:

import java.io.Serializable;
import java.util.Locale;
import javax.enterprise.context.SessionScoped;

import javax.faces.context.FacesContext;
import javax.inject.Named;

import org.xnap.commons.i18n.I18nFactory;

/**
* Injectable version of {@link org.xnap.commons.i18n.I18n}.
*
* @author Falko Menge
* @author nico.rehwaldt
*/
@Named("i18n")
@SessionScoped
public class I18n implements Serializable {

  private static final long serialVersionUID = 1L;
  private transient org.xnap.commons.i18n.I18n i18n;

  public org.xnap.commons.i18n.I18n getI18n() {
if (i18n == null) {
  FacesContext context = FacesContext.getCurrentInstance();
  String messageBundleName = context.getApplication().getMessageBundle();
  Locale locale = context.getViewRoot().getLocale();
  setI18n(I18nFactory.getI18n(getClass(), messageBundleName, locale, I18nFactory.FALLBACK));
}
return i18n;
  }

  public void setI18n(org.xnap.commons.i18n.I18n i18n) {
this.i18n = i18n;
  }

  public String marktr(String text) {
return org.xnap.commons.i18n.I18n.marktr(text);
  }

  public String tr(String text, Object o1, Object o2, Object o3, Object o4) {
return getI18n().tr(text, o1, o2, o3, o4);
  }

  public String tr(String text, Object o1, Object o2, Object o3) {
return getI18n().tr(text, o1, o2, o3);
  }

  public String tr(String text, Object o1, Object o2) {
return getI18n().tr(text, o1, o2);
  }

  public String tr(String text, Object o1) {
if (o1 instanceof Object[]) {
  return getI18n().tr(text, (Object[]) o1);
}
return getI18n().tr(text, o1);
  }

  public String tr(String arg0) {
return getI18n().tr(arg0);
  }

  public String trc(String arg0, String arg1) {
return getI18n().trc(arg0, arg1);
  }

  public String trn(String text, String pluralText, long n, Object o1, Object o2, Object o3, Object o4) {
return getI18n().trn(text, pluralText, n, o1, o2, o3, o4);
  }

  public String trn(String text, String pluralText, long n, Object o1, Object o2, Object o3) {
return getI18n().trn(text, pluralText, n, o1, o2, o3);
  }

  public String trn(String text, String pluralText, long n, Object o1, Object o2) {
return getI18n().trn(text, pluralText, n, o1, o2);
  }

  public String trn(String text, String pluralText, long n, Object o1) {
if (o1 instanceof Object[]) {
  return getI18n().trn(text, pluralText, n, (Object[]) o1);
}
return getI18n().trn(text, pluralText, n, o1);
  }

  public String trn(String arg0, String arg1, long arg2) {
return getI18n().trn(arg0, arg1, arg2);
  }

  public String trnc(String comment, String singularText, String pluralText, long n, Object obj1, Object obj2, Object obj3, Object obj4) {
return getI18n().trnc(comment, singularText, pluralText, n, obj1, obj2, obj3, obj4);
  }

  public String trnc(String comment, String singularText, String pluralText, long n, Object obj1, Object obj2, Object obj3) {
return getI18n().trnc(comment, singularText, pluralText, n, obj1, obj2, obj3);
  }

  public String trnc(String comment, String singularText, String pluralText, long n, Object obj1, Object obj2) {
return getI18n().trnc(comment, singularText, pluralText, n, obj1, obj2);
  }

  public String trnc(String comment, String singularText, String pluralText, long n, Object obj) {
if (obj instanceof Object[]) {
  return getI18n().trnc(comment, singularText, pluralText, n, (Object[]) obj);
}
return getI18n().trnc(comment, singularText, pluralText, n, obj);
  }

  public String trnc(String arg0, String arg1, String arg2, long arg3) {
return getI18n().trnc(arg0, arg1, arg2, arg3);
  }
}

use it in JSF like this:

<h:outputLabel value="#{i18n.tr('Username')}" for="usernameInput" />

and run it via gettext-commons:

<dependency>
  <!-- required for i18n with GNU gettext -->
  <groupId>org.xnap.commons</groupId>
  <artifactId>gettext-commons</artifactId>
  <version>0.9.6</version>
</dependency>

A Maven plugin can be used together with a shellscript to extract the keys from the JSF pages:

 <plugin>
    <!-- required for i18n with GNU gettext -->
    <groupId>org.xnap.commons</groupId>
    <artifactId>maven-gettext-plugin</artifactId>
    <version>1.2.3</version>
    <configuration>
      <xgettextCmd>${basedir}/src/main/po/xgettext-jsf.sh</xgettextCmd>
      <poDirectory>${basedir}/src/main/po</poDirectory>
      <targetBundle>i18n.Messages</targetBundle>
      <outputDirectory>${basedir}/src/main/resources</outputDirectory>
    </configuration>
  </plugin>
</plugins>

shellscript:

#!/bin/sh

# extract gettext strings from Java sources with options provided by Maven
xgettext --copyright-holder='ACME Inc.' --package-name='ACME Webapp' --package-version='1.0-SNAPSHOT' --msgid-bugs-address='info@example.com' $*

# replace some placeholders
sed -i '1 s/SOME DESCRIPTIVE TITLE/This is the LANGUAGE translation of ACME Webapp/' ../po/keys.pot
sed -i '2 s/YEAR/2011/' ../po/keys.pot
sed -i '3 s/PACKAGE/ACME Webapp/' ../po/keys.pot

# fix Java source file locations
sed -i 's/^#: /#: ..\/java\//' ../po/keys.pot

# add a newline
echo >> ../po/keys.pot

# extract gettext strings from JSF templates
grep "i18n\.[^(]\+('[^']\+'[^)]*)" --recursive --exclude-dir=.svn --include='*.xhtml' --only-matching --with-filename --line-number ../ | sed "s/\(.*\)\:i18n.tr('\(.*\)'.*/#: \1\nmsgid \"\2\"\nmsgstr \"\"\n/" >> ../po/keys.pot

# unify duplicate translations in message catalog
msguniq --sort-by-file --output-file=../po/keys.pot ../po/keys.pot
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top