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