Skip to content

How to Localize an Application

Kittox supports full localization of both the framework interface and your application's metadata. You can also build multi-language applications where each user selects their language at login.

Step 1: Localize the framework interface

The framework ships translated in English, Italian, German, Spanish and Portuguese — its locale folder is KittoX/Home/Locale/:

KittoX/Home/Locale/
  it/
    LC_MESSAGES/
      Kitto.po       # Source strings (editable with Poedit)
      Kitto.mo        # Compiled binary (used at runtime)

To add a new language:

  1. Copy the it/ folder and rename it with the language code (e.g. de/, fr/, es/)
  2. Open Kitto.po with Poedit
  3. Translate all msgstr entries
  4. Save — Poedit generates the .mo file automatically

The .po file covers all framework strings: form buttons (Save, Confirm, Cancel, Edit, Close, Delete, Save All, etc.), error messages, login labels, confirmation dialogs, and client-side JavaScript strings.

Step 2: Localize your application metadata

Your application's locale folder ({App}/Home/Locale/) follows the same structure. Use the _() marker in YAML files:

Field labels and hints:

yaml
Fields:
  Doll_Name: String(40) not null
    DisplayLabel: _(Name)
  Date_Bought: Date
    DisplayLabel: _(Birth Date)
  Picture: Blob
    DisplayLabel: _(Photo)
    Hint: _(Select a picture)

Allowed values:

yaml
Fields:
  Dress_Size: String(4)
    AllowedValues:
      XS: _(Extra Small)
      S: _(Small)
      M: _(Medium)

See the HelloKitto and TasKitto examples for complete working samples.

Mark only what the user reads

In the snippet above only the descriptions are wrapped: XS, S, M are the codes stored in the database. The same care applies to PluralModelName (an XML tag name, not a caption — the caption is PluralDisplayLabel), to physical and file names, and to comparison literals inside SQL Expression nodes. See what must not be wrapped.

Step 3: Mark strings in Delphi code

In custom controllers and rules, use _() from EF.Localization:

pascal
uses
  EF.Localization;

procedure TCheckDuplicateInvitations.BeforeAdd(const ARecord: TKRecord);
begin
  if ARecord.Store.Count('INVITEE_ID', ARecord.FieldByName('INVITEE_ID').Value) > 1 then
    RaiseError(_('Cannot invite the same girl twice.'));
end;

Step 4: Generate the .po files with KIDEX

Marking strings is only half the job — they must land in the .po catalogs. Don't do this by hand: KIDEx extracts them for you and keeps each language's default.po in sync with your metadata and code.

  1. In KIDEx, expand the project's Locales node, right-click the language and choose Update….
  2. KIDEx scans the metadata (Models / Views / Layouts / Config) and runs dxgettext over your Source\ folder, then merges everything into that language's default.po — existing translations are preserved, brand-new strings appear empty.
  3. Translate the empty entries in Poedit and save to compile the .mo.

Re-run Update… whenever you change metadata or code — it is non-destructive. See Update Locale for the full workflow and the list of auto-recognized YAML keys.

Step 5: Enable multi-language at runtime

Language selection is configured in Config.yaml:

yaml
LanguageId:            # empty → follow the browser (Accept-Language); set a code (en, it, …) to force it
LanguagePerSession: True
  • With an empty LanguageId, the language is auto-detected from the browser (Accept-Language) on the first visit.
  • With LanguagePerSession: True, a LanguageSwitcher flag dropdown lets the user switch language at any time; it lists every language for which the application ships a compiled catalog (Home/Locale/<code>/LC_MESSAGES/*.mo) plus English — a folder without a .mo is ignored, and the framework's own catalogs do not make a language selectable. In the examples it appears on the login form and at the bottom of the home menu — add it to any layout region with Controller: LanguageSwitcher.

See also

Released under Apache License, Version 2.0.