Skip to content
Development

An issue whose scope had already shipped, and a 404 that wasn't really about Portuguese

By Victor Da Luz
astrocloudflarei18ndev-logsite

I picked up an issue and the actual work turned out to be verifying it was already done, then discovering the one real remaining item was a completely different problem than the ticket described.

The scope was “phase 2 of full-site pt-BR localization”: extend Portuguese to the Games section, Music section, GitHub widget, and the 404 page, following a phase 1 that had shipped Portuguese for the homepage, /privacy, and the Deep Cut Atlas pages. Reasonable-sounding. I set it in progress and went to map out exactly what needed translating.

The map came back nearly empty

Games, Music, and the GitHub widget all read their copy from a shared Record<UiLocale, UiStrings> type in ui.ts, the same object every other translated string lives in. Once phase 1 added the pt column to that type, TypeScript required every existing key to carry a pt value, including the ones under games, music, and github. Those sections aren’t separate translation surfaces at all. They’re homepage sections, and the homepage was explicitly in phase 1’s shipped scope.

Nobody had to touch those three components a second time. I didn’t take that conclusion on faith either: I grepped the actual built dist/client/pt/index.html for seven specific Portuguese strings from those namespaces and found all seven rendering correctly. Confirmed, not assumed.

The remaining item was wearing a costume

That left the 404 page. And here the ticket’s framing broke. I checked whether /es/some-nonexistent-page was also English-only, expecting Spanish to already work since it’s the older locale. It wasn’t. Spanish 404s were just as broken as Portuguese ones. This was never a Portuguese gap. It was a gap in the whole site’s error-page handling that happened to also apply to Portuguese.

So why hadn’t anyone noticed a broken 404 in either language for months? Because the fix isn’t a copy problem, it’s a routing problem, and I had to disprove three plausible-sounding fixes before finding that out.

First I added a proper src/pages/es/404.astro, structured the same way every other localized page on this site is. Astro built it fine, to dist/client/es/404/index.html. Completely ignored at request time; the English root 404 still served. I wondered whether the directory-style output was the problem, so I hand-wrote a literal dist/client/es/404.html, bypassing Astro’s build entirely. Still ignored. Then I found a forum post claiming an explicit not_found_handling: "404-page" setting activates a nearest-file lookup for nested 404s, so I set that too, literal file still in place. Also ignored.

Four tests, one consistent answer: Cloudflare’s Workers Assets layer serves the single top-level 404.html for any unmatched path and never even invokes the Worker to check for something more specific. There’s no directory-tree fallback the way some static hosts do it.

Where I stopped

The actual fix means turning on run_worker_first, which routes every request on the site through the Worker instead of letting Cloudflare’s edge serve static assets directly. That’s not a decision to make inside a “translate some copy” ticket. I split it into its own issue with all four tests documented, and wrote a knowledge-base note, because this isn’t specific to this site: any of the four Astro sites on the same Cloudflare adapter would hit the identical wall the moment they wanted a 404 page that varies by anything.

One of them, vdaluz.com, already runs with run_worker_first on for unrelated reasons, so it’s probably exempt. Worth remembering before assuming a finding from one site travels cleanly to a sibling with a different config.

Lesson

An issue’s title can describe work that’s already finished, and its remaining item can be wearing a costume. “Translate the 404 page” and “decide whether to change how every request on the site gets routed” are not the same kind of ticket, even when they arrive in the same sentence.

Related reading