Files
RenewCMS/docs/design/localization-tables.md
T

35 KiB

Localization board tables

Generated from source/locale-spec.js. Read localization.md first: its explicit corrections supersede conflicting text below. API additions are proposals to be specified and accepted through /slice, not existing endpoints.

Decisions

Question Chosen behavior Rationale Existing behavior affected Backend dependency Release
Language model One story group, one article id per language, one version per locale Reuses the article editor, permissions and publish flow None for single-language sites group_id, lang on articles; unique (group_id, lang) Initial
Default vs editing vs source Three separate roles. Default is a site setting; editing language is the open article; source is chosen per translation Default is not always the best source None source_article_id per version Initial
Locale scope Per site, list of enabled languages plus one default Matches site-level settings Settings → Sites gains Languages site_languages table Initial
Site locale field Four distinct values: formatting locale (existing Site.Locale, still used for dates and numbers), default content language (new, seeded from the full Site.Locale and confirmed by the owner), article language (per version), social metadata locale (explicit or derived, never guessed) Avoids silent reinterpretation ResolveArticleSEO reads Site.Locale for social metadata (verify in repo); for localized articles it uses the article language None Initial
Disable vs remove Disable keeps content and published versions. Remove only at zero versions No configuration action deletes or unpublishes None Count per language; 409 language_in_use Initial
Existing content Setup assigns a language per site, in one transaction; each article becomes its own story Metadata only; no guessed grouping Articles gain lang Bulk assign endpoint, atomic Initial
Titles Editable after creation. A title change never alters an existing slug. Slug changes only through explicit Edit slug; no redirects are promised (none in the backend) Translated titles must be revisable; URLs stay stable. Same rule on single-language sites CHANGE: titles were immutable. Slug policy applies everywhere Allow title in PUT; slug rules Initial
Slug uniqueness Unique per (site, lang) Same slug in two languages is normal Today unique per site Index change Initial
Language control Dropdown beside the title; rows show version state; interface language unchanged Compact for 2 to 20 languages Editor heading translations[] on GET article Initial
Switching Opens another article id. Dirty form asks Keep editing, Discard, Save and switch URL is the state; no lost work None None Initial
Add translation Draft only; copy or start empty; images/authors reused; copied text flagged Needs review Copying is a start, not completion None POST translations; 409 language_exists Initial
Source reference Optional read-only pane; segment on mobile; no sync Keeps the single editor default None Read access to source Initial
Direction dir on editor and reference panes only Shell stays LTR None Per-language dir from locale Initial
List: all languages One row per story; title from default version, else first accessible; coverage chips Avoids duplicates Articles list Grouped query, access-filtered Initial
List: language selected One row per version; Not in French tab lists stories Units always stated Tabs and counts lang, tab params Initial
Search All languages: every accessible title. Language: that language only Predictable Search Access-filtered Initial
Publishing Per version; copy always names the language; no bulk publish Prevents accidental scope Publish button copy None Initial
Deleting Per version. Last version deletes the story. Article delete needs permission on all Explicit scope Delete dialog None Initial
Freshness Needs review when the source revision changes after the reviewed revision; Mark as reviewed records it Reliable, not timestamp-based None content_revision on versions; reviewed_source_revision Initial
Revision-bumping fields Title, body, excerpt, slug, image alt text, SEO and social text. Not authors, cover, site, publication Only translatable content counts None Revision incremented in same write Initial
Site move Moves the whole story; destination must enable every language; slug conflicts block No splitting or merging Site select in editor Move endpoint, validation Initial
Hidden versions Titles, counts, coverage, language summaries, previews, errors and deletion confirmations name only versions the user can read No leakage List counts, delete dialog Filter at query level Initial
Machine translation Not included Out of scope None None Later
Cross-site stories Not included Out of scope None None Later
Bulk publish / review Not included No clear need None None Later
Slug policy Slug generated once at creation. Changed only by Edit slug, before or after publishing. Published change warns: "Links to the old address will stop working. RenewCMS does not create redirects." One policy, no redirect promise Slug field Unique (site, lang) Initial
Permission model Capabilities per version: read, edit, publish, delete, create-translation, review. UI renders from capabilities[] on the article response, not from role names Matches role/scope permissions Editor, list capabilities[]; server enforces every call Initial
Missing vs hidden "Not in French" lists stories where French is absent or unreadable to the user. Add French translation on a story with an unreadable French returns a neutral 409 (see Visibility policy) Discovery cannot leak existence List Conflict check ignores read permission; response is neutral Initial
Source-copy access Read access to the chosen source is rechecked at submit, inside the transaction Access can change while the dialog is open Add translation Neutral 403/404 Initial
Disabled languages Versions stay readable and editable; publishing blocked until re-enabled; filter lists them under Disabled No silent unpublishing Site languages enabled flag per site language Initial
Header priority Left to right: language dropdown, publication badge, status badge (unsaved, saving, saved, failed), freshness badge, Read only tag, title input (fills the remaining width, same row on desktop), then reference button, Unpublish, Save, primary, overflow. At most one filled button. Collapse order: reference label, Unpublish to overflow, freshness to icon The primary action is never hidden Editor header None Initial
Public URL pattern Per-site owner setting with {lang} and {slug}; live preview from a real article; unset state links from "Public URL not configured" No fabricated website URLs Settings → Sites public_url_pattern on site Initial
Social locale per language Per-language owner field on Languages: Derived (from the tag), Set (typed), Not set. Format language_REGION Never guess a region Languages page social_locale per site language Initial
Release split Source reference (L6) and Freshness and review (L9) are release 2. Frames are drawn in full so they can be checked Smaller first release None None Release 2
UI wording The UI says "article", never "story". No revision numbers, IDs or HTTP status names in user-facing copy. Internal notes may say story Plain language All localization copy None Initial

