**TL;DR.** Hreflang informa aos motores de busca qual variante de localidade servir a cada usuário. Acertar quatro coisas: (1) clusters recíprocos completos com auto-referências, (2) códigos de idioma ISO corretos, (3) fallback x-default, (4) filtragem por entidade para que você não anuncie traduções inexistentes. Qualquer outra coisa é detalhe de implementação.

## O que hreflang faz

Hreflang é um atributo HTML (e anotação equivalente de sitemap) que sinaliza ao Google qual idioma e região uma página visa. Hreflang implementado corretamente:

- Serve usuários espanhóis sua URL em espanhol, não sua URL em inglês.
- Impede que sua URL em francês supere sua URL em alemão na Alemanha.
- Consolida a equidade de links entre variantes de localidade em vez de tratá-las como conteúdo duplicado.

Hreflang não aumenta classificações. Ele controla qual variante de localidade classifica onde.

## Passo 1: Decida onde emitir hreflang

Três opções:

| Método                | Prós                                         | Contras                                      |
| --------------------- | -------------------------------------------- | -------------------------------------------- |
| Cabeçalho HTML        | Fácil de depurar; uma fonte por página      | Adiciona bytes a cada resposta HTML          |
| Cabeçalho HTTP `Link` | Funciona para recursos não-HTML (PDFs, etc.)| Difícil de depurar; raramente necessário     |
| Sitemap XML           | Mais compacto para catálogos enormes        | Menos visível para humanos; precisa de disciplina de sitemap |

O padrão de 2026 para a maioria dos sites de e-commerce é **cabeçalho HTML**. Mude para sitemap apenas acima de 50.000 URLs.

## Passo 2: Emitir um cluster completo

Para cada URL traduzida, emita hreflang para si mesma e para cada outra variante.

Um cluster de 4 localidades (en, de, fr, es) para um produto:

```html
<link rel="alternate" hreflang="en" href="https://example.com/en/products/leather-bag" />
<link rel="alternate" hreflang="de" href="https://example.com/de/products/leather-bag" />
<link rel="alternate" hreflang="fr" href="https://example.com/fr/products/leather-bag" />
<link rel="alternate" hreflang="es" href="https://example.com/es/products/leather-bag" />
<link rel="alternate" hreflang="x-default" href="https://example.com/en/products/leather-bag" />
```

Este cluster aparece no cabeçalho de **cada** variante de localidade deste produto. A URL em alemão emite o mesmo cluster, a URL em francês emite o mesmo cluster, etc.

O cluster deve ser recíproco — A aponta para B, B aponta para A. Clusters não recíprocos são ignorados silenciosamente pelo Google.

## Passo 3: x-default

`x-default` é o fallback para usuários cujo idioma do navegador não corresponde a nenhuma de suas variantes. Normalmente sua URL em inglês (ou URL de localidade padrão).

```html
<link rel="alternate" hreflang="x-default" href="https://example.com/en/products/leather-bag" />
```

A mesma URL pode ser tanto `hreflang="en"` quanto `hreflang="x-default"`. Apenas uma URL no cluster recebe `x-default`.

## Passo 4: Filtrar para entidades realmente traduzidas

O maior erro prático: emitir um cluster de 9 localidades em um produto que só está traduzido para 3 localidades. As URLs anunciadas retornam 404; o Google vê o cluster quebrado e pode ignorar o hreflang de todo o site.

A correção: `availableLocales` por entidade.

```ts
// Pseudocódigo
interface ProductForSeo {
  slug: string;
  availableLocales: string[];  // e.g. ["en", "de", "fr"]
}

interface StoreForSeo {
  supportedLocales: string[];  // e.g. ["en", "de", "fr", "es", "it"]
  defaultLocale: string;
}

function buildHreflangCluster(product: ProductForSeo, store: StoreForSeo) {
  const effective = product.availableLocales.filter((l) =>
    store.supportedLocales.includes(l)
  );
  return effective.map((locale) => ({
    hreflang: locale,
    href: `https://example.com/${locale}/products/${product.slug}`,
  }));
}
```

O `src/lib/seo/storefront.ts` da Ordiko implementa essa interseção exata.

## Passo 5: Códigos de idioma corretos

Use códigos de idioma **ISO 639-1**:

| Idioma                  | Código     |
| ----------------------- | ---------- |
| Inglês                  | `en`      |
| Espanhol                | `es`      |
| Francês                 | `fr`      |
| Alemão                  | `de`      |
| Português               | `pt`      |
| Italiano                | `it`      |
| Russo                   | `ru`      |
| Ucraniano               | `uk`      |
| Chinês (Simplificado)   | `zh-Hans` |
| Chinês (Tradicional)    | `zh-Hant` |
| Japonês                 | `ja`      |
| Coreano                 | `ko`      |
| Árabe                   | `ar`      |

Para idioma + região (quando você serve uma variante de localidade-região):

| Variante                | Código     |
| ----------------------- | ---------- |
| Inglês dos EUA         | `en-US`    |
| Inglês do Reino Unido   | `en-GB`    |
| Inglês Canadense       | `en-CA`    |
| Espanhol do México     | `es-MX`    |
| Espanhol da Espanha    | `es-ES`    |
| Francês da França      | `fr-FR`    |
| Francês Canadense      | `fr-CA`    |
| Português do Brasil     | `pt-BR`    |
| Português de Portugal   | `pt-PT`    |

Não use:

- `en-EN` (inválido)
- `gb` (use `en-GB`)
- `cn` (use `zh-Hans`)
- `kr` (use `ko`)

## Passo 6: Validar

Três verificações:

1. **Auto-referência**: cada URL deve incluir a si mesma em seu próprio cluster.
2. **Reciprocidade**: cada variante no cluster deve incluir cada outra variante.
3. **Acessibilidade**: cada URL no cluster deve retornar 200.

Ferramentas:

| Ferramenta                        | O que verifica                              |
| ---------------------------------- | ------------------------------------------- |
| Google Search Console              | Erros hreflang do mundo real ao longo do tempo |
| [hreflang.org/validator](https://hreflang.org) | Correção do cluster                       |
| Sitebulb / Screaming Frog         | Reciprocidade e auto-referência            |
| Ahrefs / Semrush                  | Relatórios hreflang na auditoria do site   |
| `curl` manual                     | Acessibilidade por URL                      |

Padrão de teste Vitest para CI:

```ts
import { describe, it, expect } from 'vitest';

