Error con setlocale()… devuelve false

i18nLos usuarios de Ubuntu, pueden encontrarse con un problema al hacer una llamada a la función setlocale() encargada de asignar el idioma correcto para, por ejemplo, llamar a la función getText() y que recoja las traducciones en el idioma correcto.

El problema está en que únicamente podemos cargar los idiomas que están presentes en el sistema operativo y si intentamos cargar uno diferente, setlocale() nos devolverá siempre false.

Podemos saber los idiomas cargados en el sistema operativo mediante el comando:

locale -a

Esto nos devolverá un listado similar a este:

C
en_GB.utf8
en_IN
en_NG
en_US.utf8
POSIX

Si estámos intentando cargar el idioma es_ES (como era mi caso), le resultará imposible… la solución, instalar los idiomas que necesitamos lanzando el comando:

apt-get install language-pack-es-base

Posteriormente, reiniciaremos Apache:

/etc/init.d/apache2 reload

Y le indicaremos a nuestro programa que cargue el idioma con el mismo nombre que lo encontramos en nuestro sistema, es decir, en mi caso:

setlocale( LC_MESSAGES, “es_ES.UTF8” );

Y con esto conseguiremos que nuestro programa quede internacionalizado de manera correcta.

Error SVN Working Copy locked y cleanup

En alguna ocasión me he encontrado con que no puedo hacer update de un proyecto porque SVN indica el error:

Working copy xxxxxxxx locked Please execute “Cleanup” command

Pero cuando lanzao el comando cleanup también devuelve un error:

Cleanup failed to process the following paths: xxxxxx

Con lo que aparentemente, la única solución que queda es hacer un checkout nuevo e intentar no perder los cambios, sin embargo, existe otra solución:

  1. Copia los archivos editados en otra carpeta para evitar perder los cambios
  2. Borra la carpeta que esté causando el problema
  3. Ahora podrás hacer update
  4. Copia los archivos editados en la carpeta (no copies las carpetas enteras porque contienen directorios .svn que volverán a darte problemas)
  5. Por último, haz commit

Espero os sea de utilidad.

Smarty3 y autoload

Smarty Logo

Uno de los errores comunes al implementar Smarty3 es:

Fatal error: Class ‘Smarty_Internal_Wrapper’ not found

Fatal error: Class ‘Smarty_Internal_Register’ not found

Fatal error: Class ‘Smarty_Internal_Template’ not found

Estos se deban, probablemente, a que en tu aplicación estás utilizando la función __autoload también necesaria por Smarty3. La solución a este problema pasa por utilizar la función que PHP nos brinda spl_autoload_register.

En una aplicación, sólo puede existir una llamada a la función __autload, sin embargo, con spl_autoload_register podemos añadir tantos manejadores como queramos y estos se irán ejecutando en el orden en el que los hayamos registrado.

Un ejemplo sencillo de su uso sería:


class AutoloadHandler
{
static public function launch( $classname )
{
print '[['. $name .']]';
}
}

spl_autoload_register( 'AutoloadHandler::launch' );

new ThisClassNotExists();

El resultado de ejecutar este script sería algo así:

[[ThisClassNotExists]]

Fatal error: Class ‘ThisClassNotExists’ not found in …

El cual nos indica que está llamando de manera correcta al autoload, pero al no estar implementado de manera correcta y no existir la clase ‘ThisClassNotExists’ nos devuelve un error.

En definitiva, para solventar el problema, no será necesario que modifiques el código Smarty, pues este ya está utilizando de manera correcta spl_autoload_register, lo que debes hacer es sustituir tu __autoload por una clase con una función ‘launch’ (llámala como quieras) y registrarla mediante:

spl_autoload_register( 'MyAutoloadHandler::launch' );

Smarty3 y gettext

Si estás utilizando Smarty2 y te has decidido a dar el salto a Smarty3 para aprovecharte de sus nuevas funcionalidades (como por ejemplo la nada despreciable opción de herencia en templates), verás que existen algunas incompatibilidades, por ejemplo, se han decidido por seguir el estandar camelCase en el nombre de las funciones, utilizan getters y setters para los atributos o han cambiado la manera de registrar bloques.

En el caso del popular plugin smarty-gettext, si tenemos personalizada la llamada al traductor con, por ejemplo ‘{t}’ como es mi caso, nos encontraremos con un bonito error:

function call ‘register_block’ is unknown or deprecated

Esto es debido a que la forma correcta de registrar bloques en Smarty3 es:


$this->register->block('t', 'translate');

en lugar de:


$this->register_block( 't', 'translate' );

Una vez hecho esto, el siguiente error que nos deja Smarty es:

Plugin “t” not callable

En lugar del antiguo ‘translate’, el segundo parámetro deberá ser el nombre correcto de la función, es decir ‘smarty_translate’:


$this->register->block('t', 'smarty_translate');

de este modo solventaremos el problema y podremos seguir disfrutando de nuestro plugin de traducción.

Symfony: Upgrade de 1.2.x a 1.4 con PEAR

