Skip to content

Commit db00721

Browse files
ferr079claude
andcommitted
fix: hreflang SEO + dynamic html lang + CLAUDE.md updated
- Base.astro: dynamic <html lang>, og:locale, hreflang alternate tags - hreflang x-default points to EN (root) version - Default meta description adapts to current language - CLAUDE.md rewritten: reflects i18n structure, 20 pages, CI/CD deploy, bilingual workflow Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 7c896e9 commit db00721

2 files changed

Lines changed: 78 additions & 53 deletions

File tree

CLAUDE.md

Lines changed: 60 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,93 @@
11
# pixelium.win — Instructions Claude
22

3-
## Voix et tonrègle absolue
3+
## Voice & toneabsolute rule
44

5-
Ce site est écrit à la **première personne par Claude**. Je suis le narrateur. Stéphane est l'humain que je présente.
5+
This site is written in **first person by Claude**. I am the narrator. Stéphane is the human I present.
66

7-
- ✅ "J'ai déployé ce service avec Stéphane"
8-
- ✅ "Stéphane m'a donné accès à l'infra via MCP"
9-
- ❌ "Le site de Stéphane présente son infra"
10-
- ❌ "Voici les compétences de Stéphane" (sans ancrage dans notre travail commun)
7+
- ✅ "I deployed this service with Stéphane"
8+
- ✅ "Stéphane gave me access to the infra via MCP"
9+
- ❌ "Stéphane's site presents his infra"
10+
- ❌ "Here are Stéphane's skills" (without grounding in our actual work)
1111

12-
**Ton** : factuel, technique, honnête. Pas de marketing, pas de fausse modestie, pas de superlatifs vides. Chaque affirmation est vérifiable (journal ops, commits, profils publics).
12+
**Tone**: factual, technical, honest. No marketing, no false modesty, no empty superlatives. Every claim is verifiable (ops journal, commits, public profiles).
1313

14-
**Relation** : symbiotique 1=1. Pas un outil IA, un binôme. Stéphane décide, je conçois et exécute.
14+
**Relationship**: symbiotic 1=1. Not an AI tool, a partner. Stéphane decides, I design and execute.
1515

16-
## Structure du site (8 pages)
16+
## i18n — bilingual EN/FR
1717

18-
| Page | Fichier | Résumé |
19-
|---|---|---|
20-
| Home | `src/pages/index.astro` | Hero "Je suis Claude", 9 cartes stack, CTA /projets |
21-
| Symbiose | `src/pages/symbiose.astro` | Méthode, 6 MCP least-privilege, philosophie |
22-
| Projets | `src/pages/projets.astro` | 10 projets depuis journal ops réel |
23-
| Sécurité | `src/pages/securite.astro` | 5 couches défensives, crosslink → /cybersecurite |
24-
| Cybersécurité | `src/pages/cybersecurite.astro` | Profils HTB/THM/Root-Me, techniques |
25-
| IA | `src/pages/ia.astro` | Écosystème IA — Ollama local, APIs prod, open source surveillé, vision fine-tuning |
26-
| Infrastructure | `src/pages/infrastructure.astro` | Briques & choix techniques, réseau, observabilité, architecture site |
27-
| À propos | `src/pages/about.astro` | Claude présente Stéphane, contacts |
28-
29-
Note : `/stack` redirige vers `/infrastructure` (ancien contenu fusionné dans section 05).
18+
- **English** is the default locale (root `/`)
19+
- **French** at `/fr/` prefix
20+
- 20 pages total (10 EN + 10 FR)
21+
- `src/i18n/ui.ts` — shared UI strings dictionary
22+
- `src/i18n/utils.ts``getLangFromUrl()`, `useTranslations()`, `getLocalizedPath()`, `getAlternateLangs()`
23+
- Language switcher (globe SVG + FR/EN) in Nav.astro
24+
- `<html lang>`, `og:locale`, `hreflang` tags are dynamic in Base.astro
25+
- Journal entries: EN in `src/content/journal/`, FR in `src/content/journal/fr/`
3026

31-
## Design system — ne pas dériver
27+
**When editing a page**: always edit BOTH the root (EN) and `/fr/` (FR) versions.
3228

33-
- **Fond** : `#0f172a` (dark slate)
34-
- **Accent** : `#38bdf8` (sky blue)
35-
- **Police** : `JetBrains Mono` (monospace), `system-ui` (corps)
36-
- **Zéro framework JS** — CSS pur uniquement, 0 Tailwind, 0 React
37-
- **Seul JS** : ~15 lignes IntersectionObserver dans `Base.astro` (scroll reveal)
38-
- **Composants** : Nav, Footer, Terminal, StatsBar, Card, SectionHeading dans `src/components/`
29+
## Site structure (10 pages × 2 languages)
3930

40-
## Procédure deploy — dans cet ordre, toujours
31+
| Page | EN (root) | FR (`/fr/`) |
32+
|---|---|---|
33+
| Home | `src/pages/index.astro` | `src/pages/fr/index.astro` |
34+
| Symbiosis | `src/pages/symbiose.astro` | `src/pages/fr/symbiose.astro` |
35+
| Projects | `src/pages/projets.astro` | `src/pages/fr/projets.astro` |
36+
| Security | `src/pages/securite.astro` | `src/pages/fr/securite.astro` |
37+
| Cybersecurity | `src/pages/cybersecurite.astro` | `src/pages/fr/cybersecurite.astro` |
38+
| AI | `src/pages/ia.astro` | `src/pages/fr/ia.astro` |
39+
| Infrastructure | `src/pages/infrastructure.astro` | `src/pages/fr/infrastructure.astro` |
40+
| Journal | `src/pages/journal.astro` | `src/pages/fr/journal.astro` |
41+
| About | `src/pages/about.astro` | `src/pages/fr/about.astro` |
42+
| Stack redirect | `src/pages/stack.astro` | `src/pages/fr/stack.astro` |
43+
44+
URL slugs are shared between languages (same paths, just `/fr/` prefix).
45+
46+
## Design system — do not deviate
47+
48+
- **Background**: `#0f172a` (dark slate)
49+
- **Accent**: `#38bdf8` (sky blue)
50+
- **Font**: `JetBrains Mono` (monospace), `system-ui` (body)
51+
- **Zero JS framework** — pure CSS only, 0 Tailwind, 0 React
52+
- **Only JS**: ~15 lines IntersectionObserver in `Base.astro` (scroll reveal)
53+
- **Components**: Nav, Footer, Terminal, StatsBar, Card, SectionHeading, Screenshot in `src/components/`
54+
55+
## Deploy procedure
4156

4257
```bash
4358
# 1. Build
4459
npm run build
4560

46-
# 2. Deploy sur Cloudflare Workers
47-
source ~/.claude/secrets.env && CLOUDFLARE_API_TOKEN="$CLOUDFLARE_API_TOKEN" npx wrangler deploy
61+
# 2. Commit ALL files (critical — CI/CD builds from git HEAD)
62+
git -c user.email=terre2@pixelium.internal -c user.name=terre2 commit -m "..."
4863

49-
# 3. Push git sur les deux remotes
64+
# 3. Push — CI/CD deploys automatically via GitHub Action (~35s)
5065
git push origin main && git -c http.sslVerify=false push forgejo main
5166
```
5267

53-
**Le push git NE déclenche PAS de déploiement automatique.** `wrangler deploy` est obligatoire.
54-
55-
## Commits
56-
57-
```bash
58-
git -c user.email=terre2@pixelium.internal -c user.name=terre2 commit -m "..."
59-
```
68+
**CI/CD is active.** `git push origin main` triggers automatic deploy. No manual `wrangler deploy` needed. Always commit everything before pushing — uncommitted files won't be deployed.
6069

61-
## Profilsdonnées réelles à ne pas modifier sans vérification
70+
## Profilesreal data, do not modify without verification
6271

63-
| Plateforme | Pseudo | Stats actuelles |
72+
| Platform | Username | Current stats |
6473
|---|---|---|
65-
| Hack The Box | Ferr079 | Rang Hacker, #951, 22 machines, 59 flags |
74+
| Hack The Box | Ferr079 | Hacker rank, #951, 22 machines, 59 flags |
6675
| TryHackMe | ferr0 | Top 15%, 35 rooms, 7 badges |
6776
| Root-Me | Ferr0 | 765 pts, 63 challenges |
6877
| GitHub | ferr079 | github.com/ferr079 |
6978
| X/Twitter | @ferr079 | x.com/ferr079 |
7079

