# Çeviriler ve Dil Dosyaları

https://dev.wisecp.com/tr/ceviriler-ve-dil-dosyalari

İnsanın okuduğu hiçbir şey koda yazılmaz. Metin dil dosyalarında yaşar, anahtarla aranır ve eksik anahtar beklediğiniz metni değil false döndürür.

## Genel Bakış

Bir kurulum aynı anda birden çok dile hizmet eder ve dil ziyaretçi başına seçilir. Bu yüzden bir koşulun, bir exception'ın ya da bir şablonun içindeki sabit metin kısayol değildir; bir grup kullanıcının kendi dilinde asla göremeyeceği ve hiçbir çevirmenin ulaşamayacağı bir metindir.

İki arama her şeyi karşılar: biri kök dil dosyaları, diğeri `cm/` altındaki ekran dosyaları için. İkisi de eğik çizgiyle ayrılmış bir yolu iç içe dizilerde yürür.

## Referans

```php
public static function g($key = '', $replaces = [], $slang = ''): string|int|array|bool;
public static function gc($name = '', $replaces = [], $slang = ''): string|int|array|bool;
public static function selected(): string;

// Instance metot, singleton üzerinden çağrılır: Language::$init->rank_list()
public function rank_list($status = 'active'): array;

// İki statik yardımcının devrettiği instance metotlar. Argüman sırasına dikkat:
// get() dili ikinci sıraya, get_cm() değiştirmeleri ikinci sıraya alır.
public function get($arg = null, $slang = '', $replaces = []): string|int|array|bool;
public function get_cm($arg = null, $replaces = [], $slang = ''): string|int|array|bool;
```

- **Language::g()**: Kök dil dosyasından bir anahtar. Metni döndürür; yolun herhangi bir parçası eksikse `false` döner.
- **Language::gc()**: `cm/` altındaki ekran dosyasından bir anahtar. Yardımcılarda, modüllerde ve exception'larda bunu kullanın: dosyasını kendisi adlandırır, mevcut ekranın ne yüklediğine bel bağlamaz.
- **Language::selected()**: Hizmet edilen dil kodu, örneğin `en`. Dil katmanı henüz ayakta değilse kurulumun kendi diline düşer, yani komut satırında da güvenlidir.
- **Language::$init->rank_list()**: Kurulumun dilleri, gösterim sırasıyla. Instance metottur: statik bir `Language::rank_list()` YOKTUR.

### Hangi Arama Hangi Dosyayı Okur

| Çağrı | Okuduğu | Yol biçimi |
| --- | --- | --- |
| `Language::g("needs/button-save")` | Kök dil dosyaları: `needs`, `date`, `errors`, `actions`, `package` | `{dosya}/{anahtar}/{alt-anahtar}` |
| `Language::gc("admin/services/page-list")` | `cm/` altındaki ekran dosyaları, alana göre gruplanmış | `{alan}/{dosya}/{anahtar}`; alan `admin`, `website` ya da `system` |
| `Language::gc("theme/hero-title")` | Aktif temanın kendi dil dosyası | `theme/{anahtar}` |

Her eğik çizgi bir dizi seviyesidir, adın parçası değil. `'job-title/daily'` gibi düz yazılmış bir anahtar hiçbir zaman bulunmaz; iç içe dizi olmak zorundadır.

### Yer Tutucular ve Değiştirme Haritası

İkinci argüman, **yer tutucunun düz metnini** (süslü parantezi ya da iki noktası dahil) karşılığına eşler. Düz bir metin değiştirme olduğu için anahtarlar dosyadakiyle harfi harfine aynı olmalıdır.

```php
// coremio/locale/tr/cm/admin/departments.php
return [
    'error1'  => '{lang} dili için ad zorunludur.',

    // content/variables biçimi hangi yer tutucuların olduğunu bildirir.
    // Aramalar content dizesini döndürür, sarmalayıcıyı asla.
    'welcome' => [
        'content'   => 'Merhaba {name}, {count} mesajınız var.',
        'variables' => '{name},{count}',
    ],
];

// Çağrı. Anahtarlar kendi parantezlerini taşır; ':name' biçimi de aynı çalışır.
$msg = Language::gc("admin/departments/error1", ['{lang}' => "TR"]);      // "TR dili için ad zorunludur."
$hi  = Language::gc("admin/departments/welcome", ['{name}' => $name, '{count}' => 3]);

// Üçüncü argüman, hizmet edilen dil yerine tek bir dili zorlar.
$en  = Language::gc("admin/departments/error1", ['{lang}' => "EN"], "en");
```

