Avoid mouse-grabbing weirdness by calling script with python explicitly.
[Evergreen.git] / build / i18n / scripts / db-seed-i18n.py
1 #/usr/bin/env python
2 #
3 # Copyright 2007 Dan Scott <dscott@laurentian.ca>
4 #
5 # This class enables translation of Evergreen's seed database strings.
6 #
7 # Requires polib from http://polib.googlecode.com
8 #
9 # ####
10 #
11 # This program is free software; you can redistribute it and/or
12 # modify it under the terms of the GNU General Public License
13 # as published by the Free Software Foundation; either version 2
14 # of the License, or (at your option) any later version.
15 #
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 # GNU General Public License for more details.
20
21 import polib
22 import re
23 import time
24
25 class EvergreenSQL:
26     """
27     This class provides methods for extracting translatable strings from
28     Evergreen's database seed values, generating a translatable POT file,
29     reading translated PO files, and generating SQL for inserting the
30     translated values into the Evergreen database.
31     """
32
33     def getstrings(self, source):
34         """
35         Each INSERT statement contains a schema and tablename which we need to
36         insert into the config.i18n table. We'll push this into our
37         POEntry.occurences attribute.
38         
39         Each INSERT statement also contains 0 or more oils_i18n_gettext()
40         markers for the en-US string that we'll use for our msgid attribute.
41
42         A sample INSERT string that we'll scan is as follows:
43
44             INSERT INTO foo.bar (key, value) VALUES 
45                 (99, oils_i18n_gettext('string'));
46         """
47         date = time.strftime("%Y-%m-%d %H:%M:%S")
48         self.pot = polib.POFile()
49
50         # We should be smarter about the Project-Id-Version attribute
51         self.pot.metadata['Project-Id-Version'] = 'Evergreen 1.4'
52         self.pot.metadata['Report-Msgid-Bugs-To'] = 'open-ils-dev@list.georgialibraries.org'
53         # Cheat and hard-code the time zone offset
54         self.pot.metadata['POT-Creation-Date'] = "%s %s" % (date, '-0400')
55         self.pot.metadata['PO-Revision-Date'] = 'YEAR-MO-DA HO:MI+ZONE'
56         self.pot.metadata['Last-Translator'] = 'FULL NAME <EMAIL@ADDRESS>'
57         self.pot.metadata['Language-Team'] = 'LANGUAGE <LL@li.org>'
58         self.pot.metadata['MIME-Version'] = '1.0'
59         self.pot.metadata['Content-Type'] = 'text/plain; charset=utf-8'
60         self.pot.metadata['Content-Transfer-Encoding'] = '8-bit'
61
62         # table holds the fully-qualified table name (schema.table)
63         # The source SQL may use multi-row VALUES clauses for a single
64         # insert statement, so we need to remember the fq-table for
65         # multiple lines
66         table = ''
67         n = 1
68         findtable = re.compile(r'\s*INSERT\s+INTO\s+(\S+).*?$')
69         findi18n = re.compile(r'.*?oils_i18n_gettext\(\'(.+?)\'\)')
70
71         # Iterate through the source SQL grabbing table names and l10n strings
72         sourcefile = open(source)
73         for line in sourcefile:
74             ftable = findtable.search(line)
75             if ftable is not None:
76                 table = ftable.group(1)
77             fi18n = findi18n.search(line)
78             if fi18n is not None:
79                 for i18n in fi18n.groups():
80                     # Unescape escaped SQL single-quotes for translators' sanity
81                     i18n = re.compile(r'\'\'').sub("'", i18n)
82                     poe = polib.POEntry()
83                     poe.occurences = [(table, n)]
84                     poe.msgid = i18n
85                     self.pot.append(poe)
86             n = n + 1
87
88     def savepot(self, destination):
89         """
90         Saves the POT file to a specified file.
91         """
92         self.pot.save(destination)
93         
94     def loadpo(self, source):
95         """
96         Loads a translated PO file so we can generate the corresponding SQL.
97         """
98         self.pot = polib.pofile(source)
99
100     def createsql(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, translation, string) VALUES ('%s', '%s', '%s', '%s');"
107         self.sql = [] 
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 __str__(self):
119         """
120         Returns the PO representation of the strings.
121         """
122         return self.pot.__str__()
123  
124 if __name__ == '__main__':
125     pot = EvergreenSQL()
126     pot.getstrings('../../Open-ILS/src/sql/Pg/950.data.seed-values.sql')
127     pot.savepot('po/db.seed.pot')
128
129 #    test = EvergreenSQL()
130 #    test.loadpo('po/db.seed.pot')
131 #    test.createsql('fr-CA')
132 #    for insert in test.sql: 
133 #       print insert