How to implement internationalization in java - java

I have a class called Info, and i have a bunch of static String variables described in it.
public class Info{
public static stringOne= "Hello";
public static stringTwo = "world";
}
and i'm hoping to access these variables as Info.stringTwo from other classes.
1.) I need to know if this is java-Internationalization that i have applied here ? (I have all the messages that i will display in the application assigned in this class. And, i am hoping to have different languages support to the app as well)

Have a look at Resource bundle
A copy paste from the documentation:
When your program needs a locale-specific object, it loads the ResourceBundle class using the getBundle method:
ResourceBundle myResources =
ResourceBundle.getBundle("MyResources", currentLocale);
Resource bundles contain key/value pairs. The keys uniquely identify a locale-specific object in the bundle.
Here's an example of a ListResourceBundle that contains two key/value pairs:
public class MyResources extends ListResourceBundle {
protected Object[][] getContents() {
return new Object[][] {
// LOCALIZE THE SECOND STRING OF EACH ARRAY (e.g., "OK")
{"OkKey", "OK"},
{"CancelKey", "Cancel"},
// END OF MATERIAL TO LOCALIZE
};
}
}
Keys are always Strings. In this example, the keys are "OkKey" and "CancelKey". In the above example, the values are also Strings--"OK" and "Cancel"--but they don't have to be. The values can be any type of object.
You retrieve an object from resource bundle using the appropriate getter method. Because "OkKey" and "CancelKey" are both strings, you would use getString to retrieve them:
button1 = new Button(myResources.getString("OkKey"));
button2 = new Button(myResources.getString("CancelKey"));

Here is an example from here:-
import java.util.*;
public class InternationalizationDemo {
public static void main(String[] args) {
String language;
String country;
Locale locale;
ResourceBundle rb;
if (args.length != 2) {
language = new String("en");
country = new String("US");
}
else {
language = new String(args[0]);
country = new String(args[1]);
}
locale = new Locale(language, country);
rb = ResourceBundle.getBundle("MessagesBundle", locale);
System.out.println(rb.getString("localeInfo") + " ( " +
locale.getDisplayLanguage() + "," + locale.getDisplayCountry() + ").\n");
System.out.println(rb.getString("welcome"));
System.out.println(rb.getString("sayThanks"));
}
}

Though using a ResourceBundle is the traditional and most well-known approach to internationalization in Java, it is possible to make internationalization data available as class members, somewhat similar to the way you seek.
You can further put your strings for some message in different languages in a Map, indexed by language. And make this Map a static member of some class. Thus you get the ability to reference these string collections for messages by their class member names in a compiler-checked manner. And next, if you have a way to select preferred user language at run time (you have to have it), you just pick the right string from an appropriate collection using its language key, boiling down to something like this:
logger.info (MyClassWithMessages.MY_MULTILANGUAGE_MESSAGE.s ());
And the s() method to be added to your Map subclass can be made resposible for dealing with user preferences and selection from Map by language key.
That said, the remaining task is just to formulate a convenient API for all this... You are welcome to have a look at such an implementation on my blog page Look Ma, no ResourceBundle :) ..., and the next page that goes ahead with message formatting arguments.

For internationalization of Java and other applications I implemented a Message Compiler, which creates the resource bundle files and constant definitions as Java enum or static final strings for the keys from one single source file. So the constants can be used in the Java source code, which is a much safer way than using plain string constants. The message compiler cannot only be used for Java. It creates also resource files and constants for Objective-C or Swift and can be extended for other programming environments.

Related

Best practice for maintaining constants in Java

I have an old doubt about constants in Java Projects maintenance. From my perspective, when we try putting the constants inside an Abstract class like that:
public final class MyConstants {
public static final String CONSTANT1 = "const1";
public static final String CONSTANT2 = "const2";
public static final String CONSTANT3 = "const3";
public static final String CONSTANT4 = "const4";
}
after that using those constants inside classes in the project:
public void myMethod(final Map params) {
final String myparam = (String) params.get(MyConstants.CONSTANT1);
//DO SOMETHING WITH PARAMS
}
It leads to boiler plate code, verbose use of constants and no real advances. In other hand if we put those constants inside the class for somehow people don't like it. They say "what about we have the same constant declare somewhere?" the problem is maintainance issues, if we change those constants in that class the change can be visible on several parts without any big problem.
Those constants are mainly used for mapping webservices for java perspective without having to generating POJOs like JAXB based on WSDL, the webservices operations are mapped directly for key value maps in Java.
I want to know what do you think about this approach and if we have any other choice.
Thank you.
If I understand your concern, don't hardcode those constants as values except perhaps as defaults and store them with Properties and/or ResourceBundle(s). You might also read the Java Tutorial on Properties. Something like,
Properties props = new Properties();
FileInputStream in = new FileInputStream("my.proprties");
props.load(in);
String v = props.get("CONSTANT_ONE", "const1"); // <-- the "1" is a default.
Then if you need to change the property later you only have to modify the properties file.