Capability matrix (per version, enforced server-side)

Case Read Edit Publish Delete Create translation Review UI result
P1 Read-only version Yes No No No If can create on site No Banner "You can read this version. You can't edit it." No Save, Publish, Delete; formatting toolbar hidden; fields read-only; the reference action remains
P2 Edit, no publish Yes Yes No Per scope Per scope If can edit Save shown; Publish hidden; hint "Publishing needs the publish permission"
P3 Publish, no edit Yes No Yes Per scope Per scope No Publish/Unpublish shown, fields read-only (only if existing permissions allow publish without edit)
P4 Sibling readable, not editable Yes No No No n/a n/a Opens read-only; row tag "Read only"
P5 Sibling not readable No No No No n/a n/a Row absent; no count, no placeholder
P6 Can create, not modify all Yes Own versions Own Own Yes Own Delete article and Move article disabled with the reason "You can't delete this article." Delete French version stays available if allowed
Owner / Admin Yes Yes Yes Yes Yes Yes All readable versions; not inferred from role label alone

Field ownership, copy and fallback

Field Own per version Copied on "Copy from source" Fallback if empty
Title Yes Entered by the editor None (required)
Slug Yes Generated from the new title None
Body Yes Yes, flagged Needs review None
Excerpt Yes Yes First words of body
SEO title and description Yes Yes Title / excerpt, then site defaults
Social text Yes Yes SEO text
Image alt text Yes Yes None
Cover and inline images Reference, files shared Yes, no duplicate files None
Authors Yes Yes, editable None
Site Shared by the story Same None
Publication and timestamps Yes No None

API: existing vs proposed

