TigerZF
🌐Español

Capítulo 43. Zend_Locale

Tabla de contenidos

43.1. Introducción
43.1.1. Qué es la localización
43.1.2. Qué es un locale?
43.1.3. Cómo se representan los locales?
43.1.4. Seleccionar el locale correcto
43.1.5. Uso de locales automáticos
43.1.6. Uso de un locale por defecto
43.1.7. Clases de ZF compatibles con locales
43.1.8. Locale a nivel de aplicación
43.1.9. Zend_Locale_Format::setOptions(array $options)
43.1.10. Acelerar Zend_Locale y sus subclases
43.2. Uso de Zend_Locale
43.2.1. Copiar, clonar y serializar objetos Locale
43.2.2. Igualdad
43.2.3. Locales por defecto
43.2.4. Establecer un nuevo locale
43.2.5. Obtener el idioma y la región
43.2.6. Obtener el locale indicando un territorio
43.2.7. Obtener cadenas localizadas
43.2.8. Obtener las traducciones de "sí" y "no"
43.2.9. Obtener una lista de todos los locales conocidos
43.2.10. Detección de locales
43.3. Normalización y localización
43.3.1. Normalización de números: getNumber($input, Array $options)
43.3.1.1. Precisión y cálculos
43.3.2. Localización de números
43.3.3. Prueba de números
43.3.4. Normalización de valores en coma flotante
43.3.5. Localización de valores en coma flotante
43.3.6. Prueba de valores en coma flotante
43.3.7. Normalización de valores enteros
43.3.8. Localización de valores enteros
43.3.9. Prueba de valores enteros
43.3.10. Conversión de sistemas numéricos
43.4. Trabajar con fechas y horas
43.4.1. Normalización de fechas y horas
43.4.2. Prueba de fechas
43.4.3. Normalización de una hora
43.4.4. Prueba de horas
43.5. Locales admitidos

43.1. Introducción

Zend_Locale es la respuesta del Framework a la pregunta, "¿Cómo puede usarse la misma aplicación en todo el mundo?" La mayoría de la gente dirá, "Eso es fácil. Vamos a traducir toda nuestra salida a varios idiomas." Sin embargo, usar simples tablas de traducción para asignar frases de un idioma a otro no es suficiente. Las diferentes regiones tendrán convenciones distintas para nombres, apellidos, títulos de tratamiento, formato de números, fechas, horas, monedas, etc.

Necesitamos localización e internacionalización complementaria. Ambas se suelen abreviar como L10n e I18n. La internacionalización se refiere más al soporte para el uso de sistemas, independientemente de las necesidades especiales propias de grupos de usuarios relacionados por idioma, región, convenciones de formato numérico, convenciones financieras, convenciones de hora y fecha, etc. La localización implica añadir soporte explícito a los sistemas para las necesidades especiales de estos grupos particulares, como la traducción de idiomas y el soporte de costumbres o convenciones locales para comunicar plurales, fechas, horas, monedas, nombres, símbolos, clasificación y ordenación, etc. L10n e I18n se complementan entre sí. Zend Framework ofrece soporte para esto mediante una combinación de componentes, entre ellos Zend_Locale, Zend_Date, Zend_Measure, Zend_Translate, Zend_Currency, y Zend_TimeSync.

[Tip] Zend_Locale y setLocale()

La documentación de PHP indica que setlocale() no es segura para hilos (thread-safe) porque se mantiene por proceso y no por hilo. Esto significa que, en entornos multihilo, puede darse el problema de que el locale cambie aunque el script en sí nunca haya modificado el locale. Esto puede provocar comportamientos inesperados cuando se usa setlocale() en sus scripts.

Cuando usa Zend_Locale no tendrá esta limitación, porque Zend_Locale no está relacionado ni acoplado con setlocale() de PHP.

43.1.1. Qué es la localización

