Localization technique - java

I am currently developing a desktop game as part of my CS course .
Although it is not required I want my application to support Localization
So I browsed the web and found two techniques
- ResourceBundle
- properties file
However I can not decide which is better suited for me , I simply need localized messages and labels for the GUI.
Also I am confused on how such files/classes should be named
for example if FooBar extends ResourceBundle
should be like FooBar_UNIX_en_US
Btw , the assignment is an Entanglement (by gopherwoods studio) clone (Desktop not applet)
~Thanks

You use both - from your program's point of view, they are ResourceBundles, from the translators point of view they are property files. A ResourceBundle can load its strings (only strings, though) from a property file.
So you simply put files like Messages.properties (the default), Messages_eo.properties (the esperanto translation), Messages_de.properties (german translation), Messages_de_AT.properties (special strings for austrian german, overriding the general ones).
In your program you then simply do ResourceBundle bundle = ResourceBundle.getBundle("Messages"), and the runtime builds your resource bundle for the current locale from the property files.
If you need to translate other things than strings, you would need .class files instead, subclassing ResourceBundle. You can even mix both, but I would then better split them to different bundles (i.e. one text bundle and one for the dynamic resources).

You are in the right direction, the convention is typically Name_<language>_<country>.
ResourceBundle itself can use properties file to back the localization string, so you can use that. That way you don't have to compile new classes for each localization you would like to support. Just create a new properties file for the language.
Check out ResourceBundle.getBundle() factory method.

I believe using resource bundles would be the best technique.
Java itself, will attempt to reference your resource bundels by most specific to least specific (most generic).
If you have the following resources:
resource
resource_en
resource_en_GB
resource_fr
resource_fr_CA
And the end users local is en_NZ (New Zeland) he would be shown what is in the resource_en.
However, someone from Quebec, Canada would most likely be shown what is in the resource_fr_CA.
Hope that helps.

Related

Get content of a package

I want to implement a function that will take package name as input and list all the contents(only files) inside that package.
public List<String> getContents(String packageName) {
...
}
Example input
packageName = com.spring.com.demo
Expexted output
Class1.java
Class2.java
...
What is the best way to accomplish this task?
You're talking about java's 'classloader' system, which is a slight misnomer, in that it can also load resources other than classes. Point is, classes are a resource that are located somewhere, and the JVM itself needs to find them. After all, when you are running your main class and it refers to 'new Foobar()', the jvm needs to find Foobar.class somehow, read the bytes, and turn them into a new class definition.
Java's classloader system is generalized in two ways:
You can call on it to find you stuff.
You can for example write:
MyApp.class.getResource("icons/share.png")
and get a URL object you can pass straight to e.g. ImageIcon. This way, you can ship your icons for your GUI app together with your class files, and it's completely unified: However the system is loading the classes, be it from disk, from inside a jar file, from eclipse's module system if it's an eclipse plugin, or from the network - this way you're loading your images from the same place.
You can make your own
Let's say you want to write a system that loads classes (and other resources, like images) directly from the web. You can do that: You can make your own ClassLoaders.
Now for the crux of the matter
That means ClassLoader is an abstract concept that lists which features it has. It's like any other interface / abstract class in that regard: It's a template that defines what you can do with one, so that anybody can provide you with an implementation of it.
Here's the crucial thing you must understand so that you know why what you want is impossible (and why the commonly called out 'reflections' library is a hack that doesn't universally work):
The ClassLoader abstract simply has no list command.
Hence, listing? Simply not possible. The only command it does have is 'load Resource X', X being some path-like string. That is all it has. The java classloader system is never in need to 'list all classes in a package', not even when there's a star import (which is just a thing javac knows about, at the class file level star imports aren't a thing). The JVM just needs to e.g. load resource '/java/lang/String.class' - hence, the command 'here is a path, please give me the bytes for it' is all that is neccessary.
The solution to have lists anyway
During compilation, the abstractions do support 'list'. After all, the compiler really does just read java files from a directory (which supports 'list all files inside it'), you can't for example tell the compiler 'please compile all .java files in this .jar file). So, at compile time, you can make a list of resources.
So here's the trick: Save that in a text file and ask for the text file during runtime. Then translate each line in the text file to the full resource path and then ask for each of those. Thus, using just the one API call you have available to you at runtime ('load resource at path X'), you can have a list system anyway. It's just that during the compilation/build/packing step you need the tools that compile/build/pack to do some work and make you a text file with the details.
This is called the SPI (Service Provider Interface) system and java itself uses it - it's how JDBC drivers and e.g. charset implementations are found.
You can use this yourself in this three step process:
Define an interface or abstract class that serves as the thing 'providers' will implement/extend. Let's say it is com.ranjan.MyService`.
At the provider end: Write an implementation for it. Let's say it's com.zwitserloot.ServiceImpl.
During compilation, ensure that in the same place the class files end up (e.g. in the jar file for example), there's META-INF/services/com.ranjan.Myservice (a text file). This file contains the fully qualified class name of each 'provider' class: com.zwitserloot.ServiceImpl is what's on the first (and only) line.
At runtime: Use java.util.ServiceLoader and it'll take care of everything.
Your specific use case
From comments it seems like you don't really need to 'list classes', you have a bunch of classes and need to know if they are 'valid', for some definition of 'valid'. You can either just Class.forName them, though this will also initialize them (run its static initializers). Alternatively, you can run YourOwnClass.class.getResource("com.spring.com.demo.Class1.class"), and check that [A] you get an actual resource (and not null, indicating it doesn't exist), and [B] do whatever validation you want to do on this. For example, toss it through bytebuddy or ASM or some other class format editor and check if it can parse it.