Capability Status Request Errors
List articles Existing, extended GET /v1/article/?page=&size=&q=&status=&site=&seo= (existing). Proposed: lang, tab=all|missing|review (same names as the URL; no separate mode or needs_review) 400 invalid page/size (SPA never shows it)
Get article Existing, extended GET /v1/article/{id}. Proposed fields: lang, story_id, capabilities[], translations[] (readable only), source { article_id, revision, status: tracked|inaccessible|deleted } 404 for hidden or deleted
Create article Existing, extended POST /v1/article/. Proposed: lang, story_id, source_article_id, copy (routes to translation rules) 409 language_unavailable · 422 language_not_enabled
Edit Existing, extended PATCH /v1/article/{id}. Proposed: if_revision for overwrite recheck 409 revision_conflict { current_revision }
Publish / unpublish Existing PATCH /v1/article/{id}/publish, /unpublish. Per version 403 missing_permission · 422 language_disabled
Delete Existing DELETE /v1/article/{id}. Last version deletes the story 403 · 404
Add translation Proposed POST /v1/article/{id}/translations { lang, title, source_article_id, copy }. Path id is any readable version; source_article_id selects the copy source; source_revision captured in the transaction 409 language_unavailable (neutral) · 404 (neutral) · 422 · 403
Mark reviewed Proposed POST /v1/article/{id}/review { source_article_id, source_revision, translation_revision } 409 source_changed · translation_changed · source_replaced · 403
Change tracked source Proposed PATCH /v1/article/{id}/source { source_article_id|null } 422 source_cycle · 422 source_other_story · 403
Site languages Proposed GET/PUT /v1/site/{key}/languages { default, languages[{ lang, enabled }] }, atomic 422 default_not_enabled · no_enabled_language · 409 language_in_use · 409 languages_changed
Setup Proposed GET/POST /v1/language/setup { sites:[{ key, lang }] }, idempotent per site key; articles created during setup get the site default; retry after failure is safe. UI route /settings/sites/:key/languages/setup 403 · 409 setup_in_progress
Move story Proposed POST /v1/story/{story_id}/move { site }, atomic, revalidates 409 slug_conflict · 422 language_not_enabled · 403 (neutral)
Publish with unsaved edits Client sequence PATCH /v1/article/{id} (save) then PATCH /v1/article/{id}/publish. The second call is sent only if the first returns 200. No new endpoint Save failure: nothing published, edits stay unsaved
Public article (two requests) Proposed Exact: GET /v1/public/site/{key}/lang/{lang}/article/{slug}. Resolve: GET /v1/public/site/{key}/story/{story_id}?lang=&fallback=default. Existing article-ID links unchanged See Public lookup
Public URL pattern Proposed GET/PUT /v1/site/{key} { public_url_pattern }. Placeholders {lang}, {slug}. Owner only 422 unknown_placeholder · invalid_scheme · not_encoded · missing_slug · 403
Social locale Proposed PUT /v1/site/{key}/languages { languages[{ lang, enabled, social_locale|null }] } 422 invalid_social_locale

Accessibility and interaction

Control Accessible name and keyboard Focus Announcement
Language control "Language: French. Switch version". Enter or Down opens a menu; arrows move; Enter selects; Escape closes Into the list on open; back to the control on close Polite: "Editing French version"
Title input Accessible name "Title (French)", no visible label (the language dropdown beside it names the version); aria-describedby points to the help or error text; invalid sets aria-invalid and the message is an alert Stays in the field; on Try again, back to the field Polite: "Saving title", "Title saved"; errors are announced
Save, Save and publish, Retry publish Buttons named by their text including the language ("Save and publish French"); busy state sets aria-busy; Tab order: title, language, status, reference, Unpublish, Save, primary, More actions After save, stays on the button; after a failed save, on Try saving again Polite: "French saved"; "Saved as a draft. Publishing failed. Try publishing again."
More actions menu or sheet Menu button "More actions"; items are menuitems; disabled items use aria-disabled and show the reason as text First enabled item on open; back to More actions on close None
Reference button "Show source reference" or "Hide source reference", icon-only at 1024 with the same name Moves into the pane on show; back to the button on hide Polite: "Showing English reference"
Conflict dialog and sheet role dialog, modal; options are buttons in order Keep my changes, Download my version, Reload theirs, Save over theirs; Escape equals Keep my changes First button (Keep my changes) on open; back to the title on close Polite: "Download started"
Move panel and dialogs Site select is a listbox named "Site"; the note is the description of the confirm button Into the list; back to the site select Polite: "Moved to Atelier"
Add translation dialog Focus trapped; Escape cancels unless creating First field; back to the control Polite: "French draft created"
Source segment (mobile) Two-button radiogroup, arrows switch Stays on the segment Polite: "Showing English source"
Coverage chips aria-label per chip: "French: draft, needs review". The "+3" chip is named "3 more languages: …" Row, not chips. Dashed chips are buttons on desktop only when the user can create None
List unit label aria-live polite: "4 articles not in French" None Polite on every filter change
Status without color Publication badges are solid with an icon (Published: check, Draft: pencil). Freshness badges are outlined with a refresh icon and a word. Save status always has an icon and a word None None
Touch targets On mobile every button, menu row, chip button and segment is at least 44 px high; the bottom bar keeps the primary visible None None
Reduced motion No slide or fade transitions on popovers, sheets and the tab strip scroll when prefers-reduced-motion is set; the saving spinner becomes a static icon with the word "Saving" None None

