diff options
author | Shaun McCance <shaunm@gnome.org> | 2011-04-30 14:56:07 -0400 |
---|---|---|
committer | Shaun McCance <shaunm@gnome.org> | 2011-04-30 14:56:07 -0400 |
commit | 4aac006a9f0350f3dbd6588cdb4254e8b895ec78 (patch) | |
tree | a4151555c7a28e33d35ef137c012fbe7cf329f4c /itstool.in | |
parent | 6d60e6e1d14bc6b62e0c43cb0781d562d23dd684 (diff) | |
download | itstool-4aac006a9f0350f3dbd6588cdb4254e8b895ec78.tar.gz |
Added --version
Diffstat (limited to 'itstool.in')
-rwxr-xr-x | itstool.in | 797 |
1 files changed, 797 insertions, 0 deletions
diff --git a/itstool.in b/itstool.in new file mode 100755 index 0000000..69f5640 --- /dev/null +++ b/itstool.in @@ -0,0 +1,797 @@ +#!/usr/bin/env python + +VERSION="@VERSION@" + +import gettext +import hashlib +import libxml2 +import optparse +import os +import os.path +import re +import sys +import time + +NS_ITS = 'http://www.w3.org/2005/11/its' +NS_ITST = 'http://itstool.org/extensions/' +NS_BLANK = 'http://itstool.org/extensions/blank/' +NS_XLINK = 'http://www.w3.org/1999/xlink' + +class NoneTranslations: + def gettext(self, message): + return None + + def lgettext(self, message): + return None + + def ngettext(self, msgid1, msgid2, n): + return None + + def lngettext(self, msgid1, msgid2, n): + return None + + def ugettext(self, message): + return None + + def ungettext(self, msgid1, msgid2, n): + return None + + +class MessageList (object): + def __init__ (self): + self._messages = [] + self._by_node = {} + self._has_credits = False + + def add_message (self, message, node): + self._messages.append (message) + if node is not None: + self._by_node[node] = message + + def add_credits(self): + if self._has_credits: + return + msg = Message() + msg.set_context('_') + msg.add_text('translator-credits') + msg.add_comment('Put one translator per line, in the form NAME <EMAIL>, YEAR1, YEAR2') + self._messages.append(msg) + self._has_credits = True + + def get_message_by_node (self, node): + return self._by_node.get(node, None) + + def get_nodes_with_messages (self): + return self._by_node.keys() + + def output (self, out): + msgs = [] + msgdict = {} + for msg in self._messages: + key = (msg.get_context(), msg.get_string()) + if msgdict.has_key(key): + for source in msg.get_sources(): + msgdict[key].add_source(source) + for comment in msg.get_comments(): + msgdict[key].add_comment(comment) + if msg.get_preserve_space(): + msgdict[key].set_preserve_space() + else: + msgs.append(msg) + msgdict[key] = msg + out.write('msgid ""\n') + out.write('msgstr ""\n') + out.write('"Project-Id-Version: PACKAGE VERSION\\n"\n') + out.write('"POT-Creation-Date: %s\\n"\n' % time.strftime("%Y-%m-%d %H:%M%z")) + out.write('"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"\n') + out.write('"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"\n') + out.write('"Language-Team: LANGUAGE <LL@li.org>\\n"\n') + out.write('"MIME-Version: 1.0\\n"\n') + out.write('"Content-Type: text/plain; charset=UTF-8\\n"\n') + out.write('"Content-Transfer-Encoding: 8bit\\n"\n') + out.write('\n') + for msg in msgs: + out.write(msg.format()) + out.write('\n') + + +class Message (object): + def __init__ (self): + self._message = [] + self._empty = True + self._ctxt = None + self._placeholders = [] + self._sources = [] + self._comments = [] + self._preserve = False + + class Placeholder (object): + def __init__ (self, node): + self.node = node + self.name = node.name + + def escape (self, text): + return text.replace('\\','\\\\').replace('"', "\\\"").replace("\n","\\n").replace("\t","\\t") + + def add_text (self, text): + if len(self._message) == 0 or not(isinstance(self._message[-1], basestring)): + self._message.append('') + self._message[-1] += text.replace('&', '&').replace('<', '<').replace('>', '>') + if re.sub('\s+', ' ', text).strip() != '': + self._empty = False + + def add_placeholder (self, node): + holder = Message.Placeholder(node) + self._placeholders.append(holder) + self._message.append(holder) + + def get_placeholder (self, name): + placeholder = 1 + for holder in self._placeholders: + holdername = '%s-%i' % (holder.name, placeholder) + if holdername == name: + return holder + placeholder += 1 + + def add_start_tag (self, node): + if len(self._message) == 0 or not(isinstance(self._message[-1], basestring)): + self._message.append('') + self._message[-1] += ('<%s' % node.name) + if node.properties is not None: + for prop in node.properties: + if prop.type == 'attribute': + name = prop.name + if prop.ns() is not None: + name = prop.ns().name + ':' + name + atval = prop.content + atval = atval.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"') + self._message += " %s=\"%s\"" % (name, atval) + if node.children is not None: + self._message[-1] += '>' + else: + self._message[-1] += '/>' + + def add_end_tag (self, node): + if node.children is not None: + if len(self._message) == 0 or not(isinstance(self._message[-1], basestring)): + self._message.append('') + self._message[-1] += ('</%s>' % node.name) + + def is_empty (self): + return self._empty + + def get_context (self): + return self._ctxt + + def set_context (self, ctxt): + self._ctxt = ctxt + + def add_source (self, source): + self._sources.append(source) + + def get_sources (self): + return self._sources + + def add_comment (self, comment): + self._comments.append(comment) + + def get_comments (self): + return self._comments + + def get_string (self): + message = '' + placeholder = 1 + for msg in self._message: + if isinstance(msg, basestring): + message += msg + elif isinstance(msg, Message.Placeholder): + message += '<_:%s-%i/>' % (msg.name, placeholder) + placeholder += 1 + if not self._preserve: + message = re.sub('\s+', ' ', message).strip() + return message + + def get_preserve_space (self): + return self._preserve + + def set_preserve_space (self, preserve=True): + self._preserve = preserve + + def format (self): + ret = '' + for i in range(len(self._comments)): + if i != 0: + ret += '#.\n' + comment = self._comments[i] + while len(comment) > 72: + j = comment.rfind(' ', 0, 72) + if j == -1: + j = comment.find(' ') + if j == -1: + break + ret += '#. %s\n' % comment[:j] + comment = comment[j+1:] + ret += '#. %s\n' % comment + for source in self._sources: + ret += '#: %s\n' % source + if self._preserve: + ret += '#, no-wrap\n' + if self._ctxt is not None: + ret += 'msgctxt "%s"\n' % self._ctxt + message = self.get_string() + if self._preserve: + ret += 'msgid ""\n' + lines = message.split('\n') + for line, no in zip(lines, range(len(lines))): + if no == len(lines) - 1: + ret += '"%s"\n' % self.escape(line) + else: + ret += '"%s\\n"\n' % self.escape(line) + else: + ret += 'msgid "%s"\n' % self.escape(message) + ret += 'msgstr ""\n' + return ret + + +def xml_child_iter (node): + child = node.children + while child is not None: + yield child + child = child.next + +def xml_is_ns_name (node, ns, name): + if node.type != 'element': + return False + return node.name == name and node.ns() is not None and node.ns().content == ns + + +class Document (object): + def __init__ (self, filename, messages): + ctxt = libxml2.createFileParserCtxt(filename) + ctxt.lineNumbers(1) + ctxt.replaceEntities(1) + ctxt.parseDocument() + self._filename = filename + self._doc = ctxt.doc() + self._localrules = [] + def pre_process (node): + for child in xml_child_iter(node): + if xml_is_ns_name(child, 'http://www.w3.org/2001/XInclude', 'include'): + if child.prop('parse') == 'text': + child.xincludeProcessTree() + elif xml_is_ns_name(child, NS_ITS, 'rules'): + if child.hasNsProp('href', NS_XLINK): + href = child.nsProp('href', NS_XLINK) + href = os.path.join(os.path.dirname(filename), href) + hctxt = libxml2.createFileParserCtxt(href) + hctxt.replaceEntities(1) + hctxt.parseDocument() + self._localrules.append(hctxt.doc().getRootElement()) + else: + self._localrules.append(child) + pre_process(child) + pre_process(self._doc) + self._msgs = messages + self._its_translate_nodes = {} + self._its_within_text_nodes = {} + self._its_loc_notes = {} + self._itst_preserve_space_nodes = {} + self._its_lang = {} + self._itst_lang_attr = {} + self._itst_credits = None + self._itst_externals = [] + + def apply_its_rule(self, rule, xpath): + if rule.type != 'element': + return + if xml_is_ns_name(rule, NS_ITS, 'translateRule'): + if rule.prop('selector') is not None: + for node in xpath.xpathEval(rule.prop('selector')): + self._its_translate_nodes[node] = rule.prop('translate') + elif xml_is_ns_name(rule, NS_ITS, 'withinTextRule'): + if rule.prop('selector') is not None: + for node in xpath.xpathEval(rule.prop('selector')): + self._its_within_text_nodes[node] = rule.prop('withinText') + elif xml_is_ns_name(rule, NS_ITST, 'preserveSpaceRule'): + if rule.prop('selector') is not None: + for node in xpath.xpathEval(rule.prop('selector')): + self._itst_preserve_space_nodes[node] = rule.prop('preserveSpace') + elif xml_is_ns_name(rule, NS_ITS, 'locNoteRule'): + locnote = None + for child in xml_child_iter(rule): + if xml_is_ns_name(child, NS_ITS, 'locNote'): + locnote = re.sub('\s+', ' ', child.content).strip() + break + if locnote is None: + if rule.hasProp('locNoteRef'): + locnote = 'SEE: ' + re.sub('\s+', ' ', rule.prop('locNoteRef')).strip() + if rule.prop('selector') is not None: + for node in xpath.xpathEval(rule.prop('selector')): + if locnote is not None: + self._its_loc_notes[node] = locnote + else: + if rule.hasProp('locNotePointer'): + sel = rule.prop('locNotePointer') + ref = False + elif rule.hasProp('locNoteRefPointer'): + sel = rule.prop('locNoteRefPointer') + ref = True + else: + continue + try: + oldnode = xpath.contextNode() + except: + oldnode = None + xpath.setContextNode(node) + for note in xpath.xpathEval(sel): + cont = re.sub('\s+', ' ', note.content).strip() + if ref: + cont = 'SEE: ' + cont + self._its_loc_notes[node] = cont + break + xpath.setContextNode(oldnode) + elif xml_is_ns_name(rule, NS_ITS, 'langRule'): + if rule.prop('selector') is not None and rule.prop('langPointer') is not None: + for node in xpath.xpathEval(rule.prop('selector')): + try: + oldnode = xpath.contextNode() + except: + oldnode = None + xpath.setContextNode(node) + res = xpath.xpathEval(rule.prop('langPointer')) + if len(res) > 0: + self._its_lang[node] = res[0].content + # We need to construct language attributes, not just read + # language information. Technically, langPointer could be + # any XPath expression. But if it looks like an attribute + # accessor, just use the attribute name. + if rule.prop('langPointer')[0] == '@': + self._itst_lang_attr[node] = rule.prop('langPointer')[1:] + xpath.setContextNode(oldnode) + elif xml_is_ns_name(rule, NS_ITST, 'credits'): + if rule.prop('appendTo') is not None: + for node in xpath.xpathEval(rule.prop('appendTo')): + self._itst_credits = (node, rule) + break + elif xml_is_ns_name(rule, NS_ITST, 'externalRefRule'): + if rule.prop('selector') is not None and rule.prop('refPointer') is not None: + for node in xpath.xpathEval(rule.prop('selector')): + try: + oldnode = xpath.contextNode() + except: + oldnode = None + xpath.setContextNode(node) + res = xpath.xpathEval(rule.prop('refPointer')) + if len(res) > 0: + self._itst_externals.append((node, res[0].content)) + xpath.setContextNode(oldnode) + + def apply_its_rules (self): + dirs = [] + ddir = os.getenv('XDG_DATA_HOME', '') + if ddir == '': + ddir = os.path.join(os.path.expanduser('~'), '.local', 'share') + dirs.append(ddir) + ddir = os.getenv('XDG_DATA_DIRS', '') + if ddir == '': + ddir = '/usr/local/share:/usr/share' + dirs.extend(ddir.split(':')) + ddone = {} + for ddir in dirs: + itsdir = os.path.join(ddir, 'itstool', 'its') + if not os.path.exists(itsdir): + continue + for dfile in os.listdir(itsdir): + if dfile.endswith('.its'): + if not ddone.get(dfile, False): + self.apply_its_file(os.path.join(itsdir, dfile)) + ddone[dfile] = True + self.apply_local_its_rules() + + def apply_its_file (self, filename): + doc = libxml2.parseFile(filename) + root = doc.getRootElement() + if not xml_is_ns_name(root, NS_ITS, 'rules'): + return + matched = True + for match in xml_child_iter(root): + if xml_is_ns_name(match, NS_ITST, 'match'): + matched = False + xpath = self._doc.xpathNewContext() + par = match + nss = {} + while par is not None: + nsdef = par.nsDefs() + while nsdef is not None: + if nsdef.name is not None: + if not nss.has_key(nsdef.name): + nss[nsdef.name] = nsdef.content + xpath.xpathRegisterNs(nsdef.name, nsdef.content) + nsdef = nsdef.next + par = par.parent + if match.hasProp('selector'): + if len(xpath.xpathEval(match.prop('selector'))) > 0: + matched = True + break + if matched == False: + return + for rule in xml_child_iter(root): + xpath = self._doc.xpathNewContext() + par = match + nss = {} + while par is not None: + nsdef = par.nsDefs() + while nsdef is not None: + if nsdef.name is not None: + if not nss.has_key(nsdef.name): + nss[nsdef.name] = nsdef.content + xpath.xpathRegisterNs(nsdef.name, nsdef.content) + nsdef = nsdef.next + par = par.parent + self.apply_its_rule(rule, xpath) + + def apply_local_its_rules (self): + for rules in self._localrules: + def reg_ns(xpath, node): + if node.parent is not None: + reg_ns(xpath, node.parent) + nsdef = node.nsDefs() + while nsdef is not None: + if nsdef.name is not None: + xpath.xpathRegisterNs(nsdef.name, nsdef.content) + nsdef = nsdef.next + xpath = self._doc.xpathNewContext() + reg_ns(xpath, rules) + for rule in xml_child_iter(rules): + if rule.nsDefs() is not None: + rule_xpath = self._doc.xpathNewContent() + reg_ns(rule_xpath, rule) + else: + rule_xpath = xpath + self.apply_its_rule(rule, rule_xpath) + + def _append_credits(self, parent, node, trdata): + if xml_is_ns_name(node, NS_ITST, 'for-each'): + select = node.prop('select') + if select == 'years': + for year in trdata[2].split(','): + for child in xml_child_iter(node): + self._append_credits(parent, child, trdata + (year.strip(),)) + elif xml_is_ns_name(node, NS_ITST, 'value-of'): + select = node.prop('select') + val = None + if select == 'name': + val = trdata[0] + elif select == 'email': + val = trdata[1] + elif select == 'years': + val = trdata[2] + elif select == 'year' and len(trdata) == 4: + val = trdata[3] + if val is not None: + val = val.encode('utf-8') + parent.addContent(val) + else: + newnode = node.copyNode(2) + parent.addChild(newnode) + for child in xml_child_iter(node): + self._append_credits(newnode, child, trdata) + + def merge_credits(self, translations, language, node): + if self._itst_credits is None: + return + # Dear Python, please implement pgettext. + # http://bugs.python.org/issue2504 + # Sincerely, Shaun + trans = translations.ugettext('_\x04translator-credits') + if trans is None or trans == 'translator-credits': + return + regex = re.compile('(.*) \<(.*)\>, (.*)') + for credit in trans.split('\n'): + match = regex.match(credit) + if not match: + continue + trdata = match.groups() + for node in xml_child_iter(self._itst_credits[1]): + self._append_credits(self._itst_credits[0], node, trdata) + + def merge_translations(self, translations, language, node=None): + is_root = False + if node is None: + is_root = True + self.generate_messages(comments=False) + node = self._doc.getRootElement() + if node is None or node.type != 'element': + return + if is_root: + self.merge_credits(translations, language, node) + msg = self._msgs.get_message_by_node(node) + if msg is None: + children = [child for child in xml_child_iter(node)] + for child in children: + self.merge_translations(translations, language, node=child) + else: + newnode = self.get_translated(node, translations) + if newnode != node: + node.replaceNode(newnode) + if is_root: + # Apply language attributes to untranslated nodes. We don't do + # this before processing, because then these attributes would + # be copied into the new nodes. We apply the attribute without + # checking whether it was translated, because any that were will + # just be floating around, unattached to a document. + for lcnode in self._msgs.get_nodes_with_messages(): + attr = self._itst_lang_attr.get(lcnode) + if attr is None: + continue + origlang = None + lcpar = lcnode + while lcpar is not None: + origlang = self._its_lang.get(lcpar) + if origlang is not None: + break + lcpar = lcpar.parent + if origlang is not None: + lcnode.setProp(attr, origlang) + # And then set the language attribute on the root node. + if language is not None: + attr = self._itst_lang_attr.get(node) + if attr is not None: + node.setProp(attr, language) + # Because of the way we create nodes and rewrite the document, + # we end up with lots of redundant namespace definitions. We + # kill them off in one fell swoop at the end. + def fix_node_ns (node, nsdefs): + childnsdefs = nsdefs.copy() + nsdef = node.nsDefs() + while nsdef is not None: + nextnsdef = nsdef.next + if nsdefs.has_key(nsdef.name) and nsdefs[nsdef.name] == nsdef.content: + node.removeNsDef(nsdef.content) + else: + childnsdefs[nsdef.name] = nsdef.content + nsdef = nextnsdef + for child in xml_child_iter(node): + if child.type == 'element': + fix_node_ns(child, childnsdefs) + fix_node_ns(node, {}) + + def get_translated (self, node, translations): + msg = self._msgs.get_message_by_node(node) + if msg is None: + return node + trans = translations.ugettext(msg.get_string()) + if trans is None: + return node + nss = {} + def reg_ns(node, nss): + if node.parent is not None: + reg_ns(node.parent, nss) + nsdef = node.nsDefs() + while nsdef is not None: + nss[nsdef.name] = nsdef.content + nsdef = nsdef.next + reg_ns(node, nss) + nss['_'] = NS_BLANK + blurb = '<' + node.name + for nsname in nss.keys(): + if nsname is None: + blurb += ' xmlns="%s"' % nss[nsname] + else: + blurb += ' xmlns:%s="%s"' % (nsname, nss[nsname]) + blurb += '>%s</%s>' % (trans.encode('utf-8'), node.name) + ctxt = libxml2.createDocParserCtxt(blurb) + ctxt.replaceEntities(0) + ctxt.parseDocument() + trnode = ctxt.doc().getRootElement() + def scan_node(node): + for child in xml_child_iter(node): + if child.type != 'element': + continue + if child.ns() is not None and child.ns().content == NS_BLANK: + repl = self.get_translated(msg.get_placeholder(child.name).node, translations) + child.replaceNode(repl) + scan_node(child) + scan_node(trnode) + retnode = node.copyNode(2) + for child in xml_child_iter(trnode): + retnode.addChild(child.copyNode(1)) + return retnode + + def generate_messages(self, comments=True): + if self._itst_credits is not None: + self._msgs.add_credits() + for ext in self._itst_externals: + msg = Message() + try: + fullfile = os.path.join(os.path.dirname(self._filename), ext[1]) + filefp = open(fullfile) + filemd5 = hashlib.md5(filefp.read()).hexdigest() + filefp.close() + except: + filemd5 = '__failed__' + txt = "external ref='%s' md5='%s'" % (ext[1], filemd5) + msg.set_context('_') + msg.add_text(txt) + msg.add_source('%s:%i(%s)' % (self._doc.name, ext[0].lineNo(), ext[0].name)) + msg.add_comment('This is a reference to an external file such as an image or' + ' video. When the file changes, the md5 hash will change to' + ' let you know you need to update your localized copy. The' + ' msgstr is not used at all. Set it to whatever you like' + ' once you have updated your copy of the file.') + self._msgs.add_message(msg, None) + self._in_translatable = True + for child in xml_child_iter(self._doc): + if child.type == 'element': + self.generate_message(child, None, comments=comments) + break + + def generate_message (self, node, msg, comments=True): + if node.type in ('text', 'cdata') and msg is not None: + msg.add_text(node.content) + return + if node.type != 'element': + return + translate = self.get_its_translate(node) + if translate is None: + if self._in_translatable: + translate = 'yes' + else: + translate = 'no' + if translate == 'no': + if msg is not None: + msg.add_placeholder(node) + is_unit = False + msg = None + else: + is_unit = msg is None or self.is_translation_unit(node) + if is_unit: + if msg is not None: + msg.add_placeholder(node) + msg = Message() + if self.get_preserve_space(node): + msg.set_preserve_space() + msg.add_source('%s:%i(%s/%s)' % (self._doc.name, node.lineNo(), node.parent.name, node.name)) + else: + msg.add_start_tag(node) + + if comments and msg is not None: + comment = self.get_its_loc_note(node) + if comment is not None: + msg.add_comment(comment) + + in_translatable = self._in_translatable + self._in_translatable = (translate == 'yes') + for child in xml_child_iter(node): + self.generate_message(child, msg, comments=comments) + self._in_translatable = in_translatable + + if translate: + if is_unit and not msg.is_empty(): + self._msgs.add_message(msg, node) + elif msg is not None: + msg.add_end_tag(node) + + def is_translation_unit (self, node): + return self.get_its_within_text(node) != 'yes' + + def get_preserve_space (self, node): + if node.getSpacePreserve() == 1: + return True + else: + while node.type == 'element': + if self._itst_preserve_space_nodes.has_key(node): + return (self._itst_preserve_space_nodes[node] == 'yes') + node = node.parent + return False + + def get_its_translate (self, node): + if node.hasNsProp('translate', NS_ITS): + return node.nsProp('translate', NS_ITS) + if xml_is_ns_name(node, NS_ITS, 'span'): + if node.hasProp('translate'): + return node.prop('translate') + if self._its_translate_nodes.has_key(node): + return self._its_translate_nodes[node] + return None + + def get_its_within_text (self, node): + return self._its_within_text_nodes.get(node, 'no') + + def get_its_loc_note (self, node): + if node.hasNsProp('locNote', NS_ITS): + return re.sub('\s+', ' ', node.nsProp('locNote', NS_ITS)).strip() + if node.hasNsProp('locNoteRef', NS_ITS): + return 'SEE: ' + re.sub('\s+', ' ', node.nsProp('locNoteRef', NS_ITS)).strip() + if xml_is_ns_name(node, NS_ITS, 'span'): + if node.hasProp('locNote'): + return re.sub('\s+', ' ', node.prop('locNote')).strip() + if node.hasProp('locNoteRef'): + return 'SEE: ' + re.sub('\s+', ' ', node.prop('locNoteRef')).strip() + return self._its_loc_notes.get(node, None) + + +if __name__ == '__main__': + options = optparse.OptionParser() + options.set_usage('\n itstool [OPTIONS] [XMLFILES]\n itstool -m <MOFILE> [OPTIONS] [XMLFILES]') + options.add_option('-i', '--its', + action='append', + dest='itsfile', + metavar='ITS', + help='load the ITS rules in the file ITS (can specify multiple times)') + options.add_option('-l', '--lang', + dest='lang', + default=None, + metavar='LANGUAGE', + help='explicitly set the language code for output file') + options.add_option('-m', '--merge', + dest='merge', + metavar='FILE', + help='merge from a PO or MO file FILE and output XML files') + options.add_option('-o', '--output', + dest='output', + default=None, + metavar='OUT', + help='output PO files to file OUT or XML files in directory OUT') + options.add_option('-v', '--version', + action='store_true', + dest='version', + default=False, + help='output PO files to file OUT or XML files in directory OUT') + (opts, args) = options.parse_args(sys.argv) + + if opts.version: + print 'itstool ' + VERSION + sys.exit(0) + + if opts.merge is None: + messages = MessageList() + for filename in args[1:]: + doc = Document(filename, messages) + doc.apply_its_rules() + if opts.itsfile is not None: + for itsfile in opts.itsfile: + doc.apply_its_file(itsfile) + doc.generate_messages() + if opts.output is None or opts.output == '-': + out = sys.stdout + else: + try: + out = file(opts.output, 'w') + except: + sys.stderr.write('Error: Cannot write to file %s\n' % opts.output) + sys.exit(1) + messages.output(out) + else: + try: + translations = gettext.GNUTranslations(open(opts.merge, 'rb')) + except: + sys.stderr.write('Error: cannot open mo file %s\n' % opts.merge) + sys.exit(1) + translations.add_fallback(NoneTranslations()) + if opts.lang is None: + opts.lang = os.path.splitext(os.path.basename(opts.merge))[0] + if opts.output is None: + out = './' + elif os.path.isdir(opts.output): + out = opts.output + elif len(args) == 2: + if opts.output == '-': + out = sys.stdout + else: + out = file(opts.output, 'w') + else: + sys.stderr.write('Error: Non-directory output for multiple files\n') + sys.exit(1) + for filename in args[1:]: + messages = MessageList() + doc = Document(filename, messages) + doc.apply_its_rules() + if opts.itsfile is not None: + for itsfile in opts.itsfile: + doc.apply_its_file(itsfile) + doc.merge_translations(translations, opts.lang) + fout = out + if isinstance(fout, basestring): + fout = file(os.path.join(fout, os.path.basename(filename)), 'w') + fout.write(doc._doc.serialize('utf-8')) |