Skip to content

set html lang attribute from locale at server render time#436

Merged
JeremyDev87 merged 2 commits intomasterfrom
fix/412-html-lang-i18n
Feb 16, 2026
Merged

set html lang attribute from locale at server render time#436
JeremyDev87 merged 2 commits intomasterfrom
fix/412-html-lang-i18n

Conversation

@JeremyDev87
Copy link
Owner

Summary

Closes #412

  • Convert root layout to a pass-through (return children) following the next-intl recommended pattern
  • Move <html>, <body>, fonts, ThemeProvider, Toaster, and skip-to-content link into [locale]/layout.tsx with <html lang={locale}>
  • Remove the SetDocumentLang client component (no longer needed since lang is set at server render time)
  • Update layout tests to match the new structure

Problem

<html lang="en"> was hardcoded in the root layout regardless of the active locale. Screen readers and search engines received an incorrect lang attribute from the initial server-rendered HTML. The SetDocumentLang client component only corrected this after hydration.

Solution

Adopted the next-intl recommended architecture where:

  1. Root layout is a simple pass-through that returns children directly
  2. Locale layout ([locale]/layout.tsx) owns the full document shell with <html lang={locale}>

This ensures the correct lang attribute is present in the very first byte of server-rendered HTML.

Verification

Check Result
TypeScript (tsc --noEmit) 0 errors
Unit tests (224 tests) All pass
Production build Success
SSR output en.html <html lang="en">
SSR output ko.html <html lang="ko">
SSR output es.html <html lang="es">
SSR output ja.html <html lang="ja">
SSR output zh-CN.html <html lang="zh-CN">

Test plan

  • View page source for /ko — verify <html lang="ko">
  • View page source for /en — verify <html lang="en">
  • Verify each locale's server-rendered HTML has the correct lang attribute
  • Confirm screen reader announces correct language on page load
  • Lighthouse accessibility audit shows no lang-related warnings

…er time (#412)

Move <html> and <body> tags from root layout to [locale]/layout.tsx so
the lang attribute is set correctly during server rendering. This follows
the next-intl recommended pattern where the root layout is a
pass-through and the locale layout owns the document shell.

- Convert root layout to pass-through (return children)
- Move fonts, ThemeProvider, Toaster, skip-link to locale layout
- Remove SetDocumentLang client component (no longer needed)
- Update tests for new layout structure
@vercel
Copy link

vercel bot commented Feb 16, 2026

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

Project Deployment Actions Updated (UTC)
codingbuddy-landing Ready Ready Preview, Comment Feb 16, 2026 0:41am

@JeremyDev87 JeremyDev87 self-assigned this Feb 16, 2026
@JeremyDev87 JeremyDev87 added fix landing-page Landing page project tasks labels Feb 16, 2026
@JeremyDev87 JeremyDev87 changed the title fix(landing-page): set html lang attribute from locale at server render time set html lang attribute from locale at server render time Feb 16, 2026
@JeremyDev87 JeremyDev87 merged commit 2eb846a into master Feb 16, 2026
25 checks passed
@JeremyDev87 JeremyDev87 deleted the fix/412-html-lang-i18n branch February 16, 2026 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix landing-page Landing page project tasks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[MEDIUM] Landing Page: Hardcoded html lang="en" conflicts with i18n server rendering

1 participant