Release runbook now describes default migrateProdSchema, auto-migrate safety guard, and troubleshooting for updated_at restore failures; i18n docs cover partial entity_translations index. Co-authored-by: Cursor <cursoragent@cursor.com>
109 lines
4.0 KiB
Markdown
109 lines
4.0 KiB
Markdown
# Russian localization (i18n)
|
|
|
|
Full Russian support: **UI chrome** via `react-i18next`, **catalog text** via PostgreSQL `entity_translations`, with Cyrillic display aliases where available and English fallback.
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
| Layer | English | Russian |
|
|
|-------|---------|---------|
|
|
| UI labels, buttons | `client/src/locales/en/*.json` | `client/src/locales/ru/*.json` |
|
|
| Names / titles (display) | canonical DB columns | `entity_translations` (`name`, `title`) |
|
|
| Bios, notes, descriptions | canonical DB columns | `entity_translations` (`bio_full`, `body`, `notes`, …) |
|
|
|
|
English remains canonical in main tables. Russian rows use `status`: `draft` → `reviewed` → `published`. Public API returns only **`published`** (unless curator preview).
|
|
|
|
---
|
|
|
|
## User-facing locale switch
|
|
|
|
Timeline header: **EN | RU** toggle (`LocaleSwitcher`).
|
|
|
|
- Persists `gallery_locale` in `localStorage`
|
|
- Sets `document.documentElement.lang`
|
|
- Passes `?locale=ru` on catalog API requests
|
|
- Refetches bootstrap catalog when locale changes
|
|
|
|
---
|
|
|
|
## Setup (dev)
|
|
|
|
```powershell
|
|
npm run dev:migrate # includes migrate-i18n.sql
|
|
npm run dev:fetch-artist-bios-ru # draft bios + Cyrillic names from ru.wikipedia
|
|
# Curator: Translations page → review → Publish
|
|
npm run dev:import-translations -- --file path/to/translations.json --publish
|
|
```
|
|
|
|
Optional manual import JSON:
|
|
|
|
```json
|
|
[
|
|
{ "entity_type": "painting", "entity_id": 42, "field_name": "title", "value": "Джоконда", "status": "published", "source": "manual" }
|
|
]
|
|
```
|
|
|
|
CSV: `entity_type,entity_id,field_name,value,status,source`
|
|
|
|
---
|
|
|
|
## Curator translation review
|
|
|
|
1. Sign in as curator
|
|
2. Header → **Translations** (or **Переводы** in RU UI)
|
|
3. Pick entity type (artist / painting / movement)
|
|
4. Select row → edit Russian fields side-by-side with English canonical
|
|
5. **Publish** saves and marks rows `published`
|
|
|
|
Coverage stats show artists with `bio_full`, paintings with `title` alias, draft vs published counts.
|
|
|
|
API (curator-only): see [API.md](API.md#translations-curator).
|
|
|
|
---
|
|
|
|
## Translatable fields (v1)
|
|
|
|
| entity_type | fields |
|
|
|-------------|--------|
|
|
| `era`, `movement` | `name`, `description` |
|
|
| `artist` | `name`, `bio_short`, `bio_full` |
|
|
| `artist_period` | `name`, `description` |
|
|
| `painting` | `title`, `description` |
|
|
| `annotation` | `label`, `body` |
|
|
| `influence_source` | `notes`, `aspects`, `quote`, `period_note` |
|
|
|
|
---
|
|
|
|
## API locale
|
|
|
|
Public endpoints accept `?locale=ru` or `Accept-Language: ru`. Responses include `"locale": "ru"` on catalog payloads; field names unchanged — values are already resolved.
|
|
|
|
Search matches canonical text **or** published Russian **name** / **title** aliases (partial index `entity_translations_search_alias_idx`; long `bio_full` text is stored but not btree-indexed).
|
|
|
|
---
|
|
|
|
## Prod rollout
|
|
|
|
1. `npm run dev:migrate` on dev; curator review + publish Russian rows on dev
|
|
2. **`npm run devtoprod:release`** (`full` profile) — includes Step 4 schema migrate + Step 5 restore; or `npm run harmonize:schema` then harmonize/sync if you prefer merge over full promote
|
|
3. After restore, verify locale toggle on https://gallery.mysuperlab.netcraze.pro
|
|
|
|
`entity_translations` is included in [`harmonize-db.js`](../scripts/harmonize-db.js) catalog sync.
|
|
|
|
### `dev:fetch-artist-bios-ru` index limit
|
|
|
|
Early `migrate-i18n.sql` indexed all `value` text; very long Russian bios (e.g. Michelangelo) could fail with `index row size … exceeds btree maximum`. Current migration uses a **partial** index on `name` and `title` only (`char_length(value) <= 512`). Re-run `npm run dev:migrate` (or prod Step 4) after pulling this fix, then re-run `npm run dev:fetch-artist-bios-ru` for any artists that failed.
|
|
|
|
---
|
|
|
|
## npm scripts
|
|
|
|
| Script | Purpose |
|
|
|--------|---------|
|
|
| `dev:migrate:i18n` | Apply `entity_translations` table only |
|
|
| `dev:fetch-artist-bios-ru` | Fetch ru.wikipedia bios into translations (draft) |
|
|
| `dev:import-translations` | Import JSON/CSV translation rows |
|
|
|
|
See also [setup.md](setup.md), [environments.md](environments.md), [harmonize-dev-prod.md](harmonize-dev-prod.md).
|