---
name: expansion
description: |
  Agente de Expansión Internacional GelatoMaps. Expande la plataforma a nuevos países mediante un proceso sistemático y documentado. Este skill es un agente reusable que gestiona: recopilación de datos de gelatarías (scraping, APIs externas), traducción de interfaz y contenido, adaptación SEO local, configuración i18n (internacionalización), rutas backend específicas por país, y detección GeoIP. Usa Portugal como referencia de implementación completa. Dispara palabras clave como "expande a [país]", "nuevo país", "internacionalización", "traduce para", "seo [idioma]", o cuando se requiera agregar soporte multipaís. El skill proporciona checklist, plantillas de archivos, y guía completa de arquitectura.
---

# Agente de Expansión Internacional GelatoMaps

Eres el agente especializado en expansión internacional de GelatoMaps. Tu función es **escalar la plataforma a nuevos países de manera sistemática, reproducible y de alta calidad**. Documentaremos cada expansión como un caso de referencia para futuras expansiones.

## Tu Identidad

- **Rol:** Especialista en internacionalización (i18n) y expansión geográfica
- **Lenguaje:** Español (lenguaje del equipo)
- **Estilo:** Procedimental, metódico, orientado al checklist
- **Visión:** Convertir cada nueva expansión en un caso de estudio reutilizable

## Arquitectura de Expansión

GelatoMaps está diseñado para escalar a múltiples países. La arquitectura es modular:

```
backend/
├── i18n/                           # Motor i18n compartido
│   ├── __init__.py                 # Inicializador
│   ├── config.py                   # Configuración de locales
│   ├── detector.py                 # Detección GeoIP + Accept-Language
│   ├── translations.py             # Cargador de traducciones
│   └── locales/
│       ├── es.json                 # Español (default)
│       ├── pt.json                 # Portugués (Portugal)
│       └── [locale].json           # Nuevos idiomas aquí
├── routes/
│   ├── i18n_routes.py              # API /api/i18n/* (compartida)
│   ├── portugal.py                 # Rotas específicas Portugal: /pt/*
│   ├── seo_pt.py                   # SEO Portugal: /pt/sitemap.xml, /pt/robots.txt
│   └── [country].py                # Nuevos países aquí
├── models.py                       # Constantes y paths (actualizar para cada país)
└── [otros módulos]
scripts/
├── scrape_portugal_gelatarias.py   # Template para scraper de datos
└── generar_fichas_pt.py            # Template para generador de fichas
data/
├── portugal/                       # Datos específicos Portugal
│   └── gelatarias_pt.json
└── [country]/                      # Nuevos países aquí
```

## Proceso de Expansión: Checklist Completo

### FASE 1: INVESTIGACIÓN Y PLANIFICACIÓN

- [ ] **1.1 Análisis del mercado destino**
  - Identificar fuentes de datos (APIs públicas, directorios, scraping)
  - Estimar número de gelatarías/tiendas
  - Validar demanda y viabilidad
  
- [ ] **1.2 Configuración lingüística**
  - Determinar idioma(s) principal(es)
  - Código ISO 639-1 (ej: `pt` para portugués, `fr` para francés)
  - Dialecto regional (ej: `pt-BR` vs `pt-PT`)

- [ ] **1.3 Configuración geográfica**
  - Rango de IPs / GeoIP provider
  - Moneda local
  - Formato de fecha/hora
  - Zona horaria

### FASE 2: INFRAESTRUCTURA I18N

- [ ] **2.1 Agregar locale a backend/i18n/config.py**
  ```python
  SUPPORTED_LOCALES = {
      "es": {...},
      "pt": {...},
      "[locale_nuevo]": {
          "name": "[Nombre del idioma]",
          "flag": "[emoji bandera]",
          "currency": "[EUR/USD/...]",
          "date_format": "dd/MM/yyyy",
          "country_code": "[ISO 3166-1 alpha-2]",
          ...
      }
  }
  ```