Acceptance scenarios

# Given / When / Then
1 Given a single-language site, when creating an article, then no language control appears anywhere.
2 Given French is enabled, when an editor adds a French translation with "Copy from English", then a draft is created, the editor opens it, and the badge reads Draft and Needs review.
3 When French is published, then English publication is unchanged.
4 When English changes title or body after review, then French shows Needs review; changing authors does not.
5 Given dirty French, when choosing English, then a three-choice dialog appears and no work is lost.
6 Given a writer who cannot see the German draft, then German appears nowhere in lists, counts, menus or alternates.
7 When disabling German with 12 versions, then all 12 stay and 3 published stay online.
8 When two editors create French at once, then the second sees "French is no longer available" with entries kept.
9 When moving a story to a site missing a language, then the move is blocked and nothing splits.
10 When the interface language is Arabic or French, the editing language indicator still shows the article language.
11 Given French has unsaved edits, when the user chooses Save and publish French and the save fails, then nothing is published and the edits stay unsaved with Try saving again.
12 Given French is missing and unpublished, when a client resolves the story with lang=fr and fallback=default and the default is published, then the response is the default language with requested_lang fr and fallback true; with the default also unpublished it is 404 language_not_available.
13 Given a site locale pt-BR, when setup seeds the default language, then it reads Portuguese (Brazil) pt-BR and the owner confirms it before anything applies.

Existing surfaces audit and verification

Item Note
Home Recent articles show the default-language title with a language code when not default. States loc.l12.home, loc.l12.homeFr
Activity Events gain the language: "Published French version of …". State loc.l12.activity
Article menu Publish and Delete labels name the language on multilingual sites. State loc.l12.menu
API URL copy Copies the version URL with ?lang=. State loc.l12.apiCopy
SEO preview Shows the localized address and canonical. State loc.l12.seoPreview
Media usage Counts a shared image once; lists versions that use it. State loc.l12.media
Site text fallback A site-level text (for example a site description) is a fallback only for articles in the same language. A French article can use the French site text; an Arabic article with no Arabic site text gets "No fallback" and the tag is left out. State loc.l12.siteFallback
Verification limit Repository files were not accessible. Statements about them are assumptions marked verify in repo.
Decided Slug policy, hidden-version disclosure, Home counting articles, and review storing the source version only (no text diff) are decided in the other tables.

Visibility and anti-enumeration policy

Situation User can read it User cannot read it
Duplicate translation "French already exists for this article." Action: Open French version "French can't be created for this article." No Open action, no title, no hint a version exists
Create conflict response 409 language_exists with article_id 409 language_unavailable; identical body for exists-unreadable, disabled and lost race
Article delete confirmation Names readable versions: "Delete English and French?" Unreadable versions are not named or counted. If any blocks deletion: "You can't delete this article." plus Delete this version
Source unavailable Deleted: "The source was deleted." "The source isn't available to you."
Missing translation tab Row shown; Add French translation Same row; a 409 shows the neutral copy
Counts and summaries Readable versions only Never included

