2010-06-03 3 views
8

La publicación de blog "On the state of i18n in Perl" del 26 de abril de 2009 recomienda usar el módulo Locale::TextDomain de la distribución libintl-perl para l10n/i18n en Perl. Además, tengo que usar gettext de todos modos, y obtener soporte de texto en Locale :: Messages/Locale :: TextDomain es más natural que en la emulación gettext en Locale::Maketext.Localización en Perl usando gettext y Locale :: TextDomain, con recuperación si Locale :: TextDomain no está disponible

La subsección "15.5.18 Perl" en el capítulo "15 Other Programming Languages" en GNU manual de gettext dice:

Portabilidad

El paquete libintl-perl es independiente de la plataforma, pero no es parte del núcleo de Perl. El programador es responsable de proporcionar una implementación ficticia de las funciones requeridas si el paquete no está instalado en el sistema de destino.

Sin embargo ninguno de los dos ejemplos en examples/hello-perl en fuentes de gettext (uno usando inferior Locale nivel :: mensajes, uno utilizando superior Locale nivel :: textdomain) incluye detección si el paquete está instalado en el objetivo sistema, y ​​proporcionando implementación ficticia si no lo está.

Lo que se complica la materia (con respecto a la detección de si el paquete está instalado o no) es el siguiente fragmento de Locale :: textdomain página de manual:

SINOPSIS

use Locale::TextDomain ('my-package', @locale_dirs); 

use Locale::TextDomain qw (my-package); 

USO

Es crucial recordar que utiliza Locale :: TextDomain (3) como se especifica en el sección "SINOPSIS", eso significa que tiene que usar, no requerir. El módulo se comporta de manera bastante diferente en comparación con otros módulos.

¿Podría decirme cómo se debe detectar si libintl-perl está presente en el sistema de destino y cómo proporcionar la implementación ficticia fallthrough si no está instalado? ¿O dar ejemplos de programas/módulos que hacen esto?

Respuesta

7

El manual de gettext es incorrecto al sugerir que no está bien que demand a CPAN prerequisite. Todo el mundo lo hace en el mundo Perl, y gracias a la infraestructura y cadena de herramientas de CPAN, funciona muy bien. En el peor de los casos, puede agrupar las dependencias que necesita.

La respuesta directa a su pregunta es:

use Try::Tiny; 
try { 
    require Locale::TextDomain; 
    Locale::TextDomain->import('my-package', @locale_dirs); 
} catch { 
    warn 'Soft dependency could not be loaded, using fallback.'; 
    require inc::Local::Dummy::Locale::TextDomain; 
} 

Explicación: use is just require at compile time followed by import, y es aceptable para dividirlo con el fin de obligar a este para ejecutar en tiempo de ejecución.

4

tiene que incluir Locale :: textdomain con el uso en lugar de requerir debido a que está destinado precisamente para este caso, cuando se quiere i18n discreta para Perl, cuando todo lo que se necesita para la internacionalización de su código Perl es intercambiar que:

print "Hello world!\n"; 

con esto:

use Locale::TextDomain qw (com.example.myapp); 

print __"Hello world!\n"; 

En lenguajes como C preprocesados ​​esto es más fácil de lograr. Sobre todas las bibliotecas internacionalizados C contienen una #define así:

#define _(s) dgettext (GETTEXT_PACKAGE, s) 

Eso significa que _("Hello world!\n") expande a una llamada de función que contiene el textdomain de su paquete. Las fuentes de Perl no se pueden preprocesar portátilmente y, por lo tanto, Locale::TextDomain "abusa" del mecanismo de importación del pragma de uso para este fin, de modo que pueda asociar un archivo .pm con un archivo .mo particular. El dominio de texto es la raíz del nombre de archivo de los archivos .mo que instala su paquete.

Si no te gusta ese enfoque, no lo uses. También puede arreglárselas sin él:

require Locale::Messages; 
print Locale::Messages::dgettext ("com.example.myapp", "Hello world!\n"); 

Sin embargo, Locale::TextDomain es popular porque hace lo mismo de una manera mucho menos molesto.

Sobre dependiendo de una biblioteca que no se considera básica para Perl:

si un módulo Perl pertenece al núcleo de Perl o no depende de la versión de Perl. Y cada usuario puede instalar una versión diferente de un módulo central de Perl sobre el que se envía con su Perl. Por lo tanto, una configuración de paquete robusta siempre buscará la versión requerida de una biblioteca de Perl, como si comprueba la versión requerida de cualquier otra biblioteca. Suponiendo que la comprobación de perl es la misma que. verificar la presencia de una versión particular de un módulo Perl particular es una receta para problemas.

BTW, Try::Tiny tampoco es parte del núcleo Perl. Tal vez no sea la mejor opción para usarlo para verificar la presencia de otros módulos de Perl. Cuando desee probar libintl-perl, simplemente ejecute perl -MLocale::TextDomain -e exit en su script de configuración y verifique el estado de salida.

2

Basado en la respuesta de daxim, aquí hay una posible implementación. Detecta si Locale :: TextDomain está disponible y proporciona retrocesos no operativos simples para las funciones __ y __x. Agradecería las mejoras y sugerencias para este código.

BEGIN 
{ 
    if (eval("require Locale::TextDomain; 1;")) 
    { 
     Locale::TextDomain->import('my-package', @locale_dirs); 
    } 
    else 
    { 
     my $subCode = <<'EOF' 

     sub __ 
     { 
      return $_[0]; 
     } 

     sub __x 
     { 
      my $s = shift; 
      my %args = @_; 
      $s =~ s/\{(\w+)\}/$args{$1}/sg; 
      return $s; 
     } 
EOF 
; 
     eval($subCode); 
    } 
} 

Creo que todo el código debe vivir dentro de COMENZAR, de lo contrario el __ y __x llamadas en su causa errores de código. Además, las funciones secundarias se crean con eval() para evitar advertencias de "Prototipos no coincidentes". Me interesaría una solución más elegante, especialmente. para el último punto

+0

Quizás ** Package :: Stash ** o manipulación directa de la tabla de símbolos en lugar de texto eval. –

1

Crear un directorio "repliegue/Locale" y crear un módulo de TextDomain.pm allí con implementaciones de código auxiliar para todas las funciones que usted necesita:

package Locale::TextDomain; 

use strict; 

sub __($) { return $_[0] } 
sub __n($$$) { return $_[2] == 1 ? $_[0] : $_[1] } 

# And so on, see the source of Locale::TextDomain for getting an 
# idea how to implement the other stubs. 

Ahora insertar un bloque BEGIN en el punto de entrada de la solicitud (eso es típicamente un script .pl, no a.pm módulo):

BEGIN { 
    push @INC, "fallback"; 
} 

Ahora Perl siempre encontrar Locale/TextDomain.pm en @INC, en duda el talón de aplicación en el directorio de reserva.

Cuestiones relacionadas