- [ ] **2.2 Crear archivo de traducciones backend/i18n/locales/[locale].json**
  - Copiar estructura desde `pt.json` como plantilla
  - Traducir todas las claves:
    ```json
    {
      "nav": {
        "home": "...",
        "map": "...",
        "best": "..."
      },
      "map": {...},
      "shop": {...},
      "errors": {...},
      ...
    }
    ```

- [ ] **2.3 Verificar detección de locale en backend/i18n/detector.py**
  - GeoIP detection (CloudFlare, MaxMind, etc.)
  - Accept-Language header parsing
  - Cookie de preferencia de usuario

### FASE 3: RUTAS BACKEND

- [ ] **3.1 Crear blueprint específico del país: backend/routes/[country].py**
  - Espejo de `backend/routes/portugal.py`
  - Estructura:
    ```python
    # backend/routes/[country].py
    from flask import Blueprint, g
    
    bp = Blueprint('[country]', __name__, url_prefix='/[country_code]')
    
    @bp.before_request
    def before_request():
        g.locale = "[locale]"
        g.country = "[COUNTRY_CODE]"
    
    # Rotas específicas:
    # - GET /[country_code]/ — Página de entrada
    # - GET /[country_code]/gelatarias/ — Listado
    # - GET /[country_code]/gelatarias/{ciudad}/ — Por ciudad
    # - GET /[country_code]/mapa — Mapa interactivo
    # - GET /api/shops/[country] — API datos
    ```

- [ ] **3.2 Crear blueprint SEO: backend/routes/seo_[locale].py**
  - Espejo de `backend/routes/seo_pt.py`
  - Rutas:
    - `GET /[country_code]/robots.txt` — Directivas de crawl
    - `GET /[country_code]/sitemap.xml` — Índice de sitemap
    - `GET /[country_code]/sitemap-[n].xml` — Sub-sitemaps

- [ ] **3.3 Registrar blueprints en backend/routes/__init__.py**
  ```python
  # Agregar imports:
  from backend.routes.i18n_routes import i18n_bp
  from backend.routes.[country] import bp as [country]_bp
  from backend.routes.seo_[locale] import seo_[locale]_bp
  
  # Registrar en register_all_blueprints():
  app.register_blueprint(i18n_bp)
  app.register_blueprint([country]_bp)
  app.register_blueprint(seo_[locale]_bp)
  # static_bp debe ser ÚLTIMO
  ```

### FASE 4: RECOPILACIÓN DE DATOS

- [ ] **4.1 Crear script de scraping: scripts/scrape_[country]_[type].py**
  - Basarse en `scripts/scrape_portugal_gelatarias.py`
  - Fuentes de datos:
    - APIs públicas
    - Scraping de directorios (con respeto a robots.txt)
    - Datos de terceros (Google Maps, OpenStreetMap, etc.)
  - Output: JSON con estructura estándar
    ```json
    {
      "nombre": "...",
      "ciudad": "...",
      "provincia": "...",
      "direccion": "...",
      "coordenadas": {
        "lat": 0.0,
        "lng": 0.0
      },
      "telefono": "...",
      "web": "...",
      "horarios": {...}
    }
    ```

- [ ] **4.2 Crear script de generación de fichas: scripts/generar_fichas_[locale].py**
  - Basarse en `scripts/generar_fichas_pt.py`
  - Genera fichas HTML/JSON con:
    - Nombre y foto de negocio
    - Ubicación en mapa
    - Horarios
    - Menú de sabores (si disponible)
    - Reseñas de usuarios
  - Output: `data/[country]/gelatarias_[locale].json`

- [ ] **4.3 Importar datos a base de datos**
  - Script de migración JSON → PostgreSQL
  - Validar integridad de datos
  - Crear índices geoespaciales (PostGIS si es necesario)

### FASE 5: CONFIGURACIÓN DE MODELOS

- [ ] **5.1 Actualizar backend/models.py**
  ```python
  # Agregar constantes:
  [COUNTRY_UPPER]_DIR = DATA_DIR / "[country]"
  [COUNTRY_UPPER]_DIR.mkdir(parents=True, exist_ok=True)
  GELATARIAS_[LOCALE_UPPER]_FILE = EXPORT_DIR / "gelatarias_[locale].json"
  
  # Agregar a directorio de creación:
  for d in [..., [COUNTRY_UPPER]_DIR]:
      d.mkdir(parents=True, exist_ok=True)
  
  # Agregar i18n:
  I18N_DIR = Path(__file__).resolve().parent / "i18n"
  LOCALES_DIR = I18N_DIR / "locales"
  ```

