Skip to content

fix: cache translation lookups to ensure hreflang reciprocity#17864

Merged
wackerow merged 1 commit into
devfrom
fix/hreflang-translation-cache
Mar 26, 2026
Merged

fix: cache translation lookups to ensure hreflang reciprocity#17864
wackerow merged 1 commit into
devfrom
fix/hreflang-translation-cache

Conversation

@pettinarip
Copy link
Copy Markdown
Member

@pettinarip pettinarip commented Mar 26, 2026

Summary

  • Cache getTranslatedLocales() results per slug in translationRegistry.ts
  • Cache areNamespacesTranslated() filesystem checks per locale+namespace in translationStatus.ts

Context

The March 2026 SEO audit flagged 97 pages with broken hreflang reciprocity (943 flagged rows). Google requires that if Page A declares Page B as an alternate-language version, Page B must declare Page A back.

Root cause: getTranslatedLocales() and areNamespacesTranslated() use uncached existsSync() calls. During a Next.js build, different pages render at different times. If translation files shift mid-build (e.g., concurrent Crowdin sync), different pages can see different filesystem states for the same slug — producing inconsistent locale lists that break hreflang reciprocity.

Why it's intermittent: We checked all 10 flagged route+locale combinations against the current production deploy and found all hreflang sets consistent. The issue only manifests when the filesystem changes during a build.

Fix: Module-level Map caches (same pattern as the existing cachedStaticPages in staticPages.ts) ensure that once a slug's translated locales are computed, every subsequent caller gets the same result for the lifetime of the build process.

Side benefit: Eliminates redundant existsSync() calls (25 locales × ~5,000 pages = up to 125K filesystem reads reduced to ~5K).

Test plan

  • TypeScript passes (npx tsc --noEmit)
  • Build completes successfully (pnpm build)
  • Verify hreflang tags are consistent across locales for a sample page

@github-actions github-actions Bot added the tooling 🔧 Changes related to tooling of the project label Mar 26, 2026
@netlify
Copy link
Copy Markdown

netlify Bot commented Mar 26, 2026

Deploy Preview for ethereumorg ready!

Name Link
🔨 Latest commit 8a2e96e
🔍 Latest deploy log https://app.netlify.com/projects/ethereumorg/deploys/69c51dbb6f8f2700085ae412
😎 Deploy Preview https://deploy-preview-17864.ethereum.it
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
7 paths audited
Performance: 55 (🟢 up 3 from production)
Accessibility: 94 (no change from production)
Best Practices: 100 (no change from production)
SEO: 98 (🔴 down 1 from production)
PWA: 59 (no change from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Copy Markdown
Collaborator

@myelinated-wackerow myelinated-wackerow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean, well-scoped fix. Memoization logic is correct, cache keys are sound, no callers mutate the returned arrays, and the pattern matches existing cachedStaticPages convention. Approve.

Minor observations (non-blocking):

  1. Dev server staleness — Module-level caches persist for the process lifetime, so adding/removing translation files during next dev requires a restart to take effect. Matches existing behavior of cachedStaticPages.

  2. Multi-worker builds — If Next.js spawns multiple workers during build, each gets its own cache. Two workers could theoretically see different filesystem states, though the window is much narrower than the current uncached approach.

  3. Defensive copy — Current callers are safe, but returning [...cached] instead of the reference directly would guard against future callers accidentally mutating the cache.


Reviewed by Claude (Opus 4.6)

@wackerow wackerow merged commit 8f0b989 into dev Mar 26, 2026
10 checks passed
@wackerow wackerow deleted the fix/hreflang-translation-cache branch March 26, 2026 20:53
@pettinarip pettinarip mentioned this pull request Mar 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tooling 🔧 Changes related to tooling of the project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants