Greasy Fork is available in English.

Japanize.mod.core

Japanize Core Library

Ce script ne doit pas être installé directement. C'est une librairie destinée à être incluse dans d'autres scripts avec la méta-directive // @require https://update.greasyfork.org/scripts/24109/153163/Japanizemodcore.js

  1. var MYLINGUAL = {
  2. VERSION: "0.7.1",
  3. UID: "kazuho-japanize2@labs.cybozu.co.jp",
  4. getPromptService: function () {
  5. return Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  6. .getService(Components.interfaces.nsIPromptService);
  7. },
  8. notifyUser: function (message) {
  9. this.getPromptService().alert(
  10. window, this._s('prompt.title'), message);
  11. },
  12. getLang: function () {
  13. return this.getPreference('lang', this._s('defaults.lang'));
  14. },
  15. setLang: function (l) {
  16. this.setPreference('lang', l);
  17. },
  18. getStoreBaseDir: function () {
  19. try {
  20. var profileDir =
  21. Components.classes["@mozilla.org/file/directory_service;1"]
  22. .getService(Components.interfaces.nsIProperties)
  23. .get("ProfD", Components.interfaces.nsILocalFile);
  24. // return the extension directory
  25. var dir = profileDir.clone();
  26. dir.append("extensions");
  27. if (dir.exists() && dir.isDirectory()) {
  28. dir.append(this.UID);
  29. if (dir.exists() && dir.isDirectory()) {
  30. dir.append("data");
  31. return dir;
  32. }
  33. }
  34. // if failed, create our own directory below profile dir
  35. dir = profileDir.clone();
  36. dir.append("mylingual"); // only used by developers
  37. if (! dir.exists()) {
  38. dir.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0755);
  39. }
  40. return dir;
  41. } catch (e) {
  42. alert("Japanize: " + e.toString());
  43. }
  44. },
  45. getStoreDir: function () {
  46. try {
  47. var dir = this.getStoreBaseDir();
  48. dir.append(this.getLang());
  49. if (! dir.exists()) {
  50. dir.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0755);
  51. }
  52. return dir;
  53. } catch (e) {
  54. alert("Mylingual: " + e.toString());
  55. }
  56. },
  57. saveToStore: function (file, text) {
  58. text = "\ufeff" + text.toString();
  59. var conv =
  60. Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
  61. .getService(Components.interfaces.nsIScriptableUnicodeConverter);
  62. conv.charset = "UTF-8";
  63. var temppath = this.getStoreDir();
  64. temppath.append("t" + Math.floor(Math.random() * 10000000) + ".tmp");
  65. var os = Components.classes["@mozilla.org/network/file-output-stream;1"]
  66. .createInstance(Components.interfaces.nsIFileOutputStream);
  67. os.init(temppath, 0x2a, 0644, -1);
  68. for (var offset = 0; offset < text.length; offset += 1024) {
  69. var data =
  70. String.fromCharCode.apply(
  71. null,
  72. conv.convertToByteArray(
  73. text.substring(offset, offset + 1024),
  74. new Number(0)));
  75. os.write(data, data.length);
  76. }
  77. os.close();
  78. try {
  79. temppath.moveTo(this.getStoreDir(), file);
  80. } catch (e) {
  81. try {
  82. temppath.remove(false);
  83. } catch (e2) {
  84. }
  85. throw e;
  86. }
  87. },
  88. getStoreURI: function (file) {
  89. var path = this.getStoreDir();
  90. path.append(file);
  91. return Components.classes["@mozilla.org/network/io-service;1"]
  92. .getService(Components.interfaces.nsIIOService)
  93. .newFileURI(path);
  94. },
  95. getPreferenceService: function () {
  96. return Components.classes["@mozilla.org/preferences-service;1"]
  97. .getService(Components.interfaces.nsIPrefService)
  98. .getBranch("");
  99. },
  100.  
  101. getPreference: function (name, defaultValue) {
  102. var value = null;
  103. try {
  104. value =
  105. this.getPreferenceService().getCharPref(
  106. "extensions.japanize." + name);
  107. } catch (e) {
  108. }
  109. if (value == null) {
  110. value = defaultValue;
  111. }
  112. return value;
  113. },
  114. setPreference: function (name, value) {
  115. this.getPreferenceService().setCharPref(
  116. "extensions.japanize." + name, value.toString());
  117. },
  118. debugAlert: function () {
  119. if (! this.getPreference('debug', '')) {
  120. return;
  121. }
  122. alert.apply(null, arguments);
  123. },
  124. PREF_UPDATEMODE: "updatemode",
  125. UPDATEMODE_PERIODICALLY: "periodically",
  126. UPDATEMODE_EVERYTIME: "everytime",
  127. getUpdateMode: function () {
  128. return this.getPreference(
  129. this.PREF_UPDATEMODE, this.UPDATEMODE_PERIODICALLY);
  130. },
  131. setUpdateMode: function (newMode) {
  132. this.setPreference(this.PREF_UPDATEMODE, newMode);
  133. },
  134. getBaseURL: function () {
  135. return this.getPreference("baseURL", "http://japanize.mylingual.net/");
  136. },
  137. normalizeHost: function (host) {
  138. return host.toString().toLowerCase().replace(/^www\./, "");
  139. },
  140. buildTranslationURL: function (host) {
  141. var url =
  142. this.getBaseURL() + "data/" + this.normalizeHost(host)
  143. + "/current.txt";
  144. return url;
  145. },
  146. loadLocalizationData: function (doc) {
  147. doc.__MYLINGUAL_DONE = true;
  148. var browser = this.findBrowser(doc);
  149. if (! this.getMode()) {
  150. this.updateStatus(browser, "");
  151. return;
  152. }
  153. if (doc.location.protocol != "http:") {
  154. this.updateStatus(browser, "");
  155. return;
  156. }
  157. if (this.getUpdateMode() == this.UPDATEMODE_PERIODICALLY
  158. && typeof this.localTranslationTable != "undefined") {
  159. if (this.localTranslationTable["$builddate"]
  160. == this.getPreference("$builddate", -1)) {
  161. setTimeout(
  162. function () {
  163. MYLINGUAL.localizeWithLocalData(doc, browser);
  164. },
  165. 1);
  166. return;
  167. }
  168. this.localTranslationTable = undefined;
  169. }
  170. if (this.getUpdateMode() == this.UPDATEMODE_EVERYTIME) {
  171. try {
  172. var xhr = new XMLHttpRequest();
  173. xhr.open(
  174. "get",
  175. this.buildTranslationURL(doc.location.host),
  176. true);
  177. xhr.onreadystatechange = function () {
  178. if (xhr.readyState == 4) {
  179. MYLINGUAL.localizeWithData(
  180. MYLINGUAL.parseJSON(xhr.responseText),
  181. doc,
  182. browser);
  183. }
  184. };
  185. xhr.send(null);
  186. } catch (e) {
  187. alert("Japanize: " + e.toString());
  188. }
  189. } else {
  190. try {
  191. var xhr = new XMLHttpRequest();
  192. xhr.open(
  193. "get",
  194. this.getStoreURI("all.txt").spec,
  195. true);
  196. xhr.onreadystatechange = function () {
  197. if (xhr.readyState == 4) {
  198. var json = MYLINGUAL.parseJSON(xhr.responseText);
  199. MYLINGUAL.localTranslationTable = json;
  200. MYLINGUAL.localizeWithLocalData(doc, browser);
  201. }
  202. };
  203. xhr.send(null);
  204. } catch (e) {
  205. alert("Japanize: " + e.toString());
  206. }
  207. }
  208. },
  209. localizeWithLocalData: function (doc, browser) {
  210. var table;
  211. if (typeof this.localTranslationTable == 'object') {
  212. table = this.localTranslationTable[
  213. MYLINGUAL.normalizeHost(doc.location.host)];
  214. if (typeof table == 'undefined'
  215. && doc.location.host.match(/^[^\.]*\./)) {
  216. table = this.localTranslationTable['*.' + RegExp.rightContext];
  217. }
  218. }
  219. this.localizeWithData(table, doc, browser);
  220. },
  221. canTranslateHost: function (host) {
  222. var list = this.getPreference("hosts", "").split(",");
  223. if (list.length == 0) {
  224. return true;
  225. }
  226. for (var i = 0; i < list.length; i++) {
  227. var flag = list[i].charAt(0);
  228. var pat = MYLINGUAL._gsub(
  229. list[i].substring(1),
  230. /[^A-Za-z0-9\-]/g,
  231. function (m) {
  232. return m == '*' ? '.*' : '\\' + m;
  233. });
  234. pat = new RegExp(pat);
  235. if (typeof pat != 'undefined' && host.match(new RegExp(pat))) {
  236. if (flag == '-') {
  237. return false;
  238. } else if (flag == '+') {
  239. return true;
  240. }
  241. }
  242. }
  243. return true;
  244. },
  245. localizeWithData: function (json, doc, browser) {
  246. this.updateStatus(browser, "");
  247. // do nothing unless translation is available
  248. if (typeof json != "object") {
  249. return;
  250. }
  251. // check preferences
  252. if (! this.canTranslateHost(doc.location.host)) {
  253. this.updateStatus(browser, this._s('status.original'));
  254. return;
  255. }
  256. // convert json to internal representation
  257. var mappings = {
  258. text: {},
  259. re: []
  260. };
  261. this.initCommandMappings(mappings);
  262. for (var n in json) {
  263. if (n.charAt(0) == '$') {
  264. this.compileCommand(mappings, n, json[n]);
  265. } else if (n.match(/^\/(\^.*\$)\/$/)) {
  266. var v = json[n];
  267. try {
  268. n = new RegExp(RegExp.$1);
  269. } catch (e) {
  270. this.debugAlert(
  271. this._f('mylingual.error.recompile', [ n ]));
  272. continue;
  273. }
  274. mappings.re.push([ n, v ]);
  275. } else {
  276. mappings.text[n] = json[n];
  277. }
  278. }
  279. this.postProcessCommandMappings(mappings);
  280. // check url patterns
  281. if (this.ifSkipURL(mappings, doc.location)) {
  282. this.updateStatus(browser, this._s('status.bannedpage'));
  283. return;
  284. }
  285. // setup logger
  286. var log = ! ! this.getPreference("log", "");
  287. if (log && typeof FireBug == 'undefined' && ! this.noFireBugAlert) {
  288. alert("Japanize: Install FireBug to view translation logs.");
  289. this.noFireBugAlert = true;
  290. log = false;
  291. }
  292. if (log) {
  293. log = function (s) {
  294. FireBug.console.log(s);
  295. };
  296. log.log = true;
  297. } else {
  298. log = function () {
  299. };
  300. log.log = false;
  301. }
  302. // convert
  303. log("Japanize: translating: " + doc.location);
  304. this.localizeElement(doc.body, mappings, true);
  305. this.updateStatus(browser, this._s('status.translated'));
  306. // build handler for handilng DHTML modifs.
  307. var handler = function (evt) {
  308. if (handler.underOperation) {
  309. return;
  310. }
  311. if (log.log) {
  312. var msg = (function (t) {
  313. if (t.id) {
  314. return "id='" + t.id + "'";
  315. } else if (t.className) {
  316. return "class='" + t.className + "'";
  317. } else if (t.parentNode) {
  318. return arguments.callee(t.parentNode);
  319. } else if (t.nodeType == 9) {
  320. return "no identifier at root";
  321. } else {
  322. return "not within document";
  323. }
  324. }).call(null, evt.target);
  325. msg += (function (t) {
  326. while (typeof t == 'object' && t.nodeType != 9) {
  327. t = t.parentNode;
  328. }
  329. if (! t) {
  330. return '';
  331. }
  332. return ", " + t.location;
  333. }).call(null, evt.target);
  334. log("Japanize: " + msg);
  335. }
  336. setTimeout(
  337. function () {
  338. handler.underOperation = true;
  339. MYLINGUAL.localizeElement(
  340. evt.target,
  341. mappings,
  342. MYLINGUAL.getElementTranslationMode(
  343. mappings, doc.body, evt.target.parentNode));
  344. handler.underOperation = false;
  345. },
  346. 1);
  347. };
  348. if (doc.addEventListener
  349. && ! (navigator.userAgent.toString().match(/\sAppleWebKit\/([0-9]+)/i) && RegExp.$1 < 522)) {
  350. doc.addEventListener("DOMNodeInserted", handler, false);
  351. doc.addEventListener("DOMCharacterDataModified", handler, false);
  352. doc.addEventListener(
  353. "DOMAttrModified",
  354. function (evt) {
  355. if (evt.attrName == 'style') {
  356. var iframes = evt.target.getElementsByTagName('iframe');
  357. for (var i = 0; i < iframes.length; i++) {
  358. var doc = iframes[i].contentDocument;
  359. if (! doc.__MYLINGUAL_DONE) {
  360. MYLINGUAL.loadLocalizationData(doc);
  361. }
  362. }
  363. } else if (evt.target.tagName == 'INPUT'
  364. || evt.target.tagName == 'OPTION') {
  365. handler(evt);
  366. }
  367. },
  368. false);
  369. }
  370. },
  371. translateText: function (orig, mappings) {
  372. // direct match
  373. if (typeof mappings.text[orig] != 'undefined') {
  374. return mappings.text[orig];
  375. }
  376. // match (while taking care of surrounding spaces)
  377. if (orig.match(/^([ \r\n\t\xa0]*)(.+?)([ \r\n\t\xa0]*)$/)
  378. && (RegExp.$1 != '' || RegExp.$3 != '')) {
  379. if (typeof mappings.text[RegExp.$2] != 'undefined') {
  380. return RegExp.$1 + mappings.text[RegExp.$2] + RegExp.$3;
  381. }
  382. }
  383. // regexp
  384. for (var i = 0; i < mappings.re.length; i++) {
  385. var m = null;
  386. if (m = orig.match(mappings.re[i][0])) {
  387. return this._gsub(
  388. mappings.re[i][1],
  389. /\$(R?)([1-9])/g,
  390. function (_dummy, rerun, digit) {
  391. var t = m[digit - 0];
  392. if (rerun) {
  393. var t2 =
  394. MYLINGUAL.translateText(t, mappings);
  395. if (t2 != null) {
  396. t = t2;
  397. }
  398. }
  399. return t;
  400. });
  401. }
  402. }
  403. return null;
  404. },
  405. // patch required for safari
  406. _gsub: function (str, re, func) {
  407. return str.replace(re, func);
  408. },
  409. initCommandMappings: function (mappings) {
  410. var f0 = function () {
  411. return {
  412. re: [],
  413. reCaseless: [],
  414. text: {}
  415. }
  416. };
  417. var f1 = function () {
  418. return {
  419. 'class': f0(),
  420. id: f0(),
  421. path: f0(),
  422. tag: f0(),
  423. url: f0()
  424. };
  425. };
  426. mappings.skip = f1();
  427. mappings.translate = f1();
  428. },
  429. postProcessCommandMappings: function (mappings) {
  430. var f0 = function (t, n, f) {
  431. t[n] = t[n].length != 0 ? new RegExp(t[n].join('|'), f) : undefined;
  432. };
  433. var f1 = function (t) {
  434. f0(t, 're', '');
  435. f0(t, 'reCaseless', 'i');
  436. };
  437. var f2 = function (t) {
  438. f1(t['class']);
  439. f1(t.id);
  440. f1(t.path);
  441. f1(t.tag);
  442. f1(t.url);
  443. };
  444. f2(mappings.skip);
  445. f2(mappings.translate);
  446. },
  447. compileCommand: function (mappings, name, value) {
  448. if (! name.match(/^\$(.*?)\(\s*(~{0,2})\s*(.*)\s*\)$/)) {
  449. return;
  450. }
  451. var type = RegExp.$1;
  452. var re = RegExp.$2 ? RegExp.$2.length : 0;
  453. var match = RegExp.$3;
  454. var store = mappings
  455. [value[0] == 'skip' || value[0] == '' ? 'skip' : 'translate']
  456. [type];
  457. if (typeof store != 'object') {
  458. return;
  459. }
  460. if (re) {
  461. if (! new RegExp(match, re == 2 ? 'i' : '')) {
  462. this.debugAlert('Syntax error: ' + name);
  463. return;
  464. }
  465. store[re == 2 ? 'reCaseless' : 're'].push(match);
  466. } else {
  467. if (type == 'tag') {
  468. match = match.toUpperCase();
  469. }
  470. store.text[match] = 1;
  471. }
  472. },
  473. ifSkipURL: function (mappings, loc) {
  474. return this.translateOrSkip(mappings.skip.path, loc.pathname)
  475. || this.translateOrSkip(mappings.skip.url, loc.toString());
  476. },
  477. translateOrSkipElement: function (mappings, e, current) {
  478. var table = mappings[current ? 'skip' : 'translate'];
  479. if (this.translateOrSkip(table.tag, e.tagName)
  480. || e.className && this.translateOrSkip(table['class'], e.className)
  481. || e.id && this.translateOrSkip(table.id, e.id)) {
  482. return ! current;
  483. }
  484. return current;
  485. },
  486. translateOrSkip: function (table, value) {
  487. value = value.toString();
  488. return typeof table.text[value] != 'undefined'
  489. || (table.re && value.match(table.re))
  490. || (table.reCaseless && value.match(table.reCaseless));
  491. },
  492. getElementTranslationMode: function (mappings, body, element) {
  493. var path = [];
  494. for (var p = (element.nodeType == 1 ? element : element.parentNode);
  495. p != body;
  496. p = p.parentNode) {
  497. path.push(p);
  498. }
  499. var translate = true;
  500. while (path.length != 0) {
  501. translate =
  502. this.translateOrSkipElement(mappings, path.pop(), translate);
  503. }
  504. return translate;
  505. },
  506. localizeElement: function (node, mappings, translate) {
  507. if (node.nodeType == 1) {
  508. translate = this.translateOrSkipElement(mappings, node, translate);
  509. if (node.nodeName == "SCRIPT" || node.nodeName == "STYLE") {
  510. // nothing to do
  511. return;
  512. } else if (node.nodeName == "INPUT") {
  513. if (! translate) {
  514. return;
  515. }
  516. if (node.type == "button" || node.type == "reset") {
  517. var translated = this.translateText(node.value, mappings);
  518. if (translated != null) {
  519. node.value = translated;
  520. }
  521. }
  522. return;
  523. } else if (node.nodeName == "OPTION") {
  524. if (! translate) {
  525. return;
  526. }
  527. var translated = this.translateText(node.text, mappings);
  528. if (translated != null) {
  529. node.value = node.value.toString();
  530. node.text = translated;
  531. }
  532. return;
  533. }
  534. var children = node.childNodes;
  535. for (var i = 0; i < children.length; i++) {
  536. this.localizeElement(children.item(i), mappings, translate);
  537. }
  538. } else if (translate && node.nodeType == 3) {
  539. var translated =
  540. this.translateText(node.nodeValue, mappings);
  541. if (translated != null) {
  542. node.nodeValue = translated;
  543. }
  544. }
  545. },
  546. parseJSON: function (text) {
  547. var json = undefined;
  548. try {
  549. var s = Components.utils.Sandbox(
  550. "http://sandbox.japanize.31tools.com/");
  551. Components.utils.evalInSandbox("json = " + text, s);
  552. json = s.json;
  553. } catch (e) {
  554. this.debugAlert(e);
  555. }
  556. return json;
  557. },
  558. findBrowser: function (doc) {
  559. var tb = getBrowser();
  560. for (var i = 0; i < tb.browsers.length; ++i) {
  561. var b = tb.getBrowserAtIndex(i);
  562. if (b.contentDocument == doc) {
  563. return b;
  564. }
  565. }
  566. return null;
  567. },
  568. updateStatus: function (browser, text) {
  569. if (browser == null) return;
  570. browser.contentDocument.JAPANIZED_status = text;
  571. this.redrawStatus();
  572. },
  573. redrawStatus: function () {
  574. var status =
  575. getBrowser().selectedBrowser.contentDocument.JAPANIZED_status;
  576. if (typeof status == "undefined") {
  577. status = "";
  578. }
  579. var label = document.getElementById("japanize-status-label");
  580. if (status == "") {
  581. label.style.display = "none";
  582. } else {
  583. label.value = status;
  584. label.style.display = "inline";
  585. }
  586. },
  587. getMode: function () {
  588. var img = document.getElementById("japanize-status-icon");
  589. return ! ! img.src.toString().match(/icon_on(_message)?\.gif$/);
  590. },
  591. setMode: function (on) {
  592. // setup icon
  593. var s = on ? "on" : "off";
  594. var img = document.getElementById("japanize-status-icon");
  595. img.src = img.src.toString().replace(/icon_o(n|ff)/, "icon_" + s);
  596. document.getElementById("japanize-status-main").value =
  597. this._s('tooltip.is' + s);
  598. },
  599. getMenuItem: function (suffix) {
  600. return document.getElementById("japanize-popup-" + suffix);
  601. },
  602. getBundle: function () {
  603. return document.getElementById("japanize-bundle");
  604. },
  605. _s: function (n) {
  606. try {
  607. return this.getBundle().getString('mylingual.' + n);
  608. } catch (e) {
  609. this.debugAlert(
  610. "Could not find string resource: " + n + "\n\n" + e.toString());
  611. }
  612. },
  613. _f: function (n, a) {
  614. return this.getBundle().getFormattedString('mylingual.' + n, a);
  615. },
  616. showPopup: function (evt) {
  617. this.getMenuItem("enabled").setAttribute(
  618. "checked", this.getMode().toString());
  619. if (this.getUpdateMode() == this.UPDATEMODE_EVERYTIME) {
  620. this.getMenuItem("updateeverytime").setAttribute(
  621. "checked", "true");
  622. this.getMenuItem("updateperiodically").setAttribute(
  623. "checked", "false");
  624. this.getMenuItem("updatenow").setAttribute(
  625. "disabled", "true");
  626. } else {
  627. this.getMenuItem("updateeverytime").setAttribute(
  628. "checked", "false");
  629. this.getMenuItem("updateperiodically").setAttribute(
  630. "checked", "true");
  631. this.getMenuItem("updatenow").setAttribute(
  632. "disabled", "false");
  633. }
  634. },
  635. handlePopup: function (evt) {
  636. if (! evt.target.id.toString().match(/^japanize-popup-/)) {
  637. return;
  638. }
  639. var cmd = RegExp.rightContext;
  640. if (cmd == "enabled") {
  641. this.setMode(! this.getMode());
  642. } else if (cmd == "updateeverytime") {
  643. this.setUpdateMode(this.UPDATEMODE_EVERYTIME);
  644. } else if (cmd == "updateperiodically") {
  645. this.setUpdateMode(this.UPDATEMODE_PERIODICALLY);
  646. if (this.needsUpdate()) {
  647. if (this.getPromptService().confirm(
  648. window,
  649. this._s('prompt.title'),
  650. this._s('prompt.recommendupdate'))) {
  651. this.downloadAllTable(true);
  652. }
  653. }
  654. } else if (cmd == "updatenow") {
  655. this.downloadAllTable(true);
  656. }
  657. },
  658. saveAllTable: function (content, buildDate, retryCount, notifyUser) {
  659. try {
  660. this.saveToStore("all.txt", content);
  661. this.setPreference("$builddate", buildDate);
  662. if (notifyUser) {
  663. this.notifyUser(this._s('prompt.defupdated'));
  664. }
  665. } catch (e) {
  666. if (retryCount == 0) {
  667. this.notifyUser(
  668. this._s('prompt.defsavefailed')
  669. + "\n\n" + e.toString());
  670. } else {
  671. setTimeout(
  672. function () {
  673. MYLINGUAL.saveAllTable(
  674. content, buildDate, retryCount - 1, notifyUser);
  675. },
  676. 100);
  677. }
  678. }
  679. },
  680. onAllTableDownload: function (xhr, notifyUser) {
  681. var json = this.parseJSON(xhr.responseText);
  682. if (typeof json != "object") {
  683. if (notifyUser) {
  684. this.notifyUser(this._s('prompt.defdownloadfailed'));
  685. }
  686. return;
  687. }
  688. if (json["$builddate"] == this.getPreference("$builddate", -1)) {
  689. if (notifyUser) {
  690. this.notifyUser(this._s('prompt.defnochanges'));
  691. }
  692. return;
  693. }
  694. this.saveAllTable(xhr.responseText, json["$builddate"], 10, notifyUser);
  695. },
  696. downloadAllTable: function (notifyUser) {
  697. try {
  698. var xhr = new XMLHttpRequest();
  699. xhr.open(
  700. "get",
  701. this.getBaseURL() + "alldata/all.txt",
  702. true);
  703. xhr.onreadystatechange = function () {
  704. if (xhr.readyState == 4) {
  705. MYLINGUAL.onAllTableDownload(xhr, notifyUser);
  706. }
  707. };
  708. xhr.send(null);
  709. } catch (e) {
  710. alert("Japanize : " + e.toString());
  711. }
  712. },
  713. needsUpdate: function () {
  714. // every 3 hours by default
  715. var interval = this.getPreference("updateinterval", 3 * 3600) * 1000;
  716. var lastUpdateAt = this.getPreference("lastupdateat", 0) * 1;
  717. if (new Date().getTime() < lastUpdateAt + interval) {
  718. return false;
  719. }
  720. return true;
  721. },
  722. periodicalTasks: function () {
  723. if (! this.needsUpdate()) {
  724. return;
  725. }
  726. this.setPreference("lastupdateat", new Date().getTime());
  727. // update alltable if in periodical mode
  728. if (this.getUpdateMode() == this.UPDATEMODE_PERIODICALLY) {
  729. this.downloadAllTable(false);
  730. }
  731. }
  732. };
  733.  
  734. // hacks for opera
  735. MYLINGUAL.updateStatus = function (_dummy1, text) {
  736. if (text) {
  737. var t = document.createElement('div');
  738. t.id = '__mylingual_status';
  739. (function (o) {
  740. for (var i in o) {
  741. t.style[i] = o[i];
  742. }
  743. })({
  744. border: '1px solid #666',
  745. background: '#f88',
  746. padding: '0.3em',
  747. color: 'black',
  748. fontFamily: 'sans-serif',
  749. fontWeight: 'bold',
  750. position: window.innerWidth ? 'fixed' : 'absolute',
  751. left: '10px',
  752. bottom: '10px',
  753. zIndex: 100
  754. });
  755. document.body.appendChild(t);
  756. t.innerHTML = 'Japanize: ' + text;
  757. window.setTimeout(
  758. function () {
  759. t.parentNode.removeChild(t);
  760. },
  761. 3000);
  762. }
  763. };
  764.  
  765. MYLINGUAL._s = function (n) {
  766. return {
  767. 'status.translated': '翻訳完了',
  768. 'status.bannedpage': '翻訳しないページ'
  769. }[n];
  770. };
  771. MYLINGUAL._f = function () {};
  772. MYLINGUAL.localizeOpera = function (json) {
  773. if (typeof json != 'object') return;
  774. this.localizeWithData(json, document, {});
  775. };
  776.  
  777. // flickr uses customized String.prototype.replace
  778. if ("0a1".replace(/[a-z]/g, function (m) { return "A"; }) != "0A1") {
  779. MYLINGUAL._gsub = function (str, re, func) {
  780. var out = "";
  781. var match;
  782. var start = re.lastIndex = 0;
  783. while (match = re.exec(str)) {
  784. out += str.slice(start, match.index);
  785. out += func.apply(null, match).toString();
  786. start = re.lastIndex;
  787. }
  788. out += str.substring(start);
  789. return out;
  790. };
  791. }
  792.  
  793. (function () {
  794. var elem = document.createElement('script');
  795. elem.src =
  796. 'http://japanize.31tools.com/data_jsonp/'
  797. + location.host
  798. + '?jsonp=MYLINGUAL.localizeOpera';
  799. document.body.appendChild(elem);
  800. })();