Actually there is no problem at all (OK there are two ;-)
On the server-side just create a resource-bundle, that is
reading in the property-files used by GWT to create the
localized HTML-pages.
Here comes the first problem. The property-files used for
GWT must be encoded in UTF-8, Java's resource-bundle
expects ISO-8859-1. But there are implementations out there
that can be used (GWT is using one as well that is mentioned
in the docs, so you might try that one out as well).
The other problem is that the algorithm used for loading
the correct resource-bundle differs from the one used
in GWT. Giving a Locale of e.g. "en_US" and the following
available resource-bundles
- file_de.properties
- file.properties
GWT loads file.properties all the time where Java loads
the de-files if the System-Locale is DE. As well, the
default-Locales of GWT for some languages are different
(AFAIK en_US instead of en_EN and es_AG instead of es_ES)
leading to funny effects when localizing e.g. currencies.
Regards, Lothar
I'm using GWT 1.4 here and haven't migrated to 1.5, yet.
Using GWT.create will be difficult on the server-side, because
the Locale can be different for every request, so you need
a second parameter. Using ResourceBundle on the other side allows
a similar call:
ResourceBundle rb = ResourceBundle.getBundle(AdminToolsI18NConstants.class.getName(), loc);
> I suppose not, so maybe I'd have to come up with some kind of clever
> factory scheme which uses GWT.create in client code and whatever my
> own implementation is in server code.
You can implement your own version of ResourceBundle, that is
reading in the property-files and use reflection on the interface
to get the annotations. With Proxy-classes it should also be possible
to create something similar to GWT.create.
If I have very much time, I'd might be able to program something
like this, but you shouldn't wait for that, at the moment my spare
time is about zero ;-)
Regards, Lothar
> Maybe another approach would be to extend the GWT-i18n tool, which
> already does the properties file parsing and creates the interface
> file.
> I have not looked at this tool yet, but maybe it can be extended to
> generate another file for the backend, that implements the interface
> methods and builds the messages from the ResourceBundle.
That would make force everybody to actually use the tool regularily
to create the interface-file. I - for example - doesn't use the tool
but add methods to the interface-file by hand while developing the
GUI. In the long run, I realized that I'm faster and I'm also adding
Javadoc-comments describing the meaning behind the entry.
Regards, Lothar
Actually I think you can do that with the functionality of
the JVM itself using Proxies:
------
public interface MyConstants implements Messages{
public String LocalizedMessage(String argument);
}
------
public class MyConstantsProxy implements java.lang.reflect.InvocationHandler{
private ResourceBundle rb;
public MyConstantsProxy(ResourceBundle rb){
this.rb = rb;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String value = rb.getString(method.getName());
for (int i = 0; args != null && i < args.length; i++){
if (args[i] == null) continue;
value = value.replaceAll("\\{" + i + "\\}", args[i].toString());
}
return value;
}
}
------
To use the proxy you have to get the resource-bundle and create the
proxy, so an imaginary GWT.create-method might look like the following:
------
public static Object create(Class clazz, Locale loc){
ResourceBundle rb = ResourceBundle.getBundle(clazz.getName(), loc);
MyConstants constants = (MyConstants) Proxy.newProxyInstance(
getClass().getClassLoader(), new Class[]{MyConstants.class},
new MyConstantsProxy(rb));
}
------
And use the method normally:
MyConstants constants = (MyConstants) GWT.create(MyConstants.class,
new Locale("de", "DE"));
System.out.println(constants.LocalizedMessage("this is the message"));
> Maybe it would only work for the Constants
> and Messages interfaces, and a minor selection of others, but it would
> be quite useful.
I think restricting it to Messages and Constants is OK because
these two are the only ones anyway where the special behavior
of GWT.create is used.
> Unfortunately, it would be difficult to implement
> this outside of GWT because the client code a) can't use any classes
> not supported by GWT and b) must use GWT.create with a literal class
> (not a variable) as the parameter.
The skeleton above should work and is not in conflict with the
current concept of GWT. You need the second parameter because
you must be able to get different "classes" in dependence from
the Locale being set on the client.
The "only" thing missing is implementing your own version of
ResourceBundle with the same algorithm for deciding which
property-file to be used in dependence to the requested Locale
(no use of System-Locale but directly fall back to the main
property-file, wrong default Locales for EN and ES, etc.)
and UTF-8 to be used as encoding. The latter can be done
by using Properties.load(Reader) implementing all the methods
of ResourceBundle or write an InputStream that is reading in
the data as UTF-8 and converts all non-8859_1-characters to
the escaped sequence being accepted by Properties. Other
things like caching of created proxies, support of the
annotations that came with GWT 1.5 etc. IMHO can be added later.
And that's the part where I don't have the time at the moment. ;-)
Regards, Lothar