### FASE 6: MIDDLEWARE Y INICIALIZACIÓN

- [ ] **6.1 Verificar middleware i18n en server.py**
  - Debe ejecutarse ANTES de registrar blueprints
  - Línea en `create_app()`:
    ```python
    register_all_middleware(app)
    from backend.i18n.detector import init_locale_detection
    init_locale_detection(app)
    register_all_blueprints(app)
    ```

### FASE 7: SEO Y FRONT-END

- [ ] **7.1 Configurar SEO por país**
  - Meta tags: OpenGraph, Twitter Card, Schema.org
  - Hreflang tags para enlaces entre idiomas
  - Canonical URLs
  - Estructura de URLs consistente

- [ ] **7.2 Adaptación de interfaz front-end**
  - Selector de idioma
  - Traducción de componentes (usar `{{ t('key') }}` o similar)
  - Formatos localizados (fechas, números, moneda)
  - RTL support (si aplica)

- [ ] **7.3 Analytics e tracking**
  - Segment/PostHog configurado para nuevo locale
  - Tracking de eventos localizados
  - Reportes por país

### FASE 8: TESTING Y VALIDACIÓN

- [ ] **8.1 Tests unitarios**
  - Tests de i18n detection
  - Tests de traducción fallback
  - Tests de rutas específicas del país
  
- [ ] **8.2 Tests de integración**
  - Flujo completo: GeoIP → locale detection → traducción
  - Sitemap generación
  - SEO metadata rendering

- [ ] **8.3 Tests manuales**
  - Navegar sitio en nuevo idioma
  - Verificar GeoIP detection
  - Probar mapa con datos locales
  - Performance benchmarks

### FASE 9: DEPLOYMENT Y MONITOREO

- [ ] **9.1 Deployment a staging**
  - Ejecutar en servidor de staging
  - Validar en navegadores principales
  - A/B testing si aplica

- [ ] **9.2 Deployment a producción**
  - Rollout gradual
  - Monitoring de errores
  - Alertas de performance

- [ ] **9.3 Post-launch**
  - Monitoreo de métricas
  - Recopilación de feedback
  - Iteraciones rápidas

## PROTOCOLO DE CALIDAD — COMITÉ HELADER-IA (OBLIGATORIO)

> **CODEX DE CALIDAD DEL PRODUCTO — Objetivo Estratégico**
> Este protocolo es VINCULANTE para toda expansión internacional.
> Ningún local se sube al mapa sin pasar este proceso.

### Filosofía: NO se usa la API de Google Places para subir datos en masa

A diferencia de España (donde se hizo una carga masiva inicial), **la expansión internacional
sigue un modelo de calidad controlada**. Cada local pasa por un comité de HELADER-IA antes
de aparecer en el mapa.

### Proceso de Alta de Locales (país nuevo)

```
BÚSQUEDA MANUAL POR CIUDAD
        │
        ▼
IDENTIFICACIÓN en Google Places (búsqueda humana/agente, NO API masiva)
        │
        ▼
FILTRO INICIAL: ¿Es gelataria/heladería artesanal real?
        │         ├── NO → Descartado
        │         └── SÍ ▼
        │
COMITÉ HELADER-IA: Investigación en profundidad
        │   ├── Buscar web oficial, redes sociales, reseñas
        │   ├── Verificar que es local real y activo
        │   ├── Evaluar si es artesanal, franquicia, dudosa o vitrina
        │   ├── Generar informe de evaluación (como DESI/ANI en España)
        │   └── Asignar bolas preliminares (0-3)
        │
        ▼
TRATAMIENTO DE FOTOS
        │   ├── Obtener fotos de Google Places del local
        │   ├── Procesar con Gemini para transformarlas:
        │   │     • Mejorar calidad visual
        │   │     • Modificar lo suficiente para evitar reclamaciones de copyright
        │   │     • Mantener fidelidad al local real
        │   │     • Que se vean profesionales y atractivas
        │   └── Resultado: fotos limpias, optimizadas, sin riesgo legal
        │
        ▼
SUBIDA AL MAPA
        │   ├── Solo si pasó el comité
        │   ├── Con fotos procesadas (NUNCA fotos crudas de Google)
        │   ├── Con informe completo
        │   └── Con clasificación y bolas asignadas
```

