├── dist ├── .env ├── UserJS │ └── .env.example ├── icons │ ├── google.ico │ ├── lingva.png │ ├── yandex.ico │ ├── translate.svg │ └── bing.svg ├── css │ ├── foreign.css │ ├── useSiteColors.css │ └── twittertranslator.css └── twittertranslatorlegacy.user.js ├── src ├── .env ├── Common │ └── sass │ │ ├── twittertranslator.scss │ │ ├── foreign.scss │ │ ├── useSiteColors.scss │ │ ├── colors.scss │ │ └── menu.scss ├── UserJS │ ├── .env.example │ └── header.js ├── header.js ├── menu.html └── languages.js ├── assets ├── preview1.gif ├── preview2.gif ├── ExternalTranslator.gif ├── ExternalTranslator1.png ├── ExternalTranslator2.png ├── ExternalTranslator3.png ├── ExternalTranslator4.gif └── ExternalTranslator5.png ├── .prettierrc ├── .gitignore ├── .editorconfig ├── .swcrc ├── .hintrc ├── README.ja.md ├── README.zh.md ├── README.zh-tw.md ├── README.de.md ├── README.es.md ├── README.fr.md ├── README.nl.md ├── README.pl.md ├── README.pt.md ├── README.ru.md ├── README.it.md ├── twitter-translator.code-workspace ├── eslint.config.js ├── package.json ├── README.gf.md ├── README.md ├── tools └── userscript.mjs └── LICENSE /dist/.env: -------------------------------------------------------------------------------- 1 | JS_ENV="production" -------------------------------------------------------------------------------- /src/.env: -------------------------------------------------------------------------------- 1 | JS_ENV="development" -------------------------------------------------------------------------------- /src/Common/sass/twittertranslator.scss: -------------------------------------------------------------------------------- 1 | @charset 'UTF-8'; 2 | 3 | @import 'menu'; 4 | -------------------------------------------------------------------------------- /dist/UserJS/.env.example: -------------------------------------------------------------------------------- 1 | # Please do not change this env variable 2 | JS_ENV="production" 3 | -------------------------------------------------------------------------------- /src/UserJS/.env.example: -------------------------------------------------------------------------------- 1 | # Please do not change this env variable 2 | JS_ENV="development" 3 | -------------------------------------------------------------------------------- /assets/preview1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magicoflolis/twitter-translator/HEAD/assets/preview1.gif -------------------------------------------------------------------------------- /assets/preview2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magicoflolis/twitter-translator/HEAD/assets/preview2.gif -------------------------------------------------------------------------------- /dist/icons/google.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magicoflolis/twitter-translator/HEAD/dist/icons/google.ico -------------------------------------------------------------------------------- /dist/icons/lingva.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magicoflolis/twitter-translator/HEAD/dist/icons/lingva.png -------------------------------------------------------------------------------- /dist/icons/yandex.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magicoflolis/twitter-translator/HEAD/dist/icons/yandex.ico -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "tabWidth": 2, 4 | "printWidth": 100, 5 | "trailingComma": "none" 6 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | *.bak 3 | /.vscode/ 4 | /notes/ 5 | /ExternalTranslator/devbuild/ 6 | /node_modules/ 7 | */node_modules/ -------------------------------------------------------------------------------- /assets/ExternalTranslator.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magicoflolis/twitter-translator/HEAD/assets/ExternalTranslator.gif -------------------------------------------------------------------------------- /assets/ExternalTranslator1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magicoflolis/twitter-translator/HEAD/assets/ExternalTranslator1.png -------------------------------------------------------------------------------- /assets/ExternalTranslator2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magicoflolis/twitter-translator/HEAD/assets/ExternalTranslator2.png -------------------------------------------------------------------------------- /assets/ExternalTranslator3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magicoflolis/twitter-translator/HEAD/assets/ExternalTranslator3.png -------------------------------------------------------------------------------- /assets/ExternalTranslator4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magicoflolis/twitter-translator/HEAD/assets/ExternalTranslator4.gif -------------------------------------------------------------------------------- /assets/ExternalTranslator5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magicoflolis/twitter-translator/HEAD/assets/ExternalTranslator5.png -------------------------------------------------------------------------------- /dist/css/foreign.css: -------------------------------------------------------------------------------- 1 | .prf-header>div>.tet{display:inline-block !important;width:100% !important}select.tetTextColor{height:auto !important} 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = crlf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.swcrc: -------------------------------------------------------------------------------- 1 | { 2 | "jsc": { 3 | "parser": { 4 | "syntax": "ecmascript" 5 | }, 6 | "target": "es2020" 7 | }, 8 | "module": { 9 | "type": "commonjs" 10 | } 11 | } -------------------------------------------------------------------------------- /src/Common/sass/foreign.scss: -------------------------------------------------------------------------------- 1 | .prf-header > div > .tet { 2 | display: inline-block !important; 3 | width: 100% !important; 4 | }; 5 | select.tetTextColor { 6 | height: auto !important; 7 | }; 8 | -------------------------------------------------------------------------------- /.hintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "development" 4 | ], 5 | "browserslist": [ 6 | "defaults", 7 | "not ie 11", 8 | "not ios_saf <= 16.5", 9 | "not safari <= 16.5" 10 | ] 11 | } -------------------------------------------------------------------------------- /src/header.js: -------------------------------------------------------------------------------- 1 | {jshead} 2 | 'use strict'; 3 | // Uncompressed source code: 4 | // https://github.com/magicoflolis/twitter-translator/src 5 | const tetCSS = '{tetCSS}'; 6 | const nitterCSS = '{nitterCSS}'; 7 | const debugToggle = {debugToggle}; 8 | const ghCDN = 'https://cdn.jsdelivr.net/gh'; 9 | (() => { 10 | {languages} 11 | {code} 12 | })(); 13 | -------------------------------------------------------------------------------- /src/UserJS/header.js: -------------------------------------------------------------------------------- 1 | {jshead} 2 | 'use strict'; 3 | (() => { 4 | // Uncompressed source code: 5 | // https://github.com/magicoflolis/twitter-translator/src 6 | // eslint-disable-next-line no-unused-vars, quotes 7 | const tetCSS = `{tetCSS}`; 8 | // eslint-disable-next-line no-unused-vars, quotes 9 | const nitterCSS = `{nitterCSS}`; 10 | const debugToggle = {debugToggle}; 11 | const ghCDN = 'https://cdn.jsdelivr.net/gh'; 12 | {languages} 13 | {code} 14 | })(); 15 | -------------------------------------------------------------------------------- /README.ja.md: -------------------------------------------------------------------------------- 1 | # Twitter 外部翻訳者 2 | 3 | ![Menu Preview](https://raw.githubusercontent.com/magicoflolis/userscriptrepo/master/assets/ExternalTranslator.gif) 4 | 5 | ## Source Code 6 | 7 | * [GitHub](https://github.com/magicoflolis/userscriptrepo/tree/master/ExternalTranslator) 8 | 9 | ### Contacts 10 | 11 | [GitHub](https://github.com/magicoflolis) 12 | 13 | [Twitter](https://twitter.com/for_lollipops) 14 | 15 | [Greasy Fork](https://greasyfork.org/users/166061) 16 | -------------------------------------------------------------------------------- /README.zh.md: -------------------------------------------------------------------------------- 1 | # Twitter外部翻译器 2 | 3 | ![Menu Preview](https://raw.githubusercontent.com/magicoflolis/userscriptrepo/master/assets/ExternalTranslator.gif) 4 | 5 | ## Source Code 6 | 7 | * [GitHub](https://github.com/magicoflolis/userscriptrepo/tree/master/ExternalTranslator) 8 | 9 | ### Contacts 10 | 11 | [GitHub](https://github.com/magicoflolis) 12 | 13 | [Twitter](https://twitter.com/for_lollipops) 14 | 15 | [Greasy Fork](https://greasyfork.org/users/166061) 16 | -------------------------------------------------------------------------------- /README.zh-tw.md: -------------------------------------------------------------------------------- 1 | # Twitter外部翻译器 2 | 3 | ![Menu Preview](https://raw.githubusercontent.com/magicoflolis/userscriptrepo/master/assets/ExternalTranslator.gif) 4 | 5 | ## Source Code 6 | 7 | * [GitHub](https://github.com/magicoflolis/userscriptrepo/tree/master/ExternalTranslator) 8 | 9 | ### Contacts 10 | 11 | [GitHub](https://github.com/magicoflolis) 12 | 13 | [Twitter](https://twitter.com/for_lollipops) 14 | 15 | [Greasy Fork](https://greasyfork.org/users/166061) 16 | -------------------------------------------------------------------------------- /README.de.md: -------------------------------------------------------------------------------- 1 | # Twitter External Translator 2 | 3 | ![Menu Preview](https://raw.githubusercontent.com/magicoflolis/userscriptrepo/master/assets/ExternalTranslator.gif) 4 | 5 | ## Source Code 6 | 7 | * [GitHub](https://github.com/magicoflolis/userscriptrepo/tree/master/ExternalTranslator) 8 | 9 | ### Contacts 10 | 11 | [GitHub](https://github.com/magicoflolis) 12 | 13 | [Twitter](https://twitter.com/for_lollipops) 14 | 15 | [Greasy Fork](https://greasyfork.org/users/166061) 16 | -------------------------------------------------------------------------------- /README.es.md: -------------------------------------------------------------------------------- 1 | # Traductor externo de Twitter 2 | 3 | ![Menu Preview](https://raw.githubusercontent.com/magicoflolis/userscriptrepo/master/assets/ExternalTranslator.gif) 4 | 5 | ## Source Code 6 | 7 | * [GitHub](https://github.com/magicoflolis/userscriptrepo/tree/master/ExternalTranslator) 8 | 9 | ### Contacts 10 | 11 | [GitHub](https://github.com/magicoflolis) 12 | 13 | [Twitter](https://twitter.com/for_lollipops) 14 | 15 | [Greasy Fork](https://greasyfork.org/users/166061) 16 | -------------------------------------------------------------------------------- /README.fr.md: -------------------------------------------------------------------------------- 1 | # Twitter External Translator 2 | 3 | ![Menu Preview](https://raw.githubusercontent.com/magicoflolis/userscriptrepo/master/assets/ExternalTranslator.gif) 4 | 5 | ## Source Code 6 | 7 | * [GitHub](https://github.com/magicoflolis/userscriptrepo/tree/master/ExternalTranslator) 8 | 9 | ### Contacts 10 | 11 | [GitHub](https://github.com/magicoflolis) 12 | 13 | [Twitter](https://twitter.com/for_lollipops) 14 | 15 | [Greasy Fork](https://greasyfork.org/users/166061) 16 | -------------------------------------------------------------------------------- /README.nl.md: -------------------------------------------------------------------------------- 1 | # Twitter Externe vertaler 2 | 3 | ![Menu Preview](https://raw.githubusercontent.com/magicoflolis/userscriptrepo/master/assets/ExternalTranslator.gif) 4 | 5 | ## Source Code 6 | 7 | * [GitHub](https://github.com/magicoflolis/userscriptrepo/tree/master/ExternalTranslator) 8 | 9 | ### Contacts 10 | 11 | [GitHub](https://github.com/magicoflolis) 12 | 13 | [Twitter](https://twitter.com/for_lollipops) 14 | 15 | [Greasy Fork](https://greasyfork.org/users/166061) 16 | -------------------------------------------------------------------------------- /README.pl.md: -------------------------------------------------------------------------------- 1 | # Twitter Zewnętrzny tłumacz 2 | 3 | ![Menu Preview](https://raw.githubusercontent.com/magicoflolis/userscriptrepo/master/assets/ExternalTranslator.gif) 4 | 5 | ## Source Code 6 | 7 | * [GitHub](https://github.com/magicoflolis/userscriptrepo/tree/master/ExternalTranslator) 8 | 9 | ### Contacts 10 | 11 | [GitHub](https://github.com/magicoflolis) 12 | 13 | [Twitter](https://twitter.com/for_lollipops) 14 | 15 | [Greasy Fork](https://greasyfork.org/users/166061) 16 | -------------------------------------------------------------------------------- /README.pt.md: -------------------------------------------------------------------------------- 1 | # Tradutor Externo Twitter 2 | 3 | ![Menu Preview](https://raw.githubusercontent.com/magicoflolis/userscriptrepo/master/assets/ExternalTranslator.gif) 4 | 5 | ## Source Code 6 | 7 | * [GitHub](https://github.com/magicoflolis/userscriptrepo/tree/master/ExternalTranslator) 8 | 9 | ### Contacts 10 | 11 | [GitHub](https://github.com/magicoflolis) 12 | 13 | [Twitter](https://twitter.com/for_lollipops) 14 | 15 | [Greasy Fork](https://greasyfork.org/users/166061) 16 | -------------------------------------------------------------------------------- /README.ru.md: -------------------------------------------------------------------------------- 1 | # Внешний переводчик Твиттера 2 | 3 | ![Menu Preview](https://raw.githubusercontent.com/magicoflolis/userscriptrepo/master/assets/ExternalTranslator.gif) 4 | 5 | ## Source Code 6 | 7 | * [GitHub](https://github.com/magicoflolis/userscriptrepo/tree/master/ExternalTranslator) 8 | 9 | ### Contacts 10 | 11 | [GitHub](https://github.com/magicoflolis) 12 | 13 | [Twitter](https://twitter.com/for_lollipops) 14 | 15 | [Greasy Fork](https://greasyfork.org/users/166061) 16 | -------------------------------------------------------------------------------- /README.it.md: -------------------------------------------------------------------------------- 1 | # Traduttore esterno di Twitter 2 | 3 | ![Menu Preview](https://raw.githubusercontent.com/magicoflolis/userscriptrepo/master/assets/ExternalTranslator.gif) 4 | 5 | ## Source Code 6 | 7 | * [GitHub](https://github.com/magicoflolis/userscriptrepo/tree/master/ExternalTranslator) 8 | 9 | ### Contacts 10 | 11 | [GitHub](https://github.com/magicoflolis) 12 | 13 | [Twitter](https://twitter.com/for_lollipops) 14 | 15 | [Greasy Fork](https://greasyfork.org/users/166061) 16 | -------------------------------------------------------------------------------- /dist/icons/translate.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /twitter-translator.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": { 8 | "search.exclude": { 9 | "**/node_modules": true, 10 | "**/chrome_dist/js/**": true, 11 | "**/dist/js/**": true 12 | }, 13 | "editor.formatOnSaveMode": "modifications", 14 | "files.trimTrailingWhitespace": true, 15 | "files.associations": { 16 | ".eslintrc": "jsonc" 17 | }, 18 | "editor.codeActionsOnSave": { 19 | "source.fixAll": false, 20 | "source.fixAll.eslint": true 21 | }, 22 | "local-history.daysLimit": 3, 23 | "local-history.maxDisplay": 10, 24 | "local-history.saveDelay": 0, 25 | "local-history.dateLocale": "en-US", 26 | "local-history.exclude": [ 27 | "**/.history/**", 28 | "**/.vscode/**", 29 | "**/node_modules/**", 30 | "**/dist/**", 31 | "**/chrome_dist/**", 32 | "**/build/**", 33 | "**/*.code-workspace", 34 | "**/src/sass/**", 35 | ], 36 | "local-history.path": "${workspaceFolder}/.vscode", 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import js from '@eslint/js'; 3 | import globals from 'globals'; 4 | import configPrettier from 'eslint-config-prettier'; 5 | 6 | export default [ 7 | js.configs.recommended, 8 | configPrettier, 9 | { 10 | // files: ['*.js'], 11 | ignores: [ 12 | 'src/UserJS/header.js', 13 | 'src/**/header.js', 14 | 'src/languages.js', 15 | 'tools/userscript.js', 16 | 'dist/**/*.js' 17 | ], 18 | languageOptions: { 19 | ecmaVersion: 'latest', 20 | globals: { 21 | GM: 'writable', 22 | ghCDN: 'readonly', 23 | debugToggle: 'readonly', 24 | languages: 'readonly', 25 | nitterCSS: 'readonly', 26 | tetCSS: 'readonly', 27 | twCSS: 'readonly', 28 | ...globals.node, 29 | ...globals.nodeBuiltin, 30 | ...globals.browser, 31 | ...globals.greasemonkey, 32 | ...globals.webextensions 33 | }, 34 | parserOptions: { 35 | ecmaVersion: 'latest', 36 | sourceType: 'module', 37 | allowImportExportEverywhere: false, 38 | ecmaFeatures: { 39 | globalReturn: true, 40 | arrowFunctions: true, 41 | modules: true 42 | } 43 | } 44 | }, 45 | rules: { 46 | 'no-var': 'error', 47 | quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: false }] 48 | } 49 | } 50 | ]; 51 | -------------------------------------------------------------------------------- /dist/css/useSiteColors.css: -------------------------------------------------------------------------------- 1 | [id=tetNT] .tetBackground{border-color:var(--border_grey)}[id=tetNT] .tetNitter[id=tetSelector]:hover{border-color:var(--accent_border) !important;box-shadow:var(--accent_border) !important}[id=tetNT] .tetNitter[id=tetSelector]:hover [id=tetName] span{color:var(--fg_dark)}[id=tetNT] h1.tetNTextColor{color:var(--grey)}[id=tetNT] .nitter:not(.tetswitch,.tetBtn){background-color:var(--bg_color)}[id=tetNT] .nitter:not(.tetswitch,.tetBtn) div[id=tetName]{color:var(--fg_dark)}[id=tetNT] .tetBtn.nitter:not(.tet-29u,.tet-186u,.tet-122u,.tet-120u,.tet-249u,.tet-255u){color:var(--fg_color);background-color:var(--fg_dark)}[id=tetNT] input.tetNTextColor,[id=tetNT] select.tetNTextColor,[id=tetNT] div.tetNTextColor,[id=tetNT] svg.tetNTextColor,[id=tetNT] label.tetNTextColor>span{color:var(--fg_color)}[id=tetNT] .tetNText,[id=tetNT] .tetNText span{color:var(--fg_dark) !important}[id=tetNT] .tetNBackground{background-color:var(--bg_panel)}.tetNitterHover{background-color:var(--fg_dark)}[id=tetBTD] .tweetdeck:not(.tetswitch){background-color:var(--btd-accent-color)}[id=tetBTD] .r-tetTD{background-color:var(--btd-theme-background) !important}[id=tetBTD] .r-tetTD[id=tetSelector].Button--primary:hover{border-color:#1da1f2;box-shadow:#1da1f2 0px 0px 0px 1px}[id=tetBTD] .r-tetTD[id=tetSelector].Button--primary:hover [id=tetName] span{color:#1da1f2}[id=tetBTD] .r-tetBTD{background-color:var(--btd-theme-background) !important}[id=tetBTD] .r-tetBTD [id=tetName] span{color:var(--btd-accent-color)}.tetNText .tet-svg{fill:var(--fg_dark)} 2 | -------------------------------------------------------------------------------- /src/Common/sass/useSiteColors.scss: -------------------------------------------------------------------------------- 1 | // var(--accent) 2 | 3 | [id="tetNT"] { 4 | .tetBackground { 5 | border-color: var(--border_grey); 6 | }; 7 | .tetNitter { 8 | &[id="tetSelector"]:hover { 9 | border-color: var(--accent_border) !important; 10 | box-shadow: var(--accent_border) !important; 11 | [id="tetName"] span { 12 | color: var(--fg_dark); 13 | } 14 | }; 15 | }; 16 | h1.tetNTextColor { 17 | color: var(--grey); 18 | }; 19 | .nitter:not(.tetswitch,.tetBtn) { 20 | background-color: var(--bg_color); 21 | div[id="tetName"] { 22 | color: var(--fg_dark); 23 | }; 24 | }; 25 | .tetBtn.nitter:not(.tet-29u,.tet-186u,.tet-122u,.tet-120u,.tet-249u,.tet-255u) { 26 | color: var(--fg_color); 27 | background-color: var(--fg_dark); 28 | }; 29 | input.tetNTextColor, 30 | select.tetNTextColor, 31 | div.tetNTextColor, 32 | svg.tetNTextColor, 33 | label.tetNTextColor>span { 34 | color: var(--fg_color); 35 | }; 36 | .tetNText, 37 | .tetNText span { 38 | color: var(--fg_dark) !important; 39 | }; 40 | .tetNBackground { 41 | background-color: var(--bg_panel); 42 | }; 43 | }; 44 | 45 | .tetNitterHover { 46 | background-color: var(--fg_dark); 47 | }; 48 | 49 | [id="tetBTD"] { 50 | .tweetdeck:not(.tetswitch) { 51 | background-color: var(--btd-accent-color); 52 | }; 53 | 54 | .r-tetTD { 55 | background-color: var(--btd-theme-background) !important; 56 | &[id="tetSelector"].Button--primary:hover { 57 | border-color: #1da1f2; 58 | box-shadow: #1da1f2 0px 0px 0px 1px; 59 | [id="tetName"] span { 60 | color: #1da1f2; 61 | } 62 | } 63 | }; 64 | .r-tetBTD { 65 | background-color: var(--btd-theme-background) !important; 66 | [id="tetName"] span { 67 | color: var(--btd-accent-color); 68 | } 69 | }; 70 | }; 71 | .tetNText .tet-svg { 72 | fill: var(--fg_dark); 73 | }; 74 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "twitter-translator", 3 | "description": "Adds external & internal translators to various sites.", 4 | "author": "Magic ", 5 | "version": "2.5.1", 6 | "license": "GPL-3.0", 7 | "userJS": { 8 | "version": "2.6.1", 9 | "name": "Twitter External Translator", 10 | "bugs": "https://github.com/magicoflolis/twitter-translator/issues/new", 11 | "homepage": "https://github.com/magicoflolis/twitter-translator#twitter-external-translator", 12 | "icon": "https://abs.twimg.com/favicons/twitter.ico", 13 | "url": "https://github.com/magicoflolis/twitter-translator/releases/latest/download/twittertranslator.user.js" 14 | }, 15 | "type": "module", 16 | "scripts": { 17 | "dev": "concurrently \"npm run dev:UserJS\" \"npm run dev:Server\" \"npm run dev:Sass\"", 18 | "dev:UserJS": "node ./tools/userscript.mjs", 19 | "dev:Sass": "sass -w --no-source-map ./src/Common/sass:./dist/css -s compressed", 20 | "dev:Server": "http-server ./build/UserJS -s --no-dotfiles -c-1", 21 | "pub": "concurrently \"pnpm run pub:Sass\" \"pnpm run pub:UserJS\"", 22 | "pub:Sass": "sass --no-source-map ./src/Common/sass:./dist/css -s compressed", 23 | "pub:UserJS": "node -r dotenv/config ./tools/userscript.mjs dotenv_config_path=./dist/UserJS/.env" 24 | }, 25 | "devDependencies": { 26 | "@types/eslint-config-prettier": "^6.11.0", 27 | "@types/eslint__js": "^8.42.0", 28 | "concurrently": "^8.2.0", 29 | "dotenv": "^16.3.1", 30 | "eslint": "^8.46.0", 31 | "eslint-config-prettier": "^8.9.0", 32 | "globals": "^13.20.0", 33 | "http-server": "^14.1.1", 34 | "node-watch": "^0.7.3", 35 | "prettier": "^3.0.0", 36 | "sass": "^1.64.1" 37 | }, 38 | "repository": { 39 | "type": "git", 40 | "url": "git+https://github.com/magicoflolis/twitter-translator.git" 41 | }, 42 | "keywords": [ 43 | "userjs", 44 | "greasemonkey", 45 | "violentmonkey", 46 | "tampermonkey", 47 | "javascript", 48 | "browser" 49 | ], 50 | "webExt": { 51 | "sourceDir": "./dist/WebExtension/", 52 | "artifactsDir": "./build/tmp/" 53 | }, 54 | "private": true 55 | } 56 | -------------------------------------------------------------------------------- /README.gf.md: -------------------------------------------------------------------------------- 1 | # Twitter External Translator 2 | 3 | > Adds a "Translate with ..." button to Tweets and User Bios. 4 | 5 | *This was a fork of [DeepL Twitter translation](https://greasyfork.org/scripts/411976)* 6 | 7 | *** 8 | 9 | | Version | Link | Alternative | Note | 10 | |:----------:|:----------:|:----------:|:----------:| 11 | Stable | [Install](#install-area) | [Install [GitHub]](https://github.com/magicoflolis/twitter-translator/releases/latest/download/twittertranslator.user.js) | Recommended version. 12 | Legacy | - | [Install [GitHub]](https://github.com/magicoflolis/twitter-translator/raw/master/dist/twittertranslatorlegacy.user.js) | For incompatibility issues. 13 | 14 | *** 15 | 16 | | Preview | 17 | |:----------:| 18 | ![Menu Preview](https://raw.githubusercontent.com/magicoflolis/twitter-translator/master/assets/ExternalTranslator.gif)| 19 | 20 | ## Changelog 21 | 22 | > [(GitHub) Full Changelog](https://github.com/magicoflolis/twitter-translator/releases) 23 | 24 | ## Features 25 | 26 | > The menu and CSS have been compressed to reduce file size. Comments can be found under `src/main.js` on GitHub. 27 | 28 | * [ Script ] Support for External & Internal Translators! 29 | * [ Menu ] Config Menu! 30 | * [ Menu ] Multiple language support! 31 | * [ Menu ] Support for matching Twitter colors 32 | * [ Menu ] Support for matching Twitter theme 33 | * [ Site ] Support for [TwitLonger](https://www.twitlonger.com) 34 | * [ Site ] Support for [TweetDeck](https://tweetdeck.twitter.com) 35 | * [ Site ] Support for every [Nitter](https://github.com/zedeus/nitter/wiki/Instances#official-instances) 36 | * [ Script ] Now works while logged out! 37 | * [ Script ] Added "Restore to Defaults" button. 38 | * [ Site ] Added mobile.twitter.com 39 | * [ Menu ] Will automatically default to current sites theme. 40 | * [ Menu ] Will automatically select the current language of the site. 41 | * Each [ WIP ] is functional. 42 | * [ WIP ] Every theme can be applied to any site! 43 | * [ WIP ] Added help for each menu item. 44 | * [ WIP ] Reworked the menus CSS. 45 | 46 | ### Supported 47 | 48 | Translator | External | Website | Internal | 49 | :---------:|:-----------:|:-----------:|:---------:| 50 | Bing Microsoft Translator | ✅ |[link](https://www.bing.com/translator)| ❌ | 51 | DeepL Translate | ✅ |[link](https://www.deepl.com/translator)| ✅ | 52 | Google Translate | ✅ |[link](https://translate.google.com/)| ✅ | 53 | LibreTranslate | ❌ |[link](https://libretranslate.com/)| ✅ | 54 | Lingva Translate | ✅ |[link](https://lingva.ml/)| ✅ | 55 | MyMemory | ✅ |[link](https://mymemory.translated.net/)| ✅ | 56 | Translate.com | ✅ |[link](https://www.translate.com/)| ❌ | 57 | Yandex Translate | ✅ |[link](https://translate.yandex.com/)| ❌ | 58 | 59 | ## Documentation 60 | 61 | * [(GitHub) Wiki](https://github.com/magicoflolis/twitter-translator/wiki) 62 | 63 | ## Bugs / Issues 64 | 65 | * [ User Script ] *May* conflict with [Magic Userscript+ : Show Site All UserJS](https://greasyfork.org/scripts/421603). 66 | * [ Script ] *Sometimes* "Translate tweet" won't appear on Twitter. (Clicking a picture and opening the right sidebar to view the Tweet & Replies) 67 | * [ Translator ] MyMemory API doesn't work in Bios. 68 | * [ Menu ] Cannot be moved or disabled. ( WIP ) 69 | 70 | **Footnotes:** 71 | 72 | * [ Translator ] Twitters built-in translation uses Google Translate, TweetDeck uses Bing Microsoft Translator. 73 | * [ TweetDeck ] Only appears in one column. 74 | * [ Translator ] Yandex Translate may default to Russian. 75 | ![YandexHelp](https://raw.githubusercontent.com/magicoflolis/twitter-translator/master/assets/ExternalTranslator4.gif) 76 | 77 | ## Source Code 78 | 79 | [https://github.com/magicoflolis/twitter-translator](https://github.com/magicoflolis/twitter-translator) 80 | 81 | ## Contacts 82 | 83 | * [GitHub](https://github.com/magicoflolis) 84 | * [Twitter](https://twitter.com/for_lollipops) 85 | * [Greasy Fork](https://greasyfork.org/users/166061) 86 | 87 | ## Roadmap 88 | 89 | * Fix any bugs along the way. 90 | * Automatically match Twitter colors. 91 | * Show multiple translators at once. 92 | * Show multiple on TweetDeck. 93 | * Support for direct messages. 94 | * Support more translators. 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Twitter External Translator 2 | 3 | > Adds "Translate with ..." to Tweet and User Bio on various sites. 4 | *This originally was a fork of [DeepL Twitter translation](https://greasyfork.org/scripts/411976)* 5 | 6 | *** 7 | 8 | | Version | Link | Alternative | Note | 9 | |:----------:|:----------:|:----------:|:----------:| 10 | Stable | [Greasy Fork](https://greasyfork.org/scripts/421643) | [(GitHub) Install](https://github.com/magicoflolis/twitter-translator/releases/latest/download/twittertranslator.user.js) | [Bug] Duplicate "Translate with ..." in Direct Messages (sometimes) 11 | 12 | *** 13 | 14 | | Preview | 15 | |:----------:| 16 | ![Menu Preview](https://raw.githubusercontent.com/magicoflolis/twitter-translator/master/assets/preview1.gif)| 17 | 18 | ## Changelog 19 | 20 | > [(GitHub) Full Changelog](https://github.com/magicoflolis/twitter-translator/releases) 21 | 22 | ## Features 23 | 24 | > The menu and CSS have been compressed to reduce file size. Comments can be found under `src/main.js` on GitHub. 25 | 26 | * Support for External & Internal Translators! 27 | * Multi language Config menu! 28 | * Multi language Translator support! 29 | * Colors and themes can be customized. 30 | * Automatically match websites color, theme and language. 31 | * Supports mobile [Twitter](https://mobile.twitter.com/) 32 | * Supports [TwitLonger](https://www.twitlonger.com) 33 | * Supports [TweetDeck](https://tweetdeck.twitter.com) 34 | * Supports every [Nitter](https://github.com/zedeus/nitter/wiki/Instances#official-instances) 35 | * Support for multiple Bios / Tweets on websites! 36 | * Support for Twitter hover cards. 37 | * Support for Twitter & TweetDeck direct messages. 38 | * Works while logged out! 39 | * "Restore to Defaults" button. 40 | * document.location.search commands: 41 | 42 | **Supported Commands:** 43 | 44 | > Using commands is optional. 45 | 46 | * "tetopen" -- Will force open config menu on page load. 47 | * "tetrestore" -- Will restore config to defaults. 48 | * "tetdebug" -- Force enable scripts console.log 49 | 50 | ```js 51 | https:///? 52 | ``` 53 | 54 | **Examples:** 55 | 56 | > Be sure to remove command(s) from url afterwards! 57 | 58 | ```js 59 | // Will force open config menu on page load. 60 | https://twitter.com/messages/?tetopen 61 | 62 | // Can be chanined 63 | https://twitter.com/?tetrestore&tetopen&tetdebug 64 | 65 | ``` 66 | 67 | ### Supported 68 | 69 | Translator | External | Website | Internal | 70 | :---------:|:-----------:|:-----------:|:---------:| 71 | Bing Microsoft Translator | ✅ |[link](https://www.bing.com/translator)| UNTESTED | 72 | DeepL Translate | ✅ |[link](https://www.deepl.com/translator)| ✅ | 73 | Google Translate | ✅ |[link](https://translate.google.com/)| ✅ | 74 | LibreTranslate | ❌ |[link](https://libretranslate.com/)| ✅ | 75 | Lingva Translate | ✅ |[link](https://lingva.ml/)| ✅ | 76 | MyMemory | ✅ |[link](https://mymemory.translated.net/)| ✅ | 77 | Translate.com | ✅ |[link](https://www.translate.com/)| UNTESTED | 78 | Yandex Translate | ✅ |[link](https://translate.yandex.com/)| UNTESTED | 79 | 80 | ## Documentation 81 | 82 | * [(GitHub) Wiki](https://github.com/magicoflolis/twitter-translator/wiki) 83 | 84 | **FAQ:** 85 | 86 | While logged out, UserScript does not work on homepage? 87 | 88 | * UserScript does not run on login / sign up page, example: [https://twitter.com/](https://twitter.com/). 89 | * In addition, UserScript will search document.cookie for "twid" on Twitter and TweetDeck to determine if the user is logged in / out. 90 | 91 | On mobile, how do you open the config menu? 92 | 93 | * "Menu" button is disabled / hidden on mobile, you can add '?tetopen' at the end of the url to force open config menu. 94 | * Be sure to close the menu to save your changes and remove '?tetopen' from the url to prevent menu from reopening. 95 | 96 | Where does the UserScript store my API key? 97 | 98 | * API keys are storing in the webpages localStorage (localStorage.getItem("TETConfig")) and UserScripts storage. 99 | * NOTE: API keys are stored in plain text and not protected by any encryption! 100 | 101 | ## Bugs / Issues 102 | 103 | * Duplicate "Translate with ..." in Direct Messages (sometimes) 104 | * Auto Theme + Auto Color may not work on Chromium based browsers. 105 | * [Translators] Azure Cognitive Services is not implemented. 106 | 107 | **Footnotes:** 108 | 109 | * [ Translator ] Twitters built-in translation uses Google Translate, TweetDeck uses Bing Microsoft Translator. 110 | * [ Translator ] Yandex Translate may default to Russian. 111 | ![YandexHelp](https://raw.githubusercontent.com/magicoflolis/twitter-translator/master/assets/ExternalTranslator4.gif) 112 | 113 | ## Source Code 114 | 115 | [https://github.com/magicoflolis/twitter-translator](https://github.com/magicoflolis/twitter-translator) 116 | 117 | ## Contacts 118 | 119 | * [GitHub](https://github.com/magicoflolis) 120 | * [Twitter](https://twitter.com/for_lollipops) 121 | * [Greasy Fork](https://greasyfork.org/users/166061) 122 | 123 | ## Roadmap 124 | 125 | * Fix any bugs along the way. 126 | * Show multiple translators at once. 127 | * Support more translators. 128 | -------------------------------------------------------------------------------- /dist/icons/bing.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/Common/sass/colors.scss: -------------------------------------------------------------------------------- 1 | $accent_border: #ff6c6091; 2 | $fg_color: #f8f8f2; 3 | $tetBlue: rgb(29, 155, 240); 4 | $tetBlueH: rgb(26, 145, 218); 5 | $tetYellow: rgb(255, 212, 0); 6 | $tetYellowH: rgb(230, 156, 28); 7 | $tetRed: rgb(249, 24, 128); 8 | $tetRedH: rgb(202, 32, 85); 9 | $tetPurple: rgb(120, 86, 255); 10 | $tetPurpleH: rgb(134, 93, 202); 11 | $tetOrange: rgb(255, 122, 0); 12 | $tetOrangeH: rgb(220, 84, 31); 13 | $tetGreen: rgb(0, 186, 124); 14 | $tetGreenH: rgb(21, 172, 89); 15 | $twBlack: rgb(0, 0, 0); 16 | $twWhite: #fff; 17 | $twGray: #6e767d; 18 | $fg_dark: #FF6C60; 19 | $bg_panel: #161616; 20 | $bg_color: #0F0F0F; 21 | $td_color: #8899a6; 22 | $tdBlue: rgb(29, 161, 242); 23 | $td_b: #005fd1; 24 | $td_blue: #1da1f2; 25 | $td_blueB: #1da1f2 0px 0px 0px 1px; 26 | $grey: #888889; 27 | $accent_light: #FFACA0; 28 | $accent_lightB: #FFACA0 0px 0px 0px 1px; 29 | 30 | // name, color, hightlight, b 31 | // $tetColors: 32 | // "Blue" rgb(29, 155, 240) rgb(26, 145, 218) rgb(29, 161, 242), 33 | // "Green" rgb(0, 186, 124) rgb(21, 172, 89) rgb(23, 191, 99), 34 | // "Orange" rgb(255, 122, 0) rgb(220, 84, 31) rgb(244, 93, 34), 35 | // "Purple" rgb(120, 86, 255) rgb(134, 93, 202) rgb(121, 75, 196), 36 | // "Red" rgb(249, 24, 128) rgb(202, 32, 85) rgb(224, 36, 94), 37 | // "Yellow" rgb(255, 212, 0) rgb(230, 156, 28) rgb(255, 173, 31); 38 | $tetBShadows: 39 | "r-1bih22f" "box-shadow" "rgb(29, 161, 242) 0px 0px 0px 1px", 40 | "r-1cqwhho" "box-shadow" "rgb(23, 191, 99) 0px 0px 0px 1px", 41 | "r-b8m25f" "box-shadow" "rgb(244, 93, 34) 0px 0px 0px 1px", 42 | "r-11mmphe" "box-shadow" "rgb(121, 75, 196) 0px 0px 0px 1px", 43 | "r-jd07pc" "box-shadow" "rgb(224, 36, 94) 0px 0px 0px 1px", 44 | "r-cdj8wb" "box-shadow" "rgb(255, 173, 31) 0px 0px 0px 1px", 45 | "tet-29u:not(.tetswitch)" "background-color" rgb(29, 155, 240), 46 | "tet-186u:not(.tetswitch)" "background-color" rgb(0, 186, 124), 47 | "tet-122u:not(.tetswitch)" "background-color" rgb(255, 122, 0), 48 | "tet-120u:not(.tetswitch)" "background-color" rgb(120, 86, 255), 49 | "tet-249u:not(.tetswitch)" "background-color" rgb(249, 24, 128), 50 | "tet-255u:not(.tetswitch)" "background-color" rgb(255, 212, 0); 51 | 52 | @each $name, $type, $color in $tetBShadows { 53 | .#{$name} { 54 | #{$type}: #{$color}; 55 | } 56 | }; 57 | $tetColors: 58 | "tet-29u" rgb(29, 155, 240) rgb(26, 145, 218,.384), 59 | "tet-186u" rgb(0, 186, 124) rgb(21, 172, 89,.384), 60 | "tet-122u" rgb(255, 122, 0) rgb(220, 84, 31,.384), 61 | "tet-120u" rgb(120, 86, 255) rgb(134, 93, 202,.384), 62 | "tet-249u" rgb(249, 24, 128) rgb(202, 32, 85,.384), 63 | "tet-255u" rgb(255, 212, 0) rgb(230, 156, 28,.384), 64 | "nitter" rgb(255, 108, 96) rgb(255, 108, 96,.384), 65 | "tweetdeck" rgb(29, 161, 242) rgb(29, 161, 242,.384); 66 | 67 | @each $name, $color, $hightlight in $tetColors { 68 | .tetswitch.#{$name} > input:checked+label { 69 | background-color: $hightlight; 70 | &:before { 71 | background-color: $color; 72 | } 73 | } 74 | }; 75 | 76 | // .tet-svg { 77 | // fill: inherit; 78 | // } 79 | 80 | #tetReset, 81 | #tetMenuButton > span { 82 | color: $twWhite !important; 83 | }; 84 | 85 | #tetSelector > select { 86 | background-color: transparent; 87 | border: transparent; 88 | &:focus { 89 | box-shadow: none !important; 90 | } 91 | }; 92 | .navbackground { 93 | &.d1tet { 94 | background-color:rgba(91, 112, 131, 0.4); 95 | }; 96 | &.d2tet { 97 | background-color:rgba(0, 0, 0, 0.4); 98 | }; 99 | &.d3tet { 100 | background-color:rgba(91, 112, 131, 0.4); 101 | }; 102 | }; 103 | 104 | .tet-header, 105 | .tet-at { 106 | > span:last-child { 107 | color: #6e767d; 108 | }; 109 | } 110 | 111 | .r-demo, 112 | .tet-help-container, 113 | #apifield, 114 | #tetSelector { 115 | border-color: transparent; 116 | &.r-14lw9ot { 117 | border-color: rgb(83, 100, 113); 118 | }; 119 | &.r-yfoy6g { 120 | border-color: rgb(56, 68, 77); 121 | }; 122 | &.nitter, 123 | &.r-tetTD, 124 | &.r-kemksi { 125 | border-color: #2f3336; 126 | }; 127 | }; 128 | 129 | .r-14lw9ot > div#tetName span { 130 | color: rgb(83, 100, 113); 131 | } 132 | 133 | .r-kemksi > div#tetName span, 134 | .r-yfoy6g > div#tetName span { 135 | color: #6e767d; 136 | }; 137 | 138 | .tetBtn.nitter { 139 | border: transparent; 140 | }; 141 | 142 | .Button--primary { 143 | border-color: $td_blue; 144 | box-shadow: $td_blueB; 145 | } 146 | 147 | .r-tetTD { 148 | border-radius: 14px; 149 | background-color: #15202b; 150 | &#tetSelector.Button--primary:hover { 151 | border-color: $td_blue; 152 | box-shadow: $td_blue 0px 0px 0px 1px; 153 | #tetName span { 154 | color: $td_blue; 155 | } 156 | }; 157 | #tetName span { 158 | color: $td_color; 159 | }; 160 | }; 161 | 162 | .prf-header > div > .tet.tet-td { 163 | color: #fff !important; 164 | } 165 | .tet-td { 166 | color: $td_color; 167 | &#tetName { 168 | color: $td_blue !important; 169 | span { 170 | color: inherit !important; 171 | }; 172 | }; 173 | .tet-svg { 174 | fill: $td_blue; 175 | }; 176 | }; 177 | .tet-border-black { 178 | border-color: $twBlack; 179 | }; 180 | /* gray */ 181 | .r-9ilb82 { 182 | color: rgb(110, 118, 125); 183 | } 184 | .r-1kqtdi0 { 185 | border-color: #2f3336; 186 | } 187 | /* blue */ 188 | .r-p1n3y5 { 189 | border-color: $tetBlue !important; 190 | } 191 | .r-1q3imqu { 192 | background-color: $tetBlueH; 193 | } 194 | .r-13gxpu9 { 195 | color: $tetBlue; 196 | &#tetName { 197 | color: $tetBlue !important; 198 | span { 199 | color: inherit !important; 200 | }; 201 | }; 202 | .tet-svg { 203 | fill: $tetBlue; 204 | }; 205 | }; 206 | 207 | /* yellow */ 208 | .r-v6khid { 209 | border-color: $tetYellow !important; 210 | } 211 | 212 | .r-61mi1v { 213 | color: $tetYellow; 214 | &#tetName { 215 | color: $tetYellow !important; 216 | span { 217 | color: inherit !important; 218 | }; 219 | }; 220 | .tet-svg { 221 | fill: $tetYellow; 222 | }; 223 | }; 224 | 225 | .r-1kplyi6 { 226 | background-color: $tetYellowH; 227 | } 228 | 229 | /* red */ 230 | .r-1iofnty { 231 | border-color: $tetRed !important; 232 | } 233 | 234 | .r-daml9f { 235 | color: $tetRed; 236 | &#tetName { 237 | color: $tetRed !important; 238 | span { 239 | color: inherit !important; 240 | }; 241 | }; 242 | .tet-svg { 243 | fill: $tetRed; 244 | }; 245 | }; 246 | 247 | .r-1ucxkr8 { 248 | background-color: $tetRedH; 249 | } 250 | 251 | /* purple */ 252 | .r-njt2r9 { 253 | background-color: $tetPurpleH; 254 | } 255 | 256 | .r-hy56xe { 257 | border-color: $tetPurple !important; 258 | } 259 | 260 | .r-xfsgu1 { 261 | color: $tetPurple; 262 | &#tetName { 263 | color: $tetPurple !important; 264 | span { 265 | color: inherit !important; 266 | }; 267 | }; 268 | .tet-svg { 269 | fill: $tetPurple; 270 | }; 271 | }; 272 | 273 | /* orange */ 274 | .tet-122hu { 275 | background-color: $tetOrangeH; 276 | } 277 | 278 | .r-1xl5njo { 279 | border-color: $tetOrange !important; 280 | } 281 | .r-1qkqhnw { 282 | color: $tetOrange; 283 | &#tetName { 284 | color: $tetOrange !important; 285 | span { 286 | color: inherit !important; 287 | }; 288 | }; 289 | .tet-svg { 290 | fill: $tetOrange; 291 | }; 292 | }; 293 | 294 | /* green */ 295 | .r-zx61xx { 296 | background-color: $tetGreenH; 297 | } 298 | 299 | .r-5ctkeg { 300 | border-color: $tetGreen !important; 301 | } 302 | .r-nw8l94 { 303 | color: $tetGreen; 304 | &#tetName { 305 | color: $tetGreen !important; 306 | span { 307 | color: inherit !important; 308 | }; 309 | }; 310 | .tet-svg { 311 | fill: $tetGreen; 312 | }; 313 | }; 314 | /* Twitter Dim */ 315 | .r-yfoy6g { 316 | background-color: rgb(21, 32, 43); 317 | }; 318 | /* Twitter Default / White */ 319 | .r-14lw9ot { 320 | background-color: $twWhite; 321 | }; 322 | /* Twitter Dark / Black */ 323 | .r-kemksi { 324 | background-color: $twBlack; 325 | }; 326 | /* black */ 327 | .r-18jsvk2 { 328 | color: rgb(15, 20, 25) !important; 329 | }; 330 | 331 | .tweetdeck:not(.tetswitch) { 332 | background-color: $td_blue; 333 | color: #fff; 334 | &#tetName { 335 | color: $td_blue; 336 | span { 337 | color: inherit !important; 338 | }; 339 | }; 340 | .tet-svg { 341 | fill: $td_blue; 342 | }; 343 | }; 344 | 345 | .r-demo { 346 | border-style: solid !important; 347 | border-radius: 16px !important; 348 | border-width: 1px !important; 349 | }; 350 | .r-jwli3a { 351 | color: $twWhite !important; 352 | }; 353 | 354 | .tetNitterHover { 355 | background-color: $fg_dark; 356 | }; 357 | .tetNitter { 358 | border-color: $accent_light !important; 359 | box-shadow: $accent_lightB !important; 360 | }; 361 | .btNav:not(#tetNT) { 362 | .tet-icon-info.nitter, 363 | .tetBtn.nitter { 364 | color: $twWhite; 365 | background-color: $fg_dark; 366 | }; 367 | }; 368 | h1.tetNTextColor { 369 | color: $grey; 370 | }; 371 | .nitter:not(.tetswitch,.tetBtn) { 372 | border-color: $fg_dark; 373 | background-color: $bg_color; 374 | div#tetName span { 375 | color: $fg_dark; 376 | }; 377 | }; 378 | input.tetNTextColor, 379 | select.tetNTextColor, 380 | div.tetNTextColor, 381 | svg.tetNTextColor, 382 | label.tetNTextColor>span { 383 | color: $fg_color; 384 | }; 385 | .tetNText, 386 | .tetNText span { 387 | color: $fg_dark !important; 388 | }; 389 | .tetNBackground { 390 | background-color: $bg_panel; 391 | }; 392 | #tetNI { 393 | color: rgb(255, 255, 255); 394 | }; 395 | 396 | #tetAvatar { 397 | background-color: rgba(0, 0, 0, 0); 398 | }; 399 | 400 | .tet-st0 { 401 | fill:#EA4335; 402 | } 403 | .tet-st1 { 404 | fill:#4285F4; 405 | } 406 | .tet-st2 { 407 | fill:#34A853; 408 | } 409 | .tet-st3 { 410 | fill:#FBBC05; 411 | } 412 | -------------------------------------------------------------------------------- /tools/userscript.mjs: -------------------------------------------------------------------------------- 1 | import dotenv from 'dotenv'; 2 | import { access, constants, readFile, writeFile } from 'fs/promises'; 3 | import watch from 'node-watch'; 4 | 5 | // const result = dotenv.config({ path: './src/UserJS/.env' }); 6 | 7 | /** Source Directories */ 8 | const sDir = { 9 | head: './src/UserJS/header.js', 10 | body: './src/UserJS/main.js' 11 | }; 12 | /** Dest Directories */ 13 | const dDir = { 14 | dev: './build/UserJS', 15 | public: './dist/UserJS' 16 | }; 17 | /** UserJS \@grant 18 | * 19 | * \/\/@grant [permission] 20 | */ 21 | const ujsGrant = [ 22 | 'navigator.userAgent', 23 | 'document.cookie', 24 | 'GM_getValue', 25 | 'GM_setValue', 26 | 'GM_info', 27 | 'GM_openInTab', 28 | 'GM_xmlhttpRequest' 29 | ]; 30 | /** UserJS \@resource 31 | * 32 | * \/\/@resource [name] [URL] 33 | */ 34 | const ujsRes = {}; 35 | /** Watch Directories */ 36 | const watcher = watch(['./src/Common/sass/', './src/UserJS/'], { 37 | recursive: true, 38 | delay: 2000, 39 | filter: /\.(js|[s]css)$/ 40 | }); 41 | /** 42 | * setTimeout w/ Promise 43 | * @param {number} ms - Timeout in milliseconds (ms) 44 | * @returns {Promise} Promise object 45 | */ 46 | const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); 47 | /** 48 | * Object is Null 49 | * @param {Object} obj - Object 50 | * @returns {boolean} Returns if statement true or false 51 | */ 52 | const isNull = (obj) => { 53 | return Object.is(obj, null) || Object.is(obj, undefined); 54 | }; 55 | /** 56 | * Object is Blank 57 | * @param {(Object|Object[]|string)} obj - Array, Set, Object or String 58 | * @returns {boolean} Returns if statement true or false 59 | */ 60 | const isBlank = (obj) => { 61 | return ( 62 | (typeof obj === 'string' && Object.is(obj.trim(), '')) || 63 | (obj instanceof Set && Object.is(obj.size, 0)) || 64 | (Array.isArray(obj) && Object.is(obj.length, 0)) || 65 | (obj instanceof Object && 66 | typeof obj.entries !== 'function' && 67 | Object.is(Object.keys(obj).length, 0)) 68 | ); 69 | }; 70 | /** 71 | * Object is Empty 72 | * @param {(Object|Object[]|string)} obj - Array, object or string 73 | * @returns {boolean} Returns if statement true or false 74 | */ 75 | const isEmpty = (obj) => { 76 | return isNull(obj) || isBlank(obj); 77 | }; 78 | const canAccess = (filePath, encoding = 'utf-8') => { 79 | return new Promise((resolve, reject) => { 80 | access(filePath, constants.R_OK | constants.W_OK).then((testAccess) => { 81 | if (isNull(testAccess)) { 82 | resolve(readFile(filePath, encoding).then((data) => data.toString())); 83 | } 84 | reject({ 85 | msg: `Cannot access provided filePath: ${filePath}` 86 | }); 87 | }); 88 | }); 89 | }; 90 | const fileToJSON = async (filePath, encoding) => { 91 | const testAccess = await canAccess(filePath, encoding); 92 | if (typeof testAccess === 'object') { 93 | throw new Error(testAccess.msg); 94 | } 95 | return JSON.parse(testAccess); 96 | }; 97 | 98 | let result = {}; 99 | 100 | async function initUserJS(env) { 101 | try { 102 | const jsonData = await fileToJSON('./package.json', 'utf-8'); 103 | /** Build Paths */ 104 | const p = { 105 | dev: `${dDir.dev}/${jsonData.userJS.name 106 | .toLocaleLowerCase() 107 | .replaceAll(/\s/g, '')}.dev.user.js`, 108 | pub: `${dDir.public}/${jsonData.userJS.name 109 | .toLocaleLowerCase() 110 | .replaceAll(/\s/g, '')}.user.js` 111 | }; 112 | const nano = (template, data) => { 113 | // eslint-disable-next-line no-useless-escape 114 | return template.replace(/\{([\w\.]*)\}/g, (str, key) => { 115 | const keys = key.split('.'); 116 | let v = data[keys.shift()]; 117 | for (const i in keys.length) v = v[keys[i]]; 118 | return isEmpty(v) ? '' : v; 119 | }); 120 | }; 121 | const js_env = env.JS_ENV === 'development'; 122 | const outFile = js_env ? p.dev : p.pub; 123 | const formatResources = () => { 124 | const response = []; 125 | for (const [key, value] of Object.entries(ujsRes)) { 126 | response.push(`// @resource ${key} ${value}`); 127 | } 128 | return response.join('\n'); 129 | }; 130 | const buildUserJS = async () => { 131 | try { 132 | const userJSHeader = `// ==UserScript==\n// @name ${ 133 | js_env ? `[Dev] ${jsonData.userJS.name}` : jsonData.userJS.name 134 | } 135 | // @name:bg Външен преводач на Twitter 136 | // @name:zh Twitter外部翻译器 137 | // @name:zh-CN Twitter外部翻译器 138 | // @name:zh-TW Twitter外部翻译器 139 | // @name:cs Externí překladatel Twitter 140 | // @name:da Twitter ekstern oversætter 141 | // @name:et Twitteri väline tõlkija 142 | // @name:fi Twitter Ulkoinen kääntäjä 143 | // @name:el Εξωτερικός μεταφραστής Twitter 144 | // @name:hu Twitter külső fordító 145 | // @name:lv Twitter Ārējais tulkotājs 146 | // @name:lt 'Twitter' išorinis vertėjas 147 | // @name:ro Twitter Traducător extern 148 | // @name:sk Externý prekladateľ Twitter 149 | // @name:sl Twitter Zunanji prevajalec 150 | // @name:sv Twitter Extern översättare 151 | // @name:nl Twitter Externe Vertaler 152 | // @name:fr Traducteur externe Twitter 153 | // @name:de Externer Twitter-Übersetzer 154 | // @name:it Traduttore esterno di Twitter 155 | // @name:ja ツイッター外部翻訳者 156 | // @name:pl Zewnętrzny tłumacz Twittera 157 | // @name:pt Tradutor externo do Twitter 158 | // @name:pt-BR Tradutor externo do Twitter 159 | // @name:ru-RU Twitter Внешний переводчик 160 | // @name:ru Twitter Внешний переводчик 161 | // @name:es Traductor externo de Twitter 162 | // @description ${jsonData.description} 163 | // @description:zh 将第三方翻译添加到推特 164 | // @description:zh-CN 将第三方翻译添加到推特 165 | // @description:zh-TW 將第三方翻譯添加到推特 166 | // @description:bg Добавя преводачи на трети страни в Twitter 167 | // @description:cs Přidává překladatele třetích stran na Twitter 168 | // @description:da Tilføjer tredjepartsoversættere til Twitter 169 | // @description:et Lisab kolmanda osapoole tõlkijad Twitterisse 170 | // @description:fi Lisää kolmannen osapuolen kääntäjiä Twitteriin 171 | // @description:el Προσθέτει μεταφραστές 3ου μέρους στο Twitter 172 | // @description:hu Hozzáadja a 3. féltől származó fordítókat a Twitterhez 173 | // @description:lv Pievieno trešās puses tulkotājus Twitter 174 | // @description:lt Prideda trečiųjų šalių vertėjus į 'Twitter 175 | // @description:ro Adaugă traducători de la terțe părți la Twitter 176 | // @description:sk Pridáva prekladateľov tretích strán na Twitter 177 | // @description:sl Dodaja prevajalce tretjih oseb na Twitterju 178 | // @description:sv Lägger till översättare från tredje part till Twitter 179 | // @description:nl Voegt vertalers van derden toe aan Twitter 180 | // @description:fr Ajout de traducteurs tiers à Twitter 181 | // @description:de Fügt Drittanbieter-Übersetzer zu Twitter hinzu 182 | // @description:it Aggiunge traduttori di terze parti a Twitter 183 | // @description:pl Dodaje tłumaczy innych firm do Twittera 184 | // @description:pt Adiciona tradutores de terceiros ao Twitter 185 | // @description:pt-BR Adiciona tradutores de terceiros ao Twitter 186 | // @description:ja サードパーティの翻訳者をツイッターに追加 187 | // @description:ru-RU Добавляет сторонних переводчиков в Twitter 188 | // @description:ru Добавляет сторонних переводчиков в Twitter 189 | // @description:es Añade traductores de terceros a Twitter 190 | // @author ${jsonData.author} 191 | // @version ${js_env ? Number(new Date()) : jsonData.userJS.version} 192 | // @icon ${jsonData.userJS.icon} 193 | // @downloadURL ${js_env ? `https://localhost:8080/${p.dev}` : jsonData.userJS.url} 194 | // @updateURL ${js_env ? `https://localhost:8080/${p.dev}` : jsonData.userJS.url} 195 | // @namespace ${jsonData.userJS.homepage} 196 | // @homepageURL ${jsonData.userJS.homepage} 197 | // @supportURL ${jsonData.userJS.bugs} 198 | // @license ${jsonData.license} 199 | // @connect * 200 | // @match https://mobile.x.com/* 201 | // @match https://x.com/* 202 | // @match https://mobile.twitter.com/* 203 | // @match https://twitter.com/* 204 | // @match https://tweetdeck.twitter.com/* 205 | // @match https://www.twitlonger.com/show/* 206 | // @match https://nitter.*/* 207 | // @match https://nitter.*.*/* 208 | // @match https://nitter.lacontrevoie.fr/* 209 | // @match https://nitter.fdn.fr/ 210 | // @match https://nitter.kavin.rocks/* 211 | // @match https://nitter.moomoo.me/* 212 | // @match https://nitter.weiler.rocks/* 213 | // @match https://nitter.nl/* 214 | // @match https://nitter.esmailelbob.xyz/* 215 | // @match https://nitter.tiekoetter.com/* 216 | // @match https://nitter.poast.org/* 217 | // @match https://nitter.privacydev.net/* 218 | // @match https://nitter.projectsegfau.lt/* 219 | // @match https://nitter.in.projectsegfau.lt/* 220 | // @match https://canada.unofficialbird.com/* 221 | // @match https://nederland.unofficialbird.com/* 222 | // @match https://n.sneed.network/* 223 | // @match https://nitter.caioalonso.com/* 224 | // @match https://nitter.nicfab.eu/* 225 | // @match https://nitter.hostux.net/* 226 | // @match https://nitter.kling.gg/* 227 | // @match https://nitter.onthescent.xyz/* 228 | // @match https://nitter.oksocial.net/* 229 | // @match https://nitter.datura.network/* 230 | // @match https://nitter.catsarch.com/* 231 | // @exclude https://twitter.com/login 232 | // @exclude https://twitter.com/signup 233 | // @exclude https://twitter.com/i/flow/login 234 | // @exclude https://twitter.com/i/flow/signup 235 | // @exclude https://twitter.com/teams/* 236 | // @exclude https://twitter.com/*/authorize?* 237 | // @exclude https://twitter.com/*/begin_password_reset 238 | // @exclude https://twitter.com/account/* 239 | // @exclude https://mobile.twitter.com/i/flow/login 240 | // @exclude https://mobile.twitter.com/i/flow/signup 241 | // @exclude https://nitter.com${ 242 | isBlank(ujsGrant) 243 | ? '' 244 | : `\n${ujsGrant.map((param) => `// @grant ${param}`).join('\n')}` 245 | }${isBlank(ujsRes) ? '' : `\n${formatResources()}`} 246 | // @compatible chrome 247 | // @compatible firefox 248 | // @compatible edge 249 | // @compatible opera 250 | // @compatible safari 251 | // @noframes 252 | // @run-at document-start 253 | // ==/UserScript==`; 254 | const headerFile = await canAccess(sDir.head); 255 | const mainFile = await canAccess(sDir.body); 256 | const foreign = await canAccess('./dist/css/foreign.css'); 257 | const nitterCSS = await canAccess('./dist/css/useSiteColors.css'); 258 | const tetCSS = await canAccess('./dist/css/twittertranslator.css'); 259 | const lngList = await canAccess('./src/languages.js'); 260 | const wfConfig = nano(headerFile, { 261 | jshead: userJSHeader, 262 | foreign: foreign, 263 | tetCSS: tetCSS, 264 | nitterCSS: nitterCSS, 265 | languages: lngList, 266 | debugToggle: js_env.toString(), 267 | code: mainFile 268 | }); 269 | await writeFile(outFile, wfConfig); 270 | const dateOptions = { 271 | hour: 'numeric', 272 | minute: 'numeric', 273 | second: 'numeric', 274 | fractionalSecondDigits: 3 275 | }; 276 | log('Build:', { 277 | path: outFile, 278 | time: new Intl.DateTimeFormat('default', dateOptions).format(new Date(Date.now())) 279 | }); 280 | } catch (ex) { 281 | err(ex); 282 | } 283 | }; 284 | 285 | //#region Start Process 286 | log(`Node ENV: ${env.JS_ENV}`); 287 | 288 | if (js_env) { 289 | watcher.on('change', buildUserJS); 290 | watcher.on('error', (ex) => { 291 | err(ex); 292 | watcher.close(); 293 | delay(5000).then(buildUserJS); 294 | }); 295 | watcher.on('ready', buildUserJS); 296 | return; 297 | } 298 | await buildUserJS(); 299 | process.exit(0); 300 | //#endregion 301 | } catch (ex) { 302 | err(ex); 303 | } 304 | } 305 | 306 | try { 307 | if (isEmpty(process.env.JS_ENV)) { 308 | result = dotenv.config({ path: './src/UserJS/.env' }); 309 | } else { 310 | result = dotenv.config({ path: './dist/UserJS/.env' }); 311 | }; 312 | if (result.error) { 313 | throw result.error; 314 | } 315 | if (isNull(result.parsed.JS_ENV)) { 316 | dotenv.populate( 317 | result.parsed, 318 | { 319 | JS_ENV: 'development' 320 | }, 321 | { override: true, debug: true } 322 | ); 323 | } 324 | initUserJS(result.parsed); 325 | } catch (ex) { 326 | err(ex); 327 | } 328 | 329 | function log(...msg) { 330 | console.log('[UserJS]', ...msg); 331 | } 332 | 333 | function err(...msg) { 334 | console.error('[UserJS] ERROR', ...msg); 335 | } 336 | -------------------------------------------------------------------------------- /src/menu.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

