localization.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * noVNC: HTML5 VNC client
  3. * Copyright (C) 2012 Joel Martin
  4. * Licensed under MPL 2.0 (see LICENSE.txt)
  5. *
  6. * See README.md for usage and integration instructions.
  7. */
  8. /*
  9. * Localization Utilities
  10. */
  11. export function Localizer() {
  12. // Currently configured language
  13. this.language = 'en';
  14. // Current dictionary of translations
  15. this.dictionary = undefined;
  16. }
  17. Localizer.prototype = {
  18. // Configure suitable language based on user preferences
  19. setup: function (supportedLanguages) {
  20. var userLanguages;
  21. this.language = 'en'; // Default: US English
  22. /*
  23. * Navigator.languages only available in Chrome (32+) and FireFox (32+)
  24. * Fall back to navigator.language for other browsers
  25. */
  26. if (typeof window.navigator.languages == 'object') {
  27. userLanguages = window.navigator.languages;
  28. } else {
  29. userLanguages = [navigator.language || navigator.userLanguage];
  30. }
  31. for (var i = 0;i < userLanguages.length;i++) {
  32. var userLang = userLanguages[i];
  33. userLang = userLang.toLowerCase();
  34. userLang = userLang.replace("_", "-");
  35. userLang = userLang.split("-");
  36. // Built-in default?
  37. if ((userLang[0] === 'en') &&
  38. ((userLang[1] === undefined) || (userLang[1] === 'us'))) {
  39. return;
  40. }
  41. // First pass: perfect match
  42. for (var j = 0;j < supportedLanguages.length;j++) {
  43. var supLang = supportedLanguages[j];
  44. supLang = supLang.toLowerCase();
  45. supLang = supLang.replace("_", "-");
  46. supLang = supLang.split("-");
  47. if (userLang[0] !== supLang[0])
  48. continue;
  49. if (userLang[1] !== supLang[1])
  50. continue;
  51. this.language = supportedLanguages[j];
  52. return;
  53. }
  54. // Second pass: fallback
  55. for (var j = 0;j < supportedLanguages.length;j++) {
  56. supLang = supportedLanguages[j];
  57. supLang = supLang.toLowerCase();
  58. supLang = supLang.replace("_", "-");
  59. supLang = supLang.split("-");
  60. if (userLang[0] !== supLang[0])
  61. continue;
  62. if (supLang[1] !== undefined)
  63. continue;
  64. this.language = supportedLanguages[j];
  65. return;
  66. }
  67. }
  68. },
  69. // Retrieve localised text
  70. get: function (id) {
  71. if (typeof this.dictionary !== 'undefined' && this.dictionary[id]) {
  72. return this.dictionary[id];
  73. } else {
  74. return id;
  75. }
  76. },
  77. // Traverses the DOM and translates relevant fields
  78. // See https://html.spec.whatwg.org/multipage/dom.html#attr-translate
  79. translateDOM: function () {
  80. var self = this;
  81. function process(elem, enabled) {
  82. function isAnyOf(searchElement, items) {
  83. return items.indexOf(searchElement) !== -1;
  84. }
  85. function translateAttribute(elem, attr) {
  86. var str = elem.getAttribute(attr);
  87. str = self.get(str);
  88. elem.setAttribute(attr, str);
  89. }
  90. function translateTextNode(node) {
  91. var str = node.data.trim();
  92. str = self.get(str);
  93. node.data = str;
  94. }
  95. if (elem.hasAttribute("translate")) {
  96. if (isAnyOf(elem.getAttribute("translate"), ["", "yes"])) {
  97. enabled = true;
  98. } else if (isAnyOf(elem.getAttribute("translate"), ["no"])) {
  99. enabled = false;
  100. }
  101. }
  102. if (enabled) {
  103. if (elem.hasAttribute("abbr") &&
  104. elem.tagName === "TH") {
  105. translateAttribute(elem, "abbr");
  106. }
  107. if (elem.hasAttribute("alt") &&
  108. isAnyOf(elem.tagName, ["AREA", "IMG", "INPUT"])) {
  109. translateAttribute(elem, "alt");
  110. }
  111. if (elem.hasAttribute("download") &&
  112. isAnyOf(elem.tagName, ["A", "AREA"])) {
  113. translateAttribute(elem, "download");
  114. }
  115. if (elem.hasAttribute("label") &&
  116. isAnyOf(elem.tagName, ["MENUITEM", "MENU", "OPTGROUP",
  117. "OPTION", "TRACK"])) {
  118. translateAttribute(elem, "label");
  119. }
  120. // FIXME: Should update "lang"
  121. if (elem.hasAttribute("placeholder") &&
  122. isAnyOf(elem.tagName, ["INPUT", "TEXTAREA"])) {
  123. translateAttribute(elem, "placeholder");
  124. }
  125. if (elem.hasAttribute("title")) {
  126. translateAttribute(elem, "title");
  127. }
  128. if (elem.hasAttribute("value") &&
  129. elem.tagName === "INPUT" &&
  130. isAnyOf(elem.getAttribute("type"), ["reset", "button"])) {
  131. translateAttribute(elem, "value");
  132. }
  133. }
  134. for (var i = 0;i < elem.childNodes.length;i++) {
  135. var node = elem.childNodes[i];
  136. if (node.nodeType === node.ELEMENT_NODE) {
  137. process(node, enabled);
  138. } else if (node.nodeType === node.TEXT_NODE && enabled) {
  139. translateTextNode(node);
  140. }
  141. }
  142. }
  143. process(document.body, true);
  144. },
  145. }
  146. export var l10n = new Localizer();
  147. export default l10n.get.bind(l10n);