Public lookup and URLs

Topic Decision
CMS API vs website CMS API URLs (/v1/...) are never shown as website URLs. Website URLs come from a proposed per-site public_url_pattern (owner), e.g. https://example.com/{lang}/{slug}. Existing convention unverified.
Pattern not configured "Public URL not configured" with a link to site settings. No URL is fabricated. API links by article ID remain.
Exact lookup GET /v1/public/site/{key}/lang/{lang}/article/{slug}. Matches site + language + slug only (slug is unique per site and language). Missing or unpublished: 404 article_not_found. It never falls back and never tries another language's slug
Resolution by story GET /v1/public/site/{key}/story/{story_id}?lang=&fallback=default. story_id is the stable story identifier, returned on every public response and in alternates[]. No lang means the site default language. Fallback is decided only by story_id
Example: requested version published story st_01, lang=fr, French published: 200, lang fr, fallback false
Example: requested missing or unpublished lang=fr, no published French. Without fallback: 404 language_not_available. With fallback=default and a published default (en): 200, lang en, requested_lang fr, fallback true
Example: default also missing or unpublished lang=fr, fallback=default, French and the default both unavailable: 404 language_not_available. No third language is tried
Example: default requested but unpublished lang=en, English unpublished, fallback=default: 404 language_not_available
Compatibility Article-ID endpoints (GET /v1/article/{id}) and existing public URLs keep working. Setup labels existing articles with the site default language
Response identity Always lang (actual language). alternates[] lists only published, enabled-language versions
Canonical The localized page itself, unless an explicit canonical override is set
Default-language change Does not change what existing URLs return; absent or unpublished default gives 404 unless fallback is requested

Locale semantics

Value Meaning Used for
Site formatting locale Existing Site.Locale SPA dates and numbers; kept
Default content language New per-site setting. Setup seeds it from the full Site.Locale when a supported language entry matches (en-GB, pt-BR). If only the language part is supported it seeds that and says so. No locale: the owner must choose. The owner confirms or changes it explicitly; nothing applies unconfirmed Fallback, new-article default, setup
Article language BCP 47 tag per version (en, fr, pt-BR, ar) html lang, API lang, hreflang
Social metadata locale Resolved in order: 1) explicit social locale on the site language (set by an owner, e.g. fr: fr_FR); 2) the language tag already has a region (pt-BR gives pt_BR); 3) Site.Locale has the same language part (site en-GB and article en give en_GB); 4) otherwise none: og:locale and og:locale:alternate are omitted for that version and the editor shows Not set. No region is invented for a bare language. og:locale:alternate lists other published versions whose locale resolves by the same rules; the rest are left out og:locale, og:locale:alternate
SEO fallbacks Empty French SEO fields fall back to French title and excerpt. English site defaults are never applied silently to a non-default language: editor shows "Empty. English site default not used." and the tag is omitted Editor labels: "Fallback: French title", "No fallback"

Article list modes and sample data

Mode Units and count Representative title Row opens Search Sort
All languages Stories Default-language version if readable, else first readable by language code Representative version Any readable title Story updated: latest readable version
Language selected Versions in that language That version That version That language only Version updated
Missing language Stories lacking it or unreadable in it As All languages Representative version Titles in any readable language Story updated
Filters Status, Author, SEO, Needs review: a story matches if any readable version matches (language mode: the version)
Story Author, Updated Union of readable authors; latest readable update
Differing sites Language filter lists the union; Missing excludes sites that do not enable the language
Dataset (locale-fixtures.js) See the Fixture index. Journal: 8 articles, 17 versions, page size 5 (page 1 shows 5, page 2 shows 3). Enabled en (default), fr, de, ar; disabled es, it. Versions: en 7 (6 published), fr 4 (2 published, 2 Needs review), de 4 (3 published), ar 1, es 1, it 0. 4 articles have no French version. Needs translation 7, Needs review 2. Every list, tab count, unit label and pager is computed from locale-fixtures.js.

