---
url: /develop/translations.md
---
# Translations

Evolve sites are multilingual by default. Three different things are translated, and each has its own mechanism.

## Block content

Page content lives in blocks, and every translatable block field stores one value per locale. Editors switch the language in the block editor; the theme renders the active locale and falls back to the fallback locale for fields left empty (empty repeatable fields fall back too, since 2.5). Nothing to set up: a field marked translatable in its blueprint behaves this way. Regions add a layer on top, see [Regions](/modules/regions).

## Model attributes

Records of modules (posts, members, events, projects, and the core's pages, navigation items, media and static strings) use [astrotomic/laravel-translatable](https://docs.astrotomic.info/laravel-translatable/). The pattern is a base table plus an `_i18n` table that holds one row per locale:

```php
Schema::create('acme_posts_i18n', function (Blueprint $table) {
    $table->id();
    $table->unsignedBigInteger('post_id');
    $table->string('locale')->index();
    $table->string('title');
    $table->text('body')->nullable();
    $table->unique(['post_id', 'locale']);
});
```

The model carries the `Translatable` trait and names the translated attributes; the translation model is the base name with an `I18n` suffix:

```php
use Astrotomic\Translatable\Translatable;

class Post extends Model
{
    use Translatable;

    public array $translatedAttributes = ['title', 'body'];
}

class PostI18n extends Model
{
    public $timestamps = false;
    protected $fillable = ['title', 'body'];
}
```

`php artisan evolve:resource acme/blog post --translatable` scaffolds exactly this: model, `I18n` model, both migrations, and a manager whose form shows one tab per active language. Reading `$post->title` returns the value for the current locale with the package's fallback rules; `$post->translate('fr')->title` reads a specific one. The active languages come from the Languages screen in the panel.

## Static strings

Texts that belong to the theme rather than to a record (button labels, footer lines, the cookie banner) are **static strings**, edited in the panel under System > Static strings and read in Blade with `__('key')`. A string maintained only in the fallback locale resolves on every language (since 2.11), so a site can start with one language and translate later. Strings the theme introduces register themselves on first use.

## Auto-translate

With `APP_AUTO_TRANSLATE=true` and a Google service account in `GOOGLE_APPLICATION_CREDENTIALS`, block fields show an auto-translate button that fills the current locale from the fallback locale through Google Cloud Translation. The result is a draft to review, not a translation to publish unread.