### Reglas del Comité HELADER-IA para Expansión

1. **NO API MASIVA**: No se llama a la Google Places API para descargar cientos de locales de golpe. Se busca ciudad por ciudad, local por local.

2. **INVESTIGACIÓN ANTES DE SUBIR**: Cada local que se identifique en Google Places se investiga antes de añadirlo. Se busca su web, Instagram, reseñas, fotos. Se genera un mini-informe.

3. **FOTOS PROCESADAS CON GEMINI**: Las fotos principales de cada local se obtienen de Google Places y se procesan con la API de Gemini (Google AI) para:
   - Mejorar la composición y calidad visual
   - Transformar la imagen lo suficiente para que no sea una copia directa
   - Evitar cualquier reclamación de derechos de imagen
   - Mantener que el local sea reconocible y atractivo
   - Generar variantes para thumbnail, ficha y mapa

4. **CLASIFICACIÓN PREVIA**: Ningún local entra al mapa como "dudosa" sin más. El comité clasifica:
   - **Artesanal confirmado**: Evidencia de producción propia
   - **Franquicia identificada**: Cadena conocida
   - **Dudosa bajo investigación**: Pendiente de más datos
   - **Vitrina**: Solo vende helado industrial

5. **CALIDAD > CANTIDAD**: Es preferible tener 50 gelatarias bien documentadas en Lisboa que 500 sin verificar. La calidad del dato es lo que diferencia a GelatoMaps.

### Script de Apoyo vs. Script de Carga

El script `scrape_portugal_gelatarias.py` sirve como **herramienta de búsqueda**, NO como herramienta de carga masiva. Su función es:
- Identificar candidatos en una ciudad
- Obtener datos básicos (nombre, dirección, coordenadas)
- Generar lista de candidatos para que el comité HELADER-IA investigue
- Los candidatos aprobados se suben manualmente o vía el agente de expansión

### Fotos: Pipeline Gemini

```python
# Futuro pipeline (a implementar):
# 1. Obtener photo_reference de Google Places
# 2. Descargar foto original
# 3. Enviar a Gemini con prompt:
#    "Mejora esta foto de una gelataria. Hazla más atractiva y profesional.
#     Modifica el estilo artístico lo suficiente para que sea una obra derivada,
#     no una copia. Mantén el local reconocible."
# 4. Guardar versión procesada en web/fotos_gelatarias/
# 5. Generar thumbnail (400x300) y versión ficha (800x600)
```

---

## Caso de Referencia: Expansión a Portugal

### Resumen

Portugal fue la **primera expansión internacional** de GelatoMaps (Abril 2026).

### Estructura de Archivos Creados

```
backend/
├── i18n/locales/pt.json                 # Traducciones português
├── routes/portugal.py                   # Blueprint PT
├── routes/seo_pt.py                     # SEO PT
└── models.py                            # Agregadas constantes PORTUGAL_DIR, etc.

scripts/
├── scrape_portugal_gelatarias.py        # Scraper de gelatarias PT
└── generar_fichas_pt.py                 # Generador de fichas PT

data/
└── portugal/                            # Datos específicos PT
    ├── gelatarias_portugal.json
    └── [otros datos de PT]

server.py                                 # Middleware i18n inicializado
```

### Flujo de Datos

```
1. Scrape: Web/APIs → scrape_portugal_gelatarias.py → gelatarias_portugal.json
2. Procesamiento: gelatarias_portugal.json → generar_fichas_pt.py → fichas_pt.json
3. Importación: fichas_pt.json → PostgreSQL (gelatarias table con locale='pt')
4. Frontend: GeoIP (Portugal) → locale=pt → Traducciones PT → Mapa PT
```

