Summary#
There is nothing to wrap and no key to invent. Write Text("Your bag is empty."), Button("Check out", …),
Field("Email", …) and throw new Exception("That code is not one of ours.") as always: the compiler finds each text a
reader sees and shows it in the reader's language (from locales/<language>.osy, A language's words — locales/<language>.osy), falling back
to the text you wrote — never to nothing.
Signature#
Text("…") // any literal in a text position is a message
Text($"{count} items in your bag") // an interpolation is ONE message with a hole: "{count} items in your bag"
Text("Remove " + line.Name) // so is a + chain: "Remove {line.Name}"
throw new Exception("…"); // an exception's message
Translate("Open", key: "shop-status-open") // the explicit form, and the one way to give a text a keyDescription#
What counts is where the text goes. A string is a message when it reaches a place a reader sees it:
- an atom's text —
Text, aButton's orPressable's content, an accessible name (label:), aplaceholder:, an image'salt:; in an[Email]component the mail'ssubject =>, its text, its links and anEditable'sdefault:; - a component parameter that reaches one — worked out through every component, so
Button("Save"),Field("Email")and your ownSectionLabel("Orders")are text because of what those components do with the value, while astring hrefis not; a text parameter's default counts too; - a class field read into one —
new NavItem { Label = "Coffee" }is text because the shell showsitem.Label; - a function's return when the function is called in one —
Text(DeliveryLine(w))translates the wordsDeliveryLineputs together, including its locals; - a component field assigned in an action and shown —
error = "Try again";; - every exception's message — which exceptions reach a screen is not decidable (any action may
catchand showex.Message), so all are extracted, except a message that quotes code inbackticks: that one is addressed to the developer who configured something, not to the reader; - a page's
[Title("…")]and itshead { Title = …; Description = …; }; - an enum member's declared
[Label("Draft")](rolelabel, the enum's other labels beside it) — read in the reader's language wherever the label is shown, a badge, a dropdown,status.Label. A member with no[Label]shows its NAME (Pending), and that name is a word to translate too when readers see the enum — when it declares a[Label]on any member, or one of the app's own entities stores it — and the name is a word rather than a CamelCase identifier (SecondStepwants a[Label]). An enum only code reads (Direction.Up) is not text; - an entity field's display name — its
[Label("Solved at")], or its name in words ("Arrived at") on an entity a report's field picker reaches — what a report calls the field ([Label] on a field: what a report calls it, in the reader's language); - a validation attribute's own sentence —
[Required("Give it a name.")],[MaxLength(80, "…")],[Pattern(regex, "…")],[Unique("…")]… (rolevalidation) — what the browser and the server say when the rule refuses a value. The regex and the bounds are not words.
What is left alone: a string that goes nowhere a reader sees (an address, a key, a CSS value, an identifier), a
value the code COMPARES with == (translating it would break the comparison — unless its name says it is display
text: Label, Title, Caption …), a text with no letter in it ("·", "×"), anything in a test, and an entity's
data — a product's name is data, and data is translated with [Translatable] ([Translatable] — an entity's own words in every language).
A sentence is one message. $"{n} items in your bag" and "Remove " + name are each one message with holes, so a
translator can move the hole where their language puts it. A hole that is itself text — {(reminder ? ", and one reminder" : "")} — is a message of its own.
Identity is the text and its role — button "Save" and text "Save" are two messages; "Save" on two pages is one.
The place is context, not identity: moving a button does not make its label new. When one English text needs two
translations (an "Open" that is a shop's hours and an "Open" that is a button), give ONE of them a key with
Translate("Open", key: "shop-status-open"). Translate("…") also marks a text the analysis cannot see — a name a
class keeps and the code compares elsewhere.
The browser receives only its language's table, by content address, and a text's words are never markup: they are shown as text wherever they land.
Examples#
public sealed class Crumb {
public string Label;
public string To = "";
}
[Composable]
component Heading(string title, string href) {
render { Link(href: href) { Text(title); } }
}
string Notice() => "Roasted every Tuesday.";
[Route("/bag")]
[AllowAnonymous]
[Title("Your bag")]
component BagPage() {
int count = 3;
string status = "";
Crumb home = new Crumb { Label = "Home", To = "/" };
action Save() { status = "Saved."; }
render {
Stack {
Heading("Your bag", href: "/bag"); // "Your bag" — a title, through Heading's parameter; "/bag" is not text
Text($"{count} items in your bag"); // one message, with the hole {count}
Text(Notice()); // a function's words
Text(status); // "Saved." — assigned in the action
Link(href: home.To) { Text(home.Label); } // "Home" — a class field shown as text
Button("Save", onPress: Save);
Text(Translate("Open", key: "shop-status-open")); // the one "Open" that needs its own translation
}
}
}See also#
- A language's words — locales/<language>.osy — the file the words are translated in, and what the compile checks
- osy translate — the request for any model, and its answer read back —
osy translate: the request and prompt for any model, and reading its answer back - Which language a reader gets — and switching it — which language a reader gets, and how they switch
- A count's plural forms — one text per CLDR category — a count's plural forms
- A history in the reader's language — keep what happened, say it when it is read — a history or a timeline: keep what happened, say it when it is read
- [Label] on a field: what a report calls it, in the reader's language —
[Label]on a field: what a report calls it, in the reader's language