Kodall
Develop App

Localization

The localization system in Kodall provides a robust, dynamic, and multi-tenant translation mechanism for low-code applications. Instead of hardcoding user-facing strings (like titles, column headers, actions, inputs, menus, or dashboard items) directly in configurations, Kodall references localization keys. These keys are resolved to translated text at runtime based on the user's active locale.

The localization system in Kodall provides a robust, dynamic, and multi-tenant translation mechanism for low-code applications. Instead of hardcoding user-facing strings (like titles, column headers, actions, inputs, menus, or dashboard items) directly in configurations, Kodall references localization keys. These keys are resolved to translated text at runtime based on the user's active locale.


The Translation Entity (ui_i18n)

At the core of the localization system is the ui_i18n entity. It stores the mapping between localization labels (keys) and their corresponding translations in different languages.

Schema Properties

PropertyTypeDescription
keyintegerPrimary key of the translation record.
labelstringThe unique identifier/key used in views (e.g., system.ui.view_edit.title_new or entity.product.ui.title).
valuestringThe default/fallback value used when no locale-specific translation is found.
value_enstringEnglish translation value.
value_rostringRomanian translation value.
value_destringGerman translation value.
id_organizationinteger (FK)Optional. Restricts the translation override to a specific organization.
id_business_unitinteger (FK)Optional. Restricts the translation override to a specific business unit.
id_userinteger (FK)Optional. Restricts the translation override to a specific user.
date_createddatetimeTimestamp of record creation.
date_updateddatetimeTimestamp of last record update.

Schema ER Diagram

Rendering diagram...

How It Works: The Token System

When configuring user interface elements, user-facing name or title fields are populated with localization tokens instead of literal strings.

A localization token follows the format:

TEXT
${i18n.your_label_here}

The Life Cycle of a Localized Label

Key Registration

A developer or a system workflow registers a key in the ui_i18n database table. For example, registering entity.product.ui.title with the default value Product.

View/Component Configuration

The component (view, column, action, menu, or input) is saved with the token ${i18n.entity.product.ui.title} as its title.

Runtime Resolution

When a user requests the component, the frontend application detects the ${i18n....} format. It looks up the current user's active locale (e.g., German de) and queries the ui_i18n table for that label, resolving it to the value in value_de. If no translation exists, it falls back to the default value.


How "Create UI Entity" Handles Localization

When the Create UI Entity action is run on a database entity, it automatically configures all localization rules and records for the generated views. Instead of prompting for manual translation setup, the action reads the entity structure and registers the keys programmatically in the background.

For every generated UI element, the action:

  1. Translates the database technical name into a user-friendly format (e.g., changing id_product_category or product_category to a sentence-case display name).
  2. Performs a lookup in the ui_i18n table for the corresponding key. If the key does not exist, it inserts a new ui_i18n record.
  3. Saves the UI component referencing the dynamic localization token wrapper (e.g. ${i18n.entity.product.ui.title}) in its database fields.

Localization Key Structure

The system organizes localization keys into a strict hierarchical taxonomy under two root namespaces: entity and system.

YAML
entity:
  [entityName]:
    ui:
      title           # General UI title of the entity
    property:
      [propertyName]  # Titles for fields, columns, and relationships
system:
  ui:
    view_edit:
      title_new       # General edit view prefix for creating a record (e.g. "Add")
      title_edit      # General edit view prefix for modifying a record (e.g. "Edit")
      [specific-edit] # Other edit-specific actions or UI prompts
    view_search:
      [specific-search] # Search-specific grid controls or prompts

Why This Structure Was Chosen

This hierarchical convention was chosen for several critical architectural reasons:

  1. Namespace Separation (Isolation) Separating entity and system prevents naming collisions. System labels (such as general actions like "Add", "Edit", or "Search") are isolated from entity schema property names, allowing each entity to define fields independently.
  2. Algorithmic Key Generation Because the key format follows a predictable path pattern, the code generator and UI engine can dynamically calculate translation keys using simple string concatenation:
    • Entity title key: "entity." + entityName + ".ui.title"
    • Field/Property key: "entity." + entityName + ".property." + propertyName
  3. Component & Title Reusability This structure enables system views to assemble complex user-facing titles dynamically by combining system-level prefixes with entity-level titles. For example:
    • An Edit View's create title is saved as a concatenation: ${i18n.system.ui.view_edit.title_new} ${i18n.entity.product.ui.title}.
    • At runtime, this seamlessly resolves to "Add Product" in English or "Adăugare Produs" in Romanian. The system doesn't need to define separate full-sentence labels for every entity.
  4. Scoping and Management Cleanliness A structured key tree makes translation dashboards easier to build and navigate. Translators can easily search, filter, or bulk-export keys for a specific entity by query filtering on the path prefix (e.g. searching for keys starting with entity.invoice.property.).

Localization across UI Elements

Dynamic translation tokens are utilized across every layer of the user interface:

1. Search & Edit Views

  • Search View Titles: Saved as ${i18n.entity.[entityName].ui.title}.
  • Columns: Table headers use property-specific keys: ${i18n.entity.[entityName].property.[propertyName]}.
  • Filters: Input titles in the filter sidebar are bound to property keys.
  • Edit Form Inputs: Display titles are bound to property or relationship keys.

2. Actions & Entity Actions

  • Action Buttons: Custom action buttons displayed in search lists (ui_action) or detail forms (ui_entity_action) use translation keys for their label text (e.g., ui_action.name = "${i18n.action.invoice.send}").
  • Input Dialogs: If an action requests parameter inputs from the user, the parameter label is localized (e.g., ui_action_item.title = "${i18n.action.invoice.send.email_address}").

3. Menus & Dashboards

  • Navigation Menus: Main sidebar categories (menu_node) and individual sub-items (menu_node_item) reference localization labels for their display names (e.g., ${i18n.menu.sales}).
  • Dashboards: Dashboards can load custom layout grids or fetch menu lists dynamically from a backend workflow. When workflows return dashboard components, they can return the localization token (e.g. ${i18n.menu.item.inventory}) in their string responses, allowing the client interface to resolve and translate the text on the fly.

Architectural Advantages

  1. Zero-Code Runtime Customization Translations reside entirely in the ui_i18n database table, meaning translation text can be modified instantly by administrators on a live system without changing configurations, files, or executing build pipelines.
  2. Context-Sensitive & Tenant Overrides The database schema includes id_organization, id_business_unit, and id_user keys, which allow translations to be scoped:
    • Global default: entity.account.ui.title translates to Account.
    • Organization override: For an organization in the medical field, the same key translates to Patient.
    • User preference: Individual users can customize terminology to match their personal vocabulary.
  3. Optimized Network Payloads Views and page layouts are defined and transmitted once. The frontend translates elements locally on render, drastically reducing bandwidth and enabling the local caching of translation dictionaries.