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