### Dil Listesi Ne Döndürür

Satır biçimi argümana göre değişir, bu yüzden ikisi birbirinin yerine geçmez: `active` dil değiştirici için hazırlanmış gösterim satırlarını, `all` ise kapalı olanlar dahil kurulu her dilin ham paket kaydını döndürür.

```php
// Language::$init->rank_list()          açık diller, rank sırasıyla
[
    'rank' => 2, 'local' => 0, 'selected' => true, 'key' => 'en',
    'name' => 'English', 'global-name' => 'English',
    'link' => 'https://example.test/en/services',        // bu sayfanın o dildeki adresi
    'cc' => '', 'cname' => 'Worldwide', 'pc' => 1,
    'flag-img' => 'https://example.test/resources/assets/images/flags/en.svg',
];

// Language::$init->rank_list("all")     kurulu her dil, paket kaydı
// Kaydın tamamı, bu sırayla. 'key' ve 'country-name' çağrının kendisi tarafından
// eklenir; 'local' paket bayrağından değil general/local'dan (kurulumun varsayılan
// dili) türetilir; geri kalanı paket dosyasının diskteki hâlidir.
[
    'create-date' => '2018-06-21 10:15:48',
    'name' => 'English', 'show-name' => 'English',
    'country-id' => 0, 'country-code' => '',
    'code' => 'en', 'code-hyphen' => 'en_US',
    'scharacters' => '', 'charset-code' => 'UTF-8',
    'phone-code' => 1, 'currency' => 1, 'rank' => 2,
    'permalink' => true, 'prefix' => 'enabled', 'status' => true,
    'local' => false, 'rtl' => false,
    'key' => 'en', 'country-name' => 'Worldwide',
];
```

### Sayı Taşıyan Metin

```php
public static function plural(string $key, int|float $n, array $replaces = [], string $slang = ''): string;
public static function plural_set(string $key, string $slang = ''): array;
public static function plural_category(int|float $n, string $slang = ''): string;
```

- **plural()**: Bir sayıya uyan biçimi seçer. Biçimi `n === 1` ile kendiniz seçmeyin; bu yalnızca iki biçimli dillerde doğrudur. Rusça üç biçim ister, Arapça altı.
- **plural_set()**: Yalnızca tarayıcının bildiği bir sayı için tüm biçimler. Sunucu kümeyi gönderir, seçimi sayfada `wcpPlural()` yapar.
- **plural_category()**: Bir sayının düştüğü kategori: `one`, `few`, `many`, `other` ve diğerleri.

### Dil Şeritli Formlar

```php
public static function form_langs(array $defined = []): array;
public static function posted_langs(): array;
public static function removed_langs(): array;
```

- **form_langs()**: Bir kaydın şeridinin açılacağı diller: birincil dil ve kaydın hâlihazırda taşıdıkları.
- **posted_langs()**: Gönderilen formun bildirdiği diller. Kaydederken `rank_list()`'i değil bunları gezin. Yöneticinin hiç açmadığı dil de boş değer gönderir; onu kayıtlı çevirinin üzerine yazmak çeviriyi siler.
- **removed_langs()**: Yöneticinin kapatıp onayladığı diller. Birincil dil asla bunların arasında olamaz.

### Metin Nerede Yaşar

