> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flowxi.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Localization

Flowxi is **localization-first by design**.

Localization is not an optional layer or a frontend concern.\
It is a **core backend responsibility**, enforced **before any controller logic runs**.

Every API response, validation error, authentication message, and transactional email
is returned in **one single, deterministic locale** resolved at the **very beginning**
of the request lifecycle.

There is:

* no partial localization
* no mixed-language responses
* no runtime ambiguity

Everything is enforced by middleware and shared across controllers, validators, and mailers.

***

## Supported locales

Flowxi currently supports the following locales:

* `fr` — **default and mandatory fallback**
* `en`

Rules:

* Any unsupported locale is ignored
* Any malformed locale is ignored
* Resolution **always** falls back to `fr`

This behavior is enforced centrally and cannot be bypassed by controllers.

***

## Where localization happens (important)

Localization is resolved by the `SetLocaleFromRequest` middleware.

This middleware is:

* executed **before all controllers**
* applied to **all API routes**
* responsible for calling `app()->setLocale(...)`

Controllers **do not decide** the locale.\
They only **consume** the already resolved value.

***

## Locale resolution order (strict and deterministic)

For **every API request**, Flowxi resolves the locale using the following order:

1. **Custom header** `X-App-Locale`
2. **Standard header** `Accept-Language`
3. **Authenticated user locale** (`user.locale`)
4. **Fallback locale** (`fr`)

The **first valid supported locale wins**.

No later override is possible.

***

## 1) `X-App-Locale` (highest priority)

This is the **authoritative source of truth** for locale.

### Example

```http theme={null}
X-App-Locale: en
```

Behavior:

* Overrides all other sources
* Works for public and authenticated endpoints
* Used consistently for:

  * API `message`
  * validation messages
  * authentication & security errors
  * emails sent during the request

### Frontend rule (mandatory)

The frontend **must send `X-App-Locale` on every request**.

This includes:

* login
* registration
* authenticated calls
* background refresh calls

Do **not** rely on backend inference or browser defaults.

***

## 2) `Accept-Language` (secondary)

Used **only if** `X-App-Locale` is not present.

### Example

```http theme={null}
Accept-Language: en-US,en;q=0.9,fr;q=0.8
```

Parsing rules (exactly as implemented in middleware):

* Header is split by `,`
* `;q=` values are ignored
* `_` is normalized to `-`
* Region is stripped (`en-US` → `en`)
* First supported base language wins

### Resolution examples

| Header value     | Effective locale |
| ---------------- | ---------------- |
| `en-US,en;q=0.9` | `en`             |
| `fr-FR,fr;q=0.8` | `fr`             |
| `es,pt;q=0.9`    | fallback `fr`    |

If no supported language is found, Flowxi proceeds to the next step.

***

## 3) Authenticated user locale (`user.locale`)

If **no locale header is provided** and the request is authenticated:

* Flowxi checks `user.locale`
* If it matches a supported locale, it is applied

This is a **fallback mechanism**, not a preference.

Typical use cases:

* background API calls
* internal service calls
* recovery when headers are missing

It is **never** used if a locale header is present.

***

## 4) Fallback locale (guaranteed)

If no valid locale is resolved:

* Flowxi **always** falls back to `fr`

This fallback:

* is deterministic
* never throws
* guarantees a localized response in all cases

There is **no scenario** where a response is not localized.

***

## Effective locale lifecycle

Once the locale is resolved:

* `app()->setLocale(locale)` is executed
* The locale is stored as `effective_locale` on the request
* Controllers explicitly reuse this value
* Mailers receive the same locale via `->locale($lang)`

There is **exactly one locale per request**.

No controller, validator, or mailer can override it later.

***

## What is localized

The resolved locale applies to **all user-facing content**, including:

* `message` in API responses
* validation error messages
* authentication and security errors
* transactional emails:

  * magic link emails
  * email OTP codes

### Example

```json theme={null}
{
  "message": "Invalid credentials.",
  "code": "INVALID_CREDENTIALS"
}
```

Same request with `X-App-Locale: fr`:

```json theme={null}
{
  "message": "Identifiants invalides.",
  "code": "INVALID_CREDENTIALS"
}
```

Only the message changes.
The `code` remains identical.

***

## What is NOT localized (by design)

The following elements are **never translated**:

* `code` values
* enum values
* JSON keys
* request field names

These are part of the **API contract**.

Frontend logic must **always rely on `code`**, never on translated text.

***

## Email localization (guaranteed)

All authentication-related emails explicitly use the resolved locale.

Mechanism:

* Locale resolved by middleware
* Controller reads `effective_locale`
* Emails are sent using:

  * `Mail::to(...)->locale($lang)`
  * localized Blade views
  * translated strings via `__()`

Result:

* Email language **always matches API language**
* No mismatch between UI and inbox content

***

## Frontend integration examples

### Axios

```ts theme={null}
api.interceptors.request.use((config) => {
  config.headers["X-App-Locale"] = getUserLocale(); // "fr" | "en"
  return config;
});
```

***

### Fetch API

```ts theme={null}
fetch("/api/v1/auth/login", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-App-Locale": "en",
  },
  body: JSON.stringify(payload),
});
```

***

### Authenticated requests

```http theme={null}
Authorization: Bearer <token>
X-App-Locale: fr
```

Never drop the locale header after login.

***

## Frontend responsibilities

The frontend is responsible for:

* letting the user choose a language
* storing it client-side
* sending it on **every request**

Updating `user.locale` server-side is optional and used **only as a fallback**.

***

## Guarantees

Flowxi localization guarantees:

* exactly one locale per request
* no mixed-language responses
* mandatory fallback to `fr`
* consistent API and email language
* no reliance on browser heuristics
* deterministic, testable behavior

***

## Testing checklist

* Send `X-App-Locale: fr` → verify French everywhere
* Send `X-App-Locale: en` → verify English everywhere
* Remove all locale headers → fallback to `fr`
* Authenticated request without headers → uses `user.locale`
* Verify magic link and OTP emails match API language
