Do resource bundles in Java support runtime string substitution? - java

Can you do the following with a Java ResourceBundle?
In the properties file...
example.dynamicresource=You currently have {0} accounts.
At runtime...
int accountAcount = 3;
bundle.get("example.dynamicresource",accountCount,param2,...);
To give a result of
"You currently have 3 accounts."

Not without using the MessageFormat class, such as:
String pattern = bundle.getString("example.dynamicresource");
String message = MessageFormat.format(pattern, accountCount);

On their own, ResourceBundle does not support property placeholders. The usual idea is to take the String you get from the bundle, and stick it into a MessageFormat, and then use that to get your parameterized message.
If you're using JSP/JSTL, then you can combine <fmt:message> and <fmt:param> to do this, which uses ResourceBundle and MessageFormat under the covers.
If you happen to be using Spring, then it has the ResourceBundleMessageSource which does something similar, and can be used anywhere in your program. This MessageSource abstraction (combined with MessageSourceAccessor) is much nicer to use than ResourceBundle.

There are various ways, depending on the view technology you're using. If you're using "plain vanilla" Java (e.g. Swing), then use MessageFormat API as answered before. If you're using a webapplication framework (which is true, if I judge your question history here correctly), then the way depends on the view technology and/or MVC framework you're using. If it is for example "plain vanilla" JSP, then you can use JSTL fmt:message for this.
<fmt:message key="example.dynamicresource">
<fmt:param value="${bean.accountCount}">
</fmt:message>
If it is for example JSF, you can use h:outputFormat for this.
<h:outputFormat value="#{bundle['example.dynamicresource']}">
<f:param value="#{bean.accountCount}">
</h:outputFormat>
Best place is to just consult the documentation of the technology/framework you're using (or to tell it here so that we can give better suited and more detailed answers).

Struts have a nice util called MessageResources which does exactly what you ask for....
e.g.
MessageResources resources = getResources(request, "my_resource_bundle"); // Call your bundle exactly like ResourceBundle.getBundle() method
resources.getMessage("example.dynamicresource",accountCount,param2,...);
Limitation
It only allows maximum of 3 parameters (i.e. resource attribute, param1, ..., param3).
I suggest using MessageFormat (if you want to use more than 3 parameter values) as suggested by David Sykes.
PS the getResources method is available only in the Struts Action class.

