Rebuild du site sur Astro : i18n multilingue, faits verifies, Docker, CI, tests
- Astro statique, EN par defaut + /fr/ + /nl/, detection langue navigateur - i18n par fichiers JSON, ajouter une langue = ajouter des traductions - Contenu original porte a l'identique (diff d'inventaire par langue) - Chronologie legislative corrigee sur sources primaires (PE, Conseil, votes) - Timeline 23 precedents + observatoire 35 items + annuaire 66 outils FOSS, chaque affirmation verifiee et sourcee - Zero requete tierce (teste), lisible JS coupe, axe WCAG AA x2 themes - Version offline monofichier par langue a chaque build - Docker multi-stage vers nginx + CSP stricte auto-generee - CI GitHub Actions (SHA-pinnees) + verification hebdo des liens - CONTRIBUTING : divulgation d'affiliation obligatoire, allowlist de domaines testee en CI
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
# Content-migration diff report
|
||||
|
||||
Legacy monolith `index.html` (591 tri-lingual span lines / 659 `data-l` spans per
|
||||
language) → per-locale MDX under `src/content/sections/{en,fr,nl}/` + `src/data/tools.json`.
|
||||
|
||||
## How the inventories were produced
|
||||
|
||||
- `legacy-<lang>.txt` — the FULL legacy document reduced to one language
|
||||
(every `data-l` run resolved), one line of whitespace-collapsed text per
|
||||
block-level element. Chrome (topbar, hero, status banner, TOC, footer) is
|
||||
included so nothing is hidden from this audit.
|
||||
- `built-<lang>.txt` — same dump algorithm over `dist/index.html`,
|
||||
`dist/fr/index.html`, `dist/nl/index.html` after `pnpm build`.
|
||||
One deviation: `<noscript>` is skipped because parse5 exposes its children
|
||||
as raw text (it is new chrome, absent from the legacy page anyway).
|
||||
- `<b class="lbl">` / `<b class="tool-label">` elements are flushed to their
|
||||
own line on both sides so tool-card prose lines stay comparable.
|
||||
- Non-breaking spaces are folded into plain spaces on both sides.
|
||||
- `node migration/compare.mjs` then segments each file into
|
||||
head-chrome / narrative window / tail-chrome (narrative = first `PART 00 ·`
|
||||
line through the manifesto paragraph) and walks the two narrative windows
|
||||
**in order, line by line**. Every line must either match exactly or fall in
|
||||
one of the categories below; anything else exits non-zero.
|
||||
|
||||
## Result
|
||||
|
||||
| lang | legacy narrative lines | built narrative lines | unexplained differences |
|
||||
| ---- | ---------------------- | --------------------- | ----------------------- |
|
||||
| en | 789 | 991 | **0** |
|
||||
| fr | 789 | 991 | **0** |
|
||||
| nl | 789 | 991 | **0** |
|
||||
|
||||
`991 = 789 − 6 (deferred legislative rows) + 208 (tool-card labels)` in every
|
||||
language. Full machine output: `compare-report.json`.
|
||||
|
||||
## Explained differences, exhaustively
|
||||
|
||||
### 1. Tool-card labels are now real text (+208 lines per language)
|
||||
|
||||
In the legacy page the field labels ("What it's for / Why it matters /
|
||||
For whom & when", `À quoi ça sert / Pourquoi / Pour qui & quand`,
|
||||
`Waarvoor dient het / …`) and the `Install & use` summary were **CSS
|
||||
`::before`/`::after` generated content**, so they never appeared in the DOM
|
||||
text. `ToolCard.astro` renders them as real, accessible text:
|
||||
54 cards × 3 field labels + 46 install summaries = 208 new lines per language.
|
||||
The label strings are byte-identical to the legacy CSS `content` values.
|
||||
|
||||
### 2. Deferred legislative-status claims (−6 lines per language)
|
||||
|
||||
Per the migration plan, adopted/extended claims are being rewritten from
|
||||
verified sources separately. Dropped from the `#menace` comparison table
|
||||
(rows 4 and 5), verbatim:
|
||||
|
||||
- EN: `Duration` / `Temporary, extended to 3 April 2028` / `Permanent` /
|
||||
`Status (Jul 2026)` / `Adopted 9 July 2026` / `Under negotiation, 5th trilogue failed 29 June`
|
||||
- FR: `Durée` / `Temporaire, prolongé jusqu'au 3 avril 2028` / `Permanent` /
|
||||
`Statut (juil. 2026)` / `Adopté le 9 juillet 2026` / `En négociation, 5e trilogue échoué le 29 juin`
|
||||
- NL: `Looptijd` / `Tijdelijk, verlengd tot 3 april 2028` / `Permanent` /
|
||||
`Status (juli 2026)` / `Aangenomen op 9 juli 2026` / `In onderhandeling, 5e trialoog mislukt op 29 juni`
|
||||
|
||||
The status banner ("Dernière minute : 9 juillet 2026" block) was excluded
|
||||
wholesale with the chrome (see §4); it is replaced by `StatusBanner.astro`
|
||||
fed from verified sources in the parallel workstream.
|
||||
|
||||
Two borderline in-prose date claims were **kept** (judgment call — they are
|
||||
narrative argument, not adopted/extended status): the 19 March 2026 joint
|
||||
appeal, and the "kept scanning after the legal basis lapsed on 4 April 2026"
|
||||
sentence, both in `#menace`.
|
||||
|
||||
### 3. Typographic quotes (smartypants)
|
||||
|
||||
Astro's default markdown pipeline (`markdown.smartypants`, ON by default)
|
||||
typesets `"` as `“ ”` and `'` as `’` in the rendered pages
|
||||
(en: 138 lines affected, fr: 225, nl: 70). No other smartypants rule fires:
|
||||
the legacy prose contains no ASCII `...` or `--` (its 3 `…` are literal and
|
||||
pass through unchanged). This is the **only character-level transformation**
|
||||
in the entire narrative.
|
||||
|
||||
It could not be disabled from inside this migration's ownership
|
||||
(`astro.config.mjs` is off-limits). If byte-identical glyphs are required,
|
||||
the config owner can add `markdown: { smartypants: false }` — one line — and
|
||||
the compare gate can then drop its quote normalization.
|
||||
|
||||
### 4. Chrome not migrated (rebuilt separately)
|
||||
|
||||
Legacy head-chrome (36 lines/language) and tail-chrome (8 lines/language)
|
||||
deliberately not migrated to MDX:
|
||||
|
||||
- topbar: brand `◆ EXIT CHAT CONTROL`, FR/NL/EN buttons, theme toggle;
|
||||
- hero: stamp (`Mass surveillance · EU · 2026`), eyebrow, `Exit Chat Control_`
|
||||
h1, lede paragraph, three profile meta tags;
|
||||
- status banner: `Breaking: 9 July 2026` + the vote paragraph
|
||||
(superseded content, see §2);
|
||||
- TOC (24 lines) — duplicates the section titles that ARE migrated;
|
||||
- footer: Resources / Sources / Act link lists, GitHub link, disclaimer
|
||||
(`Facts last updated: 9 July 2026`).
|
||||
|
||||
The built pages already contain replacement chrome from the parallel
|
||||
rebuild workstream (TopBar/Footer/StatusBanner components, new hero h1 +
|
||||
description, skip-link, noscript note, rewritten source lists citing
|
||||
official roll-call results). That text intentionally differs from the
|
||||
legacy chrome and is **not** part of this migration's fidelity claim; it
|
||||
sits outside the compared narrative window (built head-chrome: 6 lines,
|
||||
tail-chrome: 9 lines).
|
||||
|
||||
- The legacy inline JS (lang/theme toggles, simpleicons CDN loader) was not
|
||||
migrated by design. Icon rendering will be rebuilt offline later; the
|
||||
legacy CDN slugs are preserved in `tools.json.iconSlug` (validated, §6).
|
||||
|
||||
### 5. NL gaps
|
||||
|
||||
None. Every one of the 649 `data-l` runs carries all three languages
|
||||
(en/fr/nl counts are equal in every run), so the EN-fallback path never
|
||||
fired. `extract-log.json → nlGaps: []`.
|
||||
|
||||
### 6. tools.json notes (language-neutral facts)
|
||||
|
||||
- 54 entries; every entry has `url` (first neutral footer link), full `links`
|
||||
array (21 cards have 2–3 links), `monogram`, `color`, `profiles`
|
||||
(the 🟢🟡🔴 footer note), `level` where the legacy card carried a level tag
|
||||
(34 cards; the other 20 never had one).
|
||||
- `iconSlug` was validated against the installed `simple-icons` package.
|
||||
Renamed upstream and mapped: `tutanota → tuta`, `aegis → aegisauthenticator`.
|
||||
Removed upstream and therefore set to null (6): `briar`, `molly`, `ivpn`,
|
||||
`protonpass`, `nostr`, `standardnotes`. 5 cards never had an icon in the
|
||||
legacy map (`t-bitchat`, `t-databrokers`, `t-mailbox`, `t-website`,
|
||||
`t-yunohost`).
|
||||
- 7 cards have localized display names (e.g. `Firefox (durci/hardened/gehard)`,
|
||||
`Sauvegardes chiffrées / Encrypted backups / Versleutelde back-ups`).
|
||||
`tools.json.name` stores the EN plain text; the localized display name is
|
||||
rendered through the ToolCard `name` slot from each locale's MDX.
|
||||
- One presentational attribute dropped: `style="margin:.6rem 0 .4rem"` on the
|
||||
warning box inside `t-bitchat` (styling is rebuilt later; text intact).
|
||||
|
||||
### 7. Anchors
|
||||
|
||||
`anchors.json` lists all 82 `id=` values of the legacy file. 78 exist in
|
||||
every built page: 23 section ids on `<section>` wrappers, 54 tool ids on
|
||||
ToolCard `<article>` roots, `top` on the hero h1. The 4 missing are the
|
||||
legacy control-widget ids `lang-fr`, `lang-nl`, `lang-en`, `theme`
|
||||
(toggle buttons, never used as link targets — chrome rebuilt separately).
|
||||
|
||||
### 8. External domains for the allowlist review
|
||||
|
||||
The migrated content links to 75 unique external hostnames
|
||||
(`external-domains.txt`). The parallel workstream's
|
||||
`tests/unit/dist-links.test.ts` fails until these are reviewed and added to
|
||||
`src/data/domains-allowlist.json` — that file requires review and is outside
|
||||
this migration's ownership, so it was left untouched.
|
||||
|
||||
## Reproduce
|
||||
|
||||
```
|
||||
node migration/extract.mjs # MDX + tools.json + anchors + legacy dumps
|
||||
pnpm build
|
||||
node migration/extract.mjs --built # built-page dumps
|
||||
node migration/compare.mjs # exits non-zero on any unexplained diff
|
||||
```
|
||||
Reference in New Issue
Block a user