localization.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. // localization = {} -- the dict with translations is created by the backend
  2. var ignore_ids_for_localization = {
  3. setting_sd_hypernetwork: 'OPTION',
  4. setting_sd_model_checkpoint: 'OPTION',
  5. modelmerger_primary_model_name: 'OPTION',
  6. modelmerger_secondary_model_name: 'OPTION',
  7. modelmerger_tertiary_model_name: 'OPTION',
  8. train_embedding: 'OPTION',
  9. train_hypernetwork: 'OPTION',
  10. txt2img_styles: 'OPTION',
  11. img2img_styles: 'OPTION',
  12. setting_random_artist_categories: 'OPTION',
  13. setting_face_restoration_model: 'OPTION',
  14. setting_realesrgan_enabled_models: 'OPTION',
  15. extras_upscaler_1: 'OPTION',
  16. extras_upscaler_2: 'OPTION',
  17. };
  18. var re_num = /^[.\d]+$/;
  19. var re_emoji = /[\p{Extended_Pictographic}\u{1F3FB}-\u{1F3FF}\u{1F9B0}-\u{1F9B3}]/u;
  20. var original_lines = {};
  21. var translated_lines = {};
  22. function hasLocalization() {
  23. return window.localization && Object.keys(window.localization).length > 0;
  24. }
  25. function textNodesUnder(el) {
  26. var n, a = [], walk = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null, false);
  27. while ((n = walk.nextNode())) a.push(n);
  28. return a;
  29. }
  30. function canBeTranslated(node, text) {
  31. if (!text) return false;
  32. if (!node.parentElement) return false;
  33. var parentType = node.parentElement.nodeName;
  34. if (parentType == 'SCRIPT' || parentType == 'STYLE' || parentType == 'TEXTAREA') return false;
  35. if (parentType == 'OPTION' || parentType == 'SPAN') {
  36. var pnode = node;
  37. for (var level = 0; level < 4; level++) {
  38. pnode = pnode.parentElement;
  39. if (!pnode) break;
  40. if (ignore_ids_for_localization[pnode.id] == parentType) return false;
  41. }
  42. }
  43. if (re_num.test(text)) return false;
  44. if (re_emoji.test(text)) return false;
  45. return true;
  46. }
  47. function getTranslation(text) {
  48. if (!text) return undefined;
  49. if (translated_lines[text] === undefined) {
  50. original_lines[text] = 1;
  51. }
  52. var tl = localization[text];
  53. if (tl !== undefined) {
  54. translated_lines[tl] = 1;
  55. }
  56. return tl;
  57. }
  58. function processTextNode(node) {
  59. var text = node.textContent.trim();
  60. if (!canBeTranslated(node, text)) return;
  61. var tl = getTranslation(text);
  62. if (tl !== undefined) {
  63. node.textContent = tl;
  64. }
  65. }
  66. function processNode(node) {
  67. if (node.nodeType == 3) {
  68. processTextNode(node);
  69. return;
  70. }
  71. if (node.title) {
  72. let tl = getTranslation(node.title);
  73. if (tl !== undefined) {
  74. node.title = tl;
  75. }
  76. }
  77. if (node.placeholder) {
  78. let tl = getTranslation(node.placeholder);
  79. if (tl !== undefined) {
  80. node.placeholder = tl;
  81. }
  82. }
  83. textNodesUnder(node).forEach(function(node) {
  84. processTextNode(node);
  85. });
  86. }
  87. function dumpTranslations() {
  88. if (!hasLocalization()) {
  89. // If we don't have any localization,
  90. // we will not have traversed the app to find
  91. // original_lines, so do that now.
  92. processNode(gradioApp());
  93. }
  94. var dumped = {};
  95. if (localization.rtl) {
  96. dumped.rtl = true;
  97. }
  98. for (const text in original_lines) {
  99. if (dumped[text] !== undefined) continue;
  100. dumped[text] = localization[text] || text;
  101. }
  102. return dumped;
  103. }
  104. function download_localization() {
  105. var text = JSON.stringify(dumpTranslations(), null, 4);
  106. var element = document.createElement('a');
  107. element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
  108. element.setAttribute('download', "localization.json");
  109. element.style.display = 'none';
  110. document.body.appendChild(element);
  111. element.click();
  112. document.body.removeChild(element);
  113. }
  114. document.addEventListener("DOMContentLoaded", function() {
  115. if (!hasLocalization()) {
  116. return;
  117. }
  118. onUiUpdate(function(m) {
  119. m.forEach(function(mutation) {
  120. mutation.addedNodes.forEach(function(node) {
  121. processNode(node);
  122. });
  123. });
  124. });
  125. processNode(gradioApp());
  126. if (localization.rtl) { // if the language is from right to left,
  127. (new MutationObserver((mutations, observer) => { // wait for the style to load
  128. mutations.forEach(mutation => {
  129. mutation.addedNodes.forEach(node => {
  130. if (node.tagName === 'STYLE') {
  131. observer.disconnect();
  132. for (const x of node.sheet.rules) { // find all rtl media rules
  133. if (Array.from(x.media || []).includes('rtl')) {
  134. x.media.appendMedium('all'); // enable them
  135. }
  136. }
  137. }
  138. });
  139. });
  140. })).observe(gradioApp(), {childList: true});
  141. }
  142. });