Review source and revision semantics

Topic Decision
Record { article_id, source_article_id, source_revision, translation_revision, reviewed_by, reviewed_at }
Confirmation guard The dialog carries the versions the user saw. If either moved, the dialog says "The English source changed while you were reviewing. Review again." or "French was changed by someone else while you were reviewing. Review again." Nothing is marked
Change tracked source Explicit action Change tracked source. Result: Needs review. Earlier reviews are kept as history
Cycles Prevented (422 source_cycle). Source must be in the same story
Access loss vs deletion Access lost: "The source isn't available to you right now." history kept, Mark reviewed disabled. Deleted: "Source deleted" with Choose a new source
Source replacement Pick another readable version of the story; freshness becomes Needs review
What changed Changed-field summary only, shown as "Changed fields: Title, Body", with the source version date and the translation version date. No text diff and no revision numbers in the UI
Concurrent edits Mark reviewed applies only to the revisions the user saw

Title, slug and concurrent edit flows

Case Behavior
Title editing Inline underline input in heading style, on the same row as the language, badges and actions on desktop (no box, no visible label). States: pristine, focus, editing, unsaved, invalid ("Enter a title"), too short, too long, saving, failed (value kept). Bounds 3 to 200 characters. Accessible label "Title (French)". Editing the title never changes the slug
Slug See Slug policy. Edit slug lives in Search and sharing and in the overflow menu; its note says "Editing the title never changes the slug."
Conflict "Someone else saved this version at
Overwrite scope "Replaces the title, body and search fields of this version only. Other languages are untouched."
Session expiry Draft kept locally per article (title, body, search fields) until saved or discarded. After login: "Restored unsaved changes from

Language configuration lifecycle

Action Rule
Disable default Blocked: "Choose another default first."
Disable last enabled Blocked: "At least one language must stay enabled."
Disable with content Allowed; versions remain; published stay online; publishing blocked for drafts
Re-enable Row action Re-enable; no data change
Remove Only at zero versions; never the default
Save error Dialog keeps language, default and toggle values; error above the footer
Story moves Disabled-language versions count toward destination requirements

Mobile list and prototype scope

Item Spec
Filter sheet Site, Language, Status, Author, SEO; Clear all and "Show N results"; active filters show as chips with "Remove filter Status: Draft" and Clear all
Tabs Scrolls with edge fade and buttons "Scroll tabs left/right"; Not in French is always reachable
Pager Same page size as desktop (5); "Page 1 of 2"; the URL keeps page and size
Row actions Identical capability on every width: see Row actions. Mobile uses the row menu button (44 px), desktop shows the same button (28 px)
Prototype flows Not part of this pass. The LocaleLive prototype was not touched

Editor header priority

Order Item 1440 1024 390
1 Title input (underline, heading style; own row on mobile, shares the header row on desktop) Full width Full width Full width
2 Language dropdown Visible Visible Visible, 44 px
3 Publication badge Visible Visible Visible
4 Primary action (the only filled button) Rightmost before More actions Same Fixed bottom bar, fills the width left by Save and More
5 Status badge (Unsaved changes, Saving, Saved, Save failed) Visible Visible Visible
6 Save (secondary) Visible Visible Bottom bar, next to the primary
7 Freshness badge Icon and word Collapses first: icon only, name in aria-label Wraps under the language row
8 Read only tag Visible Visible Visible
9 Reference button Icon and label Collapses second: icon only More actions sheet
10 Unpublish (secondary) Visible Collapses third: More actions menu More actions sheet
11 More actions Edit slug, Move article, Delete versions Same plus Unpublish Same plus reference and Unpublish

Action matrix