java best data structure for two to many relations

So I have three important factors, filenames which there are many, there will also be duplicates, violation types which there are 6 of, and the data relating to them.
I was thinking of using a Map for this but it only accepts two types, so I want to sort the data by the filename and for every entry under that filename, i want to retrieve the violation type, from what i want it to retrieve all the matches from the data, so say it's a map I could of said map.get(filename, violation) and it will retrieve all the results that match that.
Is there a data structure that can allow me to do this? or am I being lazy and should just sort the data myself when it comes to outputting it.
One other way to approach this would be to use a custom Class for holding the needed data. Essentially 'building' your own node that you can iterate over.
For example! you could create the following class object: (Node.java)
import java.util.*;
public class Node
{
private String violationType;
private String dataInside;
public Node()
{
this("", "");
}
public Node(String violationType)
{
this(violationType, "");
}
public Node(String violationType, String dataInside)
{
this.violationType = violationType;
this.dataInside = dataInside;
}
public void setViolationType(String violationType)
{
this.violationType = violationType;
}
public void setDataInside(String dataInside)
{
this.dataInside = dataInside;
}
public String getViolationType()
{
return violationType;
}
public String getDataInside()
{
return dataInside;
}
}
ok, great, so we have this 'node' thing with some setters, some getters, and some constructors for ease of use. Cool. Now lets see how to use it:
import java.util.*;
public class main{
public static void main(String[] args){
Map<String, Node> customMap = new HashMap<String, Node>();
customMap.put("MyFilename", new Node("Violation 1", "Some Data"));
System.out.println("This is a test of the custom Node: " + customMap.get("MyFilename").getViolationType());
}
}
Now we have a map that relates all of the data you need it to. Now, you'll get a lot of people saying 'Don't reinvent the wheel" when it comes to things like this, because built in libraries are far more optimized. That is true! If you can find a data structure that is built into java that suits your needs, USE IT. That's always a good policy to follow. That being said, if you have a pretty custom situation, sometimes it calls for a custom approach. Don't be afraid to make your own objects like this, it's easy to do in Java, and it could save you a lot of time and headache!
EDIT
So, after re-reading the OP's question, I realize you want an entire list of associated data for the given violation of a given filename. In which case, you would switch the private String dataInside to something like private ArrayList<String> dataInside; which would allow you to associate as much data as you wanted, still inside that node, just inside of an arraylist. Also note, you'd have to switch up the getters/setters a little to accomodate a list, but that's not too bad.
You could use a custom class for a mapkey which contains the two fields filename and violation type. When doing so you need to implement equals() and hashCode() methods do ensure instances of that class can be used as key for map.
You can use TreeMap. TreeMap is sorted according to the natural ordering of its keys.
TreeMap<String, List<String>> map = new TreeMap<String, List<String>>();

how to use same string in two java files

