Çok dillilik
Çok dillilik CPalius'ta eklenti değil, çekirdek özelliğidir. Üç ayrı konu vardır ve karıştırılmamalıdır:
- Siteyi hangi dillerde sunuyorsunuz? (dil listesi)
- İçerik çevirileri: bir sayfanın İngilizcesi ile Türkçesi nasıl bağlanır?
- Arayüz çevirileri: düğme, menü ve hata metinleri.
1. Diller
Etkin diller veritabanından okunur ve AACP → Sistem → Diller ekranından yönetilir (yetki: system.localization.manage). Bir dil eklerken kodu, İngilizce adı ve yerel adı elle yazmak zorunda kalmazsınız; ekleme penceresinde bir dil kataloğu vardır ("Deutsch" seçersiniz). Katalog bir izin listesi değildir: form [a-z]{2,5} biçimindeki herhangi bir kodu kabul eder.
Bir dil şunları taşır: code (tr), name (Turkish), nativeName (Türkçe), varsayılan mı, sıra numarası.
LocaleProvider dil bilgisinin tek kaynağıdır:
$provider->getCodes(); // ['tr', 'en']
$provider->getDefaultCode(); // 'tr'
$provider->isSupported('de'); // false
$provider->resolve('de'); // desteklenmiyorsa varsayılana düşer: 'tr'
.env içindeki CPALIUS_LOCALES ve CPALIUS_DEFAULT_LOCALE yalnızca veritabanına ulaşılamadığında ya da dil tablosu boşken kullanılır. Rota kısıtlarındaki %cpalius.locales_pattern% parametresi de derleme sırasında veritabanına ulaşılamazsa bu listeden üretilir. Listeyi değiştirdikten sonra cache:clear çalıştırın.
2. İçerik çevirileri
Bir içeriğin çevirisi ayrı bir satırdır. Aynı içeriğin farklı dillerdeki satırları ortak bir translation_group_id (UUID) paylaşır. Bu bir yabancı anahtar değildir; bir "grup etiketi"dir.
Node #12 tr slug=merhaba-dunya group=7c1e…
Node #19 en slug=hello-world group=7c1e…
Veritabanı kısıtları bütünlüğü sağlar:
UNIQUE(slug, locale): aynı dilde aynı adres iki kez olmaz; farklı dillerde olabilir.UNIQUE(translation_group_id, locale): bir grupta her dil için en çok bir çeviri vardır.
Küresel bir slug ya da grup kısıtı çok dilli veritabanını bozar; bu yüzden kısıtlar bileşiktir.
Studio'da çeviri
Bir içerik düzenlenirken çeviri sekmeleri görünür: var olan kardeşleri ve eksik dilleri gösterir (TranslationGroupResolver). Eksik bir dilde çeviri oluşturunca yeni satır aynı gruba bağlanır. Sorgu hatasında sekmeler boş kalır, sayfa düşmez.
Dil değiştirici
Ön yüzde mevcut sayfanın başka dildeki karşılığı LocaleSwitchService ile bulunur:
- Çeviri varsa slug karşılığına yönlendirilir.
- Çeviri yoksa aynı rota korunur ve hedef sayfa yumuşak bir "bu dilde yok" durumu gösterebilir; ana sayfaya sert 404 atlaması yapılmaz.
- Sayfaya
<link rel="alternate" hreflang>bağlantıları da bu servisle üretilir (alternateLinks).
Adres yapısı
Ön yüz adresleri dil önekiyle başlar: /tr/blog/..., /en/docs/.... Yönetim panelinin (/aacp, /admin) adresinde dil öneki yoktur; panel dili cp_locale çerezi ve kullanıcı tercihiyle seçilir.
Kullanıcının dili kayıt sırasında User::$data['locale'] içine yazılır; e-postalar ve bildirimler isteğin dili yerine alıcının diliyle üretilir (UserLocaleResolver).
3. Arayüz çevirileri
Arayüz metinleri Symfony çeviri dosyalarıdır (YAML):
cp-content/translations/messages+intl-icu.tr.yaml genel çeviriler
cp-content/translations/messages+intl-icu.en.yaml
cp-content/modules/<Ad>/Resources/translations/... modüle özgü
Varsayılan çeviri alanı (domain) messages+intl-icu'dur; bu ICU mesaj biçimidir ve çoğul ile sayı biçimlendirmesi destekler:
# messages+intl-icu.tr.yaml
docs.banner.latest: 'Bu, eski bir sürümün belgesidir. Güncel sürüm: {version}'
{{ 'docs.banner.latest'|trans({version: latest.label}) }}
Çeviri yöneticisi (AACP)
AACP → Yerelleştirme ekranı (TranslationManager) çekirdek ve tüm modüllerin çeviri dosyalarını tek yerden listeler ve düzenler:
- Anahtarı arama, değeri düzenleme (yazma atomiktir: önce
.tmp, sonra yeniden adlandırma) - Tamamlanma oranı: kaynak dile göre hedef dillerde eksik anahtarlar
- Eksik anahtar listesi (sayfalı)
- JSON ya da YAML olarak dışa/içe aktarma (anahtar × dil matrisi)
- Yeni bir dil açarken o dil için dosyaları tohumlama (
seedLocale)
Çeviri yapay zekayla yapılacaksa, çekirdek yalnızca sözleşmeyi (UiStringTranslatorInterface) tanımlar ve bir uygulama varsa "yapay zeka ile çevir" eylemleri görünür. Çekirdek hiçbir modülü doğrudan çağırmaz; uygulama yoksa düğmeler hiç çıkmaz.
Modül yazarı için kurallar
- Sabit metin bırakmayın. Etiket, mesaj ve hata için çeviri anahtarı kullanın.
- En az
trveendosyalarını birlikte yazın:cp:doctoriki dilin anahtar eşitliğini denetler. - Çevrilebilir bir varlık için
TranslatableInterfaceveTranslatableTraitkullanın (Nodeaynı kalıbı taşır). - Başka bir dilde şablon çizmeniz gerekirse (ör. e-posta),
LocaleScope::run($locale, $callback)kullanın: Twig'in|transfiltresi çevirmenin geçerli dilini okur ve geçici olarak başka dile geçmek gerekir. - Dile bağlı varlıklarda benzersizlik kısıtını dil ile birlikte tanımlayın.
final class Page implements TranslatableInterface
{
use TranslatableTrait;
// UNIQUE(slug, locale) ve UNIQUE(translation_group_id, locale)
}