```yaml
id: UJ-012
title: Save a manual content translation
actors: [administrator]
surface: admin-spa
goal: Administrator saves translated title and content as a linked draft and fresh detail returns it.
trigger: Edit target-language fields and activate Save at /wp-admin/admin.php?page=international-press-zone#/translations/posts.
fixtures: [authenticated-admin, source-post, active-target-language]
success_state:
  visible: "Translation saved" renders and target tab shows translated state.
  durable: Linked translated draft and ipz_translations row contain exact values.
  persistence: Fresh GET /wp-json/international-press-zone/v1/translations/content/{id} returns exact translation.
source_specs: [admin/src/pages/content-translate.js, includes/API/TranslationsController.php]
readiness: draft
canonical: false
blockers: []
```

## Path

| Hop | Evidence |
|---|---|
| UI trigger | `admin/src/pages/content-translate.js:752` |
| Request construction | `admin/src/pages/content-translate.js:878` |
| Endpoint auth and parse | `includes/API/TranslationsController.php:123` |
| Authoritative write | `includes/API/TranslationsController.php:1212` |
| Response | `includes/API/TranslationsController.php:1246` |
| Terminal render | `admin/src/pages/content-translate.js:888` |

## Happy path

### H1
- Setup: Administrator authenticated; source post and active target exist; target translation absent.
- Action: Enter non-empty translated title and content, then activate `Save`.
- Request: `PUT /wp-json/international-press-zone/v1/translations/content/{source-id}`.
- Response: `200` with refreshed content detail containing exact translated post and `translation_status:"translated"`.
- Visible: `Translation saved` renders; target tab and row show translated state.
- Durable: One draft translated post contains exact title/content/excerpt; one `wp_ipz_translations` row links it to source and target.
- Fresh read: `GET /wp-json/international-press-zone/v1/translations/content/{source-id}` returns `200` with exact translated values.
- Forbidden: Source post and other languages remain unchanged; no translation API call occurs.
- Evidence:
  - Setup: `includes/API/TranslationsController.php:1115`
  - Action: `admin/src/pages/content-translate.js:752`
  - Request: `admin/src/pages/content-translate.js:878`
  - Response: `includes/API/TranslationsController.php:1246`
  - Visible: `admin/src/pages/content-translate.js:888`
  - Durable: `includes/API/TranslationsController.php:1212`
  - Fresh read: `includes/API/TranslationsController.php:123`
  - Forbidden: `includes/API/TranslationsController.php:1212`

## Alternate and failure paths

### A1
- Setup: Administrator authenticated; source post and target exist; translated title input empty.
- Action: Activate `Save`.
- Request: N/A — client validation rejects before transport.
- Response: N/A — no HTTP request is produced.
- Visible: `Title is required` renders and title input receives focus.
- Durable: No translated post or translation link is created or updated.
- Fresh read: Content-detail GET returns original translation projection.
- Forbidden: No API request, post write, translation link, or source mutation occurs.
- Evidence:
  - Setup: `admin/src/pages/content-translate.js:859`
  - Action: `admin/src/pages/content-translate.js:752`
  - Request: `admin/src/pages/content-translate.js:867`
  - Response: `admin/src/pages/content-translate.js:867`
  - Visible: `admin/src/pages/content-translate.js:869`
  - Durable: `admin/src/pages/content-translate.js:867`
  - Fresh read: `includes/API/TranslationsController.php:123`
  - Forbidden: `admin/src/pages/content-translate.js:867`

## Permissions and boundaries

### P1
- Setup: Actor lacks `manage_options`; source and target otherwise valid.
- Action: Submit manual translation payload.
- Request: `PUT /wp-json/international-press-zone/v1/translations/content/{source-id}`.
- Response: `403` with `{code:"rest_forbidden",message:"Sorry, you are not allowed to do that.",data:{status:403}}`.
- Visible: REST denial exposes no protected content detail.
- Durable: No post or translation row changes.
- Fresh read: Protected content-detail GET returns permission denial.
- Forbidden: No source/translated post or translation-link write occurs.
- Evidence:
  - Setup: `includes/API/TranslationsController.php:1689`
  - Action: `includes/API/TranslationsController.php:142`
  - Request: `includes/API/TranslationsController.php:123`
  - Response: `includes/API/TranslationsController.php:1689`
  - Visible: `includes/API/TranslationsController.php:1689`
  - Durable: `includes/API/TranslationsController.php:1689`
  - Fresh read: `includes/API/TranslationsController.php:130`
  - Forbidden: `includes/API/TranslationsController.php:1689`

## Source specs

- `admin/src/pages/content-translate.js`
- `includes/API/TranslationsController.php`