Java ResourceBundle loads strings from wrong file

I create jar file which is enbedded and called as applet from ASP.Net web forms application.
I use ResourceBundle to load localized strings from properties.
I created 3 properties files:
localizedStrings.properties
localizedStrings_de.properties
localizedStrings_en.properties
and load strings with
ResourceBundle labels = ResourceBundle.getBundle("localizedStrings", Locale.GERMAN);
However all strings are loaded from strange location : Login.aspx (which is in the same directory with this applet.jar)
When I call Collections.list(labels.getKeys()).get(0)
I see some contents of Login.aspx in there, very unusual, i have tried with some other bundle names and same results.
What could be the problem here?
I would not say it is strange location. Since you haven't provided any location really, the natural place to look for is the Java classpath. If you want to change it somehow, you need to use fully qualified name for base name, i.e.:
ResourceBundle.getBundle("com.my.company.localizedStrings", Locale.GERMAN);
The only doubt I have, since you probably use something like J# is whether that will work. It should.

How to find all Java method calls and given parameters in a project programmatically?

I have a multilingual web application that gets all of the translations from a single object, for example lang.getTranslation("Login") and the object is responsible for finding the translation in an xml file in the user's language.
What I'd like to do is a script / custom static analysis that outputs all the missing translations and translations that are no more used in the application. I believe I should start by programmatically finding every call to the getTranslation method and the string parameter, storing the data in a special structure and comparing it to all the translation files.
Is there a library that will allow me to do this easily? I already found Javassist but I can't use it to read the parameter values. I also tried grepping, but I'm not sure if that's a robust solution (in case there will be a call to another class that has a getTranslation method). I know Qt has a similar mechanism for finding translatable strings in the code, but that's a totally different technology..
I'm asking this because I'm quite sure there's a good existing solution for this and I don't want to reinvent the wheel.
Ok, here's how I did it. Not the optimal solution, but works for me. I created a utility program in Java to find all the method calls and compare the parameters to existing translations.
Find all classes in my project's root package using the Reflections library
Find all getTranslation method calls of the correct class in the classes using the Javassist library and create a list of them (contains: package, class, row number)
Read the appropriate .java files in the project directory from the given row until the ';' character
Extract the parameter value and add it to a list
Find the missing translations and output them
Find the redundant translations and output them
It took me a while to do this, but at least I now have a reusable utility to keep the translation files up to date.

Correct java.util.ResourceBundle Organization

