| Index: grit/xtb_reader.py
|
| ===================================================================
|
| --- grit/xtb_reader.py (revision 0)
|
| +++ grit/xtb_reader.py (revision 0)
|
| @@ -0,0 +1,132 @@
|
| +#!/usr/bin/python2.4
|
| +# Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +'''Fast and efficient parser for XTB files.
|
| +'''
|
| +
|
| +
|
| +import sys
|
| +import xml.sax
|
| +import xml.sax.handler
|
| +
|
| +
|
| +class XtbContentHandler(xml.sax.handler.ContentHandler):
|
| + '''A content handler that calls a given callback function for each
|
| + translation in the XTB file.
|
| + '''
|
| +
|
| + def __init__(self, callback, defs=None, debug=False):
|
| + self.callback = callback
|
| + self.debug = debug
|
| + # 0 if we are not currently parsing a translation, otherwise the message
|
| + # ID of that translation.
|
| + self.current_id = 0
|
| + # Empty if we are not currently parsing a translation, otherwise the
|
| + # parts we have for that translation - a list of tuples
|
| + # (is_placeholder, text)
|
| + self.current_structure = []
|
| + # Set to the language ID when we see the <translationbundle> node.
|
| + self.language = ''
|
| + # Keep track of the if block we're inside. We can't nest ifs.
|
| + self.if_expr = None
|
| + # Root defines to be used with if expr.
|
| + if defs:
|
| + self.defines = defs
|
| + else:
|
| + self.defines = {}
|
| +
|
| + def startElement(self, name, attrs):
|
| + if name == 'translation':
|
| + assert self.current_id == 0 and len(self.current_structure) == 0, (
|
| + "Didn't expect a <translation> element here.")
|
| + self.current_id = attrs.getValue('id')
|
| + elif name == 'ph':
|
| + assert self.current_id != 0, "Didn't expect a <ph> element here."
|
| + self.current_structure.append((True, attrs.getValue('name')))
|
| + elif name == 'translationbundle':
|
| + self.language = attrs.getValue('lang')
|
| + elif name == 'if':
|
| + assert self.if_expr is None, "Can't nest <if> in xtb files"
|
| + self.if_expr = attrs.getValue('expr')
|
| +
|
| + def endElement(self, name):
|
| + if name == 'translation':
|
| + assert self.current_id != 0
|
| +
|
| + defs = self.defines
|
| + def pp_ifdef(define):
|
| + return define in defs
|
| + def pp_if(define):
|
| + return define in defs and defs[define]
|
| +
|
| + # If we're in an if block, only call the callback (add the translation)
|
| + # if the expression is True.
|
| + should_run_callback = True
|
| + if self.if_expr:
|
| + should_run_callback = eval(self.if_expr, {},
|
| + {'os': sys.platform,
|
| + 'defs' : defs,
|
| + 'pp_ifdef' : pp_ifdef,
|
| + 'pp_if' : pp_if})
|
| + if should_run_callback:
|
| + self.callback(self.current_id, self.current_structure)
|
| +
|
| + self.current_id = 0
|
| + self.current_structure = []
|
| + elif name == 'if':
|
| + assert self.if_expr is not None
|
| + self.if_expr = None
|
| +
|
| + def characters(self, content):
|
| + if self.current_id != 0:
|
| + # We are inside a <translation> node so just add the characters to our
|
| + # structure.
|
| + #
|
| + # This naive way of handling characters is OK because in the XTB format,
|
| + # <ph> nodes are always empty (always <ph name="XXX"/>) and whitespace
|
| + # inside the <translation> node should be preserved.
|
| + self.current_structure.append((False, content))
|
| +
|
| +
|
| +class XtbErrorHandler(xml.sax.handler.ErrorHandler):
|
| + def error(self, exception):
|
| + pass
|
| +
|
| + def fatalError(self, exception):
|
| + raise exception
|
| +
|
| + def warning(self, exception):
|
| + pass
|
| +
|
| +
|
| +def Parse(xtb_file, callback_function, defs={}, debug=False):
|
| + '''Parse xtb_file, making a call to callback_function for every translation
|
| + in the XTB file.
|
| +
|
| + The callback function must have the signature as described below. The 'parts'
|
| + parameter is a list of tuples (is_placeholder, text). The 'text' part is
|
| + either the raw text (if is_placeholder is False) or the name of the placeholder
|
| + (if is_placeholder is True).
|
| +
|
| + Args:
|
| + xtb_file: file('fr.xtb')
|
| + callback_function: def Callback(msg_id, parts): pass
|
| +
|
| + Return:
|
| + The language of the XTB, e.g. 'fr'
|
| + '''
|
| + # Start by advancing the file pointer past the DOCTYPE thing, as the TC
|
| + # uses a path to the DTD that only works in Unix.
|
| + # TODO(joi) Remove this ugly hack by getting the TC gang to change the
|
| + # XTB files somehow?
|
| + front_of_file = xtb_file.read(1024)
|
| + xtb_file.seek(front_of_file.find('<translationbundle'))
|
| +
|
| + handler = XtbContentHandler(callback=callback_function, defs=defs,
|
| + debug=debug)
|
| + xml.sax.parse(xtb_file, handler)
|
| + assert handler.language != ''
|
| + return handler.language
|
| +
|
|
|
| Property changes on: grit/xtb_reader.py
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|