HasLocalization
File: app/Traits/Common/HasLocalization.php
A Laravel Eloquent trait that automatically resolves localized JSON columns into the current locale's string value — so $model->name returns the Indonesian name when the app is in id locale, without writing $model->name['id'] everywhere.
Overview
Many models store multilingual content as JSON columns:
{"en": "School Name", "id": "Nama Sekolah"}Without this trait, every access requires $model->name['en'] ?? $model->name['id']. With the trait, $model->name automatically returns the correct locale.
Why It Exists
- Developer ergonomics: Reading a localized value is
$room->name, not$room->name['en'] - Consistency: Every localization follows the same JSON structure (
{en: "...", id: "..."}) - Fallback chain: If the current locale has no value, it falls back to any available locale, then shows
- - Backward compatible: Non-localized columns are unaffected — the trait only intercepts columns listed in
$localizations
Methods
getAttribute($key): mixed
Overrides Eloquent's getAttribute() to intercept localized columns.
public function getAttribute($key): mixed
{
$value = parent::getAttribute($key);
// Skip non-string keys or keys not in the localizations array
if (! is_string($key) || $key === '') return $value;
if (! property_exists($this, 'localizations')) return $value;
$localizations = $this->localizations ?? [];
if (! is_array($localizations) || ! in_array($key, $localizations, true)) return $value;
return $this->resolveLocalizedValue($value);
}Algorithm:
- Get the raw attribute value from the parent
- Check if the key is in the
$localizationsarray - If yes → resolve as localized JSON
- If no → return raw value (standard Eloquent behavior)
getLocalizationRaw(string $key): array
Returns the full JSON object for a localized field without resolution, useful for APIs or admin panels.
public function getLocalizationRaw(string $key): array
{
$raw = parent::getAttribute($key);
if (is_string($raw)) {
$json = json_decode($raw, true);
if (json_last_error() === JSON_ERROR_NONE && is_array($json)) {
return $json;
}
}
return is_array($raw) ? $raw : [];
}Usage:
$model->name; // "Nama Sekolah" (resolved)
$model->getLocalizationRaw('name'); // ["en" => "School Name", "id" => "Nama Sekolah"]resolveLocalizedValue(mixed $value): string
Core resolution algorithm:
protected function resolveLocalizedValue(mixed $value): string
{
// Plain string → return trimmed or '-'
if (is_string($value)) {
$value = trim($value);
return $value !== '' ? $value : '-';
}
// Not an array → no localization possible
if (! is_array($value)) return '-';
// Try current/base locale first
$baseLocale = $this->resolveBaseLocale();
$preferred = Arr::get($value, $baseLocale);
if (is_string($preferred) && trim($preferred) !== '') {
return trim($preferred);
}
// Fallback: return first non-empty value from any locale
foreach ($value as $candidate) {
if (is_string($candidate) && trim($candidate) !== '') {
return trim($candidate);
}
}
// Nothing found
return '-';
}Fallback chain:
Current locale → Any available locale → "-"resolveBaseLocale(): string
Determines which locale to prefer:
protected function resolveBaseLocale(): string
{
if (is_string($this->localizationBaseLocale) && trim($this->localizationBaseLocale) !== '') {
return trim($this->localizationBaseLocale);
}
return (string) app()->getLocale();
}Override the locale per-instance by setting $model->localizationBaseLocale.
How to Use
1. Add the trait to your model
use App\Traits\Common\HasLocalization;
class Room extends Model
{
use HasLocalization;
/**
* Columns that store localized JSON.
*/
protected array $localizations = ['name', 'description'];
}2. Store localized data as JSON
$room->name = json_encode(['en' => 'Classroom A', 'id' => 'Ruang Kelas A']);
$room->save();Or use the getLocalizationRaw() inverse when building the JSON:
$room->name = ['en' => 'Classroom A', 'id' => 'Ruang Kelas A'];
$room->save(); // Eloquent casts to JSON automatically3. Read localized values
// App locale: en
$room->name; // "Classroom A"
// App locale: id
$room->name; // "Ruang Kelas A"
// Raw JSON (for API responses)
$room->getLocalizationRaw('name'); // ["en" => "Classroom A", "id" => "Ruang Kelas A"]4. Override locale per-instance
$room->localizationBaseLocale = 'en';
$room->name; // Always returns English, regardless of app localeKey Files
| File | Purpose |
|---|---|
app/Traits/Common/HasLocalization.php | The trait — overrides getAttribute(), resolves localized JSON |
app/Models/ | Any model that uses use HasLocalization and defines $localizations |