From 9641ddb31ff80fe3ccfc7733f2c51c8570b873c3 Mon Sep 17 00:00:00 2001 From: Mao Nakamoto <41178744+maonakamoto@users.noreply.github.com> Date: Wed, 26 Aug 2026 11:34:58 +0200 Subject: [PATCH] fix(links): the donate buttons funded another organisation, and two nav entries went nowhere MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found by walking all 33 public pages rather than reading the code. ## Donations were going to Revamp-IT `/get-involved/donate` carried two hardcoded buttons: https://ko-fi.com/revampit https://github.com/sponsors/revampit On evig's own donate page. Someone clicking "spenden" funded the organisation evig span out of. evig has no Ko-fi and no GitHub Sponsors account, so there was nothing to repoint them at — the choice was remove them or keep collecting for someone else. Removed; the bank transfer and the device-donation path above and below them are evig's real routes. Two more links pointed at the wrong GitHub org: the "contribute code" button (github.com/revampit) and the CO₂ page's "check our maths" link (github.com/g-but/revampit — the previous org's repo AND a retired handle). Both derive from EXTERNAL_LINKS.sourceCode now. ## Two nav entries rendered `Marktplatz → evig Shop` read EXTERNAL_LINKS.shopware and `Lernen → Wiki` read EXTERNAL_LINKS.wiki. Both are empty strings — evig has neither a Shopware storefront nor a wiki. Neither MegaMenuContent nor MobileMenuNav filters empty hrefs, so both shipped as ``: the FIRST item of the Marktplatz menu opened a blank duplicate of the current page in a new tab. The shop entry's comment still read "The official RevampIT storefront is the external Shopware shop", while .claude/CLAUDE.md says evig has one store and it is /marketplace. Nothing could have caught this: not a missing key (the labels exist), not a broken route (there is no route), not a type error (`''` is a valid string). So the gate is new — `navigation-links-resolve.test.ts` asserts every href in the real exported tree is non-empty and well-formed, which also covers the derived builders. Proved by mutation: planting the empty href back turns "every href is present and non-empty" red and leaves the other three green. ## Three dead links shipped in DE copy - faq.groups[4].items[1] sold "die REVAMPED-Zertifizierung" and linked to /revamped — a 404 since #382 deleted that page. My own regression: I removed the page and its inbound CTA but not the FAQ entry. REVAMPED is the previous org's product name, so the question goes rather than the link. - `Lernen → Guides` pointed at /knowhow#guides; the Guides card ON that page pointed at /#guides. Neither anchor exists — /knowhow's only id is `ressourcen` — and the two did not even agree with each other. There are no guides. ## Lernen now points at what evig actually owns /workshops renders "0 Workshops · Aktuell sind keine Workshops geplant" and /blog renders nothing, while the 43-entry open-source alternatives registry (1029 lines, real, indexed) and the Linux page with its distro matrix sat three levels down under Dienstleistungen. Both are in Lernen now, where someone looking to learn would look, alongside a Ressourcen entry pointing at the curated-links section that does exist. ## /knowhow claimed Revamp-IT's history as evig's "Wir teilen unser 16+ Jahre Knowhow" — on an org founded 2026. That is exactly what .claude/CLAUDE.md forbids ("evig claims no 'since 2003' of its own"). Its H1 also sold "Vintage Hardware", repeated in the meta description and the guides card — the opposite of what evig sells, which is machines good enough for real work today. Rewritten to Linux, open software and the practical use of AI, in all eight locales. npm run verify green: lint, umlauts, chrome, docs, compliance, typecheck, 7750 tests (534 suites), production build. Co-Authored-By: Claude Opus 5 (1M context) --- messages/de.json | 26 +++----- messages/en.json | 26 +++----- messages/es.json | 26 +++----- messages/fr.json | 26 +++----- messages/it.json | 26 +++----- messages/ja.json | 26 +++----- messages/ko.json | 26 +++----- messages/ru.json | 26 +++----- src/app/[locale]/get-involved/donate/page.tsx | 42 +++---------- src/app/[locale]/knowhow/page.tsx | 6 +- src/app/[locale]/transparenz/co2/page.tsx | 8 ++- .../navigation-links-resolve.test.ts | 61 +++++++++++++++++++ src/config/customer-journeys.ts | 16 +++-- src/config/navigation.tsx | 43 +++++++++---- 14 files changed, 176 insertions(+), 208 deletions(-) create mode 100644 src/config/__tests__/navigation-links-resolve.test.ts diff --git a/messages/de.json b/messages/de.json index e3a046951..1b2fc75c6 100644 --- a/messages/de.json +++ b/messages/de.json @@ -77,8 +77,6 @@ "buyDevices": "Geräte kaufen", "communityListings": "Marktplatz", "communityListingsDesc": "Gebrauchte IT von evig und anderen Anbieter:innen", - "orgShop": "evig Shop", - "orgShopDesc": "Geprüfte, aufbereitete Geräte", "store": "Ladenlokal Zürich", "storeDesc": "Vor Ort stöbern und beraten lassen", "sell": "Verkaufen", @@ -97,12 +95,8 @@ "learnDesc": "Workshops, Guides und Ressourcen", "workshops": "Workshops", "workshopsDesc": "Kurse vor Ort buchen", - "guides": "Guides", - "guidesDesc": "Schritt-für-Schritt Anleitungen", "blog": "Blog", "blogDesc": "Tipps und Geschichten", - "wiki": "Wiki", - "wikiDesc": "Gemeinsames Wissensportal", "getInvolved": "Mitmachen", "getInvolvedDesc": "Teil der Bewegung werden", "engagement": "Engagement", @@ -164,7 +158,9 @@ "pressDesc": "Medienberichte", "aiDivision": "Zugang zu künstlicher Intelligenz — Assistent und passende Hardware", "vision": "Vision", - "visionDesc": "Wofür evig da ist, in voller Länge" + "visionDesc": "Wofür evig da ist, in voller Länge", + "resources": "Ressourcen", + "resourcesDesc": "Kuratierte Tools, Distributionen und Doku" }, "language": "Sprache", "missionHistory": "Mission & Geschichte", @@ -4116,16 +4112,16 @@ "knowhow": { "meta": { "title": "Knowhow - Guides, Blog, Workshops | evig", - "description": "Lerne über Vintage Hardware, Linux und Open Source. Guides, Workshops, Blog und curatierte Ressourcen." + "description": "Lerne Linux, offene Software und den praktischen Umgang mit KI. Guides, Workshops, Blog und kuratierte Ressourcen." }, "hero": { - "title": "Knowhow teilen über Vintage Hardware, Linux und Open Source", - "subtitle": "Wir teilen unser 16+ Jahre Knowhow, damit du Technologie besser verstehen und nutzen kannst. Egal ob du gerade anfängst oder bereits ein Experte bist – hier findest du Ressourcen für deine Lernreise." + "title": "Lernen, was die Maschine kann — Linux, offene Software, KI", + "subtitle": "Wir geben weiter, was wir beim Instandsetzen, Einrichten und Betreiben von Geräten gelernt haben — damit du deine Werkzeuge selbst beherrschst, statt auf jemanden zu warten." }, "sections": { "guides": { "title": "Guides", - "description": "Schritt-für-Schritt Anleitungen für Linux, Vintage Hardware und Open Source", + "description": "Schritt-für-Schritt-Anleitungen für Linux, offene Software und den Einstieg in KI", "cta": "Zu den Guides" }, "blog": { @@ -4831,14 +4827,6 @@ "label": "Zum Shop" } }, - { - "q": "Was ist die REVAMPED-Zertifizierung?", - "a": "REVAMPED kennzeichnet nachhaltige, reparierbare Builds mit dokumentierter Herkunft, klaren Upgrade-Pfaden und Qualitätssicherung.", - "link": { - "href": "/revamped", - "label": "Mehr zu REVAMPED" - } - }, { "q": "Gibt es Garantie auf eure Geräte?", "a": "Ja. Aufbereitete Geräte kommen mit Gewährleistung. Details nennen wir pro Produkt transparent." diff --git a/messages/en.json b/messages/en.json index b01f4945f..eaf04cfe4 100644 --- a/messages/en.json +++ b/messages/en.json @@ -92,7 +92,6 @@ "openSourceSolutionsDesc": "Consulting and implementation", "marketplaceDesc": "Buy, sell and IT help", "communityListingsDesc": "Used IT from evig and other sellers", - "orgShopDesc": "Tested, refurbished devices", "storeDesc": "Browse in person and get advice", "createListingDesc": "Sell your own devices — for free", "myListingsDesc": "Manage listings and sales", @@ -103,9 +102,7 @@ "aboPoolsDesc": "One AI subscription split four ways — everyone pays their share", "learnDesc": "Workshops, guides and resources", "workshopsDesc": "Book in-person courses", - "guidesDesc": "Step-by-step instructions", "blogDesc": "Tips and stories", - "wikiDesc": "Shared knowledge portal", "getInvolvedDesc": "Become part of the movement", "volunteerDesc": "Contribute your time and skills", "internshipDesc": "Gain experience", @@ -134,7 +131,6 @@ "marketplace": "Marketplace", "buyDevices": "Buy devices", "communityListings": "Marketplace", - "orgShop": "evig listings", "store": "Zürich storefront", "sell": "Sell", "createListing": "Create listing", @@ -145,9 +141,7 @@ "becomeTechnician": "Become a technician", "learn": "Learn", "workshops": "Workshops", - "guides": "Guides", "blog": "Blog", - "wiki": "Wiki", "getInvolved": "Get involved", "engagement": "Engagement", "volunteer": "Volunteering", @@ -197,7 +191,9 @@ "pressDesc": "Media coverage", "aiDivision": "Access to artificial intelligence — the assistant and the hardware to run it", "vision": "Vision", - "visionDesc": "What evig is for, at full length" + "visionDesc": "What evig is for, at full length", + "resources": "Resources", + "resourcesDesc": "Curated tools, distributions and docs" }, "experimentalBanner": "Experimental Site", "experimentalBannerLink": "go to current site", @@ -3433,14 +3429,6 @@ "label": "Go to the Shop" } }, - { - "q": "What is the REVAMPED certification?", - "a": "REVAMPED marks sustainable, repairable builds with documented provenance, clear upgrade paths and quality assurance.", - "link": { - "href": "/revamped", - "label": "More about REVAMPED" - } - }, { "q": "Is there a warranty on your devices?", "a": "Yes. Refurbished devices come with a warranty. We state the details transparently for each product." @@ -4281,16 +4269,16 @@ "knowhow": { "meta": { "title": "Knowhow - Guides, Blog, Workshops | evig", - "description": "Learn about vintage hardware, Linux and open source. Guides, workshops, blog and curated resources." + "description": "Learn Linux, open software and the practical use of AI. Guides, workshops, blog and curated resources." }, "hero": { - "title": "Sharing knowhow about vintage hardware, Linux and open source", - "subtitle": "We share our 16+ years of knowhow so you can better understand and use technology. Whether you are just starting out or already an expert – here you will find resources for your learning journey." + "title": "Learn what the machine can do — Linux, open software, AI", + "subtitle": "We pass on what we learn repairing, setting up and running machines — so you command your own tools instead of waiting for someone." }, "sections": { "guides": { "title": "Guides", - "description": "Step-by-step instructions for Linux, vintage hardware and open source", + "description": "Step-by-step guides for Linux, open software and getting started with AI", "cta": "View guides" }, "blog": { diff --git a/messages/es.json b/messages/es.json index ce69c7f2e..2c9c60e71 100644 --- a/messages/es.json +++ b/messages/es.json @@ -79,8 +79,6 @@ "buyDevices": "Comprar dispositivos", "communityListings": "Anuncios de la comunidad", "communityListingsDesc": "TI de segunda mano de particulares — 0% comisiones", - "orgShop": "Tienda evig", - "orgShopDesc": "Dispositivos verificados y reacondicionados", "store": "Tienda física Zúrich", "storeDesc": "Explora y recibe asesoría en persona", "sell": "Vender", @@ -99,12 +97,8 @@ "learnDesc": "Talleres, guías y recursos", "workshops": "Talleres", "workshopsDesc": "Cursos presenciales para reservar", - "guides": "Guías", - "guidesDesc": "Instrucciones paso a paso", "blog": "Blog", "blogDesc": "Consejos e historias", - "wiki": "Wiki", - "wikiDesc": "Portal de conocimiento colectivo", "getInvolved": "Participa", "getInvolvedDesc": "Forma parte del movimiento", "engagement": "Compromiso", @@ -164,7 +158,9 @@ "pressDesc": "Cobertura mediática", "aiDivision": "Acceso a la inteligencia artificial — el asistente y el hardware para moverlo", "vision": "Visión", - "visionDesc": "Para qué existe evig, en toda su extensión" + "visionDesc": "Para qué existe evig, en toda su extensión", + "resources": "Recursos", + "resourcesDesc": "Herramientas, distribuciones y documentación seleccionadas" }, "language": "Idioma", "missionHistory": "Misión & Historia", @@ -1246,14 +1242,6 @@ "label": "Ir a la tienda" } }, - { - "q": "¿Qué es la certificación REVAMPED?", - "a": "REVAMPED identifica builds sostenibles y reparables con procedencia documentada, rutas de actualización claras y aseguramiento de la calidad.", - "link": { - "href": "/revamped", - "label": "Más sobre REVAMPED" - } - }, { "q": "¿Hay garantía en vuestros dispositivos?", "a": "Sí. Los dispositivos reacondicionados vienen con garantía. Los detalles se especifican de forma transparente por producto." @@ -2581,16 +2569,16 @@ "knowhow": { "meta": { "title": "Knowhow - Guías, Blog, Talleres | evig", - "description": "Aprende sobre hardware vintage, Linux y Open Source. Guías, talleres, blog y recursos curados." + "description": "Aprende Linux, software abierto y el uso práctico de la IA. Guías, talleres, blog y recursos seleccionados." }, "hero": { - "title": "Compartir knowhow sobre hardware vintage, Linux y Open Source", - "subtitle": "Compartimos más de 16 años de knowhow para que puedas entender y aprovechar mejor la tecnología. Tanto si estás empezando como si ya eres experto/a — aquí encontrarás recursos para tu camino de aprendizaje." + "title": "Aprende lo que la máquina puede hacer: Linux, software abierto, IA", + "subtitle": "Transmitimos lo que aprendemos reparando, configurando y manteniendo equipos, para que domines tus propias herramientas en lugar de esperar a alguien." }, "sections": { "guides": { "title": "Guías", - "description": "Instrucciones paso a paso para Linux, hardware vintage y Open Source", + "description": "Guías paso a paso de Linux, software abierto y primeros pasos con la IA", "cta": "Ver guías" }, "blog": { diff --git a/messages/fr.json b/messages/fr.json index c56926da4..c2fdda347 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -100,7 +100,6 @@ "openSourceSolutionsDesc": "Conseil et mise en œuvre", "marketplaceDesc": "Acheter, vendre et aide informatique", "communityListingsDesc": "Informatique d'occasion — 0% de frais", - "orgShopDesc": "Appareils testés et remis à neuf", "storeDesc": "Parcourez en personne et obtenez des conseils", "createListingDesc": "Vendez vos appareils — gratuitement", "myListingsDesc": "Gérer les annonces et les ventes", @@ -111,9 +110,7 @@ "aboPoolsDesc": "Un abonnement d'IA à quatre — chacun paie sa part", "learnDesc": "Ateliers, guides et ressources", "workshopsDesc": "Réserver des cours en personne", - "guidesDesc": "Instructions étape par étape", "blogDesc": "Conseils et histoires", - "wikiDesc": "Portail de connaissances partagées", "getInvolvedDesc": "Faire partie du mouvement", "volunteerDesc": "Contribuer votre temps et vos compétences", "internshipDesc": "Acquérir de l'expérience", @@ -142,7 +139,6 @@ "marketplace": "Marché", "buyDevices": "Acheter des appareils", "communityListings": "Annonces de la communauté", - "orgShop": "Boutique evig", "store": "Magasin de Zurich", "sell": "Vendre", "createListing": "Créer une annonce", @@ -153,9 +149,7 @@ "becomeTechnician": "Devenir technicien", "learn": "Apprendre", "workshops": "Ateliers", - "guides": "Guides", "blog": "Blog", - "wiki": "Wiki", "getInvolved": "Participer", "engagement": "Engagement", "volunteer": "Bénévolat", @@ -203,7 +197,9 @@ "pressDesc": "Revue de presse", "aiDivision": "Accès à l’intelligence artificielle — l’assistant et le matériel pour le faire tourner", "vision": "Vision", - "visionDesc": "La raison d'être d'evig, en entier" + "visionDesc": "La raison d'être d'evig, en entier", + "resources": "Ressources", + "resourcesDesc": "Outils, distributions et documentation sélectionnés" }, "badge": { "new": "Nouveau" @@ -3433,14 +3429,6 @@ "label": "Vers la boutique" } }, - { - "q": "Qu'est-ce que la certification REVAMPED ?", - "a": "REVAMPED désigne des configurations durables et réparables avec une origine documentée, des voies de mise à niveau claires et un contrôle qualité.", - "link": { - "href": "/revamped", - "label": "En savoir plus sur REVAMPED" - } - }, { "q": "Y a-t-il une garantie sur vos appareils ?", "a": "Oui. Les appareils reconditionnés sont livrés avec une garantie. Nous indiquons les détails de manière transparente pour chaque produit." @@ -4281,16 +4269,16 @@ "knowhow": { "meta": { "title": "Knowhow - Guides, Blog, Ateliers | evig", - "description": "Apprends sur le matériel vintage, Linux et l'open source. Guides, ateliers, blog et ressources sélectionnées." + "description": "Apprenez Linux, les logiciels libres et l'usage concret de l'IA. Guides, ateliers, blog et ressources sélectionnées." }, "hero": { - "title": "Partager le knowhow sur le matériel vintage, Linux et l'open source", - "subtitle": "Nous partageons notre knowhow de 16+ ans pour que tu puisses mieux comprendre et utiliser la technologie. Que tu débuttes ou que tu sois déjà expert – tu trouveras ici des ressources pour ton voyage d'apprentissage." + "title": "Apprendre ce que la machine sait faire : Linux, logiciels libres, IA", + "subtitle": "Nous transmettons ce que nous apprenons en réparant, installant et faisant tourner des machines — pour que vous maîtrisiez vos outils au lieu d'attendre quelqu'un." }, "sections": { "guides": { "title": "Guides", - "description": "Instructions étape par étape pour Linux, matériel vintage et open source", + "description": "Guides pas à pas pour Linux, les logiciels libres et les premiers pas avec l'IA", "cta": "Voir les guides" }, "blog": { diff --git a/messages/it.json b/messages/it.json index 6f89225f6..7c5c6610e 100644 --- a/messages/it.json +++ b/messages/it.json @@ -79,8 +79,6 @@ "buyDevices": "Acquista dispositivi", "communityListings": "Annunci community", "communityListingsDesc": "IT usato da privati — 0% commissioni", - "orgShop": "Shop evig", - "orgShopDesc": "Dispositivi verificati e ricondizionati", "store": "Negozio Zurigo", "storeDesc": "Sfoglia e ricevi consulenza di persona", "sell": "Vendi", @@ -99,12 +97,8 @@ "learnDesc": "Workshop, guide e risorse", "workshops": "Workshop", "workshopsDesc": "Corsi in presenza da prenotare", - "guides": "Guide", - "guidesDesc": "Istruzioni passo per passo", "blog": "Blog", "blogDesc": "Consigli e storie", - "wiki": "Wiki", - "wikiDesc": "Portale di conoscenze condivise", "getInvolved": "Partecipa", "getInvolvedDesc": "Entra a far parte del movimento", "engagement": "Impegno", @@ -164,7 +158,9 @@ "pressDesc": "Rassegna stampa", "aiDivision": "Accesso all’intelligenza artificiale — l’assistente e l’hardware per farlo girare", "vision": "Visione", - "visionDesc": "Perché esiste evig, per esteso" + "visionDesc": "Perché esiste evig, per esteso", + "resources": "Risorse", + "resourcesDesc": "Strumenti, distribuzioni e documentazione selezionati" }, "language": "Lingua", "missionHistory": "Missione & Storia", @@ -1246,14 +1242,6 @@ "label": "Vai allo shop" } }, - { - "q": "Cos'è la certificazione REVAMPED?", - "a": "REVAMPED identifica build sostenibili e riparabili con provenienza documentata, chiari percorsi di upgrade e garanzia di qualità.", - "link": { - "href": "/revamped", - "label": "Scopri REVAMPED" - } - }, { "q": "C'è garanzia sui vostri dispositivi?", "a": "Sì. I dispositivi ricondizionati vengono forniti con garanzia. I dettagli sono comunicati in modo trasparente per ogni prodotto." @@ -2581,16 +2569,16 @@ "knowhow": { "meta": { "title": "Knowhow - Guide, Blog, Workshop | evig", - "description": "Impara sull'hardware vintage, Linux e Open Source. Guide, workshop, blog e risorse curate." + "description": "Impara Linux, il software aperto e l'uso pratico dell'IA. Guide, laboratori, blog e risorse selezionate." }, "hero": { - "title": "Condividi il knowhow su hardware vintage, Linux e Open Source", - "subtitle": "Condividiamo il nostro knowhow di oltre 16 anni per aiutarti a capire e usare meglio la tecnologia. Che tu stia iniziando o sia già un esperto — qui trovi risorse per il tuo percorso di apprendimento." + "title": "Imparare cosa sa fare la macchina: Linux, software aperto, IA", + "subtitle": "Trasmettiamo ciò che impariamo riparando, configurando e facendo funzionare le macchine, perché tu sia padrone dei tuoi strumenti invece di aspettare qualcuno." }, "sections": { "guides": { "title": "Guide", - "description": "Istruzioni passo per passo per Linux, hardware vintage e Open Source", + "description": "Guide passo passo su Linux, software aperto e primi passi con l'IA", "cta": "Vai alle guide" }, "blog": { diff --git a/messages/ja.json b/messages/ja.json index 1f28ee3c4..11c660122 100644 --- a/messages/ja.json +++ b/messages/ja.json @@ -79,8 +79,6 @@ "buyDevices": "機器を購入", "communityListings": "コミュニティ出品", "communityListingsDesc": "個人からの中古IT — 手数料0%", - "orgShop": "evig ショップ", - "orgShopDesc": "検査済みの再生品デバイス", "store": "チューリッヒ店舗", "storeDesc": "店頭で見て、相談する", "sell": "出品する", @@ -99,12 +97,8 @@ "learnDesc": "ワークショップ、ガイド、リソース", "workshops": "ワークショップ", "workshopsDesc": "現地コースを予約", - "guides": "ガイド", - "guidesDesc": "ステップバイステップの手順", "blog": "ブログ", "blogDesc": "ヒントとストーリー", - "wiki": "Wiki", - "wikiDesc": "共有知識ポータル", "getInvolved": "参加する", "getInvolvedDesc": "この活動の一員になる", "engagement": "エンゲージメント", @@ -164,7 +158,9 @@ "pressDesc": "メディア掲載", "aiDivision": "人工知能へのアクセス——アシスタントと、それを動かすハードウェア", "vision": "ビジョン", - "visionDesc": "evig が何のためにあるのか、その全文" + "visionDesc": "evig が何のためにあるのか、その全文", + "resources": "リソース", + "resourcesDesc": "厳選したツール、ディストリビューション、ドキュメント" }, "language": "言語", "missionHistory": "ミッション & 歴史", @@ -1246,14 +1242,6 @@ "label": "ショップへ" } }, - { - "q": "REVAMPED認証とは何ですか?", - "a": "REVAMPEDは、出所のドキュメント化、明確なアップグレードパス、品質保証を備えた持続可能で修理可能なビルドを示しています。", - "link": { - "href": "/revamped", - "label": "REVAMPEDについてもっと" - } - }, { "q": "デバイスに保証はありますか?", "a": "はい。リファービッシュ品には保証が付いています。詳細は製品ごとに透明にお伝えします。" @@ -2581,16 +2569,16 @@ "knowhow": { "meta": { "title": "ノウハウ — ガイド、ブログ、ワークショップ | evig", - "description": "ヴィンテージハードウェア、Linux、Open Sourceについて学ぶ。ガイド、ワークショップ、ブログ、厳選リソース。" + "description": "Linux、オープンなソフトウェア、AI の実践的な使い方を学ぶ。ガイド、ワークショップ、ブログ、厳選した資料。" }, "hero": { - "title": "ヴィンテージハードウェア、Linux、Open Sourceのノウハウを共有", - "subtitle": "テクノロジーをより深く理解し活用できるよう、16年以上のノウハウを共有します。初心者でも専門家でも — ここで学習の旅に役立つリソースを見つけてください。" + "title": "機械に何ができるかを学ぶ — Linux、オープンなソフトウェア、AI", + "subtitle": "機器を直し、設定し、動かしながら学んだことをそのまま渡します。誰かを待つのではなく、自分の道具を自分で使いこなせるように。" }, "sections": { "guides": { "title": "ガイド", - "description": "Linux、ヴィンテージハードウェア、Open Sourceのステップバイステップの手順", + "description": "Linux、オープンなソフトウェア、AI をはじめるための手順ガイド", "cta": "ガイドを見る" }, "blog": { diff --git a/messages/ko.json b/messages/ko.json index e48601bd2..e3fa379c6 100644 --- a/messages/ko.json +++ b/messages/ko.json @@ -79,8 +79,6 @@ "buyDevices": "기기 구매", "communityListings": "커뮤니티 판매 목록", "communityListingsDesc": "개인 간 중고 IT — 수수료 0%", - "orgShop": "evig 쇼핑몰", - "orgShopDesc": "검증된 리퍼비시 기기", "store": "취리히 매장", "storeDesc": "직접 방문하여 둘러보고 상담받기", "sell": "판매하기", @@ -99,12 +97,8 @@ "learnDesc": "워크숍, 가이드 및 리소스", "workshops": "워크숍", "workshopsDesc": "현장 강좌 예약", - "guides": "가이드", - "guidesDesc": "단계별 안내", "blog": "블로그", "blogDesc": "팁과 이야기", - "wiki": "위키", - "wikiDesc": "공동 지식 포털", "getInvolved": "참여하기", "getInvolvedDesc": "운동의 일원이 되기", "engagement": "참여", @@ -164,7 +158,9 @@ "pressDesc": "미디어 보도", "aiDivision": "인공지능에 대한 접근 — 어시스턴트와 그것을 돌릴 하드웨어", "vision": "비전", - "visionDesc": "evig가 무엇을 위해 있는지, 전문으로" + "visionDesc": "evig가 무엇을 위해 있는지, 전문으로", + "resources": "자료", + "resourcesDesc": "선별한 도구, 배포판, 문서" }, "language": "언어", "missionHistory": "미션 & 역사", @@ -1246,14 +1242,6 @@ "label": "쇼핑몰로 이동" } }, - { - "q": "REVAMPED 인증이란 무엇인가요?", - "a": "REVAMPED는 문서화된 출처, 명확한 업그레이드 경로, 품질 보증이 있는 지속 가능하고 수리 가능한 빌드를 표시합니다.", - "link": { - "href": "/revamped", - "label": "REVAMPED에 대해 더 알아보기" - } - }, { "q": "기기에 보증이 있나요?", "a": "네. 재정비된 기기에는 보증이 제공됩니다. 세부 사항은 제품별로 투명하게 안내합니다." @@ -2581,16 +2569,16 @@ "knowhow": { "meta": { "title": "노하우 - 가이드, 블로그, 워크숍 | evig", - "description": "빈티지 하드웨어, Linux, 오픈 소스에 대해 배우세요. 가이드, 워크숍, 블로그 및 큐레이션된 리소스." + "description": "리눅스와 열린 소프트웨어, 그리고 AI의 실질적인 활용을 배우세요. 가이드, 워크숍, 블로그, 선별된 자료." }, "hero": { - "title": "빈티지 하드웨어, Linux, 오픈 소스에 관한 노하우 나누기", - "subtitle": "저희의 16년 이상의 노하우를 공유하여 귀하가 기술을 더 잘 이해하고 활용할 수 있도록 합니다. 막 시작하든 이미 전문가이든 — 여기서 학습 여정을 위한 리소스를 찾을 수 있습니다." + "title": "기계가 무엇을 할 수 있는지 배우기 — 리눅스, 열린 소프트웨어, AI", + "subtitle": "기기를 고치고, 설치하고, 운영하며 배운 것을 그대로 전합니다. 누군가를 기다리는 대신 자기 도구를 스스로 다룰 수 있도록." }, "sections": { "guides": { "title": "가이드", - "description": "Linux, 빈티지 하드웨어, 오픈 소스를 위한 단계별 안내", + "description": "리눅스, 열린 소프트웨어, AI 입문을 위한 단계별 안내", "cta": "가이드 보기" }, "blog": { diff --git a/messages/ru.json b/messages/ru.json index d14ff816f..79e51af34 100644 --- a/messages/ru.json +++ b/messages/ru.json @@ -79,8 +79,6 @@ "buyDevices": "Купить устройства", "communityListings": "Объявления сообщества", "communityListingsDesc": "Б/у IT от частных лиц — 0% комиссий", - "orgShop": "Магазин evig", - "orgShopDesc": "Проверенные восстановленные устройства", "store": "Магазин в Цюрихе", "storeDesc": "Посмотреть товары и получить консультацию на месте", "sell": "Продать", @@ -99,12 +97,8 @@ "learnDesc": "Воркшопы, руководства и ресурсы", "workshops": "Воркшопы", "workshopsDesc": "Бронируйте очные курсы", - "guides": "Руководства", - "guidesDesc": "Пошаговые инструкции", "blog": "Блог", "blogDesc": "Советы и истории", - "wiki": "Wiki", - "wikiDesc": "Общая база знаний", "getInvolved": "Принять участие", "getInvolvedDesc": "Станьте частью движения", "engagement": "Активное участие", @@ -168,7 +162,9 @@ "pressDesc": "СМИ о нас", "aiDivision": "Доступ к искусственному интеллекту — ассистент и техника, чтобы он работал", "vision": "Видение", - "visionDesc": "Ради чего существует evig — полностью" + "visionDesc": "Ради чего существует evig — полностью", + "resources": "Материалы", + "resourcesDesc": "Отобранные инструменты, дистрибутивы и документация" }, "language": "Язык", "missionHistory": "Миссия и история", @@ -4119,16 +4115,16 @@ "knowhow": { "meta": { "title": "Knowhow — гайды, блог, воркшопы | evig", - "description": "Изучайте винтажное оборудование, Linux и Open Source. Гайды, воркшопы, блог и подобранные ресурсы." + "description": "Осваивайте Linux, открытые программы и практическое применение ИИ. Руководства, мастерские, блог и отобранные материалы." }, "hero": { - "title": "Делимся знаниями о винтажном оборудовании, Linux и Open Source", - "subtitle": "Мы делимся нашим 16+-летним опытом, чтобы вы могли лучше понимать и использовать технологии. Будь вы новичок или эксперт — здесь найдутся ресурсы для вашего обучения." + "title": "Узнать, на что способна машина — Linux, открытые программы, ИИ", + "subtitle": "Мы передаём то, чему научились, ремонтируя, настраивая и обслуживая технику, — чтобы вы владели своими инструментами, а не ждали кого-то." }, "sections": { "guides": { "title": "Гайды", - "description": "Пошаговые инструкции по Linux, винтажному оборудованию и Open Source", + "description": "Пошаговые руководства по Linux, открытым программам и первым шагам с ИИ", "cta": "К гайдам" }, "blog": { @@ -4778,14 +4774,6 @@ "label": "В магазин" } }, - { - "q": "Что такое сертификация REVAMPED?", - "a": "REVAMPED обозначает устойчивые, ремонтопригодные сборки с задокументированным происхождением, чёткими путями апгрейда и контролем качества.", - "link": { - "href": "/revamped", - "label": "Подробнее о REVAMPED" - } - }, { "q": "Есть ли гарантия на ваши устройства?", "a": "Да. Восстановленные устройства поставляются с гарантией. Детали мы прозрачно указываем для каждого продукта." diff --git a/src/app/[locale]/get-involved/donate/page.tsx b/src/app/[locale]/get-involved/donate/page.tsx index edc35557d..c21d3f571 100644 --- a/src/app/[locale]/get-involved/donate/page.tsx +++ b/src/app/[locale]/get-involved/donate/page.tsx @@ -4,13 +4,13 @@ export const dynamic = 'force-dynamic' import { Eyebrow } from '@/components/ui/Eyebrow' import React from 'react' import { Metadata } from 'next' -import { ArrowDown, Coffee, Heart } from 'lucide-react' +import { ArrowDown } from 'lucide-react' import { Link } from '@/i18n/navigation' import { NewsletterSignup } from '@/components/community/NewsletterSignup' import { DropoffForm } from '@/components/donate/DropoffForm' import { CopyButton } from '@/components/community/CopyButton' import { Section } from '@/components/layout/Section' -import { BANK, CONTACT, BASE_REGION, ORG } from '@/config/org' +import { BANK, CONTACT, BASE_REGION, ORG, EXTERNAL_LINKS } from '@/config/org' import { DONATION_TIER_AMOUNTS } from '@/config/donations' import { ROUTES } from '@/config/routes' import { getTranslations } from 'next-intl/server' @@ -204,39 +204,17 @@ export default async function DonatePage({ params }: DonatePageProps) {

