Skip to content

Translator

Viames Marino edited this page Mar 26, 2026 · 2 revisions

Pair framework: Translator

Pair\Helpers\Translator is Pair’s localization singleton.

It is responsible for:

  • resolving the current locale
  • loading module, application, and framework translation files
  • returning translated strings with placeholder binding
  • providing small helpers for option lists and object collections

Translator is used constantly by Controller, View, Application, and many UI helpers.

Locale lifecycle

getInstance(): Translator

Returns the singleton translator.

getCurrentLocale(): Locale

getDefaultLocale(): Locale

Return the active locale and the default application locale.

On first use, the translator:

  • loads the default locale from configuration/data
  • uses that as the temporary current locale
  • optionally inspects HTTP_ACCEPT_LANGUAGE
  • switches to the browser-preferred locale if Pair can resolve it

setLocale(Locale $newLocale): void

Changes the active locale and reloads translation strings when needed.

Example:

use Pair\Helpers\Translator;
use Pair\Models\Locale;

$translator = Translator::getInstance();

// Loads one locale from your application data.
$locale = new Locale(2);

// Switches the current translator locale.
$translator->setLocale($locale);

resetLocale(): void

Resets the current locale back to the default one and reloads the strings cache.

getCurrentLanguageCode(): ?string

Convenience helper that returns the current language code, for example it or en.

Module scope and file loading order

setModuleName($moduleName): void

Defines the module namespace used for module-level translations.

Controllers do this automatically in their constructor, but it is useful in scripts, widgets, or custom rendering flows.

Example:

use Pair\Helpers\Translator;

$translator = Translator::getInstance();

// Forces module translation lookup under modules/orders/translations/.
$translator->setModuleName('orders');

Current loading order is important because the first matching key wins:

  1. APPLICATION_PATH/modules/<module>/translations/<current-locale>.ini
  2. APPLICATION_PATH/translations/<current-locale>.ini
  3. Pair framework translations/<current-locale>.ini
  4. the same three locations again for the default locale, when current and default locales differ

This means:

  • module strings override app/framework strings
  • current-locale strings override default-locale fallback strings
  • already-loaded keys are not overwritten by later files

Main translation method

Translator::do(string $key, string|array|null $vars = null, bool $warning = true, string|Callable|null $default = null): string

This is the main method of the class and the one you will use most often.

Behavior:

  • loads string files lazily
  • looks up the key in the merged string set built from current-locale files first and default-locale files later
  • if missing, optionally uses the provided $default
  • logs warnings for missing or invalid translations when $warning is true
  • binds %s placeholders through vsprintf()

Example:

use Pair\Helpers\Translator;

// Reads one plain translation key.
$title = Translator::do('WELCOME_TITLE');

// Binds placeholder values into a string like "Welcome, John".
$message = Translator::do('WELCOME_USER', ['John']);

// Returns a custom fallback string without exposing [MISSING_KEY].
$fallback = Translator::do('MISSING_KEY', null, false, 'Default text');

Missing-key behavior

The current implementation behaves like this:

  • if $default is a string, that string is returned
  • if $default is a callable, the callable result is returned
  • if the key exists in the merged translation set, it is returned immediately
  • if $warning is true and the key is still missing, the result is [KEY]
  • if $warning is false, the raw key is returned without brackets

Example with a callable fallback:

use Pair\Helpers\Translator;

// Builds a fallback dynamically when the translation key is missing.
$label = Translator::do(
    'UNKNOWN_STATUS',
    null,
    false,
    function (string $key): string {
        // Converts the key into a readable label.
        return ucwords(strtolower(str_replace('_', ' ', $key)));
    }
);

Utility helpers

stringExists($key): bool

Returns whether the key exists in the loaded translation set available to the current translator state.

translateSelectOptions(array $optSelect): array

Translates select-option labels when the text is uppercase and longer than three characters. This is intentional: labels already written as normal human text are left untouched.

Example:

use Pair\Helpers\Translator;

$translator = Translator::getInstance();

$options = $translator->translateSelectOptions([
    'paid' => 'PAID',
    'draft' => 'Draft',
]);

// "PAID" is translated, "Draft" is left as-is.

translateActiveRecordList(array|Collection $list, string $propertyName): array|Collection

Adds a translated property named translated<PropertyName> to each item in the list.

Example:

use Pair\Helpers\Translator;

$translator = Translator::getInstance();

// Adds translatedStatus to each item when status exists.
$orders = $translator->translateActiveRecordList($orders, 'status');

After this call, an item with property status will also expose translatedStatus.

getDefaultFileName(): string

Returns the default locale file name, for example it-IT.ini.

Practical pattern: module translation in a standalone script

use Pair\Helpers\Translator;

$translator = Translator::getInstance();

// Forces module-specific strings first.
$translator->setModuleName('orders');

// Reads a label using module -> app -> framework fallback order.
$statusLabel = Translator::do('ORDER_STATUS_PAID');

Secondary methods worth knowing

These methods are not called as often as do(), but they explain the translator lifecycle:

  • getCurrentLocale(): Locale Returns the current locale after lazy initialization.
  • getDefaultLocale(): Locale Returns the application default locale.
  • resetLocale(): void Clears the current string cache and reloads the default locale.
  • getCurrentLanguageCode(): ?string Convenient for templates, meta tags, and frontend bootstrapping.

Notes and caveats

  • Translator applies the active locale to PHP through setlocale(...).
  • Placeholder binding uses vsprintf(), so translation strings should use %s-style placeholders.
  • Invalid placeholder counts are logged as warnings instead of crashing the request.
  • Controllers usually set the module automatically; in scripts or widgets you may need to call setModuleName() yourself.
  • In the current implementation, default-locale files are merged into the main string set after current-locale files, so fallback keys are often returned silently once loaded.

See also: Controller, View, Application, Configuration-file.

Clone this wiki locally