Google Analytics 4 with Consent Mode v2 (denied by default)
Trilingual cookie-consent banner (consent.js) that remembers the choice
"Manage cookies" footer link to change/withdraw consent anytime
Notes / follow-ups
MK/SI translations are AI-drafted - flagged for native-speaker proofread before public launch
Launch-gated tasks documented in docs/launch-seo-checklist.md (Search Console, domain-migration redirect, www-vs-bare decision) - to be done once live on msosorg.com
## Summary
Adds the **new blog post** and a **complete SEO + analytics foundation** across all 201 pages (EN/MK/SI), plus content fixes. All changes verified in-browser.
## What's included
### Content
- **New blog article**: "How to open a Slovenian bank account" (EN/MK/SI) with scrollspy layout, sourced link list, and hero image
- **Translated pages**: `about-us` and `timeline-and-milestones` into MK + SI; repaired the previously-dead "Who We Are" nav links across all mk/si pages
- Removed a duplicate/stray project page
### Technical SEO (all 201 pages)
- Canonical, hreflang (en/mk/**sl** + x-default), Open Graph, Twitter cards
- Organization + Article + BreadcrumbList JSON-LD (with datePublished/dateModified)
- Full meta-description coverage, multilingual `sitemap.xml`, `robots.txt`
- Favicons wired in, branded `404.html`, brand OG image
- Absolute URLs target the final domain `msosorg.com`
- Reusable injector at `tools/seo_inject.py`
### Performance
- 74 heavy photos converted to WebP (28MB -> 8.5MB, -70%)
- `loading="lazy"` on below-fold images, `fetchpriority="high"` on heroes
- `.htaccess`: gzip, caching, MIME types, `ErrorDocument 404`
- Stopped tracking `images/original/` (458MB unused masters; gitignored)
### Analytics & GDPR
- Google Analytics 4 with **Consent Mode v2** (denied by default)
- Trilingual cookie-consent banner (`consent.js`) that remembers the choice
- "Manage cookies" footer link to change/withdraw consent anytime
## Notes / follow-ups
- **MK/SI translations are AI-drafted** - flagged for native-speaker proofread before public launch
- **Launch-gated tasks** documented in `docs/launch-seo-checklist.md` (Search Console, domain-migration redirect, www-vs-bare decision) - to be done once live on `msosorg.com`
Generated with [Claude Code](https://claude.com/claude-code)
- New scrollspy article page in all three languages, with guide-style
warning callout, sourced link list + last-checked line, and standard
author + newsletter blocks
- Blog listing featured card now links to the article and shows the hero
photo + read-time instead of the "coming soon" placeholder
- Add hero image and cropped MSOS emblem avatar; add .blog-read-time and
.blog-feat-thumb--image styles
MK/SI translations are AI-produced and need a native-speaker proofread.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SEO (all 201 pages, en/mk/si):
- Inject canonical, hreflang (en/mk/sl + x-default), Open Graph, Twitter
cards and Organization JSON-LD via idempotent SEO:START/END block
- Generate multilingual sitemap.xml (xhtml:link alternates) + robots.txt
- Curated meta descriptions for lead-less pages (home, become-a-member,
faq, news hub, my-route); every page now has a description
- Absolute URLs target final domain msosorg.com, not the temp host
- Add reusable tools/seo_inject.py (+ README)
Content fixes:
- Translate about-us and timeline-and-milestones into MK + SI, wire up
their pages, and repair the previously-dead "Who We Are" nav links
across all mk/si pages
- Remove duplicate en/projects/makedonska-studentska-vecer-vo-ljubljana
(unreferenced; already covered by macedonian-student-night-in-ljubljana)
Locale correctness:
- Normalise Slovene pages to <html lang="sl"> (correct ISO 639-1)
- Map sl->si in main.js so the language-switcher highlight and newsletter
i18n keep working on Slovene pages (data-lang="si" still maps to /si/)
MK/SI translations and descriptions are AI-drafted; flag for native review.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add branded 1200x630 og-default.jpg; article pages use their hero as
og:image, others use the default
- Wire the existing (previously unlinked) favicon set into every page
- Add branded 404.html with root-absolute paths + noindex
- Emit Article + localized BreadcrumbList JSON-LD on all article pages
- Convert 74 heavy served photos to WebP (28MB -> 8.5MB, -70%), rewrite
references, add loading=lazy/decoding=async to below-fold images and
fetchpriority=high to heroes (protect LCP)
- Stop tracking images/original/ (458MB of unused source masters; kept on
disk, gitignored) and ignore .playwright-mcp/
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Appends static-site production defaults below the existing root->/en/
redirect: ErrorDocument 404 /404.html, gzip compression, browser caching
(short for CSS/JS since unhashed, longer for images/fonts), correct WebP/
SVG/manifest MIME types, -Indexes, and X-Content-Type-Options. All guarded
by <IfModule> so a missing module cannot 500; ignored by nginx.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add datePublished/dateModified to Article JSON-LD on the 11 dated
articles (curated once from EN, applied to all languages)
- Replace og-default.jpg with the official brand OG image (1200x630)
- Add docs/launch-seo-checklist.md (go-live steps: redirects, Search
Console, analytics, rich-result validation, monitoring)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- gtag.js injected on all 201 pages via tools/seo_inject.py + on 404.html
- Consent Mode v2 defaults all storage to 'denied' (EEA-safe: tag loads,
no tracking cookies until a consent banner grants analytics_storage)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- consent.js: self-contained, non-blocking bottom banner in EN/MK/SI,
remembers the choice in localStorage, links to the per-language cookie
policy. Accept -> gtag consent 'update' granted; Decline stays denied.
- Head GA snippet restores a returning visitor's prior "granted" choice
before the first hit; loads /consent.js on every page.
- Re-openable via window.msosOpenConsent() for a "manage cookies" link.
Verified in-browser: shows for new visitors, Accept grants + remembers,
reload keeps consent without re-prompting, Slovene text + /si/ policy link.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a per-language "Manage cookies" link to the footer legal bar on all
201 pages, wired to window.msosOpenConsent() so visitors can change or
withdraw their choice at any time (GDPR requirement). Verified: decline ->
re-open via link -> accept flips analytics consent to granted.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Adds the new blog post and a complete SEO + analytics foundation across all 201 pages (EN/MK/SI), plus content fixes. All changes verified in-browser.
What's included
Content
about-usandtimeline-and-milestonesinto MK + SI; repaired the previously-dead "Who We Are" nav links across all mk/si pagesTechnical SEO (all 201 pages)
sitemap.xml,robots.txt404.html, brand OG imagemsosorg.comtools/seo_inject.pyPerformance
loading="lazy"on below-fold images,fetchpriority="high"on heroes.htaccess: gzip, caching, MIME types,ErrorDocument 404images/original/(458MB unused masters; gitignored)Analytics & GDPR
consent.js) that remembers the choiceNotes / follow-ups
docs/launch-seo-checklist.md(Search Console, domain-migration redirect, www-vs-bare decision) - to be done once live onmsosorg.comGenerated with Claude Code