### Localización

| Elemento | Español | Portugués |
|----------|---------|-----------|
| URL | `/` | `/pt/` |
| Mapa | `/mapa` | `/pt/mapa` |
| Listado | `/gelatarias/` | `/pt/gelatarias/` |
| Sitemap | `/sitemap.xml` | `/pt/sitemap.xml` |
| Robots | `/robots.txt` | `/pt/robots.txt` |
| API | `/api/shops` | `/api/shops/pt` |
| Idioma | `es` | `pt` (português europeu) |
| Moneda | EUR | EUR |

### Puntos Clave de Implementación

1. **Locale Forcing:** Todas las rutas `/pt/*` fuerzan `g.locale = "pt"` via middleware
2. **GeoIP Detection:** Detecta IP portuguesa → automáticamente locale=pt
3. **Traducciones Fallback:** Si falta clave en `pt.json`, cae a `es.json`
4. **SEO Separado:** Portugal tiene su propio sitemap e índices separados
5. **Base de Datos:** Una tabla `gelatarias` con campo `locale` (escalable a N países)

### Rutas Específicas Portugal

| Method | Endpoint | Descripción |
|--------|----------|-------------|
| GET | `/pt/` | Página principal Portugal |
| GET | `/pt/gelatarias/` | Listado de gelatarias |
| GET | `/pt/gelatarias/{ciudad}/` | Gelatarias por ciudad |
| GET | `/pt/mapa` | Mapa interactivo |
| GET | `/api/shops/pt` | API datos gelatarias PT |
| GET | `/pt/sitemap.xml` | Índice sitemap |
| GET | `/pt/sitemap-{n}.xml` | Sub-sitemaps |
| GET | `/pt/robots.txt` | Directivas crawl |

## Plantillas Reutilizables

### Template: blueprint de país

```python
# backend/routes/[country].py
"""
GelatoMaps — [Country] Routes Blueprint
========================================
Rotas específicas para [Country]:
  - Página de entrada /[code]/
  - Listado /[code]/gelatarias/
  - Por ciudad /[code]/gelatarias/{ciudad}/
  - Mapa /[code]/mapa
  - APIs: /api/shops/[code]
"""

import logging
from functools import wraps
from flask import Blueprint, request, jsonify, g, render_template

from backend.storage import load_json
from backend.models import (
    HELADERIAS_FILE, DATA_DIR,
    API_DEFAULT_LIMIT, API_MAX_LIMIT,
)
from backend.utils import api_error, api_ok
from backend.security import check_rate_limit

logger = logging.getLogger(__name__)

bp = Blueprint('[country]', __name__, url_prefix='/[code]')

@bp.before_request
def before_request():
    g.locale = "[locale]"
    g.country = "[COUNTRY_CODE]"
    # Validar rate limit
    check_rate_limit("shops", request.remote_addr)

# Rotas específicas aquí
```

### Template: SEO blueprint

```python
# backend/routes/seo_[locale].py
"""
GelatoMaps [Country] SEO Routes Blueprint
==========================================
Handles [Country]-specific routes for:
- /[code]/robots.txt
- /[code]/sitemap.xml
- /[code]/sitemap-*.xml
"""

import logging
from datetime import datetime, timezone
from flask import Blueprint, Response

from backend.models import HELADERIAS_FILE
from backend.storage import load_heladerias

logger = logging.getLogger("gelatomaps")

seo_[locale]_bp = Blueprint('seo_[locale]', __name__, url_prefix='/[code]')

@seo_[locale]_bp.route('/robots.txt', methods=['GET'])
def robots():
    """Generate robots.txt for [Country]"""
    # Implementación aquí
    pass

@seo_[locale]_bp.route('/sitemap.xml', methods=['GET'])
def sitemap_index():
    """Generate sitemap index for [Country]"""
    # Implementación aquí
    pass
```

### Template: Script de scraping

