Skip to content
Nav

Translate a phrase

composer require langsys/langsys-php
Packagist version Monthly downloads License PHP 7.4+

The translate() method both translates and automatically queues new phrases for registration:

$client->setLocale('es-es');
$text = $client->translate('Home');
$text = $client->translate('Home', 'es-es');
$text = $client->translate('Home', 'es-es', 'UI');
$text = $client->translate('Home', null, 'UI');
$text = $client->translate('Menu Item', 'es-es', 'Navigation', 'content-block-id');
$text = $client->translate('Hello, {name}!', null, 'UI', null, ['name' => 'Sarah']);

If the phrase doesn’t exist in translations, it will be:

  1. Queued for registration (if write key)
  2. Returned as-is (fallback to original)
  3. Added to in-memory cache to prevent re-queueing in the same request

Pass dynamic values via the $params argument rather than building the string yourself. Placeholders use {name}, the same canonical form the Langsys JS SDKs store, so a shared catalog renders identically from a PHP backend and a JS frontend.

Placeholders work in phrases, content blocks and whole pages:

$client->translate('Hello, {name}!', null, 'UI', null, ['name' => 'Sarah']);
$client->translateContentBlock('<p>Welcome back, {name}</p>', 'homepage', ['name' => 'Sarah']);
$client->translatePage($html, 'homepage', [], ['name' => 'Sarah']);

In translateContentBlock(), placeholders resolve in text nodes and in translatable attributes (placeholder, alt, title, …).

CaseResult
Unknown keyLeft verbatim ({name} stays {name})
Key present but nullAlso left verbatim
{ name }Whitespace tolerated
String valuePassed through untouched — the opt-out from number formatting (IDs, codes)
Int / floatFormatted for the locale (1234.5 → 1.234,5 in de-DE)
Bool"true" / "false"
DateTimeInterfaceLocale-formatted, medium date style
Phrase not translated yetFallback text still interpolates, so users never see raw {name}

The phrase registered with Langsys always keeps its placeholders — interpolation only affects what your code receives.

Full ICU is supported, so plural categories are correct per language — Russian’s four, Arabic’s six:

$client->translate(
'{n, plural, one {# item} other {# items}}',
'ru-RU', null, null, ['n' => 21]
);

Requires the intl extension. If intl is disabled at runtime the SDK logs a warning naming the phrase and falls back to simple {name} substitution rather than failing the render. Malformed ICU also falls back rather than throwing.

Two spellings, both author-facing and equivalent:

<code translate="no">rm -rf /</code>
<div data-notrans>Internal build id: 4f2a91</div>

translate="no" is the standard HTML attribute. data-notrans is an alias for hosts whose templating strips unknown bare attributes, or where translate collides with another tool.

For data-notrans, presence alone is intent — the bare attribute works like any boolean HTML attribute — and only an explicit "false" or "0" opts out (case-insensitive). Excluded subtrees are never extracted, never registered, and never rendered over.

This is also the right way to tell translatePage() that a subtree is already translated. Without it, page translation looks up the already-translated string as a source phrase, misses, and registers it, putting translated text into the catalog as a new source phrase.

Keeping a run together with data-langsys-phrase

Section titled “Keeping a run together with data-langsys-phrase”

By default, page translation splits at tag boundaries, so this becomes two catalog entries — "Based on {n}" and "reviews":

<p>Based on {n} <strong>reviews</strong></p>

That puts the count in a different phrase from the noun it inflects, and no plural rule can reach across the boundary. Mark the element to register the whole run as one phrase:

<p data-langsys-phrase>Based on {n} <strong>reviews</strong></p>

The catalog then receives a single entry with markup tokens:

Based on {n} {m0o}reviews{m0c}

{m0o} / {m0c} are the opening and closing positions of the first element. Translators may move them, and the markup is rebuilt where the tokens end up. If a translation drops, unbalances or misnumbers the tokens, the text is rendered without the markup rather than failing.

This is the same wire format as the JS SDK’s <Phrase> component, so entries registered by either SDK are usable by the other.

Feedback