# Metin ve Şablon Geçersiz Kılma

https://dev.wisecp.com/tr/metin-ve-sablon-gecersiz-kilma

Getirilen bir metni ya da işaretlemeyi, güncellemenin geri almayacağı biçimde değiştirin.

## Genel Bakış

Görünen her dize bir dil dosyasından, her ekran bir şablondan gelir. Düzenlemeleri bir sonraki sürüm ezer.

Dört dikiş: çeviri filtresi, tema içerik katmanı, değişken filtresi ve enjeksiyon noktaları.

## Ön Koşullar

- Dizenin tam anahtarı; aynı kelime birkaç pakette bulunur.
- Dinleyici için bir yer: kanca dizini ya da modülünüz.
- Kurulu dillerin listesi; bir dizin listesidir, sabit çift değil.

## Yapı

Metni dört depo tutar, her birinin kendi erişimcisi vardır. Yanlışına uzanmak sessizdir.

| Depo | Yol | Okuma |
| --- | --- | --- |
| Kök paketler: needs, date, errors, actions, constants, blocks, rotalar | `coremio/locale/{dil}/{ad}.php` | `Language::g()` |
| Controller paketleri, sayfa başına bir | `coremio/locale/{dil}/cm/{admin\|website\|system}/{ad}.php` | `Language::gc()` |
| Modül dizeleri | `coremio/modules/{Tip}/{Ad}/lang/{dil}.php` | Modülün içinde `$this->lang['anahtar']` |
| Tema dizeleri ve sayfa metinleri | `templates/website/{Tema}/locale/{dil}.php` | `Language::gc("theme/anahtar")` |

Panel düzenlemeleri `content/{dil}/{kapsam}.php` dosyasına yazılır ve kazanır. Güncelleme `content` dizinine dokunmaz.

## Adım Adım

### Anahtarı Bulun

1. Dizenin hangi depoya ait olduğuna ekrana bakarak karar verin.
2. Dil dizininde uydurduğunuz anahtarı değil, görünen metni arayın.
3. Tahmininizi komut satırında doğrulayın: kök erişimci `false` döndürür.
4. Dili not edin: bir dilde çözülen anahtar diğerleri hakkında bir şey söylemez.

### Var Olan Bir Dizeyi Ezin

1. Controller paketi dizesi için çeviri filtresine dinleyici kaydedin ve değeri yerinde değiştirin.
2. Dinleyiciyi ucuz tutun: çözülen her controller dizesinde çalışır.
3. Website metinleri için dinleyici yazmayın; değişikliği tema içerik katmanına koyun.
4. Filtre kök paket dizelerine ulaşmaz.

### Yeni Bir Dize Ekleyin

1. Sayfanın paketini seçin ve anahtarı komşularıyla aynı biçimde ekleyin.
2. Onu ikisine değil, **kurulu her dile** ekleyin. Eksik anahtar `false` çözülür ve etiket hiçbir yerde hata olmadan bomboş görünür.
3. Eğik çizgili anahtarda iç içe dizi kullanın: her çizgi bir derinlik seviyesidir.
4. Görünen bir dizeyi asla şablona ya da operation'a sabit yazmayın.

### Bir Şablonu Ezin

1. Şablonun *aldığını* mı yoksa *bastığını* mı değiştireceğinize karar verin. Farklı dikişleri vardır ve ilki çok daha ucuzdur.
2. Veriyi değiştirmek için değişkenleri şablon yoluyla filtreleyin.
3. İşaretlemeyi değiştirmek için en yakın enjeksiyon noktasını kullanın.
4. Açık bir sayfayı değiştirmek için view'ı temanıza kopyalayın.

## Referans

### Erişimciler

