# 5. Language and reading direction #

← Themes · Contents · Cross-cutting features →

The components carry interface labels of their own: context menus, dialog buttons, dockable panel actions, toolbar tooltips… Those strings are translated by the library, without you having to supply them.

## 5.1 Choosing the language #

The language is global to the process. Set it once in the application object, before the first window opens:

    // open event of the application object
    PBT_SetLanguage("fr")

Code | Language
--- | ---
`en` | English (default)
`fr` | French
`de` | German
`it` | Italian
`es` | Spanish
`pt` | Portuguese

The dictionary is injected before the first render of each component: no English label flashes before the translation appears. Switching on the fly is possible — every open component is relabeled immediately.

    // Language switch from a menu in the application
    PBT_SetLanguage("de")

> A language cannot be set component by component: an application displays one language at a time. This is a deliberate choice (interface consistency), unlike the theme, which can be overridden locally.

## 5.2 Adapting a label: `of_set_translation` #

You are not locked into the dictionaries we ship. `of_set_translation(key, text)` overrides an interface string, taking priority over the language dictionary:

    // Business vocabulary: say "panes" rather than "panels"
    uo_dock.of_set_translation("dock.float", "Detach the pane")
    uo_dock.of_set_translation("dock.autohide", "Hide the pane")
    uo_dock.of_set_translation("dock.closePanel", "Close the pane")

Two use cases:

- Adapting the vocabulary to your application's business domain ("panes" rather than "panels", "branches" rather than "groups").
- Serving a language we do not ship: set your own translations key by key, in whatever language you need, from your own translation table.

    // Feed a custom language from your own translation repository
    uo_dock.of_set_translation("dock.float", of_traduire("DOCK_DETACHER"))
    uo_dock.of_set_translation("dock.show",  of_traduire("DOCK_AFFICHER"))

The override is set on the instance; it is cancelled by `of_reset()`.

### Key families #

Keys follow the `<domain>.<name>` pattern. The main families:

Prefix | Covers
--- | ---
`dock.*` | Dockable panels: float, hide, close
`toolbar.*` | Toolbar: move the bar, overflow
`tab.*` | Tabs: close
`tile.*` · `tilesbox.*` | Tiles: sizes, "no tile" message
`ribbon.*` | Ribbon: collapse, expand
`mb.*` | Message box: standard buttons, show / hide the password
`webbrowser.*` | Web browser: context menu (back, forward, reload)
`picture.*` | Picture: pan hint
`sb.*` | Status bar: its name for screen readers
`color.*` | Color picker: OK / Cancel

> 💡 To find the exact key behind a label, open the demo application in English and then in another language: the string that changes is the one from the dictionary. The complete key list ships with the library.

## 5.3 Reading direction: left-to-right / right-to-left #

For languages written from right to left (Arabic, Hebrew), a single call flips the whole application:

    // open event of the application object
    PBT_SetFlowDirection("rtl")     // "ltr" by default

What this changes in every component, present and future:

- the natural alignment of text and labels;
- the order of columns, tabs and toolbar buttons;
- the side of icons, expand arrows and chevrons;
- the side of scroll bars and side panels;
- the direction of drop-down menus and popups.

    // Switch on the fly
    PBT_SetFlowDirection("ltr")

Like the theme and the language, the reading direction is injected before the first render: a component created after the switch is born in the right direction.

> ⚠️ The reading direction only applies to PBToolboxAI components. The native PowerBuilder controls on your windows (edit fields, DataWindows) remain your responsibility.

## 5.4 Writing RTL-ready code #

Mirroring is automatic for the layout. It cannot be for the values you set yourself: if you hard-code `"left"`, it will be on the left in both reading directions.

That is why every placement property in the library uses logical values rather than physical ones:

Logical value | In left → right writing | In right → left writing
--- | --- | ---
`start` | on the left | on the right
`end` | on the right | on the left

They are exposed as constants, to be read on the object you are assigning the value to:

    // Text alignment, position of a banner...
    uo_titre.is_align      = uo_titre.ALIGN_START
    uo_onglets.is_position = uo_onglets.POSITION_START

The families involved: `ALIGN_START` / `ALIGN_END` (statictext, statusbar, picture), `POSITION_START` / `POSITION_END` (tab, dockcontainer), `MARQUEE_START` / `MARQUEE_END` (statictext).

> The old physical values `"left"` and `"right"` are still accepted everywhere: your existing code keeps working exactly as before. They are simply frozen — they will not flip in `rtl`.

### The two deliberate exceptions #

Some placements have no "start of reading": they stay physical, and that is intentional.

- Toaster — a toast is a system window anchored to a corner of the screen. `POSITION_BOTTOM_RIGHT` designates a physical corner, not the end of a line of text.
- Drawing surfaces — org chart, flow diagram, node graph, image cropping: there you place elements at `x`/`y` coordinates. A Cartesian plane does not flip with the language; only the labels inside it follow the reading direction.

## 5.5 Summary #

Setting | Scope | Where to call it
--- | --- | ---
`PBT_SetLanguage (string as_lang)` | Whole process | `open` of the application object
`of_set_translation (string as_clé, string as_texte)` | One instance | After the component is created
`PBT_SetFlowDirection (string as_sens)` | Whole process | `open` of the application object

The three global settings — theme, language and reading direction — are set together, in the same place:

    // open event of the application object
    PBT_SetLicense(gs_titulaire, gs_cle_licence)
    PBT_SetDefaultTheme("fluent-light")
    PBT_SetLanguage("fr")
    PBT_SetFlowDirection("ltr")
    PBT_Warmup()

    Open(w_principale)

← Themes · Contents · Cross-cutting features →