├── .github └── FUNDING.yml ├── .gitignore ├── .vscode └── extensions.json ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── PRIVACY_POLICY.md ├── README.md ├── _locales ├── en │ └── messages.json ├── es │ └── messages.json ├── fr │ └── messages.json ├── it │ └── messages.json ├── ja │ └── messages.json ├── ko │ └── messages.json └── zh_CN │ └── messages.json ├── background.js ├── content.js ├── icons ├── chrome-web-store-icon.png ├── icon.svg ├── icon128-disabled.png ├── icon128.png ├── icon16-disabled.png ├── icon16.png ├── icon256.png ├── icon32-disabled.png ├── icon32.png ├── icon48-disabled.png ├── icon48.png ├── icon512.png ├── icon600.png ├── icon64-disabled.png ├── icon64.png ├── icon96-disabled.png ├── icon96.png ├── toolbar-icon16.png ├── toolbar-icon19.png ├── toolbar-icon32.png ├── toolbar-icon38.png ├── toolbar-icon48.png └── toolbar-icon72.png ├── jsconfig.json ├── manifest.mv2.json ├── manifest.mv3.json ├── options-icon.png ├── options.css ├── options.html ├── options.js ├── package.json ├── promo ├── 1.xcf ├── 2.xcf ├── 3.xcf ├── 4.xcf ├── 5.xcf ├── app-store.png ├── blue_promo.png ├── chrome_small_promo_tile.xcf ├── iPhone-1.xcf ├── iPhone-2.xcf ├── iPhone-3.xcf ├── iPhone-4.xcf └── iPhone-5.xcf ├── safari ├── .gitignore ├── Control Panel for Twitter.xcodeproj │ └── project.pbxproj ├── Shared (App) │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── appicon1024-fullbleed.png │ │ │ ├── appicon1024.png │ │ │ ├── appicon128.png │ │ │ ├── appicon16.png │ │ │ ├── appicon256.png │ │ │ ├── appicon32.png │ │ │ ├── appicon512.png │ │ │ └── appicon64.png │ │ ├── Contents.json │ │ └── LargeIcon.imageset │ │ │ └── Contents.json │ ├── Base.lproj │ │ └── Main.html │ ├── Resources │ │ ├── Icon.png │ │ ├── Script.js │ │ └── Style.css │ └── ViewController.swift ├── Shared (Extension) │ ├── Resources │ │ └── manifest.json │ └── SafariWebExtensionHandler.swift ├── iOS (App) │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ └── SceneDelegate.swift ├── iOS (Extension) │ └── Info.plist ├── macOS (App) │ ├── AppDelegate.swift │ ├── Base.lproj │ │ └── Main.storyboard │ └── Tweak New Twitter.entitlements └── macOS (Extension) │ ├── Info.plist │ └── Tweak New Twitter.entitlements ├── screenshots ├── arabic.png ├── chirp_off.png ├── chirp_on.png ├── disable_home_timeline.png ├── firefox_android_disable_home_timeline.jpg ├── firefox_android_explore.jpg ├── firefox_android_hide_metrics.jpg ├── firefox_android_menu.jpg ├── firefox_android_options_popup.jpg ├── firefox_android_quote_tweets.jpg ├── firefox_android_reduced_interaction_mode.jpg ├── firefox_android_shared_tweets.jpg ├── firefox_android_timeline.jpg ├── full_width_timeline.png ├── hide_metrics.png ├── irish.png ├── japanese.png ├── more_menu.png ├── options_popup.png ├── quote_tweets.png ├── reduced_interaction_mode.png ├── shared_tweets.png ├── timeline.png ├── uninverted_follow_buttons_monochrome.png └── uninverted_follow_buttons_themed.png ├── script.js ├── scripts ├── build.js ├── copy.js ├── create-browser-action.js ├── create-store-description.mjs ├── locales │ ├── .prettierrc │ ├── README.md │ ├── base-locales.json │ ├── create-js-curl-config.js │ ├── create-locales.js │ ├── html │ │ └── _files.txt │ ├── js │ │ └── .gitkeep │ ├── update-base-locales-from-json.js │ ├── update-base-locales.js │ └── update-translations.js ├── mac-appicon-assets.sh ├── release.js ├── set-safari-screenshot-resolution.applescript ├── update-locale-messages.js └── utils.js └── types.d.ts /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: jbscript 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | browser_action.html 3 | manifest.json 4 | node_modules/ 5 | promo/*.png 6 | !promo/app-store.png 7 | scripts/locales/base-translations.json 8 | scripts/locales/html/*.html 9 | scripts/locales/js/*.js 10 | scripts/locales/js/_files.txt 11 | scripts/locales/locales.js 12 | scripts/locales/old/ 13 | scripts/translations.json 14 | web-ext-artifacts/ -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "santacodes.santacodes-region-viewer" 4 | ] 5 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Development of Control Panel for Twitter 2 | 3 | ## Setup 4 | 5 | Install development dependencies: 6 | 7 | ```shell 8 | npm install 9 | ``` 10 | 11 | ## Debug mode 12 | 13 | To enable debug mode, you can either manually set `debug = true` at the top of `script.js`, or open the options page, expand the Experiments section and click the last paragraph 5 times to gain access to the debug options, where you can enable debug mode. 14 | 15 | When debug mode is active, log statemente are displayed in the browser console and the detected type of each tweet is displayed in all supported timelines where the tweet type is being detected. 16 | 17 | There's a `log()` function which can and should be used to log useful debug information, such as the appearance of elements which trigger certain tweaks (useful as a starting point when Twitter changes things), or that a particular tweak is about to happen (for traceability). 18 | 19 | ## Desktop vs. mobile 20 | 21 | At the time of writing, the [current version of Twitter](https://blog.twitter.com/engineering/en_us/topics/infrastructure/2019/buildingthenewtwitter) uses the same webapp to provide different experiences for desktop and mobile devices. 22 | 23 | Some of the tweaks in Control Panel for Twitter work the same in both versions, but others need a different implementation or CSS selector for each version, or aren't present in one of the versions at all. 24 | 25 | To handle this, scripts in the extension have `mobile` and `desktop` flags which are used to tailor what they do according to version of Twitter being used. 26 | 27 | ### Developing mobile features 28 | 29 | If you want to test a feature in the mobile version, use the responsive design / mobile device simulation mode in your browser's developer tools. Control Panel for Twitter will automatically detect which version is being used, and the options page will also be updated accordingly. 30 | 31 | ## Running as a browser extension 32 | 33 | Control Panel for Twitter uses [web-ext](https://github.com/mozilla/web-ext#web-ext) to run as a browser extension in a temporary profile, and automatically reload it when you make changes during development. 34 | 35 | To run in Mozilla Firefox: 36 | 37 | ```shell 38 | npm run firefox 39 | ``` 40 | 41 | To run in Google Chrome: 42 | 43 | ```shell 44 | npm run chrome 45 | ``` 46 | 47 | To run in Microsoft Edge on Windows: 48 | 49 | ```shell 50 | npm run edge 51 | ``` 52 | 53 | > Note: the edge command assumes you have Windows installed on the `C:` drive, change it in your local `package.json` if that's not the case 54 | 55 | To run in Microsoft Edge on macOS: 56 | 57 | ```shell 58 | npm run edge-mac 59 | ``` 60 | 61 | ### Running on Firefox for Android 62 | 63 | To test the mobile version on-device as an extension, you'll need an Android device with [Firefox Nightly](https://play.google.com/store/apps/details?id=org.mozilla.fenix) installed. 64 | 65 | Follow the setup guide in web-ext's [Developing extensions for Firefox for Android](https://extensionworkshop.com/documentation/develop/developing-extensions-for-firefox-for-android/) documentation, and after connecting your device to your computer, run `adb` to get its id: 66 | 67 | ```shell 68 | $ adb devices 69 | List of devices attached 70 | 1a23456b device 71 | ``` 72 | 73 | To run in Firefox Nightly, pass in your device's id like so: 74 | 75 | ```shell 76 | npm run android -- --adb-device 1a23456b 77 | ``` 78 | 79 | If successful, you should see output similar to the following: 80 | 81 | ``` 82 | Applying config file: ./package.json 83 | Running web extension from /path/to/control-panel-for-twitter 84 | Selected ADB device: 1a23456b 85 | Stopping existing instances of org.mozilla.fenix... 86 | Starting org.mozilla.fenix... 87 | Waiting for org.mozilla.fenix Remote Debugging Server... 88 | Make sure to enable "Remote Debugging via USB" from Settings -> Developer Tools if it is not yet enabled. 89 | Building web extension from /path/to/control-panel-for-twitter 90 | You can connect to this Android device on TCP port 56265 91 | Installed /data/local/tmp/web-ext-artifacts-1626656312714/control_pabel_for_twitter-1.234.xpi as a temporary add-on 92 | The extension will reload if any source file changes 93 | Press R to reload (and Ctrl-C to quit) 94 | ``` 95 | 96 | You can now open the `about:debugging` page in Firefox on your computer and click one of the "Inspect" buttons in the Tabs list to connect your local Firefox Developer Tools to that tab on your device, allowing you to view console output and inspect the DOM. 97 | 98 | ## Running as a user script 99 | 100 | Install a [user script manager](https://greasyfork.org/en#home-step-1) of your choice and install `script.js` in it. 101 | 102 | Control Panel for Twitter is distributed as a browser extension and as a user script, so the main `script.js` script must always be valid in both contexts, even if we eventually add features which only work in the extension. 103 | 104 | ## Coding conventions 105 | 106 | ### Types 107 | 108 | Control Panel for Twitter is written in regular JavaScript, leveraging TypeScript's support for [type checking JavaScript files](https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html) with [type annotations provided via JSDoc](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html), and [VS Code](https://code.visualstudio.com/)'s support for using its built-in TypeScript tooling in regular JavaScript, configured via `jsconfig.json`. 109 | 110 | > Type checking should work out of the box if you use VS Code - if it doesn't, use the **Preference: Open Settings (JSON)** command in the Command Palette and check your global preferences for any config changes which might affect this. 111 | 112 | ## Common development issues 113 | 114 | **You're making a change to how timeline elements are handled, you've tripled checked your changes for logic bugs, _and_ you've added logging which says your change is doing what it should do, so why is it not working?** 115 | 116 | You're running 2 versions of Control Panel for Twitter at the same time - the one you're developing, and an older version you already have installed. 117 | 118 | If you're testing a quick change in a user script manager on desktop, check you don't have the extension version enabled. 119 | 120 | If you're running a development version on Firefox Nightly and also have the extension installed for personal use, make sure the one installed from Mozilla Add-ons is disabled while developing. 121 | 122 | Easy check: open up the "More" menu (desktop) or the slide-out menu (mobile) - if "Add muted word" is on there twice, you're definitely running 2 versions. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019, Jonny Buchanan 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | script.js includes the dedent() function from https://github.com/victornpb/tiny-dedent 2 | 3 | MIT License 4 | 5 | Copyright (c) 2021 Victor 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. -------------------------------------------------------------------------------- /PRIVACY_POLICY.md: -------------------------------------------------------------------------------- 1 | # Privacy Policy 2 | 3 | No data or personal information is collected by Control Panel for Twitter. 4 | 5 | ### Contact 6 | 7 | If you have any questions or suggestions regarding this privacy policy, please email jonathan.buchanan+extensions@gmail.com. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Control Panel for Twitter 2 | 3 | ![](icons/icon128.png) 4 | 5 | **Control Panel for Twitter is a browser extension which gives you more control over Twitter and adds missing features and UI improvements** 6 | 7 | ## Install 8 | 9 | * [Safari Extension](https://apps.apple.com/app/id1668516167?platform=iphone) - for iPhone, iPad and Mac 10 | 11 | [![Download on the App Store](promo/app-store.png)](https://apps.apple.com/app/id1668516167?platform=iphone) 12 | * [Firefox Extension](https://addons.mozilla.org/firefox/addon/control-panel-for-twitter/) - can also be installed in the Android version of Firefox 13 | * [Chrome Extension](https://chrome.google.com/webstore/detail/control-panel-for-twitter/kpmjjdhbcfebfjgdnpjagcndoelnidfj) - can also be installed in Edge, Opera, and Brave on desktop, and [Kiwi Browser](https://play.google.com/store/apps/details?id=com.kiwibrowser.browser) on Android 14 | * [Edge Add-on](https://microsoftedge.microsoft.com/addons/detail/control-panel-for-twitter/foccddlibbeccjiobcnakipdpkjiijjp) 15 | * [User script version](https://greasyfork.org/en/scripts/387773-control-panel-for-twitter) - requires a [user script manager](https://greasyfork.org/en#home-step-1) 16 | 17 | ## Releases / What's New? 18 | 19 | The [Control Panel for Twitter Releases page](https://github.com/insin/control-panel-for-twitter/releases) highlights new features, changes and fixes in each version, and shows which version is currently published on each of the browser extension stores. 20 | 21 | New versions can take anything from minutes to days to be approved for publishing after they're submitted to a browser extension store. 22 | 23 | ## Features 24 | 25 | ### Home timeline 26 | 27 | - Defaults to the "Following" (chronological) timeline, automatically switching you back if Twitter tries to move you to the "For you" (algorithmic) timeline 28 | - Hide the "For you" timeline tab (default setting) 29 | - Move Retweets to a separate tab (default setting), or hide them entirely 30 | - Move Quote Tweets and replies to them to a separate tab in the Home timeline, or hide them entirely 31 | - Hide Retweets in pinned Lists 32 | - Enable muting of Quote Tweets 33 | - Hide the floating "See new Tweets" button 34 | - Hide "Who to follow", "Follow some Topics" etc. in the Home timeline and elsewhere 35 | - Hide inline prompts in the timeline 36 | - Full-width timeline: hide the sidebar and let timeline content go full-width on Home, Lists and Communities 37 | 38 | ### UI improvements 39 | 40 | - Add "Add muted word" to the "More" menu (desktop) or slide-out menu (mobile) 41 | - Fast blocking - skips the confirm dialog when you try to block an account 42 | - Hide quotes of and replies to blocked and muted accounts 43 | - Hide Retweets in user profiles 44 | - Default to "Latest" tab in Search 45 | - When viewing a tweet's Quote Tweets, hide the quoted tweet to make more room for quotes 46 | 47 | ### X fixes 48 | 49 | - Replace X branding changes 50 | - Hide Views under tweets 51 | - Hide the "Verified" tab in Notifications and the "Verified Followers" tab in Followers/Following 52 | - Restore headlines under external links 53 | - Restore the Quote Tweets link under tweets, and other interaction links 54 | - Default sorting replies to most recent or most liked 55 | - Replace Premium blue checks with the Twitter Blue logo, or hide them altogether 56 | - Hide Premium blue check replies in threads 57 | - Hide Premium upsells throughout the app 58 | - Hide Grok 59 | - Hide Jobs 60 | - Hide Subscriptions 61 | 62 | ### UI tweaks 63 | 64 | - Disable use of the Chirp font if you don't like it 65 | - Disable bold and italic text in tweets 66 | - Use the site's normal text font style in the primary navigation menu on desktop to make it less distracting 67 | - Change the navigation menu density on desktop to make it take less room 68 | - Use normal font weight in dropdown menus - if everything's bold, nothing's bold 69 | - Uninvert the Follow and Following buttons to make them less jarring 70 | - Choice of monochrome or themed (classic) styling for uninverted buttons 71 | 72 | ### Remove algorithmic content 73 | 74 | - Hide sidebar contents 75 | - Hide Explore page contents and use it only for searching 76 | - Hide "Discover more" algorithmic tweets when viewing a tweet 77 | 78 | ### Reduce "engagement" 79 | 80 | - Hide metrics 81 | - Reduced interaction mode: hide the action bar under tweets – replies are now the only means of interacting 82 | - Disable the home timeline: find yourself [wasting too much time on Twitter](https://world.hey.com/brecht/free-range-tweet-farming-9399f6e5)? Try preventing use of the home timeline, going to Notifications or Messages by default instead 83 | 84 | ### Hide UI items you don't use 85 | 86 | - Bookmark button under tweets 87 | - Share button under tweets 88 | - Analytics links under your own tweets 89 | - Hide navigation items you don't use on desktop, and other distracting screen elements such as the Messages drawer 90 | - Hide the bottom nav item for Messages on mobile if you don't use it often 91 | - Hide items you don't use in the "More" menu (desktop) or slide-out menu (mobile) 92 | 93 | ## Screenshots 94 | 95 | ### Home timeline with most tweaks enabled 96 | 97 | | Desktop | Mobile | 98 | | - | - | 99 | | ![Screenshot of a desktop Twitter home timeline without Retweets, algorithmic timeline content, or sidebar content, with fewer navigation items and a less distracting navigation font style](screenshots/timeline.png) | ![Screenshot of a mobile Twitter home timeline without Retweets, algorithmic timeline content](screenshots/firefox_android_timeline.jpg) | 100 | 101 | ### Separate timeline for Retweets (default setting) and/or Quote Tweets 102 | 103 | | Desktop | Mobile | 104 | | - | - | 105 | | ![Screenshot of the separate timeline Control Panel for Twitter adds to desktop Twitter, configured to separate Retweets from the rest of the home timeline](screenshots/shared_tweets.png) | ![Screenshot of the separate timeline Control Panel for Twitter adds to mobile Twitter, configured to separate Retweets from the rest of the home timeline](screenshots/firefox_android_shared_tweets.jpg) | 106 | 107 | ### Full-width timeline 108 | 109 | | Desktop only | 110 | | - | 111 | | ![Screenshot of a Twitter timeline which takes up all the available width in the layout](screenshots/full_width_timeline.png) | 112 | 113 | ### Tidied-up menu, with instant access to "Add muted word" 114 | 115 | | Desktop - "More" menu | Mobile - slide-out menu | 116 | | - | - | 117 | | ![Screenshot of the "More" menu on desktop Twitter, with most of the menu items removed and a new "Add muted word" menu item](screenshots/more_menu.png) | ![Screenshot of the slide-out menu on mobile Twitter, with most of the menu items removed and a new "Add muted word" menu item](screenshots/firefox_android_menu.jpg) | 118 | 119 | ### Hide metrics 120 | 121 | | Desktop | Mobile | 122 | | - | - | 123 | | ![Scteenshot of a Twitter timeline with blank spaces where numbers for metrics should be](screenshots/hide_metrics.png) | ![Sceenshot of a mobile Twitter timeline with blank spaces where numbers for metrics should be](screenshots/firefox_android_hide_metrics.jpg) | 124 | 125 | ### Uninverted Follow buttons 126 | 127 | | Monochrome | Themed | 128 | | - | - | 129 | | ![Uninverted Follow / Following buttons using the new monochrome Twitter style](screenshots/uninverted_follow_buttons_monochrome.png) | ![Uninverted Follow / Following buttons using the classic themed Twitter style](screenshots/uninverted_follow_buttons_themed.png) | 130 | 131 | ### Disable use of Chirp font 132 | 133 | | Chirp on | Chirp off | 134 | | - | - | 135 | | ![A Twitter thread using the Chirp font](screenshots/chirp_on.png) | ![The same Twitter thread using the fallback system fonts](screenshots/chirp_off.png) | 136 | 137 | ### Improved Quote Tweets page 138 | 139 | The quoted tweet is hidden, instead of being duplicated under every quote, leaving more room for quotes 140 | 141 | | Desktop | Mobile | 142 | | - | - | 143 | | ![Screenshot of the improvements Control Panel for Twitter makes to Quote Tweet pages on desktop, showing quote content only instead of repeating the quoted tweet in every tweet](screenshots/quote_tweets.png) | ![Screenshot of the improvements Control Panel for Twitter makes to Quote Tweet pages on mobile, showing quote content only instead of repeating the quoted tweet in every tweet](screenshots/firefox_android_quote_tweets.jpg) | 144 | 145 | ### Reduced interaction mode 146 | 147 | | Desktop | Mobile | 148 | | - | - | 149 | | ![Screenshot of a Twitter timeline with the action bar below each tweet completely missing](screenshots/reduced_interaction_mode.png) | ![Screenshot of a Twitter timeline in Firefox on Android with the action bar below each tweet completely missing](screenshots/firefox_android_reduced_interaction_mode.jpg) | 150 | 151 | ## Disable the home timeline 152 | 153 | | Desktop | Mobile | 154 | | - | - | 155 | | ![Screenshot of Twitter without the Home navigation item](screenshots/disable_home_timeline.png) | ![Screenshot of Twitter in Firefox on Android without the Home navigation item](screenshots/firefox_android_disable_home_timeline.jpg) | 156 | 157 | ### Configurable via options popup and the extension options page 158 | 159 | | Desktop | Mobile | 160 | | - | - | 161 | | ![Screenshot of the options popup in Chrome on desktop](screenshots/options_popup.png) | ![Screenshot of the options popup in Firefox on Android on Android](screenshots/firefox_android_options_popup.jpg) | 162 | 163 | ### No trends on Explore screen, just search 164 | 165 | | Mobile | 166 | | - | 167 | | ![Screenshot of the Explore screen in mobile Twitter, with only the search part of the screen visible](screenshots/firefox_android_explore.jpg) | 168 | 169 | ### Language support 170 | 171 | As of v2.2, all 48 of the display languages available on Twitter are supported, some examples: 172 | 173 | | Gaeilge (Irish) | 日本語 (Japanese) | العربية (Arabic) | 174 | | - | - | - | 175 | | ![Screenshot of a desktop Twitter home timeline using Control Panel for Twitter, as Gaeilge](screenshots/irish.png) | ![Screenshot of a desktop Twitter home timeline using Control Panel for Twitter, in Japanese](screenshots/japanese.png) | ![Screenshot of a desktop Twitter home timeline using Control Panel for Twitter, in Arabic](screenshots/arabic.png) | 176 | 177 | Options are also available in the following languages: 178 | 179 | - French (translation by [@THEDARKK](https://github.com/THEDARKK), [@Alerymin](https://github.com/Alerymin), [@luclu7](https://github.com/luclu7)) 180 | - Italian (translation by [@katullo11](https://github.com/katullo11)) 181 | - Japanese (translation by [@MitoKurato](https://github.com/MitoKurato)) 182 | - Korean 183 | - Simplified Chinese (translation by [@CodeQiu](https://github.com/CodeQiu)) 184 | - Spanish (translation by [@rogama25](https://github.com/rogama25)) 185 | 186 | ### User script support 187 | 188 | [Control Panel for Twitter is also available as a user script](https://greasyfork.org/en/scripts/387773-control-panel-for-twitter) – to change the default options, you'll need to edit the `config` object at the top of the script. 189 | 190 | ## Attribution 191 | 192 | Icon adapted from "Ibis icon" by [Delapouite](https://delapouite.com/) from [game-icons.net](https://game-icons.net), [CC 3.0 BY](https://creativecommons.org/licenses/by/3.0/) 193 | -------------------------------------------------------------------------------- /_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "addAddMutedWordMenuItemLabel_desktop": { 3 | "message": "Add \"Add muted word\" to the \"More\" menu" 4 | }, 5 | "addAddMutedWordMenuItemLabel_mobile": { 6 | "message": "Add \"Add muted word\" to the slide-out menu" 7 | }, 8 | "alwaysUseLatestTweetsLabel": { 9 | "message": "Use the \"Following\" (chronological) timeline by default" 10 | }, 11 | "appStoreSubtitle": { 12 | "message": "Take control of your timeline", 13 | "description": "<= 30 characters" 14 | }, 15 | "customCssLabel": { 16 | "message": "Custom CSS" 17 | }, 18 | "debugInfo": { 19 | "message": "Enables debug logging and displays tweet debug info in the timeline" 20 | }, 21 | "debugLabel": { 22 | "message": "Debug mode" 23 | }, 24 | "debugLogTimelineStatsLabel": { 25 | "message": "Log timeline stats" 26 | }, 27 | "debugOptionsLabel": { 28 | "message": "Debug options" 29 | }, 30 | "defaultToLatestSearchLabel": { 31 | "message": "Default to \"Latest\" tab in Search" 32 | }, 33 | "disableHomeTimelineInfo": { 34 | "message": "Find yourself wasting too much time on Twitter? Try preventing use of the home timeline" 35 | }, 36 | "disableHomeTimelineLabel": { 37 | "message": "Disable the home timeline" 38 | }, 39 | "disableTweetTextFormattingLabel": { 40 | "message": "Disable bold and italic text in tweets" 41 | }, 42 | "disabledHomeTimelineRedirectLabel": { 43 | "message": "Redirect home timeline to" 44 | }, 45 | "disabledHomeTimelineRedirectOption_messages": { 46 | "message": "Messages" 47 | }, 48 | "dontUseChirpFontLabel": { 49 | "message": "Don't use the Chirp font" 50 | }, 51 | "dropdownMenuFontWeightLabel": { 52 | "message": "Use normal font weight in dropdown menus" 53 | }, 54 | "enabled": { 55 | "message": "Enabled" 56 | }, 57 | "experimentsOptionsLabel": { 58 | "message": "Experiments" 59 | }, 60 | "exportConfigLabel": { 61 | "message": "Export configuration for bug report" 62 | }, 63 | "extensionDescription": { 64 | "message": "Gives you more control over Twitter and adds missing features and UI improvements", 65 | "description": "<= 132 characters" 66 | }, 67 | "extensionDescriptionShort": { 68 | "message": "Gives you more control over Twitter and adds missing features and UI improvements", 69 | "description": "<= 112 characters" 70 | }, 71 | "extensionName": { 72 | "message": "Control Panel for Twitter" 73 | }, 74 | "extensionNameDisabled": { 75 | "message": "Control Panel for Twitter (disabled)" 76 | }, 77 | "fastBlockLabel": { 78 | "message": "Fast blocking (skips confirm dialog)" 79 | }, 80 | "features": { 81 | "message": "Features" 82 | }, 83 | "followButtonStyleLabel": { 84 | "message": "Button style" 85 | }, 86 | "followButtonStyleOption_monochrome": { 87 | "message": "Monochrome" 88 | }, 89 | "followButtonStyleOption_themed": { 90 | "message": "Themed" 91 | }, 92 | "fullWidthContentInfo": { 93 | "message": "Hide the sidebar and let timeline content go full-width" 94 | }, 95 | "fullWidthContentLabel": { 96 | "message": "Full-width timeline content" 97 | }, 98 | "fullWidthMediaLabel": { 99 | "message": "Full-width media & cards" 100 | }, 101 | "hideAccountSwitcherLabel": { 102 | "message": "Account switcher" 103 | }, 104 | "hideAdsNavLabel": { 105 | "message": "Ads" 106 | }, 107 | "hideAllMetricsLabel": { 108 | "message": "Hide all" 109 | }, 110 | "hideBookmarkButtonLabel": { 111 | "message": "Bookmark button under tweets" 112 | }, 113 | "hideBookmarkMetricsLabel": { 114 | "message": "Bookmarks" 115 | }, 116 | "hideBookmarksNavLabel": { 117 | "message": "Bookmarks" 118 | }, 119 | "hideCommunitiesNavLabel": { 120 | "message": "Communities" 121 | }, 122 | "hideComposeTweetLabel": { 123 | "message": "Hide the Compose Tweet button" 124 | }, 125 | "hideDiscoverSuggestionsLabel": { 126 | "message": "Hide \"Discover\" suggestions" 127 | }, 128 | "hideExploreNavLabel": { 129 | "message": "Explore" 130 | }, 131 | "hideExploreNavWithSidebarLabel": { 132 | "message": "Show when sidebar is hidden" 133 | }, 134 | "hideExplorePageContentsLabel": { 135 | "message": "Hide Explore page contents and use it only for searching" 136 | }, 137 | "hideFollowingMetricsLabel": { 138 | "message": "Following / followers" 139 | }, 140 | "hideForYouTimelineLabel": { 141 | "message": "Hide the \"For you\" (algorithmic) timeline" 142 | }, 143 | "hideGrok": { 144 | "message": "Hide Grok" 145 | }, 146 | "hideGrokLabel": { 147 | "message": "Hide Grok" 148 | }, 149 | "hideGrokTweetsLabel": { 150 | "message": "Hide Grok tweets" 151 | }, 152 | "hideInlinePrompts": { 153 | "message": "Hide inline prompts in the timeline" 154 | }, 155 | "hideJobsLabel": { 156 | "message": "Hide Jobs" 157 | }, 158 | "hideLikeMetricsLabel": { 159 | "message": "Likes" 160 | }, 161 | "hideListsNavLabel": { 162 | "message": "Lists" 163 | }, 164 | "hideLiveBroadcastBarLabel": { 165 | "message": "Hide Live broadcast bar" 166 | }, 167 | "hideLiveBroadcastsLabel": { 168 | "message": "Hide Live broadcasts" 169 | }, 170 | "hideMessagesBottomNavItemLabel": { 171 | "message": "Messages" 172 | }, 173 | "hideMessagesDrawerLabel": { 174 | "message": "Messages drawer" 175 | }, 176 | "hideMetricsLabel": { 177 | "message": "Hide metrics" 178 | }, 179 | "hideMonetizationNavLabel": { 180 | "message": "Monetization" 181 | }, 182 | "hideMoreSlideOutMenuItemsOptionsLabel_desktop": { 183 | "message": "Hide \"More\" menu items you don't use" 184 | }, 185 | "hideMoreSlideOutMenuItemsOptionsLabel_mobile": { 186 | "message": "Hide slide-out menu items you don't use" 187 | }, 188 | "hideNotificationsLabel": { 189 | "message": "Hide notifications" 190 | }, 191 | "hideProfileHeaderMetricsLabel": { 192 | "message": "Profile header metrics" 193 | }, 194 | "hideProfileRetweetsLabel": { 195 | "message": "Hide Retweets in user profiles" 196 | }, 197 | "hideQuoteTweetMetricsLabel": { 198 | "message": "Quote tweets" 199 | }, 200 | "hideQuotesFromLabel": { 201 | "message": "Muted users ($COUNT$)", 202 | "placeholders": { 203 | "count": { 204 | "content": "$1", 205 | "example": "1" 206 | } 207 | } 208 | }, 209 | "hideReplyMetricsLabel": { 210 | "message": "Replies" 211 | }, 212 | "hideRetweetMetricsLabel": { 213 | "message": "Retweets" 214 | }, 215 | "hideSeeNewTweetsLabel": { 216 | "message": "Hide \"See new Tweets\"" 217 | }, 218 | "hideShareTweetButtonLabel": { 219 | "message": "Share button under tweets" 220 | }, 221 | "hideSidebarContentLabel": { 222 | "message": "Hide sidebar contents" 223 | }, 224 | "hideSpacesNavLabel": { 225 | "message": "Create your Space" 226 | }, 227 | "hideSubscriptionsLabel": { 228 | "message": "Hide Subscriptions" 229 | }, 230 | "hideSuggestedFollowsLabel": { 231 | "message": "Hide suggested follows" 232 | }, 233 | "hideTimelineTweetBoxLabel": { 234 | "message": "Tweet box in timeline" 235 | }, 236 | "hideToggleNavigationLabel": { 237 | "message": "Hide Toggle navigation" 238 | }, 239 | "hideTweetAnalyticsLinksLabel": { 240 | "message": "\"View post engagements\" under your tweets" 241 | }, 242 | "hideTwitterBlueRepliesLabel": { 243 | "message": "Hide Premium blue check replies" 244 | }, 245 | "hideTwitterBlueUpsellsLabel": { 246 | "message": "Hide Premium upsells" 247 | }, 248 | "hideUnavailableQuoteTweetsLabel": { 249 | "message": "Hide quotes and replies to blocked and muted accounts" 250 | }, 251 | "hideUnusedUiItemsOptionsLabel": { 252 | "message": "Hide UI items you don't use" 253 | }, 254 | "hideVerifiedNotificationsTabLabel": { 255 | "message": "Hide \"Verified\" Notifications and Followers tabs" 256 | }, 257 | "hideViewsLabel": { 258 | "message": "Hide Views under tweets" 259 | }, 260 | "hideWhatsHappeningLabel": { 261 | "message": "Hide What's happening" 262 | }, 263 | "hideWhoToFollowEtcLabel": { 264 | "message": "Hide \"Who to follow\", \"Follow some Topics\" etc. in the timeline" 265 | }, 266 | "homeTimelineOptionsLabel": { 267 | "message": "Home timeline" 268 | }, 269 | "listRetweetsLabel": { 270 | "message": "Retweets in Lists" 271 | }, 272 | "mutableQuoteTweetsLabel": { 273 | "message": "Enable muting of Quote Tweets" 274 | }, 275 | "mutedTweetsLabel": { 276 | "message": "Muted tweets ($COUNT$)", 277 | "placeholders": { 278 | "count": { 279 | "content": "$1", 280 | "example": "1" 281 | } 282 | } 283 | }, 284 | "navBaseFontSizeLabel": { 285 | "message": "Use normal text font style in navigation bar" 286 | }, 287 | "navDensityLabel": { 288 | "message": "Navigation density" 289 | }, 290 | "notificationsLabel": { 291 | "message": "Notifications" 292 | }, 293 | "option_badges": { 294 | "message": "Hide badges only" 295 | }, 296 | "option_comfortable": { 297 | "message": "Comfortable" 298 | }, 299 | "option_compact": { 300 | "message": "Compact" 301 | }, 302 | "option_default": { 303 | "message": "Default" 304 | }, 305 | "option_hide": { 306 | "message": "Hide", 307 | "description": "Option for hiding things" 308 | }, 309 | "option_ignore": { 310 | "message": "Do nothing", 311 | "description": "Option for not changing existing Twitter functionality - we don't use 'Ignore' for this in English as it could be mistaken to mean 'Hide'" 312 | }, 313 | "option_liked": { 314 | "message": "Likes" 315 | }, 316 | "option_recent": { 317 | "message": "Latest" 318 | }, 319 | "option_relevant": { 320 | "message": "Relevancy" 321 | }, 322 | "option_separate": { 323 | "message": "Show in separate tab", 324 | "description": "Option for showing Retweets or Quote Tweets in a separate tab from the main timeline" 325 | }, 326 | "preventNextVideoAutoplayInfo": { 327 | "message": "Videos will loop instead" 328 | }, 329 | "preventNextVideoAutoplayLabel": { 330 | "message": "Prevent next video autoplaying" 331 | }, 332 | "quoteTweetsLabel": { 333 | "message": "Quote Tweets" 334 | }, 335 | "redirectToTwitterLabel": { 336 | "message": "Redirect to twitter.com" 337 | }, 338 | "reduceAlgorithmicContentOptionsLabel": { 339 | "message": "Remove algorithmic content" 340 | }, 341 | "reduceEngagementOptionsLabel": { 342 | "message": "Reduce \"engagement\"" 343 | }, 344 | "reducedInteractionModeInfo": { 345 | "message": "Hide the action bar under tweets – replies are now the only means of interacting" 346 | }, 347 | "reducedInteractionModeLabel": { 348 | "message": "Reduced interaction mode" 349 | }, 350 | "replaceLogoLabel": { 351 | "message": "Replace X branding changes" 352 | }, 353 | "restoreLinkHeadlinesLabel": { 354 | "message": "Restore headlines under external links" 355 | }, 356 | "restoreOtherInteractionLinksLabel": { 357 | "message": "Restore other links under Tweets" 358 | }, 359 | "restoreQuoteTweetsLinkLabel": { 360 | "message": "Restore Quote Tweets link under Tweets" 361 | }, 362 | "restoreTweetSourceLabel": { 363 | "message": "Restore Tweet source label" 364 | }, 365 | "retweetsLabel": { 366 | "message": "Retweets" 367 | }, 368 | "saveAndApplyButton": { 369 | "message": "Save and apply" 370 | }, 371 | "sharedTweetsOptionsLabel": { 372 | "message": "Tweets shared by other users" 373 | }, 374 | "showBlueReplyFollowersCountAmountLabel": { 375 | "message": "Number of followers" 376 | }, 377 | "showBlueReplyFollowersCountLabel": { 378 | "message": "Show accounts with over $AMOUNT$ followers", 379 | "placeholders": { 380 | "amount": { 381 | "content": "$1", 382 | "example": "1 million" 383 | } 384 | } 385 | }, 386 | "showBookmarkButtonUnderFocusedTweetsLabel": { 387 | "message": "Show under focused tweets" 388 | }, 389 | "showPremiumReplyBusinessLabel": { 390 | "message": "Show verified Business accounts" 391 | }, 392 | "showPremiumReplyFollowedByLabel": { 393 | "message": "Show accounts which follow me" 394 | }, 395 | "showPremiumReplyFollowingLabel": { 396 | "message": "Show accounts I follow" 397 | }, 398 | "showPremiumReplyGovernmentLabel": { 399 | "message": "Show verified Government accounts" 400 | }, 401 | "showRelevantPeopleLabel": { 402 | "message": "Show \"Relevant people\" when viewing a tweet" 403 | }, 404 | "sidebarLabel": { 405 | "message": "Sidebar" 406 | }, 407 | "sortRepliesLabel": { 408 | "message": "Default sorting of replies" 409 | }, 410 | "tweakNewLayoutInfo": { 411 | "message": "Experimental - only enable if you have the new layout" 412 | }, 413 | "tweakNewLayoutLabel": { 414 | "message": "Tweak new layout" 415 | }, 416 | "tweakQuoteTweetsPageLabel": { 417 | "message": "Hide the quoted tweet when viewing Quote Tweets" 418 | }, 419 | "twitterBlueChecksLabel": { 420 | "message": "Premium blue checks" 421 | }, 422 | "twitterBlueChecksOption_replace": { 423 | "message": "Replace with Twitter Blue logo" 424 | }, 425 | "uiImprovementsOptionsLabel": { 426 | "message": "UI improvements" 427 | }, 428 | "uiTweaksOptionsLabel": { 429 | "message": "UI tweaks" 430 | }, 431 | "unblurSensitiveContentLabel": { 432 | "message": "Unblur sensitive content" 433 | }, 434 | "uninvertFollowButtonsLabel": { 435 | "message": "Uninvert Follow / Following buttons" 436 | }, 437 | "unmuteButtonText": { 438 | "message": "Unmute", 439 | "description": "Button used in the options page to unmute a muted Quote Tweet" 440 | }, 441 | "xFixesLabel": { 442 | "message": "X fixes" 443 | } 444 | } -------------------------------------------------------------------------------- /_locales/es/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "addAddMutedWordMenuItemLabel_desktop": { 3 | "message": "Añade \"Añadir palabra silenciada\" al menú Más" 4 | }, 5 | "addAddMutedWordMenuItemLabel_mobile": { 6 | "message": "Añade \"Añadir palabra silenciada\" al menú hamburguesa" 7 | }, 8 | "alwaysUseLatestTweetsLabel": { 9 | "message": "Usar la timeline cronológica (Siguiendo) por defecto" 10 | }, 11 | "appStoreSubtitle": { 12 | "message": "Controla tu línea de tiempo" 13 | }, 14 | "customCssLabel": { 15 | "message": "CSS personalizado" 16 | }, 17 | "debugInfo": { 18 | "message": "Activa los registros de debug y muestra estadísticas de debug en los tweets del Inicio" 19 | }, 20 | "debugLabel": { 21 | "message": "Modo de desarrollo (debug)" 22 | }, 23 | "debugLogTimelineStatsLabel": { 24 | "message": "Registrar stats de timeline" 25 | }, 26 | "debugOptionsLabel": { 27 | "message": "Opciones de desarrollo (debug)" 28 | }, 29 | "defaultToLatestSearchLabel": { 30 | "message": "Por defecto a \"Más reciente\" en Buscar" 31 | }, 32 | "disableHomeTimelineInfo": { 33 | "message": "¿Pasas demasiado tiempo en Twitter? Desactiva la página de inicio para que no puedas acceder a ella" 34 | }, 35 | "disableHomeTimelineLabel": { 36 | "message": "Desactivar la página de inicio" 37 | }, 38 | "disableTweetTextFormattingLabel": { 39 | "message": "Deshabilitar texto en negrita e itálica en los tweets" 40 | }, 41 | "disabledHomeTimelineRedirectLabel": { 42 | "message": "Redirigir el inicio a:" 43 | }, 44 | "disabledHomeTimelineRedirectOption_messages": { 45 | "message": "Mensajes" 46 | }, 47 | "dontUseChirpFontLabel": { 48 | "message": "No usar la fuente Chirp" 49 | }, 50 | "dropdownMenuFontWeightLabel": { 51 | "message": "Usar grosor normal de fuentes en desplegables" 52 | }, 53 | "enabled": { 54 | "message": "Habilitado" 55 | }, 56 | "experimentsOptionsLabel": { 57 | "message": "Experimentos" 58 | }, 59 | "exportConfigLabel": { 60 | "message": "Exportar configuración para informe de errores" 61 | }, 62 | "extensionDescription": { 63 | "message": "Le brinda más control sobre Twitter y agrega funciones faltantes y mejoras en la interfaz" 64 | }, 65 | "extensionDescriptionShort": { 66 | "message": "Le brinda más control sobre Twitter y agrega funciones faltantes y mejoras en la interfaz" 67 | }, 68 | "extensionName": { 69 | "message": "Control Panel for Twitter" 70 | }, 71 | "extensionNameDisabled": { 72 | "message": "Control Panel for Twitter (deshabilitado)" 73 | }, 74 | "fastBlockLabel": { 75 | "message": "Bloqueo rápido (no muestra menú de confirmación)" 76 | }, 77 | "features": { 78 | "message": "Características" 79 | }, 80 | "followButtonStyleLabel": { 81 | "message": "Estilo de botones" 82 | }, 83 | "followButtonStyleOption_monochrome": { 84 | "message": "Monocromo" 85 | }, 86 | "followButtonStyleOption_themed": { 87 | "message": "Tematizados" 88 | }, 89 | "fullWidthContentInfo": { 90 | "message": "Ocultar la barra lateral y expandir el contenido de la timeline a todo el ancho de la ventana" 91 | }, 92 | "fullWidthContentLabel": { 93 | "message": "Timeline de ancho completo" 94 | }, 95 | "fullWidthMediaLabel": { 96 | "message": "Multimedia y tarjetas de ancho completo" 97 | }, 98 | "hideAccountSwitcherLabel": { 99 | "message": "Cambiador de cuentas" 100 | }, 101 | "hideAdsNavLabel": { 102 | "message": "Anuncios" 103 | }, 104 | "hideAllMetricsLabel": { 105 | "message": "Ocultar todo" 106 | }, 107 | "hideBookmarkButtonLabel": { 108 | "message": "Botón de guardados debajo de los tweets" 109 | }, 110 | "hideBookmarkMetricsLabel": { 111 | "message": "Guardados" 112 | }, 113 | "hideBookmarksNavLabel": { 114 | "message": "Guardados" 115 | }, 116 | "hideCommunitiesNavLabel": { 117 | "message": "Comunidades" 118 | }, 119 | "hideComposeTweetLabel": { 120 | "message": "Ocultar el botón de Redactar Tweet" 121 | }, 122 | "hideDiscoverSuggestionsLabel": { 123 | "message": "Ocultar sugerencias de \"Descubrir\"" 124 | }, 125 | "hideExploreNavLabel": { 126 | "message": "Explorar" 127 | }, 128 | "hideExploreNavWithSidebarLabel": { 129 | "message": "Mostrar si barra lateral está oculta" 130 | }, 131 | "hideExplorePageContentsLabel": { 132 | "message": "Ocultar contenidos de Explorar y usarlo únicamente para buscar" 133 | }, 134 | "hideFollowingMetricsLabel": { 135 | "message": "Siguiendo / Seguidores" 136 | }, 137 | "hideForYouTimelineLabel": { 138 | "message": "Ocultar la timeline algorítmica (Para ti)" 139 | }, 140 | "hideGrok": { 141 | "message": "Ocultar Grok" 142 | }, 143 | "hideGrokLabel": { 144 | "message": "Ocultar Grok" 145 | }, 146 | "hideGrokTweetsLabel": { 147 | "message": "Ocultar tweets de Grok" 148 | }, 149 | "hideInlinePrompts": { 150 | "message": "Ocultar indicaciones en línea en la timeline" 151 | }, 152 | "hideJobsLabel": { 153 | "message": "Ocultar Trabajos" 154 | }, 155 | "hideLikeMetricsLabel": { 156 | "message": "Me gustas" 157 | }, 158 | "hideListsNavLabel": { 159 | "message": "Listas" 160 | }, 161 | "hideLiveBroadcastBarLabel": { 162 | "message": "Ocultar barra de transmisión en vivo" 163 | }, 164 | "hideLiveBroadcastsLabel": { 165 | "message": "Ocultar transmisiones en vivo" 166 | }, 167 | "hideMessagesBottomNavItemLabel": { 168 | "message": "Mensajes" 169 | }, 170 | "hideMessagesDrawerLabel": { 171 | "message": "Bandeja de mensajes" 172 | }, 173 | "hideMetricsLabel": { 174 | "message": "Ocultar métricas" 175 | }, 176 | "hideMonetizationNavLabel": { 177 | "message": "Monetización" 178 | }, 179 | "hideMoreSlideOutMenuItemsOptionsLabel_desktop": { 180 | "message": "Ocultar elementos no usados en el menú \"Más\"" 181 | }, 182 | "hideMoreSlideOutMenuItemsOptionsLabel_mobile": { 183 | "message": "Ocultar elementos no usados en el menú hamburguesa" 184 | }, 185 | "hideNotificationsLabel": { 186 | "message": "Ocultar notificaciones" 187 | }, 188 | "hideProfileHeaderMetricsLabel": { 189 | "message": "Métricas del encabezado del perfil" 190 | }, 191 | "hideProfileRetweetsLabel": { 192 | "message": "Ocultar Retweets en los perfiles de usuario" 193 | }, 194 | "hideQuoteTweetMetricsLabel": { 195 | "message": "Citados" 196 | }, 197 | "hideQuotesFromLabel": { 198 | "message": "Usuarios silenciados ($COUNT$)", 199 | "placeholders": { 200 | "count": { 201 | "content": "$1", 202 | "example": "1" 203 | } 204 | } 205 | }, 206 | "hideReplyMetricsLabel": { 207 | "message": "Respuestas" 208 | }, 209 | "hideRetweetMetricsLabel": { 210 | "message": "Retweets" 211 | }, 212 | "hideSeeNewTweetsLabel": { 213 | "message": "Ocultar \"Ver Tweets nuevos\"" 214 | }, 215 | "hideShareTweetButtonLabel": { 216 | "message": "Botón de compartir debajo de los tweets" 217 | }, 218 | "hideSidebarContentLabel": { 219 | "message": "Ocultar contenido de la barra lateral" 220 | }, 221 | "hideSpacesNavLabel": { 222 | "message": "Crear tu Espacio" 223 | }, 224 | "hideSubscriptionsLabel": { 225 | "message": "Ocultar Suscripciones" 226 | }, 227 | "hideSuggestedFollowsLabel": { 228 | "message": "Ocultar seguimientos sugeridos" 229 | }, 230 | "hideTimelineTweetBoxLabel": { 231 | "message": "Cuadro de tweet en timeline" 232 | }, 233 | "hideToggleNavigationLabel": { 234 | "message": "Ocultar activar/desactivar navegación" 235 | }, 236 | "hideTweetAnalyticsLinksLabel": { 237 | "message": "\"Ver las interacciones de post\" debajo de tus tweets" 238 | }, 239 | "hideTwitterBlueRepliesLabel": { 240 | "message": "Ocultar respuestas de cheque azul Premium" 241 | }, 242 | "hideTwitterBlueUpsellsLabel": { 243 | "message": "Ocultar promociones de Premium" 244 | }, 245 | "hideUnavailableQuoteTweetsLabel": { 246 | "message": "Ocultar citas y respuestas a cuentas bloqueadas y silenciadas" 247 | }, 248 | "hideUnusedUiItemsOptionsLabel": { 249 | "message": "Ocultar elementos de interfaz no utilizados" 250 | }, 251 | "hideVerifiedNotificationsTabLabel": { 252 | "message": "Ocultar pestañas \"Verificado\" en Notificaciones y Seguidores" 253 | }, 254 | "hideViewsLabel": { 255 | "message": "Ocultar Reproducciones de tweets" 256 | }, 257 | "hideWhatsHappeningLabel": { 258 | "message": "Ocultar Qué está pasando" 259 | }, 260 | "hideWhoToFollowEtcLabel": { 261 | "message": "Ocultar \"A quién seguir\", \"Seguir temas\" etc. en la timeline" 262 | }, 263 | "homeTimelineOptionsLabel": { 264 | "message": "Cronología de inicio" 265 | }, 266 | "listRetweetsLabel": { 267 | "message": "Retuits en Listas" 268 | }, 269 | "mutableQuoteTweetsLabel": { 270 | "message": "Habilitar el silenciado de Tweets citados" 271 | }, 272 | "mutedTweetsLabel": { 273 | "message": "Tweets silenciados ($COUNT$)", 274 | "placeholders": { 275 | "count": { 276 | "content": "$1", 277 | "example": "1" 278 | } 279 | } 280 | }, 281 | "navBaseFontSizeLabel": { 282 | "message": "Usar el estilo de fuente normal en la barra de navegación" 283 | }, 284 | "navDensityLabel": { 285 | "message": "Densidad de navegación" 286 | }, 287 | "notificationsLabel": { 288 | "message": "Notificaciones" 289 | }, 290 | "option_badges": { 291 | "message": "Ocultar solo las insignias" 292 | }, 293 | "option_comfortable": { 294 | "message": "Cómodo" 295 | }, 296 | "option_compact": { 297 | "message": "Compacto" 298 | }, 299 | "option_default": { 300 | "message": "Predet." 301 | }, 302 | "option_hide": { 303 | "message": "Ocultar" 304 | }, 305 | "option_ignore": { 306 | "message": "No cambiar" 307 | }, 308 | "option_liked": { 309 | "message": "Me gusta" 310 | }, 311 | "option_recent": { 312 | "message": "Más reciente" 313 | }, 314 | "option_relevant": { 315 | "message": "Relevancia" 316 | }, 317 | "option_separate": { 318 | "message": "Mostrar en pestaña aparte" 319 | }, 320 | "preventNextVideoAutoplayInfo": { 321 | "message": "Los videos se repetirán en su lugar" 322 | }, 323 | "preventNextVideoAutoplayLabel": { 324 | "message": "Evitar la reproducción automática del siguiente video" 325 | }, 326 | "quoteTweetsLabel": { 327 | "message": "Citados" 328 | }, 329 | "redirectToTwitterLabel": { 330 | "message": "Redirigir a twitter.com" 331 | }, 332 | "reduceAlgorithmicContentOptionsLabel": { 333 | "message": "Eliminar contenido algorítmico" 334 | }, 335 | "reduceEngagementOptionsLabel": { 336 | "message": "Reducir el \"compromiso\"" 337 | }, 338 | "reducedInteractionModeInfo": { 339 | "message": "Oculta la barra de interacción debajo de los tweets - las respuestas es la única opción disponible" 340 | }, 341 | "reducedInteractionModeLabel": { 342 | "message": "Modo de interacción reducida" 343 | }, 344 | "replaceLogoLabel": { 345 | "message": "Reemplazar X cambios de marca" 346 | }, 347 | "restoreLinkHeadlinesLabel": { 348 | "message": "Restaurar titulares bajo enlaces externos" 349 | }, 350 | "restoreOtherInteractionLinksLabel": { 351 | "message": "Restaurar otro enlaces debajo Tweets" 352 | }, 353 | "restoreQuoteTweetsLinkLabel": { 354 | "message": "Restaurar el enlace de Tweets citados debajo Tweets" 355 | }, 356 | "restoreTweetSourceLabel": { 357 | "message": "Restaurar etiqueta de fuente del Tweet" 358 | }, 359 | "retweetsLabel": { 360 | "message": "Retweets" 361 | }, 362 | "saveAndApplyButton": { 363 | "message": "Guardar y aplicar" 364 | }, 365 | "sharedTweetsOptionsLabel": { 366 | "message": "Tweets compartidos por otros usuarios" 367 | }, 368 | "showBlueReplyFollowersCountAmountLabel": { 369 | "message": "Número de seguidores" 370 | }, 371 | "showBlueReplyFollowersCountLabel": { 372 | "message": "Mostrar cuentas con más de $AMOUNT$ seguidores", 373 | "placeholders": { 374 | "amount": { 375 | "content": "$1" 376 | } 377 | } 378 | }, 379 | "showBookmarkButtonUnderFocusedTweetsLabel": { 380 | "message": "Mostrar debajo de los tweets destacados" 381 | }, 382 | "showPremiumReplyBusinessLabel": { 383 | "message": "Mostrar cuentas de empresa verificadas" 384 | }, 385 | "showPremiumReplyFollowedByLabel": { 386 | "message": "Mostrar cuentas que me siguen" 387 | }, 388 | "showPremiumReplyFollowingLabel": { 389 | "message": "Mostrar cuentas que sigo" 390 | }, 391 | "showPremiumReplyGovernmentLabel": { 392 | "message": "Mostrar cuentas gubernamentales verificadas" 393 | }, 394 | "showRelevantPeopleLabel": { 395 | "message": "Mostrar \"Personas relevantes\" al ver un tweet" 396 | }, 397 | "sidebarLabel": { 398 | "message": "Barra lateral" 399 | }, 400 | "sortRepliesLabel": { 401 | "message": "Orden predeterminado de las respuestas" 402 | }, 403 | "tweakNewLayoutInfo": { 404 | "message": "Experimental - solo activar si tienes el nuevo diseño" 405 | }, 406 | "tweakNewLayoutLabel": { 407 | "message": "Ajustar nuevo diseño" 408 | }, 409 | "tweakQuoteTweetsPageLabel": { 410 | "message": "Ocultar el tweet citado en la página de citados" 411 | }, 412 | "twitterBlueChecksLabel": { 413 | "message": "Marcas de verificación azules Premium" 414 | }, 415 | "twitterBlueChecksOption_replace": { 416 | "message": "Cambiar por el logo de Twitter Blue" 417 | }, 418 | "uiImprovementsOptionsLabel": { 419 | "message": "Mejoras de interfaz" 420 | }, 421 | "uiTweaksOptionsLabel": { 422 | "message": "Cambios de interfaz" 423 | }, 424 | "unblurSensitiveContentLabel": { 425 | "message": "Quitar el desenfoque de contenido sensible" 426 | }, 427 | "uninvertFollowButtonsLabel": { 428 | "message": "No invertir botones de Seguir/Siguiendo" 429 | }, 430 | "unmuteButtonText": { 431 | "message": "Dejar de silenciar" 432 | }, 433 | "xFixesLabel": { 434 | "message": "Correcciones de X" 435 | } 436 | } -------------------------------------------------------------------------------- /_locales/fr/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "addAddMutedWordMenuItemLabel_desktop": { 3 | "message": "Ajouter \"Ajouter un mot masqué\" au menu \"Plus\"" 4 | }, 5 | "addAddMutedWordMenuItemLabel_mobile": { 6 | "message": "Ajouter \"Ajouter un mot masqué\" au menu déroulant" 7 | }, 8 | "alwaysUseLatestTweetsLabel": { 9 | "message": "Utiliser le fil \"Abonnements\" (chronologique) par défaut" 10 | }, 11 | "appStoreSubtitle": { 12 | "message": "Contrôlez votre fil" 13 | }, 14 | "customCssLabel": { 15 | "message": "CSS personnalisé" 16 | }, 17 | "debugInfo": { 18 | "message": "Active la journalisation du débogage et affiche les informations de débogage du tweet dans la ligne de temps" 19 | }, 20 | "debugLabel": { 21 | "message": "Mode de débogage (debug)" 22 | }, 23 | "debugLogTimelineStatsLabel": { 24 | "message": "Logger stats chronologie" 25 | }, 26 | "debugOptionsLabel": { 27 | "message": "Options de débogage (debug)" 28 | }, 29 | "defaultToLatestSearchLabel": { 30 | "message": "Utiliser l'onglet \"Récent\" par défaut dans la recherche" 31 | }, 32 | "disableHomeTimelineInfo": { 33 | "message": "Vous perdez trop de temps sur Twitter ? Essayez d'empêcher l'utilisation du fil Accueil" 34 | }, 35 | "disableHomeTimelineLabel": { 36 | "message": "Désactiver le fil Accueil" 37 | }, 38 | "disableTweetTextFormattingLabel": { 39 | "message": "Désactiver le texte en gras et en italique dans les tweets" 40 | }, 41 | "disabledHomeTimelineRedirectLabel": { 42 | "message": "Rediriger le fil Accueil vers" 43 | }, 44 | "disabledHomeTimelineRedirectOption_messages": { 45 | "message": "Messages" 46 | }, 47 | "dontUseChirpFontLabel": { 48 | "message": "Ne pas utiliser la police Chirp" 49 | }, 50 | "dropdownMenuFontWeightLabel": { 51 | "message": "Utiliser une taille de police normale dans les menus déroulants" 52 | }, 53 | "enabled": { 54 | "message": "Activé" 55 | }, 56 | "experimentsOptionsLabel": { 57 | "message": "Fonctionnalités expérimentales" 58 | }, 59 | "exportConfigLabel": { 60 | "message": "Exporter la configuration pour un rapport de bug" 61 | }, 62 | "extensionDescription": { 63 | "message": "Vous donne plus de contrôle sur Twitter et ajoute des fonctionnalités manquantes et des améliorations de l'interface utilisateur" 64 | }, 65 | "extensionDescriptionShort": { 66 | "message": "Donne plus de contrôle sur Twitter, ajoute des fonctionnalités manquantes, améliore l'interface utilisateur" 67 | }, 68 | "extensionName": { 69 | "message": "Control Panel for Twitter" 70 | }, 71 | "extensionNameDisabled": { 72 | "message": "Control Panel for Twitter (désactivé)" 73 | }, 74 | "fastBlockLabel": { 75 | "message": "Blocage rapide (ignore la boîte de dialogue de confirmation)" 76 | }, 77 | "features": { 78 | "message": "Fonctionnalités" 79 | }, 80 | "followButtonStyleLabel": { 81 | "message": "Style de bouton" 82 | }, 83 | "followButtonStyleOption_monochrome": { 84 | "message": "Monochrome" 85 | }, 86 | "followButtonStyleOption_themed": { 87 | "message": "Thème" 88 | }, 89 | "fullWidthContentInfo": { 90 | "message": "Masquer la barre latérale et laisser le contenu du fil sur toute la largeur" 91 | }, 92 | "fullWidthContentLabel": { 93 | "message": "Contenu du fil sur toute la largeur" 94 | }, 95 | "fullWidthMediaLabel": { 96 | "message": "Médias et cartes sur toute la largeur" 97 | }, 98 | "hideAccountSwitcherLabel": { 99 | "message": "Changer de compte" 100 | }, 101 | "hideAdsNavLabel": { 102 | "message": "Publicités" 103 | }, 104 | "hideAllMetricsLabel": { 105 | "message": "Masquer tous les paramètres" 106 | }, 107 | "hideBookmarkButtonLabel": { 108 | "message": "Bouton de signet sous les tweets" 109 | }, 110 | "hideBookmarkMetricsLabel": { 111 | "message": "Signets" 112 | }, 113 | "hideBookmarksNavLabel": { 114 | "message": "Signets" 115 | }, 116 | "hideCommunitiesNavLabel": { 117 | "message": "Communautés" 118 | }, 119 | "hideComposeTweetLabel": { 120 | "message": "Masquer le bouton Rédiger un Tweet" 121 | }, 122 | "hideDiscoverSuggestionsLabel": { 123 | "message": "Masquer les suggestions \"Découvrir\"" 124 | }, 125 | "hideExploreNavLabel": { 126 | "message": "Explorer" 127 | }, 128 | "hideExploreNavWithSidebarLabel": { 129 | "message": "Afficher si la barre latérale est masquée" 130 | }, 131 | "hideExplorePageContentsLabel": { 132 | "message": "Masquer le contenu de la page Explorer et l'utiliser uniquement pour la recherche" 133 | }, 134 | "hideFollowingMetricsLabel": { 135 | "message": "Suivre / followers" 136 | }, 137 | "hideForYouTimelineLabel": { 138 | "message": "Masquer le fil \"Pour vous\" (algorithmique)" 139 | }, 140 | "hideGrok": { 141 | "message": "Masquer Grok" 142 | }, 143 | "hideGrokLabel": { 144 | "message": "Masquer Grok" 145 | }, 146 | "hideGrokTweetsLabel": { 147 | "message": "Masquer les tweets de Grok" 148 | }, 149 | "hideInlinePrompts": { 150 | "message": "Masquer les invites en ligne dans la fil" 151 | }, 152 | "hideJobsLabel": { 153 | "message": "Masquer Emplois" 154 | }, 155 | "hideLikeMetricsLabel": { 156 | "message": "J'aime" 157 | }, 158 | "hideListsNavLabel": { 159 | "message": "Listes" 160 | }, 161 | "hideLiveBroadcastBarLabel": { 162 | "message": "Masquer la barre de diffusion en direct" 163 | }, 164 | "hideLiveBroadcastsLabel": { 165 | "message": "Masquer les diffusions en direct" 166 | }, 167 | "hideMessagesBottomNavItemLabel": { 168 | "message": "Messages" 169 | }, 170 | "hideMessagesDrawerLabel": { 171 | "message": "Tiroir des messages" 172 | }, 173 | "hideMetricsLabel": { 174 | "message": "Masquer les métriques" 175 | }, 176 | "hideMonetizationNavLabel": { 177 | "message": "Monétisation" 178 | }, 179 | "hideMoreSlideOutMenuItemsOptionsLabel_desktop": { 180 | "message": "Masquer les éléments de menu que vous n'utilisez pas" 181 | }, 182 | "hideMoreSlideOutMenuItemsOptionsLabel_mobile": { 183 | "message": "Masquer les éléments inutilisés du menu latéral" 184 | }, 185 | "hideNotificationsLabel": { 186 | "message": "Masquer les notifications" 187 | }, 188 | "hideProfileHeaderMetricsLabel": { 189 | "message": "Métriques de l'en-tête du profil" 190 | }, 191 | "hideProfileRetweetsLabel": { 192 | "message": "Masquer les Retweets dans les profils d'utilisateurs" 193 | }, 194 | "hideQuoteTweetMetricsLabel": { 195 | "message": "Citations des tweets" 196 | }, 197 | "hideQuotesFromLabel": { 198 | "message": "Utilisateurs en sourdine ($COUNT$)", 199 | "placeholders": { 200 | "count": { 201 | "content": "$1", 202 | "example": "1" 203 | } 204 | } 205 | }, 206 | "hideReplyMetricsLabel": { 207 | "message": "Réponses" 208 | }, 209 | "hideRetweetMetricsLabel": { 210 | "message": "Retweets" 211 | }, 212 | "hideSeeNewTweetsLabel": { 213 | "message": "Masquer \"Voir les nouveaux Tweets\"" 214 | }, 215 | "hideShareTweetButtonLabel": { 216 | "message": "Bouton \"Partager\" sous les tweets" 217 | }, 218 | "hideSidebarContentLabel": { 219 | "message": "Masquer le contenu de la barre latérale" 220 | }, 221 | "hideSpacesNavLabel": { 222 | "message": "Créer votre Espace" 223 | }, 224 | "hideSubscriptionsLabel": { 225 | "message": "Masquer \"Souscriptions\"" 226 | }, 227 | "hideSuggestedFollowsLabel": { 228 | "message": "Masquer les suggestions de suivi" 229 | }, 230 | "hideTimelineTweetBoxLabel": { 231 | "message": "Zone de tweet dans le fil" 232 | }, 233 | "hideToggleNavigationLabel": { 234 | "message": "Masquer activer/désactiver la navigation" 235 | }, 236 | "hideTweetAnalyticsLinksLabel": { 237 | "message": "\"Voir les engagements avec le post\" sous vos tweets" 238 | }, 239 | "hideTwitterBlueRepliesLabel": { 240 | "message": "Masquer les réponses des coches bleus Premium" 241 | }, 242 | "hideTwitterBlueUpsellsLabel": { 243 | "message": "Masquer les promotions Premium" 244 | }, 245 | "hideUnavailableQuoteTweetsLabel": { 246 | "message": "Masquer les citations et les réponses aux comptes bloqués et muets" 247 | }, 248 | "hideUnusedUiItemsOptionsLabel": { 249 | "message": "Masquer les éléments de l'interface utilisateur que vous n'utilisez pas" 250 | }, 251 | "hideVerifiedNotificationsTabLabel": { 252 | "message": "Masquer les onglets \"Certifié\" dans Notifications et Abonnés" 253 | }, 254 | "hideViewsLabel": { 255 | "message": "Masquer les vues sous les tweets" 256 | }, 257 | "hideWhatsHappeningLabel": { 258 | "message": "Masquer Ce qui se passe" 259 | }, 260 | "hideWhoToFollowEtcLabel": { 261 | "message": "Masquer \"Qui suivre\", \"Suivre certains sujets\", etc. dans le fil" 262 | }, 263 | "homeTimelineOptionsLabel": { 264 | "message": "Fil d'actualités" 265 | }, 266 | "listRetweetsLabel": { 267 | "message": "Retweets dans les Listes" 268 | }, 269 | "mutableQuoteTweetsLabel": { 270 | "message": "Activer la mise en sourdine des Tweets de citation" 271 | }, 272 | "mutedTweetsLabel": { 273 | "message": "Tweets masqués ($COUNT$)", 274 | "placeholders": { 275 | "count": { 276 | "content": "$1", 277 | "example": "1" 278 | } 279 | } 280 | }, 281 | "navBaseFontSizeLabel": { 282 | "message": "Utiliser la police d'écriture normale dans la barre de navigation" 283 | }, 284 | "navDensityLabel": { 285 | "message": "Densité de navigation" 286 | }, 287 | "notificationsLabel": { 288 | "message": "Notifications" 289 | }, 290 | "option_badges": { 291 | "message": "Masquer uniquement les badges" 292 | }, 293 | "option_comfortable": { 294 | "message": "Confortable" 295 | }, 296 | "option_compact": { 297 | "message": "Compact" 298 | }, 299 | "option_default": { 300 | "message": "Par défaut" 301 | }, 302 | "option_hide": { 303 | "message": "Masquer" 304 | }, 305 | "option_ignore": { 306 | "message": "Ne rien faire" 307 | }, 308 | "option_liked": { 309 | "message": "J'aime" 310 | }, 311 | "option_recent": { 312 | "message": "Récent" 313 | }, 314 | "option_relevant": { 315 | "message": "Pertinence" 316 | }, 317 | "option_separate": { 318 | "message": "Afficher dans un onglet séparé" 319 | }, 320 | "preventNextVideoAutoplayInfo": { 321 | "message": "Les vidéos seront lues en boucle à la place" 322 | }, 323 | "preventNextVideoAutoplayLabel": { 324 | "message": "Empêcher la lecture automatique de la vidéo suivante" 325 | }, 326 | "quoteTweetsLabel": { 327 | "message": "Tweets de citation" 328 | }, 329 | "redirectToTwitterLabel": { 330 | "message": "Rediriger vers twitter.com" 331 | }, 332 | "reduceAlgorithmicContentOptionsLabel": { 333 | "message": "Supprimer le contenu algorithmique" 334 | }, 335 | "reduceEngagementOptionsLabel": { 336 | "message": "Réduire l'engagement" 337 | }, 338 | "reducedInteractionModeInfo": { 339 | "message": "Masquer la barre d'action sous les tweets - les réponses sont désormais le seul moyen d'interagir" 340 | }, 341 | "reducedInteractionModeLabel": { 342 | "message": "Mode d'interaction réduit" 343 | }, 344 | "replaceLogoLabel": { 345 | "message": "Remplacer les changements de marque X" 346 | }, 347 | "restoreLinkHeadlinesLabel": { 348 | "message": "Restaurer les titres sous les liens externes" 349 | }, 350 | "restoreOtherInteractionLinksLabel": { 351 | "message": "Restaurer d'autres liens sous les Tweets" 352 | }, 353 | "restoreQuoteTweetsLinkLabel": { 354 | "message": "Restaurer les liens des Tweets cités sous les Tweets" 355 | }, 356 | "restoreTweetSourceLabel": { 357 | "message": "Restaurer l'étiquette de source du Tweet" 358 | }, 359 | "retweetsLabel": { 360 | "message": "Retweets" 361 | }, 362 | "saveAndApplyButton": { 363 | "message": "Enregistrer et appliquer" 364 | }, 365 | "sharedTweetsOptionsLabel": { 366 | "message": "Tweets partagés par d'autres utilisateurs" 367 | }, 368 | "showBlueReplyFollowersCountAmountLabel": { 369 | "message": "Nombre d'abonnés" 370 | }, 371 | "showBlueReplyFollowersCountLabel": { 372 | "message": "Afficher les comptes ayant plus de $AMOUNT$ abonnés", 373 | "placeholders": { 374 | "amount": { 375 | "content": "$1" 376 | } 377 | } 378 | }, 379 | "showBookmarkButtonUnderFocusedTweetsLabel": { 380 | "message": "Afficher sous les tweets mis en avant" 381 | }, 382 | "showPremiumReplyBusinessLabel": { 383 | "message": "Afficher les comptes professionnels vérifiés" 384 | }, 385 | "showPremiumReplyFollowedByLabel": { 386 | "message": "Afficher les comptes qui me suivent" 387 | }, 388 | "showPremiumReplyFollowingLabel": { 389 | "message": "Afficher les comptes que je suis" 390 | }, 391 | "showPremiumReplyGovernmentLabel": { 392 | "message": "Afficher les comptes gouvernementaux vérifiés" 393 | }, 394 | "showRelevantPeopleLabel": { 395 | "message": "Afficher \"Personnes pertinentes\" lors de l'affichage d'un tweet" 396 | }, 397 | "sidebarLabel": { 398 | "message": "Barre latérale" 399 | }, 400 | "sortRepliesLabel": { 401 | "message": "Tri par défaut des réponses" 402 | }, 403 | "tweakNewLayoutInfo": { 404 | "message": "Expérimental - n'activez que si vous avez la nouvelle mise en page" 405 | }, 406 | "tweakNewLayoutLabel": { 407 | "message": "Ajuster la nouvelle mise en page" 408 | }, 409 | "tweakQuoteTweetsPageLabel": { 410 | "message": "Masquer le tweet cité lors de l'affichage des citations de tweets" 411 | }, 412 | "twitterBlueChecksLabel": { 413 | "message": "Coches bleues Premium" 414 | }, 415 | "twitterBlueChecksOption_replace": { 416 | "message": "Remplacer par le logo Twitter Blue" 417 | }, 418 | "uiImprovementsOptionsLabel": { 419 | "message": "Améliorations de l'interface utilisateur" 420 | }, 421 | "uiTweaksOptionsLabel": { 422 | "message": "Ajustements de l'interface utilisateur" 423 | }, 424 | "unblurSensitiveContentLabel": { 425 | "message": "Supprimer le flou du contenu sensible" 426 | }, 427 | "uninvertFollowButtonsLabel": { 428 | "message": "Inverser les boutons Suivre / Se désabonner" 429 | }, 430 | "unmuteButtonText": { 431 | "message": "Restaurer" 432 | }, 433 | "xFixesLabel": { 434 | "message": "Correctifs de X" 435 | } 436 | } -------------------------------------------------------------------------------- /_locales/it/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "addAddMutedWordMenuItemLabel_desktop": { 3 | "message": "Aggiungi \"Aggiungi parola o frase silenziata\" al menu \"Altro\"" 4 | }, 5 | "addAddMutedWordMenuItemLabel_mobile": { 6 | "message": "Aggiungi \"Aggiungi parola o frase silenziata\" al menu ad hamburger" 7 | }, 8 | "alwaysUseLatestTweetsLabel": { 9 | "message": "Usa la timeline \"Seguiti\" (cronologica) di default" 10 | }, 11 | "appStoreSubtitle": { 12 | "message": "La tua timeline, come vuoi tu" 13 | }, 14 | "customCssLabel": { 15 | "message": "CSS personalizzato" 16 | }, 17 | "debugInfo": { 18 | "message": "Attiva il logging di debug e mostra le info di debug sui tweet nella timeline" 19 | }, 20 | "debugLabel": { 21 | "message": "Modalità debug" 22 | }, 23 | "debugLogTimelineStatsLabel": { 24 | "message": "Log stats timeline" 25 | }, 26 | "debugOptionsLabel": { 27 | "message": "Opzioni di debug" 28 | }, 29 | "defaultToLatestSearchLabel": { 30 | "message": "Usa \"Recenti\" come sezione di default in Cerca" 31 | }, 32 | "disableHomeTimelineInfo": { 33 | "message": "Sprechi troppo tempo su Twitter? Prova a rimuovere la Home" 34 | }, 35 | "disableHomeTimelineLabel": { 36 | "message": "Disabilita la Home" 37 | }, 38 | "disableTweetTextFormattingLabel": { 39 | "message": "Disabilita il testo in grassetto e corsivo nei tweet" 40 | }, 41 | "disabledHomeTimelineRedirectLabel": { 42 | "message": "Reindirizza la Home a" 43 | }, 44 | "disabledHomeTimelineRedirectOption_messages": { 45 | "message": "Messaggi" 46 | }, 47 | "dontUseChirpFontLabel": { 48 | "message": "Non usare il font Chirp" 49 | }, 50 | "dropdownMenuFontWeightLabel": { 51 | "message": "Usa il peso normale per il font dei menu a tendina" 52 | }, 53 | "enabled": { 54 | "message": "Abilitato" 55 | }, 56 | "experimentsOptionsLabel": { 57 | "message": "Esperimenti" 58 | }, 59 | "exportConfigLabel": { 60 | "message": "Esporta configurazione per segnalare errori" 61 | }, 62 | "extensionDescription": { 63 | "message": "Ti dà più controllo su Twitter, aggiunge fuznioni mancanti e migliora l'interfaccia" 64 | }, 65 | "extensionDescriptionShort": { 66 | "message": "Ti dà più controllo su Twitter, aggiunge fuznioni mancanti e migliora l'interfaccia" 67 | }, 68 | "extensionName": { 69 | "message": "Control Panel for Twitter" 70 | }, 71 | "extensionNameDisabled": { 72 | "message": "Control Panel for Twitter (disabilitato)" 73 | }, 74 | "fastBlockLabel": { 75 | "message": "Blocco rapido (salta la conferma)" 76 | }, 77 | "features": { 78 | "message": "Funzionalità" 79 | }, 80 | "followButtonStyleLabel": { 81 | "message": "Stile tasti" 82 | }, 83 | "followButtonStyleOption_monochrome": { 84 | "message": "Monocromo" 85 | }, 86 | "followButtonStyleOption_themed": { 87 | "message": "Colorati" 88 | }, 89 | "fullWidthContentInfo": { 90 | "message": "Nascondi la barra laterale e consenti ai contenuti nella timeline di espandersi in larghezza" 91 | }, 92 | "fullWidthContentLabel": { 93 | "message": "Timeline a larghezza intera" 94 | }, 95 | "fullWidthMediaLabel": { 96 | "message": "Media e schede a larghezza intera" 97 | }, 98 | "hideAccountSwitcherLabel": { 99 | "message": "Selettore account" 100 | }, 101 | "hideAdsNavLabel": { 102 | "message": "Annunci" 103 | }, 104 | "hideAllMetricsLabel": { 105 | "message": "Nascondi tutte" 106 | }, 107 | "hideBookmarkButtonLabel": { 108 | "message": "Tasto segnalibro sotto i tweet" 109 | }, 110 | "hideBookmarkMetricsLabel": { 111 | "message": "Segnalibri" 112 | }, 113 | "hideBookmarksNavLabel": { 114 | "message": "segnalibri" 115 | }, 116 | "hideCommunitiesNavLabel": { 117 | "message": "Community" 118 | }, 119 | "hideComposeTweetLabel": { 120 | "message": "Nascondi il pulsante Componi Tweet" 121 | }, 122 | "hideDiscoverSuggestionsLabel": { 123 | "message": "Nascondi i suggerimenti \"Scopri\"" 124 | }, 125 | "hideExploreNavLabel": { 126 | "message": "Esplora" 127 | }, 128 | "hideExploreNavWithSidebarLabel": { 129 | "message": "Mostra quando la barra laterale è nascosta" 130 | }, 131 | "hideExplorePageContentsLabel": { 132 | "message": "Nascondi i contenuti della pagina Esplora e usala solo per cercare" 133 | }, 134 | "hideFollowingMetricsLabel": { 135 | "message": "Seguiti / seguaci" 136 | }, 137 | "hideForYouTimelineLabel": { 138 | "message": "Nascondi la timeline \"Per te\" (algoritmica)" 139 | }, 140 | "hideGrok": { 141 | "message": "Nascondi Grok" 142 | }, 143 | "hideGrokLabel": { 144 | "message": "Nascondi Grok" 145 | }, 146 | "hideGrokTweetsLabel": { 147 | "message": "Nascondi i tweet di Grok" 148 | }, 149 | "hideInlinePrompts": { 150 | "message": "Nascondi i suggerimenti nella timeline" 151 | }, 152 | "hideJobsLabel": { 153 | "message": "Nascondi Offerte di lavoro" 154 | }, 155 | "hideLikeMetricsLabel": { 156 | "message": "Mi piace" 157 | }, 158 | "hideListsNavLabel": { 159 | "message": "Liste" 160 | }, 161 | "hideLiveBroadcastBarLabel": { 162 | "message": "Nascondi la barra di trasmissione in diretta" 163 | }, 164 | "hideLiveBroadcastsLabel": { 165 | "message": "Nascondi le trasmissioni in diretta" 166 | }, 167 | "hideMessagesBottomNavItemLabel": { 168 | "message": "Messaggi" 169 | }, 170 | "hideMessagesDrawerLabel": { 171 | "message": "Cassetto messaggi" 172 | }, 173 | "hideMetricsLabel": { 174 | "message": "Nascondi statistiche" 175 | }, 176 | "hideMonetizationNavLabel": { 177 | "message": "Monetizzazione" 178 | }, 179 | "hideMoreSlideOutMenuItemsOptionsLabel_desktop": { 180 | "message": "Nascondi elementi del menu \"Altro\" che non usi" 181 | }, 182 | "hideMoreSlideOutMenuItemsOptionsLabel_mobile": { 183 | "message": "Nascondi elementi del menu ad hamburger che non usi" 184 | }, 185 | "hideNotificationsLabel": { 186 | "message": "Nascondi notifiche" 187 | }, 188 | "hideProfileHeaderMetricsLabel": { 189 | "message": "Metriche dell'intestazione del profilo" 190 | }, 191 | "hideProfileRetweetsLabel": { 192 | "message": "Nascondi i retweet nei profili" 193 | }, 194 | "hideQuoteTweetMetricsLabel": { 195 | "message": "Tweet di citazione" 196 | }, 197 | "hideQuotesFromLabel": { 198 | "message": "Utenti silenziati ($COUNT$)", 199 | "placeholders": { 200 | "count": { 201 | "content": "$1", 202 | "example": "1" 203 | } 204 | } 205 | }, 206 | "hideReplyMetricsLabel": { 207 | "message": "Risposte" 208 | }, 209 | "hideRetweetMetricsLabel": { 210 | "message": "Retweet" 211 | }, 212 | "hideSeeNewTweetsLabel": { 213 | "message": "Nascondi \"Mostra nuovi tweet\"" 214 | }, 215 | "hideShareTweetButtonLabel": { 216 | "message": "Tasto condividi sotto ai tweet" 217 | }, 218 | "hideSidebarContentLabel": { 219 | "message": "Nascondi contenuti della barra laterale" 220 | }, 221 | "hideSpacesNavLabel": { 222 | "message": "Crea il tuo spazio" 223 | }, 224 | "hideSubscriptionsLabel": { 225 | "message": "Nascondi Iscrizioni" 226 | }, 227 | "hideSuggestedFollowsLabel": { 228 | "message": "Nascondi i suggerimenti di follow" 229 | }, 230 | "hideTimelineTweetBoxLabel": { 231 | "message": "Compositore tweet nella timeline" 232 | }, 233 | "hideToggleNavigationLabel": { 234 | "message": "Nascondi attiva/disattiva navigazione" 235 | }, 236 | "hideTweetAnalyticsLinksLabel": { 237 | "message": "\"Visualizza interazioni tweet\" sotto ai tuoi tweet" 238 | }, 239 | "hideTwitterBlueRepliesLabel": { 240 | "message": "Nascondi risposte degli utenti verificati Premium" 241 | }, 242 | "hideTwitterBlueUpsellsLabel": { 243 | "message": "Nascondi promozioni Premium" 244 | }, 245 | "hideUnavailableQuoteTweetsLabel": { 246 | "message": "Nascondi tweet citati e risposte di account bloccati o silenziati" 247 | }, 248 | "hideUnusedUiItemsOptionsLabel": { 249 | "message": "Nascondi elementi di interfaccia che non usi" 250 | }, 251 | "hideVerifiedNotificationsTabLabel": { 252 | "message": "Nascondi la sezione verificata dalle notifiche e dai seguaci" 253 | }, 254 | "hideViewsLabel": { 255 | "message": "Nascondi le visualizzazioni sotto ai tweet" 256 | }, 257 | "hideWhatsHappeningLabel": { 258 | "message": "Nascondi Cosa sta succedendo" 259 | }, 260 | "hideWhoToFollowEtcLabel": { 261 | "message": "Nascondi \"Chi seguire\", \"Segui dei topic\" ecc. nella timeline" 262 | }, 263 | "homeTimelineOptionsLabel": { 264 | "message": "Home" 265 | }, 266 | "listRetweetsLabel": { 267 | "message": "Retweet nelle liste" 268 | }, 269 | "mutableQuoteTweetsLabel": { 270 | "message": "Abilita silenziamento dei tweet di citazione" 271 | }, 272 | "mutedTweetsLabel": { 273 | "message": "Tweet silenziati ($COUNT$)", 274 | "placeholders": { 275 | "count": { 276 | "content": "$1", 277 | "example": "1" 278 | } 279 | } 280 | }, 281 | "navBaseFontSizeLabel": { 282 | "message": "Usa lo stile normale per il font della barra di navigazione" 283 | }, 284 | "navDensityLabel": { 285 | "message": "Densità navigazione" 286 | }, 287 | "notificationsLabel": { 288 | "message": "Notifiche" 289 | }, 290 | "option_badges": { 291 | "message": "Nascondi solo i badge" 292 | }, 293 | "option_comfortable": { 294 | "message": "Rilassata" 295 | }, 296 | "option_compact": { 297 | "message": "Compatta" 298 | }, 299 | "option_default": { 300 | "message": "Default" 301 | }, 302 | "option_hide": { 303 | "message": "Nascondi" 304 | }, 305 | "option_ignore": { 306 | "message": "Non fare nulla" 307 | }, 308 | "option_liked": { 309 | "message": "Mi piace" 310 | }, 311 | "option_recent": { 312 | "message": "Recenti" 313 | }, 314 | "option_relevant": { 315 | "message": "Pertinenza" 316 | }, 317 | "option_separate": { 318 | "message": "Mostra in scheda separata" 319 | }, 320 | "preventNextVideoAutoplayInfo": { 321 | "message": "I video verranno riprodotti in loop invece" 322 | }, 323 | "preventNextVideoAutoplayLabel": { 324 | "message": "Impedisci la riproduzione automatica del prossimo video" 325 | }, 326 | "quoteTweetsLabel": { 327 | "message": "Tweet di citazione" 328 | }, 329 | "redirectToTwitterLabel": { 330 | "message": "Reindirizza a twitter.com" 331 | }, 332 | "reduceAlgorithmicContentOptionsLabel": { 333 | "message": "Rimuovi contenuti algoritmici" 334 | }, 335 | "reduceEngagementOptionsLabel": { 336 | "message": "Riduci \"interazioni\"" 337 | }, 338 | "reducedInteractionModeInfo": { 339 | "message": "Nascondi la barra di azione sotto ai tweet: le risposte sono ora l'unico modo per interagire" 340 | }, 341 | "reducedInteractionModeLabel": { 342 | "message": "Modalità a interazione ridotta" 343 | }, 344 | "replaceLogoLabel": { 345 | "message": "Sostituisci modifiche relative al marchio X" 346 | }, 347 | "restoreLinkHeadlinesLabel": { 348 | "message": "Ripristina titoli sotto ai link esterni" 349 | }, 350 | "restoreOtherInteractionLinksLabel": { 351 | "message": "Ripristina altri link sotto ai tweet" 352 | }, 353 | "restoreQuoteTweetsLinkLabel": { 354 | "message": "Ripristina link dei tweet di citazione sotto ai tweet" 355 | }, 356 | "restoreTweetSourceLabel": { 357 | "message": "Ripristina etichetta della fonte del Tweet" 358 | }, 359 | "retweetsLabel": { 360 | "message": "Retweet" 361 | }, 362 | "saveAndApplyButton": { 363 | "message": "Salva e applica" 364 | }, 365 | "sharedTweetsOptionsLabel": { 366 | "message": "Tweet condivisi da altri utenti" 367 | }, 368 | "showBlueReplyFollowersCountAmountLabel": { 369 | "message": "Numero di seguaci" 370 | }, 371 | "showBlueReplyFollowersCountLabel": { 372 | "message": "Mostra account con più di $AMOUNT$ follower", 373 | "placeholders": { 374 | "amount": { 375 | "content": "$1", 376 | "example": "1 milione" 377 | } 378 | } 379 | }, 380 | "showBookmarkButtonUnderFocusedTweetsLabel": { 381 | "message": "Mostra sotto ai tweet selezionati" 382 | }, 383 | "showPremiumReplyBusinessLabel": { 384 | "message": "Mostra account aziendali verificati" 385 | }, 386 | "showPremiumReplyFollowedByLabel": { 387 | "message": "Mostra account che mi seguono" 388 | }, 389 | "showPremiumReplyFollowingLabel": { 390 | "message": "Mostra account che seguo" 391 | }, 392 | "showPremiumReplyGovernmentLabel": { 393 | "message": "Mostra account governativi verificati" 394 | }, 395 | "showRelevantPeopleLabel": { 396 | "message": "Mostra \"Persone rilevanti\" quando visualizzi un tweet" 397 | }, 398 | "sidebarLabel": { 399 | "message": "Barra laterale" 400 | }, 401 | "sortRepliesLabel": { 402 | "message": "Ordinamento predefinito delle risposte" 403 | }, 404 | "tweakNewLayoutInfo": { 405 | "message": "Sperimentale - abilita solo se hai il nuovo layout" 406 | }, 407 | "tweakNewLayoutLabel": { 408 | "message": "Modifica nuovo layout" 409 | }, 410 | "tweakQuoteTweetsPageLabel": { 411 | "message": "Nascondi il tweet citato quando visualizzi i tweet di citazione" 412 | }, 413 | "twitterBlueChecksLabel": { 414 | "message": "Spunta blu Premium" 415 | }, 416 | "twitterBlueChecksOption_replace": { 417 | "message": "Sostituisci con logo di Twitter Blue" 418 | }, 419 | "uiImprovementsOptionsLabel": { 420 | "message": "Miglioramenti interfaccia" 421 | }, 422 | "uiTweaksOptionsLabel": { 423 | "message": "Aggiustamenti interfaccia" 424 | }, 425 | "unblurSensitiveContentLabel": { 426 | "message": "Togli censura dai contenuti sensibili" 427 | }, 428 | "uninvertFollowButtonsLabel": { 429 | "message": "Annulla inversione tasi Segui / Segui già" 430 | }, 431 | "unmuteButtonText": { 432 | "message": "Riattiva" 433 | }, 434 | "xFixesLabel": { 435 | "message": "Anti-X" 436 | } 437 | } -------------------------------------------------------------------------------- /_locales/ja/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "addAddMutedWordMenuItemLabel_desktop": { 3 | "message": "もっと見るに「ミュートするキーワードを追加」を追加" 4 | }, 5 | "addAddMutedWordMenuItemLabel_mobile": { 6 | "message": "スライドアウトメニューに「ミュートするキーワードを追加」を追加" 7 | }, 8 | "alwaysUseLatestTweetsLabel": { 9 | "message": "常にタイムラインを「フォロー中」(時系列順)にする" 10 | }, 11 | "appStoreSubtitle": { 12 | "message": "タイムラインを制御せよ" 13 | }, 14 | "customCssLabel": { 15 | "message": "カスタムCSS" 16 | }, 17 | "debugInfo": { 18 | "message": "デバッグログを有効化し、ツイートデバッグ情報をタイムラインに表示" 19 | }, 20 | "debugLabel": { 21 | "message": "デバッグモード" 22 | }, 23 | "debugLogTimelineStatsLabel": { 24 | "message": "タイムライン統計をログ" 25 | }, 26 | "debugOptionsLabel": { 27 | "message": "デバッグオプション" 28 | }, 29 | "defaultToLatestSearchLabel": { 30 | "message": "検索のデフォルトは「最新」タブ" 31 | }, 32 | "disableHomeTimelineInfo": { 33 | "message": "Twitterに時間を盗まれていませんか?「ホーム」タイムラインの利用を控えてみる" 34 | }, 35 | "disableHomeTimelineLabel": { 36 | "message": "「ホーム」タイムラインを無効化" 37 | }, 38 | "disableTweetTextFormattingLabel": { 39 | "message": "ツイートの太字と斜体を無効にする" 40 | }, 41 | "disabledHomeTimelineRedirectLabel": { 42 | "message": "「ホーム」タイムラインをリダイレクト" 43 | }, 44 | "disabledHomeTimelineRedirectOption_messages": { 45 | "message": "メッセージ" 46 | }, 47 | "dontUseChirpFontLabel": { 48 | "message": "Chirpフォントを使用しない" 49 | }, 50 | "dropdownMenuFontWeightLabel": { 51 | "message": "ドロップダウンメニューを通常のフォントの太さにする" 52 | }, 53 | "enabled": { 54 | "message": "有効" 55 | }, 56 | "experimentsOptionsLabel": { 57 | "message": "実験的機能" 58 | }, 59 | "exportConfigLabel": { 60 | "message": "バグレポートの設定をエクスポート" 61 | }, 62 | "extensionDescription": { 63 | "message": "Twitter をより細かく制御し、不足している機能を追加して UI を改善します" 64 | }, 65 | "extensionDescriptionShort": { 66 | "message": "Twitter をより細かく制御し、不足している機能を追加して UI を改善します" 67 | }, 68 | "extensionName": { 69 | "message": "Control Panel for Twitter" 70 | }, 71 | "extensionNameDisabled": { 72 | "message": "Control Panel for Twitter (無効)" 73 | }, 74 | "fastBlockLabel": { 75 | "message": "即ブロック(確認画面をスキップする)" 76 | }, 77 | "features": { 78 | "message": "特徴" 79 | }, 80 | "followButtonStyleLabel": { 81 | "message": "ボタンのスタイル" 82 | }, 83 | "followButtonStyleOption_monochrome": { 84 | "message": "モノクロ" 85 | }, 86 | "followButtonStyleOption_themed": { 87 | "message": "テーマ" 88 | }, 89 | "fullWidthContentInfo": { 90 | "message": "サイドバーを非表示にして、タイムラインコンテンツを全幅表示にする" 91 | }, 92 | "fullWidthContentLabel": { 93 | "message": "タイムラインのコンテンツを全幅表示" 94 | }, 95 | "fullWidthMediaLabel": { 96 | "message": "メディア&カードを全幅表示" 97 | }, 98 | "hideAccountSwitcherLabel": { 99 | "message": "アカウントの切り替え" 100 | }, 101 | "hideAdsNavLabel": { 102 | "message": "広告" 103 | }, 104 | "hideAllMetricsLabel": { 105 | "message": "すべて非表示" 106 | }, 107 | "hideBookmarkButtonLabel": { 108 | "message": "ツイート下部のブックマークボタン" 109 | }, 110 | "hideBookmarkMetricsLabel": { 111 | "message": "ブックマーク" 112 | }, 113 | "hideBookmarksNavLabel": { 114 | "message": "ブックマーク" 115 | }, 116 | "hideCommunitiesNavLabel": { 117 | "message": "コミュニティ" 118 | }, 119 | "hideComposeTweetLabel": { 120 | "message": "ツイート作成ボタンを非表示" 121 | }, 122 | "hideDiscoverSuggestionsLabel": { 123 | "message": "「発見」の提案を非表示" 124 | }, 125 | "hideExploreNavLabel": { 126 | "message": "「話題を検索」" 127 | }, 128 | "hideExploreNavWithSidebarLabel": { 129 | "message": "サイドバーが非表示の場合に表示" 130 | }, 131 | "hideExplorePageContentsLabel": { 132 | "message": "「話題を検索」ページの内容を非表示(検索のみに使用する)" 133 | }, 134 | "hideFollowingMetricsLabel": { 135 | "message": "フォロー/フォロワー" 136 | }, 137 | "hideForYouTimelineLabel": { 138 | "message": "アルゴリズムによる「おすすめ」を非表示" 139 | }, 140 | "hideGrok": { 141 | "message": "Grok を非表示にする" 142 | }, 143 | "hideGrokLabel": { 144 | "message": "Grok を非表示にする" 145 | }, 146 | "hideGrokTweetsLabel": { 147 | "message": "Grokのツイートを非表示" 148 | }, 149 | "hideInlinePrompts": { 150 | "message": "タイムライン内のインラインプロンプトを非表示にする" 151 | }, 152 | "hideJobsLabel": { 153 | "message": "募集を非表示にする" 154 | }, 155 | "hideLikeMetricsLabel": { 156 | "message": "いいね件数" 157 | }, 158 | "hideListsNavLabel": { 159 | "message": "リスト" 160 | }, 161 | "hideLiveBroadcastBarLabel": { 162 | "message": "ライブ放送バーを非表示" 163 | }, 164 | "hideLiveBroadcastsLabel": { 165 | "message": "ライブ放送を非表示" 166 | }, 167 | "hideMessagesBottomNavItemLabel": { 168 | "message": "メッセージ" 169 | }, 170 | "hideMessagesDrawerLabel": { 171 | "message": "メッセージドロワー" 172 | }, 173 | "hideMetricsLabel": { 174 | "message": "メトリクスを非表示" 175 | }, 176 | "hideMonetizationNavLabel": { 177 | "message": "収益化" 178 | }, 179 | "hideMoreSlideOutMenuItemsOptionsLabel_desktop": { 180 | "message": "使用しない「もっと見る」メニューの項目を非表示" 181 | }, 182 | "hideMoreSlideOutMenuItemsOptionsLabel_mobile": { 183 | "message": "使用しないスライドアウトメニューの項目を非表示" 184 | }, 185 | "hideNotificationsLabel": { 186 | "message": "通知を非表示" 187 | }, 188 | "hideProfileHeaderMetricsLabel": { 189 | "message": "プロフィールヘッダーのメトリクス" 190 | }, 191 | "hideProfileRetweetsLabel": { 192 | "message": "ユーザープロフィールでのリツイートを非表示にする" 193 | }, 194 | "hideQuoteTweetMetricsLabel": { 195 | "message": "引用ツイート件数" 196 | }, 197 | "hideQuotesFromLabel": { 198 | "message": "ミュートしたユーザー ($COUNT$)", 199 | "placeholders": { 200 | "count": { 201 | "content": "$1", 202 | "example": "1" 203 | } 204 | } 205 | }, 206 | "hideReplyMetricsLabel": { 207 | "message": "返信件数" 208 | }, 209 | "hideRetweetMetricsLabel": { 210 | "message": "リツイート件数" 211 | }, 212 | "hideSeeNewTweetsLabel": { 213 | "message": "「新しいツイートを表示」を非表示" 214 | }, 215 | "hideShareTweetButtonLabel": { 216 | "message": "ツイート下部のシェアボタン" 217 | }, 218 | "hideSidebarContentLabel": { 219 | "message": "サイドバーコンテンツを非表示にする" 220 | }, 221 | "hideSpacesNavLabel": { 222 | "message": "スペースを作成" 223 | }, 224 | "hideSubscriptionsLabel": { 225 | "message": "サブスクリプションを非表示にする" 226 | }, 227 | "hideSuggestedFollowsLabel": { 228 | "message": "おすすめのフォローを非表示" 229 | }, 230 | "hideTimelineTweetBoxLabel": { 231 | "message": "タイムラインのツイートボックス" 232 | }, 233 | "hideToggleNavigationLabel": { 234 | "message": "ナビゲーション切り替えを非表示" 235 | }, 236 | "hideTweetAnalyticsLinksLabel": { 237 | "message": "自分のツイートの下に「ポストのエンゲージメントを表示」" 238 | }, 239 | "hideTwitterBlueRepliesLabel": { 240 | "message": "プレミアム ブルー チェックの返信を非表示にする" 241 | }, 242 | "hideTwitterBlueUpsellsLabel": { 243 | "message": "プレミアムのアップセルを非表示にする" 244 | }, 245 | "hideUnavailableQuoteTweetsLabel": { 246 | "message": "ブロックまたはミュートしたアカウントへの引用や返信を非表示にする" 247 | }, 248 | "hideUnusedUiItemsOptionsLabel": { 249 | "message": "使用しないUI項目を非表示" 250 | }, 251 | "hideVerifiedNotificationsTabLabel": { 252 | "message": "通知とフォロワーの「認証済み」タブを非表示" 253 | }, 254 | "hideViewsLabel": { 255 | "message": "ツイート下部のアナリティクスのリンクを非表示" 256 | }, 257 | "hideWhatsHappeningLabel": { 258 | "message": "「いまどうしてる?」を非表示" 259 | }, 260 | "hideWhoToFollowEtcLabel": { 261 | "message": "タイムラインの「おすすめユーザー」「おすすめトピック」を非表示" 262 | }, 263 | "homeTimelineOptionsLabel": { 264 | "message": "ホームタイムライン" 265 | }, 266 | "listRetweetsLabel": { 267 | "message": "リスト内のリツイート" 268 | }, 269 | "mutableQuoteTweetsLabel": { 270 | "message": "引用ツイートのミュートを有効にする" 271 | }, 272 | "mutedTweetsLabel": { 273 | "message": "ミュートされたツイート($COUNT$)", 274 | "placeholders": { 275 | "count": { 276 | "content": "$1", 277 | "example": "1" 278 | } 279 | } 280 | }, 281 | "navBaseFontSizeLabel": { 282 | "message": "ナビゲーションバーを通常のフォントサイズにする" 283 | }, 284 | "navDensityLabel": { 285 | "message": "ナビゲーションの密度" 286 | }, 287 | "notificationsLabel": { 288 | "message": "通知" 289 | }, 290 | "option_badges": { 291 | "message": "バッジのみ非表示" 292 | }, 293 | "option_comfortable": { 294 | "message": "快適" 295 | }, 296 | "option_compact": { 297 | "message": "コンパクト" 298 | }, 299 | "option_default": { 300 | "message": "デフォルト" 301 | }, 302 | "option_hide": { 303 | "message": "非表示" 304 | }, 305 | "option_ignore": { 306 | "message": "そのまま" 307 | }, 308 | "option_liked": { 309 | "message": "いいね" 310 | }, 311 | "option_recent": { 312 | "message": "最新" 313 | }, 314 | "option_relevant": { 315 | "message": "関連性" 316 | }, 317 | "option_separate": { 318 | "message": "別タブで開く" 319 | }, 320 | "preventNextVideoAutoplayInfo": { 321 | "message": "動画はループ再生されます" 322 | }, 323 | "preventNextVideoAutoplayLabel": { 324 | "message": "次の動画の自動再生を防ぐ" 325 | }, 326 | "quoteTweetsLabel": { 327 | "message": "引用ツイート" 328 | }, 329 | "redirectToTwitterLabel": { 330 | "message": "twitter.com にリダイレクト" 331 | }, 332 | "reduceAlgorithmicContentOptionsLabel": { 333 | "message": "アルゴリズムコンテンツを取り除く" 334 | }, 335 | "reduceEngagementOptionsLabel": { 336 | "message": "「エンゲージメント」を減らす" 337 | }, 338 | "reducedInteractionModeInfo": { 339 | "message": "ツイートの下にあるアクションバーを非表示(リプライのみで交流する)" 340 | }, 341 | "reducedInteractionModeLabel": { 342 | "message": "インタラクションモードを減らす" 343 | }, 344 | "replaceLogoLabel": { 345 | "message": "X のブランド変更を置き換える" 346 | }, 347 | "restoreLinkHeadlinesLabel": { 348 | "message": "外部リンクの下に見出しを復元する" 349 | }, 350 | "restoreOtherInteractionLinksLabel": { 351 | "message": "ツイートの下の他のリンクを復元する" 352 | }, 353 | "restoreQuoteTweetsLinkLabel": { 354 | "message": "ツイートの下にある「引用ツイート」リンクを復元する" 355 | }, 356 | "restoreTweetSourceLabel": { 357 | "message": "ツイートのソースラベルを復元" 358 | }, 359 | "retweetsLabel": { 360 | "message": "リツイート" 361 | }, 362 | "saveAndApplyButton": { 363 | "message": "保存して適用" 364 | }, 365 | "sharedTweetsOptionsLabel": { 366 | "message": "他のユーザーが共有したツイート" 367 | }, 368 | "showBlueReplyFollowersCountAmountLabel": { 369 | "message": "フォロワー数" 370 | }, 371 | "showBlueReplyFollowersCountLabel": { 372 | "message": "フォロワー数が$AMOUNT$人を超えるアカウントを表示", 373 | "placeholders": { 374 | "amount": { 375 | "content": "$1" 376 | } 377 | } 378 | }, 379 | "showBookmarkButtonUnderFocusedTweetsLabel": { 380 | "message": "フォーカスされたツイートの下に表示" 381 | }, 382 | "showPremiumReplyBusinessLabel": { 383 | "message": "認証済みビジネスアカウントを表示" 384 | }, 385 | "showPremiumReplyFollowedByLabel": { 386 | "message": "自分をフォローしているアカウントを表示" 387 | }, 388 | "showPremiumReplyFollowingLabel": { 389 | "message": "フォロー中のアカウントを表示" 390 | }, 391 | "showPremiumReplyGovernmentLabel": { 392 | "message": "認証済み政府機関アカウントを表示" 393 | }, 394 | "showRelevantPeopleLabel": { 395 | "message": "ツイート閲覧時に「おすすめユーザー」を表示する" 396 | }, 397 | "sidebarLabel": { 398 | "message": "サイドバー" 399 | }, 400 | "sortRepliesLabel": { 401 | "message": "返信のデフォルトの並べ替え" 402 | }, 403 | "tweakNewLayoutInfo": { 404 | "message": "実験的機能 - 新しいレイアウトがある場合にのみ有効にしてください" 405 | }, 406 | "tweakNewLayoutLabel": { 407 | "message": "新しいレイアウトを調整" 408 | }, 409 | "tweakQuoteTweetsPageLabel": { 410 | "message": "引用ツイート閲覧時に引用元ツイートを非表示" 411 | }, 412 | "twitterBlueChecksLabel": { 413 | "message": "プレミアムブルーチェック" 414 | }, 415 | "twitterBlueChecksOption_replace": { 416 | "message": "Twitter Blueロゴに変更" 417 | }, 418 | "uiImprovementsOptionsLabel": { 419 | "message": "UIの改善" 420 | }, 421 | "uiTweaksOptionsLabel": { 422 | "message": "UIを微調整" 423 | }, 424 | "unblurSensitiveContentLabel": { 425 | "message": "機密性の高いコンテンツのぼかしを解除する" 426 | }, 427 | "uninvertFollowButtonsLabel": { 428 | "message": "フォロー/フォロワーボタンの反転表示を解除" 429 | }, 430 | "unmuteButtonText": { 431 | "message": "ミュート解除" 432 | }, 433 | "xFixesLabel": { 434 | "message": "X の修正" 435 | } 436 | } -------------------------------------------------------------------------------- /_locales/ko/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "addAddMutedWordMenuItemLabel_desktop": { 3 | "message": "\"더 보기\" 메뉴에 \"뮤트할 단어 추가하기\" 추가" 4 | }, 5 | "addAddMutedWordMenuItemLabel_mobile": { 6 | "message": "슬라이드 메뉴에 \"뮤트할 단어 추가하기\" 추가" 7 | }, 8 | "alwaysUseLatestTweetsLabel": { 9 | "message": "기본적으로 \"팔로잉\" (시간순) 타임라인 사용" 10 | }, 11 | "appStoreSubtitle": { 12 | "message": "타임라인을 통제하세요" 13 | }, 14 | "customCssLabel": { 15 | "message": "사용자 정의 CSS" 16 | }, 17 | "debugInfo": { 18 | "message": "디버그 로깅을 활성화하고 타임라인에서 트윗 디버그 정보를 표시합니다" 19 | }, 20 | "debugLabel": { 21 | "message": "디버그 모드" 22 | }, 23 | "debugLogTimelineStatsLabel": { 24 | "message": "타임라인 통계 로깅" 25 | }, 26 | "debugOptionsLabel": { 27 | "message": "디버그 옵션" 28 | }, 29 | "defaultToLatestSearchLabel": { 30 | "message": "검색 시 기본적으로 \"최신\" 탭 사용" 31 | }, 32 | "disableHomeTimelineInfo": { 33 | "message": "트위터에 너무 많은 시간을 낭비하고 있나요? 홈 타임라인 사용을 방지해 보세요" 34 | }, 35 | "disableHomeTimelineLabel": { 36 | "message": "홈 타임라인 비활성화" 37 | }, 38 | "disableTweetTextFormattingLabel": { 39 | "message": "트윗에서 볼드체 및 이탤릭체 비활성화" 40 | }, 41 | "disabledHomeTimelineRedirectLabel": { 42 | "message": "비활성화된 홈 타임라인 리디렉션" 43 | }, 44 | "disabledHomeTimelineRedirectOption_messages": { 45 | "message": "쪽지" 46 | }, 47 | "dontUseChirpFontLabel": { 48 | "message": "Chirp 글꼴 사용 안 함" 49 | }, 50 | "dropdownMenuFontWeightLabel": { 51 | "message": "드롭다운 메뉴에서 일반 글꼴 두께 사용" 52 | }, 53 | "enabled": { 54 | "message": "활성화됨" 55 | }, 56 | "experimentsOptionsLabel": { 57 | "message": "실험" 58 | }, 59 | "exportConfigLabel": { 60 | "message": "버그 보고서를 위한 설정 내보내기" 61 | }, 62 | "extensionDescription": { 63 | "message": "트위터에 대한 더 많은 제어권을 제공하고 기능을 보완하며 UI를 개선합니다" 64 | }, 65 | "extensionDescriptionShort": { 66 | "message": "트위터에 대한 더 많은 제어권을 제공하고 기능을 보완하며 UI를 개선합니다" 67 | }, 68 | "extensionName": { 69 | "message": "Control Panel for Twitter" 70 | }, 71 | "extensionNameDisabled": { 72 | "message": "Control Panel for Twitter (비활성화됨)" 73 | }, 74 | "fastBlockLabel": { 75 | "message": "빠른 차단 (확인 대화상자 생략)" 76 | }, 77 | "features": { 78 | "message": "기능" 79 | }, 80 | "followButtonStyleLabel": { 81 | "message": "버튼 스타일" 82 | }, 83 | "followButtonStyleOption_monochrome": { 84 | "message": "흑백" 85 | }, 86 | "followButtonStyleOption_themed": { 87 | "message": "테마별" 88 | }, 89 | "fullWidthContentInfo": { 90 | "message": "사이드바를 숨기고 타임라인 콘텐츠를 전체 너비로 표시" 91 | }, 92 | "fullWidthContentLabel": { 93 | "message": "전체 너비 타임라인 콘텐츠" 94 | }, 95 | "fullWidthMediaLabel": { 96 | "message": "전체 너비 미디어 및 카드" 97 | }, 98 | "hideAccountSwitcherLabel": { 99 | "message": "계정 전환기" 100 | }, 101 | "hideAdsNavLabel": { 102 | "message": "광고" 103 | }, 104 | "hideAllMetricsLabel": { 105 | "message": "모두 숨기기" 106 | }, 107 | "hideBookmarkButtonLabel": { 108 | "message": "트윗 아래 북마크 버튼 숨기기" 109 | }, 110 | "hideBookmarkMetricsLabel": { 111 | "message": "북마크" 112 | }, 113 | "hideBookmarksNavLabel": { 114 | "message": "북마크" 115 | }, 116 | "hideCommunitiesNavLabel": { 117 | "message": "커뮤니티" 118 | }, 119 | "hideComposeTweetLabel": { 120 | "message": "트윗 작성 버튼 숨기기" 121 | }, 122 | "hideDiscoverSuggestionsLabel": { 123 | "message": "\"발견\" 제안 숨기기" 124 | }, 125 | "hideExploreNavLabel": { 126 | "message": "탐색" 127 | }, 128 | "hideExploreNavWithSidebarLabel": { 129 | "message": "사이드바 숨김 상태에서 표시" 130 | }, 131 | "hideExplorePageContentsLabel": { 132 | "message": "탐색하기 페이지 컨텐츠 숨기기 및 검색에만 사용" 133 | }, 134 | "hideFollowingMetricsLabel": { 135 | "message": "팔로잉/팔로워" 136 | }, 137 | "hideForYouTimelineLabel": { 138 | "message": "\"나를 위한 추천\" (알고리즘) 타임라인 숨기기" 139 | }, 140 | "hideGrok": { 141 | "message": "Grok 숨기기" 142 | }, 143 | "hideGrokLabel": { 144 | "message": "Grok 숨기기" 145 | }, 146 | "hideGrokTweetsLabel": { 147 | "message": "Grok 트윗 숨기기" 148 | }, 149 | "hideInlinePrompts": { 150 | "message": "타임라인에서 인라인 프롬프트 숨기기" 151 | }, 152 | "hideJobsLabel": { 153 | "message": "채용을 숨긴다" 154 | }, 155 | "hideLikeMetricsLabel": { 156 | "message": "좋아요" 157 | }, 158 | "hideListsNavLabel": { 159 | "message": "리스트" 160 | }, 161 | "hideLiveBroadcastBarLabel": { 162 | "message": "라이브 방송 표시줄 숨기기" 163 | }, 164 | "hideLiveBroadcastsLabel": { 165 | "message": "라이브 방송 숨기기" 166 | }, 167 | "hideMessagesBottomNavItemLabel": { 168 | "message": "메시지" 169 | }, 170 | "hideMessagesDrawerLabel": { 171 | "message": "메시지 드로어" 172 | }, 173 | "hideMetricsLabel": { 174 | "message": "지표 숨기기" 175 | }, 176 | "hideMonetizationNavLabel": { 177 | "message": "수익 창출" 178 | }, 179 | "hideMoreSlideOutMenuItemsOptionsLabel_desktop": { 180 | "message": "사용하지 않는 \"더 보기\" 메뉴 항목숨기기 (데스크톱)" 181 | }, 182 | "hideMoreSlideOutMenuItemsOptionsLabel_mobile": { 183 | "message": "사용하지 않는 \"더 보기\" 메뉴 항목 숨기기 (모바일)" 184 | }, 185 | "hideNotificationsLabel": { 186 | "message": "알림 숨기기" 187 | }, 188 | "hideProfileHeaderMetricsLabel": { 189 | "message": "프로필 헤더 메트릭" 190 | }, 191 | "hideProfileRetweetsLabel": { 192 | "message": "사용자 프로필에서 리트윗 숨기기" 193 | }, 194 | "hideQuoteTweetMetricsLabel": { 195 | "message": "인용 트윗" 196 | }, 197 | "hideQuotesFromLabel": { 198 | "message": "음소거된 사용자 ($COUNT$)", 199 | "placeholders": { 200 | "count": { 201 | "content": "$1", 202 | "example": "1" 203 | } 204 | } 205 | }, 206 | "hideReplyMetricsLabel": { 207 | "message": "답글" 208 | }, 209 | "hideRetweetMetricsLabel": { 210 | "message": "리트윗" 211 | }, 212 | "hideSeeNewTweetsLabel": { 213 | "message": "\"새 트윗 보기\" 숨기기" 214 | }, 215 | "hideShareTweetButtonLabel": { 216 | "message": "트윗 아래 공유 버튼 숨기기" 217 | }, 218 | "hideSidebarContentLabel": { 219 | "message": "사이드바 내용 숨기기" 220 | }, 221 | "hideSpacesNavLabel": { 222 | "message": "스페이스 만들기" 223 | }, 224 | "hideSubscriptionsLabel": { 225 | "message": "구독 숨기기" 226 | }, 227 | "hideSuggestedFollowsLabel": { 228 | "message": "추천 팔로우 숨기기" 229 | }, 230 | "hideTimelineTweetBoxLabel": { 231 | "message": "타임라인 트윗 상자" 232 | }, 233 | "hideToggleNavigationLabel": { 234 | "message": "탐색 전환 숨기기" 235 | }, 236 | "hideTweetAnalyticsLinksLabel": { 237 | "message": "내 트윗 아래에 \"게시 참여수 조회\"" 238 | }, 239 | "hideTwitterBlueRepliesLabel": { 240 | "message": "Premium 파란색 체크 답장 숨기기" 241 | }, 242 | "hideTwitterBlueUpsellsLabel": { 243 | "message": "Premium 업셀 숨기기" 244 | }, 245 | "hideUnavailableQuoteTweetsLabel": { 246 | "message": "차단 및 음소거된 계정에 대한 인용 및 답글 숨기기" 247 | }, 248 | "hideUnusedUiItemsOptionsLabel": { 249 | "message": "사용하지 않는 UI 항목 숨기기" 250 | }, 251 | "hideVerifiedNotificationsTabLabel": { 252 | "message": "알림 및 팔로어에 \"인증된\" 탭 숨기기" 253 | }, 254 | "hideViewsLabel": { 255 | "message": "트윗 아래의 조회수 숨기기" 256 | }, 257 | "hideWhatsHappeningLabel": { 258 | "message": "'지금 일어나는 일' 숨기기" 259 | }, 260 | "hideWhoToFollowEtcLabel": { 261 | "message": "타임라인에서 \"팔로우 추천\" 등 숨기기" 262 | }, 263 | "homeTimelineOptionsLabel": { 264 | "message": "홈 타임라인" 265 | }, 266 | "listRetweetsLabel": { 267 | "message": "리스트에 포함된 리트윗" 268 | }, 269 | "mutableQuoteTweetsLabel": { 270 | "message": "인용 트윗 음소거 활성화" 271 | }, 272 | "mutedTweetsLabel": { 273 | "message": "음소거된 트윗 ($COUNT$개)", 274 | "placeholders": { 275 | "count": { 276 | "content": "$1", 277 | "example": "1" 278 | } 279 | } 280 | }, 281 | "navBaseFontSizeLabel": { 282 | "message": "내비게이션 바에 일반 텍스트 글꼴 스타일 사용" 283 | }, 284 | "navDensityLabel": { 285 | "message": "네비게이션 밀도" 286 | }, 287 | "notificationsLabel": { 288 | "message": "알림" 289 | }, 290 | "option_badges": { 291 | "message": "배지만 숨기기" 292 | }, 293 | "option_comfortable": { 294 | "message": "편안한" 295 | }, 296 | "option_compact": { 297 | "message": "간략한" 298 | }, 299 | "option_default": { 300 | "message": "기본" 301 | }, 302 | "option_hide": { 303 | "message": "숨기기" 304 | }, 305 | "option_ignore": { 306 | "message": "아무것도 하지 않음" 307 | }, 308 | "option_liked": { 309 | "message": "마음에 들어요" 310 | }, 311 | "option_recent": { 312 | "message": "최신" 313 | }, 314 | "option_relevant": { 315 | "message": "관련성" 316 | }, 317 | "option_separate": { 318 | "message": "별도의 탭에 표시" 319 | }, 320 | "preventNextVideoAutoplayInfo": { 321 | "message": "비디오는 반복 재생됩니다" 322 | }, 323 | "preventNextVideoAutoplayLabel": { 324 | "message": "다음 비디오 자동 재생 방지" 325 | }, 326 | "quoteTweetsLabel": { 327 | "message": "인용 트윗" 328 | }, 329 | "redirectToTwitterLabel": { 330 | "message": "twitter.com으로 리디렉션" 331 | }, 332 | "reduceAlgorithmicContentOptionsLabel": { 333 | "message": "알고리즘 컨텐츠 제거" 334 | }, 335 | "reduceEngagementOptionsLabel": { 336 | "message": "\"참여\" 줄이기" 337 | }, 338 | "reducedInteractionModeInfo": { 339 | "message": "트윗 아래의 작업 표시줄을 숨김 - 답글이 상호작용의 유일한 수단이 됨" 340 | }, 341 | "reducedInteractionModeLabel": { 342 | "message": "상호작용 줄임 모드" 343 | }, 344 | "replaceLogoLabel": { 345 | "message": "X 브랜딩 변경 사항 바꾸기" 346 | }, 347 | "restoreLinkHeadlinesLabel": { 348 | "message": "외부 링크 아래의 제목 복원" 349 | }, 350 | "restoreOtherInteractionLinksLabel": { 351 | "message": "트윗 아래의 다른 링크 복원" 352 | }, 353 | "restoreQuoteTweetsLinkLabel": { 354 | "message": "트윗 아래의 \"트윗 인용\" 링크 복원" 355 | }, 356 | "restoreTweetSourceLabel": { 357 | "message": "트윗 출처 라벨 복원" 358 | }, 359 | "retweetsLabel": { 360 | "message": "리트윗" 361 | }, 362 | "saveAndApplyButton": { 363 | "message": "저장하고 적용" 364 | }, 365 | "sharedTweetsOptionsLabel": { 366 | "message": "다른 사용자가 공유한 트윗" 367 | }, 368 | "showBlueReplyFollowersCountAmountLabel": { 369 | "message": "팔로워 수" 370 | }, 371 | "showBlueReplyFollowersCountLabel": { 372 | "message": "팔로워 수가 $AMOUNT$명을 초과하는 계정 표시", 373 | "placeholders": { 374 | "amount": { 375 | "content": "$1" 376 | } 377 | } 378 | }, 379 | "showBookmarkButtonUnderFocusedTweetsLabel": { 380 | "message": "집중된 트윗 아래에 표시" 381 | }, 382 | "showPremiumReplyBusinessLabel": { 383 | "message": "인증된 비즈니스 계정 표시" 384 | }, 385 | "showPremiumReplyFollowedByLabel": { 386 | "message": "나를 팔로우하는 계정 표시" 387 | }, 388 | "showPremiumReplyFollowingLabel": { 389 | "message": "내가 팔로우하는 계정 표시" 390 | }, 391 | "showPremiumReplyGovernmentLabel": { 392 | "message": "인증된 정부 계정 표시" 393 | }, 394 | "showRelevantPeopleLabel": { 395 | "message": "트윗 보기 시 \"연관된 사람\" 표시" 396 | }, 397 | "sidebarLabel": { 398 | "message": "사이드바" 399 | }, 400 | "sortRepliesLabel": { 401 | "message": "답글의 기본 정렬" 402 | }, 403 | "tweakNewLayoutInfo": { 404 | "message": "실험적 기능 - 새 레이아웃이 있는 경우에만 활성화하세요" 405 | }, 406 | "tweakNewLayoutLabel": { 407 | "message": "새 레이아웃 조정" 408 | }, 409 | "tweakQuoteTweetsPageLabel": { 410 | "message": "인용 트윗을 볼 때 인용된 트윗 숨기기" 411 | }, 412 | "twitterBlueChecksLabel": { 413 | "message": "Premium 파란색 체크" 414 | }, 415 | "twitterBlueChecksOption_replace": { 416 | "message": "Twitter Blue 로고로 교체" 417 | }, 418 | "uiImprovementsOptionsLabel": { 419 | "message": "UI 개선" 420 | }, 421 | "uiTweaksOptionsLabel": { 422 | "message": "UI 조정" 423 | }, 424 | "unblurSensitiveContentLabel": { 425 | "message": "민감한 콘텐츠 흐리게 처리 해제" 426 | }, 427 | "uninvertFollowButtonsLabel": { 428 | "message": "팔로우/팔로잉 버튼 색상 반전 해제" 429 | }, 430 | "unmuteButtonText": { 431 | "message": "음소거 해제" 432 | }, 433 | "xFixesLabel": { 434 | "message": "X 수정 사항" 435 | } 436 | } -------------------------------------------------------------------------------- /_locales/zh_CN/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "addAddMutedWordMenuItemLabel_desktop": { 3 | "message": "在\"更多\"菜单中添加\"增加隐藏词\"" 4 | }, 5 | "addAddMutedWordMenuItemLabel_mobile": { 6 | "message": "在滑出式菜单中添加\"增加隐藏词\"" 7 | }, 8 | "alwaysUseLatestTweetsLabel": { 9 | "message": "默认使用 \"正在关注\"(按时间顺序)的时间线" 10 | }, 11 | "appStoreSubtitle": { 12 | "message": "掌控你的时间线" 13 | }, 14 | "customCssLabel": { 15 | "message": "自定义 CSS" 16 | }, 17 | "debugInfo": { 18 | "message": "启用调试日志并在时间线上显示推文调试信息" 19 | }, 20 | "debugLabel": { 21 | "message": "调试模式" 22 | }, 23 | "debugLogTimelineStatsLabel": { 24 | "message": "日志时间轴统计" 25 | }, 26 | "debugOptionsLabel": { 27 | "message": "调试选项" 28 | }, 29 | "defaultToLatestSearchLabel": { 30 | "message": "在搜索中默认为\"最新\"选项卡" 31 | }, 32 | "disableHomeTimelineInfo": { 33 | "message": "发现自己在Twitter上浪费了太多的时间?试着防止使用主页时间线" 34 | }, 35 | "disableHomeTimelineLabel": { 36 | "message": "禁用主页时间线" 37 | }, 38 | "disableTweetTextFormattingLabel": { 39 | "message": "禁用推文中的加粗和斜体文本" 40 | }, 41 | "disabledHomeTimelineRedirectLabel": { 42 | "message": "将主页时间线重定向至" 43 | }, 44 | "disabledHomeTimelineRedirectOption_messages": { 45 | "message": "私信" 46 | }, 47 | "dontUseChirpFontLabel": { 48 | "message": "不要使用Chirp字体" 49 | }, 50 | "dropdownMenuFontWeightLabel": { 51 | "message": "在下拉菜单中使用正常的字体大小" 52 | }, 53 | "enabled": { 54 | "message": "已启用" 55 | }, 56 | "experimentsOptionsLabel": { 57 | "message": "试验" 58 | }, 59 | "exportConfigLabel": { 60 | "message": "导出配置用于错误报告" 61 | }, 62 | "extensionDescription": { 63 | "message": "让你对Twitter有更多的控制,并增加了缺失的功能和UI改进" 64 | }, 65 | "extensionDescriptionShort": { 66 | "message": "让你对Twitter有更多的控制,并增加了缺失的功能和UI改进" 67 | }, 68 | "extensionName": { 69 | "message": "Control Panel for Twitter" 70 | }, 71 | "extensionNameDisabled": { 72 | "message": "Control Panel for Twitter (已禁用)" 73 | }, 74 | "fastBlockLabel": { 75 | "message": "快速屏蔽(跳过确认对话框)" 76 | }, 77 | "features": { 78 | "message": "特征" 79 | }, 80 | "followButtonStyleLabel": { 81 | "message": "按钮样式" 82 | }, 83 | "followButtonStyleOption_monochrome": { 84 | "message": "单色" 85 | }, 86 | "followButtonStyleOption_themed": { 87 | "message": "主题" 88 | }, 89 | "fullWidthContentInfo": { 90 | "message": "隐藏侧边栏,让时间线内容全宽化" 91 | }, 92 | "fullWidthContentLabel": { 93 | "message": "全宽的时间线内容" 94 | }, 95 | "fullWidthMediaLabel": { 96 | "message": "全宽的媒体和卡片" 97 | }, 98 | "hideAccountSwitcherLabel": { 99 | "message": "帐户切换" 100 | }, 101 | "hideAdsNavLabel": { 102 | "message": "广告" 103 | }, 104 | "hideAllMetricsLabel": { 105 | "message": "全部隐藏" 106 | }, 107 | "hideBookmarkButtonLabel": { 108 | "message": "推文下方的书签按钮" 109 | }, 110 | "hideBookmarkMetricsLabel": { 111 | "message": "书签" 112 | }, 113 | "hideBookmarksNavLabel": { 114 | "message": "书签" 115 | }, 116 | "hideCommunitiesNavLabel": { 117 | "message": "社区" 118 | }, 119 | "hideComposeTweetLabel": { 120 | "message": "隐藏撰写推文按钮" 121 | }, 122 | "hideDiscoverSuggestionsLabel": { 123 | "message": "隐藏\"发现\"建议" 124 | }, 125 | "hideExploreNavLabel": { 126 | "message": "探索" 127 | }, 128 | "hideExploreNavWithSidebarLabel": { 129 | "message": "隐藏侧边栏时显示" 130 | }, 131 | "hideExplorePageContentsLabel": { 132 | "message": "隐藏\"探索\"页面内容,只用于搜索" 133 | }, 134 | "hideFollowingMetricsLabel": { 135 | "message": "正在关注/关注者" 136 | }, 137 | "hideForYouTimelineLabel": { 138 | "message": "隐藏 \"为你推荐\" (算法) 时间线" 139 | }, 140 | "hideGrok": { 141 | "message": "隐藏 Grok" 142 | }, 143 | "hideGrokLabel": { 144 | "message": "隐藏 Grok" 145 | }, 146 | "hideGrokTweetsLabel": { 147 | "message": "隐藏 Grok 推文" 148 | }, 149 | "hideInlinePrompts": { 150 | "message": "隐藏时间线中的内联提示" 151 | }, 152 | "hideJobsLabel": { 153 | "message": "隐藏工作" 154 | }, 155 | "hideLikeMetricsLabel": { 156 | "message": "喜欢" 157 | }, 158 | "hideListsNavLabel": { 159 | "message": "列表" 160 | }, 161 | "hideLiveBroadcastBarLabel": { 162 | "message": "隐藏直播栏" 163 | }, 164 | "hideLiveBroadcastsLabel": { 165 | "message": "隐藏直播" 166 | }, 167 | "hideMessagesBottomNavItemLabel": { 168 | "message": "私信" 169 | }, 170 | "hideMessagesDrawerLabel": { 171 | "message": "讯息抽屉" 172 | }, 173 | "hideMetricsLabel": { 174 | "message": "隐藏指标" 175 | }, 176 | "hideMonetizationNavLabel": { 177 | "message": "盈利" 178 | }, 179 | "hideMoreSlideOutMenuItemsOptionsLabel_desktop": { 180 | "message": "隐藏你不使用的\"更多\"菜单项" 181 | }, 182 | "hideMoreSlideOutMenuItemsOptionsLabel_mobile": { 183 | "message": "隐藏你不使用的滑出式菜单项" 184 | }, 185 | "hideNotificationsLabel": { 186 | "message": "隐藏通知" 187 | }, 188 | "hideProfileHeaderMetricsLabel": { 189 | "message": "个人资料页眉指标" 190 | }, 191 | "hideProfileRetweetsLabel": { 192 | "message": "在用户个人资料中隐藏转发" 193 | }, 194 | "hideQuoteTweetMetricsLabel": { 195 | "message": "引用推文" 196 | }, 197 | "hideQuotesFromLabel": { 198 | "message": "已静音用户 ($COUNT$)", 199 | "placeholders": { 200 | "count": { 201 | "content": "$1", 202 | "example": "1" 203 | } 204 | } 205 | }, 206 | "hideReplyMetricsLabel": { 207 | "message": "回复" 208 | }, 209 | "hideRetweetMetricsLabel": { 210 | "message": "转推" 211 | }, 212 | "hideSeeNewTweetsLabel": { 213 | "message": "隐藏\"查看新推文\"" 214 | }, 215 | "hideShareTweetButtonLabel": { 216 | "message": "推文下的分享按钮" 217 | }, 218 | "hideSidebarContentLabel": { 219 | "message": "隐藏侧边栏内容" 220 | }, 221 | "hideSpacesNavLabel": { 222 | "message": "创建你的空间" 223 | }, 224 | "hideSubscriptionsLabel": { 225 | "message": "隐藏订阅服务" 226 | }, 227 | "hideSuggestedFollowsLabel": { 228 | "message": "隐藏推荐关注" 229 | }, 230 | "hideTimelineTweetBoxLabel": { 231 | "message": "时间线推文框" 232 | }, 233 | "hideToggleNavigationLabel": { 234 | "message": "隐藏切换导航" 235 | }, 236 | "hideTweetAnalyticsLinksLabel": { 237 | "message": "您自己的推文下的\"查看 帖子 互动量\"" 238 | }, 239 | "hideTwitterBlueRepliesLabel": { 240 | "message": "隐藏Premium蓝色勾号回复" 241 | }, 242 | "hideTwitterBlueUpsellsLabel": { 243 | "message": "隐藏Premium强制销售" 244 | }, 245 | "hideUnavailableQuoteTweetsLabel": { 246 | "message": "隐藏对已屏蔽和已静音账号的引用和回复" 247 | }, 248 | "hideUnusedUiItemsOptionsLabel": { 249 | "message": "隐藏你不使用的用户界面项目" 250 | }, 251 | "hideVerifiedNotificationsTabLabel": { 252 | "message": "隐藏通知和关注者中的\"认证\"选项卡" 253 | }, 254 | "hideViewsLabel": { 255 | "message": "隐藏推文下的观点" 256 | }, 257 | "hideWhatsHappeningLabel": { 258 | "message": "隐藏“正在发生的事”" 259 | }, 260 | "hideWhoToFollowEtcLabel": { 261 | "message": "在时间线中隐藏\"关注谁\", \"关注一些话题\"等" 262 | }, 263 | "homeTimelineOptionsLabel": { 264 | "message": "主页时间线" 265 | }, 266 | "listRetweetsLabel": { 267 | "message": "转推列表" 268 | }, 269 | "mostLiked": { 270 | "message": "最多点赞" 271 | }, 272 | "mostRecent": { 273 | "message": "最近" 274 | }, 275 | "mostRelevant": { 276 | "message": "最相关" 277 | }, 278 | "mutableQuoteTweetsLabel": { 279 | "message": "对特定推文进行隐藏引用" 280 | }, 281 | "mutedTweetsLabel": { 282 | "message": "已隐藏推文 ($COUNT$)", 283 | "placeholders": { 284 | "count": { 285 | "content": "$1", 286 | "example": "1" 287 | } 288 | } 289 | }, 290 | "navBaseFontSizeLabel": { 291 | "message": "在导航栏中使用正常的文本字体样式" 292 | }, 293 | "navDensityLabel": { 294 | "message": "导航密度" 295 | }, 296 | "notificationsLabel": { 297 | "message": "通知" 298 | }, 299 | "option_badges": { 300 | "message": "仅隐藏徽章" 301 | }, 302 | "option_comfortable": { 303 | "message": "舒适" 304 | }, 305 | "option_compact": { 306 | "message": "紧凑" 307 | }, 308 | "option_default": { 309 | "message": "默认" 310 | }, 311 | "option_hide": { 312 | "message": "隐藏" 313 | }, 314 | "option_ignore": { 315 | "message": "什么都不做" 316 | }, 317 | "option_liked": { 318 | "message": "喜欢" 319 | }, 320 | "option_recent": { 321 | "message": "最新" 322 | }, 323 | "option_relevant": { 324 | "message": "相关性" 325 | }, 326 | "option_separate": { 327 | "message": "在单独的标签中显示" 328 | }, 329 | "preventNextVideoAutoplayInfo": { 330 | "message": "视频将循环播放" 331 | }, 332 | "preventNextVideoAutoplayLabel": { 333 | "message": "防止下一个视频自动播放" 334 | }, 335 | "quoteTweetsLabel": { 336 | "message": "引用推文" 337 | }, 338 | "redirectToTwitterLabel": { 339 | "message": "重定向到 twitter.com" 340 | }, 341 | "reduceAlgorithmicContentOptionsLabel": { 342 | "message": "删除算法性内容" 343 | }, 344 | "reduceEngagementOptionsLabel": { 345 | "message": "降低 \"参与\"" 346 | }, 347 | "reducedInteractionModeInfo": { 348 | "message": "隐藏推文下的动作栏--回复现在是唯一的互动方式" 349 | }, 350 | "reducedInteractionModeLabel": { 351 | "message": "减少互动模式" 352 | }, 353 | "replaceLogoLabel": { 354 | "message": "更换 X 品牌变更" 355 | }, 356 | "restoreLinkHeadlinesLabel": { 357 | "message": "恢复外部链接下的标题" 358 | }, 359 | "restoreOtherInteractionLinksLabel": { 360 | "message": "恢复推文下的其他链接" 361 | }, 362 | "restoreQuoteTweetsLinkLabel": { 363 | "message": "恢复推文下的“引用推文”链接" 364 | }, 365 | "restoreTweetSourceLabel": { 366 | "message": "恢复推文来源标签" 367 | }, 368 | "retweetsLabel": { 369 | "message": "转发" 370 | }, 371 | "saveAndApplyButton": { 372 | "message": "保存并应用" 373 | }, 374 | "sharedTweetsOptionsLabel": { 375 | "message": "其他用户分享的推文" 376 | }, 377 | "showBlueReplyFollowersCountAmountLabel": { 378 | "message": "粉丝数" 379 | }, 380 | "showBlueReplyFollowersCountLabel": { 381 | "message": "显示粉丝数超过$AMOUNT$的账户", 382 | "placeholders": { 383 | "amount": { 384 | "content": "$1" 385 | } 386 | } 387 | }, 388 | "showBookmarkButtonUnderFocusedTweetsLabel": { 389 | "message": "在焦点推文下显示" 390 | }, 391 | "showPremiumReplyBusinessLabel": { 392 | "message": "显示已验证的企业账户" 393 | }, 394 | "showPremiumReplyFollowedByLabel": { 395 | "message": "显示关注我的账户" 396 | }, 397 | "showPremiumReplyFollowingLabel": { 398 | "message": "显示我关注的账户" 399 | }, 400 | "showPremiumReplyGovernmentLabel": { 401 | "message": "显示已验证的政府账户" 402 | }, 403 | "showRelevantPeopleLabel": { 404 | "message": "查看推文时显示\"相关人员\"" 405 | }, 406 | "sidebarLabel": { 407 | "message": "侧边栏" 408 | }, 409 | "sortReplies": { 410 | "message": "对回复排序" 411 | }, 412 | "sortRepliesLabel": { 413 | "message": "回复的默认排序" 414 | }, 415 | "tweakNewLayoutInfo": { 416 | "message": "实验性功能 - 仅在您拥有新布局时启用" 417 | }, 418 | "tweakNewLayoutLabel": { 419 | "message": "调整新布局" 420 | }, 421 | "tweakQuoteTweetsPageLabel": { 422 | "message": "查看引用推文时隐藏被引用的推文" 423 | }, 424 | "twitterBlueChecksLabel": { 425 | "message": "Premium蓝色支票" 426 | }, 427 | "twitterBlueChecksOption_replace": { 428 | "message": "替换为Twitter Blue标识" 429 | }, 430 | "uiImprovementsOptionsLabel": { 431 | "message": "用户界面改进" 432 | }, 433 | "uiTweaksOptionsLabel": { 434 | "message": "用户界面调整" 435 | }, 436 | "unblurSensitiveContentLabel": { 437 | "message": "消除敏感内容的模糊" 438 | }, 439 | "uninvertFollowButtonsLabel": { 440 | "message": "取消 关注着/正在关注 按钮" 441 | }, 442 | "unmuteButtonText": { 443 | "message": "取消隐藏" 444 | }, 445 | "xFixesLabel": { 446 | "message": "X 修复" 447 | } 448 | } -------------------------------------------------------------------------------- /background.js: -------------------------------------------------------------------------------- 1 | const isSafari = location.protocol.startsWith('safari-web-extension:') 2 | 3 | const enabledIcons = { 4 | 16: 'icons/icon16.png', 5 | 32: 'icons/icon32.png', 6 | 48: 'icons/icon48.png', 7 | 64: 'icons/icon64.png', 8 | 96: 'icons/icon96.png', 9 | 128: 'icons/icon128.png', 10 | } 11 | 12 | const disabledIcons = { 13 | 16: 'icons/icon16-disabled.png', 14 | 32: 'icons/icon32-disabled.png', 15 | 48: 'icons/icon48-disabled.png', 16 | 64: 'icons/icon64-disabled.png', 17 | 96: 'icons/icon96-disabled.png', 18 | 128: 'icons/icon128-disabled.png', 19 | } 20 | 21 | function updateToolbarIcon(enabled) { 22 | let title = chrome.i18n.getMessage(enabled ? 'extensionName' : 'extensionNameDisabled') 23 | if (chrome.runtime.getManifest().manifest_version == 3) { 24 | chrome.action.setTitle({title}) 25 | if (!isSafari) { 26 | chrome.action.setIcon({path: enabled ? enabledIcons : disabledIcons}) 27 | } else { 28 | chrome.action.setBadgeText({text: enabled ? '' : '⏻'}) 29 | } 30 | } else { 31 | chrome.browserAction.setTitle({title}) 32 | chrome.browserAction.setIcon({path: enabled ? enabledIcons : disabledIcons}) 33 | } 34 | } 35 | 36 | // Update browser action icon to reflect enabled state 37 | chrome.storage.local.get({enabled: true}, ({enabled}) => { 38 | updateToolbarIcon(enabled) 39 | }) 40 | 41 | chrome.storage.local.onChanged.addListener((changes) => { 42 | if (changes.enabled) { 43 | updateToolbarIcon(changes.enabled.newValue) 44 | } 45 | }) -------------------------------------------------------------------------------- /content.js: -------------------------------------------------------------------------------- 1 | /** @type {HTMLScriptElement} */ 2 | let $settings 3 | 4 | const isSafari = navigator.userAgent.includes('Safari/') && !/Chrom(e|ium)\//.test(navigator.userAgent) 5 | const twitterBlue = 'rgb(29, 155, 240)' 6 | const twitterLogoPath = 'M23.643 4.937c-.835.37-1.732.62-2.675.733.962-.576 1.7-1.49 2.048-2.578-.9.534-1.897.922-2.958 1.13-.85-.904-2.06-1.47-3.4-1.47-2.572 0-4.658 2.086-4.658 4.66 0 .364.042.718.12 1.06-3.873-.195-7.304-2.05-9.602-4.868-.4.69-.63 1.49-.63 2.342 0 1.616.823 3.043 2.072 3.878-.764-.025-1.482-.234-2.11-.583v.06c0 2.257 1.605 4.14 3.737 4.568-.392.106-.803.162-1.227.162-.3 0-.593-.028-.877-.082.593 1.85 2.313 3.198 4.352 3.234-1.595 1.25-3.604 1.995-5.786 1.995-.376 0-.747-.022-1.112-.065 2.062 1.323 4.51 2.093 7.14 2.093 8.57 0 13.255-7.098 13.255-13.254 0-.2-.005-.402-.014-.602.91-.658 1.7-1.477 2.323-2.41z' 7 | const xLogoPath = 'M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z' 8 | 9 | if (localStorage.cpftEnabled != 'false' && localStorage.cpftReplaceLogo != 'false') { 10 | if (!isSafari) { 11 | let $style = document.createElement('style') 12 | $style.id = 'cpftLoading' 13 | $style.textContent = ` 14 | svg path[d="${xLogoPath}"] { 15 | fill: ${twitterBlue}; 16 | d: path("${twitterLogoPath}"); 17 | } 18 | ` 19 | document.documentElement.append($style) 20 | } else { 21 | let startTime = Date.now() 22 | new MutationObserver((_, observer) => { 23 | let $logoPath = document.querySelector(`svg path[d="${xLogoPath}"]`) 24 | if ($logoPath) { 25 | $logoPath.setAttribute('d', twitterLogoPath) 26 | $logoPath.setAttribute('fill', twitterBlue) 27 | observer.disconnect() 28 | } 29 | else if (Date.now() - startTime > 1000) { 30 | observer.disconnect() 31 | } 32 | }).observe(document.documentElement, {childList: true, subtree: true}) 33 | } 34 | } 35 | 36 | // Get initial config and inject it and the main script into the Twitter page 37 | chrome.storage.local.get((/** @type {Partial} */ storedConfig) => { 38 | // Update deprecated config values 39 | // @ts-ignore 40 | if (storedConfig.twitterBlueChecks == 'dim') { 41 | storedConfig.twitterBlueChecks = 'replace' 42 | } 43 | 44 | $settings = document.createElement('script') 45 | $settings.type = 'text/json' 46 | $settings.id = 'cpftSettings' 47 | document.documentElement.appendChild($settings) 48 | $settings.innerText = JSON.stringify(storedConfig) 49 | 50 | let $main = document.createElement('script') 51 | $main.src = chrome.runtime.getURL('script.js') 52 | $main.onload = function() { 53 | this.remove() 54 | } 55 | document.documentElement.appendChild($main) 56 | 57 | chrome.storage.onChanged.addListener(onConfigChange) 58 | }) 59 | 60 | // Inject config changes from options pages into the settings 9 | 10 | 11 | Control Panel for Twitter Icon 12 |

