aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Web Geliştirme

Laravel Çoklu Dil: Localization Sistemi Kurulumu

Bir Laravel çoklu dil sistemi kurmak ilk bakışta sadece birkaç metni çevirmek gibi görünür, ama gerçek bir projede iş üç ayrı katmana yayılır: arayüz metinleri (lang dosyaları), URL'lerde dil yönetimi (locale yönlendirme) ve veritabanındaki dinamik içeriğin çevirisi. Bu rehberde üçünü de baştan sona, çalışan kod örnekleriyle ele alıyorum. Anlatımın temeli kendi portföy sitemde (aslain.dev) TR/EN/FR/NL/DE olmak üzere beş dili yönettiğim gerçek mimariye dayanıyor.

Locale temelleri: app.locale ve fallback

Laravel'de aktif dil App::getLocale() ile okunur, App::setLocale('en') ile ayarlanır. İki ayar kritiktir ve config/app.php içinde bulunur:

'locale' => 'tr',
'fallback_locale' => 'en',

fallback_locale, bir çeviri anahtarı seçili dilde bulunamazsa hangi dile düşüleceğini belirler. Bu, çok dilli bir projede en sık unutulan ama en hayat kurtaran ayardır: yeni bir metin henüz Fransızcaya çevrilmediyse boş ekran yerine İngilizcesi görünür. Desteklediğiniz dilleri tek yerden yönetmek için basit bir dizi tutmak işe yarar:

// config/app.php veya özel bir config dosyası
'available_locales' => ['tr', 'en', 'fr', 'nl', 'de'],

Lang dosyaları: arayüz metinleri

Statik arayüz metinleri (menü, buton etiketleri, form başlıkları) için Laravel'in yerleşik çeviri dosyalarını kullanın. İki biçim vardır. Birincisi PHP dizi dosyalarıdır; lang/tr/messages.php şöyle görünür:

<?php
return [
    'welcome' => 'Hoş geldin, :name',
    'nav' => [
        'projects' => 'Projeler',
        'contact'  => 'İletişim',
    ],
];

Blade içinde __('messages.welcome', ['name' => $user->name]) ile çağırırsınız; nokta gösterimi iç içe anahtarlara erişir. İkinci biçim JSON çeviri dosyalarıdır: lang/fr.json içine doğrudan kaynak cümleyi anahtar olarak yazarsınız. Bu, kısa arayüz metinleri için pratiktir:

{
    "Save changes": "Enregistrer les modifications",
    "Projects": "Projets"
}

Çağrı yine __('Save changes') şeklindedir. Laravel önce JSON dosyasına, sonra PHP dizilerine bakar. Çoğul biçimler için trans_choice() kullanılır: trans_choice('messages.apples', $count) ve dosyada 'apples' => '{0} elma yok|{1} bir elma|[2,*] :count elma' gibi pipe ile ayrılmış kurallar yazılır.

Locale yönlendirme: dili nasıl tespit edip set edersiniz

Dili her istekte ayarlamak için bir middleware en temiz yöntemdir. Kullanıcı tercihini önce oturumdan, yoksa Accept-Language başlığından okuyabilirsiniz:

php artisan make:middleware SetLocale
public function handle(Request $request, Closure $next)
{
    $supported = config('app.available_locales');
    $locale = $request->session()->get('locale')
        ?? $request->getPreferredLanguage($supported)
        ?? config('app.fallback_locale');

    if (in_array($locale, $supported, true)) {
        App::setLocale($locale);
    }

    return $next($request);
}

getPreferredLanguage(), tarayıcının Accept-Language başlığını desteklediğiniz dillerle eşleştirir; bu, sıfırdan parse etmekten daha güvenilirdir. Middleware'i Laravel 11/12'de bootstrap/app.php içinde kaydedersiniz:

->withMiddleware(function (Middleware $middleware) {
    $middleware->web(append: [\App\Http\Middleware\SetLocale::class]);
})

URL'de dili göstermek isterseniz (örn. /en/projects) rotalarınızı bir prefix grubuna alırsınız. Bu, SEO açısından değerlidir çünkü her dilin ayrı, indekslenebilir bir adresi olur:

