TranslatableStrings.h header

#include <ew/app/TranslatableStrings.h>

Namespace ew::app

TranslatableString struct

struct ew::app::TranslatableString

One string of the project's own content that can be translated.

Members

ew::core::localization::StringId ew::app::localization::TranslatableString::id

Where the string lives, as a stable <uuid>/<fieldPath> address.

QString ew::app::localization::TranslatableString::sourceText

The current source text.

QString ew::app::localization::TranslatableString::ownerLabel

The containing object's own name or title, so a human can tell which chapter or character they are looking at.

Deliberately the RAW user content and nothing else – no pre-rendered "Chapter 3 - Title" label. Composing one would mix a translatable UI word ("Title") into a value produced by a UI-agnostic library, and the caller can join this with id's field path and localize the field name at its own layer.

SourceFormat ew::app::localization::TranslatableString::format =

What kind of text sourceText is.

QString ew::app::localization::TranslatableString::speaker

Who says it, for a line of dialogue; empty for everything else.

Context a translator cannot do without. The same English sentence is translated differently depending on who says it – formality, register, and in many languages the grammatical gender of the speaker's own words. A translator handed a list of lines with no speakers has to guess, and will guess wrong somewhere.

TranslationWorkItem struct

struct ew::app::TranslationWorkItem

One row of a translator's work list: a source string, what it currently has, and what it needs.

Members

TranslatableString ew::app::localization::TranslationWorkItem::string

The source string.

QString ew::app::localization::TranslationWorkItem::translatedText

The existing translation, or empty when there is none.

ew::core::localization::TranslationStatus ew::app::localization::TranslationWorkItem::status =

What this string still needs, derived from the catalogue and the CURRENT source.

Enumerations

enum class SourceFormat { PlainText, Markdown, Html, Fountain, Dialogue }

What kind of text a source string is, so a translator is not handed markup they think is prose.

Carried per string rather than per document because one document yields several: its body is Markdown or Fountain while its title and synopsis are plain text, and a translator who reflows a screenplay's single newlines has silently destroyed its formatting – Fountain's line breaks are significant (they separate a character cue from its dialogue).

This is DERIVED at extraction, never stored: a screenplay is identified by ew::core::document::DocumentKind::Screenplay rather than by any format tag, so the answer lives in the walk rather than on the object.

Functions

std::vector< TranslatableString > ew::app::localization::extractTranslatableStrings(const ew::core::project::Project &project)

Every translatable string in project, in address order.

Empty source text is skipped: an untitled document or a property nobody filled in is not work, and listing it would pad a translator's file with rows that can never be completed.

The surface is deliberate rather than exhaustive. It covers what a READER sees: document titles, bodies, synopses and footnotes; entity names, property values and aliases; category names and their field labels/descriptions/fixed values; timeline titles and descriptions; comment bodies; and branching dialogue – a scene's title, the text of every node, and the label on every choice, which together are the highest-volume localisable content a game project has.

It excludes workflow metadata that never reaches a reader (a document's status or point-of-view marker, a timeline event's style label or layer, a dialogue node's author notes and its condition expression), and it excludes tags, which drive filtering and search – a translated tag would silently stop matching the content it classifies.

A branch node is addressed by its own stable id (<scene>/nodes/<node>/text). A choice label is addressed by its link's ENDPOINTS and guard (<scene>/links/<from>/<to>/<guard>/label), because BranchLink carries no id of its own – it is identified by where it goes from and to. A positional links/2 would name a different link the moment one was inserted above it, and a translator's returned file would land every label one row out.

An entity's aliases are extracted as ONE comma-joined string at <uuid>/aliases, matching how the codex inspector already presents and commits them. Per-alias addresses are impossible: ew::core::entity::Entity::aliases() is a std::set with no per-item identity, so any positional key would name a different alias the moment the set reordered.

std::vector< TranslationWorkItem > ew::app::localization::translationWorkList(const ew::core::project::Project &project, const ew::core::localization::TranslationCatalog &catalog)

The work list for catalog against project: every translatable string paired with its current translation and status.

Driven from the SOURCE side, not the catalogue: a string the writer has since deleted simply stops appearing, and a string they have just added appears as New without anything having to notice the difference. That is also what makes the status honest – each row's staleness is computed against the source text in the project right now.