Login Register

Localization nowhere near robust enough - proposed solution

I've been working with Dojo/Dijit for a few weeks now. Part of the requirements of the project I'm working on is a robust localization theme - every piece of text on the site needs to be localized. Perhaps I'm missing something, but the localization that Dojo seems to have available seems woefully inadequate.

The i18n functions seem to allow localization text to only be retrieved via Javascript calls - they can't be used natively in any widgets at all. Couple this with the fact that many widgets refuse to expose API to easily set text programmatically (e.g. AccordionPane, MenuItem), the end result is a mess.

Here's how I solved this problem on my own project.
-Extending each widget with an extra attribute indicating the code of the text to retrieve, which would be dynamically inserted in the right place.
-Adding a global function to get localized text, taking a widget and the code as parameters, and returning the localized string.
-Adding a new dijit.Message tag, designed specifically to display localized text.

Here is an example of how my solution works. This has been generalized (I only have a single global function) and the generalized version hasn't been tested yet, so just throwing code at you. 8-)

function getLocalizedText(widget, code)
{
  var text =  dojo.i18n.getLocalization("projectName", "translations", <%= locale %>);
  //we can change "translations" based on the ID/type of the widget if we want.
  //Or, more likely, just provide a separate global function.
  return text[code];

}

dojo.declare("dijit.Message", dijit._Widget, {
  code: "",
  textFunc: null,
  startup: function()
  {
  	dojo.addOnLoad(this, "initialize");
  },
  initialize: function()
  {
    try
    {
       var text = "";
       if (this.textFunc) 
         eval("text = " + this.textFunc + "(this, this.code)";
       if (text)
         this.domNode.innerHTML = text; 
    }
    catch(e)
    { 
      console.debug(e);
      this.domNode.innerHTML = "not found";
    }
  }
});

//Mixin for localized tags. 
//Tags which inherit this can localize one of their attributes.
dojo.declare("dijit.Localized", null, {
code: "",
textFunc: null,
titleAttribute: null,
  
postMixInProperties: function(){
  if (this.code && this.textFunc)
  {
     var text = "";
     eval("text = " + this.textFunc + "(this, this.code)";
     if (text)
       this[this.titleAttribute] = text;
     this.inherited("postMixInProperties",arguments);
  }
});

//example: localized Dialog tag.
dojo.declare("dijit.Dialog2", [dijit.Dialog, dijit.Localized], {
titleAttribute: "title"
});

Sample HTML code:


...

Et voila. Localization just got much easier for me. Thoughts?

don't follow you

Not sure what you mean by "can't be used natively" by widgets.

Refusing to expose APIs to change text is really an issue with the widget design, not the i18n system, if I understand correctly. We've reduced APIs for customization in general because they tend to cause bloat. Global functions are generally avoided in Dojo, and the resource bundles are typically factored to allow for more efficient downloading and optimization.

I'm not sure if this helps you, but one of the abstractions we offer is templated widgets, with a substitution syntax that works well with our i18n bundles.

When it comes to text in your widgets that is not provided by JavaScript, or any content in your page, Dojo does not attempt to do i18n for that -- I guess that's the core of your complaint? Dojo handles i18n for content it generates, but you still need a localization to come from the server for the basic page content. It just didn't seem feasible to drive this from JavaScript. I did toy with the idea of having a declarative mechanism to do localized tags at one point. That would be interesting to pursue, but I'm not sure how it would invalidate the underlying system. I'd think that would just be an add-on.

Yes, I was more talking

Yes, I was more talking about the widgets (hence why this is in the Dijit forum rather than the Dojo forum). It just seems strange to me to have such a robust mechanism in Dojo, which has such a strong widgeting aspect to it, and then completely fail to include any such localizability in the tags that are available, forcing the designer to grab constant onLoad functions and keep setting titles and things - especially considering the number of tags I've come across which don't even expose an API to do even that.

As I said, I've made my own solution to this, and it works quite well indeed, but it still seems odd that there isn't one built into Dijit.

I still don't see it

Still don't see how this is better than the pattern used in widgets to just load the bundle and assign the properties in postMixInProperties.

That's what I'm doing. But

That's what I'm doing. But you have to manually subclass every widget you want that to happen with. In other words, Dijit is very big into making sure its content is localized, but there's a plain text "title" attribute (which often can't even be set via Javascript) which seems to contradict the whole idea.

this?

Are you talking about the title attribute to widgets like (for example)

hello

In that case, you have to localize the contents of title on the server, the same way that you localize "hello world":

buenos dias

The problem is that only

The problem is that only works if it's being set once and for all. What if you want to dynamically change titles, or to create widgets programmatically? You'd have to keep one set of localization on the server (for the instant tags) and one set on the client (for the dynamic ones). That is, in fact, exactly the problem we ran into.

innerHTML

Hmm, I see your point (you have a menu item that says "change language", right?), but even if the title changed without going to the server, how would the innerHTML of the title pane change?

Not really...

I'm not talking about changing the language on the fly. Simply that if you have localization in place, and e.g. you want to declaratively have a contentPane with a localized title, there is no way to do so. You have to tack on an onLoad handler to each pane, and set the title programmatically - made even harder by the fact that there is no setTitle() method for it. Alternatively, you could do like I did and make custom widgets - but I just think that this sort of thing would be common enough that it should be a part of the framework.

hmm

Hmm, I don't see any difference between the title of the ContentPane and it's content (ie, the innerHTML of the ContentPane). Both need to be localized, and both of those things happen on the server.

Doesn't that defeat the

Doesn't that defeat the whole point of having Dojo localization capabilities? If you want to change things on the fly, you need to keep localization on Dojo - but you ALSO then have to keep localization on the server. So you now have two separate properties files, probably with a lot of overlap between the two. Sure it's doable, but it's harder to maintain.

No, not really

We do not have -- and never had -- a stated goal of trying to localize the entire page, which is why I think perhaps the title of this thread is a bit overblown. It just didn't seem feasible to do that, at least as our initial goal, except perhaps for isolated cases where there's a very small amount of text being driven to the client (in which case, perhaps a custom solution or a pattern like the one you're discussing could be developed on top of the existing framework)

We're trying to generalize resources needed by the Dojo framework and any javascript you write on top of it such that you'll never have to hard code a native language string or something that involves 'cultural formats'. So yes, you still rely on your traditional server-side localization frameworks. You need localization resources for Dojo-based code, which gets shipped down in a streamlined fashion to the client, and you also need localization resources for the rest of the page -- hopefully that would not involve a lot of overlap, as it represents a disjoint set of data on the page, though I suppose some overlap is possible. And yes, that means two formats, two translation processes, etc. The win is that you can reuse Dojo widgets without deploying, or even being aware of, localized resources for those widgets. Using the XD loader, those resources might not even come from your server. That's kind of cool.

So you want to take this further. Building a larger i18n system is certainly something worth discussing. Hopefully the underlying APIs will support that. I just think it's a leap to say that the lack of such a system makes the current framework flawed.

I guess the main problem was

I guess the main problem was in this statement:

"We're trying to generalize resources needed by the Dojo framework and any javascript you write on top of it such that you'll never have to hard code a native language string or something that involves 'cultural formats'."

The problem is that Dojo does not seem to be geared towards utilizing Javascript for its widgets. Most of the functionality is in the templating system and declarative tags. There's precious little functionality available to set that text programmatically - as I said, many tags don't even have a "setLabel" or "getValue" function.

Given that emphasis on declarative widgets, and an already existing framework in place to localize text, it just seemed to me to be the next logical step to integrate that with the declarative format already in place. I was simply surprised to see no effort at all to do that.

Perhaps "flawed" is the wrong word, but I feel it could be extended relatively easily to allow it.

setLabel()

I agree with what peller wrote above, but to address your statement that many widgets don't have a setLabel() function, I agree that needs to be fixed, and actually there's at least one bug open about it already.