diff --git a/public/_includes/_main-nav.jade b/public/_includes/_main-nav.jade
index 272a54d702..2cd3bdbeab 100644
--- a/public/_includes/_main-nav.jade
+++ b/public/_includes/_main-nav.jade
@@ -13,3 +13,6 @@ md-toolbar(class="main-nav background-regal l-pinned-top l-layer-5",scroll-y-off
li.l-left Events
li.l-left News
li.l-right Get Started
+ li.l-right
+ a.main-nav-button.md-button.ng-cloak(ng-click="appCtrl.toggleSource($event)", href)
+ span {{appCtrl.sourceVisible?'Hide English':'Show English'}}
diff --git a/public/_includes/_scripts-include.jade b/public/_includes/_scripts-include.jade
index 9b4cd8048b..c08fd3f395 100644
--- a/public/_includes/_scripts-include.jade
+++ b/public/_includes/_scripts-include.jade
@@ -20,6 +20,7 @@ script(src="https://ajax.googleapis.com/ajax/libs/angular_material/1.0.0/angular
+script(src="/localization/translate.js")
script(src="/resources/js/site.js")
script(src="/resources/js/util.js")
script(src="/resources/js/controllers/app-controller.js")
diff --git a/public/docs/ts/latest/glossary.jade b/public/docs/ts/latest/glossary.jade
index bc34cf94e1..0d4b58e60a 100644
--- a/public/docs/ts/latest/glossary.jade
+++ b/public/docs/ts/latest/glossary.jade
@@ -4,14 +4,21 @@ include _util-fns
:marked
# Angular 2 Glossary
+ # Angular 2 用語集
+
Angular 2 has a vocabulary of its own.
Most Angular 2 terms are everyday English words
with a specific meaning within the Angular system.
+
+ Angular2には独自の用語が存在します。
+ ほとんどのAngular2の用語は日常英語の単語ですが、Angularシステムの中において特別な意味を有しています。
We have gathered here the most prominent terms
and a few less familiar ones that have unusual or
unexpected definitions.
+ ここには主要な用語といくつかのあまり馴染みのない用語を集めています。
+
[A](#A) [B](#B) [C](#C) [D](#D) [E](#E) [F](#F) [G](#G) [H](#H) [I](#I)
[J](#J) [K](#K) [L](#L) [M](#M) [N](#N) [O](#O) [P](#P) [Q](#Q) [R](#R)
[S](#S) [T](#T) [U](#U) [V](#V) [W](#W) [X](#X) [Y](#Y) [Z](#Z)
diff --git a/public/localization/translate.js b/public/localization/translate.js
new file mode 100644
index 0000000000..332a70581d
--- /dev/null
+++ b/public/localization/translate.js
@@ -0,0 +1,124 @@
+var sourceVisible = localStorage.getItem('source-visible') === 'true';
+
+(function ($) {
+ function addOriginalToggler() {
+ var nodes = document.querySelectorAll('p, li, h1, h2, h3, h4, h5, h6, header, a, button, small');
+ _.each(nodes, function (node) {
+ var $node = $(node);
+
+ if (isLink(node) || isButton(node)) {
+ $node.on('click', function (event) {
+ event.stopPropagation();
+ });
+
+ if (/^http?s:\/\//.test($node.attr('href')) && !$node.attr('target')) {
+ $node.attr('target', '_blank');
+ }
+ }
+
+ var prevNode = node.previousElementSibling;
+ var $prevNode = $(prevNode);
+
+ if (!prevNode) {
+ return;
+ }
+
+ if (isTranslationResult(node, prevNode)) {
+ if ($prevNode.hasClass('nav-list-item') ||
+ $prevNode.hasClass('l-right') ||
+ $prevNode.hasClass('l-left')) {
+ return;
+ }
+ if ($node.text() === $prevNode.text()) {
+ return;
+ }
+
+ $node.attr('id', prevNode.id);
+ $node.addClass('translated');
+ $prevNode.removeAttr('id');
+ $prevNode.addClass('original-english');
+ if (!sourceVisible) {
+ $prevNode.addClass('hidden');
+ }
+ if (!isLink(node) && !isButton(node)) {
+ var isDragging = false;
+ $node.on('mousedown', function () {
+ $(window).on('mousemove', function () {
+ isDragging = true;
+ $(window).unbind('mousemove');
+ });
+ });
+ $prevNode.on('mousedown', function () {
+ $(window).on('mousemove', function () {
+ isDragging = true;
+ $(window).unbind('mousemove');
+ });
+ });
+ $node.on('mouseup', function () {
+ var wasDragging = isDragging;
+ isDragging = false;
+ $(window).unbind('mousemove');
+ if (!wasDragging) {
+ $prevNode.toggleClass('hidden');
+ }
+ });
+ $prevNode.on('mouseup', function () {
+ var wasDragging = isDragging;
+ isDragging = false;
+ $(window).unbind('mousemove');
+ if (!wasDragging) {
+ $prevNode.addClass('hidden');
+ }
+ });
+ }
+ $node.after($prevNode);
+ }
+ })
+ }
+
+ function attributesToString(node) {
+ return _.chain(node.attributes)
+ .map(function (value) {
+ if (value.name === 'id') {
+ return '';
+ } else {
+ return value.name + '=' + value.value;
+ }
+ })
+ .sortBy()
+ .value()
+ .join(';');
+ }
+
+ function isLink(node) {
+ return node.tagName.toUpperCase() === 'A';
+ }
+
+ function isButton(node) {
+ return node.tagName.toUpperCase() === 'BUTTON';
+ }
+
+ function isClonedNode(node1, node2) {
+ return node1.tagName === node2.tagName &&
+ attributesToString(node1) === attributesToString(node2);
+ }
+
+ function indexOfSameType(node) {
+ var i = 0;
+ var aNode = node.parentNode.firstChild;
+ while (aNode !== node) {
+ ++i;
+ if (aNode.tagName !== node.tagName) {
+ i = 0;
+ }
+ aNode = aNode.nextElementSibling;
+ }
+ return i;
+ }
+
+ function isTranslationResult(node, prevNode) {
+ return indexOfSameType(node) % 2 === 1 && isClonedNode(node, prevNode);
+ }
+
+ addOriginalToggler();
+})(angular.element);
diff --git a/public/resources/css/_translate.scss b/public/resources/css/_translate.scss
new file mode 100644
index 0000000000..8ab16e30e0
--- /dev/null
+++ b/public/resources/css/_translate.scss
@@ -0,0 +1,12 @@
+.original-english {
+ border-top: 1px dashed $regal;
+ &.hidden {
+ display: none !important;
+ }
+}
+
+td, th {
+ > p:last-child {
+ margin-bottom: 0;
+ }
+}
diff --git a/public/resources/css/main.scss b/public/resources/css/main.scss
index 0a0e019eab..a850dd2878 100644
--- a/public/resources/css/main.scss
+++ b/public/resources/css/main.scss
@@ -9,6 +9,7 @@
@import 'theme';
@import 'base/reset';
@import 'base/type';
+@import 'translate';
@import 'angular';
diff --git a/public/resources/js/controllers/app-controller.js b/public/resources/js/controllers/app-controller.js
index c8f4e15bdc..1f0492af7a 100644
--- a/public/resources/js/controllers/app-controller.js
+++ b/public/resources/js/controllers/app-controller.js
@@ -62,4 +62,20 @@ angularIO.controller('AppCtrl', ['$mdDialog', '$timeout', '$http', '$sce', funct
// TRIGGER PRETTYPRINT AFTER DIGEST LOOP COMPLETE
$timeout(prettyPrint, 1);
-} ]);
\ No newline at end of file
+
+ // TOGGLE TRANSLATIONS
+ vm.sourceVisible = localStorage.getItem('source-visible') === 'true';
+ vm.toggleSource = function ($event) {
+ $event.preventDefault();
+ vm.sourceVisible = !vm.sourceVisible;
+ var nodes = document.querySelectorAll('.original-english');
+ var $nodes = angular.element(nodes);
+ if (vm.sourceVisible) {
+ $nodes.removeClass('hidden');
+ } else {
+ $nodes.addClass('hidden');
+ }
+ localStorage.setItem('source-visible', vm.sourceVisible);
+ }
+
+}]);