Tradurre Linux con gettext

La funzione gettext è stata progettata per permettere la traduzione dell’intero Sistema Operativo GNU/Linux.

Proprio per questa ragione è compatibile al 100% con un gran numero di linguaggi di programmazione e di scripting: C, C++, C#, Bash, Python, GNU clsip, Emacs Lisp, GNU Smalltalk, Java, GNU awk, Pascal, WxWidgets, YCP, Tcl, PHP, Pike, ed altri ancora.

Per prima cosa vediamo come si utilizza `gettext` all’interno del codice sorgente. Le modalità di esecuzione variano a seconda del linguaggio di programmazione adottato per il proprio progetto, ma la sintassi è pressoché sempre la stessa, almeno per i linguaggi di programmazione più diffusi: la funzione racchiude semplicemente la stringa del messaggio da tradurre.

Va notato che quasi sempre si ricorre alla forma abbreviata, che corrisponde semplicemente ad un underscore. In questo modo, il seguente codice in C:

printf(gettext("My name is %sn"), mio_nome);

diventa:

printf(_("My name is %sn"), mio_nome);

In seguito, il comando xgettext filtrerà il codice alla ricerca della funzione gettext appena inserita, per creare il file modello .pot sulla base delle stringhe estratte dai sorgenti.

Un esempio di file .pot per un codice contenete le righe precedenti è il seguente:

#: include/myname.php:36
msgid "My name is %sn"
msgstr ""

Per avviare la traduzione si ricorre al programma `msginit`. Passando il file .po a `msginit` è possibile infatti generare un nuovo file contenente lo scheletro del nuovo .po nella lingua di destinazione.

Ad esempio, per tradurre in italiano il file en_EN.po è sufficiente lanciare il seguente comando:

msginit –locale=it_IT –input=en_EN.po

Il programma creerà il file it_IT.po, il cui contenuto sarà simile al seguente:

#: include/myname.php:36
msgid "My name is %sn"
msgstr "My name is %sn"

A questo punto il traduttore non deve fare altro che tradurre la stringa che segue msgstr. La traduzione può essere effettuata con un qualsiasi editor direttamente da linea di comando, oppure ricorrendo a programmi specifici come poEdit. Il risultato sarà simile a quanto segue:

#: include/myname.php:36
msgid "My name is %sn"
msgstr "Mi chiamo %sn"

Una volta terminata la traduzione, i file .po deve essere compilato nel file binario .mo tramite il comando `msgfmt`:

msgfmt it_IT.po

Questo è quanto!

Condivido
10 Commenti
  • Giuseppe
    Ottobre 10, 2008

    Ciao, tempo fa avevo fatto alcuni servicemenus per kde3.
    adesso li sto portando a kde4 e volevo aggiungere il supporto alle lingue barbare 🙂

    In pratica il menu’ chiama uno script bash e inizialmente avevo inserito tutte le stringhe gia’ tradotte nello stesso script:
    per esempio

    ————————————————-

    en_msg_savefile=”Save file …”
    it_msg_savefile=”Salva file …”

    ecc..

    eval msg_SaveFile=$$(echo ${lang}_msg_SaveFile)

    e quindi echo “${msg_SaveFile}”
    ————————————————

    Adesso mi chiedo, secondo te si puo’ adottare facilmente la procedura da te descritta sopra per localizzare lo scriptino in bash?

    Grazie

  • Giuseppe
    Ottobre 10, 2008

    ho trovato quello che cercavo, grazie.
    una sola cosa vorrei ancora chiederti, ci sono alcune parole che in inglese si scivono in una certa maniera ma in italiano o altre lingue no.
    per es: Done
    in italiano devo scrivere finito o finita, in base all’operazione svolta precedentemente.

    Se per es ruoto un immagine verra’ visualizzata una finestra con scritto “rotazione dell’immagine casa.jpg” “Conclusa”
    In inglese scriverei sempre e comunque “Done”!

    Sai come posso fare per risolvere questa cosa?

    Ti ringrazio in anticipo.
    Molti stanno cominciando ad usare kde4 e mi hanno scritto parecchie mail che speravano in un porting degli scripts. Solo che fino ad ora ci sono 8 lingue, ma piu’ avanti potrebbero aumentare.

    Saluti Pippo

  • Ivan Agliardi
    Ottobre 13, 2008

    Ciao Giuseppe,

    scusa il ritardo, sono molto preso. Rispondo prima alla tua seconda domanda: se decidi di utilizzare gettext la corrispondenza tra la lingua base e le varie traduzioni deve essere necessariamente univoca su tutti i vocaboli e, nel caso in cui la lingua di traduzione sia più articolata di quella di partenza, deve essere biunivoca, ove possibile. Nel caso di cui parli la biunivocità è impossibile, quindi non ti resta che tradurre blocchi di frasi invece che le singole parole. Oppure, come fa ogni bravo traduttore, ti basta adottare qualche piccola astuzia. Nel tuo caso io tradurrei “Done” con “… Fatto” anziché “Concluso/a”. Ma sono certo che hai esempi più complessi in cui questa semplice soluzione non basta, girameli qui che li discutiamo insieme.

    Per quanto riguarda la tua prima domanda, anche sa hai trovato da solo la soluzione, ti dico che usare gettext è la soluzione più semplice ed immediata e ti risparmia di chiamare in causa eval o altri “raggiri” 🙂 Trovi un esempio pratico molto significativo a questo indirizzo:

    https://tldp.org/LDP/abs/html/localization.html

    … ma sono certo che tu lo hai già visto, quindi ti invito a pubblicare qui un breve esempio di come hai implementato la cosa tu a beneficio di tutti 😉

    Bye! Ivan

  • Giuseppe
    Ottobre 13, 2008

    ciao Ivan, grazie della risposta.
    dammi il tempo di dare un buon nome alle variabili e sistemare qualche altra cosina e poi posto qualche esempio piu’ complesso.
    Cmq appena li finisco li pubblico su kde-look.org, come ho fatto con quelli per kde3 qui: https://www.kde-look.org/content/show.php/konq-pdf?content=37321

    a presto 🙂

  • Giuseppe
    Ottobre 13, 2008

    A proposito dei trucchetti di cui parlavi … per mantenere una traduzione completa con tutti i dettaggli di una lingua, basta usare coma chiave hash una chiave creata da te, e non la traduzione vera e propria. Per es:

    nel file sorgente “gettext(msg_saveFile_title)”

    e poi passiamo a creare il file en.po, it.po ecc
    in questa maniera il messaggio e’ univoco e in piu’ mi permette di usare maschili, femminili o neutri, e altre caratteristiche.

    Che ne pensi?

    ciao 🙂

  • Ivan Agliardi
    Ottobre 15, 2008

    Per quanto riguarda gli script che pubblicherai su kde-look.org, avvisami quando lo fai, sono curioso. Sul secondo messaggio (uso della chiave hash con gettext) sono certo che la cosa sarebbe pressoché impossibile da realizzare: le lingue sono profondamente differenti fra loro sia da un punto di vista morfologico che sintattico, la sola soluzione è quella di produrre tutte le frasi necessarie nella lingua d’origine e generare le corrispondenti frasi nelle lingue tradotte. È fonte di ridondanze interminabili, ma credimi, non c’è alternativa utilizzando una soluzione efficace ma molto semplice come gettext. Però se ne può sempre parlare, magari sono io che non ho colto fino in fondo il significato del tuo post.

    bye 😉

    Ivan

  • Giuseppe
    Ottobre 15, 2008

    Girando un po per i canali degli sviluppatori sono venuto a conoscenza di i18nc che sarebbe l’internazionalizzazione contestualizzata. In pratica, permette di specificare un messaggio in base al contesto. Non ho approfondito poiche’ mi e’ stato detto che sarebbe meglio che ogni software abbia nei sorgento soo messaggi in inglese en_gb e poi, tramite lacoalizzazione, le altre lingue. Quindi, alla luce di questo, non posso usare la tecnica accennata sopra.
    In ogni caso mi hanno anche detto che non bisogna usare gettext direttamente, quindi da bash non posso usarlo.

    Dopo questa premessa, ho deciso di fare questi cosi con la tecnica “eval”, e’ come usare i puntatori in bash 🙂

    Io ho finito proprio oggi i servicemenus ed hanno un mare di funzioni per lavorare con i pdf. Ne ho aggiunte alcune rispetto a quelli della versione precedente. Mi mancano ancora le traduzioni, quindi dovro’ aspettare che i vari traduttori mi riconsegnino i sorgenti con le frasi tradotte e mi sa che se ne andra’ un po di tempo (ci sono in tutto 8 lingue).

    Avevo promesso un esempio un po piu’ complesso, quindi prendero’ uno dei servicemenus che ho scritto, eliminero’ tutte le funzioni tranne una e commentero’ sommariamente solo la parte relativa all’internazionalizzazione.

    Oggetto:
    Un servicemenu che estrae le immagini da un documento pdf. (il programma che fa questo si chiama pdfimages ed e’ contenuto in poppler-utils).
    Servira’ un file .desktop da mettere in ~/.kde/share/kde4/services/ServiceMenus o nell’equivalente di sistema (per tutti gli utenti).
    Barbatrucco: ho notato che potete creare anche una sottocartella, in modo da avere piu’ ordine.
    Il file lo chiamiamo pdfimages.desktop (nome arbitrario) e contiene:

    [Desktop Entry]
    Type=Service
    ServiceTypes=KonqPopupMenu/Plugin
    MimeType=application/pdf;
    Icon=image-jpeg
    TryExec=pdfimages
    Actions=all;select;_SEPARATOR_;all_usr;select_usr;_SEPARATOR_;all_own;select_own;
    Name=pdfimages service menu
    X-KDE-Submenu=Extract images
    X-KDE-Submenu[de]=Extract images
    X-KDE-Submenu[es]=Extract images
    X-KDE-Submenu[fr]=Extract images
    X-KDE-Submenu[it]=Estrai le immagini
    X-KDE-Submenu[sr]=Extract images
    X-KDE-Submenu[sr@Latn]=Extract images
    X-KDE-Submenu[pl]=Extract images
    X-KDE-Submenu[pt]=Extract images
    
    [Desktop Action all]
    Icon=image-jpeg
    Name=From all pages
    Name[de]=From all pages
    Name[es]=From all pages
    Name[fr]=From all pages
    Name[it]=Da tutte le pagine
    Name[sr]=From all pages
    Name[sr@Latn]=From all pages
    Name[pl]=From all pages
    Name[pt]=From all pages
    Exec=sm_pdfimages.sh en all "%f"
    Exec[de]=sm_pdfimages.sh de all "%f"
    Exec[es]=sm_pdfimages.sh es all "%f"
    Exec[fr]=sm_pdfimages.sh fr all "%f"
    Exec[it]=sm_pdfimages.sh it all "%f"
    Exec[sr]=sm_pdfimages.sh sr all "%f"
    Exec[sr@Latn]=sm_pdfimages.sh sr@Latn all "%f"
    Exec[pl]=sm_pdfimages.sh pl all "%f"
    Exec[pt]=sm_pdfimages.sh pt all "%f"
    
    [Desktop Action select]
    ...
    ...
    ...
    

    Quando cliccate su una delle voci, kde esegue quello che c’e’ scritto nella riga Exec[lang], dove lang e’ la lingua impostata per kde stesso.
    Come vedete, viene chiamato uno scriptino di nome sm_pdfimages.sh e gli vengono passati alcuni parametri: la lingua, un’azione, il file su cui lavorare.

    Passiamo allo scriptino, che conterrá:

    #! /bin/sh
    
    lang=`echo "${1}" | sed -e "s/@//g"`
    action="${2}"
    inFile="${3}"
    workDir="${inFile%/*}"
    
    inFileName=`echo "${inFile}" | sed -e "s/.*///"`
    baseFileName=`echo "${inFileName%.*}" | sed -e "s/ /_/g"`
    
    #### languages strings messages #################
    # sintax for strings name is: $lang_msg_[$action]_$window_[$section]
    
    #### language en
    en_msg_imagesRootName_title="Insert pictures prefix"
    en_msg_imagesRootName=`echo "Notes: The images name, once extracted from the document, will be made by a prefix followed by a progressive number:n(${baseFileName}-000.ppm, ${baseFileName}-001.ppm ...).nnChange prefix for images or leave default value:"`
    
    en_msg_finish_title="Extraction images from all pages of document "${baseFileName}""
    en_msg_finish="Done."
    
    #### language de
    ...
    
    #### language es
    ...
    
    #### language fr
    ...
    
    #### language it
    it_msg_imagesRootName_title="Inserisci il prefisso per le immagini"
    it_msg_imagesRootName=`echo "Note: Il nome delle immagini, una votla estratte dal documento, sará composto da un prefisso seguito da un numero crescente (${baseFileName}-000.ppm, ${baseFileName}-001.ppm ...).nnCambia il prefisso per le immagini o lascia il valore predefinito:"`
    
    it_msg_finish_title="Estrazione delle immagini da tutte le pagine del documento "${baseFileName}""
    it_msg_finish="Completata."
    
    ################################################
    
    eval msg_imagesRootName_title=$$(echo ${lang}_msg_imagesRootName_title)
    eval msg_imagesRootName=$$(echo ${lang}_msg_imagesRootName)
    eval msg_finish_title=$$(echo ${lang}_msg_finish_title)
    eval msg_finish=$$(echo ${lang}_msg_finish)
    
    ################################################
    
    all () {
    	pdfimages -j "${inFileName}" `
    	kdialog --title "${msg_imagesRootName_title}" --caption "${msg_imagesRootName_title}" --icon editcopy --inputbox "${msg_imagesRootName}" "${baseFileName}"` && 
    	kdialog --title "${msg_finish_title}" --passivepopup "${msg_finish}" 5
    }
    
    all_usr () {
    ...
    }
    
    select () {
    ...
    }
    
    cd "${workDir}"
    "${action}"
    cd -
    

    Adesso vediamo quello che succede quando viene chiamato lo script in questione:

    prima di tutto devo dire che uso il contenuto della variabile action, direttamente come chiamata a funzione 🙂 In questa maniera risparmio su if case ecc…
    Quando viene eseguita una funzione (per esempio all), la bash sostituisce le variabili con il valore contenuto. Analizziamone solo una: “${msg_imagesRootName_title}”
    Questa variabile contiene il titolo di una finestra di dialogo, peró non viene specifica la lingua 🙂
    La frase corretta viene ottenuta con un giochetto che all’inizio mi ha incuriosito, tenetevi forte!! un puntatore elementare (molto elementare) 🙂

    Andiamo con ordine, prima definisco le variabili dei messaggi in ogni lingua che mi interessa e chiamo le variabili stesse con un nome che contiene la stringa della lingua usata.
    Quindi, per il titolo:

    en_msg_imagesRootName_title="Insert pictures prefix"
    it_msg_imagesRootName_title="Inserisci il prefisso per le immagini"
    

    come vedete la differenza del nome consiste solo nella parte iniziale.
    Successivamente definisco una variabile il cui nome e’ uguale a quello delle sopradescritte ma senza la parte “lang”, in questa maniera:

    eval msg_imagesRootName_title=$$(echo ${lang}_msg_imagesRootName_title)
    

    Se supponiamo che la lingua in uso sia it, con questo procedimento la shell dice a msg_imagesRootName_title di assumere il valore contenuto in $it_msg_imagesRootName_title ed il gioco e’ fatto.
    In pratica la variabile msg_imagesRootName_title conterra’ il messaggio corretto in base alla lingua utilizzata.

    Finito.
    Dopo aver valutato varie alternative, questo mi sembrava il modo piu’ facile per internazionalizzare lo script. Naturalmente se qualcuno ha un’altra idea, sarebbe ben accetta.

    Fiuu.. piu’ facile implementarlo che spiegarlo.
    Come detto sopra, ci vorrá ancora qualche tempo prima di pubblicarli, anche se potrei farlo subito e le traduzioni si aggiungeranno in seguito.

    PS se ti va di mettere i tag per il codice per renderlo piu’ leggibile, fai pure.

    Buona giornata a tutti 🙂
    Giuseppe

  • Ivan Agliardi
    Ottobre 15, 2008

    Cazzarola, questo non è un semplice commento, ma un post con i controfiocchi! Complimenti 🙂 Ammetto di non avere avuto il tempo per provare il tuo codice, ma la logica c’è e la spiegazione è chiarissima. Sei il primo a guadagnarti l’ingresso nel mio Blogroll! 😉

    Ivan

  • Giuseppe
    Ottobre 15, 2008

    Ciao Ivan, grazie del blogroll.
    Il commento sembra lungo per via del codice :-).
    Devo ancora capire perche’ non bisogna usare gettext direttamente, sembrava molto semplice e facilmente aggiornabile.
    In ogni caso, questi service menus sono una cosa non rifinita, con poco controllo sul flusso dei comandi.
    Adesso che ho messo tutto in uno script ho la possibilita’, col tempo, di inserire molti piu’ controlli. Se dai un’occhiata ai menu che avevo fatto, il flusso di ogni comando é sequenziale poiché all’interno dei file .desktop non potevo usufruire di if o variabili. Effettivamente mi ricordo di aver fatto salti mortali pur di non ricorrere a files esterni 🙂
    Spero che l’esempio postato stimoli un po di gente a creare dei menu contestuali. Dopo tutto siamo noi stessi che miglioreremo il nostro kde4, o almeno, io l’ho fatto col mio e mi ci trovo benissimo.
    Se ci riesco provo ad inserire questo lavoro su kde.org cosí chiunque potrá lavorare sui pdf in modo semplice senza bisogno di installare alcunché.

    A tutti:
    Consigli e suggerimenti per nuove funzionalitá sono ben accetti.
    Non sono un programmatore e non dovete esserlo nemmeno voi per partecipare. Nonostante questo molte persone di tutto il mondo mi hanno ringraziato per qualcosa che nemmeno pensavano fosse possibile.

    Auguro buon lavoro a tutti con il loro kde4 o altro che sia. (sempre su sistemi open).

    Giuseppe

  • Giuseppe Benigno
    Novembre 24, 2008

    Anche se con un po di ritardo, ho pubblicato ieri i servicemenu su cui ho lavorato.
    Ho messo l’annuncio sia su kde-look.org che su http://www.egregorion.net

    C’e’ il tar.gz e il deb per Intrepid.

    Buon divertimento 🙂
    Giuseppe

Leave a comment