Read resource bundle properties in a managed bean
Asked Answered
F

3

13

Using <resource-bundle> files I'm able to have i18n text in my JSF pages.

But is it possible to access these same properties in my managed bean so I can set faces messages with i18n values?

Flue answered 1/12, 2012 at 1:43 Comment(0)
M
45

Assuming that you've configured it as follows:

<resource-bundle>
    <base-name>com.example.i18n.text</base-name>
    <var>text</var>
</resource-bundle>

If your bean is request scoped, you can just inject the <resource-bundle> as @ManagedProperty by its <var>:

@ManagedProperty("#{text}")
private ResourceBundle text;

public void someAction() {
    String someKey = text.getString("some.key");
    // ... 
}

Or if you just need some specific key:

@ManagedProperty("#{text['some.key']}")
private String someKey;

public void someAction() {
    // ... 
}

If your bean is however in a broader scope, then evaluate #{text} programmatically in method local scope:

public void someAction() {
    FacesContext context = FacesContext.getCurrentInstance();
    ResourceBundle text = context.getApplication().evaluateExpressionGet(context, "#{text}", ResourceBundle.class);
    String someKey = text.getString("some.key");
    // ... 
}

Or if you only need some specific key:

public void someAction() {
    FacesContext context = FacesContext.getCurrentInstance();
    String someKey = context.getApplication().evaluateExpressionGet(context, "#{text['some.key']}", String.class);
    // ... 
}

You can even just get it by the standard ResourceBundle API the same way as JSF itself is already doing under the covers, you'd only need to repeat the base name in code:

public void someAction() {
    FacesContext context = FacesContext.getCurrentInstance();
    ResourceBundle text = ResourceBundle.getBundle("com.example.i18n.text", context.getViewRoot().getLocale());
    String someKey = text.getString("some.key");
    // ... 
}

Or if you're managing beans by CDI instead of JSF, then you can create a @Producer for that:

public class BundleProducer {

    @Produces
    public PropertyResourceBundle getBundle() {
        FacesContext context = FacesContext.getCurrentInstance();
        return context.getApplication().evaluateExpressionGet(context, "#{text}", PropertyResourceBundle.class);
    }

}

And inject it as below:

@Inject
private PropertyResourceBundle text;

Alternatively, if you're using the Messages class of the JSF utility library OmniFaces, then you can just set its resolver once to let all Message methods utilize the bundle.

Messages.setResolver(new Messages.Resolver() {
    public String getMessage(String message, Object... params) {
        ResourceBundle bundle = ResourceBundle.getBundle("com.example.i18n.text", Faces.getLocale());
        if (bundle.containsKey(message)) {
            message = bundle.getString(message);
        }
        return MessageFormat.format(message, params);
    }
});

See also the example in the javadoc and the showcase page.

Minh answered 1/12, 2012 at 3:55 Comment(8)
If your bean is request scoped is that the only scope that can access to the propperties file?Brieta
@Kuriel: JSF @ManagedProperty is not capable of injecting a narrower scope in a broader scope. Only CDI @Inject is. If you happen to use CDI, head to https://mcmap.net/q/902987/-injecting-resourcebundle-via-managedproperty-doesn-39-t-seem-to-work-inside-namedMinh
@Minh which syntax form should be used while writing text with parameters in resource bundle file?Goto
@séan35: just pass bundle value (not key!) to MessageFormat#format().Minh
@ManagedProperty("#{text}") also works in @ViewScoped and @FlowScoped beans.Arvid
@toKrause: only when using JSF 2.3 which was released only half a year ago.Minh
@Minh Are you sure? I'm using JSF 2.2 and it works fine.Arvid
@toKrause: then you used @ManagedBean instead of @Named (so @FlowScoped would have no effect at all and it will default to @RequestScoped).Minh
T
2

Another possibility:

faces-config.xml

<?xml version='1.0' encoding='UTF-8'?>
<faces-config ...>
  <application>
    <locale-config>
      <default-locale>de</default-locale>
    </locale-config>
    <resource-bundle>
      <base-name>de.fhb.resources.text.backend</base-name>
      <var>backendText</var>
    </resource-bundle>
  </application>
</faces-config>

YourBean.java

FacesContext context = FacesContext.getCurrentInstance();
Application app = context.getApplication();
ResourceBundle backendText = app.getResourceBundle(context, "backendText");
backendText.getString("your.property.key");
Terrorize answered 12/3, 2014 at 11:15 Comment(0)
A
1

