mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-05-26 17:17:51 +02:00
e3297e9bc0
PR #226 landed the i18n infrastructure and Chinese (zh-CN) translations. This follow-up adds the safeguards that make accepting community translations sustainable without exposing the project to subtle state-aligned framing in future translation PRs. Changes: frontend/src/i18n/index.tsx (renamed from .ts) - Add LOCALES registry: a single source of truth for available languages and their NATIVE display names ("English", "中文 (简体)"). Adding a new language is now a one-entry change here plus a JSON file. - Add isLocale() guard so an unknown value in localStorage falls through to navigator.language detection instead of corrupting state. - File renamed to .tsx because it contains JSX. Next.js tolerated JSX in .ts but Vite/Oxc (used by vitest) does not. frontend/src/components/SettingsPanel.tsx Add a UI language picker to the Settings header — a small <select> populated from LOCALES. Users no longer need the dev console to switch languages. Locale change remains 100% client-side (localStorage), no network call, no telemetry. CONTRIBUTING.md (new) Documents the translation-neutrality requirement that applies symmetrically to all source countries: - Translations must be technically faithful to the English source. - Substitutions aligned with state propaganda from ANY country (PRC, Russia, US, EU, etc.) will be rejected. - The test is: "would a translator working strictly from the English source produce this rendering?" Also explains how translation PRs are reviewed and how to add a new language. .github/CODEOWNERS (new) Auto-requests maintainer review on: - /frontend/src/i18n/ (translation safety) - /backend/auth.py, /backend/routers/wormhole.py, /backend/services/mesh/, /backend/services/fetchers/ (the same paths recent security audits flagged as sensitive) - /.github/workflows/, /.gitlab-ci.yml, /docker-compose*.yml, /helm/ (build/deploy) - /CONTRIBUTING.md, /.github/CODEOWNERS (policy itself) frontend/src/__tests__/i18n/i18nProvider.test.tsx (new, 8 tests) Locks in the i18n contract: - LOCALES has both en and zh-CN with non-empty native labels - Default English when navigator is English - Auto-detect zh-CN when navigator language starts with "zh" - localStorage preference overrides auto-detect - setLocale persists to localStorage - Unknown stored locale falls back to auto-detect - Renders a real zh-CN translation (catches large-scale translation removal in future PRs) - Missing key falls back to the key itself Note: i18n/index.tsx, the language toggle UI, the translation policy, and the test suite together form a defense-in-depth setup. The structural safety guarantee (no network calls, static JSON bundled at build) is intact; this PR makes the social contract around translations explicit and enforceable via branch protection on CODEOWNERS-marked paths. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
76 lines
4.9 KiB
Markdown
76 lines
4.9 KiB
Markdown
# Contributing to Shadowbroker
|
|
|
|
Thank you for taking the time to contribute. This document covers things specific to this project — for general open-source contribution etiquette, see the GitHub docs.
|
|
|
|
---
|
|
|
|
## Code contributions
|
|
|
|
1. Fork the repo on GitHub (`bigbodycobain/Shadowbroker`) or GitLab (`bigbodycobain/Shadowbroker` mirror).
|
|
2. Make your changes on a feature branch.
|
|
3. Run the local test suite:
|
|
- Backend: `pytest backend/tests/`
|
|
- Frontend: `cd frontend && npx vitest run`
|
|
4. Open a Pull Request against `main`.
|
|
|
|
CI runs on every PR. If CI fails, that's blocking — please push fixes rather than asking for it to be merged anyway.
|
|
|
|
---
|
|
|
|
## Reporting security issues
|
|
|
|
Do **not** file security issues as public GitHub issues. Email the maintainer or use a private security advisory on GitHub. Public disclosure of an exploitable vulnerability without prior coordination will be rejected from the project.
|
|
|
|
---
|
|
|
|
## Translation contributions
|
|
|
|
Shadowbroker supports UI localization (`frontend/src/i18n/`). Translation contributions are welcome but held to a stricter standard than most code changes, because translations can subtly reshape user perception in ways that are hard to spot during review. Read this section before submitting one.
|
|
|
|
### The neutrality requirement
|
|
|
|
**Translations must be technically faithful to the English source.** That means:
|
|
|
|
- Each `t('key')` entry should mean approximately the same thing in the target language as in English, modulo idiom.
|
|
- Technical terms with established meanings (e.g. "GPS jamming," "military flight," "Tor," "onion routing," "encryption") should be translated using the corresponding established technical term in the target language — **not** softened, rebranded, or politically reframed.
|
|
- The set of UI strings should be **the same** between languages. Don't omit features from one locale that are visible in another.
|
|
|
|
### What will get a translation PR rejected
|
|
|
|
Translation choices that align the project with the framing or terminology of state propaganda — from **any** country — will be rejected. This applies symmetrically:
|
|
|
|
| Country / source | Examples of substitutions we will reject |
|
|
|---|---|
|
|
| **PRC / CCP** | Calling Taiwan a "province" or "renegade province"; reframing protest layers as "riots"; using softened or euphemistic terms for surveillance, internment, or jamming when the source text is direct |
|
|
| **Russia** | Calling the Ukraine war a "special military operation"; relabeling occupied territories as Russian; softening sanctions/jamming/disinfo terminology |
|
|
| **United States / EU** | Reframing adversaries with editorial labels not in the source (e.g. inserting "regime" where the English says "government"); applying labels like "terrorist" or "rogue state" to entities the English source describes neutrally |
|
|
| **Israel / Palestine / any active conflict** | Substituting one side's preferred terminology when the source uses the other side's or a neutral term |
|
|
| **Any government** | Adding political slogans, omitting features that government finds inconvenient, or inserting terminology associated with a specific political faction |
|
|
|
|
The test is **"would a translator working strictly from the English source produce this rendering?"** If the answer requires assuming a political stance the source does not take, the substitution does not belong in the translation.
|
|
|
|
### How translation PRs are reviewed
|
|
|
|
Changes to `frontend/src/i18n/**` are owned by the maintainer (see `CODEOWNERS`) and require explicit approval. We will:
|
|
|
|
1. Diff the translation against the English source key-by-key.
|
|
2. Spot-check a sample of entries with a native speaker of the target language when possible.
|
|
3. Look for the patterns above.
|
|
4. Look for suspicious additions to the i18n infrastructure itself (e.g. a remote translation fetcher, telemetry on language choice) — the i18n layer is supposed to be 100% client-side static JSON.
|
|
|
|
A PR that adds a new language is harder to review than one that fixes typos in an existing language. For new languages, please be patient and expect a real review window. For typo fixes, please describe each change in the PR body so the reviewer can verify intent.
|
|
|
|
### What about adding a new language?
|
|
|
|
We welcome new languages. The mechanical setup is documented in the header comment of `frontend/src/i18n/index.ts`. Beyond that:
|
|
|
|
- We are more likely to merge a new language quickly if at least one reviewer in the maintainer's network speaks it.
|
|
- If you are the *only* speaker of the target language reading this repo, your translation is welcome but the merge timeline will be longer while a reviewer is found.
|
|
- Partial translations are fine — the system falls back to English for any missing key.
|
|
|
|
---
|
|
|
|
## Anything else
|
|
|
|
If you have a question that isn't a security report, opening a GitHub Discussion or a draft PR with a question in the body is the fastest way to get a response. Direct emails are read but not always replied to promptly.
|