Packages' text in an app
On this page
To show a package's or Jadpo's message in a locale, Jadpo looks first in your app's root wording for that locale, then in the owner's own. For an in-progress locale it then tries the regional sibling, in the same order, and then the default locale, in the same order.
Your app's supported locales must be complete for every package and Jadpo message the app can show. So an English-only package in an app that supports French is an error until the root file supplies the French.
Here an app supporting English and French installs a package that words its text in English only, calls its message, and words the French itself:
/// Shown under a postcode field.public type PostcodeHint = Message {}
translations { invalid_postcode: "That isn't a UK postcode." postcode_hint: "Write it as it is on a letter, such as SW1A 1AA."}
use packages/postcodes/// What the postcode field says, in the reader's language.action postcode_hint_text(reader_locale: Locale) -> PresentationText { return Postcodes.translations.postcode_hint(locale: reader_locale)}
translations { postcodes: { invalid_postcode: "Ce code postal n'existe pas." postcode_hint: "Écrivez-le comme sur une lettre." }}
test "the package words the English and the app the French" { assert postcode_hint_text(Locale.en_gb) == "Write it as it is on a letter, such as SW1A 1AA." assert postcode_hint_text(Locale.fr_fr) == "Écrivez-le comme sur une lettre."}
Without translations/fr_fr.jadpo, French has nothing to show:
application {}locales { default: Locale.en_gb supported: [Locale.en_gb, Locale.fr_fr]}
error: `Locale.fr_fr` is supported but package `Postcodes` has no wording in it for `postcode_hint` --> app.jadpo:5:31 |5 | supported: [Locale.en_gb, Locale.fr_fr] | ^^^^^^^^^^^^ no `translations/fr_fr.jadpo` reason: Package `Postcodes` ships no `Locale.fr_fr` wording of `postcode_hint`, and the application supports `Locale.fr_fr`, so the application words it in its root file, under the package's folder name. A locale that isn't finished yet is listed in `in_progress:`, and falls back to the default until it is. next: Add `translations/fr_fr.jadpo` wording `postcode_hint` under `postcodes: { }` (agent) rule: translation.file_missing help: https://jadpo.dev/docs/errors/translation.file_missingcheck failed: 1 error, 4 files
To show a package failure under a different code, not just in different
words, map it to your app's own failure at the call with attempt, as for
any package failure (Calling).
When a package changes
A package that changes a message's or a failure's fields makes a breaking change to its surface, the list of what it offers (The surface). So your app's rewording fails to compile until you update it.
A package that changes its own wording marks your app's rewording stale,
through sources.jadpo_record
(Stale translations), and the
same holds for Jadpo's wording. The root folder's
sources.jadpo_record records, for each wording your app gives outside the
default locale, a hash of the default wording it was made from. That is
your app's own default-locale wording of the message or, if the app gives
none, what Jadpo or the package ships. A default locale Jadpo doesn't ship
and the app doesn't word has nothing to compare with, so its translations
aren't judged.
A library package is published with complete wording in its own default
locale and a /// description on every public message.
Wording two versions of a package
While your app holds two versions of a library package side by side
(Where packages live), it words
each under a key carrying the version, postcodes_v2: { } and
postcodes_v3: { }, as its names carry it. With one version held, the key
is the folder's name. Here the app's own Postcodes is held at v2 and
v3 while callers move across, and the French words each:
translations { postcode_hint: "Write it as it is on a letter, spaces and all."}
use shared/providers/postcodes/// The hint as callers showed it before the upgrade.action old_hint(reader_locale: Locale) -> PresentationText { return Postcodes.v2.translations.postcode_hint(locale: reader_locale)}
use shared/providers/postcodes/// The hint with the next version.action new_hint(reader_locale: Locale) -> PresentationText { return Postcodes.v3.translations.postcode_hint(locale: reader_locale)}
translations { postcodes_v2: { postcode_hint: "Écrivez-le comme sur une lettre." } postcodes_v3: { postcode_hint: "Écrivez-le comme sur une lettre, espaces compris." }}
test "the earlier version is worded under its key" { assert old_hint(Locale.fr_fr) == "Écrivez-le comme sur une lettre."}
test "the next version is worded under its key" { assert new_hint(Locale.fr_fr) == "Écrivez-le comme sur une lettre, espaces compris." assert new_hint(Locale.en_gb) == "Write it as it is on a letter, spaces and all."}
When the second version is added, the app's wording under the folder's name no longer says which version it words. It was written while the earlier version was held alone, so the check's edit moves it to that version's key; the new version is worded afresh. When one of two is removed, the other's key goes back to the folder's name, and the removed version's group is the app's to delete:
translations { postcodes: { postcode_hint: "Écrivez-le comme sur une lettre." } postcodes_v3: { postcode_hint: "Écrivez-le comme sur une lettre, espaces compris." }}
error: `postcodes` words package `Postcodes`, which is held in two versions --> translations/fr_fr.jadpo:2:5 |2 | postcodes: { | ^^^^^^^^^ which version? reason: While two versions of a package are held side by side, the application words each under its folder name and version, as its names carry the version: `postcodes_v2: { }` for `Postcodes.v2` and `postcodes_v3: { }` for `Postcodes.v3`. This group was written while one version was held, so it words the earlier one unless it says otherwise. next: Rename the group to `postcodes_v2`, or to the other version's key if it words that one (agent) rule: translation.group_unknown help: https://jadpo.dev/docs/errors/translation.group_unknowncheck failed: 1 error, 9 files
Packages' text: groups, calls and the surface
- A package's group is its folder's name. The root file words
packages/postcodes/v2/'s text underpostcodes: { }, the name a domain can't share (package.name_taken); the record's lines andjadpo translations missingname its memberspostcodes.<member>. - What the app can word and call. A package's public messages, its
enums with wording and its failures, each by the name its own files use;
a member naming anything else, or something the package keeps private,
is
translation.member_unknown, and a call of a message that isn'tpublicispackage.not_public. A package's own code doesn't call its messages: the app does, andtranslations.postcodes.<message>(...)istranslation.message_unknownwith the call through the package as its edit. - The package's own files are checked by themselves, each against the locale its name gives, whether or not the app supports it: a package is published apart from any app. Their wording, shapes, placeholders and plural forms are checked as a domain's are.
- What a supported locale needs. Every public message, an enum once
the package or the app words it, and a failure some route answers with,
in the root file or the package's own file for that locale. With a root
file for the locale, each one missing is
translation.wording_missing; without one, the locale is onetranslation.file_missingnaming them. A locale in progress falls back, as for the app's own messages. - Every language a package ships is complete. A package has no default
locale, so the publishing bar, the checks a package must pass to be
published, holds every language it ships to completeness. Each language
file words every public message, and an enum once any file words it (a
wordingrow, shown when the package carries translations). A package with messages and no language file fails it. - The surface. The package's entry has a
localeline for each language it words; each public message is an entry,message translations.<message>with its fields, after the functions. A new locale or message is the next minor version, a message's changed fields or a dropped locale are breaking, and changed wording is a patch. - The commands.
missing,updateandaccepttake a package's text in, and so doexport,importandunused, below.
Packages' text in the exchange
- What is exchanged. What a supported locale must word of a package
(above) and anything else of it the app words in its root file, each
unit
postcodes.<member>with.<value>or.<form>, in an XLIFF<file id="postcodes" original="translations">after the app's own and before Jadpo's. It is translated from the app's default-locale wording of it, else the package's, the wording the record'sfromhashes. A package in a folder namedjadpoor like a scope of the app's would share unit ids, so export refuses it, as it does a domain namedjadpo. - What a locale has. The app's root wording, else the package's own
for that locale, which is what the app shows; the package's own is
translated, neverreviewedor stale, since no record of the app's judges it. Exporting and importing unchanged writes nothing. - What comes back is the app's: written into the root file for the
locale, in the package's group (created, beside
jadpo: { }, when the file lacks one), the whole member when one plural form or value changed, its other forms from the package's wording, and a line in the root record. The package's files are never written: a translator who changes the package's wording makes the app reword it. Import's rows name a package's unitspostcodes.<member>, asmissingdoes. unusedlists, after the app's own and underPackage wording, each member of the root files' package groups that shows nothing, with its place and why: a message or enum of the package no code of the app's calls (no code calls it), a name the package no longer has (not in Postcodes) or keeps private (private to Postcodes), and a group no installed library package words text under (no such package). These are the members to delete. A package's message the app neither calls nor words is the package's, and is not listed; a failure is shown by being reachable, as the app's are; Jadpo's group is not a package's.--jsongives them aspackageWording, each with areason(uncalled,notInPackage,private,noPackage).
Two versions of a package
How your app's wording follows a library package held in two versions side by side (Two versions side by side, lazy loading and the package cache):
-
The key. Exactly while names through the package carry the version, the app words each version's text under
<folder>_<version>,postcodes_v3: { }, even when only one of the two carries translations; otherwise under the folder's name. The key is the same everywhere the folder's name was: the root files' groups, the root record's members (de_de.postcodes_v3.postcode_hint),jadpo translations missing,export's<file id="postcodes_v3">and unit ids, whatimportwrites into, andunused, which names the package with its version (not in Postcodes.v3). The errors name the package as code does,Postcodes.v3. A domain named like a version's key ispackage.name_takenwhile two versions are held, as one named like the folder always is. -
Adding a second version moves nothing by itself. The app's wording under the folder's name was written while one version was held, so
jadpo checkreports the group (translation.group_unknown, "held in two versions") with the edit that renames it to the earlier version's key, unless the file already has that group, when its members are moved by hand. The new version starts with none of the app's wording: it may have changed its messages, so nothing is copied, and the check's missing wording lists what each supported locale needs of it. -
Removing one of two puts the other's key back to the folder's name, reported with the edit that renames it ("held in one version"); the removed version's group words nothing (
translation.group_unknown, "which the app doesn't hold"), and is the author's to delete. Neitherjadpo package addnorremoverewrites the app's root files, as they don't rewrite its names, andjadpo fixis still only for type clashes (Commands for records, findings and review). -
The record follows the wording. A translation with no line under its new key takes the line it had under the package's other key in the same locale, the folder's name or another version's, when nothing is worded under that key any more and the wording is the one the line hashes; so it keeps its acceptance, and is stale when the version it now words has different default wording from what it was translated from. Wording changed on the way is a new translation, recorded afresh.
jadpo translations updatewrites the line under the new key (moved with its wording to the package's new key) and drops the old one. -
The publishing bar checks one package in its own folder, where one version is held, so its
wordingrow is unchanged.
Markdown for agents: /docs/packages-text-in-an-app.md.Built from Jadpo main at a707efb.