La localización significa que una aplicación (o página web) puede ser usada por distintos usuarios que hablan idiomas diferentes. Pero, como ya se puede esperar, la localización significa mucho más que traducir cadenas de texto. Incluye

  • Zend_Locale - Soporte de fondo para los locales disponibles para el soporte de localización dentro de otros componentes de Zend Framework.

  • Zend_Translate - Traducción de cadenas de texto.

  • Zend_Date - Localización de fechas y horas.

  • Zend_Calendar - Localización de calendarios (soporte para sistemas de calendario no gregorianos)

  • Zend_Currency - Localización de monedas.

  • Zend_Locale_Format - Análisis y generación de números localizados.

  • Zend_Locale_Data - Recuperación de cadenas estándar localizadas, como nombres de países, nombres de idiomas y más procedentes de la CLDR.

43.1.2. Qué es un locale?

Todo usuario de ordenador hace uso de locales, aunque no lo sepa. Las aplicaciones que carecen de soporte de localización, normalmente tienen soporte implícito para un locale particular (el locale del autor). Cuando una clase o función hace uso de la localización, decimos que es compatible con locales. ¿Cómo sabe el código qué localización espera el usuario?

Una cadena u objeto de locale que identifica un locale admitido proporciona a Zend_Locale y sus subclases acceso a información sobre el idioma y la región esperados por el usuario. El formato, la normalización y las conversiones correctas se realizan en base a esta información.

43.1.3. Cómo se representan los locales?

Los identificadores de locale consisten en información sobre el idioma del usuario y su región geográfica preferida/principal (por ejemplo, estado o provincia del domicilio o del trabajo). Las cadenas identificadoras de locale utilizadas en Zend Framework son abreviaturas estándar definidas internacionalmente para idioma y región, escritas como idioma_REGIÓN. Tanto la parte del idioma como la de la región se abrevian con caracteres alfabéticos ASCII.

[Note] Nota

Tenga en cuenta que no existen solamente locales con 2 caracteres, como mucha gente cree. También hay idiomas y regiones que no se abrevian solo con 2 caracteres. Por ello, NO debería separar la región y el idioma usted mismo, sino usar Zend_Locale cuando desee separar el idioma o la región de una cadena de locale. De lo contrario, podría tener comportamientos inesperados en su código si lo hace usted mismo.

Un usuario de EE.UU. esperaría el idioma inglés y la región USA, produciendo el identificador de locale "en_US". Un usuario en Alemania esperaría el idioma alemán y la región Alemania, produciendo el identificador de locale "de_DE". Consulte la lista de combinaciones predefinidas de locale y región, si necesita seleccionar un locale específico dentro de Zend Framework.

Ejemplo 43.1. Elegir un locale específico

$locale = new Zend_Locale('de_DE'); // German language _ Germany

Un usuario alemán en Estados Unidos podría esperar el idioma alemán y la región USA, pero estas combinaciones no estándar no se admiten directamente como "locales" reconocidos. En su lugar, si se usa una combinación no válida, se truncará automáticamente eliminando el código de región. Por ejemplo, "de_IS" se truncaría a "de", y "xh_RU" se truncaría a "xh", porque ninguna de estas combinaciones es válida. Además, si el código de idioma base no está admitido (por ejemplo, "zz_US") o no existe, se usará un locale "root" por defecto. El locale "root" tiene definiciones por defecto para representaciones internacionalmente reconocidas de fechas, horas, números, monedas, etc. El proceso de truncado depende de la información solicitada, ya que algunas combinaciones de idioma y región pueden ser válidas para un tipo de dato (por ejemplo, fechas), pero no para otro (por ejemplo, formato de moneda).

Tenga cuidado con los cambios históricos, ya que los componentes de Zend Framework no conocen ni intentan rastrear los numerosos cambios de zona horaria realizados a lo largo de los años por muchas regiones. Por ejemplo, podemos ver una lista histórica que muestra decenas de cambios realizados por gobiernos sobre cuándo y si una región concreta observa el horario de verano, e incluso a qué zona horaria pertenece una área geográfica determinada. Por lo tanto, al realizar cálculos con fechas, los cálculos que realizan los componentes de Zend Framework no se ajustarán a esos cambios, sino que darán la hora correcta para la zona horaria usando las reglas actuales y modernas para el DST y la asignación de zona horaria a las regiones geográficas.

43.1.4. Seleccionar el locale correcto

En la mayoría de las situaciones, new Zend_Locale() seleccionará automáticamente el locale correcto, dando preferencia a la información proporcionada por el navegador web del usuario. Sin embargo, si se usa new Zend_Locale(Zend_Locale::ENVIRONMENT), se dará preferencia a la configuración de entorno del servidor host, tal como se describe a continuación.

Ejemplo 43.2. Selección automática de un locale

$locale  = new Zend_Locale();

// default behavior, same as above
$locale1 = new Zend_Locale(Zend_Locale::BROWSER);

// prefer settings on host server
$locale2 = new Zend_Locale(Zend_Locale::ENVIRONMENT);

// perfer framework app default settings
$locale3 = new Zend_Locale(Zend_Locale::FRAMEWORK);

El algoritmo de búsqueda usado por Zend_Locale para la selección automática de un locale utiliza tres fuentes de información:

  1. const Zend_Locale::BROWSER - El navegador web del usuario proporciona información con cada petición, que PHP publica en la variable global $_SERVER['HTTP_ACCEPT_LANGUAGE']. Si no se encuentra ningún locale coincidente, se da preferencia a ENVIRONMENT y por último a FRAMEWORK.

  2. const Zend_Locale::ENVIRONMENT - PHP publica el locale del servidor host a través de la función interna de PHP setlocale(). Si no se encuentra ningún locale coincidente, se da preferencia a FRAMEWORK y por último a BROWSER.

  3. const Zend_Locale::FRAMEWORK - Cuando Zend Framework tenga una forma estandarizada de especificar valores por defecto de componentes (previsto, pero aún no disponible), usar esta constante durante la instanciación dará preferencia a elegir un locale basado en esos valores por defecto. Si no se encuentra ningún locale coincidente, se da preferencia a ENVIRONMENT y por último a BROWSER.

43.1.5. Uso de locales automáticos

Zend_Locale proporciona tres locales adicionales. Estos locales no pertenecen a ningún idioma o región. Son locales "automáticos", lo que significa que tienen el mismo efecto que el método getDefault() pero sin los efectos negativos como la creación de una instancia. Estos locales "automáticos" se pueden usar en cualquier lugar donde también se pueda usar un locale estándar y también la definición de un locale, su representación en forma de cadena. Esto ofrece simplicidad para situaciones como trabajar con locales proporcionados por un navegador.

Hay tres locales que tienen un comportamiento ligeramente diferente:

  1. 'browser' - Zend_Locale debería trabajar con la información proporcionada por el navegador web del usuario. Se publica en PHP en la variable global $_SERVER['HTTP_ACCEPT_LANGUAGE'].

    Si un usuario proporciona más de un locale en su navegador, Zend_Locale usará el primer locale encontrado. Si el usuario no proporciona ningún locale o el script se está invocando desde la línea de comandos, se usará y devolverá automáticamente el locale automático 'environment'.

  2. 'environment' - Zend_Locale debería trabajar con la información proporcionada por el servidor host. Se publica en PHP mediante la función interna setlocale().

    Si un entorno proporciona más de un locale, Zend_Locale usará el primer locale encontrado. Si el host no proporciona ningún locale, se usará y devolverá automáticamente el locale automático 'browser'.

  3. 'auto' - Zend_Locale debería detectar automáticamente cualquier locale con el que se pueda trabajar. Primero buscará el locale del usuario y, si no tiene éxito, buscará el locale del host.

    Si no se puede detectar ningún locale, lanzará una excepción indicando que la detección automática ha fallado.

Ejemplo 43.3. Uso de locales automáticos

// without automatic detection
//$locale = new Zend_Locale(Zend_Locale::BROWSER);
//$date = new Zend_Date($locale);

// with automatic detection
$date = new Zend_Date('auto');

43.1.6. Uso de un locale por defecto

En algunos entornos no es posible detectar un locale automáticamente. Puede esperar este comportamiento cuando recibe una petición desde la línea de comandos o el navegador solicitante no tiene establecida ninguna etiqueta de idioma y, además, su servidor tiene establecido el locale por defecto 'C' u otro locale propietario.

En tales casos, Zend_Locale normalmente lanzará una excepción con un mensaje indicando que la detección automática de cualquier locale no tuvo éxito. Tiene dos opciones para manejar tal situación. Bien estableciendo un nuevo locale a mano, o definiendo un locale por defecto.

Ejemplo 43.4. Manejo de excepciones de locale

// within the bootstrap file
try {
    $locale = new Zend_Locale('auto');
} catch (Zend_Locale_Exception $e) {
    $locale = new Zend_Locale('de');
}

// within your model/controller
$date = new Zend_Date($locale);

Pero esto tiene un gran efecto negativo. Tendrá que establecer su objeto locale en cada clase que use Zend_Locale. Esto podría volverse muy incómodo si está usando múltiples clases.

Desde la versión 1.5 de Zend Framework hay una forma mucho mejor de manejar esto. Puede establecer un locale por defecto con el método estático setDefault(). Por supuesto, todo locale desconocido o no completamente cualificado también lanzará una excepción. setDefault() debería ser la primera llamada antes de iniciar cualquier clase que use Zend_Locale. Vea el siguiente ejemplo para más detalles:

Ejemplo 43.5. Establecer un locale por defecto

// within the bootstrap file
Zend_Locale::setDefault('de');

// within your model/controller
$date = new Zend_Date();

En el caso de que no se pueda detectar ningún locale, se usará automáticamente el locale de. De lo contrario, se usará el locale detectado.

43.1.7. Clases de ZF compatibles con locales

En Zend Framework, las clases compatibles con locales confían en Zend_Locale para seleccionar automáticamente un locale, tal como se explicó anteriormente. Por ejemplo, en una aplicación web de Zend Framework, construir una fecha usando Zend_Date sin especificar un locale da como resultado un objeto con un locale basado en la información proporcionada por el navegador web del usuario actual.

Ejemplo 43.6. Las fechas usan por defecto el locale correcto de los usuarios web

$date = new Zend_Date('2006',Zend_Date::YEAR);

Para anular este comportamiento por defecto y forzar a los componentes de Zend Framework compatibles con locales a usar locales específicos, independientemente del origen de los visitantes de su sitio web, especifique explícitamente un locale como tercer argumento del constructor.

Ejemplo 43.7. Anular la selección de locale por defecto

$usLocale = new Zend_Locale('en_US');
$date = new Zend_Date('2006', Zend_Date::YEAR, $usLocale);
$temp = new Zend_Measure_Temperature('100,10',
                                     Zend_Measure::TEMPERATURE,
                                     $usLocale);

Si sabe que muchos objetos deben usar todos el mismo locale por defecto, especifique explícitamente el locale por defecto para evitar la sobrecarga de que cada objeto determine el locale por defecto.

Ejemplo 43.8. Optimización de rendimiento al usar un locale por defecto

$locale = new Zend_Locale();
$date = new Zend_Date('2006', Zend_Date::YEAR, $locale);
$temp = new Zend_Measure_Temperature('100,10',
                                     Zend_Measure::TEMPERATURE,
                                     $locale);

43.1.8. Locale a nivel de aplicación