${languages.en.quest.head}

4 |
${languages.en.quest.body}
5 |
6 |
${languages.en.quest.yes}
7 |
8 |
9 |
${languages.en.quest.no}
10 |
11 |
12 |
13 |
14 | ${tetInfo.name} Settings 15 | v${tetInfo.version} 16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
${tetInfo.name}@for_lollipops
26 |
27 |
${!checkSupport ? 'ERROR Unable to resolve GM_ or GM. objects' : defaultDesc}
28 |
29 |
30 |
31 |
32 |
${languages.en.lg}
33 | 59 |
60 |
61 |
${languages.en.tr}
62 | 83 |
84 |
85 |
${languages.en.ds}
86 | 91 |
92 |
93 |
${languages.en.col}
94 | 108 |
109 |
110 |
${languages.en.th}
111 | 123 |
124 | 125 |
126 |
Version
127 | 131 |
132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 |
Defaults
141 |
142 |
143 |
144 |
145 |
146 | Advanced Config 147 | 148 |
149 |
150 |
151 |
Delay Injection
152 | 165 |
166 |
167 | 174 |
175 |
176 | 183 |
184 |
Fetch Latest Nitter Instances
185 |
186 |
187 |
188 |
189 | 190 |
191 |
192 | ? 193 |
194 | Visit GitHub ⤴ 195 |
196 |
197 | -------------------------------------------------------------------------------- /dist/css/twittertranslator.css: -------------------------------------------------------------------------------- 1 | .r-1bih22f{box-shadow:rgb(29, 161, 242) 0px 0px 0px 1px}.r-1cqwhho{box-shadow:rgb(23, 191, 99) 0px 0px 0px 1px}.r-b8m25f{box-shadow:rgb(244, 93, 34) 0px 0px 0px 1px}.r-11mmphe{box-shadow:rgb(121, 75, 196) 0px 0px 0px 1px}.r-jd07pc{box-shadow:rgb(224, 36, 94) 0px 0px 0px 1px}.r-cdj8wb{box-shadow:rgb(255, 173, 31) 0px 0px 0px 1px}.tet-29u:not(.tetswitch){background-color:rgb(29, 155, 240)}.tet-186u:not(.tetswitch){background-color:rgb(0, 186, 124)}.tet-122u:not(.tetswitch){background-color:rgb(255, 122, 0)}.tet-120u:not(.tetswitch){background-color:rgb(120, 86, 255)}.tet-249u:not(.tetswitch){background-color:rgb(249, 24, 128)}.tet-255u:not(.tetswitch){background-color:rgb(255, 212, 0)}.tetswitch.tet-29u>input:checked+label{background-color:rgba(26,145,218,.384)}.tetswitch.tet-29u>input:checked+label:before{background-color:#1d9bf0}.tetswitch.tet-186u>input:checked+label{background-color:rgba(21,172,89,.384)}.tetswitch.tet-186u>input:checked+label:before{background-color:#00ba7c}.tetswitch.tet-122u>input:checked+label{background-color:rgba(220,84,31,.384)}.tetswitch.tet-122u>input:checked+label:before{background-color:#ff7a00}.tetswitch.tet-120u>input:checked+label{background-color:rgba(134,93,202,.384)}.tetswitch.tet-120u>input:checked+label:before{background-color:#7856ff}.tetswitch.tet-249u>input:checked+label{background-color:rgba(202,32,85,.384)}.tetswitch.tet-249u>input:checked+label:before{background-color:#f91880}.tetswitch.tet-255u>input:checked+label{background-color:rgba(230,156,28,.384)}.tetswitch.tet-255u>input:checked+label:before{background-color:#ffd400}.tetswitch.nitter>input:checked+label{background-color:rgba(255,108,96,.384)}.tetswitch.nitter>input:checked+label:before{background-color:#ff6c60}.tetswitch.tweetdeck>input:checked+label{background-color:rgba(29,161,242,.384)}.tetswitch.tweetdeck>input:checked+label:before{background-color:#1da1f2}#tetReset,#tetMenuButton>span{color:#fff !important}#tetSelector>select{background-color:rgba(0,0,0,0);border:rgba(0,0,0,0)}#tetSelector>select:focus{box-shadow:none !important}.navbackground.d1tet{background-color:rgba(91,112,131,.4)}.navbackground.d2tet{background-color:rgba(0,0,0,.4)}.navbackground.d3tet{background-color:rgba(91,112,131,.4)}.tet-header>span:last-child,.tet-at>span:last-child{color:#6e767d}.r-demo,.tet-help-container,#apifield,#tetSelector{border-color:rgba(0,0,0,0)}.r-demo.r-14lw9ot,.tet-help-container.r-14lw9ot,#apifield.r-14lw9ot,#tetSelector.r-14lw9ot{border-color:#536471}.r-demo.r-yfoy6g,.tet-help-container.r-yfoy6g,#apifield.r-yfoy6g,#tetSelector.r-yfoy6g{border-color:#38444d}.r-demo.nitter,.r-demo.r-tetTD,.r-demo.r-kemksi,.tet-help-container.nitter,.tet-help-container.r-tetTD,.tet-help-container.r-kemksi,#apifield.nitter,#apifield.r-tetTD,#apifield.r-kemksi,#tetSelector.nitter,#tetSelector.r-tetTD,#tetSelector.r-kemksi{border-color:#2f3336}.r-14lw9ot>div#tetName span{color:#536471}.r-kemksi>div#tetName span,.r-yfoy6g>div#tetName span{color:#6e767d}.tetBtn.nitter{border:rgba(0,0,0,0)}.Button--primary{border-color:#1da1f2;box-shadow:#1da1f2 0px 0px 0px 1px}.r-tetTD{border-radius:14px;background-color:#15202b}.r-tetTD#tetSelector.Button--primary:hover{border-color:#1da1f2;box-shadow:#1da1f2 0px 0px 0px 1px}.r-tetTD#tetSelector.Button--primary:hover #tetName span{color:#1da1f2}.r-tetTD #tetName span{color:#8899a6}.prf-header>div>.tet.tet-td{color:#fff !important}.tet-td{color:#8899a6}.tet-td#tetName{color:#1da1f2 !important}.tet-td#tetName span{color:inherit !important}.tet-td .tet-svg{fill:#1da1f2}.tet-border-black{border-color:#000}.r-9ilb82{color:#6e767d}.r-1kqtdi0{border-color:#2f3336}.r-p1n3y5{border-color:#1d9bf0 !important}.r-1q3imqu{background-color:#1a91da}.r-13gxpu9{color:#1d9bf0}.r-13gxpu9#tetName{color:#1d9bf0 !important}.r-13gxpu9#tetName span{color:inherit !important}.r-13gxpu9 .tet-svg{fill:#1d9bf0}.r-v6khid{border-color:#ffd400 !important}.r-61mi1v{color:#ffd400}.r-61mi1v#tetName{color:#ffd400 !important}.r-61mi1v#tetName span{color:inherit !important}.r-61mi1v .tet-svg{fill:#ffd400}.r-1kplyi6{background-color:#e69c1c}.r-1iofnty{border-color:#f91880 !important}.r-daml9f{color:#f91880}.r-daml9f#tetName{color:#f91880 !important}.r-daml9f#tetName span{color:inherit !important}.r-daml9f .tet-svg{fill:#f91880}.r-1ucxkr8{background-color:#ca2055}.r-njt2r9{background-color:#865dca}.r-hy56xe{border-color:#7856ff !important}.r-xfsgu1{color:#7856ff}.r-xfsgu1#tetName{color:#7856ff !important}.r-xfsgu1#tetName span{color:inherit !important}.r-xfsgu1 .tet-svg{fill:#7856ff}.tet-122hu{background-color:#dc541f}.r-1xl5njo{border-color:#ff7a00 !important}.r-1qkqhnw{color:#ff7a00}.r-1qkqhnw#tetName{color:#ff7a00 !important}.r-1qkqhnw#tetName span{color:inherit !important}.r-1qkqhnw .tet-svg{fill:#ff7a00}.r-zx61xx{background-color:#15ac59}.r-5ctkeg{border-color:#00ba7c !important}.r-nw8l94{color:#00ba7c}.r-nw8l94#tetName{color:#00ba7c !important}.r-nw8l94#tetName span{color:inherit !important}.r-nw8l94 .tet-svg{fill:#00ba7c}.r-yfoy6g{background-color:#15202b}.r-14lw9ot{background-color:#fff}.r-kemksi{background-color:#000}.r-18jsvk2{color:#0f1419 !important}.tweetdeck:not(.tetswitch){background-color:#1da1f2;color:#fff}.tweetdeck:not(.tetswitch)#tetName{color:#1da1f2}.tweetdeck:not(.tetswitch)#tetName span{color:inherit !important}.tweetdeck:not(.tetswitch) .tet-svg{fill:#1da1f2}.r-demo{border-style:solid !important;border-radius:16px !important;border-width:1px !important}.r-jwli3a{color:#fff !important}.tetNitterHover{background-color:#ff6c60}.tetNitter{border-color:#ffaca0 !important;box-shadow:#ffaca0 0px 0px 0px 1px !important}.btNav:not(#tetNT) .tet-icon-info.nitter,.btNav:not(#tetNT) .tetBtn.nitter{color:#fff;background-color:#ff6c60}h1.tetNTextColor{color:#888889}.nitter:not(.tetswitch,.tetBtn){border-color:#ff6c60;background-color:#0f0f0f}.nitter:not(.tetswitch,.tetBtn) div#tetName span{color:#ff6c60}input.tetNTextColor,select.tetNTextColor,div.tetNTextColor,svg.tetNTextColor,label.tetNTextColor>span{color:#f8f8f2}.tetNText,.tetNText span{color:#ff6c60 !important}.tetNBackground{background-color:#161616}#tetNI{color:#fff}#tetAvatar{background-color:rgba(0,0,0,0)}.tet-st0{fill:#ea4335}.tet-st1{fill:#4285f4}.tet-st2{fill:#34a853}.tet-st3{fill:#fbbc05}.tet-flex,.btNav,#tetadvanced,#tetadvanced>.tetBackground,.tet-txt,.r-demo,.tet-main{position:relative;display:flex;align-items:stretch;box-sizing:border-box;flex-direction:column}.btNav,.txt-header,.tet-av,.tetAlertBtns>div{align-items:center !important}#tetName,.r-demo,#tetadvanced,.tetAlertTxt,.tet-header{cursor:default}.txt-header,.tetAlertBtns,.r-demo,.tet-av,.r-hover,[id=apifield]{outline-style:none !important}.tet-dc,.tet-at,div.tetAlertTxt,.tet-info,.btNav label,.tetAlertBtns>div,#tetSelector>select{font-size:15px !important}.tet-at>span:first-child,h1.tetAlertTxt,.tetAlertBtns>div{font-weight:700 !important}.tet,#tetDemo,.tet-dc,.tet-at,.tethelper-info,div.tetAlertTxt,.tet-info,.tet-icon-info,#tweet-text,#tetSelector>#tetName{font-weight:400}.tet,#tetDemo,.tetswitch>label,#tetSelector>#tetName{line-height:16px}.tetAlertBtns>div>span,#tetMenuButton>svg,.txt-header,.tetadvanced-icon,.tet-at{max-width:100%}.tet-at{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tet-dc,.tet-at,.tet-header,#tetSelector>#tetName,#tetSelector>select{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}.tet,#tweet-text,.tetAlertBtns>div,.tet-main{font-family:"TwitterChirp",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}div.tetAlertTxt,.tet-info,.tet-dc,.tet-at,.tethelper-info,.tetAlertBtns>div,#tetSelector>select{line-height:20px}.tetAvatarFrame,#tetAvatar,.tet-main,.tet-containter,.tet-av,div.tetAlertTxt{width:100%}.tetAvatarFrame,#tetAvatar{align-items:stretch;border:0px solid #000;box-sizing:border-box;display:flex;flex-direction:column;margin:0px;min-height:0px;min-width:0px;padding:0px}#tetSelector{min-width:0px;overflow-wrap:break-word}#tetSelector #tetName{position:absolute;min-width:inherit;overflow-wrap:inherit}.tet,.tet-info,#tweet-text{margin-top:1% !important}#tweet-text,.tet-demoframe{position:relative}.tet-header,.tet-icon-container,.tetadvanced-icon-container,.tetAlertBtns>div,.tetAlertTxt{text-align:center}.tet-help-container a,.tet-icon-container,#tetDemo,.tet{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.tet{flex-wrap:wrap;font-size:13px;overflow-wrap:break-word;height:-webkit-min-content;height:-moz-min-content;height:min-content;display:flex;-webkit-user-select:none !important;-moz-user-select:none !important;-ms-user-select:none !important;user-select:none !important}.tetAvatarFrame{padding-bottom:100%;position:absolute;top:0px;right:0px;left:0px;bottom:0px}.tetAvatarFrame #tetAvatar{background-size:cover;background-repeat:no-repeat;background-position:center center;z-index:-1;height:100%;position:absolute}.tet-main{padding:0px 32px 32px 32px !important;display:flex;flex-direction:column}.tet-header{min-width:0px;white-space:normal;display:grid;padding:0px 32px;margin:32px 0px 12px 0px}.tet-header .tet-info-name{line-height:28px;font-size:23px;font-weight:800}.tetConfirmation{padding:8px 32px 16px 32px !important;border-radius:16px;top:50%;left:50%;transform:translate(-50%, -50%);position:fixed !important;z-index:10000 !important}.tetConfirmation .tetAlertTxt{align-content:center;display:grid;margin:0px !important}.tetConfirmation h1.tetAlertTxt{line-height:24px;font-size:20px;min-width:0px}.tetConfirmation div.tetAlertTxt{min-width:0px}.tetConfirmation .tetAlertBtns{margin:2% 0px 2% 0px;white-space:nowrap;transition-property:background-color,box-shadow;transition-duration:.2s;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-color:rgba(0,0,0,0);overflow:hidden;border-width:1px;border-style:solid}.tetConfirmation .tetAlertBtns span{line-height:inherit !important;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border:0px solid #000;box-sizing:border-box;display:inline;margin:0px;padding:0px}.tetConfirmation .tetAlertBtns span>span{border:0px solid #000;box-sizing:border-box;display:inline;margin:0px;padding:0px}#tetadvanced{border-radius:16px}#tetadvanced>div{border-radius:16px;flex-grow:1;flex-shrink:1}.btNav:not(.mobile) [id=tetForm]{min-width:600px !important}[id=tetForm]{border-radius:16px;flex-shrink:1;position:relative;overflow:hidden}[id=tetForm] .tet-containter.tet-fg{margin-left:auto;margin-right:auto}#tetadvanced{max-width:90vw;max-height:90vh;min-width:500px;min-height:100px;flex-shrink:1;margin-left:1%;margin-right:1%}.tet-container{overflow:auto !important}.tetadvanced-container section.tetcheckbox>label,.tetadvanced-container section.tetselect{display:flex;justify-content:space-between;padding:.5em}.tetadvanced-container section.tetcheckbox>label{cursor:pointer}.tetadvanced-container .tetswitch{position:relative;width:38px;border-radius:20px;-webkit-user-select:none !important;-moz-user-select:none !important;-ms-user-select:none !important;user-select:none !important;margin:5px}.tetadvanced-container .tetswitch>input{display:none}.tetadvanced-container .tetswitch>label{display:block;overflow:hidden;cursor:pointer;height:16px;padding:0;border-radius:20px;border:1px solid #000;background-color:#464646}.tetadvanced-container .tetswitch>label:before{content:"";display:block;width:20px;height:20px;margin:-2px;background:#dadce0;position:absolute;top:0;right:20px;border-radius:20px}.tetadvanced-container .tetswitch>input:checked+label{margin-left:0}.tetadvanced-container .tetswitch>input:checked+label:before{right:0px}.btNav span,#tweet-text span,#tetMenuButton span{color:inherit;font:inherit;font-family:"TwitterChirp",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif !important;white-space:inherit;overflow-wrap:break-word}.rm,#tetMenuButton.mobile,option[disabled=""],div:not(.mini)>#tetSVG,div.mini>span{display:none !important;visibility:hidden !important}.tetFreeze{overflow:hidden !important;-ms-scroll-chaining:none !important;overscroll-behavior:none !important}#tetMenuButton{z-index:10;width:8vw;height:auto;position:fixed;top:65%;left:0px}#tetMenuButton.tetTD{left:90% !important;top:0% !important}#tetMenuButton>svg{position:relative;height:1.25em;fill:currentcolor;margin-right:12px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;right:35% !important}.tetBtn{list-style:none;text-align:inherit;text-decoration:none;border-radius:15px;justify-content:center;text-align:center;display:flex !important;font-family:inherit !important;font-size:20px !important;font-weight:bold !important;padding:0px !important;outline:none !important}.tetBtn.mini{border:rgba(0,0,0,0) !important;background:rgba(0,0,0,0) !important}.tetBtn,[id=tet],.tet{cursor:pointer !important}.tet.tet-td{display:inherit;font-size:inherit !important;font-weight:inherit !important;line-height:inherit !important;padding-bottom:4px !important}[id=tet]{justify-items:center}[id=apifield]{width:auto !important;margin:2% 6% 0px 6% !important}[id=apifield],#tetName,#tetSelector>select{padding-left:2% !important}[id=apifield],#tetSelector{align-items:stretch;display:grid;border-style:solid;border-radius:4px;border-width:1px}.tet-main #tetSelector,section.tetcheckbox{margin:2% 6% 0px 6%}#tetSelector>select{text-align:left;padding-top:12px;padding-right:0px;padding-bottom:0px;cursor:pointer;border-radius:0px;margin:0px;-webkit-appearance:none;-moz-appearance:none;appearance:none}[id=tetReset]{margin:2% 25% 0px 25%}.r-demo{margin:0px 32px 0px 32px !important;padding:12px 0px 12px 0px !important;overflow:hidden;flex-direction:row !important}.r-demo .tet-av{position:relative;margin:2px 12px 0px 12px !important;flex-basis:48px;height:48px;overflow:hidden;display:block;z-index:0}.r-demo .tet-av svg{fill:currentColor}.r-demo .tet-txt{flex-basis:0px;flex-grow:1;justify-content:center}.r-demo .tet-txt .txt-header{display:flex;margin-bottom:2px;justify-content:space-between;flex-direction:row;flex-shrink:1}.r-demo .tet-txt .txt-header .tet-at{display:flex;min-width:0px;max-width:inherit !important;white-space:normal !important}.r-demo .tet-txt .txt-header .tet-at>span:last-child{margin-left:4px}#tetDemo{margin:4px 0px 0px 0px;font-size:13px;flex-wrap:wrap;min-width:0px;display:flex !important}.btNav{-webkit-user-select:none !important;-moz-user-select:none !important;-ms-user-select:none !important;user-select:none !important;justify-content:center !important;flex-direction:row !important;top:0px !important}.btNav a,.btNav :link{text-decoration:none !important}.btNav a:hover,.btNav :link:hover{text-decoration:none !important}.btNav,.navbackground{position:fixed !important;width:100vw;height:100vh}.navbackground{top:0;left:0}.navbackground.warn{z-index:10 !important}.tet-icon-container,.tetadvanced-icon-container{cursor:pointer;display:inline-flex;position:absolute;bottom:10px;border-radius:9999px;z-index:1}.tet-icon-container{height:35px;right:25px}.tet-icon-container .tet-icon-info{color:#fff;display:inline;width:35px;height:35px;line-height:35px;border-radius:inherit;font-family:"fontello";font-size:23px}.tet-icon-container .tet-icon-info:hover{color:unset !important}.tet-icon-container .tet-help-container{position:static;border-style:solid;border-width:2px;border-radius:inherit;line-height:35px;font-size:16px;font-weight:normal;text-decoration:none;margin-left:10px}.tet-icon-container .tet-help-container a{display:inline-block;margin-left:10px;margin-right:10px}.tetadvanced-icon-container{left:10px;width:28px;height:28px}.tetadvanced-icon-container .tetadvanced-icon{height:1.75rem;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;position:relative;fill:currentcolor;border-radius:inherit;display:inline-block}.mini{min-height:3% !important;overflow:hidden;background:rgba(0,0,0,0);border-color:rgba(0,0,0,0)}.r-hover{-webkit-text-decoration-line:underline !important;text-decoration-line:underline !important}[id=tweet-text]{font-size:23px !important;line-height:28px !important}.tet-help-info{color:unset}#tetNI{margin:0px 10% 0px 10%}div.css-18t94o4.r-6koalj.r-1w6e6rj.r-37j5jr.r-n6v787.r-16dba41.r-1cwl3u0.r-14gqq1x.r-bcqeeo.r-qvutc0{width:-webkit-fit-content !important;width:-moz-fit-content !important;width:fit-content !important}.prf-header>div>.tet{display:inline-block !important;width:100% !important}select.tetTextColor{height:auto !important}.tet-favicon{width:1em;height:1em;padding-left:.2rem}[id=tet-ltg],[id=tet-ltgl],[id=tet-ltglg]{font-style:normal;font-family:inherit}[id=tet-ltg],[id=tet-ltglg]{font-weight:normal}[id=tet-ltg]{font-size:10.5833px;line-height:1.25;letter-spacing:0px;word-spacing:0px;white-space:pre;fill-opacity:1;stroke:none}[id=tet-ltgl]{font-variant:normal;font-weight:bold;font-stretch:normal}[id=tet-ltglg]{font-size:43.3964px;line-height:1.25;letter-spacing:0px;word-spacing:0px;fill-opacity:1;stroke:none;stroke-width:1.08492}[id=tet-ltglgp]{stroke-width:1.08492} 2 | -------------------------------------------------------------------------------- /src/Common/sass/menu.scss: -------------------------------------------------------------------------------- 1 | @import 'colors'; 2 | 3 | .tet-flex, 4 | .btNav, 5 | #tetadvanced, 6 | #tetadvanced > .tetBackground, 7 | .tet-txt, 8 | .r-demo, 9 | .tet-main { 10 | position: relative; 11 | display: flex; 12 | align-items: stretch; 13 | box-sizing: border-box; 14 | flex-direction: column; 15 | } 16 | 17 | .btNav, 18 | .txt-header, 19 | .tet-av, 20 | .tetAlertBtns > div { 21 | align-items: center !important; 22 | } 23 | 24 | #tetName, 25 | .r-demo, 26 | #tetadvanced, 27 | .tetAlertTxt, 28 | .tet-header { 29 | cursor: default; 30 | } 31 | 32 | .txt-header, 33 | .tetAlertBtns, 34 | .r-demo, 35 | .tet-av, 36 | .r-hover, 37 | [id="apifield"] { 38 | outline-style: none !important; 39 | } 40 | 41 | .tet-dc, 42 | .tet-at, 43 | div.tetAlertTxt, 44 | .tet-info, 45 | .btNav label, 46 | .tetAlertBtns > div, 47 | #tetSelector > select { 48 | font-size: 15px !important; 49 | } 50 | 51 | .tet-at > span:first-child, 52 | h1.tetAlertTxt, 53 | .tetAlertBtns > div { 54 | font-weight: 700 !important; 55 | } 56 | 57 | .tet, 58 | #tetDemo, 59 | .tet-dc, 60 | .tet-at, 61 | .tethelper-info, 62 | div.tetAlertTxt, 63 | .tet-info, 64 | .tet-icon-info, 65 | #tweet-text, 66 | #tetSelector > #tetName { 67 | font-weight: 400; 68 | } 69 | 70 | .tet, 71 | #tetDemo, 72 | .tetswitch > label, 73 | #tetSelector > #tetName { 74 | line-height: 16px; 75 | } 76 | 77 | .tetAlertBtns > div > span, 78 | #tetMenuButton > svg, 79 | .txt-header, 80 | .tetadvanced-icon, 81 | .tet-at { 82 | max-width: 100%; 83 | } 84 | 85 | .tet-at { 86 | overflow: hidden; 87 | text-overflow: ellipsis; 88 | white-space: nowrap; 89 | } 90 | 91 | .tet-dc, 92 | .tet-at, 93 | .tet-header, 94 | #tetSelector > #tetName, 95 | #tetSelector > select { 96 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; 97 | } 98 | 99 | .tet, 100 | #tweet-text, 101 | .tetAlertBtns > div, 102 | .tet-main { 103 | font-family: 104 | 'TwitterChirp', 105 | -apple-system, 106 | BlinkMacSystemFont, 107 | 'Segoe UI', 108 | Roboto, 109 | Helvetica, 110 | Arial, 111 | sans-serif; 112 | } 113 | 114 | div.tetAlertTxt, 115 | .tet-info, 116 | .tet-dc, 117 | .tet-at, 118 | .tethelper-info, 119 | .tetAlertBtns > div, 120 | #tetSelector > select { 121 | line-height: 20px; 122 | } 123 | 124 | .tetAvatarFrame, 125 | #tetAvatar, 126 | .tet-main, 127 | .tet-containter, 128 | .tet-av, 129 | div.tetAlertTxt { 130 | width: 100%; 131 | } 132 | 133 | .tetAvatarFrame, 134 | #tetAvatar { 135 | align-items: stretch; 136 | border: 0px solid black; 137 | box-sizing: border-box; 138 | display: flex; 139 | flex-direction: column; 140 | margin: 0px; 141 | min-height: 0px; 142 | min-width: 0px; 143 | padding: 0px; 144 | } 145 | 146 | #tetSelector { 147 | min-width: 0px; 148 | overflow-wrap: break-word; 149 | 150 | #tetName { 151 | position: absolute; 152 | min-width: inherit; 153 | overflow-wrap: inherit; 154 | } 155 | } 156 | 157 | .tet, 158 | .tet-info, 159 | #tweet-text { 160 | margin-top: 1% !important; 161 | } 162 | 163 | #tweet-text, 164 | .tet-demoframe { 165 | position: relative; 166 | } 167 | 168 | .tet-header, 169 | .tet-icon-container, 170 | .tetadvanced-icon-container, 171 | .tetAlertBtns > div, 172 | .tetAlertTxt { 173 | text-align: center; 174 | } 175 | 176 | .tet-help-container a, 177 | .tet-icon-container, 178 | #tetDemo, 179 | .tet { 180 | width: -webkit-fit-content; 181 | width: -moz-fit-content; 182 | width: fit-content; 183 | } 184 | 185 | .tet { 186 | flex-wrap: wrap; 187 | font-size: 13px; 188 | overflow-wrap: break-word; 189 | height: -webkit-min-content; 190 | height: -moz-min-content; 191 | height: min-content; 192 | display: flex; 193 | -webkit-user-select: none !important; 194 | -moz-user-select: none !important; 195 | -ms-user-select: none !important; 196 | user-select: none !important; 197 | } 198 | 199 | .tetAvatarFrame { 200 | padding-bottom: 100%; 201 | position: absolute; 202 | top: 0px; 203 | right: 0px; 204 | left: 0px; 205 | bottom: 0px; 206 | 207 | #tetAvatar { 208 | background-size: cover; 209 | background-repeat: no-repeat; 210 | background-position: center center; 211 | z-index: -1; 212 | height: 100%; 213 | position: absolute; 214 | } 215 | } 216 | 217 | .tet-main { 218 | padding: 0px 32px 32px 32px !important; 219 | display: flex; 220 | flex-direction: column; 221 | } 222 | 223 | .tet-header { 224 | min-width: 0px; 225 | white-space: normal; 226 | display: grid; 227 | padding: 0px 32px; 228 | margin: 32px 0px 12px 0px; 229 | 230 | .tet-info-name { 231 | line-height: 28px; 232 | font-size: 23px; 233 | font-weight: 800; 234 | } 235 | } 236 | 237 | .tetConfirmation { 238 | padding: 8px 32px 16px 32px !important; 239 | border-radius: 16px; 240 | top: 50%; 241 | left: 50%; 242 | transform: translate(-50%, -50%); 243 | position: fixed !important; 244 | z-index: 10000 !important; 245 | 246 | .tetAlertTxt { 247 | align-content: center; 248 | display: grid; 249 | margin: 0px !important; 250 | } 251 | 252 | h1.tetAlertTxt { 253 | line-height: 24px; 254 | font-size: 20px; 255 | min-width: 0px; 256 | } 257 | 258 | div.tetAlertTxt { 259 | min-width: 0px; 260 | } 261 | 262 | .tetAlertBtns { 263 | margin: 2% 0px 2% 0px; 264 | white-space: nowrap; 265 | transition-property: background-color, box-shadow; 266 | transition-duration: 0.2s; 267 | -webkit-user-select: none; 268 | -moz-user-select: none; 269 | -ms-user-select: none; 270 | user-select: none; 271 | border-color: rgba(0, 0, 0, 0); 272 | overflow: hidden; 273 | border-width: 1px; 274 | border-style: solid; 275 | 276 | span { 277 | line-height: inherit !important; 278 | overflow: hidden; 279 | text-overflow: ellipsis; 280 | white-space: nowrap; 281 | border: 0px solid black; 282 | box-sizing: border-box; 283 | display: inline; 284 | margin: 0px; 285 | padding: 0px; 286 | 287 | > span { 288 | border: 0px solid black; 289 | box-sizing: border-box; 290 | display: inline; 291 | margin: 0px; 292 | padding: 0px; 293 | } 294 | } 295 | } 296 | } 297 | 298 | #tetadvanced { 299 | border-radius: 16px; 300 | 301 | > div { 302 | border-radius: 16px; 303 | flex-grow: 1; 304 | flex-shrink: 1; 305 | } 306 | } 307 | 308 | .btNav:not(.mobile) [id="tetForm"] { 309 | min-width: 600px !important; 310 | } 311 | 312 | [id="tetForm"] { 313 | border-radius: 16px; 314 | flex-shrink: 1; 315 | position: relative; 316 | overflow: hidden; 317 | 318 | .tet-containter { 319 | &.tet-fg { 320 | margin-left: auto; 321 | margin-right: auto; 322 | } 323 | } 324 | } 325 | 326 | #tetadvanced { 327 | max-width: 90vw; 328 | max-height: 90vh; 329 | min-width: 500px; 330 | min-height: 100px; 331 | flex-shrink: 1; 332 | margin-left: 1%; 333 | margin-right: 1%; 334 | } 335 | 336 | .tet-container { 337 | overflow: auto !important; 338 | } 339 | 340 | .tetadvanced-container { 341 | section { 342 | &.tetcheckbox > label, 343 | &.tetselect { 344 | display: flex; 345 | justify-content: space-between; 346 | padding: 0.5em; 347 | } 348 | 349 | &.tetcheckbox > label { 350 | cursor: pointer; 351 | } 352 | } 353 | 354 | .tetswitch { 355 | position: relative; 356 | width: 38px; 357 | border-radius: 20px; 358 | -webkit-user-select: none !important; 359 | -moz-user-select: none !important; 360 | -ms-user-select: none !important; 361 | user-select: none !important; 362 | margin: 5px; 363 | 364 | > input { 365 | display: none; 366 | } 367 | 368 | > label { 369 | display: block; 370 | overflow: hidden; 371 | cursor: pointer; 372 | height: 16px; 373 | padding: 0; 374 | border-radius: 20px; 375 | border: 1px solid $twBlack; 376 | background-color: #464646; 377 | 378 | &:before { 379 | content: ''; 380 | display: block; 381 | width: 20px; 382 | height: 20px; 383 | margin: -2px; 384 | background: #dadce0; 385 | position: absolute; 386 | top: 0; 387 | right: 20px; 388 | border-radius: 20px; 389 | } 390 | } 391 | 392 | > input:checked + label { 393 | margin-left: 0; 394 | 395 | &:before { 396 | right: 0px; 397 | } 398 | } 399 | } 400 | } 401 | 402 | .btNav span, 403 | #tweet-text span, 404 | #tetMenuButton span { 405 | color: inherit; 406 | font: inherit; 407 | font-family: 408 | 'TwitterChirp', 409 | -apple-system, 410 | BlinkMacSystemFont, 411 | 'Segoe UI', 412 | Roboto, 413 | Helvetica, 414 | Arial, 415 | sans-serif !important; 416 | white-space: inherit; 417 | overflow-wrap: break-word; 418 | } 419 | 420 | .rm, 421 | #tetMenuButton.mobile, 422 | option[disabled=''], 423 | div:not(.mini) > #tetSVG, 424 | div.mini > span { 425 | display: none !important; 426 | visibility: hidden !important; 427 | } 428 | .tetFreeze { 429 | overflow: hidden !important; 430 | -ms-scroll-chaining: none !important; 431 | overscroll-behavior: none !important; 432 | } 433 | 434 | #tetMenuButton { 435 | z-index: 10; 436 | width: 8vw; 437 | height: auto; 438 | position: fixed; 439 | top: 65%; 440 | left: 0px; 441 | 442 | &.tetTD { 443 | left: 90% !important; 444 | top: 0% !important; 445 | } 446 | 447 | > svg { 448 | position: relative; 449 | height: 1.25em; 450 | fill: currentcolor; 451 | margin-right: 12px; 452 | -webkit-user-select: none; 453 | -moz-user-select: none; 454 | -ms-user-select: none; 455 | user-select: none; 456 | right: 35% !important; 457 | } 458 | } 459 | 460 | .tetBtn { 461 | list-style: none; 462 | text-align: inherit; 463 | text-decoration: none; 464 | border-radius: 15px; 465 | justify-content: center; 466 | text-align: center; 467 | display: flex !important; 468 | font-family: inherit !important; 469 | font-size: 20px !important; 470 | font-weight: bold !important; 471 | padding: 0px !important; 472 | outline: none !important; 473 | 474 | &.mini { 475 | border: transparent !important; 476 | background: transparent !important; 477 | } 478 | } 479 | 480 | .tetBtn, 481 | [id="tet"], 482 | .tet { 483 | cursor: pointer !important; 484 | } 485 | 486 | .tet.tet-td { 487 | display: inherit; 488 | font-size: inherit !important; 489 | font-weight: inherit !important; 490 | line-height: inherit !important; 491 | padding-bottom: 4px !important; 492 | } 493 | 494 | [id="tet"] { 495 | justify-items: center; 496 | } 497 | 498 | [id="apifield"] { 499 | width: auto !important; 500 | margin: 2% 6% 0px 6% !important; 501 | } 502 | 503 | [id="apifield"], 504 | #tetName, 505 | #tetSelector > select { 506 | padding-left: 2% !important; 507 | } 508 | 509 | [id="apifield"], 510 | #tetSelector { 511 | align-items: stretch; 512 | display: grid; 513 | border-style: solid; 514 | border-radius: 4px; 515 | border-width: 1px; 516 | } 517 | 518 | .tet-main #tetSelector, 519 | section.tetcheckbox { 520 | margin: 2% 6% 0px 6%; 521 | } 522 | 523 | #tetSelector > select { 524 | text-align: left; 525 | padding-top: 12px; 526 | padding-right: 0px; 527 | padding-bottom: 0px; 528 | cursor: pointer; 529 | border-radius: 0px; 530 | margin: 0px; 531 | -webkit-appearance: none; 532 | -moz-appearance: none; 533 | appearance: none; 534 | } 535 | 536 | [id="tetReset"] { 537 | margin: 2% 25% 0px 25%; 538 | } 539 | 540 | .r-demo { 541 | margin: 0px 32px 0px 32px !important; 542 | padding: 12px 0px 12px 0px !important; 543 | overflow: hidden; 544 | flex-direction: row !important; 545 | 546 | .tet-av { 547 | position: relative; 548 | margin: 2px 12px 0px 12px !important; 549 | flex-basis: 48px; 550 | height: 48px; 551 | overflow: hidden; 552 | display: block; 553 | z-index: 0; 554 | svg { 555 | fill: currentColor; 556 | } 557 | } 558 | 559 | .tet-txt { 560 | flex-basis: 0px; 561 | flex-grow: 1; 562 | justify-content: center; 563 | 564 | .txt-header { 565 | display: flex; 566 | margin-bottom: 2px; 567 | // align-items: start; 568 | justify-content: space-between; 569 | flex-direction: row; 570 | flex-shrink: 1; 571 | 572 | .tet-at { 573 | display: flex; 574 | min-width: 0px; 575 | max-width: inherit !important; 576 | white-space: normal !important; 577 | 578 | > span:last-child { 579 | margin-left: 4px; 580 | } 581 | } 582 | } 583 | } 584 | } 585 | 586 | #tetDemo { 587 | margin: 4px 0px 0px 0px; 588 | font-size: 13px; 589 | flex-wrap: wrap; 590 | min-width: 0px; 591 | display: flex !important; 592 | } 593 | 594 | .btNav { 595 | -webkit-user-select: none !important; 596 | -moz-user-select: none !important; 597 | -ms-user-select: none !important; 598 | user-select: none !important; 599 | a, 600 | :link { 601 | text-decoration: none !important; 602 | 603 | &:hover { 604 | text-decoration: none !important; 605 | } 606 | } 607 | justify-content: center !important; 608 | flex-direction: row !important; 609 | top: 0px !important; 610 | } 611 | 612 | .btNav, 613 | .navbackground { 614 | position: fixed !important; 615 | width: 100vw; 616 | height: 100vh; 617 | } 618 | 619 | .navbackground { 620 | top: 0; 621 | left: 0; 622 | 623 | &.warn { 624 | z-index: 10 !important; 625 | } 626 | } 627 | 628 | .tet-icon-container, 629 | .tetadvanced-icon-container { 630 | cursor: pointer; 631 | display: inline-flex; 632 | position: absolute; 633 | bottom: 10px; 634 | border-radius: 9999px; 635 | z-index: 1; 636 | } 637 | 638 | .tet-icon-container { 639 | height: 35px; 640 | right: 25px; 641 | 642 | .tet-icon-info { 643 | color: $twWhite; 644 | display: inline; 645 | width: 35px; 646 | height: 35px; 647 | line-height: 35px; 648 | border-radius: inherit; 649 | font-family: 'fontello'; 650 | font-size: 23px; 651 | 652 | &:hover { 653 | color: unset !important; 654 | } 655 | } 656 | 657 | .tet-help-container { 658 | position: static; 659 | border-style: solid; 660 | border-width: 2px; 661 | border-radius: inherit; 662 | line-height: 35px; 663 | font-size: 16px; 664 | font-weight: normal; 665 | text-decoration: none; 666 | margin-left: 10px; 667 | 668 | a { 669 | display: inline-block; 670 | margin-left: 10px; 671 | margin-right: 10px; 672 | } 673 | } 674 | } 675 | 676 | .tetadvanced-icon-container { 677 | left: 10px; 678 | width: 28px; 679 | height: 28px; 680 | 681 | .tetadvanced-icon { 682 | height: 1.75rem; 683 | cursor: pointer; 684 | -webkit-user-select: none; 685 | -moz-user-select: none; 686 | -ms-user-select: none; 687 | user-select: none; 688 | position: relative; 689 | fill: currentcolor; 690 | border-radius: inherit; 691 | display: inline-block; 692 | } 693 | } 694 | 695 | .mini { 696 | min-height: 3% !important; 697 | overflow: hidden; 698 | background: transparent; 699 | border-color: transparent; 700 | } 701 | 702 | .r-hover { 703 | -webkit-text-decoration-line: underline !important; 704 | text-decoration-line: underline !important; 705 | } 706 | 707 | [id="tweet-text"] { 708 | font-size: 23px !important; 709 | line-height: 28px !important; 710 | } 711 | 712 | .tet-help-info { 713 | color: unset; 714 | } 715 | 716 | #tetNI { 717 | margin: 0px 10% 0px 10%; 718 | } 719 | 720 | div.css-18t94o4.r-6koalj.r-1w6e6rj.r-37j5jr.r-n6v787.r-16dba41.r-1cwl3u0.r-14gqq1x.r-bcqeeo.r-qvutc0 { 721 | width: -webkit-fit-content !important; 722 | width: -moz-fit-content !important; 723 | width: fit-content !important; 724 | } 725 | 726 | .prf-header > div > .tet { 727 | display: inline-block !important; 728 | width: 100% !important; 729 | } 730 | 731 | select.tetTextColor { 732 | height: auto !important; 733 | } 734 | .tet-favicon { 735 | width: 1em; 736 | height: 1em; 737 | padding-left: 0.2rem; 738 | } 739 | 740 | [id="tet-ltg"], 741 | [id="tet-ltgl"], 742 | [id="tet-ltglg"] { 743 | font-style: normal; 744 | font-family: inherit; 745 | } 746 | 747 | [id="tet-ltg"], 748 | [id="tet-ltglg"] { 749 | font-weight: normal; 750 | } 751 | 752 | [id="tet-ltg"] { 753 | font-size: 10.5833px; 754 | line-height: 1.25; 755 | letter-spacing: 0px; 756 | word-spacing: 0px; 757 | white-space: pre; 758 | fill-opacity: 1; 759 | stroke: none; 760 | } 761 | 762 | [id="tet-ltgl"] { 763 | font-variant: normal; 764 | font-weight: bold; 765 | font-stretch: normal; 766 | } 767 | 768 | [id="tet-ltglg"] { 769 | font-size: 43.3964px; 770 | line-height: 1.25; 771 | letter-spacing: 0px; 772 | word-spacing: 0px; 773 | fill-opacity: 1; 774 | stroke: none; 775 | stroke-width: 1.08492; 776 | } 777 | [id="tet-ltglgp"] { 778 | stroke-width: 1.08492; 779 | } 780 | -------------------------------------------------------------------------------- /src/languages.js: -------------------------------------------------------------------------------- 1 | let languages = { 2 | en: { 3 | sel: `English (en)`, 4 | tw: `Translate with`, 5 | lg: `Language`, 6 | tr: `Translator`, 7 | ds: `Display`, 8 | menu: `Menu`, 9 | ao: `Auto`, 10 | th: `Theme`, 11 | df: `Default`, 12 | di: `Dim`, 13 | lo: `Lights out`, 14 | col: `Color`, 15 | cb: `Blue`, 16 | cy: `Yellow`, 17 | cr: `Red`, 18 | cp: `Purple`, 19 | co: `Orange`, 20 | cg: `Green`, 21 | t: `Text`, 22 | i: `Icon`, 23 | res: `Restore to Defaults`, 24 | l: `Loading`, 25 | quest: { 26 | head: `Are you sure?`, 27 | body: `Website will be reloaded.`, 28 | yes: `Yes`, 29 | no: `No`, 30 | }, 31 | }, 32 | zh: { 33 | sel: `中文 (zh)`, 34 | tw: `翻译与`, 35 | lg: `语种`, 36 | tr: `译者`, 37 | ds: `显示`, 38 | menu: `菜单`, 39 | ao: `自动的`, 40 | th: `主题`, 41 | df: `默认情况下`, 42 | di: `凹陷`, 43 | lo: `熄灯`, 44 | col: `颜色`, 45 | cb: `蓝色`, 46 | cy: `黄色`, 47 | cr: `红色`, 48 | cp: `紫色`, 49 | co: `橙色`, 50 | cg: `绿色`, 51 | t: `案文`, 52 | i: `图标`, 53 | res: `恢复`, 54 | l: `Loading`, 55 | quest: { 56 | head: `你确定吗?`, 57 | body: `网站将被重新加载`, 58 | yes: `是的`, 59 | no: `不确定`, 60 | }, 61 | }, 62 | bg: { 63 | sel: `Български (bg)`, 64 | tw: `Преведете с`, 65 | lg: `Език`, 66 | tr: `Преводач`, 67 | ds: `Показване на`, 68 | menu: `Меню`, 69 | ao: `Автоматичен`, 70 | th: `Тема`, 71 | df: `По подразбиране`, 72 | di: `Dim`, 73 | lo: `Изгасяне на осветлението`, 74 | col: `Цвят`, 75 | cb: `Синьо`, 76 | cy: `Жълто`, 77 | cr: `Червено`, 78 | cp: `Лилаво`, 79 | co: `Оранжево`, 80 | cg: `Зелено`, 81 | t: `Текст`, 82 | i: `Икона`, 83 | res: `Възстановявам`, 84 | l: `Loading`, 85 | quest: { 86 | head: `Сигурни ли сте?`, 87 | body: `Уебсайтът ще бъде презареден.`, 88 | yes: `Да`, 89 | no: `Не`, 90 | }, 91 | }, 92 | cs: { 93 | sel: `Česky (cs)`, 94 | tw: `Přeložit pomocí`, 95 | lg: `Jazyk`, 96 | tr: `Překladatel`, 97 | ds: `Zobrazit`, 98 | menu: `Nabídka`, 99 | ao: `Automatické`, 100 | th: `Téma`, 101 | df: `Výchozí`, 102 | di: `Dim`, 103 | lo: `Zhasnout světla`, 104 | col: `Barva`, 105 | cb: `Modrá`, 106 | cy: `Žlutá`, 107 | cr: `Červená`, 108 | cp: `Fialová`, 109 | co: `Oranžová`, 110 | cg: `Zelená`, 111 | t: `Text`, 112 | i: `Ikona`, 113 | res: `Obnovit`, 114 | l: `Loading`, 115 | quest: { 116 | head: `Jste si jistý?`, 117 | body: `Webové stránky budou znovu načteny.`, 118 | yes: `Ano`, 119 | no: `Ne`, 120 | }, 121 | }, 122 | da: { 123 | sel: `Dansk (da)`, 124 | tw: `Oversæt med`, 125 | lg: `Sprog`, 126 | tr: `Oversætter`, 127 | ds: `Vis`, 128 | menu: `Menu`, 129 | ao: `Automatisk`, 130 | th: `Tema`, 131 | df: `Standard`, 132 | di: `Dim`, 133 | lo: `Lyset slukkes`, 134 | col: `Farve`, 135 | cb: `Blå`, 136 | cy: `Gul`, 137 | cr: `Rød`, 138 | cp: `Lilla`, 139 | co: `Orange`, 140 | cg: `Grøn`, 141 | t: `Tekst`, 142 | i: `Ikon`, 143 | res: `Genskabe`, 144 | l: `Loading`, 145 | quest: { 146 | head: `Er du sikker?`, 147 | body: `Hjemmesiden vil blive genindlæst.`, 148 | yes: `Ja`, 149 | no: `Nej`, 150 | }, 151 | }, 152 | et: { 153 | sel: `Eesti (et)`, 154 | tw: `Tõlge koos`, 155 | lg: `Keel`, 156 | tr: `Tõlkija`, 157 | ds: `Kuva`, 158 | menu: `Menüü`, 159 | ao: `Automaatne`, 160 | th: `Teema`, 161 | df: `Vaikimisi`, 162 | di: `Dim`, 163 | lo: `Valgus välja lülitatud`, 164 | col: `Värv`, 165 | cb: `Sinine`, 166 | cy: `Kollane`, 167 | cr: `Punane`, 168 | cp: `Lilla`, 169 | co: `Oranž`, 170 | cg: `Roheline`, 171 | t: `Tekst`, 172 | i: `Ikoon`, 173 | res: `Taastada`, 174 | l: `Loading`, 175 | quest: { 176 | head: `Oled sa kindel?`, 177 | body: `Veebileht laaditakse uuesti.`, 178 | yes: `Jah`, 179 | no: `Ei`, 180 | }, 181 | }, 182 | fi: { 183 | sel: `Suomalainen (fi)`, 184 | tw: `Käännä kanssa`, 185 | lg: `Kieli`, 186 | tr: `Kääntäjä`, 187 | ds: `Näytä`, 188 | menu: `Valikko`, 189 | ao: `Automaattinen`, 190 | th: `Teema`, 191 | df: `Oletus`, 192 | di: `Dim`, 193 | lo: `Valot pois päältä`, 194 | col: `Väri`, 195 | cb: `Sininen`, 196 | cy: `Keltainen`, 197 | cr: `Punainen`, 198 | cp: `Violetti`, 199 | co: `Oranssi`, 200 | cg: `Vihreä`, 201 | t: `Teksti`, 202 | i: `Kuvake`, 203 | res: `Palauta`, 204 | l: `Loading`, 205 | quest: { 206 | head: `Oletko varma?`, 207 | body: `Sivusto ladataan uudelleen.`, 208 | yes: `Kyllä`, 209 | no: `Ei`, 210 | }, 211 | }, 212 | el: { 213 | sel: `Ελληνική (el)`, 214 | tw: `Μεταφράστε με`, 215 | lg: `Γλώσσα`, 216 | tr: `Μεταφραστής`, 217 | ds: `Εμφάνιση`, 218 | menu: `Μενού`, 219 | ao: `Αυτόματο`, 220 | th: `Θέμα`, 221 | df: `Προεπιλογή`, 222 | di: `Dim`, 223 | lo: `Σβήνει τα φώτα`, 224 | col: `Χρώμα`, 225 | cb: `Μπλε`, 226 | cy: `Κίτρινο`, 227 | cr: `Κόκκινο`, 228 | cp: `Μωβ`, 229 | co: `Πορτοκαλί`, 230 | cg: `Πράσινο`, 231 | t: `Κείμενο`, 232 | i: `Εικονίδιο`, 233 | res: `Επαναφορά`, 234 | l: `Loading`, 235 | quest: { 236 | head: `Είσαι σίγουρος;`, 237 | body: `Η ιστοσελίδα θα επαναφορτωθεί.`, 238 | yes: `Ναι`, 239 | no: `Όχι`, 240 | }, 241 | }, 242 | hu: { 243 | sel: `Magyar (hu)`, 244 | tw: `Fordítson a`, 245 | lg: `Nyelv`, 246 | tr: `Fordító`, 247 | ds: `Megjelenítés`, 248 | menu: `Menü`, 249 | ao: `Automatikus`, 250 | th: `Téma`, 251 | df: `Alapértelmezett`, 252 | di: `Dim`, 253 | lo: `Fények kikapcsolva`, 254 | col: `Szín`, 255 | cb: `Kék`, 256 | cy: `Sárga`, 257 | cr: `Piros`, 258 | cp: `Lila`, 259 | co: `Narancs`, 260 | cg: `Zöld`, 261 | t: `Szöveg`, 262 | i: `Ikon`, 263 | res: `Visszaállítása`, 264 | l: `Loading`, 265 | quest: { 266 | head: `Biztos vagy benne?`, 267 | body: `A weboldal újratöltődik.`, 268 | yes: `Igen`, 269 | no: `Nem`, 270 | }, 271 | }, 272 | lv: { 273 | sel: `Latviešu (lv)`, 274 | tw: `Tulkot ar`, 275 | lg: `Valoda`, 276 | tr: `Tulkotājs`, 277 | ds: `Displejs`, 278 | menu: `Izvēlne`, 279 | ao: `Automātiskais`, 280 | th: `Tēma`, 281 | df: `Noklusējuma`, 282 | di: `Dim`, 283 | lo: `Izslēgt gaismu`, 284 | col: `Krāsa`, 285 | cb: `Zils`, 286 | cy: `Dzeltens`, 287 | cr: `Sarkans`, 288 | cp: `Violeta`, 289 | co: `Oranža`, 290 | cg: `Zaļš`, 291 | t: `Teksts`, 292 | i: `Ikona`, 293 | res: `Atjaunot`, 294 | l: `Loading`, 295 | quest: { 296 | head: `Vai esat pārliecināts?`, 297 | body: `Tīmekļa vietne tiks ielādēta no jauna.`, 298 | yes: `Jā`, 299 | no: `Nē`, 300 | }, 301 | }, 302 | lt: { 303 | sel: `Lietuvių kalba (lt)`, 304 | tw: `Išversti su`, 305 | lg: `Kalba`, 306 | tr: `Vertėjas`, 307 | ds: `Rodyti`, 308 | menu: `Meniu`, 309 | ao: `Automatinis`, 310 | th: `Tema`, 311 | df: `Numatytoji`, 312 | di: `Dim`, 313 | lo: `Išjungti šviesą`, 314 | col: `Spalva`, 315 | cb: `Mėlyna`, 316 | cy: `Geltona`, 317 | cr: `Raudona`, 318 | cp: `Violetinė`, 319 | co: `Oranžinė`, 320 | cg: `Žalia`, 321 | t: `Tekstas`, 322 | i: `Ikona`, 323 | res: `Atkurti`, 324 | l: `Loading`, 325 | quest: { 326 | head: `Ar tikrai?`, 327 | body: `Svetainė bus iš naujo įkelta.`, 328 | yes: `Taip`, 329 | no: `Ne`, 330 | }, 331 | }, 332 | ro: { 333 | sel: `Românesc (ro)`, 334 | tw: `Tradu cu`, 335 | lg: `Limba`, 336 | tr: `Traducător`, 337 | ds: `Afișați`, 338 | menu: `Meniu`, 339 | ao: `Automat`, 340 | th: `Tema`, 341 | df: `Implicit`, 342 | di: `Dim`, 343 | lo: `Stinge lumina`, 344 | col: `Culoare`, 345 | cb: `Albastru`, 346 | cy: `Galben`, 347 | cr: `Roșu`, 348 | cp: `Violet`, 349 | co: `Portocaliu`, 350 | cg: `Verde`, 351 | t: `Text`, 352 | i: `Icoană`, 353 | res: `Restaurați`, 354 | l: `Loading`, 355 | quest: { 356 | head: `Ești sigur?`, 357 | body: `Site-ul va fi reîncărcat.`, 358 | yes: `Da`, 359 | no: `Nu`, 360 | }, 361 | }, 362 | sk: { 363 | sel: `Slovenská (sk)`, 364 | tw: `Preložiť s`, 365 | lg: `Jazyk`, 366 | tr: `Prekladateľ`, 367 | ds: `Zobraziť`, 368 | menu: `Ponuka`, 369 | ao: `Automatické`, 370 | th: `Téma`, 371 | df: `Predvolené nastavenie`, 372 | di: `Dim`, 373 | lo: `Zhasnuté svetlá`, 374 | col: `Farba`, 375 | cb: `Modrá`, 376 | cy: `Žltá`, 377 | cr: `Červená`, 378 | cp: `Fialová`, 379 | co: `Oranžová`, 380 | cg: `Zelená`, 381 | t: `Text`, 382 | i: `Ikona`, 383 | res: `Obnovenie`, 384 | l: `Loading`, 385 | quest: { 386 | head: `Ste si istý?`, 387 | body: `Webová stránka bude znovu načítaná.`, 388 | yes: `Áno`, 389 | no: `Nie`, 390 | }, 391 | }, 392 | sl: { 393 | sel: `Slovenski (sl)`, 394 | tw: `Prevedi z`, 395 | lg: `Jezik`, 396 | tr: `Prevajalec`, 397 | ds: `Prikaži`, 398 | menu: `Meni`, 399 | ao: `Samodejno`, 400 | th: `Tema`, 401 | df: `Privzeto`, 402 | di: `Dim`, 403 | lo: `Ugasne luči`, 404 | col: `Barva`, 405 | cb: `Modra`, 406 | cy: `Rumena`, 407 | cr: `Rdeča`, 408 | cp: `Vijolična`, 409 | co: `Oranžna`, 410 | cg: `Zelena`, 411 | t: `Besedilo`, 412 | i: `Ikona`, 413 | res: `Obnovitev`, 414 | l: `Loading`, 415 | quest: { 416 | head: `Ste prepričani?`, 417 | body: `Spletna stran bo ponovno naložena.`, 418 | yes: `Da`, 419 | no: `Ne`, 420 | }, 421 | }, 422 | sv: { 423 | sel: `Svenska (sv)`, 424 | tw: `Översätt med`, 425 | lg: `Språk`, 426 | tr: `Översättare`, 427 | ds: `Visa`, 428 | menu: `Meny`, 429 | ao: `Automatisk`, 430 | th: `Tema`, 431 | df: `Standard`, 432 | di: `Dim`, 433 | lo: `Ljuset släcks`, 434 | col: `Färg`, 435 | cb: `Blå`, 436 | cy: `Gul`, 437 | cr: `Röd`, 438 | cp: `Lila`, 439 | co: `Orange`, 440 | cg: `Grön`, 441 | t: `Text`, 442 | i: `Ikon`, 443 | res: `Återställ`, 444 | l: `Loading`, 445 | quest: { 446 | head: `Är du säker?`, 447 | body: `Webbplatsen kommer att laddas om.`, 448 | yes: `Ja`, 449 | no: `Nej`, 450 | }, 451 | }, 452 | nl: { 453 | sel: `Nederlands (nl)`, 454 | tw: `Vertaal met`, 455 | lg: `Taal`, 456 | tr: `Vertaler`, 457 | ds: `Weergave`, 458 | menu: `Menu`, 459 | ao: `Automatisch`, 460 | th: `Thema`, 461 | df: `Standaard`, 462 | di: `Dimmen`, 463 | lo: `Licht uit`, 464 | col: `Kleur`, 465 | cb: `Blauw`, 466 | cy: `Geel`, 467 | cr: `Rood`, 468 | cp: `Paars`, 469 | co: `Oranje`, 470 | cg: `Groen`, 471 | t: `Tekst`, 472 | i: `Icoon`, 473 | res: `Herstel`, 474 | l: `Loading`, 475 | quest: { 476 | head: `Ben je zeker?`, 477 | body: `De website wordt opnieuw geladen.`, 478 | yes: `Ja`, 479 | no: `Nee`, 480 | }, 481 | }, 482 | fr: { 483 | sel: `Français (fr)`, 484 | tw: `Traduire avec`, 485 | lg: `Langue`, 486 | tr: `Traducteur`, 487 | ds: `Afficher`, 488 | menu: `Menu`, 489 | ao: `Automatique`, 490 | th: `Thème`, 491 | df: `Défaut`, 492 | di: `Dim`, 493 | lo: `Extinction des lumières`, 494 | col: `Couleur`, 495 | cb: `Bleu`, 496 | cy: `Jaune`, 497 | cr: `Rouge`, 498 | cp: `Violet`, 499 | co: `Orange`, 500 | cg: `Vert`, 501 | t: `Texte`, 502 | i: `Icône`, 503 | res: `Restaurer`, 504 | l: `Loading`, 505 | quest: { 506 | head: `Vous êtes sûr ?`, 507 | body: `Le site web va être rechargé.`, 508 | yes: `Oui`, 509 | no: `Non`, 510 | }, 511 | }, 512 | de: { 513 | sel: `Deutsch (de)`, 514 | tw: `Übersetzen mit`, 515 | lg: `Sprache`, 516 | tr: `Übersetzer`, 517 | ds: `Anzeige`, 518 | menu: `Menü`, 519 | ao: `Automatisch`, 520 | th: `Thema`, 521 | df: `Standard`, 522 | di: `Dimmen`, 523 | lo: `Licht aus`, 524 | col: `Farbe`, 525 | cb: `Blau`, 526 | cy: `Gelb`, 527 | cr: `Rot`, 528 | cp: `Lila`, 529 | co: `Orange`, 530 | cg: `Grün`, 531 | t: `Text`, 532 | i: `Icon`, 533 | res: `Wiederherstellen`, 534 | l: `Loading`, 535 | quest: { 536 | head: `Sind Sie sicher?`, 537 | body: `Die Website wird neu geladen.`, 538 | yes: `Ja`, 539 | no: `Nein`, 540 | }, 541 | }, 542 | it: { 543 | sel: `Italiano (it)`, 544 | tw: `Tradurre con`, 545 | lg: `Lingua`, 546 | tr: `Traduttore`, 547 | ds: `Visualizza`, 548 | menu: `Menu`, 549 | ao: `Automatico`, 550 | th: `Tema`, 551 | df: `Default`, 552 | di: `Dim`, 553 | lo: `Luci spente`, 554 | col: `Colore`, 555 | cb: `Blu`, 556 | cy: `Giallo`, 557 | cr: `Rosso`, 558 | cp: `Viola`, 559 | co: `Arancione`, 560 | cg: `Verde`, 561 | t: `Testo`, 562 | i: `Icona`, 563 | res: `Ripristinare`, 564 | l: `Loading`, 565 | quest: { 566 | head: `Sei sicuro?`, 567 | body: `Il sito sarà ricaricato.`, 568 | yes: `Sì`, 569 | no: `No`, 570 | }, 571 | }, 572 | ja: { 573 | sel: `日本語 (ja)`, 574 | tw: `で翻訳する`, 575 | lg: `言語`, 576 | tr: `翻訳者`, 577 | ds: `ディスプレイ`, 578 | menu: `メニュー`, 579 | ao: `自動`, 580 | th: `テーマ`, 581 | df: `デフォルト`, 582 | di: `暗い`, 583 | lo: `消灯`, 584 | col: `カラー`, 585 | cb: `青`, 586 | cy: `黄`, 587 | cr: `赤`, 588 | cp: `紫`, 589 | co: `オレンジ`, 590 | cg: `グリーン`, 591 | t: `テキスト`, 592 | i: `アイコン`, 593 | res: `リストア`, 594 | l: `Loading`, 595 | quest: { 596 | head: `本当にいいの?`, 597 | body: `ウェブサイトが再読み込みされます。`, 598 | yes: `はい`, 599 | no: `いいえ`, 600 | }, 601 | }, 602 | pl: { 603 | sel: `Polski (pl)`, 604 | tw: `Tłumaczenie za pomocą`, 605 | lg: `Język`, 606 | tr: `Tłumacz`, 607 | ds: `Wyświetlacz`, 608 | menu: `Menu`, 609 | ao: `Automatyczny`, 610 | th: `Motyw`, 611 | df: `Domyślnie`, 612 | di: `Ściemniaj`, 613 | lo: `Nie świeci się`, 614 | col: `Kolor`, 615 | cb: `Niebieski`, 616 | cy: `Żółty`, 617 | cr: `Czerwony`, 618 | cp: `Purpurowy`, 619 | co: `Pomarańczowy`, 620 | cg: `Zielony`, 621 | t: `Tekst`, 622 | i: `Ikona`, 623 | res: `Przywróć`, 624 | l: `Loading`, 625 | quest: { 626 | head: `Czy jesteś pewien?`, 627 | body: `Strona zostanie przeładowana.`, 628 | yes: `Tak`, 629 | no: `Nie`, 630 | }, 631 | }, 632 | pt: { 633 | sel: `Português (pt)`, 634 | tw: `Traduzir com`, 635 | lg: `Idioma`, 636 | tr: `Tradutora`, 637 | ds: `Mostrar`, 638 | menu: `Menu`, 639 | ao: `Automático`, 640 | th: `Tema`, 641 | df: `Por defeito`, 642 | di: `Dim`, 643 | lo: `Luzes apagadas`, 644 | col: `Cor`, 645 | cb: `Azul`, 646 | cy: `Amarelo`, 647 | cr: `Vermelho`, 648 | cp: `Púrpura`, 649 | co: `Laranja`, 650 | cg: `Verde`, 651 | t: `Texto`, 652 | i: `Ícone`, 653 | res: `Restaurar`, 654 | l: `Loading`, 655 | quest: { 656 | head: `Tem a certeza?`, 657 | body: `O website será carregado de novo.`, 658 | yes: `Sim`, 659 | no: `Não`, 660 | }, 661 | }, 662 | ru: { 663 | sel: `Russisch (ru)`, 664 | tw: `Перевод с`, 665 | lg: `Язык`, 666 | tr: `Переводчик`, 667 | ds: `Показать`, 668 | menu: `Меню`, 669 | ao: `Автоматический`, 670 | th: `Тема`, 671 | df: `По умолчанию`, 672 | di: `Приглушить`, 673 | lo: `Выключить свет`, 674 | col: `Цвет`, 675 | cb: `Синий`, 676 | cy: `Желтый`, 677 | cr: `Красный`, 678 | cp: `Фиолетовый`, 679 | co: `Оранжевый`, 680 | cg: `Зеленый`, 681 | t: `Текст`, 682 | i: `иконка`, 683 | res: `Восстановить`, 684 | l: `Loading`, 685 | quest: { 686 | head: `Вы уверены?`, 687 | body: `Сайт будет перезагружен.`, 688 | yes: `Да`, 689 | no: `Нет`, 690 | }, 691 | }, 692 | es: { 693 | sel: `Español (es)`, 694 | tw: `Traducir con`, 695 | lg: `Idioma`, 696 | tr: `Traductor`, 697 | ds: `Mostrar`, 698 | menu: `Menú`, 699 | ao: `Automático`, 700 | th: `Tema`, 701 | df: `Por defecto`, 702 | di: `Atenuar`, 703 | lo: `Luces apagadas`, 704 | col: `Colores`, 705 | cb: `Azul`, 706 | cy: `Amarillo`, 707 | cr: `Rojo`, 708 | cp: `Púrpura`, 709 | co: `Naranja`, 710 | cg: `Verde`, 711 | t: `Texto`, 712 | i: `Icono`, 713 | res: `Restaurar`, 714 | l: `Loading`, 715 | quest: { 716 | head: `¿Está seguro?`, 717 | body: `El sitio web será recargado.`, 718 | yes: `Sí`, 719 | no: `No`, 720 | }, 721 | }, 722 | }; 723 | -------------------------------------------------------------------------------- /dist/twittertranslatorlegacy.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name [Legacy] Twitter External Translator 3 | // @name:bg [Legacy] Външен преводач на Twitter 4 | // @name:zh [Legacy] Twitter外部翻译器 5 | // @name:zh-CN [Legacy] Twitter外部翻译器 6 | // @name:zh-TW [Legacy] Twitter外部翻译器 7 | // @name:cs [Legacy] Externí překladatel Twitter 8 | // @name:da [Legacy] Twitter ekstern oversætter 9 | // @name:et [Legacy] Twitteri väline tõlkija 10 | // @name:fi [Legacy] Twitter Ulkoinen kääntäjä 11 | // @name:el [Legacy] Εξωτερικός μεταφραστής Twitter 12 | // @name:hu [Legacy] Twitter külső fordító 13 | // @name:lv [Legacy] Twitter Ārējais tulkotājs 14 | // @name:lt [Legacy] "Twitter" išorinis vertėjas 15 | // @name:ro [Legacy] Twitter Traducător extern 16 | // @name:sk [Legacy] Externý prekladateľ Twitter 17 | // @name:sl [Legacy] Twitter Zunanji prevajalec 18 | // @name:sv [Legacy] Twitter Extern översättare 19 | // @name:nl [Legacy] Twitter Externe Vertaler 20 | // @name:fr [Legacy] Traducteur externe Twitter 21 | // @name:de [Legacy] Externer Twitter-Übersetzer 22 | // @name:it [Legacy] Traduttore esterno di Twitter 23 | // @name:ja [Legacy] ツイッター外部翻訳者 24 | // @name:pl [Legacy] Zewnętrzny tłumacz Twittera 25 | // @name:pt [Legacy] Tradutor externo do Twitter 26 | // @name:pt-BR [Legacy] Tradutor externo do Twitter 27 | // @name:ru-RU [Legacy] Twitter Внешний переводчик 28 | // @name:ru [Legacy] Twitter Внешний переводчик 29 | // @name:es [Legacy] Traductor externo de Twitter 30 | // @description Adds 3rd party translators to Twitter 31 | // @description:zh 将第三方翻译添加到推特 32 | // @description:zh-CN 将第三方翻译添加到推特 33 | // @description:zh-TW 將第三方翻譯添加到推特 34 | // @description:bg Добавя преводачи на трети страни в Twitter 35 | // @description:cs Přidává překladatele třetích stran na Twitter 36 | // @description:da Tilføjer tredjepartsoversættere til Twitter 37 | // @description:et Lisab kolmanda osapoole tõlkijad Twitterisse 38 | // @description:fi Lisää kolmannen osapuolen kääntäjiä Twitteriin 39 | // @description:el Προσθέτει μεταφραστές 3ου μέρους στο Twitter 40 | // @description:hu Hozzáadja a 3. féltől származó fordítókat a Twitterhez 41 | // @description:lv Pievieno trešās puses tulkotājus Twitter 42 | // @description:lt Prideda trečiųjų šalių vertėjus į "Twitter 43 | // @description:ro Adaugă traducători de la terțe părți la Twitter 44 | // @description:sk Pridáva prekladateľov tretích strán na Twitter 45 | // @description:sl Dodaja prevajalce tretjih oseb na Twitterju 46 | // @description:sv Lägger till översättare från tredje part till Twitter 47 | // @description:nl Voegt vertalers van derden toe aan Twitter 48 | // @description:fr Ajout de traducteurs tiers à Twitter 49 | // @description:de Fügt Drittanbieter-Übersetzer zu Twitter hinzu 50 | // @description:it Aggiunge traduttori di terze parti a Twitter 51 | // @description:pl Dodaje tłumaczy innych firm do Twittera 52 | // @description:pt Adiciona tradutores de terceiros ao Twitter 53 | // @description:pt-BR Adiciona tradutores de terceiros ao Twitter 54 | // @description:ja サードパーティの翻訳者をツイッターに追加 55 | // @description:ru-RU Добавляет сторонних переводчиков в Twitter 56 | // @description:ru Добавляет сторонних переводчиков в Twitter 57 | // @description:es Añade traductores de terceros a Twitter 58 | // @author Magic of Lolis 59 | // @icon https://abs.twimg.com/favicons/twitter.ico 60 | // @version 0.18 61 | // @namespace https://github.com/magicoflolis/userscriptrepo/tree/master/ExternalTranslator#twitter-external-translator 62 | // @homepageURL https://github.com/magicoflolis/userscriptrepo/tree/master/ExternalTranslator#twitter-external-translator 63 | // @supportURL https://github.com/magicoflolis/userscriptrepo/issues/new 64 | // @require https://code.jquery.com/jquery-3.6.0.slim.min.js 65 | // @include https://twitter.com/* 66 | // @include https://tweetdeck.twitter.com/* 67 | // @exclude https://twitter.com/login 68 | // @exclude https://twitter.com/signup 69 | // @exclude https://twitter.com/account 70 | // @exclude https://twitter.com/settings/* 71 | // @exclude https://twitter.com/i/flow/signup 72 | // @grant none 73 | // @inject-into auto 74 | // @run-at document-start 75 | // ==/UserScript== 76 | "use strict"; 77 | //#region Config 78 | /** 79 | * You'll need to edit the config manually for now if you're using this 80 | * as a user script. 81 | */ 82 | let cfg = { 83 | /** Preferred translator, lowercase only! 84 | * @type {'deepl'|'yandex'|'bing'|'google'|'mymemory'|'translate'} */ 85 | translator: ('deepl'), 86 | /** Preferred display 87 | * @type {'text'|'icon'|'text + icon'} */ 88 | display: ('text + icon'), 89 | iconWidthA: '16', // Twitter 90 | iconWidthB: '14', // TweetDeck 91 | lang: $("html[lang]").attr("lang"), 92 | debug: false 93 | }; 94 | //#endregion 95 | // Web icons are encoded in Data URI. 96 | // Can be decoded: https://www.site24x7.com/tools/datauri-to-image.html 97 | let icons = { 98 | deepl: ``, 99 | yandex: ``, 100 | bing: ``, 101 | google: ``, 102 | mymemory: ``, 103 | translate: ``, 104 | }, 105 | //#region Languages 106 | en = { 107 | sel: `English (en)`, 108 | tw: `Translate with`, 109 | lg: `Language`, 110 | tr: `Translator`, 111 | ds: `Display`, 112 | ti: `Text + Icon`, 113 | t: `Text`, 114 | i: `Icon`, 115 | s: `Save`, 116 | f: checkTXT 117 | }, 118 | zh = { 119 | sel: `中文 (zh)`, 120 | tw: `翻译与`, 121 | lg: `语种`, 122 | tr: `译者`, 123 | ds: `显示`, 124 | ti: `文本+图标`, 125 | t: `案文`, 126 | i: `图标`, 127 | s: `保存`, 128 | f: checkTXT 129 | }, 130 | bg = { 131 | sel: "Български (bg)", 132 | tw: "Преведете с", 133 | lg: "Език", 134 | tr: "Преводач", 135 | ds: "Показване на", 136 | ti: "Текст + икона", 137 | t: "Текст", 138 | i: "Икона", 139 | s: "Запазване", 140 | f: checkTXT 141 | }, 142 | cs = { 143 | sel: "Česky (cs)", 144 | tw: "Přeložit pomocí", 145 | lg: "Jazyk", 146 | tr: "Překladatel", 147 | ds: "Zobrazit", 148 | ti: "Text + ikona", 149 | t: "Text", 150 | i: "Ikona", 151 | s: "Uložit", 152 | f: checkTXT 153 | }, 154 | da = { 155 | sel: "Dansk (da)", 156 | tw: "Oversæt med", 157 | lg: "Sprog", 158 | tr: "Oversætter", 159 | ds: "Vis", 160 | ti: "Tekst + ikon", 161 | t: "Tekst", 162 | i: "Ikon", 163 | s: "Gem", 164 | f: checkTXT 165 | }, 166 | et = { 167 | sel: "Eesti (et)", 168 | tw: "Tõlge koos", 169 | lg: "Keel", 170 | tr: "Tõlkija", 171 | ds: "Kuva", 172 | ti: "Tekst + ikoon", 173 | t: "Tekst", 174 | i: "Ikoon", 175 | s: "Salvesta", 176 | f: checkTXT 177 | }, 178 | fi = { 179 | sel: "Suomalainen (fi)", 180 | tw: "Käännä kanssa", 181 | lg: "Kieli", 182 | tr: "Kääntäjä", 183 | ds: "Näytä", 184 | ti: "Teksti + kuvake", 185 | t: "Teksti", 186 | i: "Kuvake", 187 | s: "Tallenna", 188 | f: checkTXT 189 | }, 190 | el = { 191 | sel: "Ελληνική (el)", 192 | tw: "Μεταφράστε με", 193 | lg: "Γλώσσα", 194 | tr: "Μεταφραστής", 195 | ds: "Εμφάνιση", 196 | ti: "Κείμενο + εικονίδιο", 197 | t: "Κείμενο", 198 | i: "Εικονίδιο", 199 | s: "Αποθήκευση", 200 | f: checkTXT 201 | }, 202 | hu = { 203 | sel: "Magyar (hu)", 204 | tw: "Fordítson a", 205 | lg: "Nyelv", 206 | tr: "Fordító", 207 | ds: "Megjelenítés", 208 | ti: "Szöveg + ikon", 209 | t: "Szöveg", 210 | i: "Ikon", 211 | s: "Mentés", 212 | f: checkTXT 213 | }, 214 | lv = { 215 | sel: "Latviešu (lv)", 216 | tw: "Tulkot ar", 217 | lg: "Valoda", 218 | tr: "Tulkotājs", 219 | ds: "Displejs", 220 | ti: "Teksts + ikona", 221 | t: "Teksts", 222 | i: "Ikona", 223 | s: "Saglabāt", 224 | f: checkTXT 225 | }, 226 | lt = { 227 | sel: "Lietuvių kalba (lt)", 228 | tw: "Išversti su", 229 | lg: "Kalba", 230 | tr: "Vertėjas", 231 | ds: "Rodyti", 232 | ti: "Tekstas + piktograma", 233 | t: "Tekstas", 234 | i: "Ikona", 235 | s: "Išsaugoti", 236 | f: checkTXT 237 | }, 238 | ro = { 239 | sel: "Românesc (ro)", 240 | tw: "Tradu cu", 241 | lg: "Limba", 242 | tr: "Traducător", 243 | ds: "Afișați", 244 | ti: "Text + Icoană", 245 | t: "Text", 246 | i: "Icoană", 247 | s: "Salvați", 248 | f: checkTXT 249 | }, 250 | sk = { 251 | sel: "Slovenská (sk)", 252 | tw: "Preložiť s", 253 | lg: "Jazyk", 254 | tr: "Prekladateľ", 255 | ds: "Zobraziť", 256 | ti: "Text + ikona", 257 | t: "Text", 258 | i: "Ikona", 259 | s: "Uložiť", 260 | f: checkTXT 261 | }, 262 | sl = { 263 | sel: "Slovenski (sl)", 264 | tw: "Prevedi z", 265 | lg: "Jezik", 266 | tr: "Prevajalec", 267 | ds: "Prikaži", 268 | ti: "Besedilo + ikona", 269 | t: "Besedilo", 270 | i: "Ikona", 271 | s: "Shrani", 272 | }, 273 | sv = { 274 | sel: "Svenska (sv)", 275 | tw: "Översätt med", 276 | lg: "Språk", 277 | tr: "Översättare", 278 | ds: "Visa", 279 | ti: "Text + ikon", 280 | t: "Text", 281 | i: "Ikon", 282 | s: "Spara", 283 | f: checkTXT 284 | }, 285 | nl = { 286 | sel: `Nederlands (nl)`, 287 | tw: `Vertaal met`, 288 | lg: `Taal`, 289 | tr: `Vertaler`, 290 | ds: `Weergave`, 291 | ti: `Tekst + Pictogram`, 292 | t: `Tekst`, 293 | i: `Icoon`, 294 | s: `Save`, 295 | f: checkTXT 296 | }, 297 | fr = { 298 | sel: `Français (fr)`, 299 | tw: `Traduire avec`, 300 | lg: `Langue`, 301 | tr: `Traducteur`, 302 | ds: `Afficher`, 303 | ti: `Texte + Icône`, 304 | t: `Texte`, 305 | i: `Icône`, 306 | s: `Sauvez`, 307 | f: checkTXT 308 | }, 309 | de = { 310 | sel: `Deutsch (de)`, 311 | tw: `Übersetzen mit`, 312 | lg: `Sprache`, 313 | tr: `Übersetzer`, 314 | ds: `Anzeige`, 315 | ti: `Text + Symbol`, 316 | t: `Text`, 317 | i: `Icon`, 318 | s: `Speichern`, 319 | f: checkTXT 320 | }, 321 | it = { 322 | sel: `Italiano (it)`, 323 | tw: `Tradurre con`, 324 | lg: `Lingua`, 325 | tr: `Traduttore`, 326 | ds: `Visualizza`, 327 | ti: `Testo + icona`, 328 | t: `Testo`, 329 | i: `Icona`, 330 | s: `Salva`, 331 | f: checkTXT 332 | }, 333 | ja = { 334 | sel: `日本語 (ja)`, 335 | tw: `で翻訳する`, 336 | lg: `言語`, 337 | tr: `翻訳者`, 338 | ds: `ディスプレイ`, 339 | ti: `テキスト+アイコン`, 340 | t: `テキスト`, 341 | i: `アイコン`, 342 | s: `保存`, 343 | f: checkTXT 344 | }, 345 | pl = { 346 | sel: `Polski (pl)`, 347 | tw: `Tłumaczenie za pomocą`, 348 | lg: `Język`, 349 | tr: `Tłumacz`, 350 | ds: `Wyświetlacz`, 351 | ti: `Tekst + Ikona`, 352 | t: `Tekst`, 353 | i: `Ikona`, 354 | s: `Zapisz`, 355 | f: checkTXT 356 | }, 357 | pt = { 358 | sel: `Português (pt)`, 359 | tw: `Traduzir com`, 360 | lg: `Idioma`, 361 | tr: `Tradutora`, 362 | ds: `Mostrar`, 363 | ti: `Texto + Ícone`, 364 | t: `Texto`, 365 | i: `Ícone`, 366 | s: `Guardar`, 367 | f: checkTXT 368 | }, 369 | ru = { 370 | sel: `Russisch (ru)`, 371 | tw: `Перевод с`, 372 | lg: `Язык`, 373 | tr: `Переводчик`, 374 | ds: `Показать`, 375 | ti: `Текст + иконка`, 376 | t: `Текст`, 377 | i: `иконка`, 378 | s: `Сохранить`, 379 | f: checkTXT 380 | }, 381 | es = { 382 | sel: `Español (es)`, 383 | tw: `Traducir con`, 384 | lg: `Idioma`, 385 | tr: `Traductor`, 386 | ds: `Mostrar`, 387 | ti: `Texto + Icono`, 388 | t: `Texto`, 389 | i: `Icono`, 390 | s: `Guardar`, 391 | f: checkTXT 392 | }; 393 | //#endregion 394 | const log = (...args) => { 395 | (cfg.debug) ? console.log('[MoL]', ...args) : false; 396 | }, 397 | isHTML = (str, doc = new DOMParser().parseFromString(str, "text/html")) => { 398 | return Array.from(doc.body.childNodes).some(node => node.nodeType === 1); 399 | }; 400 | 401 | function checkTXT() { 402 | return this.tw 403 | } 404 | async function injectTranslationButton() { 405 | let content = '',magicBtn,btContainer,btLang,site, 406 | translateTweet = $("div[lang]").eq(0).siblings().eq(0).children("span"), // "Translate Tweet" button 407 | translateBio = $('div[data-testid="UserDescription"]').eq(0).siblings().eq(0).children("span"), // "Translate Bio" button 408 | trTweet = $("div[lang]").eq(0).siblings().eq(1), // [Tweet] "Translate with ..." button 409 | trBio = $('div[data-testid="UserDescription"]').eq(0).siblings().eq(1), // [Bio] "Translate with ..." button 410 | name = (cfg.translator == 'yandex') ? `Yandex ${icons.yandex}` : (cfg.translator == 'bing') ? `Bing ${icons.bing}` : (cfg.translator == 'google') ? `Google ${icons.google}` : (cfg.translator == 'mymemory') ? `MyMemory ${icons.mymemory}` : (cfg.translator == 'translate') ? `translate.com ${icons.translate}` : `DeepL ${icons.deepl}`, 411 | nIcons = (cfg.translator == 'yandex') ? icons.yandex : (cfg.translator == 'bing') ? icons.bing : (cfg.translator == 'google') ? icons.google : (cfg.translator == 'mymemory') ? icons.mymemory : (cfg.translator == 'translate') ? icons.translate : icons.deepl, 412 | checkDisplay = (cfg.display == 'text') ? icons = { deepl: '', yandex: '', bing: '', google: '', mymemory: '', translate: '' } : (cfg.display == 'icon') ? name = nIcons : false, 413 | tweetbtn = () => { 414 | log("Injecting tweet button") 415 | btContainer = translateTweet.parent().siblings().eq(0), // "Tweet" 416 | btLang = btContainer.attr("lang"); 417 | magicBtn = translateTweet.parent().clone().appendTo(translateTweet.parent().parent()); 418 | btContainer.children("span").each((index,item) => { 419 | let tweet = $(item).html().trim(); 420 | (tweet && tweet != '' && !isHTML(tweet)) ? content += ` ${tweet}` : false; 421 | }); 422 | (!btLang) ? btLang = "auto" : false; 423 | (cfg.lang == 'bg') ? magicBtn.html(`${bg.f()} ${name}`) : (cfg.lang == 'cs') ? magicBtn.html(`${cs.f()} ${name}`) : (cfg.lang == 'da') ? magicBtn.html(`${da.f()} ${name}`) : (cfg.lang == 'et') ? magicBtn.html(`${et.f()} ${name}`) : (cfg.lang == 'fi') ? magicBtn.html(`${fi.f()} ${name}`) : (cfg.lang == 'el') ? magicBtn.html(`${el.f()} ${name}`) : (cfg.lang == 'hu') ? magicBtn.html(`${hu.f()} ${name}`) : (cfg.lang == 'lv') ? magicBtn.html(`${lv.f()} ${name}`) : (cfg.lang == 'lt') ? magicBtn.html(`${lt.f()} ${name}`) : (cfg.lang == 'ro') ? magicBtn.html(`${ro.f()} ${name}`) : (cfg.lang == 'sk') ? magicBtn.html(`${sk.f()} ${name}`) : (cfg.lang == 'sl') ? magicBtn.html(`${sl.f()} ${name}`) : (cfg.lang == 'sv') ? magicBtn.html(`${sv.f()} ${name}`) : (cfg.lang == 'zh') ? magicBtn.html(`${zh.f()} ${name}`) : (cfg.lang == 'nl') ? magicBtn.html(`${nl.f()} ${name}`) : (cfg.lang == 'fr') ? magicBtn.html(`${fr.f()} ${name}`) : (cfg.lang == 'de') ? magicBtn.html(`${de.f()} ${name}`) : (cfg.lang == 'it') ? magicBtn.html(`${it.f()} ${name}`) : (cfg.lang == 'ja') ? magicBtn.html(`${ja.f()} ${name}`) : (cfg.lang == 'pl') ? magicBtn.html(`${pl.f()} ${name}`) : (cfg.lang == 'pt') ? magicBtn.html(`${pt.f()} ${name}`) : (cfg.lang == 'ru') ? magicBtn.html(`${ru.f()} ${name}`) : (cfg.lang == 'es') ? magicBtn.html(`${es.f()} ${name}`) : magicBtn.html(`${en.f()} ${name}`); 424 | site = (cfg.translator == 'yandex') ? `https://translate.yandex.com/?lang=${btLang}-${cfg.lang}&text=${content}` : (cfg.translator == 'bing') ? `https://www.bing.com/translator/?text=${content}&from=${btLang}&to=${cfg.lang}` : (cfg.translator == 'google') ? `https://translate.google.com/?q=${content}&sl=${btLang}&tl=${cfg.lang}` : (cfg.translator == 'mymemory') ? `https://mymemory.translated.net/${cfg.lang}/${btLang}/${cfg.lang}/${content}` : (cfg.translator == 'translate') ? `https://www.translate.com/#${btLang}/${cfg.lang}/${content}` : `https://www.deepl.com/translator#${btLang}/${cfg.lang}/${content}`; 425 | magicBtn.hover(function() { 426 | $(this).addClass("r-1ny4l3l r-1ddef8g") 427 | // $(this).css("text-decoration", "underline"); 428 | }, function() { 429 | $(this).removeClass("r-1ny4l3l r-1ddef8g") 430 | // $(this).css("text-decoration", "none"); 431 | }); 432 | magicBtn.on("click", () => { 433 | window.open(`${site}`,'_blank'); 434 | }) 435 | }, 436 | biobtn = () => { 437 | log("Injecting bio button") 438 | btContainer = translateBio.parent().siblings().eq(0); // "User Bio" 439 | btLang = $("div[lang]").attr("lang"); 440 | magicBtn = translateBio.parent().clone().appendTo(translateBio.parent().parent()); 441 | btContainer.children("span").each((index,item) => { 442 | let bio = $(item).html().trim(); 443 | (bio && bio != '' && !isHTML(bio)) ? content += ` ${bio}` : false; 444 | }); 445 | (!btLang) ? btLang = "auto" : false; 446 | (cfg.lang == 'bg') ? magicBtn.html(`${bg.f()} ${name}`) : (cfg.lang == 'cs') ? magicBtn.html(`${cs.f()} ${name}`) : (cfg.lang == 'da') ? magicBtn.html(`${da.f()} ${name}`) : (cfg.lang == 'et') ? magicBtn.html(`${et.f()} ${name}`) : (cfg.lang == 'fi') ? magicBtn.html(`${fi.f()} ${name}`) : (cfg.lang == 'el') ? magicBtn.html(`${el.f()} ${name}`) : (cfg.lang == 'hu') ? magicBtn.html(`${hu.f()} ${name}`) : (cfg.lang == 'lv') ? magicBtn.html(`${lv.f()} ${name}`) : (cfg.lang == 'lt') ? magicBtn.html(`${lt.f()} ${name}`) : (cfg.lang == 'ro') ? magicBtn.html(`${ro.f()} ${name}`) : (cfg.lang == 'sk') ? magicBtn.html(`${sk.f()} ${name}`) : (cfg.lang == 'sl') ? magicBtn.html(`${sl.f()} ${name}`) : (cfg.lang == 'sv') ? magicBtn.html(`${sv.f()} ${name}`) : (cfg.lang == 'zh') ? magicBtn.html(`${zh.f()} ${name}`) : (cfg.lang == 'nl') ? magicBtn.html(`${nl.f()} ${name}`) : (cfg.lang == 'fr') ? magicBtn.html(`${fr.f()} ${name}`) : (cfg.lang == 'de') ? magicBtn.html(`${de.f()} ${name}`) : (cfg.lang == 'it') ? magicBtn.html(`${it.f()} ${name}`) : (cfg.lang == 'ja') ? magicBtn.html(`${ja.f()} ${name}`) : (cfg.lang == 'pl') ? magicBtn.html(`${pl.f()} ${name}`) : (cfg.lang == 'pt') ? magicBtn.html(`${pt.f()} ${name}`) : (cfg.lang == 'ru') ? magicBtn.html(`${ru.f()} ${name}`) : (cfg.lang == 'es') ? magicBtn.html(`${es.f()} ${name}`) : magicBtn.html(`${en.f()} ${name}`); 447 | site = (cfg.translator == 'yandex') ? `https://translate.yandex.com/?lang=${btLang}-${cfg.lang}&text=${content}` : (cfg.translator == 'bing') ? `https://www.bing.com/translator/?text=${content}&from=${btLang}&to=${cfg.lang}` : (cfg.translator == 'google') ? `https://translate.google.com/?q=${content}&sl=${btLang}&tl=${cfg.lang}` : (cfg.translator == 'mymemory') ? `https://mymemory.translated.net/${cfg.lang}/${btLang}/${cfg.lang}/${content}` : (cfg.translator == 'translate') ? `https://www.translate.com/#${btLang}/${cfg.lang}/${content}` : `https://www.deepl.com/translator#${btLang}/${cfg.lang}/${content}`; 448 | magicBtn.hover(function() { 449 | $(this).addClass("r-1ny4l3l r-1ddef8g") 450 | // $(this).css("text-decoration", "underline"); 451 | }, function() { 452 | $(this).removeClass("r-1ny4l3l r-1ddef8g") 453 | // $(this).css("text-decoration", "none"); 454 | }); 455 | magicBtn.on("click", () => { 456 | window.open(`${site}`,'_blank'); 457 | }) 458 | }; 459 | let check = (!trBio.length && translateBio.length) ? biobtn() : (!trTweet.length && translateTweet.length) ? tweetbtn() : checkDisplay; 460 | // Resizes icons 461 | if($('.exIcon').length) { 462 | $('.exIcon').attr('width', cfg.iconWidthA); 463 | }; 464 | return check 465 | } 466 | async function TweetDeck() { 467 | let content = '',magicBtn,btContainer,btLang,site, 468 | translateTweet = $('a.js-translate-call-to-action'), // "Translate Tweet" button 469 | trTweet = translateTweet.eq(1), // [Tweet] "Translate with ..." button 470 | name = (cfg.translator == 'yandex') ? `Yandex ${icons.yandex}` : (cfg.translator == 'bing') ? `Bing ${icons.bing}` : (cfg.translator == 'google') ? `Google ${icons.google}` : (cfg.translator == 'mymemory') ? `MyMemory ${icons.mymemory}` : (cfg.translator == 'translate') ? `translate.com ${icons.translate}` : `DeepL ${icons.deepl}`, 471 | nIcons = (cfg.translator == 'yandex') ? icons.yandex : (cfg.translator == 'bing') ? icons.bing : (cfg.translator == 'google') ? icons.google : (cfg.translator == 'mymemory') ? icons.mymemory : (cfg.translator == 'translate') ? icons.translate : icons.deepl, 472 | checkDisplay = (cfg.display == 'text') ? icons = { deepl: '', yandex: '', bing: '', google: '', mymemory: '', translate: '' } : (cfg.display == 'icon') ? name = nIcons : false, 473 | tweetbtn = () => { 474 | log("Injecting tweet button") 475 | checkDisplay 476 | // new dis().check() 477 | btContainer = translateTweet.siblings().eq(2), // "Tweet" 478 | content = btContainer.text(), // Content of "Tweet" 479 | btLang = btContainer.attr("lang"); 480 | magicBtn = translateTweet.before(translateTweet.clone()); // Create external translation button 481 | (!btLang) ? btLang = "auto" : false; 482 | (cfg.lang == 'bg') ? magicBtn.html(`${bg.f()} ${name}`) : (cfg.lang == 'cs') ? magicBtn.html(`${cs.f()} ${name}`) : (cfg.lang == 'da') ? magicBtn.html(`${da.f()} ${name}`) : (cfg.lang == 'et') ? magicBtn.html(`${et.f()} ${name}`) : (cfg.lang == 'fi') ? magicBtn.html(`${fi.f()} ${name}`) : (cfg.lang == 'el') ? magicBtn.html(`${el.f()} ${name}`) : (cfg.lang == 'hu') ? magicBtn.html(`${hu.f()} ${name}`) : (cfg.lang == 'lv') ? magicBtn.html(`${lv.f()} ${name}`) : (cfg.lang == 'lt') ? magicBtn.html(`${lt.f()} ${name}`) : (cfg.lang == 'ro') ? magicBtn.html(`${ro.f()} ${name}`) : (cfg.lang == 'sk') ? magicBtn.html(`${sk.f()} ${name}`) : (cfg.lang == 'sl') ? magicBtn.html(`${sl.f()} ${name}`) : (cfg.lang == 'sv') ? magicBtn.html(`${sv.f()} ${name}`) : (cfg.lang == 'zh') ? magicBtn.html(`${zh.f()} ${name}`) : (cfg.lang == 'nl') ? magicBtn.html(`${nl.f()} ${name}`) : (cfg.lang == 'fr') ? magicBtn.html(`${fr.f()} ${name}`) : (cfg.lang == 'de') ? magicBtn.html(`${de.f()} ${name}`) : (cfg.lang == 'it') ? magicBtn.html(`${it.f()} ${name}`) : (cfg.lang == 'ja') ? magicBtn.html(`${ja.f()} ${name}`) : (cfg.lang == 'pl') ? magicBtn.html(`${pl.f()} ${name}`) : (cfg.lang == 'pt') ? magicBtn.html(`${pt.f()} ${name}`) : (cfg.lang == 'ru') ? magicBtn.html(`${ru.f()} ${name}`) : (cfg.lang == 'es') ? magicBtn.html(`${es.f()} ${name}`) : magicBtn.html(`${en.f()} ${name}`); 483 | site = (cfg.translator == 'yandex') ? `https://translate.yandex.com/?lang=${btLang}-${cfg.lang}&text=${content}` : (cfg.translator == 'bing') ? `https://www.bing.com/translator/?text=${content}&from=${btLang}&to=${cfg.lang}` : (cfg.translator == 'google') ? `https://translate.google.com/?q=${content}&sl=${btLang}&tl=${cfg.lang}` : (cfg.translator == 'mymemory') ? `https://mymemory.translated.net/${cfg.lang}/${btLang}/${cfg.lang}/${content}` : (cfg.translator == 'translate') ? `https://www.translate.com/#${btLang}/${cfg.lang}/${content}` : `https://www.deepl.com/translator#${btLang}/${cfg.lang}/${content}`; 484 | magicBtn.on("click", () => { 485 | window.open(`${site}`,'_blank'); 486 | }) 487 | }; 488 | let check = (!trTweet.length && translateTweet.length) ? tweetbtn() : trTweet.attr('style', 'display: flex !important; align-items: end !important;'); 489 | // Resizes icons 490 | if($('.exIcon').length) { 491 | $('.exIcon').attr('width', cfg.iconWidthB); 492 | }; 493 | return check 494 | } 495 | let observer = new MutationObserver(() => {injectTranslationButton()}); 496 | let td = new MutationObserver(() => {TweetDeck()}); 497 | // Its a headache observing single tweet element, inconsistent load times. 498 | const target = document.querySelector("body"), 499 | init = { subtree: true, characterData: true, childList: true }; 500 | (location.host == 'twitter.com') ? observer.observe($(".css-1dbjc4n")[0], {subtree:true,characterData:true,childList:true}) : (location.host == 'tweetdeck.twitter.com') ? td.observe(target, init) : false; 501 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------