```php
// Kök paketler. $key "{dosya}/{anahtar}/{altanahtar}" biçimindedir, dizi
// seviyesi başına bir eğik çizgi. Eksik segmentte false döner. Dil fallback'i YOKTUR.
public static function g($key = '', $replaces = [], $slang = ''): array|string|int|bool;

// cm/ altındaki controller paketleri. Aynı biçim, alan için bir ek baş segment.
public static function gc($name = '', $replaces = [], $slang = ''): array|string|int|bool;

// Aktif dil kodu, örneğin "en".
public static function selected(): string;

// Makine değerinden insan etiketine. $dictionary, değerin ekleneceği locale önekidir
// ("admin/orders/status-"), '@toggle' ya da '@list:{önek}'.
// Bilinmeyen değer boş dizeye değil kendisine düşer.
public static function enum_label($value = '', $dictionary = '', $slang = ''): string;

// Tek bir paket dosyasını yazar. Aşağıdaki uyarıya bakın: BİRLEŞTİRMEZ, EZER.
public static function save($key = '', $data = [], $lk = ''): int|bool;
```

- **Language::g()**: Yalnız kök paketler. Kendisine bir controller anahtarı verilirse `false` döner ve çağıranın yedek değeri bunu genelde gizler.
- **Language::gc()**: Yalnız controller paketleri. Bir kök paket adı **boş dizi** döndürebilir ve düz bir doğruluk kontrolünden geçer.
- **Argüman sırası**: İki statik erişimci de değiştirmeleri ikinci, dili üçüncü alır. Instance metotları anlaşmaz.
- **Language::enum_label()**: Saklanmış durumu etikete çevirir. Denetim satırları ham değeri korur.

### Bir Anahtar Nasıl Görünebilir

```php
<?php
return [
    // Düz. Language::gc('admin/services/page-list') ile okunur.
    'page-list' => 'Services',

    // Yer tutuculu. İki gösterim de vardır ve ikisi de birebir arama hedefidir:
    // değiştirme haritasının anahtarları, süslü parantez ya da iki nokta dahil
    // yazıldığı gibi eşleştirilir.
    'welcome'   => 'Hello {name}, you have {count} messages.',
    'meta-title' => 'Service detail - :name',

    // Bildirimli biçim. g()/gc() 'content' dizesini döndürür; 'variables' çeviri
    // araçları için meta bilgidir ve ekrana hiç ulaşmaz.
    'quota-warning' => [
        'content'   => 'Only {left} of {total} remaining.',
        'variables' => '{left},{total}',
    ],

    // Anahtardaki eğik çizgi DERİNLİKTİR, adın parçası değil. Bu,
    // Language::gc('admin/services/labels/renew') çözülsün diye tek yoldur.
    'labels' => [
        'renew'   => 'Renew',
        'suspend' => 'Suspend',
    ],
];
```

- **Eksik anahtar**: `false` çözülür; dil fallback'i ve log kaydı yoktur. Ekranda boş bir etiket.
- **Yer tutucu değişimi**: Anahtarların düz metin değişimi; değerde göründüğü gibi geçirin.
- **Site adresi jetonu**: Controller dizeleri bir değişimi bedava alır: `{SITE-URL}` taban adrese dönüşür.

### Dört Dikiş

- **filter:i18n.translation**: Her **controller paketi** dizesinde referansla ateşlenir. Argümanlar: değer, anahtar, dil. Kök paketler ulaşmaz; dönüş kullanılmaz.
- **filter:template.variables**: Her şablonda, değişkenler açılmadan önce ateşlenir. Argümanlar: şablon yolu, veri dizisi. Dizi döndürmek veriyi **tümüyle değiştirir**.
- **Tema içerik katmanı**: `content` dosyaları `locale` anahtarlarını ezer. Panelden yazılır, paketlenmez.
- **ui: enjeksiyon noktaları**: Birkaç yüz konum, dinleyicilerinin döndürdüğünü kaçırmadan gösterir. Panelin stil yuvası.
- **ui:client.head.css**: Yukarıdakinin açık site ikizi. İşaretlemeyi döndürün; dize olmayan dönüş düşer.
- **filter:i18n.translation_save**: Çeviri düzenleyicisinde yazılanı filtreler. Değerler referansla gelir, dönüş kullanılmaz.

### Bir Tema Bir Dizeyi Nasıl Çözer

```php
// Tek bir dize, isteğe bağlı yer tutucu değişimiyle.
public function lang(string $key, array $vars = []): string;

// İçerik düzenleyicisinin kendi yüzeyi; okumak ya da yazmak isteyen modül için.
public static function contentScopes(string $themeName): array;
public static function scopeDefaults(string $themeName, string $lang, string $scope): array;
public static function scopeOverrides(string $themeName, string $lang, string $scope): array;
public static function writeScopeOverrides(string $themeName, string $lang, string $scope, array $values): bool;
```

| Sıra | Kaynak | Not |
| --- | --- | --- |
| 1 | Operatörün ezmesi | Altındaki her şeyi yener |
| 2 | Temanın aktif dildeki kendi metni | `locale/{dil}.php` ile `locale/{dil}/{kapsam}.php` birleşimi |
| 3 | Aynı anahtarın İngilizcesi | Metin sisteminin herhangi bir yerindeki tek dil fallback'i |
| 4 | Çekirdek paketleri, önce controller sonra kök | Platform dizesini yeniden kullandırır |
| 5 | Anahtarın kendisi | Burada hiçbir şey boş kalmaz |

Kapsam ya `common`'dır ya da bir view yoludur. `page` altındaki bir view o öneki düşürür.

### Paket Dosyası Yazma

> **Yazıcı dosyayı değiştirir, birleştirmez**
> 
> Verdiğiniz dizi dosyanın tamamı olur. Boş dizi döndüren bir erişimciyle birleşince paketi tek anahtara indirebilir.

## Örnek

Bir terimi dil dosyasına dokunmadan yeniden adlandırmak.

```php
// Anahtar => karşılık, dil başına. Harita araması dinleyiciyi O(1) tutar; panelin
// her dizesi üzerinde bir str_replace burada kabul edilebilir olmazdı.
const ACME_WORDING = [
    'en' => [
        'admin/services/page-list'  => 'Subscriptions',
        'admin/services/page-title' => 'Subscription detail',
    ],
    'tr' => [
        'admin/services/page-list'  => 'Abonelikler',
        'admin/services/page-title' => 'Abonelik detayı',
    ],
];

Hook::add('filter:i18n.translation', 10, function (&$value, $key, $lang) {
    // Buraya yalnız controller paketi dizeleri gelir ve yalnız bir dizeye çözüldüklerinde:
    // olmayan bir anahtar bu kancayı hiç ateşlemez, dolayısıyla bir boşluk buradan
    // doldurulamaz.
    $value = ACME_WORDING[$lang][$key] ?? $value;
});
```

Bir şablonun aldığı veriyi değiştirmek; dinleyiciyi yol testi daraltır.

```php
Hook::add('filter:template.variables', 10, function ($template_path, $data) {
    // Normalleştirme: yol, platformun dizin ayracıyla gelir.
    $path = str_replace('\\', '/', (string) $template_path);

    if (!str_ends_with($path, 'admin/services/detail.php')) return null;   // bizim değil

    // Dönüş değeri $data'nın TAMAMININ yerine geçer. Gelen dizinin üzerine inşa etmek
    // bir üslup tercihi değildir: template_dir ya da ui_lang düşerse render bozulur.
    $data['acme_banner'] = Language::gc('admin/services/acme-banner');

    return $data;
});

// İşaretleme, platformun ilan ettiği bir konumda. Dönüş değeri olduğu gibi basılır,
// yani içindeki değişken her şey burada kaçışlanmak zorundadır.
Hook::add('ui:admin.head.css', 10, fn (): string
    => '<link rel="stylesheet" href="' . Utility::AppAdress() . '/resources/acme/panel.css">');
```

Kendi dizenizi eklemek, kurulu her dile.

