[[TableOfContents()]]
= Nombre =
po4a - framework para traducir documentación y otros materiales
= Introducción =
El objetivo del proyecto po4a (por las siglas en inglés: po para cualquiercosa) es facilitar las traducciones (y de modo más interesante, el mantenimiento de las traducciones) usando las herramientas de gettext en áreas donde no eran esperadas como la documentación.
= Tabla de Contenido =
Este documento está organizado de la siguiente manera:
1.¿Por qué debería yo usar po4a? Para qué es bueno?:: Este capítulo introductorio explica la motivación del proyecto y su filosofía. Debería leerlo primero si está en el proceso de evaluar po4a para sus propias traducciones.
2.¿Cómo usar po4a?:: Este capítulo es una especie de manual de rerefencia, que trata de reponder las preguntas de los usuarios y le da una mejor comprensión de todo el proceso. Este introduce a como hacer cosas con po4a sirviendo tambien como una introducción a la documentación de herraminetas específicas.
* ¿Cómo empezar una nueva traducción?
* ¿Cómo cambiar la traducción de nuevo a un archivo de documentación?
* ¿Cómo actualizar una traducción po4a?
* ¿Cómo convertir una traducción prexistente a po4a?
* ¿Cómo adicionar texto extra a las traducciones (como el nombre del traductor)?
* ¿Cómo hacer todo esto en una sóla invocación del programa?
3.¿Cómo funciona?:: Este capítulo le da una pequeña panorámica del interior de po4a, así que puede sentirse más confiado a ayudarnos a mantenerlo y mejorlarlo. Puede también ayudarle a comprender por qué no hace lo que usted esperaba y cómo solucionar sus problemas.
4.PUF:: Este capítulo agrupa las Preguntas de Uso Frecuente. De hecho, la mayoría de las preguntas por ahora podrían ser formuladas de la forma "Por qué fue diseñado de esta manera, y no de esta otra?". Si pienas que po4a no es la respuesta correcta a la traducción de documentación, debería considerar leer esta sección. Si ella no responde su pregunta, por favor contáctenos en la lista <po4a-devel@lists.alioth.debian.org>. Adoramos la retroalimentación.
5.Notas específicas acerca de los módulos:: Este capítulo presenta las especificidades de cada modulo desde el punto de vista del traductor y del autor original. Lea esto para aprender la sintaxis que encontrará cuando traduzca cosas en este módulo, o las reglas que debería seguir en un documento original para hacer la vida del traductor más sencilla.
De hecho, esta sección no es realmente parte de este documento. En su lugar, es puesta en la documentación de cada módulo. Esto ayuda a asegurar que la información está actualizada, manteniendo la documentación y el código juntos.
6.Errores conocidos y solicitud de características:: Quite a few already :(
= ¿Por qué debería yo usar po4a?, ¿Para qué es bueno? =
Me gusta la idea del software de código abierto, de hacer posible para todo el mundo el acceso al software y su código fuente. Pero siendo francés, soy bien conciente de que el licenciamiento no es la única restricción a la apertura del software: Software Libre no traducido es inútil para los no hablantes del inglés, y aún tenemos cierto trabajo para hacerlo realmente disponible a cualquier persona por ahí.
La percepción de esta situación por los actores del software abierto dramáticamente mejoró recientemente. Nosotros, como traductores, ganamos la primera batalla y convencimos a todo el mundo de la importancia de las traducciones. Pero desafortunadamente, esa era la parte fácil. Ahora, tenemos que hacer el trabajo y de hecho traducir todas esas cosas.
Actualmente, el software libre se beneficia a sí mismo de un nivel bastante decente de traducción, gracias a la maravillosa ''suite'' de herramientas gettext. Ella es capaz de extraer las cadenas a traducir de un programa, presentarlas en un formato uniforme a los traductores, y entonces usar el resultado de sus trabajos en tiempo de ejecución para mostrar los mensajes traducidos al usuario.
Pero la situación es bien diferente cuando se trata de documentación. Muy a menudo, la documentación traducida no es suficientemente visible (no es distribuida como parte del programa), sólo parcial o, no actualizada. Esta última situación es de lejos la peor de las posibles. Traducciones desactualizadas pueden revelarse pero que ninguna traducción a los usuarios mediante la descripción de viejos comportamientos del programa que no están ya más en uso.
== El problema a resolver ==
La traducción de la documentación no es muy difícil en sí misma. Los textos son más largos que los mensajes de los programas y por ello toma más tiempo para ser logrado, pero ninguna habilidad técnica es realmente necesaria para hacerlo. La parte difícil viene cuando usted tiene que mantener su trabajo. Detectar cuales partes cambiaron y cuales necesitan ser actualizadas, es bastante difícil, propenso al error y altamente implacentero. Adivino que eso explica por qué tanta de la documentación traducida por ahí está desactualizada.
== La respuesta de po4a ==
Así, todo el asunto de po4a es hacer la traducción de la documentación mantenible. La idea es reutilizar la metodología de gettext a este nuevo campo. Como gettext, los textos son extraidos de sus ubicaciones originales a fin de ser presentados en un formato uniforme a los traductores. Las herramientas clásicas de gettext los ayudan a actualizar sus trabajos cuando una nueva liberación del original sale. Pero a diferencia del modelo clásico de gettext, las traducciones son reinyectadas en la estructura del documento original así que ellas pueden ser procesadas y distribuidas como la versión inglesa.
Gracias a esto, descubrir cuales partes del documento fueron cambiadas y necesitan una actualización se hace muy fácil. Otro buen punto es que las herramientas harán casi todo el trabajo cuando la estructura del documento original quede fundamentalmente reorganizada y cuando algunos capítulos sean movidos, unidos o divididos alrededor. Gracias a la extracción del texto a traducir de la estructura del documento, usted tambíen se mantiene alejado de la complejidad del formateo y reduce sus chances de optener un documento roto (aún si esto no le previene completamente de hacerlo).
Por favor mira las PUF abajo en este documento para una lista más completa de las ventajas y desventajas de esta aproximación.
== Formatos Soportados ==
Actualmente, esta aproximación ha sido exitosamente implementada en varias clases de formatos para formateo de texto:
=== nroff ===
El buen viejo formato de las páginas de manual, usado por tantos programas por ahí. El soporte de po4a es muy bienvenido acá puesto que este formato es algo difícil de usar y no realmente amigable para los novatos.
=== pod ===
Este es el formato de Documentación En línea de Perl (pod, por sus siglas en inglés). El lenguaje y las extensiones mismas son documentadas de esta forma, también como la mayoría de los scripts existentes de Perl. Esto hace fácil mantener la documentación cercana al código actual embebiendo las dos en el mismo archivo. Esto hace la vida del programador más fácil, pero infortunadamente no para el traductor.
=== sgml ===
Incluso si es algo excedido por XML estos días, este formato es aún usado muy a menudo para documentos que son un poco más largos que un pantallazo. Le permite hacer libros completos. Actualizar las traducciones de documentos tan largos puede llegar a ser una real pesadilla. Los diff se muestran a menudo inútiles cuando el texto original fue reindentado después de una actualización. Afortunadamente, po4a puede ayudarle en ese proceso.
Actualmente, sólo los DTD de debiandoc y docbook son soportados, pero adicionar soporte a uno nuevo es realmente fácil. Es incluso posible usar po4a en una dtd desconocida de sgml sin cambiar el código proveyendo la información necesaria en la línea de comandos. Vea Locale::Po4a::Sgml(3pm) para detalles.
=== otros ===
Po4a puede también manejar algunos formatos más raros o especializados, tales como la documentación de opciones de compilación para kernels 2.4.x o los diagramas producidos por la herramienta dia. Adicionar uno nuevo es a menudo muy fácil y la tarea principal es lograr un analizador sintáctico (parser) para su formato objetivo. Vea Locale::Po4a::TransTractor(3pm) para más información sobre esto.
== Formatos no soportados ==
Desafortunadamente, po4a aún carece de soporte para varios formatos de documentación principales. El más prominentes puede ser XML, puesto que este se hace más y más usado en la documentación del código abierto. El módulo de sgml puede ofrecer algún soporte limitado a este (principalmente funcionando cuando usted de hecho no usa las especificidades xml en su documento ;) ). Estamos actualmente trabajando en un mejor soporte aquí, y las cosas pueden cambiar en un futuro cercano. Mientras tanto, si po4a no llena realmente sus necesidades, puede querer chequear el proyecto poxml. Es similar al po4a y trata decentemente la información docbook en xml. Desafortunadamente, no puede tratar con cualquier otro formato por ahora. Y por supuesto es varias formas menos chévere que po4a ;)
TeXinfo es otra gran perdida para po4a en este momento.Toda la documentación GNU está escrita en este formato (esto es incluso un requerimiento para convertirse en un proyecto oficial GNU). La carencia de soporte en po4a así deja a todos los traductores puristas por su propia cuenta contra la adversidad del mundo. Nos gustaría lograr una solución acá, pero este formato es tan poderoso/complejo que esto no va tan rápidio como nos gustaría. Si quiere ayudar, su ayuda es naturalmente bienvenida ;)
Además de estos dos formatos principales, hay un gran resto de otros formatos que nos gustaría soportar en po4a y no sólo los de documentación. De hecho, nuestro objetivo es el plugging, todos los "huecos del mercado" dejados por las herramientas clásicas gettext. Esto incluye la documentación de python, los descriptores de paquetes (deb y rpm), las preguntas de los ''scripts'' de instalación de paquetes, bitácoras de cambio de los paquetes, y todos los formatos de archivo especializados usados por programas tales como escenarios de juegos y archivos de recursos wine.
= ¿Cómo usar po4a? =
Este capítulo es una especie de manual de referencia, que trata de contestar las preguntas de los usuarios y darle una mejor comprensión de todo el proceso. Este introduce cómo hacer cosas con po4a y sirve como una introducción a la documentación de herramientas específicas.
== Panorámica gráfica ==
El siguiente esquema da una panorámica del proceso de traducción de documentación usando po4a. No esté temeroso por su aparente complejidad, proviene del hecho de que todo el proceso está representado acá. Una vez ha convertido su proyecto a po4a, sólo la parte derecha del gráfico es relevante. Note que sgml es tomado como un ejemplo acá, pero lo mismo sigue siendo cierto para todos los módulos. Cada parte del diagrama será detallada en las siguientes secciones.
{{{
fr.sgml original.sgml ---->--------+------>----------->-------+
| | | |
V V { acutalización del original } |
| | | |
+--<---<--+ V |
| | original.nuevo.sgml----->----->----+
V V | |
[po4a-gettextize] +--->---->---+ |
| | | V |
| | | [po4a-updatepo] |
| V ^ | V
V original.pot | V |
| | | fr.po |
| | | (difuso) |
| { translation } | | |
| | ^ V V
| | | {edición manual} |
V V | | |
| | | V V
| | +--<--- fr.po addendum original.sgml
+---->----+---->----->---> (actualizado) (opcional) (actualizado)
| | |
v v v
+------>-----+------<------+
|
v
[po4a-translate]
|
V
fr.sgml
(actualizado)
}}}
En la parte izquierda, la conversión de una traducción que no usa po4a a este sistema es mostrada. En la parte superior derecha, la acción del autor original es depicted (actualizar la documentación). La mitad de la parte derecha es donde las acciones automáticas de po4a son depicted. Los nuevos materiales son extraidos, y comparados contra la traducción existente. Las partes que no cambian son encontradas, y las traducciones anterioes son usadas. Las partes que fueron parcialmente modidicadas son también conectadas a las traducciones previas, pero con un marcador específico que indica que la traducción debe ser actualizada. La figura inferior muestra como un documento formateado es construido.
De hecho, como un traductor, la única operación manual que tiene que hacer es la parte marcada {edición manual}. Si, lo siento, pero po4a le ayuda a traducir. No traduce nada por usted...
== ¿Cómo empezar una nueva traducción? ==
Esta sección presenta los pasos necesarios requeridos para empezar una nueva traducción con po4a. Los refinamientos involucrados en convertir un proyecto existente a este sistema son detallados en la sección relevante.
Para empezar una nueva traducción usando po4a, tiene que hacer los siguientes pasos:
* Extraer el texto que ha de ser traducido del documento original en un nuevo archivo pot (el formato gettext). Para eso use el programa po4a-gettextize en esta forma:
{{{
$ po4a-gettextize -f <formato> -m <maestro.doc> -p <traduccion.pot>
}}}
''<formato>'' es naturalmente el formato usando en el documento ''<maestro.doc>''. Como es de esperarse, la salida va a ''<traduccion.pot>''. Por favor refiérase a po4a-gettextize(1) para más detalles acerca de las opciones existentes.
De hecho traduzca lo que debe ser traducido. Para esto, tiene que renombrar el archivo pot por ejemplo a doc.XX.po (donde XX es el código ISO639 del lenguaje que usted está traduciciendo, por ejemplo "fr" para el francés), y edite el archivo resultante. Es a menudo buena idea no renombrar el archivo XX.po para evitar confusión con la traducción de los mensajes del programa, pero esto es un llamado a usted. No olvide actualizar las cabeceras de los archivos po, ellas son importanes.
La traducción actual puede ser hecha usando el modo po de Emacs o kbabel (basado en KDE) o gtranslator (basado en GNOME), o cualquier programa que usted prefiera usar. El bueno y viejo vi podría hacer el truco también, incluso si no hay un modo especializado para esta tarea.
Si quiere aprender más acerca de esto, definitivamente necesita referirse a la documentación gettext, disponible en el paquete gettext-doc.
== ¿Cómo cambiar la traducción de regreso a un archivo de documentación? ==
Una vez que está listo con la traducción, quiere obtener la documentación traducida y distribuirla a los usuarios junto con el original. Para esto use el programa po4a-translate(1) así (donde XX es el código del lenguaje):
{{{
$ po4a-translate -f <formato> -m <maestro.doc> -p <doc-XX.po> -l <XX.doc>
}}}
Cómo antes, ''<formato>'' es el formato usando en el documento ''<maestro.doc>''. Pero esta vez, el archivo po provisto con la bandera ''-p'' es parte de la entrada. Esta es su traducción. La salida va a <XX.doc>.
Por favor refiérase a po4a-translate(1) para más detalles.
== ¿Cómo actualizar una traducción po4a? ==
Para actualizar su traducción cuando el archivo original ha cambiado, use el programa po4a-updatepo(1) de este modo:
{{{
$ po4a-updatepo -f <format> -m <new_original.doc> -p <existing.XX.po>
}}}
(Por favor refierase a po4a-updatepo(1) para más detalles)
Naturalmente, el nuevo párrafo en el documento no quedará mágicamente traducido en el archivo po con esta operación, y usted tendrá que traducir el archivo po manualmente. De modo similar, puede tener que trabajar de nuevo la traducción por párrafos que son modificados un poco. Para estar seguro que no perdió ninguno de ellos, ellos están marcados como "difusos" (fuzzy) durante el proceso y usted tiene que remover este marcador antes de que la traducción pueda ser usada por po4a-translate. Como con la traducción inicial, lo mejor es usar su editor favorito po acá.
Una vez que su archivo po está actualizado de nuevo, sin alguna cadena no traducida o difusa, puede generar un archivo de documentación traducida, como se explicó en la sección previa.
== ¿Cómo convertir una traducción preexistente a po4a? ==
A menudo, usted suele traducir manualmente el documento felizmente hasta que una reorganización mayor del documento original ha ocurrido. Entonces, después de algunos implacenteros intentos con diff o herramientas similares, usted querra convertir a po4a. Pero por supuesto, usted no quiere perder su traducción existente en el proceso. No se preocupe, este caso también es manejado por las herramientas po4a y es llamado ''gettextización'' {{{[[Footnote(el original en inglés es gettextization)]]}}}
La clave acá es tener la misma estructura en el documento traducido y en el original de modo que las herramientas pueden comparar el contenido consecuentemente.
Si estás de suerte (es decir, si las estructuras de ambos documentos coinciden perfectamente), trabajará suavemente y estará configurado en unos pocos segundos. De otro modo, tiene que entender por qué este proceso tiene un nombre tan feo, y sería mejor estar preparado para algún trabajo incómodo aquí. En cualquier caso recuerda que es un precio a pagar para obtener el comfort de po4a después. Y el buen punto es que lo tiene que hacer sólo una vez.
No puedo enfatizar esto demasiado. A fin de facilitar el proceso, es por esto importante que usted encuentre la versión exacta que fue usada para hacer la traducción. La mejor situación es cuando usted comentó la revisión cvs usada para la traducción y usted no la modificó en en proceso de traducción, así que usted puede usarla.
No funcionará muy bien cuando use el texto original actualizado con la traducción vieja. Es aún posible, pero es más difícil y realmente deberá ser evitado si es posible. De hecho, adivino que si usted falló en encontrar el texto original de nuevo, la mejor solución es encontrar a alguien para hacer la gettextización por usted (pero, por favor, que no sea yo ;) ).
Tal vez soy demasiado dramático acá. Incluso cuando las cosas van mal, es aún mucho más rápido que traducir todo de nuevo. Yo fuí capaz de gettextizar la traducción francesa existente de la documentación de Perl en un día, incluso si las cosas fueron mal. Esto es más de dos megabites de texto, y una nueva traducción hubiera durado meses o más.
Déjenme explicarle las bases del procedimiento primero y luego volveré con pistas para logralo cuando el proceso va mal. Para facilitar la comprensión, el módulo sgml fue tomado como un ejemplo de nuevo, pero el formato usado realmente no importa.
Una vez usted tiene el original antiguo del nuevo, la ''gettextization'' puede ser tan fácil como:
{{{
$ po4a-gettextize -f <format> -m <old.original> -l <old.translation> -p <doc-XX.po>
}}}
Cuando usted es un suertudo, eso es todo. Ha convertido su vieja traducción a po4a y puede empezar con la tarea de actualización justo allí. Sólo siga el procedimiento explicado hace unas sección para sincronizar su archivo po con el más nuevo documento original, y actualice la traducción consecuentemente.
Por favor note que incluso cuando las cosas parecen funcionar apropiadamente, hay aún espacio para errores en este proceso. El punto es que po4a es incapaz de entender el texto para asegurar que la traducción concuerda con el original. Por eso es que todas las cadenas son marcadas como "fuzzy" en el proceso. Debería verificar cada una de ellas cuidadosamente antes de remover esos marcadores.
A menudo las estrucutras del documento no coinciden exactamente, preveniendo a ''po4a-gettextize'' de hacer su trabajo apropiadamente. En ese punto, todo el juego es acerca de editar los archivos para lograr que sus malditas estructuras coincidan.
Puede ayudar leer la sección Gettextization: ¿como trabaja? abajo, Entender el proceso interno le ayudará a hacerlo trabajar. El punto bueno es que po4a-gettextize es bien prólijo acerca de lo que fue mal cuando ello pasa. Primero, señala donde están las discrepancias en las estructuras del documento. Aprenderá las cadenas que no coinciden, sus posiciones en el texto y el tipo de cada una de ellas. Más aún, el archivo po generado hasta el momento será vaciado en {{{/tmp/gettextization.failed.po}}}.
* Remueva todas las partes extra de las traducciones, tales como la sección en la cual usted da el nombre del traductor y agradece a cada persona que contribuyó a la traducción. Addendums, los cuales son descritos en la siguiente sección, le permitirán re-adicionarlos luego.
* No vacile en editar tanto el original como la traducción. La cosa más importante es obtener el archivo po. Usted será capaz de actualizarlo luego. Dicho esto, editar la traducción debería ser preferido cuando las dos son posibles, puesto que hace las cosas más fáciles cuando la ''gettextization'' es hecha.
* Si es necesario, elimine alguna de las partes del original si suelen no estar traducidas. Cuando sincronice el po con el documento luego, ellas regresarán por sí mismas.
* Si cambió la estrucutra un poco (mezcló dos párrafos, o dividió otro), desaga esos cambios. Si hay asuntos en el original, debería informar al autor original. Arreglarlos en su traducción, sólo los arregla para una parte de la comunidad. Y más aún, esto es imposible cuando se usa po4a ;)
* Sometimes, the paragraph content does match, but their types don't. Fixing it is rather format-dependant. In pod and nroff, it often comes from the fact that one of the two contains a line beginning with a white space where the other doesn't. In those formats, such paragraph cannot be wrapped and thus become a different type. Just remove the space and you are fine. It may also be a typo in the tag name.
* Likewise, two paragraphs may get merged together in pod when the separating line contains some spaces, or when there is no empty line before the =item line and the content of the item.
* Sometimes, there is a desynchronization between the files, and the translation is attached to the wrong original paragraph. It is the sign that the real problem was before in the files. Check /tmp/gettextization.failed.po to see when the desynchronization begins, and fix it there.
* Sometimes, you get the strong feeling that po4a ate some parts of the text, either the original or the translation. /tmp/gettextization.failed.po indicates that both of them where gently matching, and then the gettextization fails because it tried to match one paragraph with the one after (or before) the right one, as if the right one disappeared. Curse po4a as I did when it first happened to me. Generously.
This unfortunate situation happens when the same paragraph is repeated over the document. In that case, no new entry is created in the po file, but a new reference is added to the existing one instead.
So, when the same paragraph appears twice in the original but are not translated in the exact same way each time, you will get the feeling that a paragraph of the original disappeared. Just kill the new translation. If you prefer to kill the first translation instead when it was actually better, remove the second one from where it is and put it in place of the first one.
In the contrary, if two similar but different paragraphs were translated in the exact same way, you will get the feeling that a paragraph of the translation disappeared. A solution is to add a stupid string to the original paragraph (such as "I'm different"). Don't be afraid, those things will disappear during the synchronization, and when the added text is short enough, gettext will match your translation to the existing text (marking it as fuzzy, but you don't really care since all strings are fuzzy after gettextization).
Hopefully, those tips will help you making your gettextization work and obtain your precious po file. You are now ready to synchronize your file and begin your translation. Please note that on large text, it may happen that the first synchronization takes a long time.
For example, the first po4a-updatepo of the Perl documentation's French translation (5.5 Mb po file) took about two days full on a 1Ghz G5 computer. Yes, 48 hours. But the subsequent ones only take a dozen of seconds on my old laptop. This is because the first time, most of the msgid of the po file don't match any of the pot file ones. This forces gettext to search for the closest one using a costly string proximity algorithm.
== HOWTO add extra text to translations (like translator's name)? ==
Because of the gettext approach, doing this becomes more difficult in po4a than it was when simply editing a new file along the original one. But it remains possible, thanks to the so-called addendums.
It may help the comprehension to consider addendums as a sort of patches applied to the localized document after processing. They are rather different from the usual patches (they have only one line of context, which can embed perl regular expression, and they can only add new text without removing any), but the functionalities are the same.
Their goal is to allow the translator to add extra content to the document which is not translated from the original document. The most common usage is to add a section about the translation itself, listing contributors and explaining how to report bug against the translation.
Addendum must be provided as a separate file. The first line constitutes a header indicating where in the produced document they should be placed. The rest of the addendum file will be added verbatim at the determined position of the resulting document.
The header have a pretty rigid syntax: It must begin with the string "PO4A-HEADER:", followed by a semi-colon (;) separated list of "key=value" fields. White spaces ARE important. Note that you cannot use the semi-colon char (;) in the value, and that quoting it doesn't help.
Again, it sounds scary, but the examples given below should help you to find how to write the header line you need. To illustrate the discussion, assume we want to add a section called "About this translation" after the "About this document" one.
Here are the possible header keys:
position (mandatory)
a regexp. The addendum will be placed near the line matching this regexp. Note that we're speaking about the translated document here, not the original. If more than a line match this expression (or none), the addition will fail. It is indeed better to report an error than inserting the addendum at the wrong location.
This line is called position point in the following. The point where the addendum is added is called insertion point. Those two points are near one from another, but not equal. For example, if you want to insert a new section, it is easier to put the position point on the title of the preceding section and explain po4a where the section ends (remember that position point is given by a regexp which should match a unique line).
The localization of the insertion point with regard to the position point is controlled by the mode, beginboundary and endboundary fields, as explained below.
In our case, we would have:
position=<title>About this document</title>
mode (mandatory)
It can be either the string "before" or "after", specifying the position of the addendum, relative to the position point.
Since we want the new section to be placed below the one we are matching, we have:
mode=after
beginboundary (used only when mode=after, and mandatory in that case)
endboundary (idem)
regexp matching the end of the section after which the addendum goes.
When mode=after, the insertion point is after the position point, but not directly after! It is placed at the end of the section beginning at the position point, ie after or before the line matched by the ???boundary argument, depending on whether you used beginboundary or endboundary.
In our case, we can choose to indicate the end of the section we match by adding:
endboundary=</section>
or to indicate the beginning of the next section by indicating:
beginboundary=<section>
In both case, our addendum will be placed after the </section> and before the <section>. The first one is better since it will work even if the document gets reorganized.
Both forms exist because documentation formats are different. In some of them, there is a way to mark the end of a section (just like the </section> we just used), while some other don't explicitly mark the end of section (like in nroff). In the former case, you want to make a boundary matching the end of a section, so that the insertion point comes after it. In the latter case, you want to make a boundary matching the beginning of next section, so that the insertion point comes just before it.
This can seem obscure, but hopefully, the next examples will enlighten you.
To sum up the example we used so far, in order to add a section called "About this translation" after the "About this document" one in a sgml document, you can use either of those header lines:
PO4A-HEADER: mode=after; position=About this document; endboundary=</section>
PO4A-HEADER: mode=after; position=About this document; beginboundary=<section>
If you want to add something after the following nroff section:
.SH "AUTHORS"
you should put a position matching this line, and a beginboundary matching the beginning of the next section (ie ^\.SH). The addendum will then be added after the position point and immediately before the first line matching the beginboundary. That is to say:
PO4A-HEADER:mode=after;position=AUTHORS;beginboundary=\.SH
If you want to add something into a section (like after "Copyright Big Dude") instead of adding a whole section, give a position matching this line, and give a beginboundary matching any line.
PO4A-HEADER:mode=after;position=Copyright Big Dude, 2004;beginboundary=^
If you want to add something at the end of the document, give a position matching any line of your document (but only one line. Po4a won't proceed if it's not unique), and give an endboundary matching nothing. Don't use simple strings here like "EOF", but prefer which have less chance to be in your document.
PO4A-HEADER:mode=after;position=<title>About</title>;beginboundary=FakePo4aBoundary
In any case, remember that these are regexp. For example, if you want to match the end of a nroff section ending with the line
.fi
don't use .fi as endboundary, because it will match with "the[ fi]le", which is obviously not what you expect. The correct endboundary in that case is: ^\.fi$.
If the addendum doesn't go where you expected, try to pass the -vv argument to the tools, so that they explain you what they do while placing the addendum.
=== More detailed example ===
Original document (pod formatted):
{{{
|=head1 NAME
|
|dummy - a dummy program
|
|=head1 AUTHOR
|
|me
}}}
Then, the following addendum will ensure that a section (in French) about the translator is added at the end of the file. (in French, "TRADUCTEUR" means "TRANSLATOR", and "moi" means "me")
{{{
|PO4A-HEADER:mode=after;position=AUTEUR;beginboundary=^head
|
|=head1 TRADUCTEUR
|
|moi
}}}
In order to put your addendum before the AUTHOR, use the following header:
{{{
PO4A-HEADER:mode=after;position=NOM;beginboundary=^head1
}}}
This works because the next line matching the beginboundary /^head1/ after the section "NAME" (translated to "NOM" in French), is the one declaring the authors. So, the addendum will be put between both sections.
== HOWTO do all this in one program invocation? ==
The use of po4a proved to be a bit error prone for the users since you have to call two different programs in the right order (po4a-updatepo and then po4a-translate), each of them needing more than 3 arguments. Moreover, it was difficult with this system to use only one po file for all your documents when more than one format was used.
The po4a(1) program was designed to solve those difficulties. Once your project is converted to the system, you write a simple configuration file explaining where your translation files are (po and pot), where the original documents are, their formats and where their translations should be placed.
Then, calling po4a(1) on this file ensure that the po files are synchronized against the original document, and that the translated document are generated properly. Of course, you will want to call this program twice: once before editing the po file to update them and once afterward to get completely updated translated document. But you only need to remember one command line.
= How does it work? =
This chapter gives you a brief overview of the po4a internals, so that you may feel more confident to help us maintaining and improving it. It may also help you understanding why it does not do what you expected, and how to solve your problems.
== What's the big picture here? ==
The po4a architecture is object oriented (in Perl. Isn't that neat?). The common ancestor to all parser classes is called TransTractor. This strange name comes from the fact that it is at the same time in charge of translating document and extracting strings.
More formally, it takes a document to translate plus a po file containing the translations to use as input while producing two separate outputs: Another po file (resulting of the extraction of translatable strings from the input document), and a translated document (with the same structure than the input one, but with all translatable strings replaced with content of the input po). Here is a graphical representation of this:
{{{
Input document --\ /---> Output document
\ TransTractor:: / (translated)
+-->-- parse() --------+
/ \
Input po --------/ \---> Output po
(extracted)
}}}
This little bone is the core of all the po4a architecture. If you omit the input po and the output document, you get po4a-gettextize. If you provide both input and disregard the output po, you get po4a-translate.
TransTractor::parse() is a virtual function implemented by each module. Here is a little example to show you how it works. It parses a list of paragraphs, each of them beginning with <p>.
{{{
1 sub parse {
2 PARAGRAPH: while (1) {
3 $my ($paragraph,$pararef,$line,$lref)=("","","","");
4 $my $first=1;
5 while (($line,$lref)=$document->shiftline() && defined($line)) {
6 if ($line =~ m/<p>/ && !$first--; ) {
7 $document->unshiftline($line,$lref);
8
9 $paragraph =~ s/^<p>//s;
10 $document->pushline("<p>".$document->translate($paragraph,$pararef));
11
12 next PARAGRAPH;
13 } else {
14 $paragraph .= $line;
15 $pararef = $lref unless(length($pararef));
16 }
17 }
18 return; # Did not got a defined line? End of input file.
19 }
20 }
}}}
On line 6, we encounter <p> for the second time. That's the signal of the next paragraph. We should thus put the just obtained line back into the original document (line 7) and push the paragraph built so far into the outputs. After removing the leading <p> of it on line 9, we push the concatenation of this tag with the translation of the rest of the paragraph.
This translate() function is very cool. It pushes its argument into the output po file (extraction) and returns its translation as found in the input po file (translation). Since it's used as part of the argument of pushline(), this translation lands into the output document.
Isn't that cool? It is possible to build a complete po4a module in less than 20 lines when the format is simple enough...
You can learn more about this in Locale::Po4a::TransTractor(3pm).
Gettextization: how does it work?
The idea here is to take the original document and its translation, and to say that the Nth extracted string from the translation is the translation of the Nth extracted string from the original. In order to work, both files must share exactly the same structure. For example, if the files have the following structure, it is very unlikely that the 4th string in translation (of type 'chapter') is the translation of the 4th string in original (of type 'paragraph').
{{{
Original Translation
chapter chapter
paragraph paragraph
paragraph paragraph
paragraph chapter
chapter paragraph
paragraph paragraph
}}}
For that, po4a parsers are used on both the original and the translation files to extract po files, and then a third po file is built from them taking strings from the second as translation of strings from the first. In order to check that the strings we put together are actually the translations of each other, document parsers in po4a should put information about the syntactical type of extracted strings in the document (all existing ones do so, yours should also). Then, this information is used to make sure that both documents have the same syntax. In the previous example, it would allow us to detect that string 4 is a paragraph in one case, and a chapter title in another case and to report the problem.
In theory, it would be possible to detect the problem, and resynchronize the files afterward (just like diff does). But what we should do of the few strings before desynchronizations is not clear, and it would produce bad results some times. That's why the current implementation don't try to resynchronize anything and verbosely fail when something goes wrong, requiring manual modification of files to fix the problem.
Even with these precautions, things can go wrong very easily here. That's why all translations guessed this way are marked fuzzy to make sure that the translator review and check them.
Addendum: How does it work?
Well, that's pretty easy here. The translated document is not written directly to disk, but kept in memory until all addendum are applied. The algorithms involved here are rather straightforward. We look for a line matching the position regexp, and insert the addendum before it if we're in mode=before. If not, we search for the next line matching the boundary and insert the addendum after this line if it's an endboundary or before this line if it's a beginboundary.
= FAQ =
This chapter groups the Frequently Asked Questions. In fact, most of the questions for now could be formulated that way: "Why is it designed this way, and not that one?" If you think po4a isn't the right answer to documentation translation, you should consider reading this section. If it does not answer your question, please contact us on the <po4a-devel@lists.alioth.debian.org> mailing list. We love feedback.
== Why to translate each paragraph separately? ==
Yes, in po4a, each paragraph is translated separately (in fact, each module decides this, but all existing modules do so, and yours should also). There are two main advantages to this approach:
* When the technical parts of the document are hidden from the scene, the translator can't mess with them. The fewer markers we present to the translator the less error he can do.
* Cutting the document helps in isolating the changes to the original document. When the original is modified, finding what parts of the translation need to be updated is eased by this process.
Even with these advantages, some people don't like the idea of translating each paragraph separately. Here are some of the answers I can give to their fear:
* This approach proved successfully in the KDE project and allows people there to produce the biggest corpus of translated and up to date documentation I know.
* The translators can still use the context to translate, since the strings in the po file are in the same order than in the original document. Translating sequentially is thus rather comparable whether you use po4a or not. And in any case, the best way to get the context remains to convert the document to a printable format since the text formatting ones are not really readable, IMHO.
* This approach is the one used by professional translators. I agree, that they have somehow different goals than open-source translators. The maintenance is for example often less critical to them since the content changes rarely.
== Why not to split on sentence level (or smaller)? ==
Professional translator tools sometimes split the document at the sentence level in order to maximize the reusability of previous translations and speed up their process. The problem is that the same sentence may have several translations, depending on the context.
Paragraphs are by definition longer than sentences. It will hopefully ensure that having the same paragraph in two documents will have the same meaning (and translation), regardless of the context in each case.
Splitting on smaller parts than the sentence would be very bad. It would be a bit long to explain why here, but interested reader can refer to the Locale::Maketext::TPJ13(3pm) man page (which comes with the Perl documentation), for example. To make short, each language has its specific syntactic rules, and there is no way to build sentences by aggregating parts of sentences working for all existing languages (or even for the 5 of the 10 most spoken ones, or even less).
== Why not put the original as comment along with translation (or other way)? ==
At the first glance, gettext don't seem to be adapted to all kind of translations. For example, it didn't seemed adapted to debconf, the interface all Debian packages use for their interaction with the user during installation. In that case, the texts to translate were pretty short (a dozen of line for each package), and it was difficult to put the translation in a specialized file since it has to be available before the package installation.
That's why the debconf developer decided to implement another solution, where translations are be placed in the same file than the original. This is rather appealing. One would even want to do this for xml, for example. It would look like that:
{{{
<section>
<title lang="en">My title</title>
<title lang="fr">Mon titre</title>
<para>
<text lang="en">My text.</text>
<text lang="fr">Mon texte.</text>
</para>
</section>
}}}
But it was so problematic that a po-based approach is now used. Only the original can be edited in the file, and the translations must take place in po files extracted from the master template (and placed back at package compilation time). The old system was deprecated because of several issues:
* maintenance problems
If several translators provide a patch at the same time, it gets hard to merge them together.
How will you detect changes to the original, which need to be applied to the translations? In order to use diff, you have to note which version of the original you translated. I.e., you need a po file in your file ;)
* encoding problems
This solution is viable when only European languages are involved, but the introduction of Korean, Russian and/or Arab really complicate the picture. UTF could be a solution, but there are still some problems with it.
Moreover, such problems are hard to detect (i.e., only Korean readers will detect that the encoding of Korean is broken [because of the Russian translator])
gettext solves all those problems together.
But gettext wasn't designed for that use!
That's true, but until now nobody came with a better solution. The only known alternative is manual translation, will all the maintenance issues.
What about the other translation tools for documentation using gettext?
As far as I know, there are only two of them:
poxml
This is the tool developed by KDE people to handle DocBook XML. AFAIK, it was the first program to extract strings to translate from documentation to po files, and inject them back after translation.
It can only handle XML, and only a particular DTD. I'm quite unhappy with the handling of lists, which end in one big msgid. When the list become big, the chunk becomes harder to shallow.
po-debiandoc
This program done by Denis Barbier is a sort of precursor of the po4a sgml module, which more or less deprecates it. As the name says, it handles only the debiandoc dtd, which is more or less a deprecated dtd.
The main advantages of po4a over them are the ease of extra content addition (which is even worse there) and the ability to achieve gettextization.
Educating developers about translation
When you try to translate documentation or programs, you face three kind of problems; linguistics (not everybody speaks two languages), technical (that's why po4a exists) and relational/human. Not all developers understand the necessity of translating stuff. Even when good willed may ignore how to ease the work of translators. To help with that, po4a comes with lot of documentation which can be referred to.
Another important point is that each translated file begins with a short comment indicating what the file is, how to use it. This should help the poor developers flooded with tons of files in different languages they hardly speak, and help them dealing correctly with it.
In the po4a project, translated documents are not source files anymore. Since sgml files are habitually source files, it's an easy mistake. That's why all file present this header:
{{{
| *****************************************************
| * GENERATED FILE, DO NOT EDIT *
| * THIS IS NO SOURCE FILE, BUT RESULT OF COMPILATION *
| *****************************************************
|
| This file was generated by po4a-translate(1). Do not store it (in cvs,
| for example), but store the po file used as source file by po4a-translate.
|
| In fact, consider this as a binary, and the po file as a regular source file:
| If the po get lost, keeping this translation up-to-date will be harder ;)
}}}
Likewise, gettext's regular po files only need to be copied to the po/ directory. But this is not the case of the ones manipulated by po4a. The major risk here is that a developer erases the existing translation of his program with the translation of his documentation. (Both of them can't be stored in the same po file, because the program needs to install its translation as mo file while the documentation only use its translation at compile time). That's why the po files produced by the po-debiandoc module contain the following header:
{{{
#
# ADVISES TO DEVELOPERS:
# - you do not need to manually edit POT or PO files.
# - this file contains the translation of your debconf templates.
# Do not replace the translation of your program with this !!
# (or your translators will get very upset)
#
# ADVISES TO TRANSLATORS:
# If you are not familiar with the PO format, gettext documentation
# is worth reading, especially sections dedicated to this format.
# For example, run:
# info -n '(gettext)PO Files'
# info -n '(gettext)Header Entry'
#
# Some information specific to po-debconf are available at
# /usr/share/doc/po-debconf/README-trans
# or http://www.debian.org/intl/l10n/po-debconf/README-trans
#
}}}
SUMMARY of the advantages of the gettext based approach
* The translations are not stored along with the original, which makes possible to detect if translations become out of date.
* The translations are stored in separate files from each other, which prevents translators of different languages to interfere. Both when submitting their patch or at the file encoding level.
* It is based internally on gettext (but po4a offers a very simple interface so that you don't need to understand the internals to use it). That way, we don't have to re-implement the wheel, and because of their wide use, we can think that these tools are more or less bug free.
* Nothing changed for the end-user (beside the fact translations will hopefully be better maintained :). The resulting documentation file distributed is exactly the same.
* No need for translators to learn a new file syntax and their favorite po file editor (like emacs' po mode, kbabel or gtranslator) will work just fine.
* Gettext offers simple way to get statistics about what is done, what should be reviewed and updated, and what is still to do. Some example can be found at those addresses:
- http://i18n.kde.org/tools/kbabel/img/previewKonq.png
- http://www.debian.org/intl/l10n
But everything isn't green, and this approach also has some disadvantages we have to deal with.
* Addendum are ... strange at the first glance.
* You can't adapt the translated text to your preferences, like splitting a paragraph here, and joining two other ones there. But in some sense, if there is an issue with the original, it should be reported as a bug anyway.
* Even with an easy interface, it remains a new tool people have to learn.
One of my dreams would be to integrate somehow po4a to gtranslator or kbabel. When an sgml file is opened, the strings are automatically extracted. When it's saved a translated sgml file can be written to disk. If we manage to do an MS Word (TM) module (or at least RTF) professional translators may even use it.
= Known bugs and feature requests =
The biggest issue (besides missing modules) is the encoding handling. Adding a UTF8 perl pragma and then recoding the strings on output is the way to go, but it's not done yet.
We would also like to factorise some code (about file insertion) of the sgml module back into the TransTractor so that all modules can benefit of this, but this is not user visible.
= AUTORES =
Denis Barbier <barbier,linuxfr.org>
Martin Quinson <martin.quinson,tuxfamily.org>
= Traductor =
Offray Vladimir Luna Cárdenas <offray.luna, javeriana.edu.co>
= Documento Original =
http://po4a.alioth.debian.org/
----
CategorySoftware