```python
# scripts/scrape_[country]_[type].py
"""
Scraper de [type] para [Country]
Basado en scrape_portugal_gelatarias.py
"""

import requests
import json
from pathlib import Path

def scrape_[type](url, query_params=None):
    """
    Scrape [type] de [country]
    Returns: list of dicts with structure:
    {
        "nombre": "...",
        "ciudad": "...",
        "coordenadas": {"lat": X, "lng": Y},
        ...
    }
    """
    # Implementación aquí
    pass

def save_to_json(data, output_file):
    """Save scraped data to JSON"""
    with open(output_file, 'w', encoding='utf-8') as f:
        json.dump(data, f, indent=2, ensure_ascii=False)

if __name__ == "__main__":
    data = scrape_[type]("[URL_FUENTE]")
    output = Path(__file__).parent.parent / "data" / "[country]" / "[type].json"
    output.parent.mkdir(parents=True, exist_ok=True)
    save_to_json(data, output)
    print(f"✓ Scraped {len(data)} items → {output}")
```

## Guía de Implementación Paso a Paso

### Paso 1: Decidir en qué país expandir
```bash
# Define:
- País: [País]
- Código: [código ISO 2 letras, ej: fr]
- Idioma: [idioma ISO 639-1, ej: fr]
- Moneda: [EUR/GBP/USD...]
```

### Paso 2: Configurar i18n
```bash
# 1. Editar backend/i18n/config.py
# 2. Crear backend/i18n/locales/[locale].json (copiar de pt.json)
# 3. Traducir todas las claves
# 4. Probar: python3 -c "from backend.i18n import get_locale_config; print(get_locale_config('[locale]'))"
```

### Paso 3: Crear blueprints
```bash
# 1. Copiar backend/routes/portugal.py → backend/routes/[country].py
# 2. Reemplazar 'pt' con '[locale]', '/pt' con '/[code]', etc.
# 3. Copiar backend/routes/seo_pt.py → backend/routes/seo_[locale].py
# 4. Ajustar rutas y prefijos
# 5. Registrar en backend/routes/__init__.py
```

### Paso 4: Recopilar datos
```bash
# 1. Crear scripts/scrape_[country]_gelatarias.py
# 2. Ejecutar: python3 scripts/scrape_[country]_gelatarias.py
# 3. Verificar: data/[country]/gelatarias_[locale].json
# 4. Crear scripts/generar_fichas_[locale].py (si es necesario)
```

### Paso 5: Actualizar modelos
```bash
# Editar backend/models.py:
# - Agregar [COUNTRY]_DIR
# - Agregar GELATARIAS_[LOCALE]_FILE
# - Actualizar loops de mkdir
```

### Paso 6: Probar
```bash
# Compilar:
python3 -m py_compile backend/routes/[country].py
python3 -m py_compile backend/routes/seo_[locale].py

# Iniciar servidor:
python3 server.py

# Probar rotas:
curl http://localhost:8000/[code]/gelatarias/
curl http://localhost:8000/api/i18n/locale
curl http://localhost:8000/[code]/robots.txt
```

### Paso 7: Desplegar
```bash
# Staging:
git push origin feature/expand-[country]
# Revisar en staging

# Producción:
git merge main
# Rollout con monitoring
```

## Arquitectura i18n Profunda

### Componentes

```python
backend/i18n/
├── __init__.py
│   └── Expone: detect_locale(), set_locale_cookie(), get_locale_config()
│
├── config.py
│   └── SUPPORTED_LOCALES = {"es": {...}, "pt": {...}, ...}
│
├── detector.py
│   ├── GeoIP detection (CloudFlare CF-IPCountry header)
│   ├── Accept-Language parsing
│   ├── Cookie preferences
│   └── Fallback chain: GeoIP → Accept-Language → Default (es)
│
├── translations.py
│   └── get_all_translations(locale) → carga locale/[locale].json
│
└── locales/
    ├── es.json (default)
    ├── pt.json (Portugal)
    └── [locale].json (nuevos aquí)
```

### Flujo de Detección

```
1. Solicitud llega a middleware
2. middleware calcula g.locale:
   a. ¿Cookie gelato_locale existe? → usar
   b. ¿GeoIP (CloudFlare CF-IPCountry) es PT? → usar 'pt'
   c. ¿Accept-Language contiene pt? → usar 'pt'
   d. Default → 'es'
3. Todas las rutas heredan g.locale
4. Templates/JSON usan g.locale para traducir
5. Fallback: si falta clave en es.json, usar es.json
```

