Ver contenido
Guía Técnica Completa de Declaración de Idioma: BCP 47, WCAG y SEO Internacional
Introducción
Si ya conoces los fundamentos de la declaración de idioma desde nuestra guía introductoria, esta guía técnica avanzada te equipará con conocimientos profundos sobre BCP 47, cumplimiento WCAG completo, y estrategias de implementación para sitios multilingües complejos.
La declaración de idioma correcta no es solo una etiqueta HTML—es la base de la accesibilidad internacional, el SEO multilingüe efectivo, y la experiencia de usuario para audiencias globales.
Anatomía de BCP 47: El Estándar Detrás de lang
¿Qué es BCP 47?
BCP 47 (Best Current Practice 47) es el estándar IETF que define la estructura de etiquetas de idioma¹. Es el formato que usa el atributo lang de HTML y es mucho más que códigos de dos letras.
Estructura Completa de una Etiqueta BCP 47
language-extlang-script-region-variant-extension-privateuse
| Componente | Ejemplo | Descripción |
|---|---|---|
| language | es |
Código ISO 639-1 (obligatorio) |
| extlang | cmn (mandarín) |
Sub-idioma (raro) |
| script | Latn, Hans |
Sistema de escritura |
| region | ES, MX, 419 |
País o región |
| variant | valencia |
Variante dialectal |
| extension | u-nu-thai |
Extensiones Unicode |
| privateuse | x-custom |
Uso privado |
Ejemplos Prácticos de BCP 47
<!-- Español genérico -->
<html lang="es">
<!-- Español de España -->
<html lang="es-ES">
<!-- Español de México -->
<html lang="es-MX">
<!-- Español de América Latina (código regional 419) -->
<html lang="es-419">
<!-- Chino simplificado (Mainland China) -->
<html lang="zh-Hans-CN">
<!-- Chino tradicional (Taiwan) -->
<html lang="zh-Hant-TW">
<!-- Portugués de Brasil -->
<html lang="pt-BR">
<!-- Serbio en escritura cirílica -->
<html lang="sr-Cyrl">
<!-- Serbio en escritura latina -->
<html lang="sr-Latn">
<!-- Azerbaiyano en escritura árabe -->
<html lang="az-Arab">
<!-- Inglés con extensión Unicode para números Thai -->
<html lang="en-u-nu-thai">
Cuándo Usar Cada Nivel de Especificidad
Solo Idioma (es, en, fr)
Usar cuando:
- El contenido es comprensible para todos los hablantes del idioma
- No hay diferencias regionales significativas
- Quieres máxima compatibilidad
<!-- Artículo técnico sobre programación - universal -->
<html lang="en">
Idioma + Región (es-ES, en-US, pt-BR)
Usar cuando:
- El contenido tiene vocabulario específico regional
- Diferencias ortográficas importantes (color vs colour)
- Targeting geográfico para SEO
- Contenido legal o regulatorio específico de un país
<!-- Tienda online con precios en euros -->
<html lang="es-ES">
<!-- Documentación legal para Estados Unidos -->
<html lang="en-US">
Idioma + Script (zh-Hans, sr-Cyrl)
Usar cuando:
- El idioma usa múltiples sistemas de escritura
- Quieres especificar la escritura sin vincular a una región
<!-- Chino simplificado (sin especificar país) -->
<html lang="zh-Hans">
Cumplimiento WCAG 2.2: Requisitos Completos
Criterio 3.1.1: Idioma de la Página (Nivel A)²
Requisito: El idioma humano predeterminado de cada página web puede ser determinado programáticamente.
Técnicas suficientes:
<!-- H57: Usar el atributo lang en el elemento html -->
<!DOCTYPE html>
<html lang="es">
<head>
<title>Mi Sitio Web</title>
</head>
<body>
<!-- Todo el contenido en español -->
</body>
</html>
Errores comunes que causan incumplimiento:
- Ausencia total del atributo lang:
<!-- ❌ FALLA WCAG 3.1.1 -->
<html>
- Código de idioma inválido:
<!-- ❌ FALLA WCAG 3.1.1 - "spanish" no es un código válido -->
<html lang="spanish">
- Idioma incorrecto para el contenido:
<!-- ❌ FALLA WCAG 3.1.1 - Contenido en español, declarado en inglés -->
<html lang="en">
<body>
<h1>Bienvenido a nuestro sitio</h1>
</body>
</html>
Criterio 3.1.2: Idioma de las Partes (Nivel AA)³
Requisito: El idioma humano de cada pasaje o frase del contenido puede ser determinado programáticamente, excepto para nombres propios, términos técnicos, palabras de idioma indeterminado, y palabras/frases que son parte del dialecto del texto circundante.
Técnicas suficientes:
<html lang="es">
<body>
<p>Este artículo es sobre desarrollo web.</p>
<!-- Cita en inglés - REQUIERE lang -->
<blockquote lang="en">
<p>"The best code is no code at all."</p>
<cite>— Jeff Atwood</cite>
</blockquote>
<p>Como dice la cita anterior, la simplicidad es clave.</p>
<!-- Término técnico en inglés - NO requiere lang (término técnico) -->
<p>Usamos <code>localStorage</code> para almacenar datos.</p>
<!-- Nombre propio - NO requiere lang -->
<p>La empresa Google fue fundada en 1998.</p>
<!-- Palabra extranjera adoptada al español - NO requiere lang -->
<p>El software incluye muchas features nuevas.</p>
</body>
</html>
Cuándo SÍ declarar idioma en secciones:
| Contenido | ¿Requiere lang? | Razón |
|---|---|---|
| Citas textuales | ✅ Sí | Contenido significativo en otro idioma |
| Poemas/letras | ✅ Sí | Contenido creativo en idioma original |
| Testimonios | ✅ Sí | Voz del usuario en su idioma |
| Código fuente | ⚠️ Opcional | Generalmente lang="en" |
| Términos técnicos | ❌ No | Excepción explícita en WCAG |
| Nombres propios | ❌ No | Excepción explícita en WCAG |
| Extranjerismos adoptados | ❌ No | Parte del dialecto local |
Impacto en Tecnologías de Asistencia
Lectores de pantalla y declaración de idioma:
<!-- Sin lang: NVDA/JAWS pronuncian "BIEN-veh-NEE-doh" con fonética inglesa -->
<html>
<body><h1>Bienvenido</h1></body>
</html>
<!-- Con lang="es": Pronunciación correcta en español -->
<html lang="es">
<body><h1>Bienvenido</h1></body>
</html>
Comportamiento de lectores de pantalla populares:
| Lector | Sin lang | Con lang incorrecto | Con lang correcto |
|---|---|---|---|
| NVDA | Usa idioma del sistema | Pronunciación incorrecta | ✅ Correcto |
| JAWS | Usa idioma por defecto | Cambio de voz incorrecto | ✅ Correcto |
| VoiceOver | Inferencia automática | Puede cambiar de voz | ✅ Correcto |
| TalkBack | Usa idioma del dispositivo | Pronunciación forzada | ✅ Correcto |
SEO Internacional: hreflang y Declaración de Idioma
Relación entre lang y hreflang
El atributo lang y las etiquetas hreflang trabajan juntos pero tienen propósitos diferentes⁴:
| Atributo | Propósito | Audiencia |
|---|---|---|
lang |
Declarar idioma del contenido | Navegadores, lectores de pantalla |
hreflang |
Indicar versiones alternativas | Motores de búsqueda |
Implementación correcta:
<!-- Versión en español -->
<!DOCTYPE html>
<html lang="es">
<head>
<title>Mi Sitio Web</title>
<link rel="canonical" href="https://ejemplo.com/es/">
<!-- hreflang para SEO internacional -->
<link rel="alternate" hreflang="es" href="https://ejemplo.com/es/">
<link rel="alternate" hreflang="en" href="https://ejemplo.com/en/">
<link rel="alternate" hreflang="pt-BR" href="https://ejemplo.com/pt-br/">
<link rel="alternate" hreflang="x-default" href="https://ejemplo.com/en/">
</head>
<body>
<h1>Bienvenido</h1>
</body>
</html>
Estrategias para Sitios Multilingües
Estructura de URLs
# Por subdirectorio (recomendado)
ejemplo.com/es/ → lang="es"
ejemplo.com/en/ → lang="en"
ejemplo.com/pt-br/ → lang="pt-BR"
# Por subdominio
es.ejemplo.com/ → lang="es"
en.ejemplo.com/ → lang="en"
# Por dominio de país
ejemplo.es/ → lang="es"
ejemplo.com/ → lang="en"
ejemplo.com.br/ → lang="pt-BR"
Implementación en Frameworks Modernos
Vue 3 con Vue Router:
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: '/:lang(es|en|pt-br)',
children: [
{ path: '', component: Home },
{ path: 'about', component: About }
]
}
]
// composables/useLanguage.ts
import { useHead } from '@vueuse/head'
import { useRoute } from 'vue-router'
import { computed } from 'vue'
export function useLanguage() {
const route = useRoute()
const currentLang = computed(() => {
const lang = route.params.lang as string
const langMap: Record<string, string> = {
'es': 'es',
'en': 'en',
'pt-br': 'pt-BR'
}
return langMap[lang] || 'es'
})
useHead({
htmlAttrs: {
lang: currentLang
}
})
return { currentLang }
}
Next.js con i18n:
// next.config.js
module.exports = {
i18n: {
locales: ['es', 'en', 'pt-BR'],
defaultLocale: 'es',
localeDetection: true
}
}
// pages/_document.js
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
return (
<Html> {/* Next.js inyecta lang automáticamente */}
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
Nuxt 3 con @nuxtjs/i18n:
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
locales: [
{ code: 'es', iso: 'es-ES', name: 'Español' },
{ code: 'en', iso: 'en-US', name: 'English' },
{ code: 'pt-br', iso: 'pt-BR', name: 'Português' }
],
defaultLocale: 'es',
strategy: 'prefix'
}
})
// El módulo maneja lang automáticamente
Content-Language vs lang: Diferencias Críticas
HTTP Header Content-Language
HTTP/1.1 200 OK
Content-Language: es
Content-Type: text/html; charset=UTF-8
HTML lang Attribute
<html lang="es">
Comparación Detallada
| Aspecto | Content-Language HTTP | HTML lang |
|---|---|---|
| Propósito | Audiencia objetivo del recurso | Idioma del contenido |
| Lectura | Antes de parsear HTML | Al parsear HTML |
| Accesibilidad | ❌ No usado | ✅ Usado por lectores de pantalla |
| SEO | Señal débil | Señal más fuerte |
| Granularidad | Solo a nivel de documento | Elemento por elemento |
| Recomendación | Opcional | Obligatorio (WCAG Nivel A) |
Recomendación: Siempre usa lang en HTML. El header Content-Language es opcional y menos útil.
Casos Especiales y Soluciones
Contenido Mixto
<html lang="es">
<body>
<article>
<h1>Reseña: "The Pragmatic Programmer"</h1>
<p>Este libro clásico de programación incluye consejos valiosos.</p>
<!-- Cita del libro en inglés -->
<blockquote lang="en">
<p>"Care about your craft. Why spend your life developing software unless you care about doing it well?"</p>
</blockquote>
<p>Como vemos, los autores enfatizan la importancia de la calidad.</p>
</article>
</body>
</html>
Idiomas RTL (Derecha a Izquierda)
<!-- Árabe -->
<html lang="ar" dir="rtl">
<!-- Hebreo -->
<html lang="he" dir="rtl">
<!-- Persa/Farsi -->
<html lang="fa" dir="rtl">
Secciones RTL en documento LTR:
<html lang="en">
<body>
<p>This article discusses Middle Eastern cuisine.</p>
<blockquote lang="ar" dir="rtl">
<p>الطعام العربي لذيذ جدا</p>
</blockquote>
</body>
</html>
Idiomas Sin Código ISO 639-1
Algunos idiomas solo tienen códigos ISO 639-2 (3 letras) o ISO 639-3:
<!-- Náhuatl (azteca) - Solo ISO 639-2/3 -->
<html lang="nah">
<!-- Mapudungun (mapuche) - Solo ISO 639-3 -->
<span lang="arn">Mari mari</span>
<!-- Lenguas de señas -->
<video lang="ase"> <!-- American Sign Language -->
Verificación y Testing
Herramientas de Validación
- W3C Validator: Verifica sintaxis HTML incluyendo
lang - axe DevTools: Auditoría de accesibilidad WCAG
- WAVE: Detecta errores de declaración de idioma
- UXR SEO Analyzer: Verificación específica de lang y SEO
Checklist de Verificación
Nivel A (Obligatorio)
- [ ]
<html lang="xx">presente en todas las páginas - [ ] Código de idioma válido según BCP 47
- [ ] Idioma declarado coincide con contenido principal
Nivel AA (Recomendado)
- [ ] Secciones en otros idiomas tienen
langespecífico - [ ] Citas textuales tienen idioma declarado
- [ ] Cambios de idioma significativos marcados
SEO Internacional
- [ ] hreflang implementado para todas las versiones
- [ ] x-default definido para fallback
- [ ] Consistencia entre lang y hreflang
- [ ] URLs canónicas por idioma
Cómo Verificarlo con UXR SEO Analyzer
Verifica tu configuración de idioma con nuestra extensión:
- Instala la extensión UXR SEO Analyzer
- Navega a tu sitio web
- Abre la extensión → pestaña “Basic SEO”
- Revisa “Language Declaration”
La extensión detecta:
- ✅ Presencia del atributo lang
- ✅ Validez del código BCP 47
- ⚠️ Inconsistencias entre idioma declarado y contenido
- ⚠️ Secciones sin declaración de idioma
- ❌ Códigos inválidos o mal formados
Próximos Pasos
Continúa mejorando tu implementación multilingüe:
Artículos relacionados:
- Declaración de Idioma: Fundamentos
- Hreflang: Implementación Completa
- Meta Robots: Control de Indexación
- SEO Internacional: Estrategias Avanzadas
Referencias
Este artículo fue creado utilizando fuentes autorizadas oficiales:
[1] W3C: Language tags in HTML and XML https://www.w3.org/International/articles/language-tags/ Especificación W3C completa sobre etiquetas de idioma BCP 47, incluyendo estructura, sintaxis, y casos de uso. Referencia autoritativa para la construcción correcta de códigos de idioma.
[2] WCAG 2.2: Success Criterion 3.1.1 Language of Page https://www.w3.org/WAI/WCAG22/Understanding/language-of-page.html Criterio de conformidad WCAG Nivel A que requiere declaración programática del idioma de la página. Incluye técnicas suficientes y errores comunes.
[3] WCAG 2.2: Success Criterion 3.1.2 Language of Parts https://www.w3.org/WAI/WCAG22/Understanding/language-of-parts.html Criterio de conformidad WCAG Nivel AA para declaración de idioma en secciones específicas. Define excepciones para términos técnicos y nombres propios.
[4] Google Search Central: Tell Google about localized versions https://developers.google.com/search/docs/specialty/international/localized-versions Documentación oficial de Google sobre implementación de hreflang y señales de idioma para SEO internacional.
[5] IANA Language Subtag Registry https://www.iana.org/assignments/language-subtag-registry/ Registro oficial de IANA con todos los códigos de idioma, región, script y variantes válidos para uso en etiquetas BCP 47.
Cobertura de fuentes: ALTA - Fuentes W3C, WCAG, Google Search Central e IANA proporcionan cobertura autoritativa completa.
Recursos Adicionales
Nota: Este artículo es parte de nuestra serie avanzada sobre SEO técnico e internacionalización. Explora todos los artículos en el Hub de SEO Básico.
Autor: Equipo UXR Chile Última actualización: Diciembre 2025 Tiempo de lectura: 14 minutos