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.