He estado construyendo un marco personal mío que comenzó como una forma de aprender el patrón MVC y ahora ha progresado en algo que me gusta más que la mayoría de los marcos existentes (probablemente porque agrego lo que me gusta y cambio lo que no uso me gusta pero no obstante) y para bien o para mal lo uso en algunos proyectos.
El problema que tengo ahora es que no puedo encontrar una manera decente de acceder a mi funcionalidad i18n (no es realmente solo son traducciones, no incluye soporte completo de i18n, al menos todavía no).
La forma en que funciona es que uso archivos de configuración como archivos de idioma porque pensé que sería bastante conveniente usar la Config
clase para cargarlos, ya que en mi marco los archivos de configuración se cargan dinámicamente, no se cargan a menos que sea necesario, puede echar un vistazo aquí
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];
}
}
}
Donde un solo archivo de configuración se vería así
<?php return array(
'setting0' => 'value',
'setting1' => 'value',
....
);
Eso permite que PHP almacene en caché esos archivos y cargarlos se vuelve muy rápido.
Ahora a las traducciones, como dije, son archivos de configuración en un directorio diferente llamado lang
, pero no puedo simplemente llamar Config::get('lang/en/myLangFile')
cada vez que necesito acceder a una traducción, así que inventé (inventé, eh) la Translations
clase, que representa un archivo de traducciones individuales
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;
}
}
Ahora es muy conveniente y hermoso acceder a las traducciones.
$t = new Translations([...]);
echo $t->translationKey;
Tengo una Lang
clase que se usa para configurar el idioma preferido del usuario, entre otras cosas pequeñas, así que pensé que lo usaría como una fábrica para mis Translations
clases.
class Lang {
public static function get($file) {
return new Translations(Config::get('lang/' . self::$lang . '/' . $file));
}
}
Así que ahora todo lo que tengo que hacer para obtener algunas traducciones es
$t = Lang::get('myLangFile');
echo $t->translationKey;
En caso de que se pregunte por qué tengo tantas cosas estáticas es porque estas clases no tienen sentido ser instanciadas y no me gusta el patrón de diseño singleton, prefiero tener "clases estáticas" a pesar de que no son compatibles con PHP (¿todavía?).
Hasta ahora todo bien, tengo las traducciones en marcha, pero vayamos al problema (finalmente).
Cuando se visualiza una vista, lo más probable es que imprima algo de texto al usuario y para eso necesito tener un objeto de traducción disponible en el interior, pero es bastante inconveniente tener que pasarlo desde el controlador porque tendría que ir y ponlo en cada método y eso sería un infierno, además, si hago eso, entonces otro controlador llama a la misma vista sin los objetos de traducción correctos, todo se romperá, lo que tiene sentido pero agrega complejidad al programa.
Lo que he estado haciendo hasta este punto está en la parte superior de cada vista. Construyo mi objeto de traducción
<?php $t = Lang::get('myLangFile') ?>
<div><?= $t->helloWorld ?></div>
Esto funciona y me garantiza que mis puntos de vista funcionarán independientemente de quién los llame y, básicamente, no cuesta casi nada en términos de rendimiento porque crear una instancia Translations
no copiará la matriz que contiene la información a menos que se introduzca un cambio ya que el código en el constructor es solo una asignación, así que supongo que no hay problema con eso, pero solo me está molestando por alguna razón que no es lo correcto.
Además, necesitaré usar una Translations
clase en un modelo o validador ocasionalmente y también necesitaría crear una instancia allí, por lo que en una sola ejecución podría estar instanciando el mismo Translations
objeto varias veces. Para resolver este problema, necesitaría comenzar a colocar esos objetos en el registro y creo que esto iría demasiado lejos.
Me gustaría ver cuáles son algunos pensamientos sobre este enfoque, ya que podría ser cegado por los míos y posiblemente obtener algunos consejos y cosas útiles. Gracias de antemano a cualquiera que haya elegido dedicar su tiempo a mi problema
fuente