- **coremio/locale/{dil}/**: Uygulama metni; dil başına bir dizin, ekranları yansıtan paketlere bölünmüş.
- **Modül dosyaları**: Her modül kendi `lang/` dizinini taşır; constructor onu `$this->lang` içine yükler. Metni uygulamanınkine eklenmek yerine modülle birlikte gezer.
- **Tema dosyaları**: Tema da kendi metnini taşır; `theme/` önekiyle okunur, böylece iki tema aynı şeyi farklı adlandırabilir.
- **Çevrilmiş kayıtlar**: Operatörün yazdığı içerik veritabanında, kaydın yanında dil başına bir satır olarak yaşar.

## Örnek

```php
// Paketi zaten yüklü bir ekranın içinde.
$title = Language::g("needs/button-save");

// Başka her yerde: önce dosya, sonra anahtar.
throw new Exception(Language::gc("admin/services/error-not-found"));

// Hizmet edilen dil için çeviri tablosunu join etme.
$lang  = Language::selected();
$rows  = WDB::select("t1.id, COALESCE(t2.name, t1.name) AS name")
    ->from("products AS t1")
    ->join("LEFT", "products_lang AS t2", "t2.owner_id=t1.id AND t2.lang='" . $lang . "'")
    ->build();

// Dil değiştirici.
foreach (Language::$init->rank_list() as $l)
    $items[] = ['label' => $l["name"], 'href' => $l["link"], 'on' => $l["selected"]];
```

```php
// coremio/locale/tr/cm/admin/services.php   ve aynı anahtar diğer her dilde
return [
    'page-list'        => 'Hizmetler',
    'error-not-found'  => 'Hizmet bulunamadı.',

    // İç içe, yani yolu admin/services/errors/timeout olur
    'errors' => [
        'timeout' => 'Sağlayıcı zaman aşımına uğradı.',
    ],
];

// Bir ekran dil dosyasını düzenlediğinde koddan geri yazılır.
Language::save("admin/services", $data, "tr");
```

## Tuzaklar

> **Değiştirmeler ikinci, dil üçüncü sıradadır**
> 
> İki statik yardımcı da değiştirme haritasını ikinci, dil kodunu üçüncü sırada alır. `g()` metodunun devrettiği instance metot bu sırayı tersine çevirir; sınıfın içinden kopyalanan bir parça haritanın yerine dil kodu koyar. Statik çağrıya dili ikinci sırada geçmek sessizce hiçbir değiştirme yapmaz ve hata da vermez.

> **Eksik anahtar false döndürür**
> 
> Boş dize değil, anahtarın kendisi de değil. `Language::gc("...") ?: "Bir metin"` biçiminde yazıldığında yedek değer eksikliği sonsuza kadar gizler; anahtar canlı görünürken dil dosyasında hiç var olmamıştır. Şüpheli bir anahtarı komut satırında kontrol edin ve boolean değil string bekleyin.

> **İç içe anahtar, içinde eğik çizgi olan anahtarla aynı şey değildir**
> 
> Yol biçimi iç içe dizilerin içine yürür, eğik çizgi başına bir seviye. `'meta-detail/title'` olarak düz tanımlanmış bir anahtara ulaşılamaz; yalnız son parçasını aramak da yanlış kaydı bulur ya da hiçbir şey bulmaz.

> **İstekteki ilk dil listesi kalanların biçimini belirler**
> 
> İki argüman tek bir önbelleklenmiş listeyi paylaşır ve `all` onu üzerine yazar. İstek içinde bir kez `all` istendikten sonra, sonraki her `rank_list()` gösterim satırları yerine paket kayıtlarıyla cevap verir: `link`, `selected`, `global-name` ve `flag-img` anahtarları hiç yoktur, yalnız-açık diller filtresi de onlarla birlikte gider. Bu, aynı istekte yönetim ekranından sonra gösterilen bir dil değiştiricide ortaya çıkar ve eksik her anahtar hata değil, kaydedilen bir uyarıdır. Gösterim satırlarını `all` istenmeden önce alın ya da kendi kopyanızı tutun.

> **Anahtarı yalnız kendi dilinize değil hepsine ekleyin**
> 
> Metin eklemek, kurulumun gönderdiği her dil dosyasına yapılan bir değişikliktir. Veritabanındaki kayıtlar farklı davranır: aktif dilde çevirisi olmayan bir satır kendi değerini gösterir; ikisinin ayrı kodla ele alınmasının sebebi budur.

## İlgili Makaleler

- [Kod Konvansiyonları](https://dev.wisecp.com/tr/kod-konvansiyonlari)
- [Modül Dil Dosyaları](https://dev.wisecp.com/tr/modul-dil-dosyalari)
- [Tema Çevirisi](https://dev.wisecp.com/tr/tema-cevirisi)
- [Metin ve Şablon Geçersiz Kılma](https://dev.wisecp.com/tr/metin-ve-sablon-gecersiz-kilma)
