Switching Language at Runtime in LightSwitch HTML Client

Introduction

Hi, back again and as I promised in my last post, I will show you, how we can change the language in our localized LightSwitch HTML 2013 application.
HINT: This article describes a “hack” and if anybody have a better idea-let’s talk about it! :-)

Prerequisites

You have to be familiar with localizing a LightSwitch HTML 2013 application.
If not, take a look here: Walkthrough: Localizing a LightSwitch Application.

Some Code

First, create a new JS file in the scripts folder and reference it in the default.hm.
Add following lines to the new file: (I got this code from Javascript Madness: Query String Parsing from Jan Wolter. Great stuff, Jan. THX!)

// This is public domain code written in 2011 by Jan Wolter and distributed
// for free at http://unixpapa.com/js/querystring.html
//
// Query String Parser
//
//    qs= new QueryString()
//    qs= new QueryString(string)
//
//        Create a query string object based on the given query string. If
//        no string is given, we use the one from the current page by default.
//
//    qs.value(key)
//
//        Return a value for the named key.  If the key was not defined,
//        it will return undefined. If the key was multiply defined it will
//        return the last value set. If it was defined without a value, it
//        will return an empty string.
//
//   qs.values(key)
//
//        Return an array of values for the named key. If the key was not
//        defined, an empty array will be returned. If the key was multiply
//        defined, the values will be given in the order they appeared on
//        in the query string.
//
//   qs.keys()
//
//        Return an array of unique keys in the query string.  The order will
//        not necessarily be the same as in the original query, and repeated
//        keys will only be listed once.
//
//    QueryString.decode(string)
//
//        This static method is an error tolerant version of the builtin
//        function decodeURIComponent(), modified to also change pluses into
//        spaces, so that it is suitable for query string decoding. You
//        shouldn't usually need to call this yourself as the value(),
//        values(), and keys() methods already decode everything they return.
//
// Note: W3C recommends that ; be accepted as an alternative to & for
// separating query string fields. To support that, simply insert a semicolon
// immediately after each ampersand in the regular expression in the first
// function below.

function QueryString(qs) {
    this.dict = {};

    // If no query string  was passed in use the one from the current page
    if (!qs) qs = location.search;

    // Delete leading question mark, if there is one
    if (qs.charAt(0) == '?') qs = qs.substring(1);

    // Parse it
    var re = /([^=&]+)(=([^&]*))?/g;
    while (match = re.exec(qs)) {
        var key = decodeURIComponent(match[1].replace(/\+/g, ' '));
        var value = match[3] ? QueryString.decode(match[3]) : '';
        if (this.dict[key])
            this.dict[key].push(value);
        else
            this.dict[key] = [value];
    }
}

QueryString.decode = function (s) {
    s = s.replace(/\+/g, ' ');
    s = s.replace(/%([EF][0-9A-F])%([89AB][0-9A-F])%([89AB][0-9A-F])/gi,
	function (code, hex1, hex2, hex3) {
	    var n1 = parseInt(hex1, 16) - 0xE0;
	    var n2 = parseInt(hex2, 16) - 0x80;
	    if (n1 == 0 && n2 < 32) return code;
	    var n3 = parseInt(hex3, 16) - 0x80;
	    var n = (n1 << 12) + (n2 << 6) + n3;
	    if (n > 0xFFFF) return code;
	    return String.fromCharCode(n);
	});
    s = s.replace(/%([CD][0-9A-F])%([89AB][0-9A-F])/gi,
	function (code, hex1, hex2) {
	    var n1 = parseInt(hex1, 16) - 0xC0;
	    if (n1 < 2) return code;
	    var n2 = parseInt(hex2, 16) - 0x80;
	    return String.fromCharCode((n1 << 6) + n2);
	});
    s = s.replace(/%([0-7][0-9A-F])/gi,
	function (code, hex) {
	    return String.fromCharCode(parseInt(hex, 16));
	});
    return s;
};

QueryString.prototype.value = function (key) {
    var a = this.dict[key];
    return a ? a[a.length - 1] : undefined;
};

QueryString.prototype.values = function (key) {
    var a = this.dict[key];
    return a ? a : [];
};

QueryString.prototype.keys = function () {
    var a = [];
    for (var key in this.dict)
        a.push(key);
    return a;
};

Then, replace in default.htm

<script type="text/javascript" src="Scripts/msls-2.5.1-min.js"></script>

with

<script type="text/javascript" src="Scripts/msls-2.5.1.js"></script>

This is because we have to change something in ootb LS javascript. At line 1781 you will find the snippet, where LightSwitch set the default language of the application:

    languages = [];
    
    preferredLanguage = msls_getClientParameter("preferredLanguage");
    preferredLanguage = preferredLanguage ? $.trim(preferredLanguage.toUpperCase()) : null; 

Change these lines to

    languages = [];
    var qs = new QueryString();
    var curLang = qs.value("lang");
    preferredLanguage = curLang; //msls_getClientParameter("preferredLanguage");
    preferredLanguage = preferredLanguage ? $.trim(preferredLanguage.toUpperCase()) : null;

So, what are we doing here? We just want to tell our application our preferred language via URL parameter.
LightSwitch now “knows” on each start, that our preferred language is in our parameter. To set this value we need a control (I preferred a dropdown list, because it easier to use this on a mobile device) which redirects to the same location with a new parameter:

http://myLSApplication.local/HTMLClient
to
http://myLSApplication.local/HTMLClient/?lang=de-DE

Adding a Control to Change the Language

