Monthly Archives: September 2012

Quick and Dirty Localization With JavaScript

Here’s a quick and dirty JavaScript localization routine that provides basic localization (no support for plurals, etc) , operates on the DOM of the page and uses data-lang attribute for language keys storage. Lokalizr works with all major browsers, beginning with IE8. If you do not want to read the code below, you can just download and test the class from this link.

The Lokalizr JavaScript Class:

(function() {
    "use strict";

    /*
     * @class Lokalizr
     * @constructor Lokalizr
     * @param languages {Object} [required]
     * @param defaultLanguage {String} [optional]
     **/
    function Lokalizr(languages, defaultLanguage) {

        this.languages = languages || {};

        if(defaultLanguage) {
            this.localize(defaultLanguage);
        }
    }

    Lokalizr.prototype = {

    /*
     * @map ATTR
     * @public
     **/
    ATTRS: {
        lang: "data-lang"
    },

    /*
     * @map MESSAGES
     * @public
     **/

    MESSAGES: {
        invalid: "Invalid language code."
    },

    /*
     * @method localize
     * @public
     * @param langCode {String} [required]
     **/
    localize: function(langCode) {
        if(false === "querySelectorAll" in document) {
            return;
        }

        var
            lang = this.languages[langCode],
            attr = this.ATTRS.lang,
            elements = document.querySelectorAll("[" + attr + "]");

        if(!lang) {
            this.error(this.MESSAGES.invalid);
            return;
        }

        for(var i = 0, len = elements.length; i < len; i++) {
            var
                element = elements[i],
                key = element.getAttribute(attr);

            element.innerHTML = lang[key];
        }
    },

    /*
     * @method getLangString
     * @public
     * @param langCode {String} [required]
     * @param langString {String} [required]
     * @return {String}
     **/
    getLangString: function(langCode, langString) {
        if(langCode && langString) {
            return this.languages[langCode][langString];
        }
    },

    /*
     * @method error
     * @public
     * @param message {String} [required]
     **/
    error: function(message) {
        window.alert(message);
    }
};

    window.Lokalizr = Lokalizr;
})();

Example Markup:

<p data-lang="hello">Hello</p>
<p data-lang="good-morning">Good Morning</p>
<p data-lang="good-evening">Good Evening</p>

Usage:

(function() {
    // instantiate Lokalizr and localize automatically
    window.lang = new window.Lokalizr({
        "en-US": {
            "hello": "Hi",
            "good-morning": "Good morning",
            "good-evening": "Good evening"
        },
        "de-DE": {
            "hello": "Hallo",
            "good-morning": "guten Morgen",
            "good-evening": "guten Abend"
        }
     } , "de-DE");

     // localize on demand
     window.lang.localize("en-US");

     // get specific language keys
     window.console.log("language string",
         window.lang.getLangString("de-DE", "hello"));
     window.console.log("language string",
         window.lang.getLangString("de-DE", "good-morning"));
     window.console.log("language string",
         window.lang.getLangString("de-DE", "good-evening"));
 })();

That’s it! Did you check the demo?.

Enjoy the weekend!

Related Posts

JavaScript Mapper for RESTFul Methods

Recently I had to work with a bunch of RESTFul API methods, so instead of defining manually separate calls/methods for each API request, I decided to do it viceversa – to force JavaScript to create these methods automatically for me out of the RESTFul API by providing the URLS and other required data. In short – we provide a REST end-point and a key/value map of all API methods, which we plan to use, along with their data types, request type and callback functions, which is then processed by the RestMethodMapper class and converted on the fly to pure JavaScript methods to that class, so instead of calling:

"rest/user/get/my"

… We can execute:

window.mapper.userGetMy();

… And we can also pass as an argument the http parameters object:

window.mapper.userGetMy({
    firstName: "John",
    lastName: "Smith",
    id: 9999
});

… Which will result in an ajax request to:

rest/user/get/?firstName=John&lastName=Smith&id=9999&_=1348612389319

The API methods are defined in the constructor of the RestMethodMapper class like this – the first argument is the REST end-point, the second argument is a key/value object map of all RESTFul method and their properties (type, dataType, success and failure callbacks):

(function() {
    window.mapper = new AcidJs.RestMethodMapper(
        "rest/",
        {
            "user/get/": {
                type: "GET",
                cache: false,
                success: function(response) {
                    console.log("success:", response);
                },
                error: function(jqXHR, textStatus, errorThrown) {
                    console.log("error: ", jqXHR, textStatus, errorThrown);
                },
                dataType: "json"
            },
            "user/get/my/": {
                type: "get",
            },
            "msg/post/new/": {
                type: "post"
                success: function() { },
                error: function(jqXHR, textStatus, errorThrown) {
                    console.log("error: ", jqXHR, textStatus, errorThrown);
                },
                dataType: "json"
            }
        }
    );
})();

The above code can be tested like this:

window.mapper.userGet({
    firstName: "John",
    lastName: "Smith",
    id: 9999
}); // which will request rest/user/get/ with the parameters set as an argument object
window.mapper.userGetMy(); // which will request reset/user/get/my/
window.mapper.msgPostNew({
    id: 1234,
    body: "Lorem ipsum dolot sit amet"
}); // which will request rest/msg/post/new/ with the parameters set as an argument object

Below is the full source code of the RestMethodMapper class:

(function() {
    "use strict";

    /*
     * @namespace AcidJs
     **/
    if(undefined === window.AcidJs) {
        window.AcidJs = {};
    }

    /*
     * @class RestMethodMapper
     * @constructor
     * @param endpoint {String} [optional]
     * @param method {String} rest api method, for example "user/get/my"
     * @author Martin Ivanov http://acidjs.wemakesites.net
     **/
    function RestMethodMapper(endpoint, method) {
       endpoint = endpoint || "";
       method = method || {};

       var
           that = this;

       $.each(method, function(key, value) {
           (function() {
               var
                   name = that.restToMethod(key);

               if(!that[name]) {
                   var
                       ajaxConfig = {
                           url: endpoint + key
                       };

                   if(value) {
                       $.each(value, function(k, v) {
                           ajaxConfig[k] = v;
                       });
                   }

                   that[name] = function(data) {
                       if(data) {
                           ajaxConfig.data = data;
                       }
                       $.ajax(ajaxConfig);
                   };
                }
            })();
        });
    }

    RestMethodMapper.prototype = {
        /*
         * @method restToMethod convert RESTFul api method to a JavaScript method
         * @param url {String}
         * @return {String}
         **/
        restToMethod: function(url){
            if(!url) {
                return "";
            }

            var
                path = url.split("/"),
                methodName = "";

            for(var i = 0, len = path.length; i < len; i++) {
                methodName += (i === 0) ? path[i] : path[i].charAt(0).toUpperCase() + path[i].substr(1);
            }

            return methodName;
        }
    };

    window.AcidJs.RestMethodMapper = RestMethodMapper;
})();

The RestMethodMapper class uses jQuery, but obviously it can be easily implemented in pure JavaScript or with the help any other JavaScript library. I utilized jQuery, because the project required it, so I made use of that library’s $.ajax() method.

Related Posts

HTML5 Sticky Notes

Stickeez is a sticky notes JavaScript application using the new HTML5 File API, localStorage and CSS3. The data is fully persisted on the client. Stickeez also has an option for importing/exporting data so users can save their notes before cleaning up cookies or import notes to another browser. And finally – users can choose between 4 types of board styles – cork, fridge, whiteboard and skulls.

You can also use Stickeez as a Google Chrome extension.