Skip to content

Instantly share code, notes, and snippets.

@quietlynn
Created April 10, 2012 16:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save quietlynn/2352474 to your computer and use it in GitHub Desktop.
Save quietlynn/2352474 to your computer and use it in GitHub Desktop.
Google+ i18n => Internationalization and localization on Google+
/*
Google+ i18n => Internationalization and localization on Google+
Copyright (C) 2012 Jingqin Lynn
Includes jQuery
Copyright 2011, John Resig
Dual licensed under the MIT or GPL Version 2 licenses.
http://jquery.org/license
Includes Sizzle.js
http://sizzlejs.com/
Copyright 2011, The Dojo Foundation
Released under the MIT, BSD, and GPL Licenses.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// ==UserScript==
// @name Google+ i18n
// @namespace http://project.quietmusic.org/j/
// @description Internationalization and localization on Google+
// @match https://plus.google.com/*
// ==/UserScript==
(function (name, url, main) {
'use strict';
//Use the <base> element to detect Google+ main page.
var base = document.querySelector('base');
if (!base || !base.href.match(/^https:\/\/plus\.google\.com(\/u\/\d+)?\/?/)) return;
var win = window;
if (typeof(unsafeWindow) != 'undefined') {
//Chrome V8 don't support unsafeWindow. Time for a hack.
if (window == unsafeWindow) {
var span = document.createElement('span');
span.setAttribute('onclick', 'return window;');
unsafeWindow = span.onclick();
}
win = unsafeWindow;
}
if (win.DependencyLoader.dependencyState(name) == win.DependencyLoader.Dependency.LOADING) {
main();
} else {
var dependencies = [
{ 'jQuery.gplus' : 'https://gist.github.com/raw/2645666/jquery.gplus.js' }
];
var me = {}; me[name] = url;
dependencies.push(me);
win.DependencyLoader.requireOrdered(dependencies,
null, function () {
win.DependencyLoader.require(name, main);
}
);
}
})(
'org.quietmusic.project.gplus.i18n',
'https://gist.github.com/raw/2352474/gplus.i18n.user.js',
function () {
'use strict';
var $ = window.jQuery;
var specialMentionSelector = '.proflink[oid=113378906374136605398]';
var extractLangCode = function (node) {
if (!(node instanceof Text)) return null;
var langMatch = node.data.match(/^\s*(\w+(-\w+)?)\s*$/);
if (langMatch == null) return null;
return langMatch[1];
};
var createLangContainer = function (content, lang) {
var langContainer = $('<span/>').attr('lang', lang).attr('class', 'ext-i18n-container').css({
'border-style': 'solid',
'border-color': '#ccccff',
'display': 'block',
}).hide();
content.append(langContainer);
return langContainer;
};
var createLangOption = function (select, lang) {
var option = $('<option/>').attr('value', lang);
option.text(lang);
select.append(option);
return option;
};
var langPref = (function () {
var langPref = null;
var settingString = localStorage.getItem('ext-i18n-lang');
if (settingString != null) {
try {
langPref = JSON.parse(settingString);
if (!(langPref instanceof Array)) langPref = null;
} catch (_) {
langPref = null;
}
}
langPref = langPref || [];
var currentLang = $.gplus.lang();
if (currentLang != '') {
if (langPref.indexOf(currentLang) < 0) langPref.push(currentLang);
//Fallback to a general language code.
var hyphenPos = currentLang.indexOf('-');
if (hyphenPos > 0) {
var genLang = currentLang.substring(0, hyphenPos);
if (langPref.indexOf(genLang) < 0) langPref.push(genLang);
}
}
return langPref;
})();
var setLangPref = function () {
var settingString = JSON.stringify(langPref);
var result = prompt('Language:', settingString);
if (result) {
var tempLangPref = null;
try {
var tempLangPref = JSON.parse(result);
if (!(tempLangPref instanceof Array)) tempLangPref = null;
} catch (_) {
}
if (tempLangPref != null) {
langPref = tempLangPref;
localStorage.setItem('ext-i18n-lang', result);
}
}
};
var getTranslateLink = function () {
var transLink = $('<span/>').attr('class', 'ext-i18n-trans-link');
transLink[0].addEventListener('DOMNodeInserted', function (e) {
e = e || window.event;
if (!e.target.querySelector) return;
if (e.target.classList.contains('goog-te-gadget-link') ||
e.target.querySelector('.goog-te-gadget-link') != null) {
transLink.attr('class', 'ext-i18n-trans-link-inserted');
}
}, false);
return transLink;
};
var processSpecialMention = function (mention, noExpand) {
var nextNode = mention.parent()[0].nextSibling;
var lang = extractLangCode(nextNode);
if (lang == null) return; //It's just a plain mention of the i18n page.
var content = mention.closest('content');
if (content.length == 0) return; //Not in a content.
var domContent = content[0];
var post = content.closest('post');
if (post.length > 0 && !noExpand) {
//Collapsed post may contain corrupted language versions. Let's expand it!
var expandButton = post.find('postExpandButton');
if (expandButton.length > 0) {
if (!expandButton.attr('data-ext-i18n-clicked')) {
expandButton.attr('data-ext-i18n-clicked', 'true');
var handler = post.dynamicSelect('expandedContainer', function (container) {
post.stopDynamicSelect(handler);
container.find(specialMentionSelector).eachElement(function (e) {
processSpecialMention(e, 'no expand');
});
});
expandButton.doClick();
}
return; //Don't process the collapsed post.
}
}
//Prevent users from toggling the post by removing the buttons.
post.find('postToggleButton').remove();
if (post.length > 0) post.attr('data-ext-i18n-expanded', 'true');
mention.closest('proflinkWrapper').remove();
var remaining = document.evaluate('following-sibling::node()', nextNode, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
domContent.removeChild(nextNode);
var i18nDivs = {};
var currentLang = null; //We'll fix it later.
var select = $('<select/>').attr('class', 'ext-i18n-select');
select.change(function(_) {
i18nDivs[currentLang].hide();
currentLang = select.val();
//Record the currently selected language.
post.attr('ext-i18n-selected-lang', currentLang);
i18nDivs[currentLang].show();
});
select[0].addEventListener('contextmenu', function (e) {
e = e || window.event;
e.preventDefault();
setLangPref();
});
content.append(select);
var langContainer = createLangContainer(content, lang);
i18nDivs[lang] = langContainer;
createLangOption(select, lang);
mention = null;
var ignoreFirstBr = true;
for (var i = 0; i < remaining.snapshotLength; i++) {
var node = remaining.snapshotItem(i);
if (mention != null) {
lang = extractLangCode(node);
if (lang != null) { //Another language!
mention.closest('proflinkWrapper').remove();
domContent.removeChild(node);
langContainer = createLangContainer(content, lang);
i18nDivs[lang] = langContainer;
createLangOption(select, lang);
ignoreFirstBr = true;
} else {
mention.closest('proflinkWrapper').detach().appendTo(langContainer);
domContent.removeChild(node);
langContainer.append(node);
}
mention = null;
} else {
var nodeIsElement = node instanceof Element;
if (nodeIsElement && $(specialMentionSelector, node).length > 0) {
mention = $.gplus.wrap(node);
} else {
domContent.removeChild(node);
if (ignoreFirstBr && nodeIsElement && node.tagName == 'BR') {
//Ouch, that's a line break following the special i18n line.
ignoreFirstBr = false;
} else {
langContainer.append(node);
}
}
}
}
var postLang = post && post.attr('ext-i18n-selected-lang');
if (postLang) currentLang = postLang;
if (!currentLang || !i18nDivs[currentLang]) {
for(var i in langPref) {
currentLang = langPref[i];
if (i18nDivs[currentLang]) break;
var langPrefix = currentLang + '-';
for (var l in i18nDivs) {
if (l.indexOf(langPrefix) == 0) {
//A specific version of the language.
currentLang = l;
break;
}
}
if (i18nDivs[currentLang]) break;
}
if (!i18nDivs[currentLang]) {
for (var l in i18nDivs) {
//Pick the first one.
currentLang = l;
break;
}
// Offer to translate
for (var l in i18nDivs) {
langContainer.prepend(getTranslateLink());
}
}
}
select.val(currentLang);
select.change(); //Trigger the event to show the selected language.
var transScript = $('<script/>').attr('src','//translate.google.com/translate_a/element.js?cb=googleSectionalElementInit&ug=section&hl=auto')
transScript.appendTo(document.head);
};
$.gplus.page().dynamicSelect(specialMentionSelector, processSpecialMention);
//Google Translate Element
window.googleSectionalElementInit = function googleSectionalElementInit() {
new window.google.translate.SectionalElement({
sectionalNodeClassName: 'ext-i18n-container',
controlNodeClassName: 'ext-i18n-trans-link',
background: '#ffff99'
}, 'google_sectional_element');
};
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment