Ho creato un mio framework personale che è iniziato come un modo per apprendere il pattern MVC e ora è progredito in qualcosa che mi piace più della maggior parte dei framework là fuori (che probabilmente è perché aggiungo ciò che mi piace e cambio ciò che non mi piace, ma comunque) e nel bene o nel male lo uso in alcuni progetti.
Il problema che ho ora è che non riesco a trovare un modo decente per accedere alla mia funzionalità i18n (in realtà non è proprio la traduzione, non include il supporto completo per i18n, almeno non ancora).
Il modo in cui funziona è che utilizzo i file di configurazione come file di linguaggio perché ho pensato che sarebbe stato abbastanza comodo usare la classe Config
per caricarli poiché nel mio framework i file di configurazione sono caricati dinamicamente - non caricati se non necessario, è possibile guarda qui
class Config {
private static $settings = array();
private function __construct() {
}
public static function load($file) {
$path = PROJECT_PATH . '/config/' . $file . '.php';
if (is_file($path)) {
$settings = require($path);
} else {
throw new Exception('Configuration file [' . $file . '] doesn\'t exist', 500);
}
self::$settings[$file] = $settings;
return true;
}
public static function get($file = null) {
if ($file === null) {
return self::$settings;
} elseif (isset(self::$settings[$file]) || self::load($file)) {
return self::$settings[$file];
}
}
}
Dove un singolo file di configurazione sarebbe simile a questo
<?php return array(
'setting0' => 'value',
'setting1' => 'value',
....
);
Ciò consente a PHP di memorizzare nella cache quei file e caricarli diventa molto veloce.
Ora alle traduzioni, come ho detto sono file di configurazione in una directory diversa denominata lang
, ma non posso andare in giro chiamando Config::get('lang/en/myLangFile')
ogni volta che ho bisogno di accedere a una traduzione, quindi ho inventato (inventato , huh) la classe Translations
, che rappresenta un singolo file di traduzione
class Translations {
protected $data = [];
public function __construct(array $translations) {
$this->data = $translations;
}
public function __get($name) {
return isset($this->data[$name]) ? $this->data[$name] : $name;
}
}
Ora è super conveniente e bello accedere alle traduzioni
$t = new Translations([...]);
echo $t->translationKey;
Ho una classe Lang
che viene utilizzata per impostare la lingua preferita dell'utente tra le altre piccole cose, quindi ho pensato che l'avrei usata come factory per le mie Translations
classes
class Lang {
public static function get($file) {
return new Translations(Config::get('lang/' . self::$lang . '/' . $file));
}
}
Quindi ora tutto quello che devo fare per prendere alcune traduzioni è
$t = Lang::get('myLangFile');
echo $t->translationKey;
Nel caso ti stia chiedendo perché ho così tanta roba statica è perché queste classi non hanno senso essere istanziate e non mi piace il disegno del singleton, preferisco avere "classi statiche" anche se non lo sono supportato in PHP (ancora?).
Fin qui tutto bene, ho le traduzioni in corso, ma consentirò di arrivare al problema (finalmente).
Quando una vista è renderizzata è molto probabile che stampi del testo all'esterno all'utente e per questo ho bisogno di avere un oggetto di traduzione disponibile all'interno, ma è piuttosto scomodo doverlo passare dal controller perché avrei per andare a metterlo su ogni metodo e sarebbe un inferno, inoltre se lo faccio allora qualche altro controller chiama la stessa vista senza che gli oggetti di traduzione corretti si spezzino, il che ha senso ma aggiunge complessità al programma.
Quello che ho fatto fino a questo momento è in cima a ogni vista. Costruisco il mio oggetto di traduzione
<?php $t = Lang::get('myLangFile') ?>
<div><?= $t->helloWorld ?></div>
Questo funziona e mi garantisce che le mie visualizzazioni funzioneranno indipendentemente da chi le chiama e fondamentalmente non costa praticamente nulla in termini di prestazioni perché l'istanziazione di Translations
non copierà la matrice che contiene le informazioni a meno che non venga introdotta una modifica dal codice nel costruttore è solo un incarico, quindi credo che non ci siano problemi, ma mi disturba solo per qualche ragione che non è la cosa giusta da fare.
Inoltre dovrò usare occasionalmente una classe Translations
in un modello o validatore e avrei bisogno di istanziarla anche lì, quindi in una singola esecuzione potrei creare istanze multiple dello stesso oggetto Translations
. Per risolvere questo problema avrei bisogno di iniziare a mettere quegli oggetti nel registro e penso che sarebbe troppo lontano.
Mi piacerebbe vedere quali sono alcuni pensieri su questo approccio in quanto potrei essere accecato dal mio e possibilmente ricevere alcuni consigli utili e cose del genere. Grazie in anticipo a tutti coloro che hanno scelto di risparmiare tempo con il mio problema!