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
28 class IDL(basel10n.BaseL10N):
30 This class provides methods for extracting translatable strings from
31 Evergreen's fieldmapper IDL reporter:label attributes, generating a
32 translatable POT file, reading translated PO files, and generating
33 an updated fm_IDL.xml file with the additional language strings.
38 basel10n.BaseL10N.__init__(self)
42 def get_strings(self, source):
44 Extracts translatable strings from the reporter:label attributes
45 in Evergreen's fieldmapper IDL file.
49 locator = xml.sax.xmlreader.Locator()
50 parser = xml.sax.make_parser()
51 handler = IDLHandler()
52 handler.setDocumentLocator(locator)
53 parser.setContentHandler(handler)
56 for entity in handler.entities:
58 poe.occurrences = handler.entities[entity]
61 self.idl = handler.entityized
63 def create_entity(self):
65 Creates an entity definition file based on a translated PO file.
67 entity = '<!ENTITY %s "%s">'
68 for entry in self.pot:
69 for name in entry.occurrences:
70 if entry.msgstr == '':
71 # No translation available; use the en-US definition
72 self.definitions.append(unicode(entity % (name[0], entry.msgid), 'utf_8'))
74 self.definitions.append(unicode(entity % (name[0], entry.msgstr), 'utf_8'))
76 class IDLHandler(xml.sax.handler.ContentHandler):
78 Parses a fieldmapper IDL file to get at reporter:label and name attributes.
79 Generates a list of entity definitions and their values, as well as an
80 entity-ized version of the fieldmapper IDL.
84 xml.sax.handler.ContentHandler.__init__(self)
85 self.entities = dict()
87 self.entityized = u"""<?xml version="1.0" encoding="utf-8"?>
88 <!DOCTYPE fieldmapper [
89 <!--#include virtual="/opac/locale/${locale}/fm_IDL.dtd"-->
94 def setDocumentLocator(self, locator):
96 Override setDocumentLocator so we can track line numbers
98 self.locator = locator
100 def startElement(self, name, attributes):
102 Return the reporter:label or name attribute value for each class
103 field, or link element.
106 lineno = self.locator.getLineNumber()
108 self.classid = attributes['id']
109 if attributes.has_key('reporter:label'):
111 entity = "%s.%s.label" % (name, self.classid)
112 elif name == 'field':
113 entity = "%s.%s.%s.label" % (name, self.classid, \
116 entity = "%s.%s.%s.label" % (name, self.classid, \
118 label = attributes['reporter:label']
119 if not self.entities.has_key(label):
120 self.entities[label] = [(str(entity), lineno)]
122 self.entities[label].append((str(entity), lineno))
124 # Now we'll render an entity-ized version of this element
125 element = "<%s" % (name)
126 for att in attributes.keys():
127 # Replace reporter:label attribute values with entities
128 if att == 'reporter:label':
129 element = element + " %s='&%s;'" % (att, entity)
131 element = element + " %s='%s'" % (att, attributes[att])
133 # field and link elements are empty elements
134 if name == 'field' or name == 'link':
135 element = element + " />"
137 element = element + ">"
138 self.entityized = self.entityized + element
140 def characters(self, content):
142 Shove character data into the entityized IDL file
144 self.entityized = self.entityized + xml.sax.saxutils.escape(content)
146 def endElement(self, name):
148 field and link elements are empty elements
150 if name == 'field' or name == 'link':
153 self.entityized = self.entityized + "</%s>" % (name)
157 Determine what action to take
159 opts = optparse.OptionParser()
160 opts.add_option('-p', '--pot', action='store', \
161 help='Create a POT file from the specified fieldmapper IDL file', \
163 opts.add_option('-c', '--convert', action='store', \
164 help='Create a fieldmapper FILE that uses entities instead of text ' \
165 'strings for field labels and names', metavar='FILE')
166 opts.add_option('-e', '--entity', action='store', \
167 help='Create an entity definition from a translated PO FILE', \
169 opts.add_option('-o', '--output', dest='outfile', \
170 help='Write output to FILE (defaults to STDOUT)', metavar='FILE')
171 (options, args) = opts.parse_args()
174 # Generate a new POT file from the fieldmapper IDL
176 pot.get_strings(options.pot)
178 pot.savepot(options.outfile)
180 sys.stdout.write(pot.pot.__str__())
181 # Generate an entity file from a PO file
183 pot.loadpo(options.entity)
186 outfile = codecs.open(options.outfile, encoding='utf-8', mode='w')
187 for entity in pot.definitions:
188 outfile.write(entity + "\n")
190 for entity in pot.definitions:
192 # Generate an entity-ized fieldmapper IDL file
193 elif options.convert:
194 pot.get_strings(options.convert)
196 outfile = codecs.open(options.outfile, encoding='utf-8', mode='w')
197 outfile.write(pot.idl)
199 sys.stdout.write(pot.idl)
200 # No options were recognized - print help and bail
204 if __name__ == '__main__':