Zend Framework permite el uso de un locale a nivel de aplicación. Simplemente establece una instancia de Zend_Locale en el registro con la clave 'Zend_Locale'. Entonces esta instancia se usará dentro de todas las clases compatibles con locales de Zend Framework. De esta forma, establece un locale en su registro y luego puede olvidarse de establecerlo de nuevo. Se usará automáticamente en todas las demás clases. Vea el siguiente ejemplo para el uso correcto:

Ejemplo 43.9. Uso de un locale a nivel de aplicación

// within your bootstrap
$locale = new Zend_Locale('de_AT');
Zend_Registry::set('Zend_Locale', $locale);

// within your model or controller
$date = new Zend_Date();
// print $date->getLocale();
echo $date->getDate();

43.1.9. Zend_Locale_Format::setOptions(array $options)

La opción 'precision' de un valor se usa para truncar o extender dígitos adicionales. Un valor de '-1' desactiva la modificación del número de dígitos en la parte fraccionaria del valor. La opción 'locale' ayuda al analizar números y fechas usando separadores y nombres de meses. La opción 'format_type' del formato de fecha selecciona entre los tokens de especificación de formato de fecha CLDR/ISO y los tokens de date() de PHP. La opción 'fix_date' activa o desactiva las heurísticas que intentan corregir fechas no válidas. La opción 'number_format' especifica un formato de número por defecto para usar con toNumber() (vea esta sección).

La opción 'date_format' se puede usar para especificar una cadena de formato de fecha por defecto, pero tenga cuidado al usar getDate(), checkdateFormat() y getTime() después de usar setOptions() con un 'date_format'. Para usar estos cuatro métodos con el formato de fecha por defecto de un locale, use array('date_format' => null, 'locale' => $locale) como sus opciones.

Ejemplo 43.10. Las fechas usan por defecto el locale correcto de los usuarios web

Zend_Locale_Format::setOptions(array('locale' => 'en_US',
                                     'fix_date' => true,
                                     'format_type' => 'php'));

Para trabajar con las definiciones estándar de un locale se puede usar la opción Zend_Locale_Format::STANDARD. Establecer la opción Zend_Locale_Format::STANDARD para date_format usa las definiciones estándar del locale actualmente establecido. Establecerla para number_format usa el formato de número estándar de ese locale. Y establecerla para locale usa el locale estándar para este entorno o navegador.

Ejemplo 43.11. Uso de las definiciones STANDARD para setOptions()

Zend_Locale_Format::setOptions(array('locale' => 'en_US',
                                     'date_format' => 'dd.MMMM.YYYY'));
// overriding the global set date format
$date = Zend_Locale_Format::getDate('2007-04-20',
                                    array('date_format' =>
                                              Zend_Locale_Format::STANDARD);

// global setting of the standard locale
Zend_Locale_Format::setOptions(array('locale' => Zend_Locale_Format::STANDARD,
                                     'date_format' => 'dd.MMMM.YYYY'));

43.1.10. Acelerar Zend_Locale y sus subclases

Zend_Locale y sus subclases pueden acelerarse mediante el uso de Zend_Cache. Use el método estático Zend_Locale::setCache($cache) si está usando Zend_Locale. Zend_Locale_Format puede acelerarse usando la opción cache dentro de Zend_Locale_Format::setOptions(array('cache' => $adapter));. Si está usando ambas clases, solo debería establecer la caché para Zend_Locale, de lo contrario, la última caché establecida sobrescribirá la caché establecida anteriormente. Por comodidad también están los métodos estáticos getCache(), hasCache(), clearCache() y removeCache().

Cuando no se establece ninguna caché, Zend_Locale establecerá automáticamente una caché por sí mismo. A veces se desea evitar que se establezca una caché, aunque esto degrade el rendimiento. En este caso debería usarse el método estático disableCache(true). No solo desactiva la caché establecida actualmente, sin borrarla, sino que también evita que se genere automáticamente una caché cuando no hay ninguna establecida.