Using Laravel Translatable in Kirby CMS

Updated 2021-07-13: This should work with Kirby 3.5 and PHP 7.3

Here is a way how to use Kirby CMS along with Backpack for Laravel as a database admin (or any other app that uses Laravel ORM) with multi-language database table. For that, use the spatie/laravel-translatable package that saves translation as JSON in the respective column.

id title
32 {"en":"Title","de":"Titel"}

Retrieving the right translation is as easy as $myModel->title and depending whats set as language in your Laravel app you get the right translated item.

Now Kirby handles things a bit different and it would be easy to recreate this kind of functionality, but why not utilize some Laravel's black magic here?

Install dependencies

I'm using afbora/kirby-blade: Enable Laravel Blade Template Engine for Kirby 3 and ran in some conflicts with beebmx/kirby-db: Enable Kirby 3 database support for Illuminate\Database, because the latter is using Laravel 5.x (to this date 2021-07-13) illuminate/database under the hood.

Also there are some PSR-4 warnings so I tried to fix that in my own fork.

1. Change /composer.json

Require my fork of beebmx/kirby-db "beebmx/kirby-db": "dev-patch-1" and refer to it in the repositories part of the file.

    "require": {
        "php": ">=7.1.0",
        "getkirby/cms": "^3.0",
        "beebmx/kirby-db": "dev-patch-1"
    "autoload": {
      "psr-4": {
        "MO\\": "site/"
    "repositories": [
        "type": "vcs",
        "url": ""

2. Install beebmx/kirby-db


$ composer update beebmx/kirby-db

this will install my fork of the plugin, which is basically just an updated composer.json file

3. Update the illuminate/* Bundle

The plugin comes with an outdated version of Laravel's Eloquent ORM and this might kill your app, if you have more recent Laravel libraries installed, like collections or afbora/kirby-blade.

To fix that, run right after step 2.

$ composer update --working-dir=./site/plugins/kirby-db

This will update illuminate/database to the latest version and installs spatie/translatable as required for this exercise.

Setting up the autoloader in /composer.json

I could use a simple require but I think a better way is to setup a PSR-4 autoload and use namespaces etc.

    "autoload": {
      "psr-4": {
        "MO\\": "site/"

Setup the Eloquent Model

The model is placed at site/models/ORM/Categories.php (to differentiate from Kirby Page Models)


namespace MO\models\ORM;
use Beebmx\KirbyDB\Model;
use Spatie\Translatable\HasTranslations;

class Categories extends Model
    use HasTranslations;
    protected $table = 'products_categories';
    public $translatable = ['title'];

Setup the Kirby Page Model

The Page model at resides at site/models/categories.php


use MO\models\ORM as ORM;

class CategoriesPage extends Kirby\Cms\Page
     * Language Code
     * @var string

    public $lc;

    public function __construct(array $props)
        // this only set the default language ?!
        $this->lc = $this->kirby()->language()->code();

    public function children()

        $results = [];
        $pages   = [];

        $this->lc = $this->kirby()->language()->code();
        $cats = ORM\Categories::all();
        foreach($cats as $cat) {
            // set the locale for translatable
            $pages[] = [
              'slug'     => $cat->id,
              'num'      => 0,
              'template' => 'comment',
              'model'    => 'comment',
              'content'  => [
                'title'  => $cat->title,

        return Pages::factory($pages, $this);

And, any idea why I can't set $this->lc in the CategoriesPage::__construct() ?