File:Languages.js
/**
* @module Languages
* @namespace springroll
* @requires Core
*/
(function(window, undefined)
{
var Loader = include('springroll.Loader'),
Application = include('springroll.Application'),
EventDispatcher = include('springroll.EventDispatcher');
/**
* Keeps track of the user locale, by auto-detecting the browser language, allowing a user
* selection, and automatically modifying any url that runs through the CacheManager.
*
* @class Languages
* @extends springroll.EventDispatcher
* @constructor
* @param {Object} config The language settings to be used.
* @param {String} config.default The default language name to use if asked for one that is
* not present.
* @param {Array} config.languages An array of all supported languages, with entries being
* locale ids (dialects allowed). Locale ids should be lower
* case.
* @param {String} [config.replace="%LANG%"] A string to replace in urls with the current
* language.
*/
var Languages = function(config)
{
if (_instance)
{
throw "Only one Languages can exist at a time!";
}
_instance = this;
EventDispatcher.call(this);
/**
* The value to replace with the current language in URLS.
* @property {String} _replace
* @private
* @default "%LANG%"
*/
this._replace = "%LANG%";
/**
* The current language.
* @property {String} _current
* @private
*/
this._current = null;
/**
* The default language.
* @property {String} _default
* @private
*/
this._default = null;
/**
* Available languages.
* @property {Array} languages
* @public
*/
this.languages = null;
/**
* A dictionary of translated strings, set with setStringTable().
* @property {Dictionary} _stringTable
* @private
*/
this._stringTable = null;
};
// Reference to the prototype
var s = EventDispatcher.prototype;
var p = EventDispatcher.extend(Languages);
/**
* Fired when the chosen language has changed.
* @event changed
* @param {String} language The newly chosen language.
*/
/**
* Configure
* @method setConfig
* @param {Object} config The language settings to be used.
* @param {String} config.default The default language name to use if asked for one that is
* not present.
* @param {Array} config.languages An array of all supported languages, with entries being
* locale ids (dialects allowed). Locale ids should be lower
* case.
* @param {String} [config.replace="%LANG%"] A string to replace in urls with the current
* language.
*/
p.setConfig = function(config)
{
if (!config.languages || !config.default)
{
throw "Languages requires a language dictionary and a default language!";
}
this._replace = config.replace || this._replace;
this._default = config.default;
this.languages = config.languages;
//set the initial language
this.setLanguage(this.getPreferredLanguages());
//connect to the CacheManager
this.modifyUrl = this.modifyUrl.bind(this);
Application.instance.loader.cacheManager.registerURLFilter(this.modifyUrl);
};
/**
* Get the singleton instance of the Languages object.
* @property {springroll.Languages} instance
* @static
* @public
*/
var _instance = null;
Object.defineProperty(Languages, "instance",
{
get: function()
{
return _instance;
}
});
/**
* The current language.
* @property {String} current
* @readOnly
* @public
*/
Object.defineProperty(p, "current",
{
get: function()
{
return this._current;
}
});
/**
* Gets the preferred languages from the browser.
* @method getPreferredLanguages
* @return {Array} The list of preferred languages in order of preference.
*/
p.getPreferredLanguages = function()
{
var rtn;
var navigator = window.navigator;
if (navigator.languages)
{
//use the newer Firefox and Chrome language list if available.
rtn = navigator.languages;
}
else if (navigator.language)
{
//fall back to the browser's UI language
rtn = [navigator.language || navigator.userLanguage];
}
else
rtn = [];
return rtn;
};
/**
* Sets the current language, based on specified preferences and what is available.
* @method setLanguage
* @param {Array|String} languageList The list of preferred languages in order of preference,
* or a single language.
*/
p.setLanguage = function(languageList)
{
if (!languageList) return;
if (!Array.isArray(languageList))
languageList = [languageList];
var chosen;
for (var i = 0, len = languageList.length; i < len; ++i)
{
var language = languageList[i].toLowerCase();
if (this.languages.indexOf(language) >= 0)
{
//check to see if we have the full language and dialect (if included)
chosen = language;
break;
}
else if (language.indexOf("-") >= 0)
{
//check to see if we have the language without the dialect
language = language.split("-")[0].toLowerCase();
if (this.languages.indexOf(language) >= 0)
{
chosen = language;
break;
}
}
}
if (!chosen)
chosen = this._default;
if (chosen != this._current)
{
this._current = chosen;
this.trigger('changed', chosen);
}
};
/**
* Sets the string table for later reference.
* @method setStringTable
* @param {Dictionary} dictionary The string table, with keys that you would use to reference
* the translations.
*/
p.setStringTable = function(dictionary)
{
this._stringTable = dictionary;
};
/**
* Gets a string from the current string table.
* @method getString
* @param {String} key The key of the string to get.
* @return {String} The translated string.
*/
p.getString = function(key)
{
return this._stringTable ? this._stringTable[key] : null;
};
/**
* Gets a formatted string from the current string table. See String.format() in the Core
* module.
* @method getFormattedString
* @param {String} key The key of the string to get.
* @param {Array|*} args An array or list of arguments for formatting.
* @return {String} The translated string.
*/
p.getFormattedString = function(key)
{
var string = this._stringTable ? this._stringTable[key] : null;
if (string)
return string.format(Array.prototype.slice.call(arguments, 1));
else
return null;
};
/**
* Modifies a url, replacing a specified value with the current language.
* @method modifyUrl
* @param {String} url The url to modify to a language specific version.
*/
p.modifyUrl = function(url)
{
while (url.indexOf(this._replace) >= 0)
url = url.replace(this._replace, this._current);
return url;
};
/**
* Destroys the Languages object.
* @method destroy
*/
p.destroy = function()
{
var loader = Application.instance.loader;
if (loader)
{
loader.cacheManager.unregisterURLFilter(this.modifyUrl);
}
this.modifyUrl = this.languages = null;
_instance = null;
s.destroy.call(this);
};
// Assign to namespace
namespace('springroll').Languages = Languages;
})(window);