]> git.evergreen-ils.org Git - working/Evergreen.git/blob - build/i18n/scripts/db-seed-i18n.py
Make unit tests less fragile.
[working/Evergreen.git] / build / i18n / scripts / db-seed-i18n.py
1 #!/usr/bin/env python
2 #
3 """
4 This class enables translation of Evergreen's seed database strings.
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 re
24 import sys
25
26 class SQL(basel10n.BaseL10N):
27     """
28     This class provides methods for extracting translatable strings from
29     Evergreen's database seed values, generating a translatable POT file,
30     reading translated PO files, and generating SQL for inserting the
31     translated values into the Evergreen database.
32     """
33
34     def __init__(self):
35         self.pot = None
36         basel10n.BaseL10N.__init__(self)
37         self.sql = []
38
39     def loadpo(self, potfile):
40         """
41         Load a POT file
42         """
43         basel10n.BaseL10N.loadpo(self, potfile)
44
45     def pothead(self):
46         """
47         Initialize POT metadata
48         """
49         basel10n.BaseL10N.pothead(self)
50
51     def savepot(self, outfile):
52         """
53         Write a POT file
54         """
55         basel10n.BaseL10N.savepot(self, outfile)
56
57     def getstrings(self, source):
58         """
59         Each INSERT statement contains a schema and tablename which we need to
60         insert into the config.i18n table. We'll push this into our
61         POEntry.occurences attribute.
62         
63         Each INSERT statement also contains 0 or more oils_i18n_gettext()
64         markers for the en-US string that we'll use for our msgid attribute.
65
66         A sample INSERT string that we'll scan is as follows:
67
68             INSERT INTO foo.bar (key, value) VALUES 
69                 (99, oils_i18n_gettext('string'));
70         """
71         self.pothead()
72
73         # table holds the fully-qualified table name (schema.table)
74         # The source SQL may use multi-row VALUES clauses for a single
75         # insert statement, so we need to remember the fq-table for
76         # multiple lines
77         table = ''
78         num = 1
79         findtable = re.compile(r'\s*INSERT\s+INTO\s+(\S+).*?$')
80         findi18n = re.compile(r'.*?oils_i18n_gettext\(\'(.+?)\'\)')
81
82         # Iterate through the source SQL grabbing table names and l10n strings
83         sourcefile = open(source)
84         for line in sourcefile:
85             ftable = findtable.search(line)
86             if ftable is not None:
87                 table = ftable.group(1)
88             fi18n = findi18n.search(line)
89             if fi18n is not None:
90                 for i18n in fi18n.groups():
91                     # Unescape escaped SQL single-quotes for translators' sanity
92                     i18n = re.compile(r'\'\'').sub("'", i18n)
93                     if i18n is not None:
94                         poe = polib.POEntry()
95                         poe.occurences = [(table, num)]
96                         poe.msgid = i18n
97                         self.pot.append(poe)
98             num = num + 1
99
100     def create_sql(self, locale):
101         """
102         Creates a set of INSERT statements that place translated strings
103         into the config.i18n_core table.
104         """
105
106         insert = "INSERT INTO config.i18n_core (fq_field, identity_value," \
107             " translation, string) VALUES ('%s', '%s', '%s', '%s');"
108         for entry in self.pot:
109             for table in entry.occurences:
110                 # Escape SQL single-quotes to avoid b0rkage
111                 msgid = re.compile(r'\'').sub("''", entry.msgid)
112                 msgstr = re.compile(r'\'').sub("''", entry.msgstr)
113                 if msgstr == '':
114                     # Don't generate a stmt for an untranslated string
115                     break
116                 self.sql.append(insert % (table[0], msgid, locale, msgstr))
117
118 def main():
119     """
120     Determine what action to take
121     """
122     opts = optparse.OptionParser()
123     opts.add_option('-p', '--pot', action='store', \
124         help='Generate POT from the specified source SQL file', metavar='FILE')
125     opts.add_option('-s', '--sql', action='store', \
126         help='Generate SQL from the specified source POT file', metavar='FILE')
127     opts.add_option('-l', '--locale', \
128         help='Locale of the SQL file that will be generated')
129     opts.add_option('-o', '--output', dest='outfile', \
130         help='Write output to FILE (defaults to STDOUT)', metavar='FILE')
131     (options, args) = opts.parse_args()
132
133     if options.pot:
134         pot = SQL()
135         pot.getstrings(options.pot)
136         if options.outfile:
137             pot.savepot(options.outfile)
138         else:
139             sys.stdout.write(pot.pot.__str__())
140     elif options.sql:
141         if not options.locale:
142             opts.error('Must specify an output locale')
143         pot = SQL()
144         pot.loadpo(options.sql)
145         pot.create_sql(options.locale)
146         if not options.outfile:
147             outfile = sys.stdout
148         else:
149             outfile = open(options.outfile, 'w')
150         for insert in pot.sql: 
151             outfile.write(insert + "\n")
152     else:
153         opts.print_help()
154
155 if __name__ == '__main__':
156     main()