describe('hreflang cluster', () => {
  it('cada URL de variante retorna 200', async () => {
    const cluster = [
      'https://example.com/en/products/x',
      'https://example.com/de/products/x',
      'https://example.com/fr/products/x',
    ];
    for (const url of cluster) {
      const res = await fetch(url);
      expect(res.status).toBe(200);
    }
  });

  it('cada variante emite hreflang auto-referente', async () => {
    for (const url of cluster) {
      const html = await fetch(url).then((r) => r.text());
      expect(html).toContain(`hreflang="${getLocale(url)}" href="${url}"`);
    }
  });
});
```

## Casos especiais

**Aplicativos de página única**: emita hreflang no lado do servidor no cabeçalho do documento. Não confie na injeção do lado do cliente — o rastreador do Google pode não executar seu JS.

**ccTLDs**: hreflang ainda se aplica. `example.de` pode especificar `hreflang="de-DE"` para si mesmo e vincular a `example.com/en/...` para `en`.

**Região sem diferença de idioma**: se você serve `en-US` e `en-GB` com conteúdo idêntico, hreflang os diferencia. Não compartilhe a URL — dê a cada uma sua própria URL, mesmo que o conteúdo seja idêntico.

## Armadilhas comuns

| Erro                                   | Efeito                                           |
| -------------------------------------- | ------------------------------------------------ |
| Cluster não recíproco                  | Google ignora completamente o hreflang          |
| URL de variante retorna 404            | Google ignora a URL; pode descer o cluster      |
| Código de idioma errado                 | Variante tratada como não direcionada           |
| Múltiplas URLs x-default                | Uma é ignorada arbitrariamente                   |
| Hreflang apenas na URL canônica       | Subpáginas não têm sinal hreflang                |
| Misturando URLs absolutas e relativas   | Use sempre URLs absolutas                        |
| Domínio diferente por localidade sem hreflang consistente | Cluster quebra                       |

## Como a Ordiko emite hreflang

`src/lib/seo/storefront.ts` calcula `alternates.languages` para cada objeto de metadados de página do Next.js. A função recebe:

- `store.supportedLocales`
- `entity.availableLocales` (opcional, padrão para store.supportedLocales)
- `store.defaultLocale` (usado para x-default)

E emite o cluster de interseção no cabeçalho HTML. Auto-referência, reciprocidade e x-default são garantidos pela implementação. A filtragem por entidade é opt-in através do campo `availableLocales` no carregador de entidades.

## FAQ

**Cabeçalho HTML ou sitemap — qual é melhor?**
O cabeçalho HTML é mais fácil de depurar porque você pode verificar com Visualizar Fonte. O sitemap é mais compacto para lojas com 50k+ URLs porque hreflang é emitido uma vez por par de URLs, não no cabeçalho de cada página. Escolha HTML para lojas com menos de 50k URLs; sitemap acima disso. A Ordiko emite cabeçalho HTML por padrão.

**Qual código de idioma devo usar para espanhol latino-americano vs espanhol da Espanha?**
es-MX para o México, es-AR para a Argentina, es-CO para a Colômbia, es-ES para a Espanha. A combinação idioma-região é suportada. Para uma única localidade latino-americana servindo vários países, es-419 (o código da ONU para América Latina e Caribe) é válido, mas menos amplamente suportado.

**Posso ter várias URLs x-default?**
Não. Uma x-default por cluster. Se seu negócio serve inglês globalmente, o .com (ou sua URL de localidade padrão) é o x-default. A mesma URL pode ser tanto hreflang='en' quanto hreflang='x-default'.

**Como a Ordiko lida com a correção do hreflang?**
A biblioteca de SEO da vitrine da Ordiko (src/lib/seo/storefront.ts) intersecta os `availableLocales` de cada entidade com os locais suportados da loja ao emitir `alternates.languages`. Um produto traduzido apenas para en + de anunciará apenas essas duas localidades, independentemente do conjunto mais amplo de localidades da loja.