~cm-t/ubuntu-fr-tour/ubuntu-fr-tour

« back to all changes in this revision

Viewing changes to 13.04/12.10/translate-html/translate_html/StringExtractor.py

  • Committer: cm-t arudy
  • Date: 2013-10-22 01:24:09 UTC
  • Revision ID: arudy@ubuntu-fr.org-20131022012409-3dmo4i9u4ufohe5f
First Fr push to 13.10
Fixed many icons (updated to new version or fixed graphic)
Added Cloud indicator
Added Keyboard uindicator
Fixed many layout to fit Fr string

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#! /usr/bin/env python
2
 
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
3
 
### BEGIN LICENSE
4
 
# Copyright (C) 2011 David Planella <david.planella@ubuntu.com>
5
 
# This program is free software: you can redistribute it and/or modify it
6
 
# under the terms of the GNU General Public License version 3, as published
7
 
# by the Free Software Foundation.
8
 
#
9
 
# This program is distributed in the hope that it will be useful, but
10
 
# WITHOUT ANY WARRANTY; without even the implied warranties of
11
 
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12
 
# PURPOSE.  See the GNU General Public License for more details.
13
 
#
14
 
# You should have received a copy of the GNU General Public License along
15
 
# with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 
### END LICENSE
17
 
#
18
 
# This module implements a class to extract translatable messages from
19
 
# different types of files and put them into a Gettext POT file ready to give
20
 
# to translators to do their work. At this point only extracting messages
21
 
# from HTML files has been implemented.
22
 
 
23
 
import codecs
24
 
import mimetypes
25
 
import os
26
 
from HTMLParser import HTMLParser
27
 
from traceback import print_exc
28
 
from sys import stderr
29
 
from translate_html import translate_htmlconfig
30
 
from re import sub
31
 
import sys
32
 
from datetime import datetime
33
 
 
34
 
try:
35
 
    import polib
36
 
except ImportError:
37
 
    sys.stderr.write('You need the Python Polib library to run this ' +
38
 
                     'script.\nYou can install it by running:\n\t' +
39
 
                     '$ sudo apt-get install python-polib')
40
 
 
41
 
# MIME type definitions (type, encoding)
42
 
HTML_FILE = ('text/html', None)
43
 
JS_FILE = ('application/javascript', None)
44
 
 
45
 
BOM = u'\ufeff'
46
 
PO_FOLDER = translate_htmlconfig.PO_FOLDER
47
 
GETTEXT_DOMAIN = translate_htmlconfig.GETTEXT_DOMAIN
48
 
POTFILES = translate_htmlconfig.POTFILES
49
 
 
50
 
 
51
 
class HTMLStringParser(HTMLParser):
52
 
    """This class does the actual extraction from messages from HTML files.
53
 
    HTML entities are generally not supported, the only exception being
54
 
    &amp;.
55
 
 
56
 
    return a Python set containing the extracted text
57
 
 
58
 
    """
59
 
    def __init__(self):
60
 
        HTMLParser.__init__(self)
61
 
        self.skiptag = False
62
 
        self.entityseen = False
63
 
        self._text = []
64
 
 
65
 
    def handle_data(self, data):
66
 
        text = data.strip()
67
 
        if (len(text) > 0) and not self.skiptag and (text != BOM):
68
 
            text = sub('[ \t\r\n]+', ' ', text)
69
 
            if not self.entityseen:
70
 
                self._text.append(text)
71
 
            else:
72
 
                entity = self._text.pop()
73
 
                self._text[-1] += ' ' + entity + ' ' + text
74
 
                self.entityseen = False
75
 
 
76
 
    def handle_starttag(self, tag, attrs):
77
 
        if tag == 'script':
78
 
            self.skiptag = True
79
 
        elif tag == 'noscript':
80
 
            self.skiptag = True
81
 
 
82
 
    def handle_endtag(self, tag):
83
 
        if tag == 'script':
84
 
            self.skiptag = False
85
 
        elif tag == 'noscript':
86
 
            self.skiptag = False
87
 
 
88
 
    def handle_entityref(self, name):
89
 
        # We only support &amp; for now
90
 
        if name == 'amp':
91
 
            self.handle_data('&' + name + ';')
92
 
            self.entityseen = True
93
 
 
94
 
    def text(self):
95
 
        return set(self._text)
96
 
 
97
 
 
98
 
class StringExtractor(object):
99
 
    """This class reads the list of files to extract strings from from the
100
 
    POTFILES.in file, performs the extraction and saves the POT file to disk.
101
 
 
102
 
    """
103
 
    def __init__(self):
104
 
        self.files = self._load_files()
105
 
        self.potfile = polib.POFile()
106
 
        time_str = datetime.now().isoformat(' ')
107
 
        self.potfile.metadata = {
108
 
            'Project-Id-Version': '1.0',
109
 
            'Report-Msgid-Bugs-To': 'you@example.com',
110
 
            'POT-Creation-Date': time_str,
111
 
            'PO-Revision-Date': time_str,
112
 
            'Last-Translator': 'you <you@example.com>',
113
 
            'Language-Team': 'English <yourteam@example.com>',
114
 
            'MIME-Version': '1.0',
115
 
            'Content-Type': 'text/plain; charset=utf-8',
116
 
            'Content-Transfer-Encoding': '8bit',
117
 
        }
