1 // ==========================================================================
  2 // Project:   The M-Project - Mobile HTML5 Application Framework
  3 // Copyright: (c) 2010 M-Way Solutions GmbH. All rights reserved.
  4 // Creator:   Dominik
  5 // Date:      29.11.2010
  6 // License:   Dual licensed under the MIT or GPL Version 2 licenses.
  7 //            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
  8 //            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
  9 // ==========================================================================
 10 
 11 m_require('core/foundation/object.js');
 12 
 13 /**
 14  * @class
 15  *
 16  * M.I18N defines a prototype for for internationalisation and localisation within
 17  * The M-Project. It is used to set and get the application's language and to
 18  * localize any string within an application.
 19  *
 20  * @extends M.Object
 21  */
 22 M.I18N = M.Object.extend(
 23 /** @scope M.I18N.prototype */ {
 24 
 25     /**
 26      * The type of this object.
 27      *
 28      * @type String
 29      */
 30     type: 'M.I18N',
 31 
 32     /**
 33      * The system's default language.
 34      *
 35      * @type String
 36      */
 37     defaultLanguage: 'en_us',
 38 
 39     /**
 40      * This property is used to map the navigator's language to an ISO standard
 41      * if necessary. E.g. 'de' will be mapped to 'de_de'. Currently we only provide
 42      * support for english and german. More languages are about to come or can be
 43      * added by overwriting this property.
 44      *
 45      * @type Object
 46      */
 47     languageMapper: {
 48         de: 'de_de',
 49         en: 'en_us'
 50     },
 51     
 52     /**
 53      * This method returns the localized string for the given key based on
 54      * the current language.
 55      *
 56      * @param {String} key The key to the localized string.
 57      * @returns {String} The localizes string based on the current application language.
 58      */
 59     l: function(key) {
 60         return this.localize(key);
 61     },
 62 
 63     /**
 64      * This method returns the localized string for the given key based on
 65      * the current language. It is internally used as a wrapper for l() for
 66      * a better readability.
 67      *
 68      * @private
 69      * @param {String} key The key to the localized string.
 70      * @returns {String} The localizes string based on the current application language.
 71      */
 72     localize: function(key) {
 73         if(!M.Application.currentLanguage) {
 74             M.Application.currentLanguage = this.getLanguage();
 75         }
 76 
 77         if(this[M.Application.currentLanguage] && this[M.Application.currentLanguage][key]) {
 78             return this[M.Application.currentLanguage][key];
 79         } else if(this[M.Application.defaultLanguage] && this[M.Application.defaultLanguage][key]) {
 80             M.Logger.log('Key \'' + key + '\' not defined for language \'' + M.Application.currentLanguage + '\', switched to default language \'' + M.Application.defaultLanguage + '\'', M.WARN);
 81             return this[M.Application.defaultLanguage][key];
 82         }  else if(this[this.defaultLanguage] && this[this.defaultLanguage][key]) {
 83             M.Logger.log('Key \'' + key + '\' not defined for language \'' + M.Application.currentLanguage + '\', switched to system\'s default language \'' + this.defaultLanguage + '\'', M.WARN);
 84             return this[this.defaultLanguage][key];
 85         } else {
 86             M.Logger.log('Key \'' + key + '\' not defined for both language \'' + M.Application.currentLanguage + '\' and the system\'s default language \'' + this.defaultLanguage + '\'', M.WARN);
 87         }
 88 
 89     },
 90 
 91     /**
 92      * This method sets the applications current language and forces it to reload.
 93      *
 94      * @param {String} language The language to be set.
 95      */
 96     setLanguage: function(language) {
 97         if(!this.isLanguageAvailable(language)) {
 98             M.Logger.log('There is no language \'' + language + '\' specified!', M.WARN);
 99             return;
100         } else if(language && language === M.Application.currentLanguage) {
101             M.Logger.log('Language \'' + language + '\' already selected', M.INFO);
102             return;
103         }
104 
105         if(localStorage) {
106             localStorage.setItem('$' + M.Application.name + '_lang$', language);
107             location.reload();
108         }
109     },
110 
111     /**
112      * This method is used to get a language for the current user. This process is divided
113      * into three steps. If one step leads to a language, this on is returned. The steps are
114      * prioritized as follows:
115      *
116      * - get the user's language by checking his navigator
117      * - use the application's default language
118      * - use the systems's default language
119      *
120      * @returns {String} The user's language.
121      */
122     getLanguage: function() {
123         var language = null;
124 
125         if(localStorage) {
126             language = localStorage.getItem('$' + M.Application.name + '_lang$');
127         }
128 
129         if(language) {
130             return language;
131         } else if(navigator) {
132             var regexResult = /([a-zA-Z]{2,3})[\s_.-]?([a-zA-Z]{2,3})?/.exec(navigator.language);
133             if(regexResult && this[regexResult[0]]) {
134                 return regexResult[0].toLowerCase();
135             } else if(regexResult && regexResult[1] && this.languageMapper[regexResult[1]]) {
136                 var language = this.languageMapper[regexResult[1]];
137                 return language.toLowerCase();
138             } else if(M.Application.defaultLanguage) {
139                 return M.Application.defaultLanguage.toLowerCase();
140             }
141         } else {
142             return this.defaultLanguage;
143         }
144     },
145 
146     /**
147      * This method checks if the passed language is available within the app or not. 
148      *
149      * @param {String} language The language to be checked.
150      * @returns {Boolean} Indicates whether the requested language is available or not.
151      */
152     isLanguageAvailable: function(language) {
153         if(this[language] && typeof(this[language]) === 'object') {
154             return true;
155         } else {
156             M.Logger.log('no language \'' + language + '\' specified.', M.WARN);
157             return false;
158         }
159     }
160 
161 });