Now, let’s build a control to change the language via UI. I think, a good location for this control is the standard command bar.
First, add a new button on your start page. Add following lines to the post_render method:

    myapp.Home.MyBtn_postRender = function (element, contentItem) {
    // Write code here.
    var $langSwitcher = $('<div id="langSwitcherDiv" style=" z-index:10000; color:#ffffff; " >' +
        '<select id="myLanguages" onchange="switchLanguage(this.value)">' +
        '<option value="de-DE" ' + getCurrentLanguage("de-DE") + '> DE </option>' +
        '<option value="en-US" ' + getCurrentLanguage("en-US") + '> EN </option>' +
        '</select></div>');
    $(element)
      .empty()
      .append($langSwitcher);
};

function getCurrentLanguage(l) {
    var qs = new QueryString();
    var curLang = qs.value("lang");
    if (curLang != undefined && curLang != "") {
        if (curLang == l)
            return "selected='selected'";
    }
    return "";
} 

function switchLanguage(value) {
    window.location.href = msls.application.rootUri + "/HTMLClient?lang=" + value;
};

Of course, change the options of the dropdown list to your needs.
What we are doing here is, first we create a jQuery object of the new dropdown list.
Then we clear the element object of our button and add our new dropdown list.
The function “getCurrentLanguage” is needed to preselect the actual language. Maybe there is a better solution for it, but this works.
And “switchLanguage” makes the redirect to our start page with a new parameter. (This can be done more dynamically, of course.)

Conclusion

And here is our result:

  1. Start your application:
    IMG_1297

  2. Tab on the dropdown list:
    IMG_1298

  3. The page is displayed in your selected language:
    IMG_1299

I know, this is not a perfect solution, but it is working!
Any feedback would be appreciated!

That’s all for now, folks!

Comments

  1. Reblogged this on SutoCom Solutions.

  2. Jesús says:

    Hi, I’m Jesus, from Madrid, Spain. Thanks for sharing your solution to switch localization, it seems very interesting. Anyway, I guess I cannot make it work properly, so I would like to ask you for your help:

    I use VisualStudio 2013 and the localization on the server and html lightswitch client. I tried to follow your steps:

    1. I created a new js file on the scripts folder, I named it QueryString.js and referenced it into “default” html with

    2. I changed the reference into . Please, note that I’m using 2.5.2, not 2.5.1, I don’t now if that is important.

    3. I changed the lines you mentioned on msls-2.5.2.js

    4. I added the control to change the language on my start screen.

    After that, when I debug the app, I get the following error messages (translated from spanish):

    – 0x800a1391 Error on runtime JavaScript: ‘QueryString’ is not defined (Exception in line 1797, column 5 in http://localhost:51023/HTML/Scripts/msls-2.5.2.js)

    – 0x800a1391 Error on runtime JavaScript: ‘msls’ is not defined (Exception in line 1, column 1 in http://localhost:51023/HTML/Scripts/Generated/generatedAssets.js)

    – 0x800a1391 Error on runtime JavaScript: ‘msls’ is not defined (Exception in line 66, column 13 in http://localhost:51023/HTML/

    Any help would be great, thanks in advance!
    Jesús

  3. Jesús says:

    Sorry, some javascript lines were missing on the previous question. I reproduce the complete text:

    Hi, I’m Jesus, from Madrid, Spain. Thanks for sharing your solution to switch localization, it seems very interesting. Anyway, I guess I cannot make it work properly, so I would like to ask you for your help:

    I use VisualStudio 2013 and the localization on the server and html lightswitch client. I tried to follow your steps:

    1. I created a new js file on the scripts folder, I named it QueryString.js and referenced it into “default” html with script type=”text/javascript” src=”Scripts/QueryString.js”

    2. I changed the reference script type=”text/javascript” src=”Scripts/msls-2.5.2-min.js into script type=”text/javascript” src=”Scripts/msls-2.5.2.js. Please, note that I’m using 2.5.2, not 2.5.1, I don’t now if that is important.

    3. I changed the lines you mentioned on msls-2.5.2.js

    4. I added the control to change the language on my start screen.

    After that, when I debug the app, I get the following error messages (translated from spanish):

    – 0x800a1391 Error on runtime JavaScript: ‘QueryString’ is not defined (Exception in line 1797, column 5 in http://localhost:51023/HTML/Scripts/msls-2.5.2.js)

    – 0x800a1391 Error on runtime JavaScript: ‘msls’ is not defined (Exception in line 1, column 1 in http://localhost:51023/HTML/Scripts/Generated/generatedAssets.js)

    – 0x800a1391 Error on runtime JavaScript: ‘msls’ is not defined (Exception in line 66, column 13 in http://localhost:51023/HTML/

    Any help would be great, thanks in advance!
    Jesús

  4. Jesús says:

    Sorry for the disturbance, I found out what happened, I put the reference after the msls-2.5.2 reference in the default.htm document. Once I put it on the line above it works like charm.
    It’s great! thanks for sharing!

  5. Hi, Jesus. Thank you for your feedback. In fact, it is important to keep the right order of the JS references. ;-)
    I’m glad you resolve this by yourself!

  6. mohamed says:

    Hi , am mohamed , i read this article more and more
    and try but there is no result

    is there any problem to user msls-2.0.0 ?

    • Ronald Rink says:

      Hi mohamed, I am not aware of such a restriction. When you debug the code, where does the error actually occur? Could you please in detail where the language changer does not work? Thanks, Ronald

  7. Lujain Mohamed says:

    Hi, I am Lujain i tried this article but i have no result , I want to make my web application to support Arabic and English any one can help me ?

    • Ronald Rink says:

      Hi Lujain, could please describe what exactly is not working? Otherwise it is difficult to say, what went wrong. Thanks! Regards, Ronald

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: