add vandalism detection script - #48
Conversation
ef1097b to
cb8e0b3
Compare
Adds a script utilizing a LLM to check .po translation files for vandalized translations.
cb8e0b3 to
f13ef8a
Compare
the *summary.txt file contains all results but might not align 100% with the json files as I stitched the result of 2 partial runs together (they had some overlap so i combined the positive results).
|
Summary of the 19.02.2026 run: Click to expandTotal spam entries detected: 164 ──────────────────────────────────────── Original: - an arbitrary on-chain script, e.g.: Original: Add to coin control Original: Cannot start QR scanner, no usable camera found. Original: Cannot start QR scanner: initialization failed. Original: Startup times are instant because it operates in conjunction with high-performance servers that handle the most complicated parts of the Bitcoin system. ──────────────────────────────────────── Original: Details Original: Close Electrum? ──────────────────────────────────────── Original: unknown ──────────────────────────────────────── Original: &Pay to many ──────────────────────────────────────── Original: Save Original: Save Original: Save ──────────────────────────────────────── Original: Terms of Use Original: Server settings ──────────────────────────────────────── Original: Exit Electrum ──────────────────────────────────────── Original: Close ──────────────────────────────────────── Original: A CPFP is a transaction that sends an unconfirmed output back to yourself, with a high fee. The goal is to have miners confirm the parent transaction in order to get the fee attached to the child transaction. Original: Cannot determine dynamic fees, not connected Original: Cannot pay less than the amount specified in the invoice Original: Error parsing Lightning invoice Original: Fees are paid by the sender. Original: Integers weights can also be used in conjunction with '!', e.g. set one amount to '2!' and another to '3!' to split your coins 40-60. Original: Invoice has unknown status Original: Raw Original: Rebalance your channels in order to increase your sending or receiving capacity Original: The platform QR detection library is not available. Original: There are still channels that are not fully closed Original: There are still coins present in this wallet. Really delete? Original: There are still unpaid requests. Really delete? Original: This is a channel backup. Original: You can use it to request a force close. Original: You will be able to pay once the swap is confirmed. Original: A CPFP is a transaction that sends an unconfirmed output back to yourself, with a high fee. The goal is to have miners confirm the parent transaction in order to get the fee attached to the child transaction. Original: This channel will be usable after %1 confirmations ──────────────────────────────────────── Original: (No FX rate available) ──────────────────────────────────────── Original: CLTV expiry ──────────────────────────────────────── Original: Add a cosigner to your multi-sig wallet Original: Address unknown for node: Original: All outputs are non-change is_mine Original: Cannot create child transaction Original: Offline Original: Remote Node Original: Save Original: Your wallet history has been successfully exported. Original: Save Original: Save ──────────────────────────────────────── Original: Cannot have witness v1+ in p2sh Original: [p] - print stored payment order Original: Transaction is unrelated to this wallet. ──────────────────────────────────────── Original: Invalid Public key Original: Not Now Original: Redeem Script Original: Distributed by Electrum Technologies GmbH Original: Not Now Original: Detect Existing Accounts ──────────────────────────────────────── Original: Go online to complete wallet creation Original: Never disclose your seed. Original: No donation address for this server Original: Request force-close Original: Sign/verify Message Original: Success Original: Never disclose your seed. Original: Success ──────────────────────────────────────── Original: Could not close channel: Original: From Original: Outputs Original: Type ──────────────────────────────────────── Original: A suggested fee is automatically added to this field. You may override it. The suggested fee increases with the size of the transaction. Original: Number of zeros displayed after the decimal point. For example, if this is set to 2, "1." will be displayed as "1.00" Original: Password was updated successfully Original: Select file to export your private keys to Original: Select which language is used in the GUI (after restart). Original: The amount of fee can be decided freely by the sender. However, transactions with low fees take more time to be processed. Original: The description is not sent to the recipient of the funds. It is stored in your wallet file, and displayed in the 'History' tab. Original: The following addresses were added Original: The following inputs could not be imported Original: This seed will allow you to recover your wallet in case of computer failure. Original: To make sure that you have properly saved your seed, please retype it here. Original: Warning: The next address will not be recovered automatically if you restore your wallet from seed; you may need to add it manually.\n\nThis occurs because you have too many unused addresses in your wallet. To avoid this situation, use the existing addresses first.\n\nCreate anyway? Original: Your wallet history has been successfully exported. Original: To make sure that you have properly saved your seed, please retype it here. Original: This seed will allow you to recover your wallet in case of computer failure. ──────────────────────────────────────── Original: Clear Original: Reporting Bugs Original: [Clear] Original: tasks ──────────────────────────────────────── Original: Banner ──────────────────────────────────────── Original: Amount too low Original: Could not resolve LNURL Original: This plugin requires installation of additional dependencies. Original: unknown Original: Enter the list of private keys to sweep into this wallet Original: Amount received onchain ──────────────────────────────────────── Original: Block height ──────────────────────────────────────── Original: Broadcasting transaction... Original: Seed Type Original: Seed Type ──────────────────────────────────────── Original: &Flip horizontally Original: &New contact Original: - an arbitrary on-chain script, e.g.: Original: A CPFP is a transaction that sends an unconfirmed output back to yourself, with a high fee. The goal is to have miners confirm the parent transaction in order to get the fee attached to the child transaction. Original: A backup does not contain information about your local balance in the channel. Original: All outputs are non-change is_mine Original: At block height: {} Original: A CPFP is a transaction that sends an unconfirmed output back to yourself, with a high fee. The goal is to have miners confirm the parent transaction in order to get the fee attached to the child transaction. ──────────────────────────────────────── Original: watching only ──────────────────────────────────────── Original: &Plot Original: &View Original: Build Date ──────────────────────────────────────── Original: &Addresses Original: &Documentation Original: &Donate to server Original: &Encrypt/decrypt message Original: &Export Original: &File Original: &From file Original: &From text Original: &From the blockchain Original: &Help Original: &Labels Original: &Load transaction Original: &New/Restore Original: &Official website Original: &Password Original: &Plugins Original: &Recently open Original: 2. Align your Revealer borderlines to the dashed lines on the top and left. Original: 4. Type the numbers in the software Original: A backup is saved automatically when generating a new wallet. Original: A copy of your wallet file was created in Original: A few examples Original: A library is probably missing. Original: A small fee will be charged on each transaction that uses the remote server. You may check and modify your billing preferences once the installation is complete. Original: A suggested fee is automatically added to this field. You may override it. The suggested fee increases with the size of the transaction. Original: Accept Word Original: Acquisition price Original: Add a cosigner to your multi-sig wallet Original: Additional fees Original: Additional {} satoshis are going to be added. Original: Address is frozen Original: Address not in wallet. Original: Also, dust is not kept as change, but added to the fee. Original: Amount for OP_RETURN output must be zero. Original: Amount to be sent Original: An uninitialized Digital Bitbox is detected. Original: An unnamed {} Original: Are you SURE you want to wipe the device?\nYour wallet still has bitcoins in it! Original: Are you sure you want to erase the Digital Bitbox? Original: Are you sure you want to proceed? Original: Are you sure you want to remove this transaction and {} child transactions? Original: Are you sure you want to remove this transaction? Original: Blockchain Original: Broadcasting transaction... Original: Child Pays for Parent Original: Child pays for parent Original: A few examples ──────────────────────────────────────── Original: Import Original: Use this dialog to change your password. Original: Import Original: Import ──────────────────────────────────────── Original: Script type and Derivation path Original: To create a spending wallet, please enter a master private key (xprv/yprv/zprv). ──────────────────────────────────────── Original: 2. Align your Revealer borderlines to the dashed lines on the top and left. Original: Your wallet history has been successfully exported. |
|
I reviewed the translations flagged by the LLM, removed them manually and blocked some of the translators that did obvious nonsense. Observations made:
I think proofreaders and LLM post processing would increase the translation quality a lot. We should update the Crowdin project description with some hints/guidelines for translators, e.g. "Please also consider proofreading, it is important", "please don't remove placeholders like {}`, so they are aware of these things. What do you think of the following description (first paragraph is copy pasted from crowdin): Electrum is an easy to use Bitcoin client. It protects you from losing coins in a backup mistake or computer failure, because your wallet can be recovered from a secret phrase that you can write on paper or learn by heart. There is no waiting time when you start the client, because it does not download the Bitcoin blockchain. Notes for translators:
|
Adds a script utilizing a LLM to check .po translation files for vandalized translations.
I think it is reasonably reliable and seems to tend more on the false positive side.
Using
google/gemini-3-flash-previewit costs roughly ~0.02 usd cent per translation (on ppq.ai).We have ~184660 translations, so running this script once through the whole repo would
cost ~36$ using
gemini-3-flash-preview.This should hopefully allow us to detect most of the vandalism that has happened over time.
The script itself and the unittests were mostly written by an LLM as well, i reviewed (and tested) them and they seem to do the job.
For the future we could modify the script to run it in the CI and check only the diff of new translations if it turns out to be accurate enough.
Edit:
The sum of ~184660 translations i used for the calculation above is the sum of all words from the crowdin UI, though what actually matters is the count of strings, which is much lower ~42k, resulting in a lower cost of only roughly ~9$ to scan the whole translation set.