Route::prefix('{locale}')
    ->whereIn('locale', ['tr','en','fr','nl','de'])
    ->group(function () {
        Route::get('/projects', [ProjectController::class, 'index']);
    });

Dil değiştirme butonu ise tercihi oturuma yazıp geri döner:

Route::get('/lang/{locale}', function (string $locale) {
    if (in_array($locale, config('app.available_locales'), true)) {
        session()->put('locale', $locale);
    }
    return back();
});

Veritabanı içeriğini çevirmek

Asıl zorluk lang dosyaları değil, kullanıcının admin panelinden girdiği dinamik içeriktir: proje başlıkları, hizmet açıklamaları, blog yazıları. Burada iki sağlam yaklaşım vardır. Birincisi her çevrilebilir sütunu bir JSON olarak saklamaktır. Migration'da sütunu json yaparsınız, modelde cast edersiniz:

// migration
$table->json('title');

// model
protected $casts = ['title' => 'array'];

Satır {"tr":"Başlık","en":"Title","fr":"Titre"} tutar. Okurken küçük bir yardımcı metot, seçili dili döndürür ve eksikse İngilizceye, o da yoksa ilk mevcut dile düşer:

public function tr(string $field, ?string $locale = null): string
{
    $locale = $locale ?? app()->getLocale();
    $values = $this->{$field} ?? [];
    return $values[$locale]
        ?? $values['en']
        ?? (reset($values) ?: '');
}

Bu yöntem hızlıdır ve ekstra tablo gerektirmez; aslain.dev'de tam olarak bunu kullanıyorum. İkinci yaklaşım, spatie/laravel-translatable paketidir. Aynı JSON sütun mantığını standartlaştırır ve $project->title dediğinizde otomatik aktif dile çözer. Kurulumu basittir:

composer require spatie/laravel-translatable

Modelde HasTranslations trait'ini eklersiniz ve public array $translatable = ['title', 'body']; tanımlarsınız. Çok sayıda dil veya çeviri yönetimi gereken büyük projelerde paket bakımı kolaylaştırır; küçük projelerde kendi trait'iniz yeterlidir.

Performans ve yaygın tuzaklar

Birkaç pratik nokta sistemi sağlam tutar:

  • Önbellek: Üretimde php artisan config:cache ve route:cache çalıştırın. Closure içeren rotalar cache'lenemez; controller'a taşıyın.
  • fallback'i ihmal etmeyin: Tek bir eksik anahtar boş başlık yaratır. JSON içeriğinde de mutlaka bir geri-düşme zinciri tanımlayın.
  • hreflang: URL'de dil kullanıyorsanız <head>'e her dilin alternatif bağlantısını ekleyin; Google doğru dili doğru kullanıcıya gösterir.
  • Tarih ve sayılar: Carbon ile $date->locale(app()->getLocale())->translatedFormat('d F Y') yerel ay adlarını verir; biçimi elle çevirmeyin.

Sık Sorulan Sorular

JSON sütun mu, yoksa ayrı çeviri tablosu mu kullanmalıyım?

Dil sayısı sabit ve makulse (örneğin 5 dil) JSON sütun en basit ve en hızlı yoldur; tek sorguda tüm diller gelir. Çok fazla dil, dilleri ayrı sorgulama ihtiyacı veya çeviri durumu takibi gerekiyorsa ayrı bir translations tablosu daha esnektir.

Dili URL prefix'i mi yoksa oturum mu ile yönetmeliyim?

SEO önemliyse URL prefix (/en/...) tercih edin: her dilin indekslenebilir kendi adresi olur. Tamamen kişisel bir panel veya tek sayfalık bir uygulamaysa oturum/çerez tabanlı seçim yeterli ve daha sade olur.

fallback_locale ne işe yarar?

Seçili dilde bir çeviri anahtarı bulunamazsa Laravel otomatik olarak fallback_locale diline döner. Bu, henüz çevrilmemiş metinlerin boş görünmesini engeller; genellikle İngilizce olarak ayarlanır.

Çok dilli bir Laravel projesi mi planlıyorsunuz? İster sıfırdan kurulum, ister mevcut sitenizi çoklu dile taşıma olsun, mimariyi temiz ve sürdürülebilir kurmanıza yardımcı olabilirim. Benimle iletişime geçin.

Devamı için