]> git.lyx.org Git - lyx.git/blob - po/lyx_pot.py
Merge branch 'master' into biblatex2
[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 from __future__ import print_function
20
21 import sys, os, re, getopt
22 import io
23
24 def relativePath(path, base):
25     '''return relative path from top source dir'''
26     # full pathname of path
27     path1 = os.path.normpath(os.path.realpath(path)).split(os.sep)
28     path2 = os.path.normpath(os.path.realpath(base)).split(os.sep)
29     if path1[:len(path2)] != path2:
30         print("Path %s is not under top source directory" % path)
31     path3 = os.path.join(*path1[len(path2):]);
32     # replace all \ by / such that we get the same comments on Windows and *nix
33     path3 = path3.replace('\\', '/')
34     return path3
35
36
37 def writeString(outfile, infile, basefile, lineno, string):
38     string = string.replace('\\', '\\\\').replace('"', '')
39     if string == "":
40         return
41     print(u'#: %s:%d\nmsgid "%s"\nmsgstr ""\n' % \
42         (relativePath(infile, basefile), lineno, string), file=outfile)
43
44
45 def ui_l10n(input_files, output, base):
46     '''Generate pot file from lib/ui/*'''
47     output = io.open(output, 'w', encoding='utf_8', newline='\n')
48     Submenu = re.compile(r'^[^#]*Submenu\s+"([^"]*)"', re.IGNORECASE)
49     Popupmenu = re.compile(r'^[^#]*PopupMenu\s+"[^"]+"\s+"([^"]*)"', re.IGNORECASE)
50     IconPalette = re.compile(r'^[^#]*IconPalette\s+"[^"]+"\s+"([^"]*)"', re.IGNORECASE)
51     Toolbar = re.compile(r'^[^#]*Toolbar\s+"[^"]+"\s+"([^"]*)"', re.IGNORECASE)
52     Item = re.compile(r'[^#]*Item\s+"([^"]*)"', re.IGNORECASE)
53     TableInsert = re.compile(r'[^#]*TableInsert\s+"([^"]*)"', re.IGNORECASE)
54     for src in input_files:
55         input = io.open(src, encoding='utf_8')
56         for lineno, line in enumerate(input.readlines()):
57             if Submenu.match(line):
58                 (string,) = Submenu.match(line).groups()
59                 string = string.replace('_', ' ')
60             elif Popupmenu.match(line):
61                 (string,) = Popupmenu.match(line).groups()
62             elif IconPalette.match(line):
63                 (string,) = IconPalette.match(line).groups()
64             elif Toolbar.match(line):
65                 (string,) = Toolbar.match(line).groups()
66             elif Item.match(line):
67                 (string,) = Item.match(line).groups()
68             elif TableInsert.match(line):
69                 (string,) = TableInsert.match(line).groups()
70             else:
71                 continue
72             string = string.replace('"', '')
73             if string != "":
74                 print(u'#: %s:%d\nmsgid "%s"\nmsgstr ""\n' % \
75                     (relativePath(src, base), lineno+1, string), file=output)
76         input.close()
77     output.close()
78
79
80 def layouts_l10n(input_files, output, base, layouttranslations):
81     '''Generate pot file from lib/layouts/*.{layout,inc,module}'''
82     ClassDescription = re.compile(r'^\s*#\s*\\Declare(LaTeX|DocBook)Class.*\{(.*)\}$', re.IGNORECASE)
83     ClassCategory = re.compile(r'^\s*#\s*\\DeclareCategory\{(.*)\}$', re.IGNORECASE)
84     Style = re.compile(r'^\s*Style\s+(.*\S)\s*$', re.IGNORECASE)
85     # match LabelString, EndLabelString, LabelStringAppendix and maybe others but no comments
86     LabelString = re.compile(r'^[^#]*LabelString\S*\s+(.*\S)\s*$', re.IGNORECASE)
87     MenuString = re.compile(r'^[^#]*MenuString\S*\s+(.*\S)\s*$', re.IGNORECASE)
88     OutlinerName = re.compile(r'^[^#]*OutlinerName\s+(\S+|\"[^\"]*\")\s+(\S+|\"[^\"]*\")\s*$', re.IGNORECASE)
89     Tooltip = re.compile(r'^\s*Tooltip\S*\s+(.*\S)\s*$', re.IGNORECASE)
90     GuiName = re.compile(r'^\s*GuiName\s+(.*\S)\s*$', re.IGNORECASE)
91     ListName = re.compile(r'^\s*ListName\s+(.*\S)\s*$', re.IGNORECASE)
92     CategoryName = re.compile(r'^\s*Category\s+(.*\S)\s*$', re.IGNORECASE)
93     NameRE = re.compile(r'^\s*#\s*\\DeclareLyXModule.*{(.*)}$', re.IGNORECASE)
94     CiteNameRE = re.compile(r'^\s*#\s*\\DeclareLyXCiteEngine.*{(.*)}$', re.IGNORECASE)
95     InsetLayout = re.compile(r'^InsetLayout\s+\"?(.*)\"?\s*$', re.IGNORECASE)
96     FlexCheck = re.compile(r'^Flex:(.*)', re.IGNORECASE)
97     CaptionCheck = re.compile(r'^Caption:(.*)', re.IGNORECASE)
98     DescBegin = re.compile(r'^\s*#DescriptionBegin\s*$', re.IGNORECASE)
99     DescEnd = re.compile(r'^\s*#\s*DescriptionEnd\s*$', re.IGNORECASE)
100     Category = re.compile(r'^\s*#\s*Category:\s+(.*\S)\s*$', re.IGNORECASE)
101     I18nPreamble = re.compile(r'^\s*((Lang)|(Babel))Preamble\s*$', re.IGNORECASE)
102     EndI18nPreamble = re.compile(r'^\s*End((Lang)|(Babel))Preamble\s*$', re.IGNORECASE)
103     I18nString = re.compile(r'_\(([^\)]+)\)')
104     CounterFormat = re.compile(r'^\s*PrettyFormat\s+"?(.*)"?\s*$', re.IGNORECASE)
105     CiteFormat = re.compile(r'^\s*CiteFormat', re.IGNORECASE)
106     KeyVal = re.compile(r'^\s*_\w+\s+(.*\S)\s*$')
107     Float = re.compile(r'^\s*Float\s*$', re.IGNORECASE)
108     UsesFloatPkg = re.compile(r'^\s*UsesFloatPkg\s+(.*\S)\s*$', re.IGNORECASE)
109     IsPredefined = re.compile(r'^\s*IsPredefined\s+(.*\S)\s*$', re.IGNORECASE)
110     End = re.compile(r'^\s*End', re.IGNORECASE)
111     Comment = re.compile(r'^(.*)#')
112     Translation = re.compile(r'^\s*Translation\s+(.*\S)\s*$', re.IGNORECASE)
113     KeyValPair = re.compile(r'\s*"(.*)"\s+"(.*)"')
114
115     oldlanguages = []
116     languages = []
117     keyset = set()
118     oldtrans = dict()
119     if layouttranslations:
120         linguas_file = os.path.join(base, 'po/LINGUAS')
121         for line in open(linguas_file).readlines():
122             res = Comment.search(line)
123             if res:
124                 line = res.group(1)
125             if line.strip() != '':
126                 languages.extend(line.split())
127
128         # read old translations if available
129         try:
130             input = io.open(output, encoding='utf_8')
131             lang = ''
132             for line in input.readlines():
133                 res = Comment.search(line)
134                 if res:
135                     line = res.group(1)
136                 if line.strip() == '':
137                     continue
138                 res = Translation.search(line)
139                 if res:
140                     lang = res.group(1)
141                     if lang not in languages:
142                         oldlanguages.append(lang)
143                         languages.append(lang)
144                     oldtrans[lang] = dict()
145                     continue
146                 res = End.search(line)
147                 if res:
148                     lang = ''
149                     continue
150                 res = KeyValPair.search(line)
151                 if res and lang != '':
152                     key = res.group(1)
153                     val = res.group(2)
154                     key = key.replace('\\"', '"').replace('\\\\', '\\')
155                     val = val.replace('\\"', '"').replace('\\\\', '\\')
156                     oldtrans[lang][key] = val
157                     keyset.add(key)
158                     continue
159                 print("Error: Unable to handle line:")
160                 print(line)
161         except IOError:
162             print("Warning: Unable to open %s for reading." % output)
163             print("         Old translations will be lost.")
164
165         # walon is not a known document language
166         # FIXME: Do not hardcode, read from lib/languages!
167         if 'wa' in languages:
168             languages.remove('wa')
169
170     if layouttranslations:
171         out = io.open(output, 'w', encoding='utf_8')
172     else:
173         out = io.open(output, 'w', encoding='utf_8', newline='\n')
174     for src in input_files:
175         readingDescription = False
176         readingI18nPreamble = False
177         readingFloat = False
178         readingCiteFormats = False
179         isPredefined = False
180         usesFloatPkg = True
181         listname = ''
182         floatname = ''
183         descStartLine = -1
184         descLines = []
185         lineno = 0
186         for line in io.open(src, encoding='utf_8').readlines():
187             lineno += 1
188             res = ClassDescription.search(line)
189             if res != None:
190                 string = res.group(2)
191                 if not layouttranslations:
192                     writeString(out, src, base, lineno + 1, string)
193                 continue
194             res = ClassCategory.search(line)
195             if res != None:
196                 string = res.group(1)
197                 if not layouttranslations:
198                     writeString(out, src, base, lineno + 1, string)
199                 continue
200             if readingDescription:
201                 res = DescEnd.search(line)
202                 if res != None:
203                     readingDescription = False
204                     desc = " ".join(descLines)
205                     if not layouttranslations:
206                         writeString(out, src, base, lineno + 1, desc)
207                     continue
208                 descLines.append(line[1:].strip())
209                 continue
210             res = DescBegin.search(line)
211             if res != None:
212                 readingDescription = True
213                 descStartLine = lineno
214                 continue
215             if readingI18nPreamble:
216                 res = EndI18nPreamble.search(line)
217                 if res != None:
218                     readingI18nPreamble = False
219                     continue
220                 res = I18nString.search(line)
221                 if res != None:
222                     string = res.group(1)
223                     if layouttranslations:
224                         keyset.add(string)
225                     else:
226                         writeString(out, src, base, lineno, string)
227                 continue
228             res = I18nPreamble.search(line)
229             if res != None:
230                 readingI18nPreamble = True
231                 continue
232             res = NameRE.search(line)
233             if res != None:
234                 string = res.group(1)
235                 if not layouttranslations:
236                     writeString(out, src, base, lineno + 1, string)
237                 continue
238             res = CiteNameRE.search(line)
239             if res != None:
240                 string = res.group(1)
241                 if not layouttranslations:
242                     writeString(out, src, base, lineno + 1, string)
243                 continue
244             res = Style.search(line)
245             if res != None:
246                 string = res.group(1)
247                 string = string.replace('_', ' ')
248                 # Style means something else inside a float definition
249                 if not readingFloat:
250                     if not layouttranslations:
251                         writeString(out, src, base, lineno, string)
252                 continue
253             res = LabelString.search(line)
254             if res != None:
255                 string = res.group(1)
256                 if not layouttranslations:
257                     writeString(out, src, base, lineno, string)
258                 continue
259             res = MenuString.search(line)
260             if res != None:
261                 string = res.group(1)
262                 if not layouttranslations:
263                     writeString(out, src, base, lineno, string)
264                 continue
265             res = OutlinerName.search(line)
266             if res != None:
267                 string = res.group(2)
268                 if not layouttranslations:
269                     writeString(out, src, base, lineno, string)
270                 continue
271             res = Tooltip.search(line)
272             if res != None:
273                 string = res.group(1)
274                 if not layouttranslations:
275                     writeString(out, src, base, lineno, string)
276                 continue
277             res = GuiName.search(line)
278             if res != None:
279                 string = res.group(1)
280                 if layouttranslations:
281                     # gui name must only be added for floats
282                     if readingFloat:
283                         floatname = string
284                 else:
285                     writeString(out, src, base, lineno, string)
286                 continue
287             res = CategoryName.search(line)
288             if res != None:
289                 string = res.group(1)
290                 if not layouttranslations:
291                     writeString(out, src, base, lineno, string)
292                 continue
293             res = ListName.search(line)
294             if res != None:
295                 string = res.group(1)
296                 if layouttranslations:
297                     listname = string.strip('"')
298                 else:
299                     writeString(out, src, base, lineno, string)
300                 continue
301             res = InsetLayout.search(line)
302             if res != None:
303                 string = res.group(1)
304                 string = string.replace('_', ' ')
305                 #Flex:xxx is not used in translation
306                 #if not layouttranslations:
307                 #    writeString(out, src, base, lineno, string)
308                 m = FlexCheck.search(string)
309                 if m:
310                     if not layouttranslations:
311                         writeString(out, src, base, lineno, m.group(1))
312                 m = CaptionCheck.search(string)
313                 if m:
314                     if not layouttranslations:
315                         writeString(out, src, base, lineno, m.group(1))
316                 continue
317             res = Category.search(line)
318             if res != None:
319                 string = res.group(1)
320                 if not layouttranslations:
321                     writeString(out, src, base, lineno, string)
322                 continue
323             res = CounterFormat.search(line)
324             if res != None:
325                 string = res.group(1)
326                 if not layouttranslations:
327                     writeString(out, src, base, lineno, string)
328                 continue
329             res = Float.search(line)
330             if res != None:
331                 readingFloat = True
332                 continue
333             res = IsPredefined.search(line)
334             if res != None:
335                 string = res.group(1).lower()
336                 if string == 'true':
337                     isPredefined = True
338                 else:
339                     isPredefined = False
340                 continue
341             res = UsesFloatPkg.search(line)
342             if res != None:
343                 string = res.group(1).lower()
344                 if string == 'true':
345                     usesFloatPkg = True
346                 else:
347                     usesFloatPkg = False
348                 continue
349             res = CiteFormat.search(line)
350             if res != None:
351                 readingCiteFormats = True
352                 continue
353             res = End.search(line)
354             if res != None:
355                 # We have four combinations of the flags usesFloatPkg and isPredefined:
356                 #     usesFloatPkg and     isPredefined: might use standard babel translations
357                 #     usesFloatPkg and not isPredefined: does not use standard babel translations
358                 # not usesFloatPkg and     isPredefined: uses standard babel translations
359                 # not usesFloatPkg and not isPredefined: not supported by LyX
360                 # The third combination is even true for MarginFigure, MarginTable (both from
361                 # tufte-book.layout) and Planotable, Plate (both from aguplus.inc).
362                 if layouttranslations and readingFloat and usesFloatPkg:
363                     if floatname != '':
364                         keyset.add(floatname)
365                     if listname != '':
366                         keyset.add(listname)
367                 isPredefined = False
368                 usesFloatPkg = True
369                 listname = ''
370                 floatname = ''
371                 readingCiteFormats = False
372                 readingFloat = False
373                 continue
374             if readingCiteFormats:
375                 res = KeyVal.search(line)
376                 if res != None:
377                     val = res.group(1)
378                     if not layouttranslations:
379                         writeString(out, src, base, lineno, val)
380
381     if layouttranslations:
382         # Extract translations of layout files
383         import polib
384
385         # Sort languages and key to minimize the diff between different runs
386         # with changed translations
387         languages.sort()
388         keys = []
389         for key in keyset:
390             keys.append(key)
391         keys.sort()
392
393         ContextRe = re.compile(r'(.*)(\[\[.*\]\])')
394
395         print(u'''# This file has been automatically generated by po/lyx_pot.py.
396 # PLEASE MODIFY ONLY THE LAGUAGES HAVING NO .po FILE! If you want to regenerate
397 # this file from the translations, run `make ../lib/layouttranslations' in po.
398 # Python polib library is needed for building the output file.
399 #
400 # This file should remain fixed during minor LyX releases.
401 # For more comments see README.localization file.''', file=out)
402         for lang in languages:
403             print(u'\nTranslation %s' % lang, file=out)
404             if lang in list(oldtrans.keys()):
405                 trans = oldtrans[lang]
406             else:
407                 trans = dict()
408             if not lang in oldlanguages:
409                 poname = os.path.join(base, 'po/' + lang + '.po')
410                 po = polib.pofile(poname)
411                 # Iterate through po entries and not keys for speed reasons.
412                 # FIXME: The code is still too slow
413                 for entry in po:
414                     if not entry.translated():
415                         continue
416                     if entry.msgid in keys:
417                         key = entry.msgid
418                         val = entry.msgstr
419                         # some translators keep untranslated entries
420                         if val != key:
421                             trans[key] = val
422             for key in keys:
423                 if key in list(trans.keys()):
424                     val = trans[key].replace('\\', '\\\\').replace('"', '\\"')
425                     res = ContextRe.search(val)
426                     if res != None:
427                         val = res.group(1)
428                     key = key.replace('\\', '\\\\').replace('"', '\\"')
429                     print(u'\t"%s" "%s"' % (key, val), file=out)
430                 # also print untranslated entries to help translators
431                 elif not lang in oldlanguages:
432                     key = key.replace('\\', '\\\\').replace('"', '\\"')
433                     res = ContextRe.search(key)
434                     if res != None:
435                         val = res.group(1)
436                     else:
437                         val = key
438                     print(u'\t"%s" "%s"' % (key, val), file=out)
439             print(u'End', file=out)
440
441     out.close()
442
443
444 def qt4_l10n(input_files, output, base):
445     '''Generate pot file from src/frontends/qt4/ui/*.ui'''
446     output = io.open(output, 'w', encoding='utf_8', newline='\n')
447     pat = re.compile(r'\s*<string>(.*)</string>')
448     prop = re.compile(r'\s*<property.*name.*=.*shortcut')
449     for src in input_files:
450         input = io.open(src, encoding='utf_8')
451         skipNextLine = False
452         for lineno, line in enumerate(input.readlines()):
453             # skip the line after <property name=shortcut>
454             if skipNextLine:
455                 skipNextLine = False
456                 continue
457             if prop.match(line):
458                 skipNextLine = True
459                 continue
460             # get lines that match <string>...</string>
461             if pat.match(line):
462                 (string,) = pat.match(line).groups()
463                 string = string.replace('&amp;', '&').replace('&quot;', '"')
464                 string = string.replace('&lt;', '<').replace('&gt;', '>')
465                 string = string.replace('\\', '\\\\').replace('"', r'\"')
466                 string = string.replace('&#x0a;', r'\n')
467                 print(u'#: %s:%d\nmsgid "%s"\nmsgstr ""\n' % \
468                     (relativePath(src, base), lineno+1, string), file=output)
469         input.close()
470     output.close()
471
472
473 def languages_l10n(input_files, output, base):
474     '''Generate pot file from lib/languages'''
475     out = io.open(output, 'w', encoding='utf_8', newline='\n')
476     GuiName = re.compile(r'^[^#]*GuiName\s+(.*)', re.IGNORECASE)
477
478     for src in input_files:
479         descStartLine = -1
480         descLines = []
481         lineno = 0
482         for line in io.open(src, encoding='utf_8').readlines():
483             lineno += 1
484             res = GuiName.search(line)
485             if res != None:
486                 string = res.group(1)
487                 writeString(out, src, base, lineno, string)
488                 continue
489
490     out.close()
491
492
493 def latexfonts_l10n(input_files, output, base):
494     '''Generate pot file from lib/latexfonts'''
495     out = io.open(output, 'w', encoding='utf_8', newline='\n')
496     GuiName = re.compile(r'^[^#]*GuiName\s+(.*)', re.IGNORECASE)
497
498     for src in input_files:
499         descStartLine = -1
500         descLines = []
501         lineno = 0
502         for line in io.open(src, encoding='utf_8').readlines():
503             lineno += 1
504             res = GuiName.search(line)
505             if res != None:
506                 string = res.group(1)
507                 writeString(out, src, base, lineno, string)
508                 continue
509
510     out.close()
511
512
513 def external_l10n(input_files, output, base):
514     '''Generate pot file from lib/external_templates'''
515     output = io.open(output, 'w', encoding='utf_8', newline='\n')
516     Template = re.compile(r'^Template\s+(.*)', re.IGNORECASE)
517     GuiName = re.compile(r'\s*GuiName\s+(.*)', re.IGNORECASE)
518     HelpTextStart = re.compile(r'\s*HelpText\s', re.IGNORECASE)
519     HelpTextSection = re.compile(r'\s*(\S.*)\s*$')
520     HelpTextEnd = re.compile(r'\s*HelpTextEnd\s', re.IGNORECASE)
521     i = -1
522     for src in input_files:
523         input = io.open(src, encoding='utf_8')
524         inHelp = False
525         hadHelp = False
526         prev_help_string = ''
527         for lineno, line in enumerate(input.readlines()):
528             if Template.match(line):
529                 (string,) = Template.match(line).groups()
530             elif GuiName.match(line):
531                 (string,) = GuiName.match(line).groups()
532             elif inHelp:
533                 if HelpTextEnd.match(line):
534                     if hadHelp:
535                         print(u'\nmsgstr ""\n', file=output)
536                     inHelp = False
537                     hadHelp = False
538                     prev_help_string = ''
539                 elif HelpTextSection.match(line):
540                     (help_string,) = HelpTextSection.match(line).groups()
541                     help_string = help_string.replace('"', '')
542                     if help_string != "" and prev_help_string == '':
543                         print(u'#: %s:%d\nmsgid ""\n"%s\\n"' % \
544                             (relativePath(src, base), lineno+1, help_string), file=output)
545                         hadHelp = True
546                     elif help_string != "":
547                         print(u'"%s\\n"' % help_string, file=output)
548                     prev_help_string = help_string
549             elif HelpTextStart.match(line):
550                 inHelp = True
551                 prev_help_string = ''
552             else:
553                 continue
554             string = string.replace('"', '')
555             if string != "" and not inHelp:
556                 print(u'#: %s:%d\nmsgid "%s"\nmsgstr ""\n' % \
557                     (relativePath(src, base), lineno+1, string), file=output)
558         input.close()
559     output.close()
560
561
562 def formats_l10n(input_files, output, base):
563     '''Generate pot file from configure.py'''
564     output = io.open(output, 'w', encoding='utf_8', newline='\n')
565     GuiName = re.compile(r'.*\\Format\s+\S+\s+\S+\s+"([^"]*)"\s+(\S*)\s+.*', re.IGNORECASE)
566     GuiName2 = re.compile(r'.*\\Format\s+\S+\s+\S+\s+([^"]\S+)\s+(\S*)\s+.*', re.IGNORECASE)
567     input = io.open(input_files[0], encoding='utf_8')
568     for lineno, line in enumerate(input.readlines()):
569         label = ""
570         labelsc = ""
571         if GuiName.match(line):
572             label = GuiName.match(line).group(1)
573             shortcut = GuiName.match(line).group(2).replace('"', '')
574         elif GuiName2.match(line):
575             label = GuiName2.match(line).group(1)
576             shortcut = GuiName2.match(line).group(2).replace('"', '')
577         else:
578             continue
579         label = label.replace('\\', '\\\\').replace('"', '')
580         if shortcut != "":
581             labelsc = label + "|" + shortcut
582         if label != "":
583             print(u'#: %s:%d\nmsgid "%s"\nmsgstr ""\n' % \
584                 (relativePath(input_files[0], base), lineno+1, label), file=output)
585         if labelsc != "":
586             print(u'#: %s:%d\nmsgid "%s"\nmsgstr ""\n' % \
587                 (relativePath(input_files[0], base), lineno+1, labelsc), file=output)
588     input.close()
589     output.close()
590
591
592 def encodings_l10n(input_files, output, base):
593     '''Generate pot file from lib/encodings'''
594     output = io.open(output, 'w', encoding='utf_8', newline='\n')
595     # assuming only one encodings file
596     #                 Encoding utf8      utf8    "Unicode (utf8)" UTF-8    variable inputenc
597     reg = re.compile('Encoding [\w-]+\s+[\w-]+\s+"([\w \-\(\)]+)"\s+[\w-]+\s+(fixed|variable|variableunsafe)\s+\w+.*')
598     input = io.open(input_files[0], encoding='utf_8')
599     for lineno, line in enumerate(input.readlines()):
600         if not line.startswith('Encoding'):
601             continue
602         if reg.match(line):
603             print(u'#: %s:%d\nmsgid "%s"\nmsgstr ""\n' % \
604                 (relativePath(input_files[0], base), lineno+1, reg.match(line).groups()[0]), file=output)
605         else:
606             print("Error: Unable to handle line:")
607             print(line)
608             # No need to abort if the parsing fails
609             # sys.exit(1)
610     input.close()
611     output.close()
612
613
614
615 Usage = '''
616 lyx_pot.py [-b|--base top_src_dir] [-o|--output output_file] [-h|--help] [-s|src_file filename] -t|--type input_type input_files
617
618 where
619     --base:
620         path to the top source directory. default to '.'
621     --output:
622         output pot file, default to './lyx.pot'
623     --src_file
624         filename that contains a list of input files in each line
625     --input_type can be
626         ui: lib/ui/*
627         layouts: lib/layouts/*
628         layouttranslations: create lib/layouttranslations from po/*.po and lib/layouts/*
629         qt4: qt4 ui files
630         languages: file lib/languages
631         latexfonts: file lib/latexfonts
632         encodings: file lib/encodings
633         external: external templates file
634         formats: formats predefined in lib/configure.py
635 '''
636
637 if __name__ == '__main__':
638     input_type = None
639     output = 'lyx.pot'
640     base = '.'
641     input_files = []
642     #
643     optlist, args = getopt.getopt(sys.argv[1:], 'ht:o:b:s:',
644         ['help', 'type=', 'output=', 'base=', 'src_file='])
645     for (opt, value) in optlist:
646         if opt in ['-h', '--help']:
647             print(Usage)
648             sys.exit(0)
649         elif opt in ['-o', '--output']:
650             output = value
651         elif opt in ['-b', '--base']:
652             base = value
653         elif opt in ['-t', '--type']:
654             input_type = value
655         elif opt in ['-s', '--src_file']:
656             input_files = [f.strip() for f in io.open(value, encoding='utf_8')]
657
658     if input_type not in ['ui', 'layouts', 'layouttranslations', 'qt4', 'languages', 'latexfonts', 'encodings', 'external', 'formats'] or output is None:
659         print('Wrong input type or output filename.')
660         sys.exit(1)
661
662     input_files += args
663
664     # Ensure a unique sorting of input files and ignore the order in which they
665     # are given on the command line. This is important to avoid huge
666     # pseudo-diffs in the generated .pot file which would then end up in the
667     # .po files as well. We had this situation for years with people using
668     # different build systems to remerge .po files.
669     input_files.sort()
670
671     if input_type == 'ui':
672         ui_l10n(input_files, output, base)
673     elif input_type == 'latexfonts':
674         latexfonts_l10n(input_files, output, base)
675     elif input_type == 'layouts':
676         layouts_l10n(input_files, output, base, False)
677     elif input_type == 'layouttranslations':
678         layouts_l10n(input_files, output, base, True)
679     elif input_type == 'qt4':
680         qt4_l10n(input_files, output, base)
681     elif input_type == 'external':
682         external_l10n(input_files, output, base)
683     elif input_type == 'formats':
684         formats_l10n(input_files, output, base)
685     elif input_type == 'encodings':
686         encodings_l10n(input_files, output, base)
687     else:
688         languages_l10n(input_files, output, base)
689
690