I have an internationalized project with many modules. Each module has its own set of bundles:
- database-module
+ com_naugler_project_database.properties
+ com_naugler_project_database_fr.properties
- mapping-module
+ com_naugler_project_mapping.properties
+ com_naugler_project_mapping_fr.properties
However, many of the internationalized terms are redundant (such as 'OK' or 'Cancel') and I would like have these terms in one place for easier maintenance and development.
I found this helpful explanation of ResourceBundle inheritance, but it appears as though a (not?) common ancestor would not be internationalized properly because:
- common-module
+ com_naugler_project.properties
+ com_naugler_project_fr.properties <-- this is not an ancestor
- database-module
+ com_naugler_project_database.properties
+ com_naugler_project_database_fr.properties <-- of this
Am I way off base with my bundle organization? What is the right way to provide a common internationalized ancestor?
What you want seems to be the hierarchy of Resources, that is, you probably want one class to derive from over (or being composed of some specific part and some common part).
Basically, ResourceBundle was not designed for it, and you are on your own.
But you want some advice, I suppose.
Make sure that common terms are really common. That is things like "OK", "Cancel", "Next >", "< Previous", "Open", "File", etc. will have common translations in their context. I mean it is fairly safe to translate such standard items only once, but if you want to use them in different context, you still need another entry. Why? Because "Open" button translation would be different than "Open" dialog title translation in quite a few languages.
Move all the .properties files to one place (for example a directory called "resources"). Of course module-specific files should be separated to different subdirectories...
Create a resource factory that will return an instance of the ResourceBundle class (or your own Facade - this approach will actually let you share some common bundle).
The good practice for large applications is to create some Language Pack, that is to separate language resources to their own directories (i.e. /resources/en, /resources/fr, /resources/zh-Hans). The problem with this approach, however would be the fact that you would need to implement resource fallback by yourself (with the aid of an article you mention in the question, the hierarchy is actually resource loading hierarchy). That means some special cases like falling back from language tag "nb" to "no" but not falling back from "nn"; falling back from "zh-CN" and "zh-SG" to "zh-Hans" and then to "zh" but falling back from "zh-HK" and "zh-TW" and "zh-MO" to "zh-Hant" and then to your default language, not falling from "pt-BR" to "pt" (falling back to default language instead).
Seems like a lot of work? Well, but the maintenance work afterwards would be minimal.
One thing might come in handy PropertyResourceBundle have two constructors that will let you load whatever properties file you want, namely: PropertyResourceBundle(InputStream stream) and PropertyResourceBundle(Reader reader). Honestly, in large projects standard ResourceBundle mechanism has too many limitations, so you really need your own resource access layer...
As Paweł Dyda indicated, resource bundles on their own do not support class hierarchy resolution. However the Rincl project, which my company just released, should do just what you're looking for---and handle UTF-8 .properties files and XML properties files as well. It even does message formatting for you on the fly.
As explained in the in the Rincl quick start, you can simply implement Rincled and then call getResources(); Rincl will load your resource bundles even if declared in a parent class or interface:
public class MyClass extends BaseClass implements Rincled {
…
final String userName = "Jane Doe";
//Retrieve the formatted user label based upon the current locale.
//en-US: "Settings for user Jane Doe."
//pt-BR: "Definições para usuário Jane Doe."
final String userLabel = getResources().getString("user-label", userName);
…
Rincl is available at http://rincl.io/ with an intro and even a full lesson on Java internationalization. There are many new features coming up, but the latest version should already work for you. Let me know if you have any questions or problems.

Architecture setup for constantly changing text, property files? In a Java EE environment

In a Java EE environment, we are normally used to storing text in a property/resource file. And that property file is associated with some view HTML markup file. E.g. if your label 'First Name' changes to 'Full Name' on a HTML page, you could use the property to make that update.
firstName=First Name
someOtherData=This is the data to display on screen, from property file
If you are in an environment, where it is difficult to update those property files on a regular basis, what architecture are developers using to change text/label content that would normally reside in a property file? Or let's say you need to change that content before redeploying a property file change. A bad solution is to store that in a database? Are developers using memcache? Is that usually used for caching solutions?
Edit-1 A database is really not designed for this type of task (pulling text to display on the screen), but there are use-cases for a database. I can add a locale column or state field, also add a column filter by group. If I don't use a database or property file, what distributed key/value solution would allow me to add custom filters?
Edit-2 Would you use a solution outside of the java framework? Like a key/value datastore? memcachedb?
I want to assure you that if you need constant changes on localized texts, for example they tend to differ from deployment to deployment, database is the way to go. Well, not just the database, you need to cache your strings somehow. And of course you wouldn't want to totally re-build your resource access layer, I suppose.
For that I can suggest extending ResourceBundle class to automatically load strings from database and store it in WeakHashMap. I choose WeakHashMap because of its features - it removes a key from the map when it is no longer needed reducing memory footprint. Anyway, you need to create an accessor class. Since you mentioned J2EE, which is pretty ancient technology, I will give you Java SE 1.4 compatible example (it could be easily re-worked for newer Java, just put #Override when needed and add some String generalization to Enumeration):
public class WeakResourceBundle extends ResourceBundle {
private Map cache = new WeakHashMap();
protected Locale locale = Locale.US; // default fall-back locale
// required - Base is abstract
// #Override
protected Object handleGetObject(String key) {
if (cache.containsKey(key))
return cache.get(key);
String value = loadFromDatabase(key, locale);
cache.put(key, value);
return value;
}
// required - Base is abstract
// #Override
public Enumeration getKeys() {
return loadKeysFromDatabase();
}
// optional but I believe needed
// #Override
public Locale getLocale() {
return locale;
}
// dummy testing method, you need to provide your own
// should throw MissingResourceException if key does not exist
private String loadFromDatabase(String key, Locale aLocale) {
System.out.println("Loading key: " + key
+ " from database for locale:"
+ aLocale );
return "dummy_" + aLocale.getDisplayLanguage(aLocale);
}
// dummy testing method, you need to provide your own
private Enumeration loadKeysFromDatabase() {
return Collections.enumeration(new ArrayList());
}
}
Because of some strange ResourceBundle's loading rules, you would actually need to extend WeakResourceBundle class to create one class each for supported languages:
// Empty Base class for Invariant Language (usually English-US) resources
// Do not need to modify anything here since I already set fall-back language
package com.example.i18n;
public class MyBundle extends WeakResourceBundle {
}
One supported language each (I know it sucks):
// Example class for Polish ResourceBundles
package com.example.i18n;
import java.util.Locale;
public class MyBundle_pl extends WeakResourceBundle {
public MyBundle_pl() {
super();
locale = new Locale("pl");
}
}
Now, if you need to instantiate your ResourceBundle, you would only call:
// You probably need to get Locale from web browser
Locale polishLocale = new Locale("pl", "PL");
ResourceBundle myBundle = ResourceBundle.getBundle(
"com.example.i18n.MyBundle", polishLocale);
And to access the key:
String someValue = myBundle.getString("some.key");
Possible gotchas:
ResourceBundle requires Fully Qualified Class Name (thus the package name).
If you omit Locale parameter, default (which means Server) Locale would be used. Be sure to always pass Locale while instantiating ResourceBundle.
myBundle.getString() could throw MissingResourceException if you follow my suggestion. You would need to use try-catch block to avoid problems. Instead you may decide on returning some dummy string from database access layer in the event of missing key (like return "!" + key + "!") but either way it should probably be logged as an error.
You should always attempt to create Locale objects passing both language and country code. That is just because, languages like Chinese Simplified (zh_CN) and Chinese Traditional (zh_TW) for example, are totally different languages (at least in terms of writing) and you would need to support two flavors of them. For other countries, ResourceBundle will actually load correct language resource automatically (note that I have created MyBundle_pl.java, not MyBundle_pl_PL.java and it still works. Also, ResourceBundle would automatically fall-back to Enlish-US (MyBundle.java) if there is no resource class for given language (that is why I used such a strange class hierarchy).
EDIT
Some random thoughts about how to make it more awsome.
Static factories (avoid using ResourceBundle directly)
Instead of directly instantiating the bundles with ResourceBundle, you could add static factory method(s):
public static ResourceBundle getInstance(Locale aLocale) {
return ResourceBundle.getBundle("com.example.i18n.MyBundle", aLocale);
}
If you decide to change the name of WeakResourceBundle class to something more appropriate (I decided to use LocalizationProvider), you could now easily instantiate your bundles from consuming code:
ResourceBundle myBundle = LocalizationProvider.getInstance(polishLocale);
Auto-generated resource classes
Localized MyBundle classes could be easily generated via building script. The script could be either configuration file or database driven - it somehow needs to know which Locale are in use within the system. Either way, the classes share very similar code, so generating them automatically really makes sense.
Auto-detecting Locale
Since you are the one that implement the class, you have full control of its behavior. Therefore (knowing your application architecture) you can include Locale detection here and modify getInstance() to actually load appropriate language resources automatically.
Implement additional Localization-related methods
There are common tasks that needs to be done in Localized application - formatting and parsing dates, numbers, currencies, etc. are usual examples. Having end user's Locale in place, you can simply wrap such methods in LocalizationProvider.
Gee, I really love my job :)
You speak about property files, but at execution time, you are likely to have a resource bundle or something that want a list of key/value pairs (maybe even depending of the locale)
You can store data in whatever format and then use it to contruct the right ressource bundle with it. Even if it comes from memory. So database can perfectly do that, because, properties would all be loaded at startup, cached in JVM memory and that's all. (SELECT * FROM LOCALIZATION_DATA)
Don't use distributed cache for that, the data set you have is likely to be small anyway... what ? Maybe a few MB at worst. And access to that data must be instantaneous once loaded because all views will trigger access to it dozen, or even hundred of time per page.
If you want to update the data without restarting the application just add an administration screen somewhere with a "reload localization data", or even a screen that allow to update this type of data (but save to the file/DB/whatever)
From a workflow point of view, it depend of what you are trying to achieve.
The classic property file is the prefered way of doing this. You put it into versionning, together with the source code so you always have the translation up to date with the code. You want to debug V1.3.0.1 ? just get this version, and you'll use the property file that was used at this time. You added new code that require new keys ? Or just changed they key name for whatever reason ? You know that the code and your locatization information are linked into a coherant state. And this is automatic.
If your data is not under version control, you loose automatic versionning and history of your data. When you deploy/redeploy to a new machine, discrepancy can appear and even prevent the application from running propertly (if a new key is required but not added. This is not great, prone to errors and more manual interventions.
If you really need live updates, and really can't release new version for that, what i would do is to have two source for your data. The standard data, under version control, so your sure all is good for a new install from scratch. And the "customised data", in the server that can override standard values. The customized values are not lost when updating from version to version, because this is just the standard values that are updated.
If the change in the server is purely a one shoot customization, then you just go to the right admin webpage, use the customize localization data screen and that's all.
If the change is something that you'll want to keep for any new installation, you add it 2 time. One time in the server, one time in version control.
You could always use JNDI, or even consider a document repository like JCR for this sort of thing.
Not so sure a database couldn't handle this, I think what you are really looking for is a cache that can be invalidated when those properties change. Have you thought about using something like JBoss Infinispan (http://www.jboss.org/infinispan)? It's extremely simple to use, and can be distributed across multiple application servers.
Infinispan, once configured, can be used like a Map; keep in mind you can configure it to be distributed across a cluster!
If you don't mind using a NoSQL solution, I would recommend something like Redis or Memcache. Of course, I would advocate that you keep a local cache (why incur the cost of a network call, especially if these properties are not likely to change often?).
As requested by Berlin Brown, I add another answer, more focussed on it's specific needs :
From the amount of data you need (like a thousand of entries), you just need to load your property file at startup by specifying a remote URL.
Data is cached in JVM memory for maximum performance.
Depending on your workflow you then have a background process that check for update on a regalar basis (let say each minute, hour, whatever is enough for you) or you can have a "button" in administration "refresh localization data" developper use when an update is needed.
No need for database. No need for memcached, no need for NoSQL. a simple URL accessible from production server. In term of security and dev it is easier, faster and more flexible.
Implementation details: if you use the standard format, you'll have a file per language/contry. Don't forget to update for all languages or bundle them together (using a zip for exemple).

Categories