Sharing the localization code between client and server

156 views
Skip to first unread message

Dobes

unread,
Sep 20, 2008, 6:25:28 PM9/20/08
to Google Web Toolkit
I like the way GWT does it's localization and it would be great if I
could use the same code in client AND server (especially, use it in my
code that is shared between client and server). Any idea how possible
this is?

Lothar Kimmeringer

unread,
Sep 21, 2008, 9:13:25 AM9/21/08
to Google-We...@googlegroups.com
Dobes schrieb:

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

Dobes

unread,
Sep 21, 2008, 7:04:01 PM9/21/08
to Google Web Toolkit
Hm, I see. But would I be able to use GWT.create(...) to create the
Constants subclass, and have it honor my @DefaultStringValue()
annotations?

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.

I guess I'll have to give this some more thought, the code to work
around this with extra client and server code that generates its own
strings instead of generating strings in shared code might still be
less work that implementing my own fancy GWT shared i18n stuff.

Kroc

unread,
Sep 22, 2008, 2:24:28 AM9/22/08
to Google Web Toolkit
I'm also looking for this kind of 'smart factory' to use localization
in my shared code.

One easy way (which is good enough for me), is MY.create() return
GWT.create() on client side and null on server side...
This solution may lead to null pointer exception.

If you find an elegant solution, please share it.
Thank

Vincent

Lothar Kimmeringer

unread,
Sep 22, 2008, 6:02:18 AM9/22/08
to Google-We...@googlegroups.com
Dobes schrieb:

> Hm, I see. But would I be able to use GWT.create(...) to create the
> Constants subclass, and have it honor my @DefaultStringValue()
> annotations?

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

Martin Trummer

unread,
Sep 23, 2008, 8:03:45 AM9/23/08
to Google Web Toolkit
Hi,

I am also interested in this.

Our approach is to write the texts into the properties files and then
use the GWT-i18n tool to generate the interface-files.
Of course this is not the best thing to do, because all the arguments
will be strings...

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.

regards, martin

Lothar Kimmeringer

unread,
Sep 23, 2008, 8:21:14 AM9/23/08
to Google-We...@googlegroups.com
Martin Trummer schrieb:

> 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

Dobes

unread,
Sep 23, 2008, 3:11:20 PM9/23/08
to Google Web Toolkit
It seems like it should be possible to implement a kind of server-side
GWT.create() that generates an subclass using cglib or one of the
other bytecode generators. Maybe it would only work for the Constants
and Messages interfaces, and a minor selection of others, but it would
be quite useful. 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.

Lothar Kimmeringer

unread,
Sep 23, 2008, 5:27:00 PM9/23/08
to Google-We...@googlegroups.com
Dobes schrieb:

> It seems like it should be possible to implement a kind of server-side
> GWT.create() that generates an subclass using cglib or one of the
> other bytecode generators.

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

Reply all
Reply to author
Forward
0 new messages