Skip to content

feat(i18n): each language declares itself in the HTML, one home dictionary per language, and the creator descriptor - #149

Merged
santifer merged 12 commits into
mainfrom
i18n/root-layout-per-locale
Oct 9, 2026
Merged

santifer merged 12 commits into
mainfrom
i18n/root-layout-per-locale

Conversation

@santifer

@santifer santifer commented Oct 9, 2026

Copy link
Copy Markdown
Member

What this changes

Three things that move dates and entity signals, shipped together so they are measured as one change.

1. Each language declares itself in the HTML. Every page used to say <html lang="en">, including the Spanish, French and German ones. Each language now has its own root layout, so /es says es, /fr says fr and /de says de. The shared chrome (providers, footer, analytics) lives in one RootShell component. English routes move under src/app/(en)/, which is a route group and does not change any URL.

2. One home dictionary per language. The four homes shared one file, so editing the French home moved the English home's last-modified date. The dictionary is now split into src/app/_home/home-{en,es,fr,de}.tsx, and each home depends only on its own file.

3. Santiago is described as the creator of career-ops. Bylines, the /about descriptions, the author answers on the home (four languages) and on /methodology, the press boilerplate, llms.txt and llms-full.txt now use the same descriptor as santifer.io and Wikidata. The paragraphs are rewritten so they do not repeat it. founderOf is removed from the Person node: it is not a schema.org property, and Organization.founder already states the relation.

What does not change

  • No URL is added or removed: 163 of 163 sitemap URLs match production.
  • /methodology keeps "Last updated 7 May 2026" and its dateModified. Only the bio wording and the role name change there.
  • The signatory bio on /manifesto and /es/manifesto is not touched, and the manifesto date guard passes.
  • The WIRED logo and its alt text on the home are not touched.

Dates that move

Seven sitemap entries: /, /es, /fr, /de, /about, /methodology, /press. Blog posts and comparison pages do not move, because their dates come from frontmatter. /about shows "Last updated 9 Oct 2026", and its ProfilePage dateModified matches.

Two things to look at before merging

  • The 404 page uses Next's experimental globalNotFound flag, needed once there is more than one root layout. Approved on 1 October.
  • The English home's share image changes URL because of the route group. The old URL answers with a 308 to the new one, and so do the wide signatory cards. Approved on 1 October.

How it was checked

A squash of this branch on top of main (a8e5620) was built and served locally:

  • Agent-layer guard: pass.
  • Schema parity: pass, 118 FAQ and glossary claims on 163 URLs.
  • No future dates: pass.
  • i18n SEO guard: pass on 163 of 163 URLs, with the <html lang> check enforced.
  • Raw <html lang> is en, es, fr, de on the four homes.
  • The author sentence renders as "Aparicio, who" with no stray space before the comma, in the visible text and in the JSON-LD.

Lines that still carry a long dash in this diff are existing copy that moved with the dictionary split. They are not new, and they are left for a separate pass so this PR moves no more text than it has to.

Merge

This touches the home, so it is merged by Santiago. Planned for Monday 12 October.

🤖 Generated with Claude Code

santifer and others added 12 commits October 1, 2026 09:40
…llow it

On /de (and /es, /fr) the ⌘K dialog searched the English index. /api/search
already keeps one Orama index per language, with that language's tokenizer:
/api/search?query=bewerbung&locale=de returns 100 German hits, the same query
without locale returns 0. But the dialog takes the locale from Fumadocs'
I18nProvider, and the shared root layout never mounted one, so it sent none
and the server fell back to English.

