Language Systems

Moxie.Build supports translating any user-facing text into multiple languages from a single database table. Procedures, templates, and database field metadata all share the same translation store, so a string written once is reusable everywhere.

The Content.Lang Table

The Content.Lang table is the canonical home for application translations. Each record has at minimum:

Field Purpose
Alias Unique key, usually written as Prefix.tag (e.g. Site.btnSignIn).
English The source-language value.
French The translation for that language.

Adding more languages. Any number of languages can be supported. For each new language:

  1. Add a new field to the Content.Lang table named after the language (e.g. Spanish, German, Japanese).
  2. Update the corresponding language values in the Setup table so the runtime knows which languages are enabled and how to switch between them.

Once both are in place, the same retrieval syntax (below) automatically picks the column matching the active language.

Selecting the Active Language

The active language is determined per request. The simplest way to switch is the URL parameter ?Cnw-Lang=French (or whichever language field name you've added). English is the default when no language is specified.

Setting the Prefix

Translation aliases are usually written as Prefix.tag. The prefix namespaces all the tags used by one procedure or template, which keeps tag suffixes short and lets you reuse common names (btnSave, title, etc.) across different pages without collision.

In a Procedure

Use LangWith at the top of your procedure (or before any block that needs translations):

LangWith    "Profile"

From that line onward, every translation lookup in the procedure resolves against the Profile.* namespace.

You can call LangWith again later to switch namespaces mid-procedure — useful when you need to pull a string from a different prefix (such as a shared Api.* set of toast messages) without changing the procedure's main prefix permanently. Just restore the original prefix when you're done.

In a Template

Templates use the parallel form:

< ? $$ Profile ?>

Place this near the top of the template, and subsequent translation tags (below) will resolve against Profile.*.

Retrieving a Translated Value

Once a prefix is active, there are four ways to look up a value, each suited to a different context.

1. Top Query — Lang$

Lang$ is the Top Query function for retrieving a single translated value. It takes one parameter, the tag suffix:

[New] welcome    =    Lang$ "welcomeTitle"

With LangWith "Profile" active, this returns the value of Profile.welcomeTitle in the active language.

Use Lang$ when you need the string as a value (assigning to a field, concatenating, passing to another command).

2. Work Query — Lang

Lang is the Work Query Function for resolving translations across many records at once. It takes four parameters: FieldBase, Destination, Source, IfLenFld.

Lang    "Profile.", "Label", "tagSuffix", ""

Use Lang when you're operating on a multi-record work query and want each record's source field to be resolved through the language table efficiently in one pass.

3. Inside an HtmlBlock{$suffix$}

Inside an HtmlBlock or HtmlBlocks the {$suffix$} syntax resolves a translation against the procedure's active LangWith prefix:

HtmlBlock
    < h1>{$welcomeTitle$}< /h1>
    < p>{$welcomeDesc$}< /p>
End HtmlBlock

A note on the examples below: a single space has been inserted after the literal lessthan sign or [ in some examples (e.g. < ? … ?>, [ Language …], or HTML wrapper tags like < h1> and < /p>) to prevent the Moxie.Build template engine from interpreting them as live syntax on this page. The actual syntax has no such space.

You can also include a fully-qualified alias (with one or more dots) to reach a record from a different prefix:

< p>{$Api.linkCopied$}< /p>

4. In a Template — < ? $ tag ?>

Templates have two forms:

< ? $$ Profile ?>
< h1>< ? $ welcomeTitle ?>< /h1>
< p>< ? $ Api.linkCopied ?>< /p>

Schema Field Translations

Field labels, notes, and attribute placeholders in your table definitions can also be translated. In the field's .tab definition, write {$$} as a shorthand placeholder in the Label, Note, or Attr column:

FieldName  {$$}  {$$}  [Placeholder] {$$}

The shorthand resolves to an alias built from the table name and field name:

Where Resolves to (for table example.table, field FieldName)
Label column example.table.FieldName
Note column example.table.FieldName.Note
Attr column (e.g. inside [Placeholder]) example.table.FieldName.Attr

For more complex cases where one cell needs to embed multiple translation references, use the named form {$customSuffix$} which resolves to example.table.customSuffix:

Status  {$$}  {$$} {$statusHelp$}

Inline Translations

For short embedded text that doesn't warrant a Content.Lang record — particularly inline within field attributes or [!] dropdown labels — you can use inline language tags:

[ Language English]Sign In[/ Language][ Language French]Connexion[/ Language]

Only the segment matching the active language renders. Use these sparingly — Content.Lang records are usually preferable because they're discoverable and translatable in one place.

Fallback Behavior

When a tag is looked up:

  1. Moxie.Build first checks the Content.Lang table.
  2. If no record is found, it falls back to the BuiltIn language table.
  3. If still not found, it returns the alias itself as the value (e.g. Profile.welcomeTitle) rather than raising an error.

This makes development friction-free — you can reference a tag before the record exists, see the alias appear in the rendered page, and add the record when you're ready. There's no error to catch.

Planning for Multiple Languages

Different languages render at different lengths. French and Spanish typically run 20–30% longer than the equivalent English; German can be longer still. When you write the source-language string, picture the longest likely translation:

Quick Reference

Where Set prefix Resolve a tag
Procedure (Top Query) LangWith "Prefix" Lang$ "suffix"
Procedure (Work Query) LangWith "Prefix" Lang "Base.", "Dest", "Source", ""
HtmlBlock / HtmlBlocks Procedure's LangWith {$suffix$} or {$Full.Alias$}
Template < ? $$ Prefix ?> < ? $ suffix ?> or < ? $ Full.Alias ?>
Schema field Filename-derived {$$} shorthand or {$customSuffix$}
Inline attribute text [ Language X]...[/ Language]