State Permissions Primary (filled) Secondary Notes
Clean draft edit + publish Publish French Save (off) loc.l5.default
Clean draft edit only None Save (off) Hint: Publishing needs the publish permission
Dirty draft edit only Save None loc.l5.dirty; "Saving keeps it as a draft."
Dirty draft edit + publish Save and publish French Save loc.l5.dirtyPublish
Clean online edit + publish None Unpublish French, Save (off) loc.l5.cleanOnline; "This version is online. Saving updates the live page right away."
Dirty online edit + publish Save Unpublish French loc.l5.onlineDirty
Saving any Saving… (busy) None loc.l5.saving
Saved any Publish French if allowed Save (off) loc.l5.saved
Save failed edit Try saving again None loc.l5.saveFail; nothing published
Publish failed after save edit + publish Retry publish Save (off) loc.l5.pubFail; "Saved as a draft. Publishing failed. Try publishing again."
Unpublish with edits publish Unchanged Unpublish French loc.l8.unpublishDirty; saved version goes offline, local edits stay, nothing is saved
Read-only read None None Reference button remains
Publish without edit publish Publish French None Fields read-only

Title field states

State Look Message Save
Pristine Heading-size text, neutral border None Off
Focus Primary 2px underline "Changing the title doesn't change the address." Off
Editing Primary border, counter n / 200 Same note On
Unsaved Neutral border, Unsaved changes badge Same note On
Invalid Error border and icon "Enter a title" Blocked
Too short Error border, counter "Use at least 3 characters" Blocked
Too long Error border, counter 203 / 200 "Use 200 characters or fewer" Blocked
Saving Spinner "Saving title…" Busy
Save failed Error border and icon "Couldn't save the title. Your text is kept." Try again On

Row actions (same on every width)

Action Shown when Desktop Mobile
Open Always, for the version the row opens Row click and menu Row tap and menu
Open another language… More than one readable version Menu Menu
Add translation… User can create and a language is missing Menu (dashed chip button as a shortcut) Menu
Publish / Unpublish User can publish Menu Menu
Copy API URL Always Menu Menu
Delete version User can delete Menu Menu

Coverage chips for many languages

Width Chips shown Overflow Dashed missing chips
1440 5 "+3" chip for 8 languages; named "3 more languages: …" Last in order; buttons only if the user can create; hidden otherwise
1024 4 (narrower column) "+4" Same
390 4, under the title "+4" Not buttons; added from the row menu
Order Default language, other existing versions, disabled-language versions, then missing Never shown for languages the user can't create

URL state (article list)

Param Values Default
site Site key First site
lang Language code; absent means all languages all
tab all, missing, review (Published and Drafts are the status filter) all
q Search text empty
status online, draft any
author Author name any
seo attention any
page Page number, starting at 1; filter changes reset it 1
size Rows per page 5 in the fixture

Public URL pattern validation

Case Example Message
Valid https://journal.example.com/{lang}/{slug} Preview: https://journal.example.com/fr/comment-nous-chiffrons-une-renovation
Unknown placeholder https://journal.example.com/{language}/{slug} Unknown placeholder {language}. Use {lang} and {slug}.
Bad scheme ftp://journal.example.com/{lang}/{slug} Start with https:// or http://.
Not encoded https://journal.example.com/my pages/{lang}/{slug} Remove spaces and characters that need encoding. Use letters, digits, - and _.
Missing {slug} https://journal.example.com/{lang} Add {slug} so each article has its own address.
Unset Public URL not configured, with a link to this setting

Social locale per language

State Label Meaning
Derived Derived: pt_BR The language tag has a region. Not editable except by setting a value
Set Set: fr_FR An owner typed it. Format language_REGION
Not set Not set No region available. og:locale and og:locale:alternate are left out
Invalid fr-FR Use letters and one underscore, for example fr_FR.

Move article

Case Behavior
Entry point The site select in the editor details
Note "Moves all language versions of this article." Lists readable versions; a version the user can read but not edit is tagged Read only; unreadable versions are not listed or counted
Confirm "Move to Atelier?" with the same list
Failures Language missing in the destination (disabled languages count), address conflict (names only readable conflicting versions), no permission (neutral)

Release 2 groups

Group Release Why
L6 Source reference Release 2 Drawn in full so the checker has frames
L9 Freshness and review Release 2 Drawn in full so the checker has frames