Development/Tutorials/Localization/i18n (gl)
Tutorial Series | Localization |
Previous | recoméndase Introduction to Unicode, mais non é imprescindíbel |
What's Next | Avoiding Common Localization Pitfalls |
Further Reading | n/a |
Resumo
Chegar a un público amplo de usuarios e programadores require que se poida traducir o software e que este se adapte cando se execute de xeito que sexa lingüística e culturalmente relevante para quen se sente diante dun computador. Este é o territorio da localización e este titorial guía nos pasos precisos para que unha aplicación sexa localizábel.
Que son a "internacionalización" e a "localización"?
A internacionalización, ou i18n ("i" seguido de 18 letras e despois por un "n"), é o proceso de escribir unha aplicación para que se poda executar en calquera "locale" (as informacións que describen os formatos e mensaxes dunha determinada língua ou país). Isto significa ter en conta cousas tais como:
- as mensaxes de texto que se lle mostran ao usuario
- a entrada de datos por parte do usuario, ficheiros e outras fontes
- o formato das datas, números, moedas, etc.
A localización, ou l10n ("l" seguido de 10 caracteres e despois por un "n"), é o proceso de tomar unha aplicación internacionalizada e adaptala a un "locale" determinado.
En termos xerais, os programadores internacionalizan as súas aplicacións e as equipas de tradución localízanas.
Por que é isto importante?
O desenvolvemento do KDE ten lugar fundamentalmente en inglés, dado que esta lingua permite chegar a máis persoas nas comunidades de programadores e de tradutores. Porén, o inglés non é a lingua principal da maioría das persoas do planeta. De feito, menos dun 8% da humanidade fala inglés e menos dun 5% o fala como lingua materna. Mesmo na Internet, só o 35% de quen están en liña emprega o inglés como lingua principal e conforme máis e máis persoas se conectan, este número vai decrecendo. Para alén disto, a maioría das linguas, incluídas nove de cada dez das máis faladas, empregan caracteres que non están no ASCII na súa escrita. É doado ver, polo tanto, o por que fornecer software localizado se tornou nunha necesidade.
Como proxecto internacional que abrangue o mundo enteiro, esta localización é un valor central da cultura do KDE. De feito, mesmo se moitos programadores do KDE escriben o seu software en inglés, empregan o escritorio no seu "locale" nativo.
Código traducíbel mediante i18n()
Para se asegurar de que unha aplicación está preparada para ser localizada hai que seguir unhas regras simples. Hai que traducir todas as cadeas que sexan visíbeis para o usuario antes de que se lle mostren na pantalla; exceptúanse as mensaxes de depuración, as teclas de configuración e outros tipos semellantes de datos textuais.
O KDE fornece a clase KLocale como parte de libkdecore para facilitar os detalles técnicos da localización. O KLocale facilita no posíbel que os programadores fagan que o seu código admita o i18n, mais hai outras cousas que hai que ter en conta para que as aplicacións sexan utilizábeis noutras linguas e países.
O acceso a un obxecto KLocale global fornécese mediante KGlobal::locale(). Este obxecto KLocale créao KInstance automaticamente e ocúpase de todas as opcións relacionadas co i18n do usuario. Elimínase automaticamente cando se sae da aplicacións.
As traducións son posíbeis grazas ao método QString i18n(const char*), definido en klocalizedstring.h, no que hai que envolver todas as cadeas que haxa que mostrar. O QString que devolve i18n() é a cadea traducida (de ser preciso). Isto fai que crear widgets traducíbeis sexa tan doado como neste exemplo:
#include <klocalizedstring.h>
[...]
QPushButton* myButton = new QPushButton(i18n("Translate this!"));
QString acepta o Unicode de maneira nativa, o que permite que todas as traducións se representen correctamente. Polo tanto, toda a xestión de cadeas que faga unha aplicación debería empregar QString.
ki18n
O método i18n() require que se crease un KInstance (p.ex. KApplication). Fornécese outro método para as cadeas que se creasen con anterioridade a isto: ki18n(). isto permite marcar como tais cadeas que habería que traducir máis tarde. O ki18n() devolve un KLocalizedString, que pode ser finalizado nun QString (isto é, traducido de verdade) despois de terse creado o KInstance, empregando o seu método toString().
O k18n() emprégase tipicamente nas cadeas que se pasan a KAboutData porque se constrúe antes de KApplication e só se pode empregar i18(n) despois da construción de KApplication. Para alén destes casos especiais, é máis seguro empregar i18n() se non se ten certeza de que o código se vaia executar despois da construción de KApplication ou doutro KInstance.
Engadir contexto con i18nc()
Existe un método extendido, i18nc() que toma dous argumentos const char*. O primeiro argumento é unha descrición de contexto adicional da segunda cadea que se ha de traducir. A primeira cadea emprégase para atopar a tradución correspondente adecuada no momento da execución e preséntaselles aos tradutores para axudar a comprender o significado da cadea.
Empregue i18nc() cando o propósito do texto poida ser ambiguo en ausencia doutro contexto. Por exemplo, considere un menú de contexto nun xestor de ficheiros cunha entrada chamada "View" que abre un visor do ficheiro seleccionado. Neste contexto, "View" é un verbo. Porén, a mesma aplicación pode ter tamén un menú chamado "View" na barra de menú. Neste contexto, "View" é un substantivo. Na versión en inglés da aplicación todo parece correcto, mais na maioría das demais linguas unha das dúas cadeas "View" será incorrecta.
Para alén disto, ás veces os tradutores precisan de axuda adicional para comprender a que se refire exactamente o texto durante o proceso de tradución.
No exemplo anterior do xestor de ficheiros, poderíase, polo tanto, escribir:
contextMenu->addAction(i18nc("verb, to view something", "View"));
viewMenu->addAction(i18nc("noun, the view", "View"));
Agora as dúas cadeas son traducíbeis correctamente, tanto polos tradutores humanos como no momento de execución por KLocale.
Empregue esta forma de i18n cando a cadea que haxa que traducir sexa curta ou o sentido difícil de discernir cando non se coñece exactamente o contexto. Por exemplo:
Use this form of i18n whenever the string to translate is short or the meaning is hard to discern when the context is not exactly known. For example:
QString up = i18nc("Go one directory up in the hierarchy", "Up");
QString relation = i18nc("A person's name and their familial relationship to you.", "%1 is your %2", name, relationship);
Tamén se poden engadir contextos cando se deseñan formularios en QT Designer. Cada etiqueta dun widget, incluídas as suxestións e os textos "que é isto", ten un atributo "comment", que ten o mesmo propósito como primeiro argumento da chamada i18nc().
Contexto normal das frases frecuentes
A continuación hai unha táboa que mostra algunhas palabras e frases frecuentes en inglés e o contexto que hai que empregar con elas para asegurarse de que se traducen correctamente noutras linguas.
Frase | Contexto | Chamada i18nc | Exemplo |
---|---|---|---|
Busy | Refering to a person | i18nc("A person is busy", "Busy") | |
Busy | Refering to a thing | i18nc("A thing is busy", "Busy") | |
Color | Color mode, as opposed to Grayscale | i18nc("Not Grayscale", "Color") | |
Creator | Refering to a person | i18nc("A person who creates", "Creator") | |
Creator | Refering to software | i18nc("Software", "Creator") | |
Display | Refering to hardware | i18nc("Hardware display", "Display") | |
Editor | Refering to a person | i18nc("A person who edits", "Editor") | |
Editor | Refering to software | i18nc("Software", "Editor") | |
Line | Refering to drawing | i18nc("Draw a line", "Line") | |
Line | Refering to text | i18nc("Line of text", "Line") | |
Name | Refering to a name of thing | i18nc("A thing's name", "Name") | In theme change dialog: i18nc("Theme name", "Name") |
Name | Refering to first name and last name of person | i18nc("Person's first and last name", "Name") | In KAddessbook contact edit dialog: i18nc("Person's first and last name", "Name") |
New | Create smth | i18nc("Action", "New") | |
New | Status | i18nc("New mail message", "New") | |
No | Answer to a question | i18nc("Answer to a question", "No") | |
No | Availability of a thing | i18nc("Availability", "No") | |
(Re)load | (Re)load a document, medium etc. | i18nc("(Re)load a document", "(Re)load") | |
(Re)load | (Re)start a program, daemon etc. | i18nc("(Re)start a program", "(Re)load") | |
Title | Refering to a person | i18nc("A person's title", "Title") | |
Title | Refering to a thing | i18nc("A thing's title", "Title") | |
Trash | Refering to the action of emptying | i18nc("The trash is not empty. Empty it", "Empty") | |
Trash | Refering to the state of being empty | i18nc("The trash is empty. This is not an action, but a state", "Empty") | |
Volume | Refering to sound | i18nc("Sound volume", "Volume") | |
Volume | Refering to a filesystem | i18nc("Filesystem volume", "Volume") | |
Volume | Refering to books | i18nc("Book volume", "Volume") | |
Yes | Answer to a question | i18nc("Answer to a question", "Yes") | |
Yes | Availability of a thing | i18nc("Availability", "Yes") |
Plurais
Os plurais son moi distintos en canda lingua. Moitas linguas teñen plurais diferentes para 2, 10, 20, 100, etc. Cando a cadea que se quere traducir se refire a máis dun elemento, hai que empregar a terceira forma de i18n,i18np(). Esta toma as formas de singular e de plural do inglés como primeiros dous argumentos, seguidos dos argumentos substitutos, como sempre, mais un deles ao menos un deles ha ser un valor enteiro. Por exemplo:
msgStr = i18np("1 image in album %2", "%1 images in album %2", numImages, albumName);
i18np() expándese a tantos casos como requira a lingua do usuario. En inglés son só dúas formas, mentres que noutras linguas poden ser máis, dependendo do valor do primeiro argumento con valor enteiro.
Observe que hai que empregar esta forma mesmo se a cadea se refire sempre a máis de un elemento, dado que algunhas linguas empregan unha forma de singular mesmo cando se refiren a un plural (tipicamente para 21, 31, etc.). Este código:
i18n("%1 files were deleted", numFilesDeleted);
é, polo tanto, incorrecto, e debería ser:
i18np("1 file was deleted",
"%1 files were deleted",
numFilesDeleted);
Para fornecer tanto contexto como formas de plural, empregue i18ncp como neste exemplo:
i18ncp("Personal file", "1 file", "%1 files", numFiles);
Formato de datas e números
Cando o programa lle mostre un número ao usuario, halle de prestar atención aos separadores de decimais e de milleiros e ao símbolo da moeda (de existir) que se empregue. Estes símbolos difiren de rexión en rexión. Nos países de fala inglesa emprégase un punto (.) para separar a parte decimal dun número, mentres que nalgunhas linguas europeas, entre elas o galego, emprégase a vírgula (,). A continuación hai un resumo pequeno de funcións que axudan a formatar os números correctamente, tendo conta das convencións locais en beneficio do programador.
Formats a.. | From a.. | Function Prototype |
---|---|---|
Number | String | QString formatNumber( const QString & numStr ) |
Number | Integer, double | formatNumber( double num, int precision = -1 ) |
Money | String | formatMoney( const QString & numStr ) |
Money | Number | formatMoney( double num, const QString & currency, int digits = -1 ) |
Date | String | formatDate( const QDate & pDate, bool shortFormat=false ) |
Time | QTime | formatTime( const QTime & pTime, bool includeSecs=false) |
Date and time | QDateTime | formatDateTime( const QDateTime &pDateTime, bool shortFormat = true, bool includeSecs = false ) |
Existen funcións semellantes para ler información fornecida polo usuario durante a execución no seu formato localizado, p.ex. readNumber() ou readMoney().
Calendarios
A programación de aplicacións que traballen con datas e horas, como os calendarios, é unha área moi complexa. Non é só que unha cadea que conteña unha data ou hora teña unha aparencia distinta baseada no "locale", senón que hai que ter en conta outros aspectos, tais como:
- o día no que comeza a semana (vexa int weekStartDay())
- cantos meses ten o ano
- calendarios baseados na "era"
- se se utiliza o formato de 24 horas (vexa bool use12Clock())
O Klocale fornece, entre outros, estes métodos:
Formats a.. | From a.. | Function Prototype |
---|---|---|
Date | QDate | formatDate( const QDate & pDate, bool shortFormat=false ) |
Time | QTime | formatTime( const QTime & pTime, bool includeSecs=false ) |
Date and time | QDateTime | formatDateTime( const QDateTime &pDateTime, bool shortFormat=true, bool includeSecs=false ) |
cleanup confusing sections and fix sections which contain a todo
fornecer máis información acerca dos distintos sistemas de calendario
Evitar problemas frecuentes
Existen un monte de problemas frecuentes que poden dificultar que se localice axeitadamente unha aplicación. Vexa Avoiding Common Localization Pitfalls para saber máis sobre eles e sobre como evitalos.