118
 
 
119
 
    def _load_files(self):
120
 
        """Loads the files to extract strings from. They are expected to
121
 
        be listed in the POFILES.in file"""
122
 
        with open(translate_htmlconfig.get_source_file(PO_FOLDER,
123
 
                                                       POTFILES)) as fp:
124
 
            file_list = []
125
 
            for line in fp.readlines():
126
 
                if not line.startswith('#'):
127
 
                    line = os.path.join(
128
 
                        translate_htmlconfig.get_sources_path(), line)
129
 
                    file_list.append(line.strip())
130
 
            return file_list
131
 
 
132
 
    def _save_potfile(self):
133
 
        """Writes the resulting POT file to disk"""
134
 
        self.potfile.save(os.path.join(
135
 
                            translate_htmlconfig.get_sources_path(),
136
 
                            PO_FOLDER,
137
 
                            GETTEXT_DOMAIN + '.pot'))
138
 
 
139
 
    def extract(self):
140
 
        """Extracts the messages from the given file by choosing the
141
 
        appropriate extractor type, and saves the POT file to disk"""
142
 
        for file_to_extract in self.files:
143
 
            extractor = getExtractor(self.potfile, file_to_extract)
144
 
            extractor.extract()
145
 
        self._save_potfile()
146
 
 
147
 
 
148
 
class StringExtractorJs(object):
149
 
    """This class implements the extractor from messages in JavaScript files
150
 
    It is currently not supported.
151
 
 
152
 
    """
153
 
    def __init__(self, potfile, jsfile):
154
 
        self.jsfile = jsfile
155
 
        self.potfile = potfile
156
 
 
157
 
    def extract(self):
158
 
 
159
 
        jsfile_rel = self.jsfile.replace(
160
 
                            translate_htmlconfig.get_sources_path(), '..')
161
 
        with codecs.open(self.jsfile, 'r', 'utf-8') as fp:
162
 
            linecount = 0
163
 
            for line in fp.readlines():
164
 
                linecount += 1
165
 
                if line.startswith('var'):
166
 
                    var, message = line.split('=', 1)
167
 
                    var = var.split()[1]
168
 
                    message = message.strip()
169
 
                    message = message[1:-2]
170
 
 
171
 
                    entry = polib.POEntry(
172
 
                                comment=var,
173
 
                                occurrences=[(jsfile_rel, linecount)],
174
 
                                msgid=message,
175
 
                                msgstr=u'')
176
 
                    self.potfile.append(entry)
177
 
 
178
 
 
179
 
class StringExtractorHtml(object):
180
 
    """This class implements the extractor from messages in HTML files.
181
 
    It reads the given HTML file and puts the extracted messages in a
182
 
    potfile structure
183
 
 
184
 
    """
185
 
    def __init__(self, potfile, htmlfile):
186
 
        self.htmlfile = htmlfile
187
 
        self.potfile = potfile
188
 
 
189
 
    def extract(self):
190
 
        htmlfile_rel = self.htmlfile.replace(
191
 
                            translate_htmlconfig.get_sources_path(), '..')
192
 
        try:
193
 
            with codecs.open(self.htmlfile, 'r', 'utf-8') as fp:
194
 
                html_file = fp.read()
195
 
                extractor = HTMLStringParser()
196
 
                extractor.feed(html_file)
197
 
                extractor.close()
198
 
                messages = extractor.text()
199
 
 
200
 
                for message in messages:
201
 
                    entry = polib.POEntry(
202
 
                        occurrences=[(htmlfile_rel, 0)],
203
 
                        msgid=message,
204
 
                        msgstr=u'')
205
 
                    self.potfile.append(entry)
206
 
        except:
207
 
            print_exc(file=stderr)
208
 
 
209
 
 
210
 
class StringExtractorNone(object):
211
 
    """Dummy message extractor
212
 
 
213
 
    """
214
 
    def __init__(self, potfile, path):
215
 
        pass
216
 
 
217
 
    def extract(self):
218
 
        pass
219
 
 
220
 
 
221
 
def getExtractor(potfile, path):
222
 
    """Factory-like function to guess the type of file to extract translations
223
 
    from by its MIME type, and return the appropriate extractor class to
224
 
    handle it.
225
 
 
226
 
    """
227
 
    # Guess the type of the given file
228
 
    filetype, encoding = mimetypes.guess_type(path)
229
 
 
230
 
    # Return the appropriate extractor class to handle the type
231
 
    if (filetype, encoding) == HTML_FILE:
232
 
        return StringExtractorHtml(potfile, path)
233
 
    elif (filetype, encoding) == JS_FILE:
234
 
        return StringExtractorJs(potfile, path)
235
 
    else:
236
 
        return StringExtractorNone(potfile, path)