Skip to content
Nav

Using translations

composer require langsys/langsys-php-laravel
Packagist version Monthly downloads License PHP 8.1+ Laravel 10 / 11 / 12

The signature mirrors the JS SDKs: t($phrase, $category?, $params?, $locale?). The phrase is both the lookup key and the base-language default — no keys file.

<h1>@t('Welcome to my app', 'UI')</h1>
<p>@t('Hello, {name}! You have {count} new messages.', 'Greetings', ['name' => $name, 'count' => $count])</p>
// Controllers, Livewire components, jobs, mail — anywhere:
$title = t('Order confirmed', 'Checkout');
$body = t('Your order {id} ships on {date}.', 'Checkout', ['id' => (string) $order->number, 'date' => $order->ships_at]);

Output through @t is HTML-escaped like {{ }}.

{name} placeholders use the same syntax as the JS SDKs, so the same phrase translates once and renders everywhere. Numbers and DateTimeInterface values are CLDR-formatted for the target locale (pass strings to opt out), and ICU MessageFormat pluralization gives correct categories per language:

t('{count, plural, one {# item} other {# items}}', 'Cart', ['count' => $count]);

Unknown placeholders are left visible rather than rendering empty.

Interpolation itself lives in langsys/langsys-php, so Blade, plain PHP, and the JS SDKs all render a shared phrase identically.

<strong>@t('Home', 'Main Menu')</strong> {{-- "Inicio" --}}
<strong>@t('Home', 'Home repairs')</strong> {{-- "Hogar" --}}

DetectLocale tries the configured sources in order (query, cookie, session, header by default), canonicalizes the winner to BCP 47, and sets it on both the Laravel app and the Langsys client. Accept-Language parsing is delegated to the SDK’s LocaleDetector::fromAcceptLanguage(), so it honours q-value priority (en,es-MX;q=0.9 resolves to en), rejects q=0 as “not acceptable” per RFC 7231, and fills a missing region (en → en-EN), since the Langsys API addresses translations by xx-yy codes. An explicit ?locale=es-ES choice persists via cookie (or session — see config/langsys.php). The locale cookie is exempted from cookie encryption so client-side JS can share the preference.

With a write key, phrases that miss the catalog are queued in-memory during the request and flushed to Langsys after the response is sent — by the terminable middleware under PHP-FPM, and by a RequestTerminated listener under Octane (where PHP’s shutdown handlers never fire between requests). Read-only keys skip the flush silently. Disable with LANGSYS_AUTO_FLUSH=false and flush manually via app(\Langsys\SDK\Client::class)->flushPendingRegistrations().

Nothing extra to configure: Livewire’s AJAX updates run through the same web middleware, so t() inside components resolves in the page’s locale and newly discovered phrases flush after every update.

class Checkout extends Component
{
public function getTitleProperty(): string
{
return t('Review your order', 'Checkout');
}
}
Feedback