Link to the repository
[Only for premium members]
[Only for premium members]
We've covered translations for static text and routes, but what about the Models? What if we have a Blog Post that we want to store in a multi-language format?
There are quite a few ways to do this, but first, let's look at the simplest way without any packages:

For this demo, we will create Posts in multiple languages. The idea here will be:
config/app.php as supportedLocales)Post model that will have all the details about the post, except for the title and contentPostTranslation model that will have the title and content of the post in a specific languagehasOne relation and attribute mutators in our Post model)Post and its translations in one goHere's the database schema for our Post and its translations in PostTranslation:
Migration
Schema::create('posts', function (Blueprint $table) { $table->id(); $table->dateTime('publish_date')->nullable(); $table->foreignId('user_id')->constrained(); $table->softDeletes(); $table->timestamps();}); Schema::create('post_translations', function (Blueprint $table) { $table->id(); $table->foreignId('post_id')->constrained()->cascadeOnDelete(); $table->string('locale'); $table->string('title'); $table->longText('post'); $table->softDeletes(); $table->timestamps();});
Our Post model, which will contain a title and post attributes to always have the current locale translation of the text:
app/Models/Post.php
use Illuminate\Database\Eloquent\Casts\Attribute;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\BelongsTo;use Illuminate\Database\Eloquent\Relations\HasMany;use Illuminate\Database\Eloquent\Relations\HasOne;use Illuminate\Database\Eloquent\SoftDeletes; class Post extends Model{ use SoftDeletes; protected $fillable = [ 'publish_date', 'user_id', ]; protected $casts = [ 'publish_date' => 'datetime', ]; // Preloading current locale translation at all times protected $with = [ 'defaultTranslation' ]; public function title(): Attribute { return new Attribute( // Always making sure that we have current locale title get: fn() => $this->defaultTranslation->title, ); } public function post(): Attribute { return new Attribute( // Always making sure that we have current locale post model get: fn() => $this->defaultTranslation->post, ); } public function author(): BelongsTo { return $this->belongsTo(User::class, 'user_id'); } public function translations(): HasMany { return $this->hasMany(PostTranslation::class); } public function defaultTranslation(): HasOne { // Making sure that we always retrieve current locale information return $this->translations()->one()->where('locale', app()->getLocale()); }}
And our PostTranslation model:
app/Models/PostTranslation.php
use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\BelongsTo;use Illuminate\Database\Eloquent\SoftDeletes; class PostTranslation extends Model{ use SoftDeletes; protected $fillable = [ 'post_id', 'locale', 'title', 'post', ]; public function post(): BelongsTo { return $this->belongsTo(Post::class); }}
Once we have our Models, we can look into our PostController and see how we can create a new post with translations...