4 This class enables translation of Evergreen's seed database strings.
6 Requires polib from http://polib.googlecode.com
8 # Copyright 2007-2008 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 class SQL(basel10n.BaseL10N):
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.
36 basel10n.BaseL10N.__init__(self)
39 def getstrings(self, source):
41 Each INSERT statement contains 0 or more oils_i18n_gettext()
42 markers for the en-US string that identify the string (which
43 we push into the POEntry.occurrences attribute), class hint,
44 and property. We concatenate the class hint and property and
45 use that for our msgid attribute.
47 A sample INSERT string that we'll scan is as follows:
49 INSERT INTO foo.bar (key, value) VALUES
50 (99, oils_i18n_gettext(99, 'string', 'class hint', 'property'));
55 findi18n = re.compile(r'.*?oils_i18n_gettext\((.*?)\'\)')
56 intkey = re.compile(r'\s*(?P<id>\d+),\s*\'(?P<string>.+?)\',\s*\'(?P<class>.+?)\',\s*\'(?P<property>.+?)$')
57 textkey = re.compile(r'\s*\'(?P<id>.*?)\',\s*\'(?P<string>.+?)\',\s*\'(?P<class>.+?)\',\s*\'(?P<property>.+?)$')
60 # Iterate through the source SQL grabbing table names and l10n strings
61 sourcefile = open(source)
62 for line in sourcefile:
65 entry = findi18n.search(line)
68 for parms in entry.groups():
69 # Try for an integer-based primary key parameter first
70 fi18n = intkey.search(parms)
72 # Otherwise, it must be a text-based primary key parameter
73 fi18n = textkey.search(parms)
74 fq_field = "%s.%s" % (fi18n.group('class'), fi18n.group('property'))
75 # Unescape escaped SQL single-quotes for translators' sanity
76 msgid = re.compile(r'\'\'').sub("'", fi18n.group('string'))
78 # Hmm, sometimes people use ":" in text identifiers and
79 # polib doesn't seem to like that; urlencode the colon
80 occurid = re.compile(r':').sub("%3A", fi18n.group('id'))
83 serts[msgid].occurrences.append((fq_field, occurid))
86 poe.occurrences = [(fq_field, occurid)]
90 print "Error in line %d of SQL source file" % (num)
92 for poe in serts.values():
95 def create_sql(self, locale):
97 Creates a set of INSERT statements that place translated strings
98 into the config.i18n_core table.
101 insert = "INSERT INTO config.i18n_core (fq_field, identity_value," \
102 " translation, string) VALUES ('%s', '%s', '%s', '%s');"
103 for entry in self.pot:
104 for fq_field in entry.occurrences:
105 # Escape SQL single-quotes to avoid b0rkage
106 msgstr = re.compile(r'\'').sub("''", entry.msgstr)
108 # And unescape any colons in the occurence ID
109 occurid = re.compile(r'%3A').sub(':', fq_field[1])
112 # Don't generate a stmt for an untranslated string
114 self.sql.append(insert % (fq_field[0], occurid, locale, msgstr))
118 Determine what action to take
120 opts = optparse.OptionParser()
121 opts.add_option('-p', '--pot', action='store', \
122 help='Generate POT from the specified source SQL file', metavar='FILE')
123 opts.add_option('-s', '--sql', action='store', \
124 help='Generate SQL from the specified source POT file', metavar='FILE')
125 opts.add_option('-l', '--locale', \
126 help='Locale of the SQL file that will be generated')
127 opts.add_option('-o', '--output', dest='outfile', \
128 help='Write output to FILE (defaults to STDOUT)', metavar='FILE')
129 (options, args) = opts.parse_args()
133 pot.getstrings(options.pot)
135 pot.savepot(options.outfile)
137 sys.stdout.write(pot.pot.__str__())
139 if not options.locale:
140 opts.error('Must specify an output locale')
142 pot.loadpo(options.sql)
143 pot.create_sql(options.locale)
144 if not options.outfile:
147 outfile = open(options.outfile, 'w')
148 for insert in pot.sql:
149 outfile.write(insert + "\n")
153 if __name__ == '__main__':