skip to content

Localization

Laravel translates interface text from lang/ files through __() and trans_choice(), and picks each request's locale with App::setLocale. Interviewers probe multi-language requirements.

on this pageshow

explore

questions

11

In Laravel 13, where is the application's default locale configured, and how do you switch the locale for the current request?

level: juniorimportance: must knowfreq 55%

answer

  1. a key in config/app.php
  2. APP_LOCALE in .env, default en
  3. a setter on the App facade
  4. currentLocale() and isLocale()
  5. nothing is persisted

basics

~10 s

The default is the locale key in config/app.php, read from APP_LOCALE and defaulting to en. App::setLocale('es') switches it for the rest of the current request; App::currentLocale() and App::isLocale('es') read it back.

solid answer

~40 s

The skeleton's `config/app.php` holds `'locale' => env('APP_LOCALE', 'en')`, so you normally set `APP_LOCALE` in `.env` rather than editing the file. At runtime `App::setLocale('es')` switches it: it writes `app.locale` in the in-memory config, sets the translator's locale, and dispatches a `LocaleUpdated` event. `App::currentLocale()`, an alias of `getLocale()`, returns the value and `App::isLocale('es')` compares against it. Nothing is stored: the next request boots from config again, so a per-user or per-URL choice has to be re-applied on every request, usually in middleware. `setLocale` rejects only values containing a slash, a backslash, `..` or a null byte, so check user input against your supported list first.

code

php · 13 lines
php
<?php

use Illuminate\Support\Facades\App;

App::currentLocale();   // 'en' (from APP_LOCALE)

App::setLocale('de');

App::currentLocale();   // 'de'
App::isLocale('de');    // true
__('hr.leave_request'); // read from lang/de/hr.php

// the next request starts again at 'en'

go deeper

for a junior

Recall config/app.php's locale key, APP_LOCALE in .env, App::setLocale() for the current request, and currentLocale()/isLocale() to read it.

for a middle

Explain what setLocale() does in order: config value, translator locale, LocaleUpdated event, and why nothing persists between requests.

for a senior

Point out the traps that ship bugs: request-level setLocale, raw config writes after the translator is built, env() in code, and unvalidated user input.

for a principal

Decide where locale state lives across web requests, APIs and background work so every entry point applies it the same way.

## The configured default Every Laravel application has one **default locale**, the language used for translations when nothing else has chosen one. In the Laravel 13 skeleton it lives in `config/app.php`: ```php 'locale' => env('APP_LOCALE', 'en'), ``` So the usual way to change it is an entry in `.env`: ```ini APP_LOCALE=de ``` Because `env()` is called inside a config file, the value survives `php artisan config:cache`: the cached config already holds the resolved string. ## Switching at runtime `App::setLocale($locale)`, the facade call for the application's `setLocale()` method, changes the locale for the rest of the current request. In order, it: 1. writes the new value to the in-memory config key `app.locale`; 2. sets the translator's current locale, so later `__()` calls use it; the translator throws an `InvalidArgumentException` here for a value containing `/`, a backslash, `..` or a null byte; 3. dispatches `Illuminate\Foundation\Events\LocaleUpdated`, carrying the new `locale` and the `previousLocale`. Anything listening for that event can follow the change. Carbon's own Laravel service provider, which is package-discovered, listens for it and switches Carbon's locale to match. ## Reading the locale | Call | Returns | |---|---| | `App::currentLocale()` | the current value of `app.locale` | | `App::getLocale()` | the same value; `currentLocale()` is an alias | | `App::isLocale('de')` | `true` when the current locale equals the argument | | `App::getFallbackLocale()` | the value of `app.fallback_locale` | Use these rather than `config('app.locale')` so code reads as intent and survives a future change of storage. ## Why the choice does not persist Under PHP-FPM each request boots the application from scratch and reads `app.locale` from config again. `setLocale` changes memory only; it writes no cookie, session value or database row. A user's choice therefore has to be **stored somewhere** and **re-applied on every request**: typically a middleware reads a user column, a URL segment or the `Accept-Language` header and calls `App::setLocale()` before the controller runs. ## Validating input `setLocale` accepts any string without path characters, including codes you have no translations for, such as `xx`. The translator then misses every line and falls back, and pluralization rules for an unknown code choose the first form. Always check a user-supplied value against a list of supported locales before passing it on. ## Pitfalls - **`$request->setLocale('de')`** sets the locale property of the HTTP request object (inherited from Symfony's request class); it does not touch the translator, so `__()` output is unchanged. - **`config(['app.locale' => 'de'])`** writes config but, once the translator has been built, does not update it; only `App::setLocale()` does both and fires the event. - **Calling `env('APP_LOCALE')` in application code** returns `null` once config is cached, because `.env` is no longer loaded; read the config value or `App::currentLocale()` instead. - **Setting the locale in a controller** works for that action but is easy to forget elsewhere; a middleware keeps it in one place. ## Where it fits in a request A typical request on a multilingual site goes through these stages: 1. The application boots and the translator starts at `app.locale`. 2. A middleware decides the request's language from a stored preference, a URL segment or a header, and calls `App::setLocale()`. 3. Controllers, views, validation messages and anything else that translates now use that locale. 4. The response is sent and the in-memory state is discarded. Because stage 2 happens on every request, the decision must be cheap: read a column already loaded with the user, a route parameter or a header, not a remote service. ## Checking it on a running app - `php artisan about` lists the configured `Locale` among the environment details. - `php artisan config:show app` prints the whole `app` config, including `locale`, `fallback_locale` and `faker_locale`. - In a feature test, call `App::setLocale('de')` inside the test, request a page and assert the German text, so the expectation is explicit rather than dependent on `.env`.

  • How can other code react when the locale changes mid-request?
    Listen for `Illuminate\Foundation\Events\LocaleUpdated`, which `App::setLocale()` dispatches with the new `locale` and the `previousLocale`. Carbon's package-discovered service provider already listens for it and switches Carbon's locale; your own listener could, for example, reconfigure a formatting service.
  • What happens if a request calls App::setLocale('../etc')?
    The translator's `setLocale()` throws an `InvalidArgumentException` for values containing a slash, a backslash, `..` or a null byte, because the locale becomes part of a file path. Any other string is accepted, which is why you still need an allowlist.
  • Why is isLocale('de') preferable to comparing config('app.locale') directly?
    It reads as intent and goes through the application's own accessor, so the check keeps working however the locale is stored. Functionally both compare the current `app.locale` value.

