docs(plan): v1.0 cycle — fases 17–20 (versioning + list flow + emojis + euskera)

Four planned-fase docs for the first tagged release.

- Fase 17 — semver git tags + CHANGELOG.md (Keep-a-Changelog, [new]/
  [fix]/[tweak] prefixes), one big v0.0.0-beta backfill block covering
  Fases 0–16, About-modal in /settings rendering bundled CHANGELOG via
  ?raw import, deploy-script tag check + tag column in .deploys.log.
- Fase 18 — shopping list flow: required title (client + DB tighten),
  per-collective per-prefix #N auto-numbering parsed from typed title,
  collectives.default_list_title, collective_list_titles catalog + admin
  RPCs, autocomplete union (catalog + last-10). Migration 027.
- Fase 19 — EMOJI_CATALOG with faces/food/animals/objects categories
  (~280 codepoints, Unicode 14 baseline for iOS<17 compat), new
  EmojiPicker.svelte replacing the 8-emoji hardcoded selector at 4
  sites. No migration.
- Fase 20 — Euskera locale: messages/eu.json via machine-translate
  seed flagged with [needs review], users.language check constraint
  extended to ('en','es','eu'), accept-language parser + selector in
  /settings. Migration 028. v1.0.0 tag lands at the end of this fase.

README + CLAUDE.md updated with the v1.0 cycle pointers.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-19 01:01:34 +02:00
parent 1638d2f6e8
commit 427fe33c9c
6 changed files with 576 additions and 0 deletions

View File

