Text and languages
Every label in a form is text somebody has to read, and every text a person reads might have to be in more than one language. FormScript keeps them out of the logic and in one place.
The text block
form loan version = "1.0" {
text {
"loan.title": "Loan application"
"loan.amount": "Loan amount"
"loan.monthly": { "default": "Monthly payment", "ar": "القسط الشهري" }
"loan.errors.too_small": "The amount is too small"
}
field amount { type = number label = t("loan.amount") }
field monthly { type = number label = t("loan.monthly") }
}
A key is either a string or a map of locales:
"loan.monthly": { "default": "Monthly payment", "ar": "القسط الشهري" }
"default" is the text used when the current language has no entry of its
own. The locale codes are the usual ones — "ar", "en", "fr", and so on.
Reading a label
t("loan.amount") looks the key up in the current language.
field amount {
type = number
label = t("loan.amount")
hint = t("loan.amount_hint")
}
Text lives in a text block, never inline in a label. Writing
label = "Loan amount" works, and the specification warns about it —
W-TEXT-01 — because it is a habit worth breaking early. A label written
inline cannot be translated without rewriting the document.
Where else text appears
Three more places, all of them the same idea:
field birth_date {
type = date
label = t("applicant.dob")
hint = t("applicant.dob_hint")
validate {
custom = age(self) is between 18 and 75
? true
: t("applicant.dob_required")
}
}
- the
label— the name of the question; - the
hint— a line of help under it; - a custom validation message — the text of the complaint.
And t() works in a page or a section label, and in a choice:
choice employment {
label = t("applicant.employment")
type = enum("employed" = t("employment.employed"), "self" = t("employment.self"))
}
Formatting
Two builtins write values out for a person to read:
field amount { type = number value = formatMoney(pmt(0.05 / 12, term, principal), "GBP") }
field due { type = string value = formatDate(start_date, "d MMMM yyyy") }
formatMoney(n, currency)— an amount, with the currency written out;formatDate(d, pattern)— a date, in the pattern you give.
Both are presentation: what they produce is a value for a person to read, and the data plane keeps the number and the date.
The display type
There is one more thing worth knowing, and it is the reason formatMoney
exists at all.
The specification has a display value: a value that exists only to be
shown to a person, and never to be stored. A label built with t() is a
display value; a formatted amount is a display value.
The distinction matters because a display value can be re-read: t("loan.monthly")
gives the text in the current language, and the runtime knows it is a
presentation of the number and not the number itself. So a form can be shown
in Arabic without the data being Arabic.
A whole form, in two languages
form loan version = "1.0" {
text {
"loan.title": { "default": "Loan application", "ar": "طلب قرض" }
"loan.amount": { "default": "Loan amount", "ar": "مبلغ القرض" }
"loan.monthly": { "default": "Monthly payment", "ar": "القسط الشهري" }
}
field amount { type = number label = t("loan.amount") }
field monthly { type = number label = t("loan.monthly") }
output {
amount: number
monthly: number
}
}
The logic did not change. The output document did not change. The data is the same in every language, and the text is the only thing that changed — which is the whole point of keeping the text in one block.