~ubuntu-branches/ubuntu/lucid/gnome-doc-utils/lucid

« back to all changes in this revision

Viewing changes to xml2po/xml2po.py

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2005-12-19 08:34:21 UTC
  • mto: (2.1.1 etch) (1.1.18 upstream)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20051219083421-k72rkh3n6vox1c0t
Tags: upstream-0.5.2
ImportĀ upstreamĀ versionĀ 0.5.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
81
81
                    self.comments[t] = comment
82
82
 
83
83
    def outputHeader(self, out):
 
84
        import time
84
85
        out.write("""msgid ""
85
86
msgstr ""
86
87
"Project-Id-Version: PACKAGE VERSION\\n"
87
 
"PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\\n"
88
 
"Language-Team: LANGUAGE\\n"
89
 
"Last-Translator: TRANSLATOR\\n"
 
88
"POT-Creation-Date: %s\\n"
 
89
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"
 
90
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"
 
91
"Language-Team: LANGUAGE <LL@li.org>\\n"
90
92
"MIME-Version: 1.0\\n"
91
93
"Content-Type: text/plain; charset=UTF-8\\n"
92
94
"Content-Transfer-Encoding: 8bit\\n"
93
95
 
94
 
""")
 
96
""" % (time.strftime("%Y-%m-%d %H:%M%z")))
95
97
 
96
98
    def outputAll(self, out):
97
99
        self.outputHeader(out)
114
116
 
115
117
 
116
118
def normalizeNode(node):
117
 
    #print node.content
118
119
    if not node:
119
120
        return
120
121
    elif isSpacePreserveNode(node):
125
126
        else:
126
127
            node.setContent(re.sub('\s+',' ', node.content))
127
128
 
128
 
    elif node.children:
 
129
    elif node.children and node.type == 'element':
129
130
        child = node.children
130
131
        while child:
131
132
            normalizeNode(child)
140
141
    try:
141
142
        # Lets add document DTD so entities are resolved
142
143
        dtd = doc.intSubset()
143
 
        tmp = ''
144
 
        if expand_entities: # FIXME: we get a "Segmentation fault" in libxml2.parseMemory() when we include DTD otherwise
145
 
            tmp = dtd.serialize()
 
144
        tmp = dtd.serialize('utf-8')
146
145
        tmp = tmp + '<norm>%s</norm>' % text
147
146
    except:
148
147
        tmp = '<norm>%s</norm>' % text
149
148
 
150
149
    try:
151
 
        #libxml2.replaceEntities(0)
152
 
        tree = libxml2.parseMemory(tmp,len(tmp))
 
150
        ctxt = libxml2.createDocParserCtxt(tmp)
 
151
        if expand_entities:
 
152
            ctxt.replaceEntities(1)
 
153
        ctxt.parseDocument()
 
154
        tree = ctxt.doc()
153
155
        newnode = tree.getRootElement()
154
156
    except:
155
157
        print >> sys.stderr, """Error while normalizing string as XML:\n"%s"\n""" % (text)
170
172
 
171
173
def stringForEntity(node):
172
174
    """Replaces entities in the node."""
173
 
    text = node.serialize()
 
175
    text = node.serialize('utf-8')
174
176
    try:
175
177
        # Lets add document DTD so entities are resolved
176
178
        dtd = node.doc.intSubset()
177
 
        tmp = dtd.serialize() + '<norm>%s</norm>' % text
 
179
        tmp = dtd.serialize('utf-8') + '<norm>%s</norm>' % text
178
180
        next = 1
179
181
    except:
180
182
        tmp = '<norm>%s</norm>' % text
218
220
    if file:
219
221
        gt = gettext.GNUTranslations(file)
220
222
        if gt:
221
 
            return gt.gettext(text)
 
223
            return gt.ugettext(text.decode('utf-8'))
222
224
    return text
223
225
 
224
226
def startTagForNode(node):
231
233
        for p in node.properties:
232
234
            if p.type == 'attribute':
233
235
                # FIXME: This part sucks
234
 
                try:
235
 
                    params += ' %s:%s="%s"' % (p.ns().name, p.name, p.content)
236
 
                except:
237
 
                    params += ' %s="%s"' % (p.name, p.content)
 
236
                params += p.serialize('utf-8')
238
237
    return result+params
239
238
        
 
239
def endTagForNode(node):
 
240
    if not node:
 
241
        return 0
 
242
 
 
243
    result = node.name
 
244
    return result
 
245
        
240
246
def isFinalNode(node):
241
247
    if automatic:
242
248
        auto = autoNodeIsFinal(node)
299
305
 
300
306
def replaceNodeContentsWithText(node,text):
301
307
    """Replaces all subnodes of a node with contents of text treated as XML."""
302
 
    #print >> sys.stderr, text
303
308
    if node.children:
304
 
        starttag = startTagForNode(node)
305
 
        endtag = node.name
 
309
        starttag = node.name #startTagForNode(node)
 
310
        endtag = endTagForNode(node)
306
311
        try:
307
312
            # Lets add document DTD so entities are resolved
308
313
            dtd = doc.intSubset()
309
314
            tmp = ''
310
315
            if expand_entities: # FIXME: we get a "Segmentation fault" in libxml2.parseMemory() when we include DTD otherwise
311
 
                tmp = dtd.serialize()
 
316
                tmp = dtd.serialize('utf-8')
312
317
            tmp = tmp + '<%s>%s</%s>' % (starttag, text, endtag)
313
318
        except:
314
319
            tmp = '<%s>%s</%s>' % (starttag, text, endtag)
315
320
 
316
321
        try:
317
 
            ctxt = libxml2.createDocParserCtxt(tmp)
 
322
            ctxt = libxml2.createDocParserCtxt(tmp.encode('utf-8'))
318
323
            ctxt.replaceEntities(0)
319
324
            ctxt.parseDocument()
320
325
            newnode = ctxt.doc()
321
326
        except:
322
 
            print >> sys.stderr, """Error while parsing translation as XML:\n"%s"\n""" % (text)
 
327
            print >> sys.stderr, """Error while parsing translation as XML:\n"%s"\n""" % (text.encode('utf-8'))
323
328
            return
324
329
 
325
330
        newelem = newnode.getRootElement()
360
365
    """