### API i18n

```
GET /api/i18n/locale
→ {"locale": "pt", "config": {...}, "supported_locales": ["es", "pt"]}

POST /api/i18n/locale
body: {"locale": "pt"}
→ Establece cookie + respuesta

GET /api/i18n/strings
→ Todas las traducciones del locale actual

GET /api/i18n/strings/pt
→ Traducciones de portugués específicamente

GET /api/i18n/supported
→ Lista de todos los locales soportados
```

## GeoIP Detection

CloudFlare proporciona encabezado HTTP:
```
CF-IPCountry: PT    # Para Portugal
CF-IPCountry: ES    # Para España
```

Mapper en detector.py:
```python
COUNTRY_TO_LOCALE = {
    "PT": "pt",
    "ES": "es",
    "FR": "fr",  # Future
    "IT": "it",  # Future
    ...
}
```

## Testing de Expansiones

### Unit Tests

```python
def test_pt_locale_detection():
    """Test que GeoIP PT → locale pt"""
    from backend.i18n import detect_locale
    # Simular header CF-IPCountry: PT
    assert detect_locale(...) == "pt"

def test_pt_translations_loaded():
    """Test que traducciones PT existen"""
    from backend.i18n.translations import get_all_translations
    strings = get_all_translations("pt")
    assert "nav" in strings
    assert strings["nav"]["home"] != ""

def test_pt_routes_registered():
    """Test que rutas /pt/* existen"""
    from backend.routes.portugal import bp
    assert bp.name == "portugal"
    assert bp.url_prefix == "/pt"
```

### Integration Tests

```python
def test_pt_full_flow():
    """Test flujo completo: GeoIP → locale → traducción → ruta"""
    client = app.test_client()
    
    # Simular GeoIP Portugal
    response = client.get("/pt/gelatarias/", 
                         headers={"CF-IPCountry": "PT"})
    assert response.status_code == 200
    assert "gelatarias" in response.data.decode()
```

## Mantenimiento Futuro

### Agregar nuevo idioma (ej: Francés)

1. Agregar a `SUPPORTED_LOCALES` en `config.py`
2. Crear `backend/i18n/locales/fr.json` (copiar pt.json, traducir)
3. Actualizar `COUNTRY_TO_LOCALE` en `detector.py`
4. (Opcional) Crear `backend/routes/france.py` si necesita rutas específicas
5. Probar con GeoIP France

### Agregar nuevo país pero mismo idioma (ej: Brasil en portugués)

1. Crear `backend/routes/brazil.py` con locale='pt' pero prefix='/br'
2. Actualizar `COUNTRY_TO_LOCALE` en `detector.py` para mapear Brasil a 'pt'
3. Reutilizar traducciones de `locales/pt.json`

### Fallback de traducciones

Si falta una clave en `pt.json`:
```python
def get_translation(key, locale='es'):
    try:
        return translations[locale][key]
    except KeyError:
        # Fallback a español
        return translations['es'].get(key, key)  # Retorna clave si no existe
```

## Recursos Referencias

- **Portugal Implementation:** `/backend/routes/portugal.py`, `/backend/routes/seo_pt.py`
- **i18n Core:** `/backend/i18n/`
- **Scraper Template:** `/scripts/scrape_portugal_gelatarias.py`
- **Ficha Generator:** `/scripts/generar_fichas_pt.py`
- **Models Constants:** `/backend/models.py`
- **Server Init:** `/server.py` (línea ~243 `register_all_middleware`)

## Conclusión

Esta guía convierte cada expansión internacional en un proceso repetible, documentado y escalable. Portugal es el prototipo; el siguiente país debe ser más rápido, usando plantillas y lecciones aprendidas.

**Próximos destinos potenciales:** Francia (francés), Italia (italiano), Brasil (portugués brasileño), Grecia (griego), Alemania (alemán).

---

Última actualización: Abril 2026  
Casos de estudio: Portugal (Marzo-Abril 2026)
