Osy#betaRun it on Osyrin: osyrin.com

Reference / I18n

A language's words — locales/<language>.osy

translations sv { role "source" [key "k"] => "translation" | { one: …, other: … } | null [was "old" => …]; }

A project's translations are checked-in source: one `locales/<language>.osy` per language, a `translations sv { }` block of `role "source" => "translation";` entries with their context above them. `osy translate` writes and keeps them in step; you own the words. The compile refuses a translation with the wrong placeholders, a missing plural form, or markup — at its line.

stable1 example compiled by CIi18nlanguagetranslationfile-format

Summary#

One file per language per project — an app's or a kit's — at locales/<language>.osy. It is SOURCE: it rides every compile, test and deploy with the rest of the project, a kit's archive carries its own, and a mistake in it is a compile error at its line. osy translate writes it (osy translate — the request for any model, and its answer read back); the words are yours to edit.

Signature#

translations sv {
  /// Checkout · /checkout · a button's label · at most ~16 characters
  button "Check out" => "Till kassan";
  /// BagPage · /bag · placeholders: {count} = count (int) — {count} is a count
  text "{count} items in your bag" => { one: "{count} vara i din kasse", other: "{count} varor i din kasse" };
  text "Open" key "shop-status-open" => "Öppet";
  title "Your shopping bag" => null was "Your bag" => "Din kasse";
}

Description#

An entry is keyed exactly as a message is (Which words are translated — the compiler finds every text a reader sees): its ROLE, its source TEXT and, rarely, a key. Its value is a text, one text per plural category ({ one: …, other: … }, A count's plural forms — one text per CLDR category), or null — not translated yet, so the reader sees the source text. The /// lines above it are its context — where it is, what it is, how long it may be, what its placeholders hold, what sits beside it — written by osy translate for whoever translates the file cold.

Kept in step, never regenerated. A text the file translates keeps its translation. A new text arrives as => null. A text whose source changed (so its identity did) is matched to the entry it replaced — the same role in the same component — and written STALE: => null was "old source" => "old translation", so the old words are right there as a hint. A text no longer in the source is dropped.

What the compile refuses, at the translation's line, on the server and in osy validate alike:

refusalwhy
a placeholder the source does not have, or a source placeholder left outthe hole would show as {name} or the value would vanish
plural forms for a text with no countnothing chooses between them
a plural form the language lacks, or one it needs missingSwedish has one and other; Polish one, few, many, other
the same text translated twice in one languagewhich one wins would be an accident
markup — <b>, <img …>, <!--a translation is TEXT, and is always shown as text

Precedence. A kit ships locales/*.osy of its own words; an app's file carries its own words and, for a language a kit does not speak, the kit's words too (osy translate puts them there, marked with the kit's name). By identity, the app's entry wins — so an app overrides a kit's word by translating the same text and role itself.

The languages an app speaks are its source language (English, unless app.SourceLanguage says otherwise — app.SourceLanguage — the language the app is written in) and every language it has its OWN file for; a kit's extra languages are not offered on their own, because the app's words would still be in its source language.

Examples#

[Route("/")]
[AllowAnonymous]
component Home() {
  int count = 2;
  action Pay() { Navigation.Go("/"); }
  render {
    Stack {
      Text("Your bag is empty.");
      Text($"{count} items in your bag");
      Button("Check out", onPress: Pay);
    }
  }
}

translations sv {
  text "Your bag is empty." => "Din kasse är tom.";
  text "{count} items in your bag" => { one: "{count} vara i din kasse", other: "{count} varor i din kasse" };
  button "Check out" => "Till kassan";
}

See also#

Related

Which words are translated — the compiler finds every text a reader sees

You write your app's words where they belong, in ordinary strings. The compiler finds every one a reader can see — by…

osy translate — the request for any model, and its answer read back

There is no platform model. `osy translate --to sv,de` brings `locales/sv.osy` and `locales/de.osy` in step with the…

A count's plural forms — one text per CLDR category

A message with a whole-number hole (`$"{n} items"`) may take one text per plural category of its language — CLDR's…

Which language a reader gets — and switching it

A reader's language is, in order: their explicit choice (a `/sv/` address prefix or a language switch), their own…