Haiku's Locale Kit: Catalogs, Formatting, and Runtime Language Selection
A practical guide to Haiku's translation catalogs, fallback rules, locale-aware number and date formatting, collation, and UI testing.
Internationalizing a Haiku application requires two related but different systems. Translation catalogs select human-language strings, while locale objects and formatters express numbers, money, percentages, dates, times, and sorting according to the user’s conventions. Replacing English labels is necessary, but it is not sufficient: an interface can be fully translated and still display an ambiguous date, sort names incorrectly, or clip every long button label.
The Locale Kit supplies native APIs for both parts. BCatalog loads strings associated with an application, library, add-on, or signature. BLocale represents language and formatting conventions, and specialized formatter classes turn program values into localized presentation. The Interface Kit’s Layout API then helps controls adapt to the resulting text instead of assuming one English label width.
Catalogs separate source text from displayed text
BCatalog is Haiku’s string-localization class. Its documented GetString() interface can look up a source string together with optional context and a translator comment, or retrieve an entry by numeric identifier. Most application code does not instantiate catalogs directly; it uses macros defined by the Locale Kit so the same source expressions can be found by catalog-generation tools and resolved at runtime.
A source file defines B_TRANSLATION_CONTEXT to identify the area of the program in which its strings appear. Code then wraps visible source strings in B_TRANSLATE(). When the application runs, that macro obtains the appropriate entry from its catalog. When localization tools scan the source, the macro marks the string as translatable. Haiku’s Catalog.h also defines variants for an explicit context or translator comment and a marking macro for strings that should be collected but translated at a different point.
Context is not decorative metadata. The English word “Open” may be a verb on a button, an adjective describing a connection, or part of a status. A translator cannot reliably choose grammar from the isolated word. Distinct contexts allow identical source text to receive different translations. A concise translator comment can explain placeholders, keyboard conventions, or where the string appears, reducing guesswork without embedding implementation details into the translation.
The BCatalog API can also open a catalog explicitly using an application MIME signature or an entry_ref for the catalog owner. The direct path is useful for tools that manage catalogs or software that localizes content belonging to something other than its own image. Normal application strings should use the macros, which keep lookups and extraction consistent.
Catalog identity and fallback protect the interface
Catalogs belong to a particular application, library, or add-on rather than one global table of translations. The owner and its application signature help the Locale Kit locate the relevant data. The API also exposes a fingerprint mechanism that can distinguish catalog versions; documentation notes that a fingerprint of zero disables that check. Version matching matters because an old catalog may no longer contain newly introduced strings or may describe placeholders differently.
Haiku’s catalog documentation defines a language fallback chain. The system first seeks the user’s preferred regional language, then a more generic version of that language where applicable, then follows the configured preferred-language list. If no usable translation is found, the source string is the final fallback. A missing entry should therefore show meaningful source text rather than an empty control.
That behavior does not excuse incomplete catalog testing. A mixed-language interface may be technically functional but confusing. Test a complete catalog, a deliberately partial catalog, and the absence of a catalog. Confirm that source strings remain readable and that a stale translation cannot change the meaning of a command. Status text and destructive-action labels deserve the same localization review as menu items.
Each image using the translation macros must be prepared and linked as documented. The BCatalog reference says applications, libraries, and add-ons using the macros link with liblocalestub.a, which lets the Locale Kit identify the image and locate matching catalogs. Build rules and catalog tools should remain part of the project rather than a manual release-day procedure; otherwise newly added source text can silently miss translation extraction.
Locale-aware formatting is not string substitution
BLocale combines language information with formatting conventions. Its API provides access to a BLanguage, a BFormattingConventions object, and a collator. This separation reflects a real user need: the language used for words and the regional conventions used for dates or numbers are related but not identical choices.
BNumberFormat formats integer and floating-point values and has dedicated operations for monetary values and percentages. Application code should keep the numeric value as a number until presentation time, then ask the formatter to produce text. Manually inserting commas, periods, currency symbols, or percent signs hardcodes assumptions about grouping, decimal separators, symbol placement, and spacing.
Dates and times have the same issue. BDateTimeFormat accepts a time value, date and time styles, and, in one overload, a BTimeZone. The result reflects the chosen locale conventions. A hardcoded sequence such as month/day/year is ambiguous internationally, and simply translating month names does not fix the order. Store an absolute or well-defined temporal value, decide which time zone the product means, and localize only at the display boundary.
Format styles are preferable to handcrafted patterns for general user-facing text because the locale implementation can choose an appropriate short or long representation. Machine protocols and persistent file formats are different: they should use an explicitly specified, locale-independent representation so changing the user’s settings never corrupts parsing. The boundary between storage and presentation must be deliberate.
Collation differs from byte ordering
BLocale supplies locale-sensitive collation through BCollator. Sorting strings by raw UTF-8 bytes or code-point order does not generally produce the order readers expect in a given language. Accents, case, and language-specific letter relationships affect comparison. A file list, address book, or menu that displays localized names should use the locale’s collator when the promised ordering is linguistic.
Collation and identity are different jobs. A database key, package name, or protocol identifier needs stable, locale-independent rules; a user’s visible alphabetical list needs culturally meaningful order. Applying locale collation to persistent identifiers can make behavior change when preferences change, while applying byte order to names can make the interface look broken. Keep a stable key and a localized sort key or comparator where both requirements exist.
Search requires its own product decision. Collation may define ordering without defining every equivalence users expect in substring matching. Do not assume that a case-insensitive byte transformation reproduces a locale’s linguistic rules. Document whether search is exact, case-insensitive, or language-aware, and test it with the scripts and accents the application actually supports.
Write source strings translators can preserve
Avoid building sentences from separately translated fragments. Grammar can reorder verbs, nouns, counts, or modifiers, and a translator cannot move text across independently looked-up controls. Prefer a complete semantic message with clearly documented substitutions. If several outcomes require different grammar, give them separate source strings rather than forcing one concatenation pattern.
Placeholder contracts must remain stable. A translator comment should explain whether a value is a filename, person, count, or keyboard shortcut and whether markup must remain intact. Code should verify that translated catalog entries contain the placeholders it will supply. A translation that drops or duplicates a format placeholder can be a functional defect, not merely awkward wording.
Do not embed layout padding, alignment spaces, or punctuation outside the translatable unit unless the punctuation is truly structural. Quotation style and spacing can vary. Likewise, avoid using an English label as an internal identifier. Menus, settings, and messages need stable programmatic constants that are independent of the displayed catalog string.
Layout and runtime testing complete the work
Translated text regularly expands, and the same language can render differently with another system font. Interface Kit layouts calculate placement from control size requirements, making them a better default than rectangles measured around English text. Windows should remain usable when a label wraps or grows, and important controls must not fall outside the reachable area.
Test more than two closely related Latin locales. Use at least one catalog with substantially longer labels, one locale with different number separators, and one language using a different script. Verify menu widths, button groups, text alignment, shortcuts, truncation, and dialog resizing. Haiku’s current documentation and community translation status should guide which shipped catalogs are suitable test targets; do not claim right-to-left support merely because a catalog exists.
Language changes also require a lifecycle decision. Some text is created once when a window is constructed; changing the system preference does not magically rebuild every existing label. Test the behavior Haiku documents for newly launched applications and decide whether your program requires a restart or explicitly rebuilds its interface. State that behavior rather than leaving users to infer it from partially changed screens.
A solid localization review therefore checks four layers: source strings are extractable and contextual, catalogs load and fall back safely, values use locale-aware formatters and collators, and layouts survive the resulting output. Treating all four as code quality—not a final translation pass—keeps one application binary usable across the language and regional preferences Haiku was designed to support.
Related:
- Haiku’s Translation Kit: Roster-Based Media Conversion Between Applications
- Haiku’s Kit-Based API: Application, Interface, Storage, and Media Kits
Sources: