Acceso a objetos i18n desde diferentes ámbitos


10

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 Configclase 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 Translationsclase, 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 Langclase 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 Translationsclases.

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 Translationsno 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 Translationsclase 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 Translationsobjeto 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

Respuestas:


0

<?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 de Traducciones 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.

Entiendo lo que quieres decir ...
Creo que una cosa que podría molestarte es que al agregar a la vista la responsabilidad de cargar los archivos de idioma, estás rompiendo el patrón de diseño de Inversión de control.
Por eso, por ejemplo, su 'myLangFile' se hace demasiado grande y desea dividirlo en 2 archivos separados, no puede hacerlo sin cambiar el código de vista.
¿Qué piensas?


1
Exactamente, esa es una razón absolutamente válida.
php_nub_qq

1
De Verdad? ¿El archivo de idioma no puede incluir otros archivos en sí mismo? O leer de una base de datos?
svidgen

@svidgen que es un diseño extremadamente malo
php_nub_qq
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.