```php
// Kurulu diller bir dizin listesidir, asla koda gömülü bir çift değil.
$langs = array_map('basename', glob(ROOT_DIR . 'coremio' . DS . 'locale' . DS . '*', GLOB_ONLYDIR) ?: []);

foreach ($langs as $lang) {
    // O dilde açıkça çözün: üçüncü argüman, ikinci değil.
    $existing = Language::gc('admin/services/acme-banner', [], $lang);

    // false, anahtarın ORADA olmadığı demektir; İngilizcede çözülüyor olsa bile.
    if ($existing === false)
        echo 'missing in ' . $lang . PHP_EOL;
}

// Tek bir anahtarı tek bir dilde, komut satırından okumak; bir paketin hangi erişimciye
// ihtiyaç duyduğu tartışmasını böyle bitirirsiniz.
var_dump(Language::g('needs/untitled', [], 'tr'));    // dize, kök paket
var_dump(Language::gc('needs/untitled', [], 'tr'));   // false, yanlış erişimci
```

Ve tema tarafı; burada ezme bir dinleyici değil bir dosyadır.

```php
<?php
// Yalnız bu tema için locale/en/home.php içindeki eşleşen anahtarları ezer.
// Bu dosyayı panel yazar; bir modül de tema API'si üzerinden yazabilir.
// Yükseltme locale/ dizinini değiştirir, content/ dizinini asla; ezme böylece yaşar.
return [
    'hero-title'    => 'Hosting that stays out of your way',
    'hero-subtitle' => 'Deploy in a minute, scale when you need to.',
];
```

```php
$theme = Theme::active()->getName();

// Gönderilen varsayılanları ve operatörün mevcut ezmelerini ayrı ayrı okuyun:
// bunlar iki katmandır ve yazmadan önce birleştirmek varsayılanları dondururdu.
$defaults  = Theme::scopeDefaults($theme, 'en', 'home');
$overrides = Theme::scopeOverrides($theme, 'en', 'home');

$overrides['hero-title'] = 'Hosting that stays out of your way';

// Boş bir dizi, ezme dosyasını tümüyle kaldırır ve varsayılanları geri getirir.
Theme::writeScopeOverrides($theme, 'en', 'home', $overrides);
```

## Tuzaklar

> **Yanlış erişimci sessizce başarısız olur, sonra veri yok eder**
> 
> Dil fallback'i ve uyarı yoktur: eksik segment false ya da boş dizi döndürür. Her okumayı bir varsayılanla koruyun.

> **İki dil, dil listesi değildir**
> 
> Kurulu dilleri dizinden okuyun; eksik kalan dilde anahtar hiçbir şey göstermez.

> **Değişken filtresi değiştirir, birleştirmez**
> 
> Yalnız kendi eklemelerinizi döndürmek şablonun her şeyini siler. Gelen diziye ekleyip tamamını döndürün.

> **Çeviri filtresi sayfa başına yüzlerce kez çalışır**
> 
> Çözülen her controller dizesi ondan geçer. İşi harita aramasıyla sınırlayın.

> **Anahtar adındaki eğik çizgi bir karakter değil, bir seviyedir**
> 
> Her segment başka bir dizi seviyesidir; eğik çizgili düz bir anahtar bulunamaz.

## İlgili Makaleler

- [Çeviriler ve Dil Dosyaları](https://dev.wisecp.com/tr/ceviriler-ve-dil-dosyalari)
- [View ve Şablonlar](https://dev.wisecp.com/tr/view-ve-sablonlar)
- [Tema Çevirisi](https://dev.wisecp.com/tr/tema-cevirisi)
- [Kanca Dinleyicisi Yazma](https://dev.wisecp.com/tr/kanca-dinleyicisi-yazma)
- [Çekirdeğe Dokunmadan Çalışma](https://dev.wisecp.com/tr/cekirdege-dokunmadan-calisma)
- [Çekirdek Yükseltmesini Atlatma](https://dev.wisecp.com/tr/cekirdek-yukseltmesini-atlatma)
