vektor
vektor

Reputation: 2926

Share localization strings from backend to JavaScript

Consider a JSP application with a couple of JavaScript files. The backend is fully localized, using several .properties files, one for each language. Rendered HTML contains strings in the correct language - all of this is the usual stuff and works perfectly.

Now however, from time to time I need to use some localized string in a JavaScript resource. Suppose e.g.:

function foo() {
  alert('This string should be localized!');
}

Note that this is somewhat similar to the need to refer some AJAX endpoints from JavaScript, a problem well solved by a reverse JS router. However the key difference here is that the backend does not use the router, but it does use the strings.

I have come up with several approaches, but none of them seems to be good enough.

Parameters

JSP that renders the code to invoke foo() will fetch the string:

foo('<%= localize("alert.text") %>');

function foo(alertText) {
  alert(alertText);
}

Pros: It works. Cons: Method signatures are bloated.

Prototypes

JSP renders a hidden span with the string, JS fetches it:

<span id="prototype" class="hidden">This string should be localized!</span>

function foo() {
  alert($('#prototype').text());
}

Pros: Method signatures are no longer bloated. Cons: Must make sure that the hidden <span>s are always present.

AJAX

There is an endpoint that localizes strings by their key, JS calls it. (The code is approximate.)

function foo() {
  $.ajax({ url : '/ajax/localize', data : { key : 'alert.text' } })
      .done(function(result) {
          alert(result);
      } );
}

Pros: Server has full control over the localized result. Cons: One HTTP call per localized string! Any of the AJAX calls fail, the logic breaks.

This can be improved by getting multiple strings at once, but the rountrip problem is an essential one.

Shared properties files

Property file containing the current language is simply exposed as an additional JS resource on the page.

<script src="/locales/en.js" /> // brings in the i18n object

function foo() {
  alert(i18n.alert.text);
}

Pros: Fast and reliable. Cons: All the strings are pulled in - also the ones we don't need or want to expose to the user.

This can be improved by keeping a separate set of strings for JS, but that violates the DRY principle.

Now what?

So that's it, that's the ideas I've had. None of them is ideal, all have their own share of problems. I am currently usings the first two approaches, with a mixed success. Are there any other options?

Upvotes: 4

Views: 1115

Answers (1)

Turnerj
Turnerj

Reputation: 4288

Your idea with a shared properties file is the neater solution out of the 4 ideas you suggested. A popular CMS I use called Silverstripe actually does the same thing, loads a localised JS file that adds the strings to a dictionary, allowing a common API for retrieving the strings.

One point made in the comments is about including localised strings for a particular view. While this can have some uses under particular situations where you have thousands of strings per localisation (totaling more than a few hundred KBs), it can also be a little unnecessary.

Client-side

Depending how many other JS resources you are loading at the same time, you may not want another request per view just to add a few more strings for that locale. Each view's localisation would need to be requested separately which can be a little inefficient. Give the browser all the localisations in one request and let it just read from its cache for each view.

The browser caching the complete collection of locale strings can lead to a better user experience with faster page load times with one less request per view. For mobile users, this can be quite helpful as even with faster mobile internet, not every single request is lightning fast.

Server-side

If you go by the method suggested in the comments by having a locale.asp file generating the JS locale strings on the fly, you are giving the server a little more work per user. This won't be that bad if each user requests it once however if it is request per view, it might start adding up.

If the user views 5 different pages, that is 5 times the server is executing the JSP, building the data for the particular view. While your code might be basic if-statements and loading a few files from the filesystem, there is still overhead in executing that code. While it might not be a problem say for 10 requests per minute, it could lead to issues with 1,000 requests per minute.

Again, that extra overhead can be small but it just simply isn't necessary unless you really want many small HTTP requests instead of few larger HTTP requests and little browser caching.

Additional Thoughts

While this might sound like premature optimisation, I think it is a simple and important thing to consider. We don't know whether you have 5 users or 5,000, whether your users go see 5 different views or 500, whether you will have many/any mobile users, how many locales you want to support, how many different strings per locale you have.

Because of this I think it is best to see the larger picture of what the choice of having locale strings downloaded per view would do.

Upvotes: 1

Related Questions