Multilanguage
Introduction
Thanks to the spatie/laravel-translatable package you can translate your models into multiple languages. HotCoffee's own Article
and InfoPage
models take advantage of this. Additionally there is a helper method language_fields()
that will generate the HTML input fields in your forms in separate tabs on the page for each language that you declare in hotcoffee.php
config file.
Usage
Define all the locales for the translatable models in the languages
array in config/hotcoffee.php
. Each language should be an associative array with this structure'acronym' => 'full name'
. The first language is going to be the default one.
'languages' => [
'en' => 'English',
'bg' => 'Български',
'de' => 'Deutsche',
],
If you have defined more than one language in the array you will be able to see the flag icons above the title and content fields when creating or editing info pages and articles. Clicking an icon will switch to the tab that contains the fields for that particular locale.

These fields and flag icons are generated, because we called the language_fields()
helper method in the template. Flag images are loaded from the public/vendor/hotcoffee/img/flags
directory. If the acronym of a locale is 'de', then the loaded image will be de.svg
from that same directory. Simply put any missing flag svg files that you need there.
To make your own models translatable they should use the Spatie\Translatable\HasTranslations
trait. You need to also define all translatable fields:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Spatie\Translatable\HasTranslations;
class Product extends Model
{
use HasTranslation;
/**
* Translatable attributes.
*/
public $translatable = ['name', 'description'];
/**
* The attributes that are mass assignable.
*/
protected $fillable = [
'name', 'description', 'price'
];
}
Now in your template:
<form action="{{ route('products.store') }}" method="post">
<h6 class="heading-small text-muted mb-4">New Product</h6>
{{ csrf_field() }}
<!-- TRANSLATABLE FIELDS -->
{!! language_fields([
'name' => ['type' => 'text', 'title' => 'Product Name'],
'description' => ['type' => 'textarea', 'title' => 'Content', 'class' => 'tinymce'],
], $product ?? null) !!}
<!-- END TRANSLATABLE FIELDS -->
<!-- NON TRANSLATABLE FIELDS -->
<input type="text" name="price" />
<!-- END NON TRANSLATABLE FIELDS -->
<input type="submit" />
</form>
The HTML output of language_fields()
method in this case would look something like this (given, that we have set 3 locales - en, bg and de):
<!-- Flag Icons -->
<ul class="nav nav-pills nav-pills-circle" role="tablist" id="tabs_2">
<li class="nav-item">
<a class="nav-link rounded-circle active " id="en" data-toggle="tab" href="#tab-en" role="tab" aria-controls="en" aria-selected="true">
<img src="https://yourapp.com/vendor/hotcoffee/img/flags/en.svg" alt="English" class="flag-img">
</a>
</li>
<li class="nav-item">
<a class="nav-link rounded-circle " id="bg" data-toggle="tab" href="#tab-bg" role="tab" aria-controls="bg" aria-selected="true">
<img src="https://yourapp.com/vendor/hotcoffee/img/flags/bg.svg" alt="Български" class="flag-img">
</a>
</li>
<li class="nav-item">
<a class="nav-link rounded-circle " id="de" data-toggle="tab" href="#tab-de" role="tab" aria-controls="bg" aria-selected="true">
<img src="https://yourapp.com/vendor/hotcoffee/img/flags/de.svg" alt="Deutsche" class="flag-img">
</a>
</li>
</ul>
<!-- Tabs with language fields -->
<div class="tab-content" id="lang-tabs">
<!-- English Fields -->
<div class="tab-pane fade" id="tab-en" role="tabpanel" aria-labelledby="tab-en">
<label class="form-control-label" for="input-name">Name</label>
<input type="text" name="name[en]" class="form-control" />
<label class="form-control-label" for="input-name">Content</label>
<textarea name="description[en]" class="tinymce form-control"><textarea>
</div>
<!-- Bulgarian Fields -->
<div class="tab-pane fade" id="tab-bg" role="tabpanel" aria-labelledby="tab-bg">
<label class="form-control-label" for="input-name">Name</label>
<input type="text" name="name[bg]" class="form-control" />
<label class="form-control-label" for="input-name">Content</label>
<textarea name="description[bg]" class="tinymce form-control"><textarea>
</div>
<!-- German Fields -->
<div class="tab-pane fade" id="tab-de" role="tabpanel" aria-labelledby="tab-de">
<label class="form-control-label" for="input-name">Name</label>
<input type="text" name="name[de]" class="form-control" />
<label class="form-control-label" for="input-name">Content</label>
<textarea name="description[de]" class="tinymce form-control"><textarea>
</div>
</div>
The function will also add "has-danger" class if a validation of a field has failed.

It will also populate the value=""
attribute (or content of a <textarea>
field) automatically when editing a model. Hence why you need to specify the variable name of the model as a second parameter:
{!! language_fields($fields = array(), $product ?? null !!}
When the form is submitted, the content of the request will be this:

Now in your store()
method you can do this:
Product::create($request->all());
Of course when using Eloquent's create()
or update()
methods you will need to specify the fillable
or guarded
attribute on the model.
public $translatable = ['name', 'description'];
protected $fillable = ['name', 'description', 'price'];
Whenever you need to display the content of the product for example you can just do this:
$product->content; // Returns value of content field in the current app locale.
If you want to get the content field in a specific locale:
$product->getTranslation('content', 'bg'); // Returns value of content field in Bulgarian.
To learn more about translating models visit https://github.com/spatie/laravel-translatable
Last updated