# Internationalization

Celena's interface and content are translated through a simple JSON-based localization mechanism.

## Language detection

The `Celena\Core\I18n\Locale` class determines the active language in this priority order:

1. Query parameter `?lang=en` (if the language is in the available list);
2. cookie `celena_lang`;
3. the browser's `Accept-Language` header;
4. the default language (option `app.locale`, e.g. `en`).

The list of available languages is built automatically from the `core/languages/*.json` files. Currently these are `ru`, `en`, `uk`, `pl`, `ro`.

```php
$active = $locale->detect($request);  // 'en' | 'ru' | 'uk' | …
$locale->remember($active);           // remember in a cookie for a year
```

## Translation files

Strings are stored as JSON and loaded automatically from three places:

```
core/languages/{lang}.json
modules/<Module>/languages/{lang}.json
plugins/<slug>/languages/{lang}.json
```

The format is a nested object; keys are flattened with dots:

```json
{
  "landing": {
    "nav": { "services": "Services", "contact": "Contact" }
  }
}
```

→ available as the key `landing.nav.services`.

## Usage

In a template:

```html
{lang key="landing.nav.services"}
{lang key="greeting" name="{user.name}"}   <!-- :name substitution -->
```

In PHP:

```php
$t = app(\Celena\Core\I18n\Translator::class);
echo $t->translate('landing.nav.services');
echo $t->translate('greeting', ['name' => 'Anna']);
```

## Fallback

If a key is missing in the current language, it's taken from the fallback language (`en`); if it's missing there too, the key itself is returned. So an untranslated string never "breaks" the page.

## SEO for languages

The `template.globals` hook sets two variables for each page:

- `{locale}` — the current language for the `<html lang>` attribute;
- `{canonical_self}` — the self-referencing canonical: a clean URL for the default language, `?lang=xx` for the others.

Alternative language versions are declared via `<link rel="alternate" hreflang="…">`. A template can disable the default hreflang block by passing `no_hreflang="1"` and output its own (this is what the documentation section does, limiting the list to three languages).

## How to add a language

1. Create `core/languages/<code>.json` (e.g. `de.json`) — the language appears in the available list automatically.
2. Add the same file in the modules/plugins where translations are needed.
3. Optionally add an entry to the language switcher in the theme header.

## Translating the interface from the admin

The `Translations` module (the **Translations** section in the panel) lets you edit UI strings without hand-editing JSON.