LocaleRootProvider reads the locale from the path, the same way
FooterLocaleLink and the AI search do, and passes it to RootProvider together
with the ten Fumadocs UI labels for es, fr and de (search placeholder, "On this
page", previous/next page...). It passes no `locales` list on purpose: with
more than one, Fumadocs layouts render their own language picker next to ours.

English is unchanged: locale=en, default labels. No date source is touched
(neither file feeds git-date or home-date), so no lastmod moves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ared home modules into _home (renames only)

Pure renames, no content change, so every moved file keeps its git history
and, with git-date's --follow --diff-filter=r, its lastmod. Edits come in the
following commits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e server HTML; one home dictionary per language

<html lang> was "en" on every page: the single root layout hardcoded it, and
a script corrected it in the browser, which crawlers that read raw HTML never
see (search-ops D1). Each locale now has its own root layout ((en)/, es/, fr/,
de/), all rendering the same RootShell (providers, footer, analytics) with
their own lang, the content-language meta on translated pages, and a static
locale for the ⌘K search. LangSync and the inline script are gone. Unmatched
URLs get global-not-found.tsx (experimental.globalNotFound), which keeps the
404 the site had: Next's message inside the English shell, noindex. Switching
language is now a full page load, the cost of separate root layouts.

The home dictionary is split: home-dict.tsx keeps the type and helpers, and
each language has its own home-<locale>.tsx. A home's lastmod now depends on
its route, the shared trunk and its own dictionary, so editing the French
home stops moving the English one.

Dates: the English routes moved into (en) in the previous commit as pure
renames, and git-date now runs git log with --follow --diff-filter=r, so a
moved page keeps its last real change as lastmod. The sitemap paths and
home-date follow the new locations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With one root layout per locale the server HTML carries the right <html lang>
on every page, so a wrong one is a regression. Agreed with search-ops when the
guard landed (#142): flip it in the same PR as the root layouts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…locale

# Conflicts:
#	src/components/locale-root-provider.tsx
#	src/components/root-shell.tsx
Moving the home under (en)/ changes the file name Next derives for its
opengraph image (same bytes, new path hash), so the old URL would 404 for
cards cached by social networks and for saved links.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…king after the move into (en)

An adversarial review of this branch reproduced three regressions:

- Every signatory's wide card moved from /manifesto/s/<user>/opengraph-image to
  ...-1xn4ck (Next hashes generated image routes inside a route group). The
  example card on /manifesto and /es/manifesto, the "Download your card: wide"
  link and every card already shared on social sites would 404. A 308 keeps
  the stable path working, and the i18n guard now fails if either old card
  URL stops ending in an image (stable-image, with its selftest sabotage).
- git-date skipped any rename commit, including R<100 ones. PRs land
  squashed, so a move and an edit share one commit and the edit never reached
  the lastmod. -M100% makes only exact renames count as moves.
- .coderabbit.yaml still pointed its homepage rules at src/app/(home)/, which
  no longer exists, so its "visual change needs the maintainer" checks went
  silent. They now cover src/app/**/(home)/ and src/app/_home/.

The outputFileTracingIncludes keys are also written as the escaped picomatch
route globs Next documents. The TTF is traced by static analysis either way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he site, and drop founderOf from the Person node

Bylines, the /about descriptions, the home and /methodology author answers, the press boilerplate, llms.txt and llms-full.txt now use the same descriptor as santifer.io and Wikidata. The author paragraphs are rewritten so they do not repeat it, in en, es, fr and de.

/about: Featured in WIRED Greece in the two descriptions, two sentences reworded, Last updated and ProfilePage dateModified set to 9 Oct 2026.
/methodology: bio FAQ wording and role-name correction only; methodology unchanged, dateModified kept.
schema: founderOf removed from the Person node. It is not a schema.org property, and Organization.founder already states the relation.

The signatory bio on the manifesto pages is not touched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
career-ops-docs Ready Ready Preview Oct 9, 2026 6:54am UTC

Request Review

@coderabbitai

coderabbitai Bot commented Oct 9, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 48 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: career-ops-hq/career-ops-docs/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 85b6f28a-756f-4ee6-99d4-75a5b2462570
📥 Commits

Reviewing files that changed from the base of the PR and between a8e5620 and 7fadc8c.

⛔ Files ignored due to path filters (2)
  • src/app/(en)/(home)/opengraph-image.jpg is excluded by !**/*.jpg, !**/*.jpg
  • src/app/(en)/manifesto/s/[username]/InstrumentSerif-Regular.ttf is excluded by !**/*.ttf
📒 Files selected for processing (56)
  • .coderabbit.yaml
  • .github/copilot-instructions.md
  • next.config.mjs
  • scripts/verify-i18n-seo.mjs
  • src/app/(en)/(home)/layout.tsx
  • src/app/(en)/(home)/opengraph-image.alt.txt
  • src/app/(en)/(home)/page.tsx
  • src/app/(en)/about/layout.tsx
  • src/app/(en)/about/page.tsx
  • src/app/(en)/blog/[slug]/page.tsx
  • src/app/(en)/blog/layout.tsx
  • src/app/(en)/blog/page.tsx
  • src/app/(en)/changelog/page.tsx
  • src/app/(en)/compare/[slug]/page.tsx
  • src/app/(en)/compare/layout.tsx
  • src/app/(en)/compare/page.tsx
  • src/app/(en)/docs/[[...slug]]/page.tsx
  • src/app/(en)/docs/layout.tsx
  • src/app/(en)/layout.tsx
  • src/app/(en)/manifesto/page.tsx
  • src/app/(en)/manifesto/s/[username]/card-square/route.tsx
  • src/app/(en)/manifesto/s/[username]/opengraph-image.tsx
  • src/app/(en)/manifesto/s/[username]/page.tsx
  • src/app/(en)/manifesto/sign-preview/route.tsx
  • src/app/(en)/methodology/layout.tsx
  • src/app/(en)/methodology/page.tsx
  • src/app/(en)/press/page.tsx
  • src/app/(en)/privacy/layout.tsx
  • src/app/(en)/privacy/page.tsx
  • src/app/(en)/subscribed/page.tsx
  • src/app/(en)/sustain/layout.tsx
  • src/app/(en)/sustain/page.tsx
  • src/app/(home)/home-dict.tsx
  • src/app/_home/home-content.tsx
  • src/app/_home/home-de.tsx
  • src/app/_home/home-dict.tsx
  • src/app/_home/home-en.tsx
  • src/app/_home/home-es.tsx
  • src/app/_home/home-fr.tsx
  • src/app/_home/page.client.tsx
  • src/app/de/(home)/page.tsx
  • src/app/de/layout.tsx
  • src/app/es/(home)/page.tsx
  • src/app/es/layout.tsx
  • src/app/fr/(home)/page.tsx
  • src/app/fr/layout.tsx
  • src/app/global-not-found.tsx
  • src/app/llms-full.txt/route.ts
  • src/app/sitemap.ts
  • src/components/lang-sync.tsx
  • src/components/locale-root-provider.tsx
  • src/components/root-shell.tsx
  • src/lib/git-date.ts
  • src/lib/home-date.ts
  • src/lib/llms-index.ts
  • src/lib/schema.ts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

This branch was successfully deployed

1 active deployment
Preview — 7fadc8c7 Deployed Oct 9, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant