Uso e bug di NibTool

Matteo - 11 mar 2007 16:15

Avevamo già scritto di un bug su AppleGlot. Niente rispetto a quello trovato ora su nibtool.

nibtool è lo strumento principale fornito da Apple per localizzare risorse delle applicazioni Mac: permette di estrarre le stringhe da un file nib e di creare una versione localizzata a partire dal file nib originale e dal file di stringhe tradotto. Inoltre permette di estrarre le stringhe in modo incrementale: se si ha già una traduzione di alcune parti del nib e ne vengono aggiunte di nuove nel nib originale, può essere creato automaticamente un file di stringhe con quelle già tradotte e quelle nuove insieme.

Per generare un file di stringhe dal file nib originale il comando è:

nibtool -L MainMenu.nib > MainMenu.strings 

Il file generato è un file di testo in formato UTF–16 che contiene una serie di linee di questo tipo:

/* componente (testo) : <title:testo> (oid:XXX) */
"testo" = "testo";

"componente" è il nome Cocoa del componente a cui la stringa si riferisce, ad esempio NSButton. "testo" è il testo originale messo nell'Interface Builder. "XXX" è l'id numerico della stringa. In tutto questo l'unica parte che va modificata (tradotta) è l'ultimo "testo".

Per creare un file nib a partire da quello originale, applicando le modifiche fatte al file di stringhe, il comando è:

nibtool -d MainMenu.strings MainMenu.nib -W MainMenu_trad.nib

Infine se è stato modificato il file MainMenu.nib e si vuole creare un nuovo file MainMenu.strings senza perdere le traduzioni già fatte, il comando da utilizzare è:

nibtool -L -I MainMenu_trad.nib MainMenu.nib > MainMenu.strings 

Purtroppo nella generazione incrementale pare ci sia un bug: per qualche motivo non vengono riportate nel nuovo file eventuali traduzioni già effettuate sulle stringhe dei tooltip, identificate nel file di stringhe dal componente NSIBHelpConnector.

Per di più il nibtool non può essere utilizzato per l'integrazione automatica dei file di stringhe dei bundle, quelli cioè utilizzati dalle funzioni  della famiglia NSLocalizedString* per utilizzare stringhe localizzate dall'interno del codice: sebbene queste stringe possano essere facilmente estratte dal codice col comando genstrings, ogni integrazione va fatta normalmente a mano.

Per risolvere entrambi questi inconvenienti, ho scritto un breve script in Python (il mio primo script in Python! — scusate se c'è qualche svista):

#!/usr/bin/python

import sys
import codecs
import re
import os.path

def exit_usage(err):
    sys.stderr.write('Usage: ' + sys.argv[0] + ' <target language> <strings file name>\n')
    sys.stderr.write(err)
    sys.exit()

try:
    if len(sys.argv) != 3:
        exit_usage('')
   
    tgtLang = sys.argv[1]
    if not os.path.isdir(tgtLang + '.lproj'):
        exit_usage('Target language\'s folder not found.\n')

    filename = sys.argv[2]
    tgtFileName = tgtLang + '.lproj/' + filename
    if not os.path.isfile(tgtFileName):
        exit_usage('Target file not found.\n')

    srcFileName = 'English.lproj/' + filename
    if not os.path.isfile(srcFileName):
        exit_usage('English source file not found\n')

    tgtFile = codecs.open(tgtFileName, "r", "utf-16")
    text = tgtFile.read()
    tgtFile.close()
    lines = text.split(u'\n')
    assign_preg = re.compile(r'^\"(.*)\" = \"(.*)\"\;')

    strings = {}
    for line in lines:
        m = assign_preg.match(line)
        if m:
            orig = m.expand(r'\1')
            trad = m.expand(r'\2')
            strings[orig] = trad

    srcFile = codecs.open(srcFileName, "r", "utf-16")
    text = srcFile.read()
    srcFile.close()
    lines = text.split(u'\n')

    txtOut = u''

    for line in lines:
        m = assign_preg.match(line)
        if m:
            orig = m.expand(r'\1')
            if orig in strings:
                txtOut += u'"' + orig + u'" = "' + strings[orig] + u'";\n'
                del strings[orig]
            else:
                txtOut += line + u'\n'
        else:
            txtOut += line + u'\n'
           
    if len(strings):
        txtOut += u'/* The following strings were not found '
        txtOut += u'in the English file: delete them if you don\'t '
        txtOut += u'need them anymore */\n\n'
        for k in strings.keys():
            txtOut += u'"' + k + u'" = "' + strings[k] + u'";\n'
           
    tgtFile = codecs.open(tgtFileName + '.new', 'w', 'utf-16')
    tgtFile.write(txtOut)
    tgtFile.close()

except IOError:
    print 'I/O error'
    sys.exit(0)

Questo script si aspetta una struttura abbastanza comune della cartella di sviluppo: i file di stringa originali nella cartella English.lproj, quelli delle altre lingue in altre cartelle, ad esempio Italian.lproj. Ho chiamato questo script strings_update.py e gli ho dato il flag di esecuzione: chmod +x strings_update.py. In questo modo può essere eseguito direttamente da Terminale come fosse uno script qualunque.

Lo script serve per integrare nuove modifiche al file di stringhe inglesi nei file delle altre lingue. Ad esempio per applicare modifiche al file MainMenu.strings italiano a partire da quello inglese più recente (generato come detto sopra con l'opzione -L di nibtool), il comando sarebbe:

./strings_update.py Italian MainMenu.strings

Lo script genera un file MainMenu.strings.new nella cartella Italian.lproj. Eventuali stringhe non più presenti nel file inglese ma trovate in quello italiano vengono messe in fondo al nuovo file con una nota perché potrebbero essere relative a stringhe leggermente modificate o semplicemente corrette nelle risorse inglesi.

 
Weblog Koan Progetti Foto Contatti DW.net map