var nyc = nyc || {};
/**
* @external google.translate.TranslateElement
*/
/**
* @desc Class for language translation using the Google Translate Gadget
* @public
* @class
* @extends {nyc.EventHandling}
* @constructor
* @property {(String|Element|JQuery)} target The HTML DOM element that will provide language choices
* @param {nyc.Lang.Choices} languages The languages to provide
* @param {boolean} [isButton=false] Show as a button
*/
nyc.Lang = function(target, languages, isButton){
var codes = [], div = $(nyc.Lang.HTML);
nyc.lang = this;
this.isButton = isButton;
this.hints = [];
this.namedCodes = {};
$(target).append(div);
for (var code in languages){
var name = languages[code].val,
opt = $('<option></option>').attr('value', name).html(languages[code].desc);
$('#lang-choice').append(opt);
codes.push(code);
this.hints.push(languages[code].hint);
this.namedCodes[name] = code;
}
this.codes = codes.toString();
this.languages = languages;
div.trigger('create');
if (isButton){
$('#lang-choice-button').addClass('ctl ctl-btn');
$('#lang-choice-button span').remove();
}else{
$('#lang-choice-button').addClass('mnu');
}
$('body').addClass('lang-en');
$.getScript('//translate.google.com/translate_a/element.js?cb=nyc.lang.init');
};
nyc.Lang.prototype = {
/**
* @private
* @member {boolean}
*/
isButton: false,
/**
* @private
* @member {Array<string>}
*/
namedCodes: null,
/**
* @private
* @member {string}
*/
code: '',
/**
* @private
* @member {string}
*/
codes: '',
/**
* @private
* @member {google.translate.TranslateElement}
*/
translate: null,
/**
* @private
* @member {Array<string>}
*/
hints: null,
/**
* @private
* @member {Array<string>}
*/
languages: null,
/**
* @desc Initializes the class on callback from the Google Translate Gadget loader
* @public
* @method
*/
init: function(){
nyc.lang.translate = new google.translate.TranslateElement({
pageLanguage: 'en',
includedLanguages: nyc.lang.codes,
layout: google.translate.TranslateElement.InlineLayout.SIMPLE,
autoDisplay: false
}, 'lang-trans');
$('#lang-choice').show();
nyc.lang.initDropdown();
nyc.lang.setLangDropdown();
if (nyc.lang.isButton){
$('#lang-choice-button span').hide();
}else{
$('#lang-choice-button span').html('Translate').show();
}
nyc.lang.hack();
nyc.lang.trigger(nyc.Lang.EventType.READY, true);
},
/**
* @private
* @method
*/
showHint: function(){
var hints = this.hints;
if (!this.isButton){
var h = 0;
setInterval(function(){
$('#lang-choice-button span').html(hints[h] || 'Translate');
h++;
if (h == hints.length) h = 0;
}, 1000);
}
},
/**
* @private
* @method
*/
chooseLang: function(lang){
var choices = $('iframe.goog-te-menu-frame:first').contents().find('.goog-te-menu2-item span.text');
if (choices.length){
if (lang == 'English'){
nyc.lang.showOriginalText();
}else{
$(choices).each(function(){
if ($(this).text() == lang){
$(this).click();
return false;
}
});
}
if (!this.isButton){
$('#lang-choice-button span').show();
}
this.code = this.namedCodes[lang] || 'en';
this.css();
this.trigger(nyc.Lang.EventType.CHANGE, this.code);
}else{
var me = this;
setTimeout(function(){me.chooseLang(lang);}, 100);
}
},
css: function(){
$.each(this.codes.split(','), function(_, code){
$('body').removeClass('lang-' + code);
});
$('body')[this.code == 'en' ? 'removeClass' : 'addClass']('translated');
$('body').addClass('lang-' + this.code);
},
/**
* @private
* @method
*/
initDropdown: function(){
var me = this;
$('#lang-choice').change(function(){
me.chooseLang($(this).val());
});
},
/**
* @private
* @method
*/
showOriginalText: function(){
var googBar = $('iframe.goog-te-banner-frame:first');
$(googBar.contents().find('.goog-te-button button')).each(function(){
if ($(this).text() == 'Show original'){
$(this).trigger('click');
if ($('#lang-choice').val() != 'English'){
$('#lang-choice').val('English');
}
return false;
}
});
},
/**
* @private
* @method
*/
defaultLang: function(){
return navigator.language ? navigator.language.split('-')[0] : 'en';
},
/**
* @private
* @method
*/
setLangDropdown: function(){
var defLang = this.defaultLang(),
langCode = this.getCookieValue();
this.showHint();
if (!langCode){
for (var code in this.languages){
if (code.indexOf(defLang) == 0){
langCode = code;
break;
}
}
langCode = langCode || 'en';
}
$('#lang-choice').val(this.languages[langCode].val).trigger('change');
},
/**
* @desc Get the currently chosen language code
* @public
* @method
* @return {string} The currently chosen language code
*/
lang: function(){
return this.code;
},
/**
* @private
* @method
*/
hack: function(){
/*
* google translate doesn't translate placeholder attributes
* so we'll add a hidden span after input elements that have placeholders
* then use the placeholder text for the span
* then apply the translation of the span back to the placeholder
*/
$('input[placeholder]').each(function(){
var next = $(this).next();
if (!next.hasClass('lang-placeholder')){
$(this).after('<span class="lang-placeholder">' + $(this).attr('placeholder') + '</span>');
}else{
$(this).attr('placeholder', next.html().replace(/<font>/g, '').replace(/<\/font>/g, ''));
}
});
/*
* fix jquerymobile buttons crippled by font tags added by google translate
*/
$('font').each(function(){
if ($(this).data('lang-hack') != 'hacked'){
var parent = $(this).parent();
$(this).data('lang-hack', 'hacked');
if (parent.length && parent[0].tagName.toUpperCase() != 'FONT' && parent.data('role') == 'button'){
$(this).click(function(event){
event.stopImmediatePropagation();
parent.trigger('click');
});
}
}
});
$('body').css('top', 'auto');
$('#goog-gt-tt').remove();
setTimeout($.proxy(this.hack, this), 200);
},
/**
* @private
* @method
* @return {string}
*/
getCookie: function(){
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++){
var cookie = cookies[i];
while (cookie.charAt(0) == ' ') cookie = cookie.substring(1, cookie.length);
if ( cookie.indexOf('googtrans=') == 0 ){
return cookie.substring(10, cookie.length);
}
}
},
/**
* @private
* @method
* @return {string}
*/
getCookieValue: function(){
var cookie = this.getCookie();
if (cookie){
cookie = cookie.split('/');
cookie = cookie[2];
return cookie;
}
}
};
nyc.inherits(nyc.Lang, nyc.EventHandling);
/**
* @desc Enumeration for nyc.Lang event types
* @public
* @enum {string}
*/
nyc.Lang.EventType = {
/**
* @desc The ready event type
*/
READY: 'ready',
/**
* @desc The change event type
*/
CHANGE: 'change'
};
/**
* @desc A language choice for {@link nyc.Lang.Choices}
* @public
* @typedef {Object}
* @property {string} val The language value used by Google
* @property {string} desc The display value for the language
* @property {string=} hint The translation of the word 'Translate' in the language
*/
nyc.Lang.Choice;
/**
* @desc A mapping of {@link nyc.Lang.Choice} objects to language codes
* @public
* @typedef {Object<string, nyc.Lang.Choice>}
* @example
{
en: {val: 'English', desc: 'English', hint: 'Translate'},
es: {val: 'Spanish', desc: 'Español', hint: 'Traducir'}
}
*/
nyc.Lang.Choices;
/**
* @desc The class has completed initialization
* @event nyc.Lang#ready
* @type {boolean}
*/
/**
* @desc The language value has changed
* @event nyc.Lang#change
* @type {string}
*/
/**
* @private
* @const
* @type {string}
*/
nyc.Lang.HTML =
"<div id='lang-btn' title='Translate...'>" +
"<div id='lang-trans'></div>" +
"<select id='lang-choice' class='notranslate' translate='no'></select>" +
"</div>";