2009-07-21 5 views
10

Digamos que está haciendo un software de blog, y quiere mostrar el número de comentarios que recibió una entrada. Es posible hacerlo de esta manera:¿La manera más elegante de tratar con singles/plurales?

[Entry title] 
[Content........] 
[ <?php print($numComments;) ?> Comments] 

que podría resultar en:

[Entry title] 
[Content........] 
5 Comments 

Pero si una entrada sólo tenía 1 comentario, quiero la línea de decir 'Comentario' en lugar de 'Comentarios'. Y en línea if/else s son feos y repetitivos.

¿Cuál es la mejor manera de lidiar con esto?

+4

+1 Para su nombre de usuario, porque me lo dijo. Eso es inteligente y me interesaría saber cuántos votos a favor tienes solo por eso. :) – Dusty

+1

Estoy medio tentado de menospreciar solo para contrarrestar los efectos de las personas que votaron a favor –

Respuesta

13

utilice la función ngettext para cosas como esta. Es le permite tratar correctamente con plurales en inglés y otros idiomas , de una vez por todas. Se utiliza de esta manera:

printf(ngettext("%d Comment", "%d Comments", $numComments), $numComments); 

La función ngettext volverá la primera cadena de formato ("%d Comment") si sólo hay un solo comentario y la segunda cadena de formato ("%d Comments") si hay más. La función printf será y luego colocará el número en la cadena.

Esto puede parecer mucho trabajo, pero es muy potente: funciona con idiomas que tienen más de una forma plural - que en realidad existen (!). El manual de PHP da un ejemplo de la palabra "ventana" que se convierte en "1 okno", "2 okna" y "5 oken" en algún lenguaje exótico que no reconozco ...

Si usted es consecuente sobre el uso de ngettext, a continuación, sus futuros usuarios de países lejanos será muy agradecido :-)

Editar: Como se sugiere en los comentarios, hay una sola función a hacer lo anterior:

function pluralize($num, $singleWord, $pluralWord) { 
    return printf(ngettext($singleWord, $pluralWord, $num), $num); 
} 

Por defecto, xgettext suele reconocer esta nueva función, pero se puede añadir con la bandera --keyword. Dado un archivo test.php con

echo ngettext("foo", "foos", 1); 
echo pluralize(2, "bar", "bars"); 

se puede extraer de las cuerdas con

xgettext --keyword=pluralize:2,3 test.php 

El messages.po archivo resultante tiene entradas como estas:

#: test.php:7 
msgid "foo" 
msgid_plural "foos" 
msgstr[0] "" 
msgstr[1] "" 

#: test.php:8 
msgid "bar" 
msgid_plural "bars" 
msgstr[0] "" 
msgstr[1] "" 

El traductor va a llenar en cada forma plural y con una línea formada correctamente "Plural-Forms" en el encabezado del catálogo de mensajes, usted será capaz para admitir todos los idiomas.

+0

sería repetitivo usar esto con un printf todo el tiempo, pero tal vez se pueda escribir una función de envoltura que imprima y% d. ¿Quizás podría escribir el cuerpo de esta función y actualizar su respuesta? 'function pluralize ($ num, $ singleWord, $ pluralWord = '')' –

+0

@Click Upvote: buena idea. Hice la función con tres argumentos obligatorios: la cadena plural es necesaria para que xgettext pueda reconocer la llamada a la función y tratarla correctamente. –

+0

Eso sería eslovaco. –

3

Crea una función que toma un número y una palabra, y devuelve una cadena que contiene ambos. Agregará una "s" (o consulte un diccionario que construya) cuando el número sea mayor que 1.

+1

Haría que la función agregue la s si el número no es 1, por lo que 0 también tiene el formato plural. –

+0

¿Cómo llamarías a esa función? –

+0

Pluralizar parece ser el nombre más apropiado. – Brandon

2

No es el más elegante, pero es el más fácil de enviar "Comentario (s)".

[Entry title] 
[Content........] 
1 Comment(s) 
+0

Fácil, pero no funciona bien en todas las situaciones –

+2

Como se nota, esto no es muy elegante ... Cuando ver ese resultado, siempre me pregunto por qué la computadora no pasó el milisegundo extra para averiguar si la "s" debería estar allí o no :-) –

+0

+1 Haha. Convenido. – Dusty

4

¿Por qué no se toman el tiempo para humanizar las cosas aún más ....

switch ($numComments) 
{ 
    case 0: 
     echo "Be the first to write a comment"; 
     break; 
    case 1: 
     echo "Just one comment so far"; 
     break; 
    default: 
     echo "There are $numComments comments"; 

} 
+0

+1 Este método evitará la mayoría de los problemas de localización. – fishlips

+0

@fishlips: excepto cuando un idioma tiene tres o más formas plurales. Como se explica a continuación, la función ngettext es la solución más general. Permite a un traductor incluir todos sus formularios en plural en el archivo ".po" y el correcto en el tiempo de ejecución. –

3

Me sorprende que nadie sugirió que aún, pero lo que suelo hacer es utilizar el operador condicional:

string commentWord = numComments != 1 ? "Comments" : "Comment"; 

Nota: la cadena debe, por supuesto, no puede ser codificado como esto en absoluto, sino más bien cargado de algún repositorio de recursos, donde se almacena con un marcador de posición para el formato de número, por lo que puede manejar idiomas en que el número debe aparecer última (o en el medio):

// should load "{0} Comments" or "{0} Comment" if we run in an English locale 
string comments = string.Format(
     numComments != 1 ? GetResource("Comments") : GetResource("Comment"), 
     numComments); 
+4

Esta no es la forma correcta de internacionalizar. El idioma que no es inglés tiene sus propias reglas para las formas plurales; p.ej. El lituano tiene tres formas diferentes: "1 komentaras", "2 komentarai", "10 komentarų". El marco gettext GNU popular en los programas C tiene una solución para esto (la función ngettext). No estoy familiarizado con Java/C#/PHP, así que no puedo decir cuál es la solución correcta canónica allí. –

+0

@Marius: gracias por esa información. No estaba al tanto de esas reglas lituanas. He hecho un poco de software internacional (evento hizo un software de traducción de textos de interfaz de usuario para un cliente grande) pero nunca he encontrado esas demandas. ¡Muy interesante! No voy a profundizar en esto aquí en detalle, solo quería presentar el concepto de recoger los textos de un repositorio de recursos, en lugar de simplemente codificarlos. –

+0

@Fredrik: También me sorprendió la primera vez que escuché de idiomas con más de dos formas plurales ... Soy danés y solía tener solo dos formas :-) Afortunadamente, la función ngettext puede manejarlo, por favor vea mi responde en otro lugar en esta página. –

0

Echa un vistazo a Rails inflector module. Esto proporciona una solución agradable, centralizada y configurable para este problema.

2

En C/C++, puede hacer lo siguiente. Es posible que pueda hacer algo similar en PHP.

printf("%d %s\n", numComments, numComments == 1 ? "Comment" : "Comments"); 

Lo siguiente también funciona, pero puede que tenga problemas con \b (retroceso) siendo manejado de forma incorrecta en diferentes implementaciones.

printf("%d Comment%s\n", numComments, numComments == 1 ? " \b" : "s"); 

Usando \0 (carácter nulo) para imprimir nada, en cambio, imprimen un espacio en mi aplicación.

Cuestiones relacionadas