Publi

5 consejos para internacionalizar nuestros programas con gettext [PHP]

Hace unos meses publicaba un artículo para hacer traducciones con gettext en nuestras aplicaciones, ahora vamos a ampliar aquello con algunos consejos útiles y trucos.

1 – Conocer globalmente la locale

No todo es gettext(), que usaremos para mensajes de la interfaz, puede que incluyamos textos desde base de datos y necesitemos tener a mano en todo momento esa locale, además de mucha más información sobre nuestro proyecto. Para ello, una buena forma es crear una clase estática que almacene esa información. Algo como esto:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Config
{
  private static $variables = array();

  static function get($varName)
  {
    return (isset(self::$variables[$varName]))?self::$variables[$varName]:null;
  }

  static function set($varName, $value)
  {
    self::$variables[$varName]=$value;
  }
};

Así, justo cuando definamos la locale hacemos

1
Config::set('locale', 'es');

Y en cualquier punto del código, se puede hacer:

1
echo Config::get('locale');

para obtener la locale. Siempre que hayamos incluido el archivo donde se encuentra la clase de arriba.

2 – Utilizar varios dominios en nuestra aplicación

A medida que la aplicación va creciendo, y sobre todo si van entrando más personas en su desarrollo, nos puede venir bien separar algunas traducciones en módulos o dominios, así varios equipos de traducción pueden trabajar a la vez, y varias personas pueden desarrollar sin fastidiar el trabajo a los traductores. Además de que queda todo mucho mejor organizado.

Para ello vamos a utilizar la función dgettext(), a la cual le tenemos que especificar el dominio (primer argumento) donde se encuentran los mensajes de traducción para dicho mensaje (segundo argumento)

Como dgettext() es muy largo de escribir y será lo que más veces encontremos en el código… sí dgettext, se puede escribir en poco más de un segundo, pero _d, ocupa 4 veces menos y tardaremos poco menos de un segundo, algo de tiempo y mucho espacio cuando lo hayamos escrito 1000 veces ganaremos:

1
2
3
4
function _d($domain, $message)
{
  return dgettext($domain, $message);
}

Una vez hecho esto, si miramos poedit, aquel programa para hacer las traducciones, que escaneaba el código en busca de palabras clave (funciones), por defecto no soporta dgettext ni _d, por tanto, tendremos que añadirlas. Pero si las añadimos tal cual, se creerá que el mensaje es el dominio (cogerá siempre el primer argumento de la función), para ello, añadiremos dgettext:2 y _d:2 de la siguiente forma

Cuando volvamos a escanear nuestros fuentes, lo hará bien, cogiendo el segundo parámetro.

3 – Usa sprintf()

Muchas veces es necesario introducir un pequeño dato dentro de los mensajes que traducimos… por ejemplo:

Tu amigo Juan cumple hoy 30 años

En este caso, la parte fija es «Tu amigo» «cumple hoy» «años», y puede que en otros idiomas el orden de las partes fijas no sea ese, por tanto tenemos un problema. No podemos introducir en nuestro archivo po todos los nombres que se nos ocurran con todas las edades que podamos poner… se nos generaría un fichero de varios megas y seguro que viene un usuario que se llama «Asclepiodoto» y nos ha fastidiado la aplicación.
Para ello tenemos sprintf() una función heredada de C, que funciona con la sintaxis de printf() de hecho son familia. sprintf() devolverá una cadena de acuerdo con un formato. En este caso podemos hacer:

1
2
3
  $nombre="Juan";
  $edad=30;
  echo sprintf(_('Your friend %s is %d today'), $nombre, $edad);

Siempre suelo utilizar inglés como idioma por defecto, pero más o menos queda así, donde %s se sustituirá por una cadena cogida del primer segundo argumento de sprintf(), es decir $nombre y %d por la segunda, $edad.
Las palabras clave de printf() %d, %s, %c, %f, etc las podéis ver si consultáis el manual de sprintf

4 – Crea tus propias funciones de traducción

Una opción muy parecida a la anterior, si solemos utilizar en muchos casos sprintf() junto con _() o dgettext(), podemos hacer eso desde una sola llamada a __() o __d() (por poner nombres)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function __()
{
  $args=func_get_args();
  $nargs=count($args);
  if ($nargs<1)
    return false;

  $string=$args[0];
  array_splice($args, 0,1);
  return vsprintf(_($string), $args);
}

function __d()
{
  $args=func_get_args();
  $nargs=count($args);
  if ($nargs<2)
    return false;

  $string=$args[1];
  $domain=$args[0];
  array_splice($args, 0,2);
  return vsprintf(dgettext($domain, $string), $args);
}

Así, para escribir la cadena de los años que cumple tu amigo:

1
2
3
  $nombre="Juan";
  $edad=30;
  echo __('Your friend %s is %d today', $nombre, $edad);

Sin más complicación

5 – Utilizar ngettext()

Esto, en combinación con sprintf es un fantástico aliado, y nos permitirá escribir mensajes apropiados cuando estemos expresando cantidades, sobre todo esto es interesante porque en algunos idiomas la forma plural a utilizar dependerá del número de elementos con los que contamos.
En muchos lenguajes podemos utilizar dos formas: una para singular y otra para el plural. Debemos especificar una regla que indique el número de plurales y cuándo se utilizan estos. Pero, de gestionar esto se encarga gettext.
En principio, para configurar poedit para poder introducir plurales debemos decirle en Catalogo / Opciones / Formas plurales lo siguiente: nplurals=2; plural=n != 1; para un idioma que sólo tiene singular y una forma plural. Aquí podremos especificar para otros idiomas las reglas para especificar los plurales que creamos convenientes.

Luego nosotros desde el código fuente sólo decimos:

1
2
3
$n=4;
echo sprintf(ngettext('You have %d new message', 'You have %d new messages', $n), $n)."\n";
?>

Así podemos delegar para tener un potente uso de plurales en nuestra aplicación. De otra forma habría que implementarlo, y debemos modificar el código fuente para la inserción de idiomas complicados (con más de una forma plural) y eso nos puede dar más de un calentamiento de cabeza.

También podría interesarte....

There are 4 comments left Ir a comentario

  1. Pingback: Bitacoras.com /

  2. Pingback: Conocer la accesibilidad de un método en PHP (público, privado, protegido) | Poesía Binaria /

  3. Mike Rooney /
    Usando Google Chrome Google Chrome 121.0.0.0 en Windows Windows NT

    Hello, I read this nice article. I think You put a best effort to write this perfect article. I appreciate your work. thank you so much.
    Wolves 2024 George Clooney Black Coat

  4. Madeline /
    Usando Google Chrome Google Chrome 122.0.0.0 en Windows Windows NT

    I really enjoyed this blog. It is a useful topic. It greatly aids my ability to solve certain challenges quordle.

Leave a Reply