Sheath rule
blade-prefer-lang-helper
{{ __() }} over the @lang directive.
as a dangerous fix. See Auto-fix.
Part of the migration preset.
#Why
@lang('key') and {{ __('key') }} perform the same lookup, and Laravel's
localization documentation uses the helper throughout. Settling on one keeps a
search for a translation key finding every use of it.
The forms differ in how they escape output:
| Form | Compiles to | Escapes |
|---|---|---|
@lang('key') |
echo app('translator')->get('key') |
No |
{{ __('key') }} |
echo e(__('key')) |
Yes |
{!! __('key') !!} |
echo __('key') |
No |
@lang renders translations without escaping them. The helper form escapes by
default.
#Examples
#Bad
<h1>@lang('messages.welcome')</h1>
<p>@lang('messages.greeting', ['name' => $user->name])</p>
#Good
<h1>{{ __('messages.welcome') }}</h1>
<p>{{ __('messages.greeting', ['name' => $user->name]) }}</p>
{{-- When the translation really does contain markup --}}
<p>{!! __('messages.terms_html') !!}</p>
#Auto-fix
The fix is dangerous and only runs under --fix --dangerous, because it
adds escaping that was not there before. A translation string containing HTML
renders as markup through @lang and as visible tags through {{ }}.
{{-- before --}}
@lang('messages.welcome')
{{-- after --}}
{{ __('messages.welcome') }}
Review the run. Where a translation is meant to carry markup, change those to
{!! __('...') !!} rather than reverting to @lang.
Review translations inside <script> tags manually. HTML escaping can turn an
apostrophe into visible entity text such as '. Move the translation out of
the script when possible, or use {!! __('...') !!} when raw output is
intentional.
#What is never rewritten
The block form is a different directive. It compiles to
$__env->startTranslation() and translates its own body, so it is left alone:
@lang(['name' => $user->name])
Welcome back, :name.
@endlang
@lang with no arguments opens the same kind of block, and is also left alone.
#Notes
- Reported wherever a standalone
@langappears, including inside an attribute. - Arguments are carried over exactly as written.
- Both forms are current Laravel. This is a consistency preference rather than a defect check.
#Related Rules
- security-no-raw-echo - the raw echo
@langperforms without saying so