{tSupport('otherWays.title')}

-
-
- - {tSupport('oneTime.cta')} - -
- -
-
-
+ {/* Two donation buttons stood here, hardcoded to ko-fi.com/revampit + and github.com/sponsors/revampit. On evig's own donate page they + sent money to a DIFFERENT organisation — the one evig span out + of. evig has no Ko-fi and no GitHub Sponsors account, so there is + nothing to repoint them at; the honest options were "remove" or + "collect donations for someone else". The bank transfer above and + the device donation below are evig's real paths. */}
{t('contribute.intro')}

+ {/* Was hardcoded to g-but/revampit — a retired GitHub handle AND the + previous organisation's repo, so the "check our maths" link on + the transparency page pointed at neither evig nor a live account. + It derives from EXTERNAL_LINKS.sourceCode now. */} `: the first item of the Marktplatz menu, and + * one of four items under Lernen, each opening a blank duplicate of the + * current page in a new tab. + * + * Nothing could catch that. It is not a missing key (the labels exist), not a + * broken route (there is no route), and not a type error (`''` is a valid + * string). Only opening the menu and clicking would reveal it — which is why + * it survived a rebrand and several audits. + * + * This is the gate for that class. It runs against the real exported tree, so + * it also covers the derived builders (`buildServicesNavigationItems`, + * `buildMarktplatzNavigationItems`) — an empty href reintroduced through + * SERVICE_CONFIGS or CUSTOMER_JOURNEYS fails here too. + */ + +import { mainNavigation, type NavigationItem } from '@/config/navigation' + +/** Flatten the tree so sub-items are checked alongside their parents. */ +function allItems(items: readonly NavigationItem[]): NavigationItem[] { + return items.flatMap((item) => [item, ...allItems(item.subItems ?? [])]) +} + +const label = (i: NavigationItem) => i.nameKey ?? i.name + +describe('navigation links resolve', () => { + const items = allItems(mainNavigation) + + it('sweeps a non-trivial tree', () => { + // A sweep over an empty tree passes trivially. Fail loudly instead. + expect(items.length).toBeGreaterThan(15) + }) + + it('every href is present and non-empty', () => { + const empty = items + .filter((i) => typeof i.href !== 'string' || i.href.trim() === '') + .map((i) => `${label(i)} → renders as
, which goes nowhere`) + expect(empty).toEqual([]) + }) + + it('every href is an internal path or an absolute URL', () => { + const malformed = items + .filter((i) => typeof i.href === 'string' && i.href.trim() !== '') + .filter((i) => !/^(\/|https?:\/\/)/.test(i.href)) + .map((i) => `${label(i)} → "${i.href}" is neither an internal path nor an absolute URL`) + expect(malformed).toEqual([]) + }) + + it('nothing marked external points at an internal path', () => { + const wrong = items + .filter((i) => i.external && i.href.startsWith('/')) + .map((i) => `${label(i)} → ${i.href} is marked external but is internal`) + expect(wrong).toEqual([]) + }) +}) diff --git a/src/config/customer-journeys.ts b/src/config/customer-journeys.ts index 9ded13790..75237035e 100644 --- a/src/config/customer-journeys.ts +++ b/src/config/customer-journeys.ts @@ -10,7 +10,6 @@ */ import { ROUTES } from '@/config/routes' -import { EXTERNAL_LINKS } from '@/config/org' import type { NavigationItem } from '@/config/navigation' export const CUSTOMER_JOURNEYS = { @@ -19,14 +18,13 @@ export const CUSTOMER_JOURNEYS = { sectionKey: 'sectionBuySell', hubHref: ROUTES.public.marketplace, items: [ - { - // The official RevampIT storefront is the external Shopware shop; - // the internal /marketplace is the community P2P listing surface. - nameKey: 'orgShop', - href: EXTERNAL_LINKS.shopware, - descriptionKey: 'orgShopDesc', - external: true, - }, + // An "evig Shop" entry stood here, pointing at EXTERNAL_LINKS.shopware — + // an empty string. It rendered as , so the + // first item of the Marktplatz menu opened a blank copy of the current + // page in a new tab. Its comment still described "the official RevampIT + // storefront". evig has ONE store and it is /marketplace (see the + // storefront architecture rule in .claude/CLAUDE.md), so there is no + // second shop to link to. { nameKey: 'communityListings', href: ROUTES.public.marketplace, diff --git a/src/config/navigation.tsx b/src/config/navigation.tsx index 30661afd7..f25cac689 100644 --- a/src/config/navigation.tsx +++ b/src/config/navigation.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { ORG, EXTERNAL_LINKS } from '@/config/org' +import { ORG } from '@/config/org' import { buildMarktplatzNavigationItems } from '@/config/customer-journeys' import { DIVISION_PAGES, EVIG_DIVISIONS } from '@/config/divisions' import { ROUTES } from '@/config/routes' @@ -160,10 +160,32 @@ export const mainNavigation: NavigationItem[] = [ descriptionKey: 'workshopsDesc', }, { - name: 'Guides', - nameKey: 'guides', - href: '/knowhow#guides', - descriptionKey: 'guidesDesc', + // "Guides" pointed at /knowhow#guides. There is no #guides element on + // /knowhow — its only id is `ressourcen` — and the card ON that page + // pointed at /#guides, a homepage anchor that does not exist either. + // Two dead links that did not even agree with each other, for content + // that has never been written. + // + // These two entries are what evig actually owns to teach with: a + // 43-entry open-source alternatives registry, and a Linux page with a + // distro-recommendation matrix. Both were filed under Dienstleistungen, + // three levels from anyone looking to learn something. + name: 'Open-Source-Alternativen', + nameKey: 'openSourceSolutions', + href: '/services/open-source-solutions', + descriptionKey: 'openSourceSolutionsDesc', + }, + { + name: 'Linux einrichten', + nameKey: 'linuxOpenSource', + href: '/services/linux-open-source', + descriptionKey: 'linuxOpenSourceDesc', + }, + { + name: 'Ressourcen', + nameKey: 'resources', + href: '/knowhow#ressourcen', + descriptionKey: 'resourcesDesc', }, { name: 'Blog', @@ -171,13 +193,10 @@ export const mainNavigation: NavigationItem[] = [ href: '/blog', descriptionKey: 'blogDesc', }, - { - name: 'Wiki', - nameKey: 'wiki', - href: EXTERNAL_LINKS.wiki, - descriptionKey: 'wikiDesc', - external: true, - }, + // A "Wiki" entry stood here with href = EXTERNAL_LINKS.wiki, which is an + // empty string — the same defect as the Marktplatz "evig Shop" entry: + // it rendered as and opened a blank copy of + // the current page. evig has no wiki. ], }, {