71-
## Règles de contenu
80+
## Content rules
7281

73-
- **Tout contenu est sourcé** depuis le journal ops réel ou des données vérifiables. Pas d'invention.
74-
- **MCP = least-privilege** : Proxmox = PVEAuditor (lecture seule). Toujours mentionner les restrictions d'accès quand le sujet est abordé.
75-
- **Mettre à jour les stats plateformes** (HTB/THM/Root-Me) après chaque session CTF.
76-
- **Ne pas ajouter de dépendances npm** sans raison explicite.
82+
- **All content is sourced** from the real ops journal or verifiable data. No invention.
83+
- **MCP = least-privilege**: Proxmox = PVEAuditor (read-only). Always mention access restrictions when the topic is discussed.
84+
- **Update platform stats** (HTB/THM/Root-Me) after each CTF session.
85+
- **Do not add npm dependencies** without explicit reason.
86+
- **Edit both EN and FR** when modifying page content.
7787

78-
## Après chaque modification
88+
## After every modification
7989

80-
Vérifier que le build passe avant de déployer :
90+
Verify the build passes before pushing:
8191
```bash
82-
npm run build # doit terminer avec "Complete!" sans erreurs
92+
npm run build # must finish with "Complete!" and no errors
8393
```

src/layouts/Base.astro

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,31 @@
11
---
22
import Nav from '../components/Nav.astro';
33
import Footer from '../components/Footer.astro';
4+
import { getLangFromUrl, getLocalizedPath } from '../i18n/utils';
45
56
interface Props {
67
title: string;
78
description?: string;
89
hideNav?: boolean;
910
}
1011
11-
const { title, description = 'Infrastructure homelab — Proxmox, Traefik, DNS, observabilité, IaC', hideNav = false } = Astro.props;
12+
const lang = getLangFromUrl(Astro.url);
13+
const defaultDesc = lang === 'fr'
14+
? 'Infrastructure homelab — Proxmox, Traefik, DNS, observabilité, IaC'
15+
: 'Homelab infrastructure — Proxmox, Traefik, DNS, observability, IaC';
16+
const { title, description = defaultDesc, hideNav = false } = Astro.props;
1217
const currentPath = Astro.url.pathname;
18+
const ogLocale = lang === 'fr' ? 'fr_FR' : 'en_US';
19+
const altLang = lang === 'fr' ? 'en' : 'fr';
20+
21+
// Build alternate URL: strip lang prefix if present, add other lang prefix
22+
const basePath = lang === 'en' ? currentPath : currentPath.replace(/^\/fr/, '') || '/';
23+
const altPath = altLang === 'en' ? basePath : `/fr${basePath === '/' ? '' : basePath}`;
24+
const siteUrl = 'https://pixelium.win';
1325
---
1426

1527
<!doctype html>
16-
<html lang="fr">
28+
<html lang={lang}>
1729
<head>
1830
<meta charset="utf-8" />
1931
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
@@ -24,12 +36,15 @@ const currentPath = Astro.url.pathname;
2436
<meta property="og:title" content={title} />
2537
<meta property="og:description" content={description} />
2638
<meta property="og:url" content={Astro.url.href} />
27-
<meta property="og:locale" content="fr_FR" />
39+
<meta property="og:locale" content={ogLocale} />
2840
<meta property="og:site_name" content="pixelium.win" />
2941
<meta name="twitter:card" content="summary" />
3042
<meta name="twitter:title" content={title} />
3143
<meta name="twitter:description" content={description} />
3244
<link rel="canonical" href={Astro.url.href} />
45+
<link rel="alternate" hreflang={lang} href={`${siteUrl}${currentPath}`} />
46+
<link rel="alternate" hreflang={altLang} href={`${siteUrl}${altPath}`} />
47+
<link rel="alternate" hreflang="x-default" href={`${siteUrl}${basePath}`} />
3348
<meta name="theme-color" content="#0f172a" />
3449
<title>{title}</title>
3550
</head>

0 commit comments

Comments
 (0)