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