{"id":1597,"date":"2010-11-15T08:26:08","date_gmt":"2010-11-15T13:26:08","guid":{"rendered":"http:\/\/www.andygibson.net\/blog\/?p=1597"},"modified":"2015-08-16T11:16:49","modified_gmt":"2015-08-16T10:16:49","slug":"resource-bundles-in-jsf-2-0-applications","status":"publish","type":"post","link":"https:\/\/www.andygibson.net\/old-blog\/article\/resource-bundles-in-jsf-2-0-applications\/","title":{"rendered":"Resource Bundles in JSF 2.0 Applications"},"content":{"rendered":"<p>Setting up resource message bundles in JSF to provide multilingal messages and captions is often overlooked when first creating an application. Leaving it till later in the project means you will have to go back and manually change the constants over to resource based values. Resource bundles JSF 1.2 were far from perfect but fortunately, using resource bundles in JSF 2.0 is very easy and this tutorial will show you how to add bundles and use them in your JSF 2.0 pages.<br \/>\n<!--more--><br \/>\nFor this example, we&#8217;ll create a new application using the <code>jee6-servlet-basic-archetype<\/code> Knappsack Maven archetype. The full source can be <a href=\"http:\/\/www.andygibson.net\/blog\/wp-content\/uploads\/2010\/10\/resourcedemo.zip\">downloaded<\/a> and run using <code>mvn clean jetty:run<\/code> from the command line.<\/p>\n<p>Message resources are stored in properties files which consist of name value pairs that binds a message key string with the message value. We&#8217;ll use the following example<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nfirstName=First Name\r\nlastName=Last Name\r\nforgotPassword=Forgot Password?\r\nusernameTaken={0} is already taken\r\n<\/pre>\n<p>This file needs to be saved and referenced in a package, which would normally be in the same place as your source code, but Maven provides a separate area for resources. Save the file in the <code>src\/main\/resources\/org\/fluttercode\/resourcedemo\/<\/code> folder with the name <code>MessageResources.properties<\/code>. Open up the <code>faces-config<\/code> file and add the following XML :<\/code><\/code><\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;application&gt;\r\n\t&lt;resource-bundle&gt;\r\n\t\t&lt;base-name&gt;org.fluttercode.resourcedemo.MessageResources&lt;\/base-name&gt;\r\n\t\t&lt;var&gt;msgs&lt;\/var&gt;\r\n\t&lt;\/resource-bundle&gt;\r\n&lt;\/application&gt;\r\n<\/pre>\n<p>Here, we have told JSF about the resource bundle and assigned a variable name to it. Now we will go and add a reference to one of the messages in our home page. Open <code>home.xhtml<\/code> and replace the initial message with the following :<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;h:outputText  value=&quot;#{msgs.firstName}&quot;\/&gt;\r\n<\/pre>\n<p>This is a JSF output text component that gets its value from the resource bunde, in this case, the <code>firstName<\/code> value. If you are using JBoss Tools, you will see that it can perform autocompletion for you on both the <code>msgs<\/code> value and the actual property keys on the <code>msgs<\/code> resources. It also displays the actual property value in the preview window for the page. If you run the app now by typing <code>mvn jetty:run<\/code> in the command line, you will see that the word <code>First Name<\/code> appears in the page.<\/p>\n<h1>Access Resources From Code<\/h1>\n<p>Typically, in your application you will generate messages for the user that also needs to be obtained from the resource bundle. To do this, we will create a bean that can fetch the resource bundle for us and extract strings from it.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\npublic class MessageProvider {\r\n\r\n\tprivate ResourceBundle bundle;\r\n\r\n\tpublic ResourceBundle getBundle() {\r\n\t\tif (bundle == null) {\r\n\t\t\tFacesContext context = FacesContext.getCurrentInstance();\r\n\t\t\tbundle = context.getApplication().getResourceBundle(context, \"msgs\");\r\n\t\t}\r\n\t\treturn bundle;\r\n\t}\r\n\r\n\tpublic String getValue(String key) {\r\n\r\n\t\tString result = null;\r\n\t\ttry {\r\n\t\t\tresult = getBundle().getString(key);\r\n\t\t} catch (MissingResourceException e) {\r\n\t\t\tresult = \"???\" + key + \"??? not found\";\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n}\r\n<\/pre>\n<p>This class fetches the resource bundle from the faces context which will determine the best bundle to use based on the supported locales and the client locale. The second method uses the first method to fetch a string resource from the bundle.<br \/>\nWe&#8217;ll create a JSF backing bean to use this bean to return a message to the user.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n@Named\r\n@RequestScoped\r\npublic class SomeBean {\r\n\r\n\tpublic String getMessage() {\r\n\t\tString msg = new MessageProvider().getValue(\"someMessage\");\r\n\t\treturn MessageFormat.format(msg, \"SomeValue\");\r\n\t}\r\n}\r\n<\/pre>\n<p>In our <code>home.jsf<\/code> page, we display our message by adding<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nMessage = #{someBean.message}\r\n<\/pre>\n<p>Which results in the following phrase being displayed :<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nMessage = SomeValue is not valid\r\n<\/pre>\n<p>Having just the one default properties file in place is the bare minimum for using string resource bundles in your applications, and I would recommend using that for any application, even if it is never going to be multi-lingual. At the very least, it keeps your string constants in one place and at best, it makes it really easy to support multiple languages at a later date.<\/p>\n<h1>Handling JSF Locale Information<\/h1>\n<p>If you go multi-lingual you will need to provide multiple versions of the resource file for different locales, and list the supported locales in your <code>faces-config.xml<\/code> file.<br \/>\nTo test this, create multiple copies of the <code>MessageResources<\/code> file in the same directory with different names such as <code>MessageResources_de.properties<\/code> or <code>MessageResources_fr.properties<\/code> and in the content for each, use the same values, but add the locale on the end.<\/p>\n<p><b>MessageResources_fr.properties<\/b><\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nfirstName=First Name(fr)\r\nlastName=Last Name(fr)\r\nforgotPassword=Forgot Password?(fr)\r\nsomeMessage={0} is not valid(fr)\r\n<\/pre>\n<p>In the <code>faces-config.xml<\/code> file you can add the supported locales and set the default locale to use.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n\t&lt;application&gt;\r\n\t\t&lt;locale-config&gt;\r\n\t\t\t&lt;default-locale&gt;en_US&lt;\/default-locale&gt;\r\n\t\t\t&lt;supported-locale&gt;de&lt;\/supported-locale&gt;\r\n\t\t\t&lt;supported-locale&gt;en_GB&lt;\/supported-locale&gt;\r\n\t\t\t&lt;supported-locale&gt;fr&lt;\/supported-locale&gt;\r\n\t\t&lt;\/locale-config&gt;\r\n\t\t&lt;resource-bundle&gt;\r\n\t\t\t&lt;base-name&gt;org.fluttercode.resourcedemo.MessageResources&lt;\/base-name&gt;\r\n\t\t\t&lt;var&gt;msgs&lt;\/var&gt;\r\n\t\t&lt;\/resource-bundle&gt;\r\n\t&lt;\/application&gt;\r\n<\/pre>\n<p>Now, depending on where you are in the world, and your browser locale, if you plan on following along, you&#8217;ll have to substitute your own locale for en_US. Since we have a <code>MessageProperties<\/code> file without a locale in the file name, if it cannot find a matching locale, it will use this default bundle. If the default locale is specified in <code>faces-config<\/code>,then that locale will be used instead of the non-specific default.<br \/>\nPlay around with renaming some of the resource files, especially the file that matches your own locale. If the file exists, but it is not included in the list of supported locales in <code>faces-config<\/code> it won&#8217;t be used. You can also change the <code>default-locale<\/code> value to one other than your own locale and see how the locale would be selected.<br \/>\nJSF will also select a locale that matches based on the language if not the specific region. In my case, having a locale of <code>en_US<\/code> means that if available, JSF will select the <code>MessageResources_en<\/code> bundle if there is no bundle specifically for <code>en_US<\/code>.<\/p>\n<p><a href=\"http:\/\/www.andygibson.net\/blog\/wp-content\/uploads\/2010\/10\/resourcedemo.zip\">Download the Maven source code <\/a> for this project and run it locally by unzipping it into a folder and typing <code>mvn clean jetty:run<\/code> and going to <a href=\"http:\/\/localhost:8080\/resourcedemo\/\">http:\/\/localhost:8080\/resourcedemo\/<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Setting up resource message bundles in JSF to provide multilingal messages and captions is often overlooked when first creating an application. Leaving it till later in the project means you will have to go back and manually change the constants over to resource based values. Resource bundles JSF 1.2 were far from perfect but fortunately, [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[63],"tags":[32],"_links":{"self":[{"href":"https:\/\/www.andygibson.net\/old-blog\/wp-json\/wp\/v2\/posts\/1597"}],"collection":[{"href":"https:\/\/www.andygibson.net\/old-blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.andygibson.net\/old-blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.andygibson.net\/old-blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.andygibson.net\/old-blog\/wp-json\/wp\/v2\/comments?post=1597"}],"version-history":[{"count":16,"href":"https:\/\/www.andygibson.net\/old-blog\/wp-json\/wp\/v2\/posts\/1597\/revisions"}],"predecessor-version":[{"id":2144,"href":"https:\/\/www.andygibson.net\/old-blog\/wp-json\/wp\/v2\/posts\/1597\/revisions\/2144"}],"wp:attachment":[{"href":"https:\/\/www.andygibson.net\/old-blog\/wp-json\/wp\/v2\/media?parent=1597"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.andygibson.net\/old-blog\/wp-json\/wp\/v2\/categories?post=1597"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.andygibson.net\/old-blog\/wp-json\/wp\/v2\/tags?post=1597"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}