saying these in an interview costs you the question

  • App::setLocale() saves the choice so later requests use it too
  • $request->setLocale('de') changes the language of __() output
  • config(['app.locale' => 'de']) always updates the translator
  • setLocale() throws for any locale without a lang folder
  • The default locale is set in bootstrap/app.php
open as a page

In Laravel, how do you define a translation line in lang/{locale}/messages.php and read it with __(), and what comes back when the key is missing?

level: juniorimportance: must knowfreq 62%

basics

~10 s

Create lang/{locale}/messages.php returning a keyed array and call __('messages.welcome'). If neither the current nor the fallback locale has that line, __() returns the key string itself instead of throwing.

open as a page

On a multinational Laravel HR portal, how would you apply each employee's saved language on every request, falling back to the browser's Accept-Language?

level: middleimportance: must knowfreq 45%

basics

~10 s

Write a middleware that takes $request->user()?->locale when it is supported, else $request->getPreferredLanguage($supported), and calls App::setLocale(). Append it to the web group so it runs after the session starts and the employee is known.

open as a page

In Laravel, when would you keep translations in lang/es.json rather than lang/es/*.php group files, and how does __() decide which one to read?

level: middleimportance: must knowfreq 48%

basics

~20 s

Use lang/es.json, keyed by the original sentence, for many UI strings; use PHP group files for stable short keys and nested arrays. __() checks the locale's JSON file first, then parses the key as group.item.

open as a page

In a Laravel translation string, how are :name, :Name and :NAME placeholders filled, and what happens to a placeholder you do not pass?

level: juniorimportance: should knowfreq 38%

basics

~20 s

Pass an array as the second argument, __('messages.thanks', ['name' => 'ana']). Laravel replaces :name as given, :Name with the first letter uppercased and :NAME fully uppercased; a placeholder with no value stays in the output literally.

open as a page

In Laravel's config/app.php, what do locale, fallback_locale and faker_locale each control, and which environment variables set them?

level: middleimportance: should knowfreq 32%

basics

~10 s

locale (APP_LOCALE, default en) is the starting translation locale; fallback_locale (APP_FALLBACK_LOCALE, default en) supplies group-file lines the active locale lacks; faker_locale (APP_FAKER_LOCALE, default en_US) only sets the language of fake() and factory data.

open as a page

In Laravel, how would a middleware take the locale from a /{locale}/ URL segment without shifting every controller action's parameters?

level: middleimportance: should knowfreq 30%

basics

~10 s

Read $request->route('locale'), reject unsupported codes, call App::setLocale(), then $request->route()->forgetParameter('locale') so actions do not receive it. URL::defaults(['locale' => $locale]) lets route() fill the segment in generated links.

open as a page

Translating a Laravel charity site into Spanish and Polish, how do trans_choice() and |-separated or range plural strings pick the right form?

level: middleimportance: should knowfreq 42%

basics

~20 s

trans_choice() splits the line on |, returns the first segment whose {n} or [a,b] condition matches the count, and otherwise uses the locale's plural rule to pick an index. Polish needs three forms, Spanish two.

open as a page

Why can a Laravel queue worker produce one employee's payslip in another employee's language after a job calls App::setLocale(), and how do you prevent it?

level: seniorimportance: should knowfreq 28%

basics

~10 s

queue:work reuses one booted application for many jobs, and App::setLocale() changes its in-memory config and translator, so the next job inherits it. Restore the previous locale in finally, or pass the locale to __().

open as a page

A Laravel charity site's Polish pages show raw keys like donations.thanks and some English sentences; how do you find and prevent missing translation keys?

level: seniorimportance: should knowfreq 30%

basics

~10 s

A raw group.key means neither Polish nor the fallback locale has that PHP line; an English sentence means pl.json lacks a JSON key. Catch them with Lang::handleMissingKeysUsing() and a test comparing keys with Lang::hasForLocale().

open as a page

In Laravel, how do you change a package's translation lines without editing vendor/, and what should the override file contain?

level: middleimportance: nice to knowfreq 20%

basics

~10 s

Create lang/vendor/{namespace}/{locale}/{group}.php containing only the lines you want to change. Laravel merges it over the package's own file, so every line you leave out still comes from the package.

open as a page