4 This class enables translation of Evergreen's fieldmapper IDL XML.
6 Requires polib from http://polib.googlecode.com
8 # Copyright 2007 Dan Scott <dscott@laurentian.ca>
10 # This program is free software; you can redistribute it and/or
11 # modify it under the terms of the GNU General Public License
12 # as published by the Free Software Foundation; either version 2
13 # of the License, or (at your option) any later version.
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
26 import xml.sax.handler
27 import xml.sax.saxutils
29 class IDL(basel10n.BaseL10N):
31 This class provides methods for extracting translatable strings from
32 Evergreen's fieldmapper IDL reporter:label attributes, generating a
33 translatable POT file, reading translated PO files, and generating
34 an updated fm_IDL.xml file with the additional language strings.
39 basel10n.BaseL10N.__init__(self)
43 def get_strings(self, source):
45 Extracts translatable strings from the reporter:label attributes
46 in Evergreen's fieldmapper IDL file.
50 locator = xml.sax.xmlreader.Locator()
51 parser = xml.sax.make_parser()
52 handler = IDLHandler()
53 handler.setDocumentLocator(locator)
54 parser.setContentHandler(handler)
57 for entity in handler.entities:
59 poe.occurrences = handler.entities[entity]
62 self.idl = handler.entityized
64 def create_entity(self):
66 Creates an entity definition file based on a translated PO file.
68 entity = '<!ENTITY %s %s>'
69 for entry in self.pot:
70 for name in entry.occurrences:
71 entdef = xml.sax.saxutils.quoteattr(entry.msgstr)
72 if entry.msgstr == '':
73 # No translation available; use the en-US definition
74 entdef = xml.sax.saxutils.quoteattr(entry.msgid)
75 self.definitions.append(entity % (name[0], entdef))
77 class IDLHandler(xml.sax.handler.ContentHandler):
79 Parses a fieldmapper IDL file to get at reporter:label and name attributes.
80 Generates a list of entity definitions and their values, as well as an
81 entity-ized version of the fieldmapper IDL.
85 xml.sax.handler.ContentHandler.__init__(self)
86 self.entities = dict()
88 self.entityized = u"""<?xml version="1.0" encoding="utf-8"?>
89 <!DOCTYPE fieldmapper [
90 <!--#include virtual="/opac/locale/${locale}/fm_IDL.dtd"-->
95 def setDocumentLocator(self, locator):
97 Override setDocumentLocator so we can track line numbers
99 self.locator = locator
101 def startElement(self, name, attributes):
103 Return the reporter:label or name attribute value for each class
104 field, or link element.
107 lineno = self.locator.getLineNumber()
109 self.classid = attributes['id']
110 if attributes.has_key('reporter:label'):
112 entity = "%s.%s.label" % (name, self.classid)
113 elif name == 'field':
114 entity = "%s.%s.%s.label" % (name, self.classid, \
117 entity = "%s.%s.%s.label" % (name, self.classid, \
119 label = attributes['reporter:label']
120 if not self.entities.has_key(label):
121 self.entities[label] = [(str(entity), lineno)]
123 self.entities[label].append((str(entity), lineno))
125 # Now we'll render an entity-ized version of this element
126 element = "<%s" % (name)
127 for att in attributes.keys():
128 # Replace reporter:label attribute values with entities
129 if att == 'reporter:label':
130 element = element + " %s='&%s;'" % (att, entity)
132 element = element + " %s='%s'" % (att, attributes[att])
134 # field and link elements are empty elements
135 if name == 'field' or name == 'link':
136 element = element + " />"
138 element = element + ">"
139 self.entityized = self.entityized + element
141 def characters(self, content):
143 Shove character data into the entityized IDL file
145 self.entityized = self.entityized + xml.sax.saxutils.escape(content)
147 def endElement(self, name):
149 field and link elements are empty elements
151 if name == 'field' or name == 'link':
154 self.entityized = self.entityized + "</%s>" % (name)
158 Determine what action to take
160 opts = optparse.OptionParser()
161 opts.add_option('-p', '--pot', action='store', \
162 help='Create a POT file from the specified fieldmapper IDL file', \
164 opts.add_option('-c', '--convert', action='store', \
165 help='Create a fieldmapper FILE that uses entities instead of text ' \
166 'strings for field labels and names', metavar='FILE')
167 opts.add_option('-e', '--entity', action='store', \
168 help='Create an entity definition from a translated PO FILE', \
170 opts.add_option('-o', '--output', dest='outfile', \
171 help='Write output to FILE (defaults to STDOUT)', metavar='FILE')
172 (options, args) = opts.parse_args()
175 # Generate a new POT file from the fieldmapper IDL
177 pot.get_strings(options.pot)
179 pot.savepot(options.outfile)
181 sys.stdout.write(pot.pot.__str__())
182 # Generate an entity file from a PO file
184 pot.loadpo(options.entity)
187 outfile = codecs.open(options.outfile, encoding='utf-8', mode='w')
188 for entity in pot.definitions:
189 outfile.write(entity + "\n")
191 for entity in pot.definitions:
193 # Generate an entity-ized fieldmapper IDL file
194 elif options.convert:
195 pot.get_strings(options.convert)
197 outfile = codecs.open(options.outfile, encoding='utf-8', mode='w')
198 outfile.write(pot.idl)
200 sys.stdout.write(pot.idl)
201 # No options were recognized - print help and bail
205 if __name__ == '__main__':