]> git.evergreen-ils.org Git - working/Evergreen.git/blob - build/i18n/scripts/fieldmapper.py
Add a quick Dojo resource bundle <-> POT roundtripping script
[working/Evergreen.git] / build / i18n / scripts / fieldmapper.py
1 #!/usr/bin/env python
2 # fieldmapper.py
3 """
4 This class enables translation of Evergreen's fieldmapper IDL XML.
5
6 Requires polib from http://polib.googlecode.com
7 """
8 # Copyright 2007 Dan Scott <dscott@laurentian.ca>
9 #
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.
14 #
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.
19
20 import basel10n
21 import optparse
22 import polib
23 import sys
24 import xml.sax
25 import xml.sax.handler
26
27 class IDL(basel10n.BaseL10N):
28     """
29     This class provides methods for extracting translatable strings from
30     Evergreen's fieldmapper IDL reporter:label attributes, generating a
31     translatable POT file, reading translated PO files, and generating
32     an updated fm_IDL.xml file with the additional language strings.
33     """
34
35     def __init__(self):
36         self.pot = None
37         basel10n.BaseL10N.__init__(self)
38         self.idl = ''
39         self.definitions = []
40
41     def get_strings(self, source):
42         """
43         Extracts translatable strings from the reporter:label attributes
44         in Evergreen's fieldmapper IDL file.
45         """
46         self.pothead()
47
48         locator = xml.sax.xmlreader.Locator()
49         parser = xml.sax.make_parser()
50         handler = IDLHandler()
51         handler.setDocumentLocator(locator)
52         parser.setContentHandler(handler)
53         parser.parse(source)
54
55         for entity in handler.entities:
56             poe = polib.POEntry()
57             poe.occurrences = handler.entities[entity]
58             poe.msgid = entity
59             self.pot.append(poe)
60         self.idl = handler.entityized
61
62     def create_entity(self):
63         """
64         Creates an entity definition file based on a translated PO file.
65         """
66         entity = '<!ENTITY %s "%s">'
67         for entry in self.pot:
68             for name in entry.occurrences:
69                 if entry.msgstr == '':
70                     # No translation available; use the en-US definition
71                     self.definitions.append(entity % (name[0], entry.msgid))
72                 else:
73                     self.definitions.append(entity % (name[0], entry.msgstr))
74
75 class IDLHandler(xml.sax.handler.ContentHandler):
76     """
77     Parses a fieldmapper IDL file to get at reporter:label and name attributes.
78     Generates a list of entity definitions and their values, as well as an
79     entity-ized version of the fieldmapper IDL.
80     """
81
82     def __init__(self):
83         xml.sax.handler.ContentHandler.__init__(self)
84         self.entities = dict()
85         self.classid = None
86         self.entityized = u"""<?xml version="1.0" encoding="utf-8"?>
87 <!DOCTYPE fieldmapper [
88     <!--#include virtual="/opac/locale/${locale}/fm_IDL.dtd"--> 
89 ]>
90 """
91         self.locator = None
92
93     def setDocumentLocator(self, locator):
94         """
95         Override setDocumentLocator so we can track line numbers
96         """
97         self.locator = locator
98
99     def startElement(self, name, attributes):
100         """
101         Return the reporter:label or name attribute value for each class
102         or field element.
103         """
104         entity = None
105         lineno = self.locator.getLineNumber()
106         if name == 'class':
107             self.classid = attributes['id']
108         if attributes.has_key('reporter:label'):
109             if name == 'class':
110                 entity = "%s.%s.label" % (name, self.classid)
111             elif name == 'field':
112                 entity = "%s.%s.%s.label" % (name, self.classid, \
113                     attributes['name'])
114             label = attributes['reporter:label']
115             if not self.entities.has_key(label):
116                 self.entities[label] = [(str(entity), lineno)]
117             else:
118                 self.entities[label].append((str(entity), lineno))
119
120         # Now we'll render an entity-ized version of this element
121         element = "<%s" % (name)
122         for att in attributes.keys():
123             # Replace reporter:label attribute values with entities
124             if att == 'reporter:label':
125                 element = element + " %s='&%s;'" % (att, entity) 
126             else:
127                 element = element + " %s='%s'" % (att, attributes[att])
128
129         # field and link elements are empty elements
130         if name == 'field' or name == 'link':
131             element = element + " />"
132         else:
133             element = element + ">"
134         self.entityized = self.entityized + element
135
136     def characters(self, content):
137         """
138         Shove character data into the entityized IDL file
139         """
140         self.entityized = self.entityized + xml.sax.saxutils.escape(content)
141
142     def endElement(self, name):
143         """
144         field and link elements are empty elements
145         """
146         if name == 'field' or name == 'link':
147             pass
148         else:
149             self.entityized = self.entityized + "</%s>" % (name)
150
151 def main():
152     """
153     Determine what action to take
154     """
155     opts = optparse.OptionParser()
156     opts.add_option('-p', '--pot', action='store', \
157         help='Create a POT file from the specified fieldmapper IDL file', \
158         metavar='FILE')
159     opts.add_option('-c', '--convert', action='store', \
160         help='Create a fieldmapper FILE that uses entities instead of text ' \
161         'strings for field labels and names', metavar='FILE')
162     opts.add_option('-e', '--entity', action='store', \
163         help='Create an entity definition from a translated PO FILE', \
164         metavar='FILE')
165     opts.add_option('-o', '--output', dest='outfile', \
166         help='Write output to FILE (defaults to STDOUT)', metavar='FILE')
167     (options, args) = opts.parse_args()
168
169     pot = IDL()
170     # Generate a new POT file from the fieldmapper IDL
171     if options.pot:
172         pot.get_strings(options.pot)
173         if options.outfile:
174             pot.savepot(options.outfile)
175         else:
176             sys.stdout.write(pot.pot.__str__())
177     # Generate an entity file from a PO file
178     elif options.entity:
179         pot.loadpo(options.entity)
180         pot.create_entity()
181         if options.outfile:
182             outfile = open(options.outfile, 'w')
183             for entity in pot.definitions: 
184                 outfile.write(entity + "\n")
185         else:
186             for entity in pot.definitions:
187                 print(entity)
188     # Generate an entity-ized fieldmapper IDL file
189     elif options.convert:
190         pot.get_strings(options.convert)
191         if options.outfile:
192             outfile = open(options.outfile, 'w')
193             outfile.write(pot.idl)
194         else:
195             sys.stdout.write(pot.idl)
196     # No options were recognized - print help and bail
197     else:
198         opts.print_help()
199
200 if __name__ == '__main__':
201     main()