I don't think you can make this work for Non-English properties file.
My message.properties file has the following line:
info.fomat.log.message.start=Starting to parse log message in {0} format.
And my message_fr_FR.properties file has the following line:
info.fomat.log.message.start=A partir d'analyser le message connecter {0} format.
This code works only for the English one
String.format((String) messages .getString(GlobalConstants.MESSAGE_FORMAT_START), GlobalConstants.STR_JSON));
It does NOT replace the placeholder with the value when my language / locale is French :-(
Even MessageFormat.fomat() is no good

I don't believe ResourceBundle can do that itself, but String can:
String.format(bundle.getString("example.dynamicresource"), accountCount);

Remember that when using MessageFormat.format() you need to use a double quote ('') in your resource bundle if you want to express single quote (').

MessageFormoat#format will work for the case like:
greetingTo=Have Param, saying hello {0}
You can declare two methods like this where RB is a instance of ResourceBundle:
/**This is a method that takes the param to substitute the placeholder**/
public String getString(String key, Object... params ) {
try {
return MessageFormat.format(this.RB.getString(key), params);
} catch (MissingResourceException e) {
return "[" + key + "]";
}
}
/**Without a param, this will derectly delegate to ResourceBundle#getString**/
public String getString(String key) {
try {
return this.RB.getString(key);
} catch (MissingResourceException e) {
return "[" + key + "]";
}
}

Related

How to change slf4j log into html link

I have java code as:
final URI myUri = new URIBuilder()
.setScheme(azkabanHostProtocol)
.setHost(azkabanHost + ":" + azkabanPort)
.setPath("/executor")
.setParameter("execid", executionID).build();
logger.info(myUri.toString());
I want to display myURI in form of an url/html link into Azkaban's logs so that by clicking on the url it is opened. I am using log4j for logging.
You may create your own Layout class extending HTMLLayout .
Then override the format method to suit your needs.
The actual implementation has the following lines, that you may want to replace :
sbuf.append(Transform.escapeTags(event.getRenderedMessage()));
See that all tags in the message String, will be escaped by default.
Your version could be based on a kind of marker, say String mark = "[LINK]"; for instance
if(event.getRenderedMessage().startsWith(mark)){
String uri = event.getRenderedMessage().substring(mark.length());
String link = "" + uri + "";
sbuf.append(link);
}
else
sbuf.append(Transform.escapeTags(event.getRenderedMessage()));
And you would call the logger this way :
logger.info(mark + myUri.toString());
The following topic will help you use a custom HTMLLayout : how to change htmllayout in log4j2
Here is the source code for the default HTMLLayout, as a starter.
How do you view the Azkaban log files? If they are just raw text files being viewed with a vanilla text editor then there is no way to accomplish what you want. If you are viewing them in a smarter UI then you need to format them according to what that UI requires.
In short, the answer to your question is completely driven by whatever tool you are using to view the logs.

How to check for a device language in android?

I want my application to check which language the phone is using. This if statement is supposed to do that:
if (Locale.getDefault().getLanguage().equals("en")) {
yourYesResponse = "That is great " + usersName + "!";
}
else if (Locale.getDefault().getLanguage().equals("fr")) {
yourYesResponse = "C\'est bon " + usersName + "!";
}
But even if my device is set to French it still displays the English. Is there anything wrong with this if statement and if yes, then what?
EDIT: Thanks for the help. I appreciate it.
In order to get the device language, you can use this:
Locale.getDefault().getDisplayLanguage();
or,
Locale.getDefault().getLanguage(); //to get usual language code
Use :
Locale.getDefault().getLanguage().contentEquals("en")
The String#equals() not only compares the String's contents, but also checks if the other object is also an instance of a String. The String#contentEquals() methods only compares the contents (the character sequence) and does not check if the other object is also an instance of String. It can be anything as long as it is an implementation of CharSequence or an instance of StringBuffer.
For have the system language:
Locale.getDefault().getDisplayLanguage();
As everyone already explain that i18N (String XMLs in different languages) have to be used to achieve this simple thing but if you are looking for user language for some other purpose then please use one of this.
Locale.getDefault().getLanguage();
This will give language iso code i.e. "de", "ru".
OR
Resources.getSystem().getConfiguration().locale;
This returns global shared Resources object that provides access to only system resources.
You could solve this by declaring a string resource file for each language.
Create resource folders named values-fr and values-en and add a file called strings.xml to both folders.
The string.xml file in values-en:
<resources>
<string name="good">That is great </string>
</resources>
And you load the resource like this:
yourYesResponse = getResources().getText(R.string.good) + usersName + "!";
Niek was faster...
Usually locale is provided with followig format fr_FR where first fr is language code and second one is country code, thats why you should use
Locale.getDefault().getLanguage().startsWith("fr")
but Android way is to use resources
getString(R.string.hello, userName);
Edited: Ok, shame on me, I didn't notice that you call getLanguage(), but second part is correct.
The Android way of doing this, is using xml resources, as explained in Localizing with Resources.
values/strings.xml:
<resources>
<string name="yes_response">That is great, %s!</string>
</resources>
values-fr/strings.xml:
<resources>
<string name="yes_response">C\'est bon, %s!</string>
</resources>
Code:
yourYesResponse = context.getString(R.string.yes_response, usersName);
Motivation:
It is good practice to use the Android resource framework to separate
the localized aspects of your application as much as possible from the
core Java functionality:
You can put most or all of the contents of your application's user
interface into resource files, as described in this document and in
Providing Resources.
The behavior of the user interface, on the other
hand, is driven by your Java code. For example, if users input data
that needs to be formatted or sorted differently depending on locale,
then you would use Java to handle the data programmatically. This
document does not cover how to localize your Java code.

Access to MessageResources

What's the analogous of
Resources.getMessage(request,"key");
(it's in org.apache.struts.validator package)?
I need to take the right string according to the language in use and put that string in an array.
These strings have a variable part. For example:
The field %s is required
I want to take the The field and is required from the MessageResources
EDIT
I've used
ResourceBundle myResources = ResourceBundle.getBundle("MessageResources");
String msg = MessageFormat.format(myResources.getString("errors.required"),
new Object[] { title });
It works, but only with the default language
You can use a resource bundle for this in idiomatic Java. The bundles are properties files, and they are named according to their locale's.
Here is a link to ResourceBundle in the Java API documentation.
http://docs.oracle.com/javase/7/docs/api/java/util/ResourceBundle.html
Let me know if you need any more info.

How do I encode URI parameter values?

I want to send a URI as the value of a query/matrix parameter. Before I can append it to an existing URI, I need to encode it according to RFC 2396. For example, given the input:
http://google.com/resource?key=value1 & value2
I expect the output:
http%3a%2f%2fgoogle.com%2fresource%3fkey%3dvalue1%2520%26%2520value2
Neither java.net.URLEncoder nor java.net.URI will generate the right output. URLEncoder is meant for HTML form encoding which is not the same as RFC 2396. URI has no mechanism for encoding a single value at a time so it has no way of knowing that value1 and value2 are part of the same key.
Jersey's UriBuilder encodes URI components using application/x-www-form-urlencoded and RFC 3986 as needed. According to the Javadoc
Builder methods perform contextual encoding of characters not permitted in the corresponding URI component following the rules of the application/x-www-form-urlencoded media type for query parameters and RFC 3986 for all other components. Note that only characters not permitted in a particular component are subject to encoding so, e.g., a path supplied to one of the path methods may contain matrix parameters or multiple path segments since the separators are legal characters and will not be encoded. Percent encoded values are also recognized where allowed and will not be double encoded.
You could also use Spring's UriUtils
I don't have enough reputation to comment on answers, but I just wanted to note that downloading the JSR-311 api by itself will not work. You need to download the reference implementation (jersey).
Only downloading the api from the JSR page will give you a ClassNotFoundException when the api tries to look for an implementation at runtime.
I wrote my own, it's short, super simple, and you can copy it if you like:
http://www.dmurph.com/2011/01/java-uri-encoder/
It seems that CharEscapers from Google GData-java-client has what you want. It has uriPathEscaper method, uriQueryStringEscaper, and generic uriEscaper. (All return Escaper object which does actual escaping). Apache License.
I think that the URI class is the one that you are looking for.
Mmhh I know you've already discarded URLEncoder, but despite of what the docs say, I decided to give it a try.
You said:
For example, given an input:
http://google.com/resource?key=value
I expect the output:
http%3a%2f%2fgoogle.com%2fresource%3fkey%3dvalue
So:
C:\oreyes\samples\java\URL>type URLEncodeSample.java
import java.net.*;
public class URLEncodeSample {
public static void main( String [] args ) throws Throwable {
System.out.println( URLEncoder.encode( args[0], "UTF-8" ));
}
}
C:\oreyes\samples\java\URL>javac URLEncodeSample.java
C:\oreyes\samples\java\URL>java URLEncodeSample "http://google.com/resource?key=value"
http%3A%2F%2Fgoogle.com%2Fresource%3Fkey%3Dvalue
As expected.
What would be the problem with this?

ResourceBundle from Java/Struts and replace expressions

If I have a Resource bundle property file:
A.properties:
thekey={0} This is a test
And then I have java code that loads the resource bundle:
ResourceBundle labels = ResourceBundle.getBundle("A", currentLocale);
labels.getString("thekey");
How can I replace the {0} text with some value
labels.getString("thekey", "Yes!!!");
Such that the output comes out as:
Yes!!! This is a test.
There are no methods that are part of Resource Bundle to do this. Also, I am in Struts, is there some way to use MessageProperties to do the replacement.
The class you're looking for is java.text.MessageFormat; specifically, calling
MessageFormat.format("{0} This {1} a test", new Object[] {"Yes!!!", "is"});
or
MessageFormat.format("{0} This {1} a test", "Yes!!!", "is");
will return
"Yes!!! This is a test"
[Unfortunately, I can't help with the Struts connection, although this looks relevant.]
There is the class org.apache.struts.util.MessageResources with various methods getMessage, some of them take arguments to insert to the actual message.
Eg.:
messageResources.getMessage("thekey", "Yes!!!");

Categories

Resources