You can turn on Control Panel for Twitter’s Safari extension in Settings.

13 |

You can turn on Control Panel for Twitter’s extension in Safari Extensions preferences.

14 |

Control Panel for Twitter’s extension is currently on. You can turn it off in Safari Extensions preferences.

15 |

Control Panel for Twitter’s extension is currently off. You can turn it on in Safari Extensions preferences.

16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /safari/Shared (App)/Resources/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/safari/Shared (App)/Resources/Icon.png -------------------------------------------------------------------------------- /safari/Shared (App)/Resources/Script.js: -------------------------------------------------------------------------------- 1 | function show(platform, enabled, useSettingsInsteadOfPreferences) { 2 | document.body.classList.add(`platform-${platform}`) 3 | 4 | if (useSettingsInsteadOfPreferences) { 5 | document.querySelector('.platform-mac.state-on').innerText = 'Control Panel for Twitter’s extension is currently on. You can turn it off in the Extensions section of Safari Settings.' 6 | document.querySelector('.platform-mac.state-off').innerText = 'Control Panel for Twitter’s extension is currently off. You can turn it on in the Extensions section of Safari Settings.' 7 | document.querySelector('.platform-mac.state-unknown').innerText = 'You can turn on Control Panel for Twitter’s extension in the Extensions section of Safari Settings.' 8 | document.querySelector('.open-preferences').innerText = 'Quit and Open Safari Settings…' 9 | } 10 | 11 | if (typeof enabled === 'boolean') { 12 | document.body.classList.toggle(`state-on`, enabled) 13 | document.body.classList.toggle(`state-off`, !enabled) 14 | } else { 15 | document.body.classList.remove(`state-on`) 16 | document.body.classList.remove(`state-off`) 17 | } 18 | 19 | if (platform === 'ios') { 20 | document.querySelector('.open-preferences').innerText = 'Open Safari Settings…' 21 | } 22 | } 23 | 24 | function openPreferences() { 25 | 26 | } 27 | 28 | document.querySelector('button.open-preferences').addEventListener('click', () => { 29 | webkit.messageHandlers.controller.postMessage('open-preferences') 30 | }) 31 | -------------------------------------------------------------------------------- /safari/Shared (App)/Resources/Style.css: -------------------------------------------------------------------------------- 1 | * { 2 | -webkit-user-select: none; 3 | -webkit-user-drag: none; 4 | cursor: default; 5 | } 6 | 7 | :root { 8 | color-scheme: light dark; 9 | 10 | --spacing: 20px; 11 | } 12 | 13 | html { 14 | height: 100%; 15 | } 16 | 17 | body { 18 | display: flex; 19 | align-items: center; 20 | justify-content: center; 21 | flex-direction: column; 22 | 23 | gap: var(--spacing); 24 | margin: 0 calc(var(--spacing) * 2); 25 | height: 100%; 26 | 27 | font: -apple-system-short-body; 28 | text-align: center; 29 | } 30 | 31 | body:not(.platform-mac, .platform-ios) :is(.platform-mac, .platform-ios) { 32 | display: none; 33 | } 34 | 35 | body.platform-ios .platform-mac { 36 | display: none; 37 | } 38 | 39 | body.platform-mac .platform-ios { 40 | display: none; 41 | } 42 | 43 | body.platform-ios .platform-mac { 44 | display: none; 45 | } 46 | 47 | body:not(.state-on, .state-off) :is(.state-on, .state-off) { 48 | display: none; 49 | } 50 | 51 | body.state-on :is(.state-off, .state-unknown) { 52 | display: none; 53 | } 54 | 55 | body.state-off :is(.state-on, .state-unknown) { 56 | display: none; 57 | } 58 | 59 | button { 60 | font-size: 1em; 61 | } 62 | -------------------------------------------------------------------------------- /safari/Shared (App)/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Shared (App) 4 | // 5 | 6 | import WebKit 7 | 8 | #if os(iOS) 9 | import UIKit 10 | typealias PlatformViewController = UIViewController 11 | #elseif os(macOS) 12 | import Cocoa 13 | import SafariServices 14 | typealias PlatformViewController = NSViewController 15 | #endif 16 | 17 | let extensionBundleIdentifier = "dev.jbscript.Tweak-New-Twitter.Extension" 18 | 19 | class ViewController: PlatformViewController, WKNavigationDelegate, WKScriptMessageHandler { 20 | 21 | @IBOutlet var webView: WKWebView! 22 | 23 | override func viewDidLoad() { 24 | super.viewDidLoad() 25 | 26 | self.webView.navigationDelegate = self 27 | 28 | #if os(iOS) 29 | self.webView.scrollView.isScrollEnabled = false 30 | #endif 31 | 32 | self.webView.configuration.userContentController.add(self, name: "controller") 33 | 34 | self.webView.loadFileURL(Bundle.main.url(forResource: "Main", withExtension: "html")!, allowingReadAccessTo: Bundle.main.resourceURL!) 35 | } 36 | 37 | func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { 38 | #if os(iOS) 39 | webView.evaluateJavaScript("show('ios')") 40 | #elseif os(macOS) 41 | webView.evaluateJavaScript("show('mac')") 42 | 43 | SFSafariExtensionManager.getStateOfSafariExtension(withIdentifier: extensionBundleIdentifier) { (state, error) in 44 | guard let state = state, error == nil else { 45 | // Insert code to inform the user that something went wrong. 46 | return 47 | } 48 | 49 | DispatchQueue.main.async { 50 | if #available(macOS 13, *) { 51 | webView.evaluateJavaScript("show('mac', \(state.isEnabled), true)") 52 | } else { 53 | webView.evaluateJavaScript("show('mac', \(state.isEnabled), false)") 54 | } 55 | } 56 | } 57 | #endif 58 | } 59 | 60 | func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { 61 | if (message.body as! String != "open-preferences") { 62 | return 63 | } 64 | #if os(iOS) 65 | if #available(iOS 18.0, *) { 66 | let url = URL(string: "App-Prefs:com.apple.mobilesafari")! 67 | guard UIApplication.shared.canOpenURL(url) else { 68 | return 69 | } 70 | UIApplication.shared.open(url) 71 | } else { 72 | let url = URL(string: "App-Prefs:Safari&path=WEB_EXTENSIONS")! 73 | guard UIApplication.shared.canOpenURL(url) else { 74 | return 75 | } 76 | UIApplication.shared.open(url) 77 | } 78 | #elseif os(macOS) 79 | SFSafariApplication.showPreferencesForExtension(withIdentifier: extensionBundleIdentifier) { error in 80 | guard error == nil else { 81 | // Insert code to inform the user that something went wrong. 82 | return 83 | } 84 | 85 | DispatchQueue.main.async { 86 | NSApplication.shared.terminate(nil) 87 | } 88 | } 89 | #endif 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /safari/Shared (Extension)/Resources/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "default_locale": "en", 4 | "name": "__MSG_extensionName__", 5 | "description": "__MSG_extensionDescriptionShort__", 6 | "homepage_url": "https://soitis.dev/control-panel-for-twitter", 7 | "version": "4.12.2", 8 | "icons": { 9 | "48": "icon48.png", 10 | "96": "icon96.png", 11 | "128": "icon128.png", 12 | "256": "icon256.png", 13 | "512": "icon512.png" 14 | }, 15 | "background": { 16 | "service_worker": "background.js", 17 | "type": "module" 18 | }, 19 | "content_scripts": [ 20 | { 21 | "matches": [ 22 | "https://twitter.com/*", 23 | "https://mobile.twitter.com/*", 24 | "https://x.com/*", 25 | "https://mobile.x.com/*" 26 | ], 27 | "js": [ 28 | "content.js" 29 | ], 30 | "run_at": "document_start" 31 | } 32 | ], 33 | "web_accessible_resources": [ 34 | { 35 | "matches": [ 36 | "https://twitter.com/*", 37 | "https://mobile.twitter.com/*", 38 | "https://x.com/*", 39 | "https://mobile.x.com/*" 40 | ], 41 | "resources": [ 42 | "script.js" 43 | ] 44 | } 45 | ], 46 | "options_ui": { 47 | "browser_style": true, 48 | "page": "options.html" 49 | }, 50 | "action": { 51 | "default_title": "__MSG_extensionName__", 52 | "default_popup": "browser_action.html", 53 | "default_icon": { 54 | "16": "toolbar-icon16.png", 55 | "19": "toolbar-icon19.png", 56 | "32": "toolbar-icon32.png", 57 | "38": "toolbar-icon38.png", 58 | "48": "toolbar-icon48.png", 59 | "72": "toolbar-icon72.png" 60 | } 61 | }, 62 | "permissions": [ 63 | "storage" 64 | ] 65 | } -------------------------------------------------------------------------------- /safari/Shared (Extension)/SafariWebExtensionHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SafariWebExtensionHandler.swift 3 | // Shared (Extension) 4 | // 5 | 6 | import SafariServices 7 | import os.log 8 | 9 | let SFExtensionMessageKey = "message" 10 | 11 | class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling { 12 | 13 | func beginRequest(with context: NSExtensionContext) { 14 | let item = context.inputItems[0] as! NSExtensionItem 15 | let message = item.userInfo?[SFExtensionMessageKey] 16 | os_log(.default, "Received message from browser.runtime.sendNativeMessage: %@", message as! CVarArg) 17 | 18 | let response = NSExtensionItem() 19 | response.userInfo = [ SFExtensionMessageKey: [ "Response to": message ] ] 20 | 21 | context.completeRequest(returningItems: [response], completionHandler: nil) 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /safari/iOS (App)/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // iOS (App) 4 | // 5 | 6 | import UIKit 7 | 8 | @main 9 | class AppDelegate: UIResponder, UIApplicationDelegate { 10 | 11 | var window: UIWindow? 12 | 13 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 14 | // Override point for customization after application launch. 15 | return true 16 | } 17 | 18 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 19 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /safari/iOS (App)/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /safari/iOS (App)/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /safari/iOS (App)/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIApplicationSceneManifest 6 | 7 | UIApplicationSupportsMultipleScenes 8 | 9 | UISceneConfigurations 10 | 11 | UIWindowSceneSessionRoleApplication 12 | 13 | 14 | UISceneConfigurationName 15 | Default Configuration 16 | UISceneDelegateClassName 17 | $(PRODUCT_MODULE_NAME).SceneDelegate 18 | UISceneStoryboardFile 19 | Main 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /safari/iOS (App)/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // iOS (App) 4 | // 5 | 6 | import UIKit 7 | 8 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 9 | 10 | var window: UIWindow? 11 | 12 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 13 | guard let _ = (scene as? UIWindowScene) else { return } 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /safari/iOS (Extension)/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionPointIdentifier 8 | com.apple.Safari.web-extension 9 | NSExtensionPrincipalClass 10 | $(PRODUCT_MODULE_NAME).SafariWebExtensionHandler 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /safari/macOS (App)/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // macOS (App) 4 | // 5 | 6 | import Cocoa 7 | 8 | @main 9 | class AppDelegate: NSObject, NSApplicationDelegate { 10 | 11 | func applicationDidFinishLaunching(_ notification: Notification) { 12 | // Override point for customization after application launch. 13 | } 14 | 15 | func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 16 | return true 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /safari/macOS (App)/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 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 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /safari/macOS (App)/Tweak New Twitter.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.network.client 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /safari/macOS (Extension)/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionPointIdentifier 8 | com.apple.Safari.web-extension 9 | NSExtensionPrincipalClass 10 | $(PRODUCT_MODULE_NAME).SafariWebExtensionHandler 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /safari/macOS (Extension)/Tweak New Twitter.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /screenshots/arabic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/arabic.png -------------------------------------------------------------------------------- /screenshots/chirp_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/chirp_off.png -------------------------------------------------------------------------------- /screenshots/chirp_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/chirp_on.png -------------------------------------------------------------------------------- /screenshots/disable_home_timeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/disable_home_timeline.png -------------------------------------------------------------------------------- /screenshots/firefox_android_disable_home_timeline.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/firefox_android_disable_home_timeline.jpg -------------------------------------------------------------------------------- /screenshots/firefox_android_explore.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/firefox_android_explore.jpg -------------------------------------------------------------------------------- /screenshots/firefox_android_hide_metrics.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/firefox_android_hide_metrics.jpg -------------------------------------------------------------------------------- /screenshots/firefox_android_menu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/firefox_android_menu.jpg -------------------------------------------------------------------------------- /screenshots/firefox_android_options_popup.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/firefox_android_options_popup.jpg -------------------------------------------------------------------------------- /screenshots/firefox_android_quote_tweets.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/firefox_android_quote_tweets.jpg -------------------------------------------------------------------------------- /screenshots/firefox_android_reduced_interaction_mode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/firefox_android_reduced_interaction_mode.jpg -------------------------------------------------------------------------------- /screenshots/firefox_android_shared_tweets.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/firefox_android_shared_tweets.jpg -------------------------------------------------------------------------------- /screenshots/firefox_android_timeline.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/firefox_android_timeline.jpg -------------------------------------------------------------------------------- /screenshots/full_width_timeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/full_width_timeline.png -------------------------------------------------------------------------------- /screenshots/hide_metrics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/hide_metrics.png -------------------------------------------------------------------------------- /screenshots/irish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/irish.png -------------------------------------------------------------------------------- /screenshots/japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/japanese.png -------------------------------------------------------------------------------- /screenshots/more_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/more_menu.png -------------------------------------------------------------------------------- /screenshots/options_popup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/options_popup.png -------------------------------------------------------------------------------- /screenshots/quote_tweets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/quote_tweets.png -------------------------------------------------------------------------------- /screenshots/reduced_interaction_mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/reduced_interaction_mode.png -------------------------------------------------------------------------------- /screenshots/shared_tweets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/shared_tweets.png -------------------------------------------------------------------------------- /screenshots/timeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/timeline.png -------------------------------------------------------------------------------- /screenshots/uninverted_follow_buttons_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/uninverted_follow_buttons_monochrome.png -------------------------------------------------------------------------------- /screenshots/uninverted_follow_buttons_themed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/screenshots/uninverted_follow_buttons_themed.png -------------------------------------------------------------------------------- /scripts/build.js: -------------------------------------------------------------------------------- 1 | const {execSync} = require('child_process') 2 | const path = require('path') 3 | const fs = require('fs') 4 | 5 | let manifestVersions = [2, 3] 6 | if (process.argv[2] && manifestVersions.includes(Number(process.argv[2]))) { 7 | manifestVersions = [Number(process.argv[2])] 8 | } 9 | 10 | for (let manifestVersion of manifestVersions) { 11 | console.log(`\nBuilding MV${manifestVersion} version`) 12 | let manifestFile = `manifest.mv${manifestVersion}.json` 13 | let manifestData = require(`../${manifestFile}`) 14 | fs.copyFileSync(`./${manifestFile}`, './manifest.json') 15 | execSync('web-ext build', {stdio: 'inherit'}) 16 | let renameTo = `./web-ext-artifacts/control_panel_for_twitter-${manifestData['version']}.mv${manifestVersion}.zip` 17 | fs.renameSync( 18 | `./web-ext-artifacts/control_panel_for_twitter-${manifestData['version']}.zip`, 19 | renameTo, 20 | ) 21 | console.log('Moved to:', path.resolve(renameTo)) 22 | fs.rmSync('./manifest.json') 23 | } -------------------------------------------------------------------------------- /scripts/copy.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | fs.copyFileSync(process.argv[2], process.argv[3]) -------------------------------------------------------------------------------- /scripts/create-browser-action.js: -------------------------------------------------------------------------------- 1 | // Creates browser_action.html, which is just options.html with styling to 2 | // control the popup width appropriately for each browser. 3 | const fs = require('fs') 4 | 5 | let options = fs.readFileSync('./options.html', {encoding: 'utf8'}) 6 | 7 | fs.writeFileSync( 8 | './browser_action.html', 9 | options.replace('', ''), 10 | {encoding: 'utf8'} 11 | ) -------------------------------------------------------------------------------- /scripts/create-store-description.mjs: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs' 2 | 3 | import clipboard from 'clipboardy' 4 | 5 | let extraTranslations = { 6 | "desktopVersion": { 7 | "en": " (desktop version)", 8 | "es": " (versión de escritorio)", 9 | "fr": " (version de bureau)", 10 | "it": " (versione desktop)", 11 | "ja": "(デスクトップ版)", 12 | "ko": " (데스크톱 버전)", 13 | "zh_CN": "(桌面版)" 14 | }, 15 | "mobileVersion": { 16 | "en": " (mobile version)", 17 | "es": " (versión móvil)", 18 | "fr": " (version mobile)", 19 | "it": " (versione mobile)", 20 | "ja": "(モバイル版)", 21 | "ko": " (모바일 버전)", 22 | "zh_CN": "(手机版)" 23 | } 24 | } 25 | 26 | let localeCode = process.argv[2] 27 | 28 | if (!localeCode) { 29 | console.log(` 30 | Usage: 31 | npm run create-store-description ja 32 | npm run create-store-description ja html 33 | `.trim()) 34 | process.exit(1) 35 | } 36 | 37 | let locale = JSON.parse(fs.readFileSync(`./_locales/${localeCode}/messages.json`, {encoding: 'utf8'})) 38 | let messages = Object.fromEntries(Object.entries(locale).map(([prop, value]) => ([prop, value.message]))) 39 | // Add extra translations 40 | Object.assign(messages, Object.fromEntries(Object.entries(extraTranslations).map(([prop, value]) => [prop, value[localeCode]]))) 41 | 42 | let storeDescription = ` 43 | ${messages.homeTimelineOptionsLabel} 44 | 45 | • ${messages.alwaysUseLatestTweetsLabel} 46 | • ${messages.hideForYouTimelineLabel} 47 | • ${messages.retweetsLabel} 48 | • ${messages.option_separate} / ${messages.option_hide} 49 | • ${messages.quoteTweetsLabel} 50 | • ${messages.option_separate} / ${messages.option_hide} 51 | • ${messages.mutableQuoteTweetsLabel} 52 | • ${messages.hideSeeNewTweetsLabel} 53 | • ${messages.hideWhoToFollowEtcLabel} 54 | • ${messages.hideInlinePrompts} 55 | • ${messages.fullWidthContentLabel}${messages.desktopVersion} 56 | • ${messages.fullWidthContentInfo} 57 | 58 | ${messages.uiImprovementsOptionsLabel} 59 | 60 | • ${messages.preventNextVideoAutoplayLabel}${messages.mobileVersion} 61 | • ${messages.addAddMutedWordMenuItemLabel_desktop} 62 | • ${messages.fastBlockLabel} 63 | • ${messages.hideUnavailableQuoteTweetsLabel} 64 | • ${messages.hideProfileRetweetsLabel} 65 | • ${messages.listRetweetsLabel} 66 | • ${messages.defaultToLatestSearchLabel} 67 | • ${messages.tweakQuoteTweetsPageLabel} 68 | 69 | ${messages.xFixesLabel} 70 | 71 | • ${messages.redirectToTwitterLabel} 72 | • ${messages.tweakNewLayoutLabel} 73 | • ${messages.hideToggleNavigationLabel} 74 | • ${messages.replaceLogoLabel} 75 | • ${messages.hideViewsLabel} 76 | • ${messages.hideVerifiedNotificationsTabLabel} 77 | • ${messages.restoreTweetSourceLabel} 78 | • ${messages.restoreLinkHeadlinesLabel} 79 | • ${messages.restoreQuoteTweetsLinkLabel} 80 | • ${messages.restoreOtherInteractionLinksLabel} 81 | • ${messages.sortRepliesLabel} 82 | • ${messages.option_recent} / ${messages.option_liked} 83 | • ${messages.twitterBlueChecksLabel} 84 | • ${messages.twitterBlueChecksOption_replace} / ${messages.option_hide} 85 | • ${messages.hideTwitterBlueRepliesLabel} 86 | • ${messages.hideTwitterBlueUpsellsLabel} 87 | • ${messages.hideGrokLabel} 88 | • ${messages.hideGrokTweetsLabel} 89 | • ${messages.hideJobsLabel} 90 | • ${messages.hideSubscriptionsLabel} 91 | 92 | ${messages.uiTweaksOptionsLabel} 93 | 94 | • ${messages.dontUseChirpFontLabel} 95 | • ${messages.disableTweetTextFormattingLabel} 96 | • ${messages.navBaseFontSizeLabel}${messages.desktopVersion} 97 | • ${messages.navDensityLabel}${messages.desktopVersion} 98 | • ${messages.option_comfortable} / ${messages.option_compact} 99 | • ${messages.dropdownMenuFontWeightLabel} 100 | • ${messages.uninvertFollowButtonsLabel} 101 | • ${messages.followButtonStyleOption_monochrome} / ${messages.followButtonStyleOption_themed} 102 | • ${messages.unblurSensitiveContentLabel} 103 | 104 | ${messages.reduceAlgorithmicContentOptionsLabel} 105 | 106 | • ${messages.hideSidebarContentLabel}${messages.desktopVersion} 107 | • ${messages.hideExplorePageContentsLabel} 108 | • ${messages.hideDiscoverSuggestionsLabel} 109 | 110 | ${messages.reduceEngagementOptionsLabel} 111 | 112 | • ${messages.hideMetricsLabel} 113 | • ${messages.reducedInteractionModeLabel} 114 | • ${messages.reducedInteractionModeInfo} 115 | • ${messages.hideComposeTweetLabel} 116 | • ${messages.disableHomeTimelineLabel} 117 | • ${messages.disableHomeTimelineInfo} 118 | • ${messages.notificationsLabel} 119 | • ${messages.option_badges} / ${messages.option_hide} 120 | 121 | ${messages.hideUnusedUiItemsOptionsLabel} 122 | 123 | • ${messages.hideBookmarkButtonLabel} 124 | • ${messages.hideShareTweetButtonLabel} 125 | • ${messages.hideTweetAnalyticsLinksLabel} 126 | • ${messages.hideTimelineTweetBoxLabel}${messages.desktopVersion} 127 | • ${messages.hideAccountSwitcherLabel}${messages.desktopVersion} 128 | • ${messages.hideMessagesDrawerLabel}${messages.desktopVersion} 129 | • ${messages.hideExploreNavLabel}${messages.desktopVersion} 130 | • ${messages.hideCommunitiesNavLabel} 131 | • ${messages.hideMoreSlideOutMenuItemsOptionsLabel_desktop} 132 | `.trim() 133 | 134 | if (process.argv[3] == 'html') { 135 | // XXX This depends _very specifically_ on the way dashes, spaces and newlines 136 | // are used in the template string above. 137 | storeDescription = `${messages.features}:\n\n` + storeDescription 138 | // 2 nested items 139 | .replace(/^• ([^\n]+)\n • ([^\n]+)\n • ([^\n]+)/gm, '
  • $1
  • ') 140 | // 1 nested item 141 | .replace(/^• ([^\n]+)\n • ([^\n]+)/gm, '
  • $1
  • ') 142 | // No nested items 143 | .replace(/^• ([^\n]+)/gm, '
  • $1
  • ') 144 | // Section titles 145 | .replace(/^([^\n<][^\n]+)\n\n/gm, '$1\n\n') 148 | .replace(/$/, '\n') 149 | } else { 150 | storeDescription = `${messages.features}:\n\n` + storeDescription 151 | } 152 | 153 | storeDescription += '\n\nTWITTER, TWEET and RETWEET are trademarks of Twitter Inc. or its affiliates' 154 | 155 | clipboard.writeSync(storeDescription) 156 | console.log(storeDescription) -------------------------------------------------------------------------------- /scripts/locales/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": false, 3 | "semi": false, 4 | "singleQuote": true 5 | } -------------------------------------------------------------------------------- /scripts/locales/README.md: -------------------------------------------------------------------------------- 1 | ## Updating Locales 2 | 3 | ### Get locale files from Twitter 4 | 5 | > Tweak `html/_files.txt` and `create-js-curl-config.js` first if locales have changed. 6 | 7 | ```sh 8 | (cd html && curl -K _files.txt) 9 | node create-js-curl-config.js 10 | (cd js && curl -K _files.txt) 11 | ``` 12 | 13 | ### Create locale object for script.js 14 | 15 | Run `node create-locales.js` to create `locales.js`. 16 | 17 | Open it, save to format it with Prettier, then use its contents to update `script.js`. 18 | -------------------------------------------------------------------------------- /scripts/locales/create-js-curl-config.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | let curlConfig = '' 5 | for (let file of fs.readdirSync('./html')) { 6 | if (!file.endsWith('.html')) continue 7 | let localeCode = file.split('.')[0] 8 | let html = fs.readFileSync(path.join('html', file), {encoding: 'utf8'}) 9 | let match = html.match( 10 | new RegExp( 11 | `https://abs\\.twimg\\.com/responsive-web/client-web-legacy/i18n/${localeCode}\\.(?:[a-z\\d]+)\\.js` 12 | ) 13 | ) 14 | 15 | if (!match) { 16 | console.log('could not find locale file URL', {file, localeCode}) 17 | continue 18 | } 19 | 20 | curlConfig += `-o ${localeCode}.js\nurl="${match[0]}"\n` 21 | } 22 | 23 | fs.writeFileSync('./js/_files.txt', curlConfig) 24 | -------------------------------------------------------------------------------- /scripts/locales/create-locales.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | const {sortProperties} = require('../utils') 5 | 6 | /** @type Record> */ 7 | const locales = JSON.parse(fs.readFileSync('./base-locales.json', 'utf-8')) 8 | 9 | // These codes are from Twitter's locale files 10 | let template = { 11 | ADD_MUTED_WORD: 'd768049c', 12 | GROK_ACTIONS: 'e3eceda6', 13 | HOME: 'ha8209bc', 14 | LIKES: 'd7b8ebaa', 15 | LIVE_ON_X: 'd961a4a0', 16 | MUTE_THIS_CONVERSATION: 'e2d6c17e', 17 | POST_ALL: 'ge8e4a38', 18 | PROFILE_SUMMARY: 'fc7db594', 19 | QUOTE: 'bb5c5864', 20 | QUOTES: 'j45978a8', 21 | REPOST: 'g062295e', 22 | REPOSTS: 'ja42739e', 23 | SHOW: 'a0e81a2e', 24 | SHOW_MORE_REPLIES: 'c837fcaa', 25 | SORT_REPLIES_BY: 'ad6e11ac', 26 | } 27 | 28 | for (let file of fs.readdirSync('./js')) { 29 | if (!file.endsWith('.js')) continue 30 | let localeCode = file.split('.')[0] 31 | let locale = locales[localeCode] 32 | let src = fs.readFileSync(path.join('js', file), {encoding: 'utf8'}) 33 | for (let [key, code] of Object.entries(template)) { 34 | let match = src.match(new RegExp(`"${code}","([^"]+)"`)) 35 | if (!match) match = src.match(new RegExp(`"${code}",'([^']+)'`)) 36 | if (match) { 37 | locale[key] = match[1] 38 | } else { 39 | console.log('no match', {file, key, code}) 40 | } 41 | } 42 | locales[localeCode] = sortProperties(locale) 43 | } 44 | 45 | // Delete translations which duplicate English (the fallback locale) 46 | for (let localeCode in locales) { 47 | if (localeCode == 'en') continue 48 | let locale = locales[localeCode] 49 | for (let translationKey in locale) { 50 | if (locale[translationKey] == locales['en'][translationKey]) { 51 | delete locale[translationKey] 52 | } 53 | } 54 | } 55 | 56 | fs.writeFileSync( 57 | 'locales.js', 58 | `const locales = ${JSON.stringify(locales, null, 2)}`, 59 | 'utf8' 60 | ) 61 | -------------------------------------------------------------------------------- /scripts/locales/html/_files.txt: -------------------------------------------------------------------------------- 1 | -L 2 | --cookie nope 3 | -o ar-x-fm.html 4 | url="https://x.com/?mx=2&lang=ar-x-fm" 5 | -L 6 | --cookie nope 7 | -o ar.html 8 | url="https://x.com/?mx=2&lang=ar" 9 | -L 10 | --cookie nope 11 | -o bg.html 12 | url="https://x.com/?mx=2&lang=bg" 13 | -L 14 | --cookie nope 15 | -o bn.html 16 | url="https://x.com/?mx=2&lang=bn" 17 | -L 18 | --cookie nope 19 | -o ca.html 20 | url="https://x.com/?mx=2&lang=ca" 21 | -L 22 | --cookie nope 23 | -o cs.html 24 | url="https://x.com/?mx=2&lang=cs" 25 | -L 26 | --cookie nope 27 | -o da.html 28 | url="https://x.com/?mx=2&lang=da" 29 | -L 30 | --cookie nope 31 | -o de.html 32 | url="https://x.com/?mx=2&lang=de" 33 | -L 34 | --cookie nope 35 | -o el.html 36 | url="https://x.com/?mx=2&lang=el" 37 | -L 38 | --cookie nope 39 | -o en.html 40 | url="https://x.com/?mx=2&lang=en" 41 | -L 42 | --cookie nope 43 | -o es.html 44 | url="https://x.com/?mx=2&lang=es" 45 | -L 46 | --cookie nope 47 | -o eu.html 48 | url="https://x.com/?mx=2&lang=eu" 49 | -L 50 | --cookie nope 51 | -o fa.html 52 | url="https://x.com/?mx=2&lang=fa" 53 | -L 54 | --cookie nope 55 | -o fi.html 56 | url="https://x.com/?mx=2&lang=fi" 57 | -L 58 | --cookie nope 59 | -o fil.html 60 | url="https://x.com/?mx=2&lang=fil" 61 | -L 62 | --cookie nope 63 | -o fr.html 64 | url="https://x.com/?mx=2&lang=fr" 65 | -L 66 | --cookie nope 67 | -o ga.html 68 | url="https://x.com/?mx=2&lang=ga" 69 | -L 70 | --cookie nope 71 | -o gl.html 72 | url="https://x.com/?mx=2&lang=gl" 73 | -L 74 | --cookie nope 75 | -o gu.html 76 | url="https://x.com/?mx=2&lang=gu" 77 | -L 78 | --cookie nope 79 | -o he.html 80 | url="https://x.com/?mx=2&lang=he" 81 | -L 82 | --cookie nope 83 | -o hi.html 84 | url="https://x.com/?mx=2&lang=hi" 85 | -L 86 | --cookie nope 87 | -o hr.html 88 | url="https://x.com/?mx=2&lang=hr" 89 | -L 90 | --cookie nope 91 | -o hu.html 92 | url="https://x.com/?mx=2&lang=hu" 93 | -L 94 | --cookie nope 95 | -o id.html 96 | url="https://x.com/?mx=2&lang=id" 97 | -L 98 | --cookie nope 99 | -o it.html 100 | url="https://x.com/?mx=2&lang=it" 101 | -L 102 | --cookie nope 103 | -o ja.html 104 | url="https://x.com/?mx=2&lang=ja" 105 | -L 106 | --cookie nope 107 | -o kn.html 108 | url="https://x.com/?mx=2&lang=kn" 109 | -L 110 | --cookie nope 111 | -o ko.html 112 | url="https://x.com/?mx=2&lang=ko" 113 | -L 114 | --cookie nope 115 | -o mr.html 116 | url="https://x.com/?mx=2&lang=mr" 117 | -L 118 | --cookie nope 119 | -o ms.html 120 | url="https://x.com/?mx=2&lang=ms" 121 | -L 122 | --cookie nope 123 | -o nb.html 124 | url="https://x.com/?mx=2&lang=nb" 125 | -L 126 | --cookie nope 127 | -o nl.html 128 | url="https://x.com/?mx=2&lang=nl" 129 | -L 130 | --cookie nope 131 | -o pl.html 132 | url="https://x.com/?mx=2&lang=pl" 133 | -L 134 | --cookie nope 135 | -o pt.html 136 | url="https://x.com/?mx=2&lang=pt" 137 | -L 138 | --cookie nope 139 | -o ro.html 140 | url="https://x.com/?mx=2&lang=ro" 141 | -L 142 | --cookie nope 143 | -o ru.html 144 | url="https://x.com/?mx=2&lang=ru" 145 | -L 146 | --cookie nope 147 | -o sk.html 148 | url="https://x.com/?mx=2&lang=sk" 149 | -L 150 | --cookie nope 151 | -o sr.html 152 | url="https://x.com/?mx=2&lang=sr" 153 | -L 154 | --cookie nope 155 | -o sv.html 156 | url="https://x.com/?mx=2&lang=sv" 157 | -L 158 | --cookie nope 159 | -o ta.html 160 | url="https://x.com/?mx=2&lang=ta" 161 | -L 162 | --cookie nope 163 | -o th.html 164 | url="https://x.com/?mx=2&lang=th" 165 | -L 166 | --cookie nope 167 | -o tr.html 168 | url="https://x.com/?mx=2&lang=tr" 169 | -L 170 | --cookie nope 171 | -o uk.html 172 | url="https://x.com/?mx=2&lang=uk" 173 | -L 174 | --cookie nope 175 | -o ur.html 176 | url="https://x.com/?mx=2&lang=ur" 177 | -L 178 | --cookie nope 179 | -o vi.html 180 | url="https://x.com/?mx=2&lang=vi" 181 | -L 182 | --cookie nope 183 | -o zh-Hant.html 184 | url="https://x.com/?mx=2&lang=zh-Hant" 185 | -L 186 | --cookie nope 187 | -o zh.html 188 | url="https://x.com/?mx=2&lang=zh" 189 | -------------------------------------------------------------------------------- /scripts/locales/js/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/control-panel-for-twitter/6b5125d73f376bd841bcc09ac49fcd73aa464854/scripts/locales/js/.gitkeep -------------------------------------------------------------------------------- /scripts/locales/update-base-locales-from-json.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | const {sortProperties} = require('../utils') 5 | 6 | const baseLocales = JSON.parse(fs.readFileSync('./base-locales.json', 'utf-8')) 7 | 8 | const [translationsFile] = process.argv.slice(2) 9 | if (!translationsFile) { 10 | console.log( 11 | ` 12 | Copies translations from a translations JSON file to base-locales.json 13 | 14 | Where the translations JSON file is in the format: 15 | 16 | { 17 | "NEW_TRANSLATION_KEY": { 18 | "en": "English version", 19 | "es": "Versión en español" 20 | } 21 | } 22 | 23 | Usage: 24 | node update-base-locales-from-json.js base-translations.json 25 | `.trim() 26 | ) 27 | process.exit(1) 28 | } 29 | 30 | if (!fs.existsSync(translationsFile)) { 31 | console.error(`${translationsFile} does not exist`) 32 | process.exit(1) 33 | } 34 | 35 | let translationsJson 36 | try { 37 | translationsJson = JSON.parse(fs.readFileSync(translationsFile, 'utf-8')) 38 | } catch (err) { 39 | console.error(`error parsing ${translationsFile}: ${err}`) 40 | process.exit(1) 41 | } 42 | 43 | for (let [translationKey, translations] of Object.entries(translationsJson)) { 44 | for (let [localeCode, message] of Object.entries(translations)) { 45 | baseLocales[localeCode][translationKey] = message 46 | baseLocales[localeCode] = sortProperties(baseLocales[localeCode]) 47 | } 48 | } 49 | 50 | fs.writeFileSync( 51 | 'base-locales.json', 52 | JSON.stringify(baseLocales, null, 2), 53 | 'utf8' 54 | ) 55 | -------------------------------------------------------------------------------- /scripts/locales/update-base-locales.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | const {sortProperties} = require('../utils') 5 | 6 | const locales = JSON.parse(fs.readFileSync('./base-locales.json', 'utf-8')) 7 | 8 | const [key, code, localesDir = 'js'] = process.argv.slice(2) 9 | if (!key || !code) { 10 | console.log(` 11 | Copies a translation from Twitter's locale files to ./base-locales.json 12 | 13 | Usage: 14 | node update-base-locales.js TWEET 123456 15 | node update-base-locales.js TWEET 123456 ./old 16 | `.trim()) 17 | process.exit(1) 18 | } 19 | 20 | for (let file of fs.readdirSync(localesDir)) { 21 | if (!file.endsWith('.js')) continue 22 | let localeCode = file.split('.')[0] 23 | let locale = locales[localeCode] 24 | let src = fs.readFileSync(path.join(localesDir, file), {encoding: 'utf8'}) 25 | let match = src.match(new RegExp(`"${code}","([^"]+)"`)) 26 | if (match) { 27 | locale[key] = match[1] 28 | } else { 29 | console.log('no match', {file, key, code}) 30 | } 31 | locales[localeCode] = sortProperties(locale) 32 | } 33 | 34 | fs.writeFileSync('base-locales.json', JSON.stringify(locales, null, 2), 'utf8') 35 | -------------------------------------------------------------------------------- /scripts/locales/update-translations.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | const {sortProperties} = require('../utils') 5 | 6 | const [translationKey, code, localesDir = 'js'] = process.argv.slice(2) 7 | if (!translationKey || !code) { 8 | console.log(` 9 | Copies a translation from Twitter's locale files to ../translations.json 10 | 11 | Usage: 12 | node update-translations.js translationKey 123456 13 | node update-translations.js translationKey 123456 ./old 14 | `.trim()) 15 | process.exit(1) 16 | } 17 | 18 | const srcLocales = ['en', 'es', 'fr', 'it', 'ja', 'ko', 'zh'] 19 | // Maps from Twitter locale code to web extension locale code where they differ 20 | const destLocales = {zh: 'zh_CN'} 21 | const translations = JSON.parse( 22 | fs.readFileSync('../translations.json', 'utf-8') 23 | ) 24 | translations[translationKey] = {} 25 | 26 | for (let srcLocale of srcLocales) { 27 | let srcPath = path.join(localesDir, `${srcLocale}.js`) 28 | let src = fs.readFileSync(srcPath, {encoding: 'utf8'}) 29 | let match = src.match(new RegExp(`"${code}","([^"]+)"`)) 30 | if (match) { 31 | let destLocale = destLocales[srcLocale] || srcLocale 32 | translations[translationKey][destLocale] = match[1] 33 | } else { 34 | console.log('no match', {srcPath, code}) 35 | } 36 | } 37 | 38 | fs.writeFileSync( 39 | '../translations.json', 40 | JSON.stringify(sortProperties(translations), null, 2), 41 | 'utf8' 42 | ) 43 | -------------------------------------------------------------------------------- /scripts/mac-appicon-assets.sh: -------------------------------------------------------------------------------- 1 | # Mac: run via `zsh -i ./mac-appicon-assets.sh` if using an alias 2 | 3 | # Requires inkscape to be in your PATH or aliased, e.g. on Mac: 4 | # alias inkscape="/Applications/Inkscape.app/Contents/MacOS/inkscape" 5 | inkscape -w 16 -h 16 ../icons/icon.svg -o ../safari/Shared\ \(App\)/Assets.xcassets/AppIcon.appiconset/appicon16.png 6 | inkscape -w 32 -h 32 ../icons/icon.svg -o ../safari/Shared\ \(App\)/Assets.xcassets/AppIcon.appiconset/appicon32.png 7 | inkscape -w 64 -h 64 ../icons/icon.svg -o ../safari/Shared\ \(App\)/Assets.xcassets/AppIcon.appiconset/appicon64.png 8 | inkscape -w 128 -h 128 ../icons/icon.svg -o ../safari/Shared\ \(App\)/Assets.xcassets/AppIcon.appiconset/appicon128.png 9 | inkscape -w 256 -h 256 ../icons/icon.svg -o ../safari/Shared\ \(App\)/Assets.xcassets/AppIcon.appiconset/appicon256.png 10 | inkscape -w 512 -h 512 ../icons/icon.svg -o ../safari/Shared\ \(App\)/Assets.xcassets/AppIcon.appiconset/appicon512.png 11 | inkscape -w 1024 -h 1024 ../icons/icon.svg -o ../safari/Shared\ \(App\)/Assets.xcassets/AppIcon.appiconset/appicon1024.png -------------------------------------------------------------------------------- /scripts/release.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | 3 | const semver = require('semver') 4 | 5 | const manifestPaths = ['./manifest.mv2.json', './manifest.mv3.json', './Safari/Shared (Extension)/Resources/manifest.json'] 6 | const optionsJsPath = './options.js' 7 | const optionsHtmlPath = './options.html' 8 | const safariProjectPath = './Safari/Control Panel for Twitter.xcodeproj/project.pbxproj' 9 | const scriptPath = './script.js' 10 | 11 | let releaseType = process.argv[2] 12 | 13 | if (!releaseType) { 14 | console.log(` 15 | Usage: 16 | npm run release (patch|minor|major) 17 | `.trim()) 18 | process.exit(1) 19 | } 20 | 21 | let currentVersion = JSON.parse(fs.readFileSync(manifestPaths[0], {encoding: 'utf8'})).version 22 | let nextVersion = semver.inc(currentVersion, releaseType) 23 | 24 | for (let manifestPath of manifestPaths) { 25 | fs.writeFileSync( 26 | manifestPath, 27 | fs.readFileSync(manifestPath, {encoding: 'utf8'}) 28 | .replace(/"version": "[^"]+"/, `"version": "${nextVersion}"`), 29 | {encoding: 'utf8'} 30 | ) 31 | } 32 | 33 | fs.writeFileSync( 34 | optionsJsPath, 35 | fs.readFileSync(optionsJsPath, {encoding: 'utf8'}) 36 | .replace(/control-panel-for-twitter-.+\.config\.txt/, `control-panel-for-twitter-v${nextVersion}.config.txt`), 37 | {encoding: 'utf8'} 38 | ) 39 | 40 | fs.writeFileSync( 41 | optionsHtmlPath, 42 | fs.readFileSync(optionsHtmlPath, {encoding: 'utf8'}) 43 | .replace(/id="version">[^<]+v${nextVersion}<`), 44 | {encoding: 'utf8'} 45 | ) 46 | 47 | fs.writeFileSync( 48 | safariProjectPath, 49 | fs.readFileSync(safariProjectPath, {encoding: 'utf8'}) 50 | .replace(/CURRENT_PROJECT_VERSION = (\d+)/g, (_, current) => `CURRENT_PROJECT_VERSION = ${Number(current) + 1}`) 51 | .replace(/MARKETING_VERSION = [^;]+/g, `MARKETING_VERSION = ${nextVersion}`), 52 | {encoding: 'utf8'} 53 | ) 54 | 55 | fs.writeFileSync( 56 | scriptPath, 57 | fs.readFileSync(scriptPath, {encoding: 'utf8'}) 58 | .replace(/@version (\d+)/g, (_, current) => `@version ${Number(current) + 1}`), 59 | {encoding: 'utf8'} 60 | ) 61 | 62 | console.log(`Bumped to v${nextVersion}`) -------------------------------------------------------------------------------- /scripts/set-safari-screenshot-resolution.applescript: -------------------------------------------------------------------------------- 1 | (* 2 | Sets Safari dimensions for 2880 x 1800 px screenshots - including the drop shadow - at scale=2. 3 | This only works when not connected to an external display. 4 | *) 5 | tell application "Safari" 6 | activate 7 | set bounds of window 1 to {0, 0, 1328, 788} 8 | end tell -------------------------------------------------------------------------------- /scripts/update-locale-messages.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | 3 | const {sortProperties} = require('./utils') 4 | 5 | if (process.argv.some(arg => /^-h|--help$/.test(arg))) { 6 | console.log(` 7 | Updates ../_locales/**/messages.json with translations from ./scripts/translations.json 8 | 9 | Where translations.json is in the format: 10 | 11 | { 12 | "exampleMessageLabel": { 13 | "en": "English version", 14 | "es": "Versión en español" 15 | } 16 | } 17 | `.trim() 18 | ) 19 | process.exit() 20 | } 21 | 22 | let translationsJson = JSON.parse(fs.readFileSync('./translations.json', 'utf-8')) 23 | let localeMessagesJson = new Map() 24 | 25 | for (let [messageProp, translations] of Object.entries(translationsJson)) { 26 | for (let [localeCode, message] of Object.entries(translations)) { 27 | if (!localeMessagesJson.has(localeCode)) { 28 | localeMessagesJson.set( 29 | localeCode, 30 | JSON.parse( 31 | fs.readFileSync(`../_locales/${localeCode}/messages.json`, 'utf-8') 32 | ) 33 | ) 34 | } 35 | let messagesJson = localeMessagesJson.get(localeCode) 36 | messagesJson[messageProp] = {...messagesJson[messageProp], message} 37 | } 38 | } 39 | 40 | for (let [localeCode, messagesJson] of localeMessagesJson.entries()) { 41 | fs.writeFileSync( 42 | `../_locales/${localeCode}/messages.json`, 43 | JSON.stringify(sortProperties(messagesJson), null, 2), 44 | 'utf8' 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /scripts/utils.js: -------------------------------------------------------------------------------- 1 | function sortProperties(locale) { 2 | let entries = Object.entries(locale) 3 | entries.sort(([a], [b]) => { 4 | if (a < b) return -1 5 | if (a > b) return 1 6 | return 0 7 | }) 8 | return Object.fromEntries(entries) 9 | } 10 | 11 | module.exports = { 12 | sortProperties, 13 | } -------------------------------------------------------------------------------- /types.d.ts: -------------------------------------------------------------------------------- 1 | export type Config = { 2 | enabled: boolean 3 | debug: boolean 4 | debugLogTimelineStats: boolean 5 | version?: 'desktop' | 'mobile' 6 | // Shared 7 | addAddMutedWordMenuItem: boolean 8 | // XXX This is now more like "use the Following tab by default" 9 | alwaysUseLatestTweets: boolean 10 | defaultToLatestSearch: boolean 11 | disableHomeTimeline: boolean 12 | disabledHomeTimelineRedirect: 'notifications' | 'messages' 13 | disableTweetTextFormatting: boolean 14 | dontUseChirpFont: boolean 15 | dropdownMenuFontWeight: boolean 16 | fastBlock: boolean 17 | followButtonStyle: 'monochrome' | 'themed' 18 | hideAdsNav: boolean 19 | hideBookmarkButton: boolean 20 | hideBookmarkMetrics: boolean 21 | hideBookmarksNav: boolean 22 | hideCommunitiesNav: boolean 23 | hideComposeTweet: boolean 24 | hideExplorePageContents: boolean 25 | hideFollowingMetrics: boolean 26 | hideForYouTimeline: boolean 27 | hideGrokNav: boolean 28 | hideGrokTweets: boolean 29 | hideInlinePrompts: boolean 30 | hideJobsNav: boolean 31 | hideLikeMetrics: boolean 32 | hideListsNav: boolean 33 | hideMetrics: boolean 34 | hideMonetizationNav: boolean 35 | // XXX This now controls hiding all "Discover" suggestions 36 | hideMoreTweets: boolean 37 | hideNotifications: 'ignore' | 'badges' | 'hide' 38 | hideProfileRetweets: boolean 39 | hideQuoteTweetMetrics: boolean 40 | hideQuotesFrom: string[] 41 | hideReplyMetrics: boolean 42 | hideRetweetMetrics: boolean 43 | hideSeeNewTweets: boolean 44 | hideShareTweetButton: boolean 45 | hideSpacesNav: boolean 46 | hideSubscriptions: boolean 47 | // XXX This now controls hiding profile header metrics 48 | hideTotalTweetsMetrics: boolean 49 | hideTweetAnalyticsLinks: boolean 50 | hideTwitterBlueReplies: boolean 51 | hideTwitterBlueUpsells: boolean 52 | hideUnavailableQuoteTweets: boolean 53 | // XXX This now also controls hiding Verified Followers 54 | hideVerifiedNotificationsTab: boolean 55 | hideViews: boolean 56 | hideWhoToFollowEtc: boolean 57 | listRetweets: 'ignore' | 'hide' 58 | mutableQuoteTweets: boolean 59 | mutedQuotes: QuotedTweet[] 60 | quoteTweets: SharedTweetsConfig 61 | redirectToTwitter: boolean 62 | reducedInteractionMode: boolean 63 | // XXX This now controls all replacement of X brand changes 64 | replaceLogo: boolean 65 | restoreLinkHeadlines: boolean 66 | restoreQuoteTweetsLink: boolean 67 | restoreOtherInteractionLinks: boolean 68 | restoreTweetSource: boolean 69 | retweets: SharedTweetsConfig 70 | showBlueReplyFollowersCount: boolean 71 | showBlueReplyFollowersCountAmount: string 72 | showBookmarkButtonUnderFocusedTweets: boolean 73 | showPremiumReplyBusiness: boolean 74 | showPremiumReplyFollowedBy: boolean 75 | showPremiumReplyFollowing: boolean 76 | showPremiumReplyGovernment: boolean 77 | sortReplies: 'relevant' | 'recent' | 'liked' 78 | tweakNewLayout: boolean 79 | tweakQuoteTweetsPage: boolean 80 | twitterBlueChecks: 'ignore' | 'replace' | 'hide' 81 | unblurSensitiveContent: boolean 82 | uninvertFollowButtons: boolean 83 | // Experiments 84 | customCss: string 85 | // Desktop only 86 | fullWidthContent: boolean 87 | fullWidthMedia: boolean 88 | hideAccountSwitcher: boolean 89 | hideExploreNav: boolean 90 | hideExploreNavWithSidebar: boolean 91 | hideLiveBroadcasts: boolean 92 | hideMessagesDrawer: boolean 93 | hideSidebarContent: boolean 94 | hideSuggestedFollows: boolean 95 | hideTimelineTweetBox: boolean 96 | hideToggleNavigation: boolean 97 | hideWhatsHappening: boolean 98 | navBaseFontSize: boolean 99 | navDensity: 'default' | 'comfortable' | 'compact' 100 | showRelevantPeople: boolean 101 | // Mobile only 102 | hideLiveBroadcastBar: boolean 103 | hideMessagesBottomNavItem: boolean 104 | preventNextVideoAutoplay: boolean 105 | } 106 | 107 | export type Locale = { 108 | [key in LocaleKey]?: string 109 | } 110 | 111 | export type LocaleKey = 112 | | 'ADD_ANOTHER_TWEET' 113 | | 'ADD_MUTED_WORD' 114 | | 'GROK_ACTIONS' 115 | | 'HOME' 116 | | 'LIKES' 117 | | 'LIVE_ON_X' 118 | | 'MOST_RELEVANT' 119 | | 'MUTE_THIS_CONVERSATION' 120 | | 'POST_ALL' 121 | | 'POST_UNAVAILABLE' 122 | | 'PROFILE_SUMMARY' 123 | | 'QUOTE' 124 | | 'QUOTES' 125 | | 'QUOTE_TWEET' 126 | | 'QUOTE_TWEETS' 127 | | 'REPOST' 128 | | 'REPOSTS' 129 | | 'RETWEET' 130 | | 'RETWEETED_BY' 131 | | 'RETWEETS' 132 | | 'SHARED' 133 | | 'SHARED_TWEETS' 134 | | 'SHOW' 135 | | 'SHOW_MORE_REPLIES' 136 | | 'SORT_REPLIES_BY' 137 | | 'TURN_OFF_QUOTE_TWEETS' 138 | | 'TURN_OFF_RETWEETS' 139 | | 'TURN_ON_RETWEETS' 140 | | 'TWEET' 141 | | 'TWEETS' 142 | | 'TWEET_ALL' 143 | | 'TWEET_INTERACTIONS' 144 | | 'TWEET_YOUR_REPLY' 145 | | 'TWITTER' 146 | | 'UNDO_RETWEET' 147 | | 'VIEW' 148 | | 'WHATS_HAPPENING' 149 | 150 | export type NamedMutationObserver = MutationObserver & {name: string} 151 | 152 | export type Disconnectable = {name: string, disconnect(): void} 153 | 154 | export type QuotedTweet = { 155 | quotedBy: string 156 | user: string 157 | time: string 158 | text?: string 159 | } 160 | 161 | export type SharedTweetsConfig = 'separate' | 'hide' | 'ignore' 162 | 163 | export type TweetType = 164 | | 'PINNED_TWEET' 165 | | 'PROMOTED_TWEET' 166 | | 'QUOTE_TWEET' 167 | | 'RETWEET' 168 | | 'RETWEETED_QUOTE_TWEET' 169 | | 'TWEET' 170 | | 'UNAVAILABLE' 171 | | 'UNAVAILABLE_QUOTE_TWEET' 172 | | 'UNAVAILABLE_RETWEET' 173 | 174 | export type TimelineItemType = 175 | | TweetType 176 | | 'BLUE_REPLY' 177 | | 'BUSINESS_REPLY' 178 | | 'DISCOVER_MORE_HEADING' 179 | | 'DISCOVER_MORE_TWEET' 180 | | 'FOCUSED_TWEET' 181 | | 'GOVERNMENT_REPLY' 182 | | 'HEADING' 183 | | 'INLINE_PROMPT' 184 | | 'SHOW_MORE' 185 | | 'SUBSEQUENT_ITEM' 186 | | 'UNAVAILABLE' 187 | 188 | export type TimelineOptions = { 189 | classifyTweets?: boolean 190 | hideHeadings?: boolean 191 | isTabbed?: boolean 192 | isUserTimeline?: boolean 193 | onTabChanged?: () => void 194 | onTimelineAppeared?: () => void 195 | tabbedTimelineContainerSelector?: string 196 | timelineSelector?: string 197 | } 198 | 199 | export type IndividualTweetTimelineOptions = { 200 | observers: Map 201 | seen: WeakMap 202 | } 203 | 204 | export type IndividualTweetDetails = { 205 | itemType: TimelineItemType, 206 | hidden: boolean | null, 207 | } 208 | 209 | export type UserInfo = { 210 | following: boolean 211 | followedBy: boolean 212 | followersCount: number 213 | } 214 | 215 | export type UserInfoObject = {[index: string]: UserInfo} 216 | 217 | export type VerifiedType = 'BLUE' | 'BUSINESS' | 'GOVERNMENT' 218 | --------------------------------------------------------------------------------