361
366
    worth = 1
362
367
    parent = node.parent
363
 
    final = isFinalNode(node)
 
368
    final = isFinalNode(node) and node.name not in ignored_tags
364
369
    while not final and parent:
365
370
        if isFinalNode(parent):
 
371
            final = 1 # reset if we've got to one final tag
 
372
        if final and (parent.name not in ignored_tags) and worthOutputting(parent):
366
373
            worth = 0
367
374
            break
368
375
        parent = parent.parent
371
378
 
372
379
    return autoNodeIsFinal(node)
373
380
    
374
 
def processElementTag(node):
 
381
def processElementTag(node, replacements, restart = 0):
375
382
    """Process node with node.type == 'element'."""
376
383
    if node.type == 'element':
377
384
        outtxt = ''
378
 
 
379
 
        if not worthOutputting(node):
380
 
            child = node.children
381
 
            while child:
382
 
                outtxt += doSerialize(child)
383
 
                child = child.next
 
385
        if restart:
 
386
            myrepl = []
384
387
        else:
385
 
            PlaceHolder = 0
386
 
            submsgs = {}
387
 
 
388
 
            child = node.children
389
 
            while child:
390
 
                if isFinalNode(child):
391
 
                    PlaceHolder += 1
392
 
                    (starttag, submsg, endtag) = processElementTag(child)
393
 
                    outtxt += '<placeholder-%d/>' % (PlaceHolder)
394
 
                    if mode=='merge':
395
 
                        submsgs[PlaceHolder] = (starttag, getTranslation(submsg, isSpacePreserveNode(node)), endtag)
 
388
            myrepl = replacements
 
389
 
 
390
        submsgs = []
 
391
 
 
392
        child = node.children
 
393
        while child:
 
394
            if (isFinalNode(child)) or (child.type == 'element' and worthOutputting(child)):
 
395
                myrepl.append(processElementTag(child, myrepl, 1))
 
396
                outtxt += '<placeholder-%d/>' % (len(myrepl))
 
397
            else:
 
398
                if child.type == 'element':
 
399
                    (starttag, content, endtag, translation) = processElementTag(child, myrepl, 0)
 
400
                    outtxt += '<%s>%s</%s>' % (starttag, content, endtag)
396
401
                else:
397
402
                    outtxt += doSerialize(child)
398
403
 
399
 
                child = child.next
400
 
 
401
 
            if mode=='merge':
402
 
                outtxt = getTranslation(outtxt, isSpacePreserveNode(node))
403
 
                for i in submsgs.keys():
404
 
                    outtxt = outtxt.replace('<placeholder-%d/>' % (i), ''.join(submsgs[i]))
405
 
                if worthOutputting(node):
406
 
                    replaceNodeContentsWithText(node, outtxt)
407
 
            elif worthOutputting(node):
408
 
                msg.outputMessage(outtxt, node.lineNo(), getCommentForNode(node), isSpacePreserveNode(node), tag = node.name)
409
 
 
410
 
        starttag = '<' + startTagForNode(node) + '>'
411
 
        endtag = '</' + node.name + '>'
412
 
        return (starttag, outtxt, endtag)
 
404
            child = child.next
 
405
 
 
406
        if mode == 'merge':
 
407
            translation = getTranslation(outtxt, isSpacePreserveNode(node))
 
408
        else:
 
409
            translation = outtxt
 
410
        starttag = startTagForNode(node)
 
411
        endtag = endTagForNode(node)
 
412
 
 
413
        if restart or worthOutputting(node):
 
414
            i = 0
 
415
            while i < len(myrepl):
 
416
                replacement = '<%s>%s</%s>' % (myrepl[i][0], myrepl[i][3], myrepl[i][2])
 
417
                i += 1
 
418
                translation = translation.replace('<placeholder-%d/>' % (i), replacement)
 
419
 
 
420
            if worthOutputting(node):
 
421
                if mode == 'merge':
 
422
                    replaceNodeContentsWithText(node, translation)
 
423
                else:
 
424
                    msg.outputMessage(outtxt, node.lineNo(), getCommentForNode(node), isSpacePreserveNode(node), tag = node.name)
 
425
 
 
426
        return (starttag, outtxt, endtag, translation)
413
427
    else:
414
428
        raise Exception("You must pass node with node.type=='element'.")
415
429
 
458
472
    elif node.type == 'text':
459
473
        return node.serialize('utf-8')
460
474
    elif node.type == 'element':
461
 
        return ''.join(processElementTag(node))
 
475
        repl = []
 
476
        (starttag, content, endtag, translation) = processElementTag(node, repl, 1)
 
477
        return '<%s>%s</%s>' % (starttag, content, endtag)
462
478
    else:
463
479
        child = node.children
464
480
        outtxt = ''
531
547
            sys.stderr.write("Error: cannot rename file.\n")
532
548
            sys.exit(11)
533
549
        else:
534
 
            os.system("msgfmt -cv -o /dev/null %s" % (file))
 
550
            os.system("msgfmt -cv -o %s %s" % (NULL_STRING, file))
535
551
            sys.exit(0)
536
552
 
537
553
def load_mode(modename):
565
581
ultimate = [ ]
566
582
ignored = [ ]
567
583
filenames = [ ]
 
584
translationlanguage = ''
568
585
 
569
586
mode = 'pot' # 'pot' or 'merge'
570
587
automatic = 0
573
590
 
574
591
output  = '-' # this means to stdout
575
592
 
 
593
NULL_STRING = '/dev/null'
 
594
if not os.path.exists('/dev/null'): NULL_STRING = 'NUL'
 
595
 
576
596
import getopt, fileinput
577
597
 
578
598
def usage (with_help = False):
591
611
    -r    --reuse=FILE         Specify translated XML file with the same structure
592
612
    -t    --translation=FILE   Specify MO file containing translation, and merge
593
613
    -u    --update-translation=LANG.po   Updates a PO file using msgmerge program
 
614
    -l    --language=LANG      Set language of the translation to LANG
594
615
    -v    --version            Output version of the xml2po program
595
616
 
596
617
    -h    --help               Output this message
610
631
if len(sys.argv) < 2: usage()
611
632
 
612
633
args = sys.argv[1:]
613
 
try: opts, args = getopt.getopt(args, 'avhkem:t:o:p:u:r:',
 
634
try: opts, args = getopt.getopt(args, 'avhkem:t:o:p:u:r:l:',
614
635
                           ['automatic-tags','version', 'help', 'keep-entities', 'expand-all-entities', 'mode=', 'translation=',
615
 
                            'output=', 'po-file=', 'update-translation=', 'reuse=' ])
 
636
                            'output=', 'po-file=', 'update-translation=', 'reuse=', 'language=' ])
616
637
except getopt.GetoptError: usage(True)
617
638
 
618
639
for opt, arg in opts:
624
645
        expand_entities = 0
625
646
    elif opt in ('-e', '--expand-all-entities'):
626
647
        expand_all_entities = 1
 
648
    elif opt in ('-l', '--language'):
 
649
        translationlanguage = arg
627
650
    elif opt in ('-t', '--translation'):
628
651
        mofile = arg
629
652
        mode = 'merge'
630
 
        translationlanguage = os.path.splitext(mofile)[0]
 
653
        if translationlanguage == '': translationlanguage = os.path.split(os.path.splitext(mofile)[0])[1]
631
654
    elif opt in ('-r', '--reuse'):
632
655
        origxml = arg
633
656
    elif opt in ('-u', '--update-translation'):
635
658
    elif opt in ('-p', '--po-file'):
636
659
        mofile = ".xml2po.mo"
637
660
        pofile = arg
638
 
        translationlanguage = os.path.splitext(pofile)[0]
639
 
        os.system("msgfmt -o %s %s >/dev/null" % (mofile, pofile)) and sys.exit(7)
 
661
        if translationlanguage == '': translationlanguage = os.path.split(os.path.splitext(pofile)[0])[1]
 
662
        os.system("msgfmt -o %s %s >%s" % (mofile, pofile, NULL_STRING)) and sys.exit(7)
640
663
        mode = 'merge'
641
664
    elif opt in ('-o', '--output'):
642
665
        output = arg