igorblumberg's avatar

Translatable Trait

Hello, I'm developing a project where I need localization (the front end page must have 2 languages). For URL mapping and setting locales I'm using this package:

https://github.com/mcamara/laravel-localization

When it comes to translating model data I couldn't find a quick-and-easy package to use. The best one I found was:

https://github.com/dimsav/laravel-translatable

But it does much more then I need, and requires one table for each module to be translated. I developed my own trait to handle this and I would like the community input on it.

My goal is to keep accessing and setting $model->name and keeping all localization issues behind the scenes.

I've managed to achieve this with the following trait:

<?php 

namespace App\Http\Traits;

use Illuminate\Database\Eloquent\Model;
use App\Models\Translation;
use \LaravelLocalization;

trait TranslatableTrait
{
    public function __get($key)
    {
    if(isset($this->translatable) && in_array($key, $this->translatable))
        {
            //translate and return
            return $this->getTranslation($key);
        }
        else
        {
            //don't translate, call parent
            return parent::__get($key);
        }
    }

    public function __set($key, $value)
    {
    if(isset($this->translatable) && in_array($key, $this->translatable))
        {
            //translate and return
            $this->setTranslation($key,$value);
        }
        else
        {        
            parent::__set($key, $value);
        }
    }
    public function trans($key,$locale)
    {
        return $this->getTranslation($key,$locale);
    }

    public function getTranslation( $key, $locale = NULL )
    {
        if(!$locale)
        {
            $locale = LaravelLocalization::getCurrentLocale();
        }
        //model class, model id, locale code
        $translation = Translation::where("model_class",get_class($this))->where("model_id",$this->id)->where("key",$key)->where("locale",$locale)->first();        
        if(!$translation)
        {
            return "";
        }
        else
        {
            return $translation->value;
        }
    }

    public function setTranslation($key,$value,$locale = NULL)
    {
        if(!$locale)
        {
            $locale = LaravelLocalization::getCurrentLocale();
        }
        $translation = Translation::where("model_class",get_class($this))->where("model_id",$this->id)->where("key",$key)->where("locale",$locale)->first();       
        if(!$translation)
        {
            $translation = new Translation;
            $translation->model_class = get_class($this);
            $translation->model_id = $this->id;
            $translation->key = $key;
            $translation->locale = $locale;
            $translation->value = $value;
        }
        else
        {
            $translation->value = $value;
        }        
        
        return $translation->save();
    }

     public function toJson($locale = NULL)
    {
        if(!$locale)
        {
            $locale = LaravelLocalization::getCurrentLocale();
        }
        $array = $this->toArray();
        if(isset($this->translatable))
        {
            foreach($this->translatable as $value)
            {
                $array[$value] = $this->getTranslation($value,$locale);
            }
        }
        return json_encode($array);
    }
}

To use this trait you need only one table:

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateTranslationsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('translations', function (Blueprint $table) {
            $table->increments('id');
            $table->string('model_class');
            $table->string('model_id');
            $table->string('key');
            $table->string('locale', 2);
            $table->text('value');
            $table->timestamps();
            $table->unique(['model_class', 'model_id','locale','key']);
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('translations');
    }
}

Then just import the Trait and set an array with the fields you need to translate to your modules and it's done.

 use TranslatableTrait;
protected $translatable = ['name','description'];

The next step would be adding some tests and creating a package.

Do you think it will be usefull for someone else?

thanks!

ps.: I don't have any open source package, not sure the amount of work needed to keep one "live". I would also appreciate some input on that.

0 likes
0 replies

Please or to participate in this conversation.