From grimoire
Declares page language via <html lang> and marks inline content in other languages for screen reader TTS accuracy. Covers WCAG 3.1.1 and 3.1.2 requirements.
How this skill is triggered — by the user, by Claude, or both
Slash command
/grimoire:apply-page-languageThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Declare the page language on `<html lang>` and mark inline content in a different language —
Declare the page language on <html lang> and mark inline content in a different language —
so screen readers use the correct pronunciation, TTS voice, and hyphenation rules.
Adopted by: WCAG 2.1 SC 3.1.1 (Level A, required universally) and SC 3.1.2 (Level AA, required
by Section 508 US, EU EN 301 549, UK PSBAR 2018). The HTML Living Standard and every major framework
(Next.js, Nuxt, SvelteKit, Angular) provide built-in mechanisms for setting lang as a baseline
HTML requirement. Google Lighthouse, axe-core, and WAVE all flag missing lang as a critical error.
Impact: Screen readers switch TTS voice engines based on the lang attribute — reading French
text with an English voice produces unintelligible output. NVDA, JAWS, and VoiceOver all implement
automatic language switching per the lang attribute. WebAIM's 2024 screen reader survey found 68%
of screen reader users rely on automatic language switching. Without lang, browsers also fail to
apply correct spell-check, hyphenation, and quotation mark rules for language-specific characters.
Why best: The HTTP Content-Language header and <meta http-equiv="Content-Language"> cannot
substitute — screen readers do not use these for TTS voice selection. The lang attribute on HTML
elements is the only mechanism supported across all screen readers and browsers for per-element
language switching.
Sources: W3C WCAG 2.1 SC 3.1.1, 3.1.2 (2018); IETF BCP 47; MDN HTML lang; WebAIM Screen Reader Survey 2024
lang on every <html> element (3.1.1)Every HTML page must have a valid BCP 47 language tag on the root element:
<!-- Wrong — no lang, or invalid tag -->
<html>
<html lang="">
<html lang="english"> <!-- not a BCP 47 tag -->
<!-- Right — BCP 47 primary language subtag -->
<html lang="en"> <!-- English (any region) -->
<html lang="en-US"> <!-- English, United States — use when dialect matters -->
<html lang="fr"> <!-- French -->
<html lang="de"> <!-- German -->
<html lang="zh-Hans"> <!-- Chinese, Simplified -->
<html lang="ar"> <!-- Arabic -->
Use just the two-letter ISO 639-1 code (en, fr, de) unless a regional variant matters
for pronunciation (en-US vs en-GB, pt-BR vs pt-PT).
Any phrase, word, or passage in a language different from the page language needs a lang
attribute on its containing element:
<!-- Page language: English -->
<html lang="en">
<body>
<!-- Wrong — French phrase read with English TTS voice -->
<p>The menu offered <em>carte blanche</em>.</p>
<!-- Right — French phrase gets French TTS voice -->
<p>The menu offered <em lang="fr">carte blanche</em>.</p>
<!-- Right — foreign-language publication title -->
<li><cite lang="de">Der Spiegel</cite> — German news magazine</li>
<!-- Right — extended foreign-language block -->
<blockquote lang="ja">
<p>すべての人間は、生まれながらにして自由であり...</p>
</blockquote>
</body>
Proper nouns — people's names, place names, brand names — do not need lang. They are
pronounced consistently regardless of surrounding language.
lang on SPA locale changes (3.1.1)In SPAs where locale changes without a full page reload, update document.documentElement.lang:
// React — update when locale changes
function App() {
const { locale } = useLocale();
useEffect(() => {
document.documentElement.lang = locale; // e.g. "fr", "de", "ja"
}, [locale]);
return <RouterProvider router={router} />;
}
// Vue Router — update on every navigation
router.afterEach((to) => {
document.documentElement.setAttribute('lang', to.meta.locale ?? 'en');
});
Without this update, a user switching to French in a SPA hears English TTS voice reading French content for the entire session.
lang in framework base templates| Framework | Where to set lang |
|---|---|
| Next.js (App Router) | <html lang="en"> in app/layout.tsx |
| Next.js (Pages) | i18n.defaultLocale in next.config.js + <html lang={locale}> in _document.js |
| Nuxt | app.head.htmlAttrs.lang in nuxt.config.ts |
| SvelteKit | <html lang="en"> in src/app.html |
| Angular | <html lang="en"> in src/index.html |
| Create React App | <html lang="en"> in public/index.html |
| Vite | <html lang="en"> in index.html |
| Language | Tag | Language | Tag | |
|---|---|---|---|---|
| English | en | Japanese | ja | |
| English (US) | en-US | Korean | ko | |
| English (UK) | en-GB | Arabic | ar | |
| French | fr | Hebrew | he | |
| German | de | Russian | ru | |
| Spanish | es | Chinese (Simplified) | zh-Hans | |
| Portuguese (Brazil) | pt-BR | Chinese (Traditional) | zh-Hant |
Full registry: IANA Language Subtag Registry (iana.org/assignments/language-subtag-registry)
lang even
inside foreign-language text.const, function) are not natural language.
No lang needed on <code> blocks unless they contain natural-language strings in a
foreign language.aria-hidden="true" doesn't need lang.lang missing from <html>. Most common failure — flagged by Axe, Lighthouse, and WAVE.
Add lang="en" (or correct language) to the <html> element in your base template immediately.
Framework scaffold output lacks lang. Create React App, Vite, and many starters omit lang.
Check your index.html or base layout file before deploying.
lang="en" on a non-English page. A French website with lang="en" reads the entire page
in English TTS voice. Verify lang matches actual content, not developer preference.
lang not updated in multilingual SPAs. When a user switches locale, document.documentElement.lang
must update. Static lang="en" in the HTML template is wrong when the page renders French content.
npx claudepluginhub jeffreytse/grimoire --plugin grimoireValidates hreflang implementations, detects common mistakes (missing return tags, incorrect codes), and generates correct tags for HTML, headers, or sitemaps.
Plans multi-language/region site architecture: URL structure (subfolder vs subdomain vs ccTLD), hreflang, translation workflow, locale formatting, RTL design, and stalled rollout audits.
Provides guidelines for writing inclusive UI text: gender-neutral pronouns, ability-neutral verbs, and culture-aware phrasing. Useful for reviewing or creating user-facing copy.