Sorry for my bad English and for maybe stupid question but I'm new in Java.
I need use same string in 2 java files for example:
In first java file I've got code for sending emails, I've got string set to default email:
public String mail = new String ("lala#gmail.com");
and I use this string in code for send email:
email.addTo(mail);
In second java file something like set up where can user set new email address I want to have same string, connected with string in first java file. When user put new email String mail will be change to new email address and in email.addTo(mail); will be use this new address
How can I do this?
use Shared Preferences, you can store it as key-value Pair. value being your email and key can be any unique string which you want to identify it with.
I'm a bit confused with the question, but I'll take a stab at it. Basically, you would like to have one String in a given file be used in multiple locations. This is easily done using class-level variables and making them publicly accessible.
For example, in the file:
EmailObject.java
public class EmailObject {
public static final String mail = "lala#gmail.com";
// The rest of your code
}
Another file can access this like so:
OtherObject.java
public void sendEmail() {
EmailMessage email = new EmailMessage();
email.addTo(EmailObject.mail);
}
Note the static and final modifiers on the original. This ensures that you do not need an actual instance of EmailObject to access the string and it also ensures that the string is never modified accidentally by some other object.
There are, of course, other ways to do this, but this one matches your code the most. This is also a very "Java" solution. Android has other ways to share data (as indicated by the other answer).
The simplest way that I would not recommend is to have a public static field:
class A {
public static String commonString;
}
class B {
public void methodThatUsesString () {
// Do stuff with the string
Log.d("I have the string", A.commonString);
}
}
If you have two Activities, and one starts another, you can send data through Intents.
The forementioned SharedPreferences way is a good solution too, if the email address is a persistent thing, a preference if you will, and not just data reqired for an operation.
You can keep a reference of one instance of a class in the otherone, and access it's fields through it:
class A {
public String commonString;
}
class B {
private final A instaceOfA;
public B (A instanceOfA) {
this.instanceOfA = instanceOfA;
}
public void methodThatUsesString () {
// Do stuff with the string
Log.d("I have the string", instanceOfA.commonString);
}
}
Or even use a getter or setter if performance is not an issue.
Many answers depending on how the string will be used.
If it's a constant string, one that will never change, never use final static String
public final static String AUTHOR_MAIL = "lala#gmail.com";
Then you can use it in a static way wherever you want.
email.addTo(MyClass.AUTHOR_MAIL);
If this String will be used in different Activities you can not access it directly (you can not tell if the other Activity is still alive). You have to use Persistence Mechanisms such as SharedPreferences or directly send needed data in your Intent.
If it's in a helper class inside your Activity, you can just use mObject.mail to get it.

Simulate named parameters in Java

