source: lliurex-mate-welcome/trunk/fuentes/edgar-allan @ 5163

Last change on this file since 5163 was 3933, checked in by alviboi, 2 years ago
  • Property svn:executable set to *
File size: 15.4 KB
Line 
1#! /usr/bin/python3
2# -*- coding:utf-8 -*-
3
4import codecs
5import glob
6import os
7import re
8import shutil
9import sys
10
11try:
12    import polib
13except:
14    print("Requires polib. apt-get install python3-polib.")
15    sys.exit(1)
16
17def get_translatables_from_file(input_file, trim_strs = True):
18    """ Get all translatable strings (enclosed by '‌' characters)
19        from the specfified file
20
21    Args : html_file - the file with the translatable strings
22
23           trim_strs - if True the translatable strings will have \n and
24                       redundant spaces between words removed
25                   
26    Returns: a list of tuples, each of which contains a list of line numbers
27             at which a translatable string was found, plus the string
28             itself (without the ‌s). Example:
29             [[12,43, 66], "System Requirements"]
30
31    """
32
33    # use regular expressions to iterate through all the translatables
34    p= re.compile("‌(.+?)‌", re.MULTILINE | re.DOTALL)
35    lines = open(input_file, 'r')
36    content = lines.read()
37    line_nos = []
38    strings = []
39    for m in re.finditer (p, content):
40
41        # get the translatable string and remove the "‌"s, \n chars
42        # and redundant spaces etc. in the text
43        text = content[m.start() : m.end()]
44        text = text.replace("‌", "")
45
46        if trim_strs:
47            text = text.replace("\n", "")
48            text = " ".join(text.split())
49
50        # if the text has already been encounted, add its line number to
51        # the relevant entry in line_nos[]
52        # otherwise add a new entry in line_nos and strings[]
53
54        line_no = content.count("\n", 0, m.start()) + 1
55        if text in strings:
56            line_nos[strings.index(text)].append(line_no)
57        else:
58            line_nos.append([line_no])
59            strings.append(text)
60
61    # prepare and return the results
62    translatables=[]
63    for i in range(0, len(strings)):
64        translatables.append([line_nos[i], strings[i]])
65
66    return translatables
67
68###############################################################################
69def create_pot_file (input_file, pot_file, verbose):
70    """
71        Create a .pot file from a translatables set of translatable strings
72
73    Args:
74        translatables:  a list of tuples, each of which contain the line number
75                        at which a translatable string was found, plus the string
76                        itself
77        pot_file     : the filename of the .pot to create
78        verbose      : whether to display progress info
79    """
80
81    translatables  = get_translatables_from_file(input_file)
82
83    # check if the file exists. If it does, open it, otherwise create a new file
84    new_file = not os.path.exists(pot_file)
85    if new_file:
86        pofile = polib.POFile()
87        pofile.metadata= {
88            'Project-Id-Version': 'Ubuntu MATE Welcome',
89            "Report-Msgid-Bugs-To ": "you@example.com",
90            "POT-Creation-Date": "2016-02-27 12:48+0100",
91            "PO-Revision-Date": "YEAR-MO-DA HO:MI+ZONE",
92            "Last-Translator": "FULL NAME <EMAIL@ADDRESS>",
93            "Language-Team:": "LANGUAGE <LL@li.org>",
94            "MIME-Version": "1.0",
95            "Content-Type": "text/plain; charset=UTF-8",
96            "Content-Transfer-Encoding": "8bit",}
97    else:
98        pofile = polib.pofile(pot_file)
99   
100    source_path, source_file = os.path.split(input_file)
101    for translatable in translatables:
102        entry = polib.POEntry(
103                msgid = translatable[1],
104                msgstr = "",
105                occurrences = [(source_file, "%s" %str(translatable[0]).strip("[]"))])
106
107        if new_file:
108            pofile.append (entry)
109            if verbose:
110                print ('Added "%s" to pot file' %translatable[1])
111        else:
112            # add the entry only if it isn't already present...
113            present = False
114            for en in pofile:
115                if en.msgid == entry.msgid:
116                    present = True
117                    break
118
119            if not present:
120                pofile.append(entry)
121                if verbose:
122                    print ('Added "%s" to pot file' %translatable[1])
123            else:
124                if verbose:
125                   print ('Did not add "%s" - already present.' %translatable[1])
126
127    if verbose:
128        print ('Saving pot file to %s' %pot_file)
129
130    pofile.save(pot_file)
131    if verbose:
132        print ("Saved")
133
134###################################################################################
135def translate_file(in_file, in_po, out_file, verbose):
136    """ Translate a file from English to another language
137
138    For every translatable string in in_file, replace the corresponding
139    text in the input file with the appropriate translation from the .po
140    file. When all  translations are done, write the resulting html to the
141    output file
142
143    Args:
144        in_file: the original filename whose contents are in English within
145                 &zwnj; enclosures
146        in_po  : the filename of the .po file to use for the translation
147        out_file : the filename that the translation gets written to
148
149    """
150
151    # get the translatable strings from the input file
152    translatables = get_translatables_from_file(in_file, trim_strs=False)
153
154    # read the entitrecontents of the file
155    content = open(in_file, 'r').read()
156
157    # read the po file
158    po_file = polib.pofile(in_po)
159
160    # for every translatable string, try to find and replace it with the appropriate
161    # translated
162    for translatable in translatables:
163
164        #can we find the translatable text in the input file?
165        if translatable[1] in content:
166
167            # remove \n and redundant spaces between words from the translatable string, so that
168            # it will match the entry in the .po file
169            trim_text = translatable[1].replace("\n", "")
170            trim_text = " ".join(trim_text.split())           
171           
172            # iterate through the po entries looking for the one which matches the current translatable
173            for entry in po_file:
174                if (entry.msgid == trim_text):
175                   
176                    if (entry.msgstr !=""):
177                   
178                        # replace the English text with the tranlated text.
179                        # NOTE: ALL occurrences of the English text are replaced throughout the entire
180                        # file
181                   
182                        content = content.replace("%s%s%s" %("&zwnj;", translatable[1], "&zwnj;"), entry.msgstr)
183                        if verbose:
184                            print ("Translated %s >> %s" %(trim_text, entry.msgstr))
185                    else:
186                        # there's no translation, so instead just remove the &zwnj; characters from the string
187                        content = content.replace("%s%s%s" %("&zwnj;", translatable[1], "&zwnj;"), entry.msgid)
188                        if verbose:
189                            print("No translation for %s, so &zwnj; characters removed" %entry.msgid)
190                    break
191
192        else:
193            if verbose:
194                print ("WARNING: translatable string  %s not found" %translatable[1])
195
196    outfile = codecs.open(out_file, 'w', encoding='utf-8')   
197    outfile.write(content)
198    outfile.close()
199
200##########################################################################
201def create_dummy_translations(in_po, out_po, verbose):
202    """ Take the input po file and set the translations to be the reverse of the original string
203        and write the results to a new po_file
204
205    Args:
206        in_po  : the source .po
207        out_po : the po file where the dummy translations are to be written
208        verbose: let the user know what's going on...
209    """
210
211
212    pofile = polib.pofile(in_po)
213    for entry in pofile:
214        entry.msgstr = entry.msgid[::-1]
215        if verbose:
216            print ('Setting translation of "%s" to "%s"' %(entry.msgid, entry.msgstr))
217   
218    if verbose:
219        print ('Saving to %s' %out_po)
220    pofile.save(out_po)
221    if verbose:
222        print('Saved')
223
224########################################################################
225def create_all_pot_files(slide_dir, po_dir, verbose):
226    """ Create .pot files for all the html files in slide_dir and place them
227        in the po_dir directory
228       
229        Args: slide_dir - the directory containing the html files
230              po_dir - the directory where the .pot files are to be created
231              verbose - let the user know what's happening
232
233    """           
234
235    # if there isnt already a 'po' directory in ./data, create one
236    if not os.path.exists(po_dir):
237        os.mkdir(po_dir)
238        if verbose:
239            print ("Created %s directory" %po_dir)
240
241    template_slides = glob.glob(os.path.join(slide_dir, '*.html'))
242
243    # create a list of tuples containing the full slide path and filename, and the slide
244    # names minus the .html extension
245    slide_info=[]
246    for slide in template_slides:
247        slide_filename = slide
248        slide_name =(os.path.splitext(os.path.split(slide)[1])[0])
249        slide_info.append([slide_filename, slide_name])
250
251    # if necessary create directories under po_dir for the slides
252    for slide in slide_info:
253        if not os.path.exists(os.path.join(po_dir, slide[1])):
254            os.mkdir(os.path.join(po_dir, slide[1]))
255            if verbose:
256                print ("Created directory %s" %os.path.join(po_dir, slide[1]))
257
258    # now create the .pot files
259    for slide in slide_info:
260        pot_file = os.path.join(po_dir, slide[1])
261        pot_file = os.path.join(pot_file, slide[1] + ".pot")
262        if os.path.exists(pot_file):
263            # move the existing file out of the way
264            shutil.copyfile (pot_file, pot_file + ".old")
265
266        # create the pot file
267        create_pot_file(slide[0], pot_file, False)
268        if verbose:
269            print ("Created %s" %pot_file)
270
271    print ("All .pots created.")
272
273#################################################################################################
274def create_i18n_slides(slide_dir, po_dir, i18n_dir, verbose):
275    """ Create translations of the html slides in source_dir, using the .po files in po_dir/<slide name>
276        and write them to the i18n directory in i18n_dir/<locale>/
277
278    Args:
279        slide_dir : the location of the html files
280        po_dir    : the location of the po files containing translations
281        i18n_diir : the location where translatied html gets written
282        verbose   : let the user know what's going on
283    """
284
285
286    # make the 'i18n' directory if not already present
287    if not os.path.exists(i18n_dir):
288        os.mkdir(i18n_dir)
289
290    template_slides = glob.glob(os.path.join(slide_dir, '*.html'))
291
292    for slide in template_slides:
293        slide_name = (os.path.splitext(os.path.split(slide)[1])[0])
294        print("Working on slide: %s...." %slide_name)
295
296        slide_po = os.path.join(po_dir, slide_name)
297        locales = glob.glob(os.path.join(slide_po, '*.po'))
298        for locale_file in sorted(locales):
299            locale_name = os.path.basename(locale_file).replace(".po", "")
300
301            locale_slides = os.path.join(i18n_dir, locale_name)
302            #make the locale directory if it doesn't already exists
303            if not os.path.exists(locale_slides):
304                os.mkdir(locale_slides)
305       
306            output_slide = os.path.join(locale_slides, slide_name + ".html")
307       
308            if os.path.exists(output_slide):
309                os.remove(output_slide)
310       
311            translate_file(slide, locale_file, output_slide, False)
312            if verbose:
313                print ("Translated %s to %s locale" %(slide_name,locale_name))
314
315    print ('All slides translated')
316
317create_all_pots = False
318create_pot = False
319translate_all = False
320translate = False
321reverse_po = False
322input_file = ''
323output_file = ''
324po_file = ''
325verbose = False
326
327commands=0
328for arg in sys.argv:
329    if arg == '--help':
330        print('\nUsage: edgar-allan [command] [arguments]')
331        print('\nCommand may be one of the following:')         
332        print('  create-all-pots            Create .pot files for each html file in the data directory and write')
333        print('                             them to the data/po directory')
334        print('  create-pot                 Create a .pot file from an input file containing &zwnj; enclosed')
335        print('                             strings.')
336        print('  translate-all              Create translations for all slides in the data directory using the')
337        print('                             available .po files in the data/po/<slide>/ directory')
338        print('  translate                  Translate an input file using a specified .po file and write the')
339        print('                             result to an output file.')
340        print('  po                         Take a po file and set all of the translations within it to be')
341        print('                             the reverse of the original string and write the result to an output')
342        print('                             file (can be useful when testing the translation function.')
343        print('Arguments:')
344        print('  --input=<filename>         The file for input to the create-pot and translate commands.')
345        print('  --po-file=<filename>       The .po file to use when translating a file.')
346        print('  --output=<filename>        The file to be created by the create-pot and translate commands')
347        print('  --verbose, -v              Display detailed output')
348        print('')
349        exit()
350
351    if arg == 'create-all-pots':
352        create_all_pots = True
353        commands+=1
354
355    if arg == 'translate-all':
356        translate_all = True
357        commands+=1
358
359    if arg == 'create-pot':
360        create_pot = True
361        commands+=1
362
363    if arg == 'translate':
364        translate = True
365        commands+=1
366
367    if arg=='po':
368        reverse_po = True
369        commands+=1
370       
371    if arg.startswith('--input='):
372        input_file = arg.split('--input=')[1]
373
374    if arg.startswith('--output='):
375        output_file = arg.split('--output=')[1]
376
377    if arg.startswith('--po-file='):
378        po_file = arg.split('--po-file=')[1]
379
380    if arg == '--verbose' or arg == '-v':
381        verbose = True
382
383if commands>1:
384    print('Specify only one of the create-pot, translate, po... commands')
385    exit()
386
387if commands==0:
388    print('No command specified - use --help to see what''s available')
389    exit()
390
391# check that commands which need arguments have them
392cmd_check = None
393if translate:
394    cmd_check = 'translate'
395elif create_pot:
396    cmd_check = 'create-pot'
397elif reverse_po:
398    cmd_check = 'po'
399
400if cmd_check is not None:
401    if (input_file == ''):
402        print('No input file specifed for %s command' %cmd_check)
403        exit()
404
405    if (output_file ==''):
406        print('No output file specified for %s command' %cmd_check)
407        exit()
408
409    if translate and (po_file==""):
410        print('No .po file specified for %s command' %cmd_check)
411        exit()
412
413source_dir = '.'
414build_slides = os.path.join(source_dir, 'data')
415po_dir = os.path.join(build_slides, 'po')
416i18n_dir =os.path.join(source_dir, 'i18n')
417
418if create_all_pots:
419    create_all_pot_files(build_slides, po_dir, verbose)
420elif translate_all:
421    create_i18n_slides(build_slides, po_dir, i18n_dir, verbose)
422elif create_pot:
423    create_pot_file (input_file, output_file, verbose)
424elif translate:
425    translate_file (input_file, po_file, output_file, verbose)
426elif reverse_po:
427    create_dummy_translations(input_file, output_file, verbose)
428
429
430
Note: See TracBrowser for help on using the repository browser.