Antes de empezar a hacer el upgrade de symfony debemos asegurarnos que los plugins utilizados actualmente en el proyecto son compatibles con la versión 1.4, en caso de no ser compatibles, tenemos tres opciones:

  1. Buscar un plugin similar que sí sea compatible.
  2. Modificar nuestra aplicación para que no utilice dicho plugin.
  3. Si no podemos prescindir de él, habrá que esperar a que saquen la compatibilidad o hackearlo nosotros mismos (lo qual podría ser muy fácil o muy difícil en función del tipo de problema).

Pasos a seguir para subir de versión:

1) Update de los canales de pear

sudo pear update-channels

2) Upgrade de symfony a la versión 1.3

sudo pear upgrade -f symfony/symfony-1.3.0

3) Validamos que no estamos usando métodos deprecated (estós están eliminados en la versión 1.4)

symfony project:validate

En caso de obtener errores del validador, los solventaremos antes de hacer el upgrade siguiendo instrucciónes en la página Deprecations and removals in 1.3

4) Upgrade del projecto a la versión 1.3

symfony project:upgrade1.3

5) Upgrade de los plugins a la última versión

symfony plugin:upgrade [plugin]

6) Upgrade de symfony a la última versión

sudo pear upgrade symfony/symfony

7) Limpiamos la caché antes de probar

symfony cc

Ahora deberíamos tener nuestro proyecto updateado a la última versión estable de symfony 😀

Symfony i18n con gettext

Symfony permite varios métodos para internazionalizar nuestra aplicación. Por defecto, utilizan el formato XLIFF sin embargo, personalmente me gusta más gettext.

¿Cómo configurar symfony para usar gettext?

Para configurar symfony para que utilice gettext seguiremos los siguientes pasos:

1) Activamos el módulo I18N modificando el archivo settings.yml:

#apps/<appName>/config/settings.yml
all:
  .settings:
    charset:                utf-8
    i18n:                   on
    standard_helpers:       [ [TUS_HELPERS_ACTIVADOS]..., I18N]

2) Abrimos el archivo factories.yml y añadimos la entrada i18n:

#apps/<appName>/config/factories.yml
all:
  i18n:
    class: sfI18N
    param:
      default_culture:  en_US
      source:           gettext</pre>

3) Crearemos una carpeta i18n dentro de apps//:

apps/<appName>/i18n/<lang>

Donde <lang> será el idioma en dos letras (en, es, fr…) y dentro tendremos los ficheros messages.po y messages.mo.

Ahora podemos utilizar la función __( ‘texto_a_traducir’ ) con doble underscore [ _ ] en lugar del simple utilizado normalmente.

¿Cómo generar automáticamente nuestros ficheros po y mo?

Symfony trae una serie de herramientas que nos permiten generar los archivos po y mo de manera automática. Invocando el comando:

symfony i18n:extract frontend en --auto-save

Se recorrerá todos los archivos php de nuestra aplicación (código y templates) y sacará los textos que encuentre en las funciones __().

También se puede utilizar el mismo comando de la siguiente manera:

symfony i18n:extract frontend en --auto-delete

para eliminar las cadenas de texto que ya no existen.

Pasar segundos a horas:minutos:segundos

Una sencilla función que dado un número de segundos, nos devuelve el tiempo en formato hh:mm:ss


protected function makeTimeFromSeconds( $total_seconds )
{
    $horas              = floor ( $total_seconds / 3600 );
    $minutes            = ( ( $total_seconds / 60 ) % 60 );
    $seconds            = ( $total_seconds % 60 );

    $time['horas']      = str_pad( $horas, 2, "0", STR_PAD_LEFT );
    $time['minutes']    = str_pad( $minutes, 2, "0", STR_PAD_LEFT );
    $time['seconds']    = str_pad( $seconds, 2, "0", STR_PAD_LEFT );

    $time               = implode( ':', $time );

    return $time;
}

Espero os sea de utilidad.

La clase sfConfig de Symfony

Aquí os dejo algo de información sobre como solicitar variables de configuración en symfony además de un listado muy útil con todas las variables que Symfony trae predefinidas.

Cómo pedir variables definidas

Se puede llamar a la función estática get del objeto sfConfig para solicitar cualquier variable definida pasándo dos valores. El primero indica el nombre de la variable solicitada y el segundo, el valor que retornará en caso de no existir dicha variable.

sfConfig::get('sf_config_variable', 'The default value'); // The default is optional

Continue reading

Cómo optimizar tus aplicaciones Web

Optimizar aplicaciones PHPManuel Aguilar publicó una magnífica presentación sobre cómo optimizar aplicaciones Web dada en la PHP Barcelona Conference 2008 y he considerado interesante recopilar a modo de resumen las ideas más importantes de ese artículo, en cualquier caso, recomiendo la lectura del mismo para recoger toda su esencia y ampliar información.

Partiendo de un estudio de Yahoo! que dice que el 80% del tiempo de carga de una web corresponde al lado del cliente, podemos seguir una serie de reglas que aumentarán significativamente la percepción de velocidad del usuario. Continue reading