PHPackages                             spletna-postaja/translatable - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. spletna-postaja/translatable

ActiveLibrary[Database &amp; ORM](/categories/database)

spletna-postaja/translatable
============================

Translatable Eloquent models.

2.0.5(4y ago)43.0k4MITPHPPHP &gt;=7.3

Since Feb 13Pushed 4y agoCompare

[ Source](https://github.com/spletna-postaja/translatable)[ Packagist](https://packagist.org/packages/spletna-postaja/translatable)[ RSS](/packages/spletna-postaja-translatable/feed)WikiDiscussions master Synced 2mo ago

READMEChangelog (8)Dependencies (3)Versions (31)Used By (0)

Translatable Eloquent models
============================

[](#translatable-eloquent-models)

[![Total Downloads](https://camo.githubusercontent.com/e50ca2ae49a23c66d771b7da7c5b1a267ce2f37ca3b3885d1f55d3a4766e2a1c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f73706c65746e612d706f7374616a612f7472616e736c617461626c653f6c6162656c3d446f776e6c6f616473267374796c653d666c61742d7371756172652663616368655365636f6e64733d363030)](https://packagist.org/packages/spletna-postaja/translatable)[![Build Status](https://camo.githubusercontent.com/6affe235dc3094089a3b9c3c32338bee505d617bff1976ed80de56e405952f71/68747470733a2f2f696d672e736869656c64732e696f2f7472617669732f73706c65746e612d706f7374616a612f7472616e736c617461626c652f6d61737465723f6c6162656c3d4275696c64267374796c653d666c61742d7371756172652663616368655365636f6e64733d363030)](https://travis-ci.org/spletna-postaja/translatable)[![CircleCI](https://camo.githubusercontent.com/1812dba9b29283736324a7d2ff692275a76fefc1dc3ca31574ebf8d170c36f11/68747470733a2f2f696d672e736869656c64732e696f2f636972636c6563692f6275696c642f6769746875622f73706c65746e612d706f7374616a612f7472616e736c617461626c652f6d61737465723f6c6162656c3d436972636c654349267374796c653d666c61742d7371756172652663616368655365636f6e64733d363030)](https://circleci.com/gh/spletna-postaja/translatable)[![StyleCI](https://camo.githubusercontent.com/43e8550f52a6699c159e484f33cff2b905b2e6fa3ebff71b4924f51e3ae56029/68747470733a2f2f6769746875622e7374796c6563692e696f2f7265706f732f3231353035303930342f736869656c643f6272616e63683d6d6173746572)](https://github.styleci.io/repos/215050904)[![ScrutinizerCI](https://camo.githubusercontent.com/b646a03b66859d18d43621f49a11f71f02aae3d0f4121f9ba0cba45804d18d15/68747470733a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f7175616c6974792f672f73706c65746e612d706f7374616a612f7472616e736c617461626c652f6d61737465723f6c6162656c3d5363727574696e697a65724349267374796c653d666c61742d7371756172652663616368655365636f6e64733d363030)](https://scrutinizer-ci.com/g/spletna-postaja/translatable/)[![GitHub issues](https://camo.githubusercontent.com/8dcaea07bce5c1f955af7941f6ec3940c5591dfe2fd5f6404f81f342dca60f4b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6973737565732f73706c65746e612d706f7374616a612f7472616e736c617461626c653f6c6162656c3d497373756573267374796c653d666c61742d737175617265)](https://github.com/spletna-postaja/translatable/issues)[![GitHub release (latest SemVer)](https://camo.githubusercontent.com/1b22f9334cd53895df7afc1bbcde4eac75d4720ac5945a898b7fa18c30a767f8/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f73706c65746e612d706f7374616a612f7472616e736c617461626c653f6c6162656c3d52656c65617365267374796c653d666c61742d7371756172652663616368655365636f6e64733d363030)](https://github.com/spletna-postaja/translatable)[![MIT License](https://camo.githubusercontent.com/02b5768d10de7603e778c9717c10eb3dd793b69d4c895d552cab992d4ab52b57/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f73706c65746e612d706f7374616a612f7472616e736c617461626c653f6c6162656c3d4c6963656e736526636f6c6f723d626c7565267374796c653d666c61742d7371756172652663616368655365636f6e64733d363030)](https://github.com/spletna-postaja/translatable/blob/master/LICENSE)

This package provides a powerful and transparent way of managing multilingual models in Eloquent.

It makes use of Laravel's enhanced global scopes to join translated attributes to every query rather than utilizing relations as some alternative packages. As a result, only a single query is required to fetch translated attributes and there is no need to create separate models for translation tables, making this package easier to use.

- [Quick demo](#quick-demo)
- [Versions](#versions)
- [Installation](#installation)
    - [Configuration in Laravel](#configuration-in-laravel)
    - [Configuration outside Laravel](#configuration-outside-laravel)
- [Creating migrations](#creating-migrations)
- [Configuring models](#configuring-models)
- [CRUD operations](#crud-operations)
    - [Selecting rows](#selecting-rows)
    - [Inserting rows](#inserting-rows)
    - [Updating rows](#updating-rows)
    - [Deleting rows](#deleting-rows)
- [Translations as a relation](#translations-as-a-relation)
- [Author and maintenance](#author-and-maintenance)
- [License](#licence)

Quick demo
----------

[](#quick-demo)

To enable translations in your models, you first need to prepare your schema according to the [convention](#creating-migrations). After that you can pull in the `Translatable` trait:

```
use Laraplus\Data\Translatable;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use Translatable;
}
```

And that's it! No other configuration is required. The translated attributes will be automatically cached and all your queries will start returning translated attributes:

```
Post::first();
$post->title; // title in the current locale

Post::translateInto('de')->first();
$post->title; // title in 'de' locale

Post::translateInto('de')->withFallback('en')->first();
$post->title; // title in 'de' if available, otherwise in 'en'
```

Since translations are joined to the query it's also very easy to filter and sort by translated attributes:

```
Post::where('body', 'LIKE', '%Laravel%')->orderBy('title', 'desc');
```

Or even return only translated records:

```
Post::onlyTranslated()->all()
```

Multiple [helpers](#crud-operations) are available for all basic CRUD operations. For all available options, read the [full documentation](#crud-operations) below.

Versions
--------

[](#versions)

PackageLaravelPHP**v1.0.0 - v1.0.22**`5.2.* - 5.8.*``5.6.* / 7.0.* - 7.2.*`**v2.0.0 - v2.0.**\*`>=6.0``>=7.3.*`Installation
------------

[](#installation)

This package can be used within Laravel or Lumen applications as well as any other application that utilizes Laravel's database component . The package can be installed through composer:

```
composer require spletna-postaja/translatable

```

### Configuration in Laravel

[](#configuration-in-laravel)

The package will be auto-discovered in Laravel although you can still manually add a service provider to your `/config/app.php` configuration file, under the `providers` key:

```
'providers' => [
    // Other providers
    Laraplus\Data\TranslatableServiceProvider::class,
],
```

Optionally you can configure some other options by publishing the `translatable.php` configuration file:

```
php artisan vendor:publish --provider="Laraplus\Data\TranslatableServiceProvider" --tag="config"

```

Open the configuration file to check all available settings:

### Configuration outside Laravel

[](#configuration-outside-laravel)

When using this package outside Laravel, you can configure it using `TranslatableConfig` class:

```
TranslatableConfig::currentLocaleGetter(function() {
    // Return the current locale of the application
});

TranslatableConfig::fallbackLocaleGetter(function() {
    // Return the fallback locale of the application
});
```

You can optionally adjust some other settings as well. To see all available options inspect Laravel's Service Provider:

Creating migrations
-------------------

[](#creating-migrations)

To utilize multilingual models you need to prepare your database tables in a certain way. Each translatable table consists of translatable and non translatable attributes. While non translatable attributes can be added to your table normally, translatable fields need to be in their own table named according to the convention.

Below you can see a sample migration for the `posts` table:

```
Schema::create('posts', function(Blueprint $table)
{
    $table->increments('id');
    $table->datetime('published_at');
    $table->timestamps();
});

Schema::create('posts_i18n', function(Blueprint $table)
{
    $table->integer('post_id')->unsigned();
    $table->string('locale', 6);
    $table->string('title');
    $table->string('body');

    $table->primary(['post_id', 'locale']);
});
```

By default, translation tables must end with `_i18n` suffix although this can be changed in the previously mentioned configuration file. Translation table must always contain a foreign key to the parent table as well as a `locale`field (also configurable) which will store the locale of translated attributes. Incrementing keys are not allowed on translation models. A composite key containing `locale` and foreign key reference to the parent model needs to be defined instead. Optionally you may define foreign key constraints, but the package will work without them as well.

**Important: make sure that no translated attributes are named the same as any non translated attribute since that will break the queries. This also applies to timestamps (which should not be added to the translation tables but to primary tables only) and for incrementing keys (not allowed on translation tables).**

Configuring models
------------------

[](#configuring-models)

To make your models aware of the translated attributes you need to pull in the `Translatable` trait:

```
use Laraplus\Data\Translatable;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use Translatable;
}
```

Optionally you may define an array of `$translatable` attributes, but the package is designed to work without it. In that case translatable attributes will be automatically determined from the database schema and cached indefinitely. If you are using the cache approach, don't forget to clear the cache every time the schema changes.

By default, if the model is not translated into the current locale, fallback translations will be selected instead. If no translations are available, `null` will be returned for all translatable attributes. If you wish to change that behavior you can either modify the `translatable.php` configuration file or adjust the behavior on "per model" basis:

```
class Post extends Model
{
    use Translatable;

    protected $withFallback = false;

    protected $onlyTranslated = true;
}
```

CRUD operations
---------------

[](#crud-operations)

### Selecting rows

[](#selecting-rows)

To select rows from your translatable models, you can use all of the usual Eloquent query helpers. Translatable attributes will be returned in your current locale. To learn more about how to configure localization in Laravel, please refer to the official documentation:

```
Post::where('active', 1)->orderBy('title')->get();
```

#### Query helpers

[](#query-helpers)

The above query will by default also return records that don't have any translations in the current or fallback locale. To return only translated rows, you can change the `defaults.only_translated` config option to `true`, or use the `onlyTranslated()` query helper:

```
Post::onlyTranslated()->get();
```

Sometimes you may want to disable fallback translations altogether. To do this, you may either change the `defaults.with_fallback` configuration option to `false` or use the `withoutFallback()` query helper:

```
Post::withoutFallback()->get();
```

Both of the helpers above have their opposite forms: `withUntranslated()` and `withFallback()`. You may also provide an optional `$locale` argument to the `withFallback()` helper to change the default fallback locale:

```
Post::withUntranslated()->withFallback()->get();
Post::withUntranslated()->withFallback('de')->get();
```

Sometimes you may wish to retrieve translations in a locale different from the current one. To achieve that, you may use the `translateInto($locale)` helper:

```
Post::translateInto('de')->get();
```

In case you do not need the translated attributes at all, you may use the `withoutTranslations()` helper, which will remove the translatable global scope from your query

```
Post::withoutTranslations()->get();
```

#### Filtering and sorting by translated attributes

[](#filtering-and-sorting-by-translated-attributes)

Often you may wish to filter query results by translated attributes. This package allows you to use all of the usual Eloquent `where` clauses normally. This will work even with fallback translations since all of the columns within where clauses will be automatically wrapped in the `ifnull` statements and prefixed with the appropriate table names:

```
Post::where('title', 'LIKE', '%Laravel%')->orWhere('description', 'LIKE', '%Laravel%')->get();
```

The same logic applies for `order by` clauses, which will also be automatically transformed to the correct format:

```
Post::orderBy('title')->get();
```

**Notice: if you are using `whereRaw` clauses, we will not be able to format your expressions automatically since we do not parse whereRaw expressions. Instead you will need to include the appropriate table prefix manually.**

### Inserting rows

[](#inserting-rows)

When creating new models in the current locale, you may use the normal Laravel syntax, as if you were inserting rows into a single table:

```
Post::create([
    'title'        => 'My title',
    'published_at' => Carbon::now(),
]);
```

If you want to store the record in an alternative locale, you may use the `createInLocale($locale, $attributes)` helper:

```
Post::createInLocale('de', [
    'title'        => 'Title in DE',
    'published_at' => Carbon::now(),
]);
```

Often you will need to store a new record together with all translations. To do that, you may list translatable attributes as a second argument of the `create()` method:

```
Post::create([
    'published_at' => Carbon::now()
], [
    'en' => ['title' => 'Title in EN'],
    'de' => ['title' => 'Title in DE'],
]);
```

All of the above helpers also have their `force` forms that let you bust the mass assignment protection.

```
Post::forceCreate([/*attributes*/], [/*translations*/]);
Post::forceCreateInLocale($locale, [/*attributes*/]);
```

### Updating rows

[](#updating-rows)

Updating records in the current locale is as easy as if you were updating a single table:

```
$user = User::first();

$user->title = 'New title';
$user->save();
```

If you wish to update a record in another locale, you may use the `saveTranslation($locale, $attributes)` helper that will either update an existing translation or create a new one (if it doesn't exist yet):

```
$user = User::first();

$user->saveTranslation('en', [
    'title' => 'Title in EN'
]);

$user->saveTranslation('de', [
    'title' => 'Title in DE'
]);
```

A `forceSaveTranslation($locale, $attributes)` helper is also available to bust mass assignment protection.

To update multiple rows at once, you may also use the query builder:

```
User::where('published_at', '>', Carbon::now())->update(['title' => 'New title']);
```

To update a different locale using the query builder, you can call the `transleteInto($locale)` helper:

```
User::where('published_at', '>', Carbon::now())->translateInto('de')->update(['title' => 'New title']);
```

### Deleting rows

[](#deleting-rows)

Deleting rows couldn't be easier. Do it as per usual and translations will be automatically deleted together with the parent row:

```
$user = User::first();

$user->delete();
```

To delete multiple rows at once, you may also use the query builder. Translations will be cleaned up automatically:

```
User::where('published_at', '>', Carbon::now())->delete();
```

Translations as a relation
--------------------------

[](#translations-as-a-relation)

Sometimes you may wish to retrieve all translations of a certain model. Luckily the package implements a `hasMany`relation which will help you do just that:

```
$user = $user->first();

foreach ($user->translations as $translation) {
    echo "Title in {$translation->locale}: {$translation->title}";
}
```

A `translate($locale)` helper is available when you wish to access an attribute in a specific locale:

```
$user = $user->first();

$user->translate('en')->title; // Title in EN
$user->translate('de')->title; // Title in DE
```

When using the relation, you will usually want to preload it without joining translated attributes to the query. There is a `withAllTranslations()` helper available to do just that:

```
User::withAllTranslations()->get();
```

**Notice: there is currently limited support for updating and inserting new records using the relation. Instead you can use the helpers described above.**

Author and maintenance
----------------------

[](#author-and-maintenance)

Author and lead developer of this project is [Anže Časar](https://github.com/acasar).

This project is supported and maintained by [Spletna postaja](https://spletna-postaja.com/), a web development company.

Ta projekt podpira in vzdržuje [Spletna postaja](https://spletna-postaja.com/), podjetje za razvoj in [izdelavo spletnih strani](https://spletna-postaja.com/izdelava-spletnih-strani) in [izdelavo spletnih trgovin](https://spletna-postaja.com/izdelava-spletnih-trgovin).

[![Twitter](https://camo.githubusercontent.com/dfc7de7fd3d12fa70531365aa4dcd6dd265341d3e3fed42885316ac26ae05d8d/68747470733a2f2f696d672e736869656c64732e696f2f747769747465722f75726c3f6c6162656c3d547765657425323061626f75742532307468697325323070726f6a656374267374796c653d736f6369616c2675726c3d68747470732533412532462532466769746875622e636f6d25324673706c65746e612d706f7374616a612532467472616e736c617461626c65)](https://twitter.com/intent/tweet?text=Wow:&url=https%3A%2F%2Fgithub.com%2Fspletna-postaja%2Ftranslatable)

License
-------

[](#license)

This project is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).

[![MIT License](https://camo.githubusercontent.com/02b5768d10de7603e778c9717c10eb3dd793b69d4c895d552cab992d4ab52b57/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f73706c65746e612d706f7374616a612f7472616e736c617461626c653f6c6162656c3d4c6963656e736526636f6c6f723d626c7565267374796c653d666c61742d7371756172652663616368655365636f6e64733d363030)](https://github.com/spletna-postaja/translatable/blob/master/LICENSE)

###  Health Score

35

—

LowBetter than 79% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity23

Limited adoption so far

Community15

Small or concentrated contributor base

Maturity69

Established project with proven stability

 Bus Factor1

Top contributor holds 58.7% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~70 days

Recently: every ~173 days

Total

30

Last Release

1706d ago

Major Versions

1.0.21 → 2.0.02019-10-14

1.0.x-dev → 2.0.22019-10-15

PHP version history (2 changes)1.0.0PHP &gt;=5.5.0

2.0.0PHP &gt;=7.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/975dd5a96021f39a82e0708c39da6be28b68a78bb80566fb1cbc91dc64edf8d0?d=identicon)[blazorazem](/maintainers/blazorazem)

---

Top Contributors

[![acasar](https://avatars.githubusercontent.com/u/6329543?v=4)](https://github.com/acasar "acasar (54 commits)")[![BlazOrazem](https://avatars.githubusercontent.com/u/5699173?v=4)](https://github.com/BlazOrazem "BlazOrazem (29 commits)")[![morrizon](https://avatars.githubusercontent.com/u/4554805?v=4)](https://github.com/morrizon "morrizon (4 commits)")[![marcheffels](https://avatars.githubusercontent.com/u/34892532?v=4)](https://github.com/marcheffels "marcheffels (1 commits)")[![ricardoh](https://avatars.githubusercontent.com/u/1449606?v=4)](https://github.com/ricardoh "ricardoh (1 commits)")[![scrutinizer-auto-fixer](https://avatars.githubusercontent.com/u/6253494?v=4)](https://github.com/scrutinizer-auto-fixer "scrutinizer-auto-fixer (1 commits)")[![imbrish](https://avatars.githubusercontent.com/u/8572846?v=4)](https://github.com/imbrish "imbrish (1 commits)")[![j6s](https://avatars.githubusercontent.com/u/3374170?v=4)](https://github.com/j6s "j6s (1 commits)")

---

Tags

eloquenti18nl10nlaravellaravel-6-packagelaravel-frameworklaravel-packagelaravel-translatablelaravel-translation-managerlaravel-translationslaravel-translatoropen-source-projectphpspletna-postajatranslation-managementlaraveli18ntranslatemodeleloquenttranslatable

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/spletna-postaja-translatable/health.svg)

```
[![Health](https://phpackages.com/badges/spletna-postaja-translatable/health.svg)](https://phpackages.com/packages/spletna-postaja-translatable)
```

###  Alternatives

[rinvex/laravel-categories

Rinvex Categories is a polymorphic Laravel package, for category management. You can categorize any eloquent model with ease, and utilize the power of Nested Sets, and the awesomeness of Sluggable, and Translatable models out of the box.

470161.6k3](/packages/rinvex-laravel-categories)[rinvex/laravel-tenants

Rinvex Tenants is a contextually intelligent polymorphic Laravel package, for single db multi-tenancy. You can completely isolate tenants data with ease using the same database, with full power and control over what data to be centrally shared, and what to be tenant related and therefore isolated from others.

823.4k10](/packages/rinvex-laravel-tenants)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
