Files
Shadowbroker/CONTRIBUTING.md
T
Shadowbroker e3297e9bc0 i18n: add language toggle, neutrality policy, and codeowner gate (#238)
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>
2026-05-19 01:48:24 -06:00

4.9 KiB

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.