Here is a solution I'm using, not as simple but at least working :

First class :

package com.spectotechnologies.website.util;

import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;

/**
 *
 * @author Alexandre Lavoie
 */
public class MessageInterpolator extends ResourceBundleMessageInterpolator
{
    public static final String LANGUAGE_TAG_PATTERN = "\\{[^}]*\\}";

    @Override
    public String interpolate(String p_sMessage, Context p_oContext)
    {
        return super.interpolate(replaceMessages(p_sMessage),p_oContext);
    }

    @Override
    public String interpolate(String p_sMessage, Context p_oContext, Locale p_oLocale)
    {
        StringManager.setLocale(p_oLocale);

        return super.interpolate(replaceMessages(p_sMessage),p_oContext,p_oLocale);
    }

    private String replaceMessages(String p_sMessage)
    {
        Matcher oMatcher;
        String sKey;
        String sReplacement;
        StringBuffer sbTemp = new StringBuffer();

        oMatcher = Pattern.compile(LANGUAGE_TAG_PATTERN).matcher(p_sMessage);
        while(oMatcher.find())
        {
            sKey = oMatcher.group().substring(1,oMatcher.group().length() - 1);

            sReplacement = StringManager.getString(sKey);

            if(!sReplacement.startsWith("???"))
            {
                oMatcher.appendReplacement(sbTemp,sReplacement);
            }
        }

        oMatcher.appendTail(sbTemp);

        return sbTemp.toString();
    }
}

Second class :

package com.spectotechnologies.website.util;

import com.spectotechnologies.util.BundleManager;
import com.spectotechnologies.util.FacesSessionManager;
import java.util.Locale;

/**
 * set-up and interface a BundleManager
 * save the bundleManager into the session
 * @author Charles Montigny
 */
public final class StringManager
{
    /** the session name of this class bundle manager */
    public static final String BUNDLE_MANAGER_SESSION_NAME = "StringManager_BundleManager";

    /**  List of ResourceBundle names to load.
     * Will be load in order.
     * The last ones values may overrite the first ones values. */
    private final static String[] BUNDLE_LIST = {
        "com.spectotechnologies.hibernate.validation.resources.ValidationMessages",
        "com.spectotechnologies.website.general.resources.ValidationMessages",
        "com.spectotechnologies.website.general.resources.General"};

    /** bundle manager */
    private static BundleManager m_oBundleManager = null;

    private static BundleManager getBundleManager()
    {
        if(m_oBundleManager == null)
        {
            // get the bundle into the session
            m_oBundleManager = (BundleManager)FacesSessionManager.getObject(BUNDLE_MANAGER_SESSION_NAME);
            if(m_oBundleManager == null)
            {
                // session was empty, load a new one
                m_oBundleManager = new BundleManager();
                for(int iIndex = 0; iIndex < BUNDLE_LIST.length; iIndex++)
                {
                    m_oBundleManager.addBundle(BUNDLE_LIST[iIndex]);
                }
                // add the bundle to the session
                FacesSessionManager.setObject(BUNDLE_MANAGER_SESSION_NAME, m_oBundleManager);
            }
        }
        return m_oBundleManager;
    }

    /**
     * get a string value in the bundle manager by a string key
     * @param p_sKey the string key
     * @return the value of the string key
     */
    public static String getString(String p_sKey)
    {
        return getBundleManager().getStringValue(p_sKey);
    }

    /**
     * set the locale
     * @param p_oLocale the locale to set
     */
    public static void setLocale(Locale p_oLocale)
    {
        getBundleManager().setLocale(p_oLocale);

        // update the session
        FacesSessionManager.setObject(BUNDLE_MANAGER_SESSION_NAME,
                getBundleManager());
    }
}

After you need to override BUNDLE_LIST with your properties files. Once done, use it like that :

sMessage = StringManager.getString("website.validation.modifySystem.modified");

If you have questions, do not hesitate!

EDIT :

You also need to declare the MessageInterpolator

META-INF/validation.xml

<validation-config
    xmlns="http://jboss.org/xml/ns/javax/validation/configuration"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/configuration">
    <message-interpolator>com.spectotechnologies.website.util.MessageInterpolator</message-interpolator>
</validation-config>
Arboreous answered 1/12, 2012 at 2:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.