@@ -0,0 +1,136 @@
### Fase 20 — Euskera locale (eu)
**v1.0 · 4/4.** Última fase del ciclo v1.0. Tras cerrarla, se taggea `v1.0.0`.
**Estado: 📋 Planificada.** Añadir Euskera (Basque, ISO 639-1 `eu`) como tercer idioma soportado, sumándose a `en` y `es`. Tras esta fase la app está disponible para los hogares vasco-parlantes.
**Estado actual (auditado 2026-05-19):**
- Paraglide en `apps/web/messages/{en,es}.json`. Compile-time tree-shaken por idioma.
- Selector de idioma actual: `users.language text` (probablemente `en` | `es` por check constraint o convención). Auto-detect ya en Fase 10.8.
- ~300+ keys en cada locale (estimado por el tamaño actual).
**Decisiones clave:**
- **Machine-translate seed + flag for review (opción B):** generar `messages/eu.json` con traducción automática (DeepL-formatted-text o GPT-class) marcando cada valor con sufijo `[needs review]` para que la persona euskera-hablante pueda repasar y borrar el marcador.
- Soporte de idiomas declarados en la lista canónica: `apps/web/src/lib/i18n/supported.ts` (verificar nombre exacto, puede que viva en `paraglide` config). Añadir `'eu'`.
- `users.language` accept `'eu'` en el check constraint (si existe). Si no hay constraint, añadirlo ahora con 3 valores.
- Auto-detect (Fase 10.8): reconocer `eu` / `eu-ES` / `eu-FR` en `accept-language`.
- Selector visible: `/settings` ya tiene un control de idioma. Añadir opción "Euskera".
---
#### 20.1 Migración: language check
**Fichero:** `supabase/migrations/028_users_language_eu.sql`.
```sql
-- Drop the existing check (if it exists; some seeds may not have it).
alter table public.users
drop constraint if exists users_language_check;
-- Re-add with eu allowed.
alter table public.users
add constraint users_language_check
check (language in ('en','es','eu'));
```
**Tareas:**
- [ ] **20.1.1** Migración 028.
- [ ] **20.1.2** Tests pgTAP `supabase/tests/020_users_language_eu.sql`:
- update a `'eu'` accepted.
- update a `'fr'` rejected by check.
- [ ] **20.1.3** `just db-types`.
---
#### 20.2 Locale file
**Fichero:** nuevo `apps/web/messages/eu.json`.
- [ ] **20.2.1** Pipeline de generación (manual, una vez):
1. Tomar `messages/es.json` como source-of-truth (lengua romance + base traductor más fiable hacia euskera que `en`).
2. Traducir cada valor con DeepL API o GPT con prompt "Translate to Euskera (Basque), keep ICU placeholders intact, preserve punctuation, formal register".
3. Marcar cada valor traducido con sufijo ` [needs review]` antes del cierre de la string. **Excepción**: las keys con placeholders ICU (`{name}`, `{count}`) llevan también el sufijo pero la review debe verificar que los placeholders no se hayan movido a posiciones gramaticalmente raras para euskera (SOV order vs SVO).
- [ ] **20.2.2** Validar el JSON: misma key set que `en.json` y `es.json`. Script `scripts/check-locales.mjs` que diff las keys y falla si faltan o sobran.
- [ ] **20.2.3** Bundle Paraglide rebuild: `pnpm --filter @colectivo/web exec paraglide-compile` (o cualquiera que sea el comando — verificar en `package.json`).
---
#### 20.3 Wiring
**Ficheros:**
- `apps/web/src/lib/i18n/*` (configuración de Paraglide — locales soportados).
- `apps/web/src/lib/utils/accept-language.ts` (Fase 10.8 — añadir `'eu'` al set conocido).
- `apps/web/src/routes/(app)/settings/+page.svelte` (selector de idioma).
**Tareas:**
- [ ] **20.3.1** Añadir `'eu'` al array de idiomas en la config de Paraglide (`project.inlang/settings.json` u otro fichero del plugin).
- [ ] **20.3.2** `accept-language.ts` parser: reconocer `eu`, `eu-ES`, `eu-FR``'eu'`.
- [ ] **20.3.3** Selector de idioma en `/settings`: nueva opción "Euskera". Label en cada idioma:
- `en`: "Basque"
- `es`: "Euskera"
- `eu`: "Euskera"
- [ ] **20.3.4** Cambiar idioma a `eu` recarga Paraglide tags sin reload de página (`setLanguageTag('eu')`) + escribe `users.language = 'eu'`.
---
#### 20.4 Tests
- [ ] **20.4.1** Vitest unit `apps/web/src/lib/utils/accept-language.test.ts` (extender):
- LANG-U-EU-01 `eu``'eu'`.
- LANG-U-EU-02 `eu-ES``'eu'`.
- LANG-U-EU-03 `eu-FR;q=0.5,en``'eu'` (preferencia primaria).
- [ ] **20.4.2** Vitest integración `language-bootstrap.test.ts` (extender):
- LANG-INT-EU-01 user setea language=eu, update OK.
- LANG-INT-EU-02 user intenta language='fr' → check constraint violation.
- [ ] **20.4.3** Playwright `tests/e2e/euskera.test.ts`:
- **EU-01** Ana cambia idioma a Euskera en `/settings` → strings nav cambian (Listas → "Erosketak", o lo que diga el JSON), sin reload.
- **EU-02** Eva (usuario nuevo) con header `Accept-Language: eu` → onboarding renderiza en Euskera.
---
#### 20.5 Review checklist (post-translation)
Antes del v1.0.0 release, abrir issue/asignar tarea para alguien euskera-hablante:
- [ ] **20.5.1** Repasar `messages/eu.json`, eliminar el sufijo ` [needs review]` de cada string corregido.
- [ ] **20.5.2** Para keys con plurales (`item_count_one`, `item_count_other` si existen), verificar que ambos son correctos (euskera no distingue como inglés/español; puede ser una sola forma).
- [ ] **20.5.3** Términos del dominio: "colectivo", "lista", "tarea", "nota", "compra". Acordar la traducción con el cliente (no asumir que la máquina la acertó).
---
#### 20.Z Verificación + cierre
- [ ] **20.Z.1** `just test-all` verde. Suma esperada: +2 pgTAP + 3 unit + 2 integración + 2 e2e = +9.
- [ ] **20.Z.2** Smoke manual: rotar las 3 pantallas top-level (`/lists`, `/tasks`, `/notes`) en cada idioma. Ninguna debe mostrar la key cruda (`__SKIPPED__` o el id).
- [ ] **20.Z.3** Bundle-size check: el chunk de `eu` es lazy-loaded por Paraglide; verificar que solo se carga cuando el user lo elige. No debe pesar más que `es.json`.
- [ ] **20.Z.4** Entrada en CHANGELOG: `[new] Euskera (Basque) locale (Fase 20). Machine-translated seed pending native review.`
- [ ] **20.Z.5** Documentar en `docs/history/fase-20-euskera-locale.md`.
---
#### 20.ZZ v1.0.0 release
- [ ] **20.ZZ.1** Bump `package.json` version → `1.0.0`.
- [ ] **20.ZZ.2** Editar `CHANGELOG.md`: mover entradas de `[Unreleased]` a `## [v1.0.0] — YYYY-MM-DD`. Incluir resumen de las 4 fases del ciclo (1720).
- [ ] **20.ZZ.3** `git tag -a v1.0.0 -m "v1.0.0 — versioning + shopping list flow + emoji avatars + euskera"`.
- [ ] **20.ZZ.4** Deploy desde el tag. Smoke en prod.
- [ ] **20.ZZ.5** Anuncio interno + nota sobre euskera review.
---
### Riesgos / notas
- **Calidad de la traducción automática**: euskera no es un idioma soportado de primera por DeepL (verificar fecha actual). GPT-4 class lo hace pero con errores. El sufijo `[needs review]` es explícito para no shipear texto incorrecto sin marcar.
- **ICU placeholders en euskera**: el orden de palabras (SOV) puede empujar `{name}` a posiciones no naturales en inglés/español. Revisar.
- **Selector ya soporta `system` (auto-detect)**: por la Fase 10.8 ya hay lógica de fallback. Asegurar que `eu` propaga por todo el árbol.
- **Test fixture users**: si los seeds (Ana, Borja, …) tienen `language='es'` hardcoded, ningún test rompe — solo los nuevos.
### Scope explícito fuera
- Galego, Català, Português, Francés. Solo Euskera en este release.
- Pluralización ICU avanzada (one/two/few/many/other) — euskera usa pluralización simple.
- Traducción de los strings de Keycloak (login screen). Ese es el operador del Keycloak externo.
- Localización del CHANGELOG. Solo en inglés.
- Localización de los nombres de los emojis (Fase 19). Aria-label sigue siendo el codepoint name CLDR en inglés.