I write a little web API which should it make easy to create URIs. Each resource class should contain a method createURI which takes the needed parameters. This method should use a helper method, populateUriTemplate, in the background to create an URI string. populateUriTemplate needs key value pairs to populate an URI template. In another language like Scala or Python I would use named parameters, but Java doesn't support them. So the question is: How to simulate named parameters in Java?
The straight forward solution would be to create a map:
public String createUri(int id, String name){
Map<String, Object> params = new HashMap<String, Object>();
params.put("id", id);
params.put("name", name);
return populateUriTemplate(params);
}
But I don't like to create a map first and put each parameter to it.
Another idea is to use a static method, param, to create key value pairs:
public String createUri(int id, String name){
return populateUriTemplate(param("id", id), param("name", name));
}
Looks much better to me!
It could be refined a bit to make it more self-explanatory, even if a few more characters are needed:
public String createUri(int id, String name){
return populateUriTemplate(key("id").value(id), key("name").value(name));
}
I've also thought of the builder pattern, but this would force the user of my API to create an explicit builder for each resource class, what would be tedious without a benefit. The type of the parameter is not important, as long as a proper implemented toString method exists.
My favourite is one of the both approaches with the static methods above (param(key, value) or key(k).value(v)). Do you know a better way to simulate named parameters in this case?
For some ideas on the builder pattern, you could see this blog post by Stephan Schmidt.
You also just gave me the idea to do the following, with fluent interfaces, a Callable, and a static method:
createUri().id(5).name("dennetik").call();
Which would require createing a Callable class (CreateUri) with the static method:
public static final CreateUriFluentInterface createUri() {
return FluentInterface.of(new CreateUri(), CreateUriFluentInterface.class);
}
And a fluent interface, like this:
public interface CreateUriFluentInterface {
public CreateUriFluentInterface id(Integer id);
public CreateUriFluentInterface name(String name);
}
Which isn't that much boilerplate code, is it?
(Well, if you tone down that horribly named CreateUriFluentInterface a bit, it isn't.)
(You would probably have CreateUriFluentInterface extend Callable<String>, to be able to reroute the call to Callable#call())
populateUriTemplate("id",id, "name",name);
void populateUriTemplate(Object... nvs){
for(int i=0; i<nvs.length/2; i++)
....
}
Maybe you like this approach:
class Params {
private HashMap<String, Object> allParams = new HashMap<String,Object>();
public Params(ParamEntry...params) {
for( ParamEntry p : params ) {
allParams.put(p.name, p.value);
}
}
public getParam(String name) {
return allParams.get(name);
}
class ParamEntry {
public String name;
public Object value;
}
}
public String createUri(Params.ParamsEntry ... params){
return populateUriTemplate(new Params(params));
}
To call it use
createUri(new Param.ParamEntry("name", valueObject) );
Inside the populateUriTemplate...
just use params.get("name");
Spring MVC does exactly this. As well as being able to bind requests to specific methods in controller classes, you can bind request parameters to method parameters. You can have a look to see how it works, but basically it picks a strategy to map the right request parameter to the right method parameter.
You basically get something like:
public String createUri(#RequestParam int id, #RequestParam String name){
return populateUriTemplate(id, name);
}
This is almost silly and slightly off topic, but using Lombok's #Builder annotation takes this closer to the desired result.
Furthermore if the builder, builder method and build method names are changed to _ they almost disappear:
import static foo.Template._;
class Resource {
String createURI(String id, String name) {
return populateURITemplate(_.id(id).name(name)._());
}
String populateURITemplate(Template t ){
return t.id+"="+t.name;
}
}
#Builder(builderClassName = "_", builderMethodName = "_", buildMethodName = "_" )
class Template {
static _ _ = _();
String id;
String name;
}
Named parameters are not the way:
Named parameters do not make your code any cleaner in this case. I would argue that they make things more complex and error prone in Java because you lose type safety and you lose compiler warnings about identifiers that do not exist.
TypeSafe Immutable Fluent Builders:
I wrote an article on a UrlBuilder implementation earlier this year, it shows a type safe fluent interface that enforces order of construction for mandatory input and allows for optional parts with sane defaults as well.
Now I will be the first to admit that the approach I use is fairly verbose, but it is extremely productive once that initial price is paid. It works with dependency injection and is easily unit testable and most importantly is composable for specialization.
final URL url1 = new UrlBuilder().scheme("http").host("www.google.com").build();
System.out.println("url1 = " + url1);
final URL url2 = new UrlBuilder().scheme("https").userInfo("xkcd", "correcthorsebatterystaple").host("admin.xkcd.com").build();
System.out.println("url2 = " + url2);
Produces:
url1 = http://www.google.com
url2 = https://xkcd:correcthorsebatterystaple#admin.xkcd.com
I am addressing the verbosity of the anonymous inner class implementations of the interfaces with another approach I am experimenting with; type safe implementations of value objects from interfaces using dynamic proxies.
This will do away with the boilerplate value objects and replace them with Map<String,?> but put a dynamically generated type safe immutable Interface wrapper around them.
I encourage you to read about both of these and see how combining them gives you a better solution than named properties ever would.
When I get time to refactor my UrlBuilder with the dynamic proxies I will post another blog post about it as well.
Named Parameters via Guice
If you are dead set on named parameters then I would recommend looking at Guice #Named bindings. You still lose the compile type checks and safety but at least you get some validations from Guice.
public class RealBillingService implements BillingService {
#Inject
public RealBillingService(#Named("Checkout") CreditCardProcessor processor,
TransactionLog transactionLog) {
...
}

Is there an elegant way to convert ISO 639-2 (3 letter) language codes to Java Locales?

E.g. eng, spa, ita, ger
I could iterate all locales and compare the codes, but I wonder whether there is a more elegant & performant way to achieve this....
Thanks a lot for any hints :)
I don't know if there's an easy way to convert the 3-letter to the 2-letter versions, but in a worse case scenario, you could create a Map of them, like so:
String[] languages = Locale.getISOLanguages();
Map<String, Locale> localeMap = new HashMap<String, Locale>(languages.length);
for (String language : languages) {
Locale locale = new Locale(language);
localeMap.put(locale.getISO3Language(), locale);
}
Now you can look up locales using things like localeMap.get("eng");
Edit: Modified the way the map is created. Now there should be one object per language.
Edit 2: It's been a while, but changed the code to use the actual length of the languages array when initializing the Map.
You can use constructor Locale(String language), where language is the 2 letter ISO-639-1 code. I think the easiest way to convert ISO-639-2 to ISO-639-1 would be to create HashMap<String,String> constant.
Some modified code from my project, which has a similar requirement. We have our own historical timezone format so we can't use standard libraries.
public class MyProjectTimeZoneFactory {
private static Map timeZoneDb;
/**
* Set up our timezone id mappings; call this from any constructor
* or static method that needs it.
*/
private static void init() {
if(null == TimeZoneDb) {
timeZoneDb = new HashMap(); // Maybe a TreeMap would be more appropriate
timeZoneDb.put(" ","GMT+00");
timeZoneDb.put("EAD ","GMT+10");
timeZoneDb.put("JST ","GMT+9");
// etc.
}
}
public static TimeZone getTimeZone(String id)
throws CommandFormatException {
init();
TimeZone tz;
if(timeZoneDb.containsKey(id)) {
tz = TimeZone.getTimeZone((String)timeZoneDb.get(id));
} else {
throw new CommandFormatException("Invalid Timezone value");
}
return tz;
}
}
You could argue that it would be better to have the map in configuration rather than code - perhaps in a properties file. That may be true - but do remember the Pragmatic Programmers' rule 'Your not going to need it'.

Categories

Resources