Itsnotlupus' I18N Support

no budget? no translators? no problem.

目前為 2023-07-17 提交的版本,檢視 最新版本

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.cn-greasyfork.org/scripts/471000/1221122/Itsnotlupus%27%20I18N%20Support.js

// ==UserScript==
// @name         Itsnotlupus' I18N Support
// @namespace    Itsnotlupus Industries
// @version      1.0
// @description  no budget? no translators? no problem.
// @author       Itsnotlupus
// @license      MIT
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==

/*jshint esversion: 11 */

/* There are 2 kind of localized strings you'll find in userscripts:
 * 1. strings found in the original web page.
 * 2. strings used by the userscript itself.
 *
 * To get the former translated, you will need to hook into the web app and somehow
 * get a hold of the proper localized strings.
 *
 * For the latter, you can rely on this library to ask Google Translate for some
 * machine-translated strings.  
 * It's not going to be flawless, but it should generally be close enough.
 *
 * Pass an array for strings found in the original page, and an object mapping 
 * ids to strings for your userscript strings.
 */
 
class I18N {
    constructor() {
        this.translations = GM_getValue("translations", {});
    }
    
    setEnStrings(enStringsArray = [], enStringsObject = {}) {
        this.enStringsArray = enStringsArray;
        this.enStringsObject = enStringsObject;
        this.i18n = { 'en': Object.assign(this.enStringsArray.reduce((o, v) => (o[v]=v,o), {}), this.enStringsObject) };
    }
    
    async setLanguage(lang, callback) {
        this.lang = lang;
        if (lang !== 'en') {
            this.i18n[lang] = await callback(this.enStringsArray) ?? {};
             
            await Promise.all(Object.keys(this.i18n.en).filter(k=>!this.i18n[lang][k]).map(async id => {
                this.i18n[lang][id] = await this.getTranslation(this.i18n.en[id], 'en', lang);
            }));
        }
    }
     
    async getTranslation(text, from, to) {
        const key = JSON.stringify({text,from,to});
        let translated = this.translations[key];
        if (!translated) {
          const string = await this._getTranslation(text, from, to);
          if (string) {
            this.translations[key] = string;
            GM_setValue("translations", this.translations);
            translated = string;
          } else {
            translated = text;
          }
        }
        return translated;
    }
    
    _getTranslation(text, from, to) {
        return new Promise((r,e) =>
            GM_xmlhttpRequest({
                method: 'POST',
                url: `https://translate.google.com/translate_a/single?client=at&dt=t&dt=rm&dj=1`,
                data: new URLSearchParams({
                  sl: from,
                  tl: to,
                  q: text
                }),
                responseType: "json",
                onload: v => r(v.response.sentences.map(s=>s.trans).join('')),
                onerror: e
              })
            );
    }
    
    translate(s) {
        return this.i18n[this.lang]?.[s] ?? s;
    }
}

const i18n = new I18N();

const t = s => i18n.translate(s);