]> git.lyx.org Git - lyx.git/blob - po/lyx_pot.py
653a359e59bb7a60ff71c87b299c57591404f077
[lyx.git] / po / lyx_pot.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 # file lyx_pot.py
5 # This file is part of LyX, the document processor.
6 # Licence details can be found in the file COPYING.
7 #
8 # \author Bo Peng
9 #
10 # Full author contact details are available in file CREDITS
11
12 # Usage: use
13 #     lyx_pot.py -h
14 # to get usage message
15
16 # This script will extract translatable strings from input files and write
17 # to output in gettext .pot format.
18 #
19 import sys, os, re, getopt
20
21 def relativePath(path, base):
22     '''return relative path from top source dir'''
23     # full pathname of path
24     path1 = os.path.normpath(os.path.realpath(path)).split(os.sep)
25     path2 = os.path.normpath(os.path.realpath(base)).split(os.sep)
26     if path1[:len(path2)] != path2:
27         print "Path %s is not under top source directory" % path
28     path3 = os.path.join(*path1[len(path2):]);
29     # replace all \ by / such that we get the same comments on Windows and *nix
30     path3 = path3.replace('\\', '/')
31     return path3
32
33
34 def ui_l10n(input_files, output, base):
35     '''Generate pot file from lib/ui/*'''
36     output = open(output, 'w')
37     Submenu = re.compile(r'^[^#]*Submenu\s+"([^"]*)"')
38     Popupmenu = re.compile(r'^[^#]*PopupMenu\s+"[^"]+"\s+"([^"]*)"')
39     Toolbar = re.compile(r'^[^#]*Toolbar\s+"[^"]+"\s+"([^"]*)"')
40     Item = re.compile(r'[^#]*Item\s+"([^"]*)"')
41     TableInsert = re.compile(r'[^#]*TableInsert\s+"([^"]*)"')
42     for src in input_files:
43         input = open(src)
44         for lineno, line in enumerate(input.readlines()):
45             if Submenu.match(line):
46                 (string,) = Submenu.match(line).groups()
47                 string = string.replace('_', ' ')
48             elif Popupmenu.match(line):
49                 (string,) = Popupmenu.match(line).groups()
50             elif Toolbar.match(line):
51                 (string,) = Toolbar.match(line).groups()
52             elif Item.match(line):
53                 (string,) = Item.match(line).groups()
54             elif TableInsert.match(line):
55                 (string,) = TableInsert.match(line).groups()
56             else:
57                 continue
58             string = string.replace('"', '')
59             if string != "":
60                 print >> output, '#: %s:%d\nmsgid "%s"\nmsgstr ""\n' % \
61                     (relativePath(src, base), lineno+1, string)
62         input.close()
63     output.close()
64
65
66 def writeString(outfile, infile, basefile, lineno, string):
67   string = string.replace('\\', '\\\\').replace('"', '')
68   if string == "":
69     return
70   print >> outfile, '#: %s:%d\nmsgid "%s"\nmsgstr ""\n' % \
71     (relativePath(infile, basefile), lineno, string)
72
73 def layouts_l10n(input_files, output, base):
74   '''Generate pot file from lib/layouts/*.{layout,inc,module}'''
75   out = open(output, 'w')
76   Style = re.compile(r'^Style\s+(.*)')
77   # include ???LabelString???, but exclude comment lines
78   LabelString = re.compile(r'^[^#]*LabelString\S*\s+(.*)')
79   GuiName = re.compile(r'\s*GuiName\s+(.*)')
80   ListName = re.compile(r'\s*ListName\s+(.*)')
81   NameRE = re.compile(r'DeclareLyXModule.*{(.*)}')
82   DescBegin = re.compile(r'#+\s*DescriptionBegin\s*$')
83   DescEnd   = re.compile(r'#+\s*DescriptionEnd\s*$')
84
85   for src in input_files:
86     readingDescription = False
87     descStartLine = -1
88     descLines = []
89     lineno = 0
90     for line in open(src).readlines():
91       lineno += 1
92       if readingDescription:
93         res = DescEnd.search(line)
94         if res != None:
95           readingDescription = False
96           desc = " ".join(descLines)
97           print >> out, '#: %s:%d\nmsgid "%s"\nmsgstr ""\n' % \
98             (relativePath(src, base), lineno + 1, desc)
99           continue
100         descLines.append(line[1:].strip())
101         continue
102       res = DescBegin.search(line)
103       if res != None:
104         readingDescription = True
105         descStartLine = lineno
106         continue
107       res = NameRE.search(line)
108       if res != None:
109         string = res.group(1)
110         string = string.replace('\\', '\\\\').replace('"', '')
111         if string != "":
112           print >> out, '#: %s:%d\nmsgid "%s"\nmsgstr ""\n' % \
113             (relativePath(src, base), lineno + 1, string)
114         continue
115       res = Style.search(line)
116       if res != None:
117         string = res.group(1)
118         string = string.replace('_', ' ')
119         writeString(out, src, base, lineno, string)
120         continue
121       res = LabelString.search(line)
122       if res != None:
123         string = res.group(1)
124         writeString(out, src, base, lineno, string)
125         continue
126       res = GuiName.search(line)
127       if res != None:
128         string = res.group(1)
129         writeString(out, src, base, lineno, string)
130         continue
131       res = ListName.search(line)
132       if res != None:
133         string = res.group(1)
134         writeString(out, src, base, lineno, string)
135         continue
136   out.close()
137
138
139 def qt4_l10n(input_files, output, base):
140     '''Generate pot file from src/frontends/qt4/ui/*.ui'''
141     output = open(output, 'w')
142     pat = re.compile(r'\s*<string>(.*)</string>')
143     prop = re.compile(r'\s*<property.*name.*=.*shortcut')
144     for src in input_files:
145         input = open(src)
146         skipNextLine = False
147         for lineno, line in enumerate(input.readlines()):
148             # skip the line after <property name=shortcut>
149             if skipNextLine:
150                 skipNextLine = False
151                 continue
152             if prop.match(line):
153                 skipNextLine = True
154                 continue
155             # get lines that match <string>...</string>
156             if pat.match(line):
157                 (string,) = pat.match(line).groups()
158                 string = string.replace('&amp;', '&').replace('&lt;', '<').replace('&gt;', '>').replace('"', r'\"')
159                 print >> output, '#: %s:%d\nmsgid "%s"\nmsgstr ""\n' % \
160                     (relativePath(src, base), lineno+1, string) 
161         input.close()
162     output.close()
163
164
165 def languages_l10n(input_files, output, base):
166     '''Generate pot file from lib/language'''
167     output = open(output, 'w')
168     # assuming only one language file
169     reg = re.compile('[\w-]+\s+[\w"]+\s+"([\w \-\(\)]+)"\s+(true|false)\s+[\w-]+\s+\w+\s+"[^"]*"')
170     input = open(input_files[0])
171     for lineno, line in enumerate(input.readlines()):
172         if line[0] == '#':
173             continue
174         # From:
175         #   afrikaans   afrikaans       "Afrikaans"     false  iso8859-15 af_ZA  ""
176         # To:
177         #   #: lib/languages:2
178         #   msgid "Afrikaans"
179         #   msgstr ""
180         if reg.match(line):
181             print >> output, '#: %s:%d\nmsgid "%s"\nmsgstr ""\n' % \
182                 (relativePath(input_files[0], base), lineno+1, reg.match(line).groups()[0])
183         else:
184             print "Error: Unable to handle line:"
185             print line
186             sys.exit(1)
187     input.close()
188     output.close()
189
190
191 def external_l10n(input_files, output, base):
192     '''Generate pot file from lib/external_templates'''
193     output = open(output, 'w')
194     Template = re.compile(r'^Template\s+(.*)')
195     GuiName = re.compile(r'\s*GuiName\s+(.*)')
196     HelpTextStart = re.compile(r'\s*HelpText\s')
197     HelpTextSection = re.compile(r'\s*(\S.*)\s*$')
198     HelpTextEnd = re.compile(r'\s*HelpTextEnd\s')
199     i = -1
200     for src in input_files:
201         input = open(src)
202         inHelp = False
203         hadHelp = False
204         prev_help_string = ''
205         for lineno, line in enumerate(input.readlines()):
206             if Template.match(line):
207                 (string,) = Template.match(line).groups()
208             elif GuiName.match(line):
209                 (string,) = GuiName.match(line).groups()
210             elif inHelp:
211                 if HelpTextEnd.match(line):
212                     if hadHelp:
213                         print >> output, '\nmsgstr ""\n'
214                     inHelp = False
215                     hadHelp = False
216                     prev_help_string = ''
217                 elif HelpTextSection.match(line):
218                     (help_string,) = HelpTextSection.match(line).groups()
219                     help_string = help_string.replace('"', '')
220                     if help_string != "" and prev_help_string == '':
221                         print >> output, '#: %s:%d\nmsgid ""\n"%s\\n"' % \
222                             (relativePath(src, base), lineno+1, help_string)
223                         hadHelp = True
224                     elif help_string != "":
225                         print >> output, '"%s\\n"' % help_string
226                     prev_help_string = help_string
227             elif HelpTextStart.match(line):
228                 inHelp = True
229                 prev_help_string = ''
230             else:
231                 continue
232             string = string.replace('"', '')
233             if string != "" and not inHelp:
234                 print >> output, '#: %s:%d\nmsgid "%s"\nmsgstr ""\n' % \
235                     (relativePath(src, base), lineno+1, string)
236         input.close()
237     output.close()
238
239
240 Usage = '''
241 lyx_pot.py [-b|--base top_src_dir] [-o|--output output_file] [-h|--help] -t|--type input_type input_files
242
243 where 
244     --base:
245         path to the top source directory. default to '.'
246     --output:
247         output pot file, default to './lyx.pot'
248     --input_type can be
249         ui: lib/ui/*
250         layouts: lib/layouts/*
251         qt4: qt4 ui files
252         languages: file lib/languages
253         external: external templates file
254 '''
255
256 if __name__ == '__main__':
257     input_type = None
258     output = 'lyx.pot'
259     base = '.'
260     #
261     optlist, args = getopt.getopt(sys.argv[1:], 'ht:o:b:',
262         ['help', 'type=', 'output=', 'base='])
263     for (opt, value) in optlist:
264         if opt in ['-h', '--help']:
265             print Usage
266             sys.exit(0)
267         elif opt in ['-o', '--output']:
268             output = value
269         elif opt in ['-b', '--base']:
270             base = value
271         elif opt in ['-t', '--type']:
272             input_type = value
273     if input_type not in ['ui', 'layouts', 'modules', 'qt4', 'languages', 'external'] or output is None:
274         print 'Wrong input type or output filename.'
275         sys.exit(1)
276     if input_type == 'ui':
277         ui_l10n(args, output, base)
278     elif input_type == 'layouts':
279         layouts_l10n(args, output, base)
280     elif input_type == 'qt4':
281         qt4_l10n(args, output, base)
282     elif input_type == 'external':
283         external_l10n(args, output, base)
284     else:
285         languages_l10n(args, output, base)
286