~landscape/zope3/trunk

« back to all changes in this revision

Viewing changes to src/zope/app/i18n/filters.py

  • Committer: Sidnei da Silva
  • Date: 2010-07-05 21:07:01 UTC
  • Revision ID: sidnei.da.silva@canonical.com-20100705210701-zmqhqrbzad1mhzsl
- Reduce deps

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
##############################################################################
2
 
#
3
 
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
4
 
# All Rights Reserved.
5
 
#
6
 
# This software is subject to the provisions of the Zope Public License,
7
 
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
8
 
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9
 
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10
 
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11
 
# FOR A PARTICULAR PURPOSE.
12
 
#
13
 
##############################################################################
14
 
"""Translation Domain Message Export and Import Filters
15
 
 
16
 
$Id: filters.py 38178 2005-08-30 21:50:19Z mj $
17
 
"""
18
 
__docformat__ = 'restructuredtext'
19
 
 
20
 
import time, re
21
 
from types import StringTypes
22
 
from zope.interface import implements
23
 
 
24
 
from zope.i18n.interfaces import IMessageExportFilter, IMessageImportFilter
25
 
from zope.app.i18n.interfaces import ILocalTranslationDomain
26
 
 
27
 
 
28
 
class ParseError(Exception):
29
 
    def __init__(self, state, lineno):
30
 
        Exception.__init__(self, state, lineno)
31
 
        self.state = state
32
 
        self.lineno = lineno
33
 
 
34
 
    def __str__(self):
35
 
        return "state %s, line %s" % (self.state, self.lineno)
36
 
 
37
 
 
38
 
class GettextExportFilter(object):
39
 
 
40
 
    implements(IMessageExportFilter)
41
 
    __used_for__ = ILocalTranslationDomain
42
 
 
43
 
 
44
 
    def __init__(self, domain):
45
 
        self.domain = domain
46
 
 
47
 
    def exportMessages(self, languages):
48
 
        'See IMessageExportFilter'
49
 
        domain = self.domain.domain
50
 
 
51
 
        if isinstance(languages, StringTypes):
52
 
            language = languages
53
 
        elif len(languages) == 1:
54
 
            language = languages[0]
55
 
        else:
56
 
            raise TypeError(
57
 
                'Only one language at a time is supported for gettext export.')
58
 
 
59
 
        dt = time.time()
60
 
        dt = time.localtime(dt)
61
 
        dt = time.strftime('%Y/%m/%d %H:%M', dt)
62
 
        output = _file_header %(dt, language.encode('UTF-8'),
63
 
                                domain.encode('UTF-8'))
64
 
 
65
 
        for msgid in self.domain.getMessageIds():
66
 
            msgstr = self.domain.translate(msgid, target_language=language)
67
 
            msgstr = msgstr.encode('UTF-8')
68
 
            msgid = msgid.encode('UTF-8')
69
 
            output += _msg_template %(msgid, msgstr)
70
 
 
71
 
        return output
72
 
 
73
 
 
74
 
 
75
 
class GettextImportFilter(object):
76
 
 
77
 
    implements(IMessageImportFilter)
78
 
    __used_for__ = ILocalTranslationDomain
79
 
 
80
 
 
81
 
    def __init__(self, domain):
82
 
        self.domain = domain
83
 
 
84
 
    def importMessages(self, languages, file):
85
 
        'See IMessageImportFilter'
86
 
 
87
 
        if isinstance(languages, StringTypes):
88
 
            language = languages
89
 
        elif len(languages) == 1:
90
 
            language = languages[0]
91
 
        else:
92
 
            raise TypeError(
93
 
                'Only one language at a time is supported for gettext export.')
94
 
 
95
 
        result = parseGetText(file.readlines())[3]
96
 
        headers = parserHeaders(''.join(result[('',)][1]))
97
 
        del result[('',)]
98
 
        charset = extractCharset(headers['content-type'])
99
 
        for msg in result.items():
100
 
            msgid = unicode(''.join(msg[0]), charset)
101
 
            msgid = msgid.replace('\\n', '\n')
102
 
            msgstr = unicode(''.join(msg[1][1]), charset)
103
 
            msgstr = msgstr.replace('\\n', '\n')
104
 
            self.domain.addMessage(msgid, msgstr, language)
105
 
 
106
 
 
107
 
 
108
 
def extractCharset(header):
109
 
    charset = header.split('charset=')[-1]
110
 
    return charset.lower()
111
 
 
112
 
 
113
 
def parserHeaders(headers_text):
114
 
    headers = {}
115
 
    for line in headers_text.split('\\n'):
116
 
        name = line.split(':')[0]
117
 
        value = ''.join(line.split(':')[1:])
118
 
        headers[name.lower()] = value
119
 
 
120
 
    return headers
121
 
 
122
 
 
123
 
def parseGetText(content):
124
 
    # The regular expressions
125
 
    com = re.compile('^#.*')
126
 
    msgid = re.compile(r'^ *msgid *"(.*?[^\\]*)"')
127
 
    msgstr = re.compile(r'^ *msgstr *"(.*?[^\\]*)"')
128
 
    re_str = re.compile(r'^ *"(.*?[^\\])"')
129
 
    blank = re.compile(r'^\s*$')
130
 
 
131
 
    trans = {}
132
 
    pointer = 0
133
 
    state = 0
134
 
    COM, MSGID, MSGSTR = [], [], []
135
 
    while pointer < len(content):
136
 
        line = content[pointer]
137
 
        #print 'STATE:', state
138
 
        #print 'LINE:', line, content[pointer].strip()
139
 
        if state == 0:
140
 
            COM, MSGID, MSGSTR = [], [], []
141
 
            if com.match(line):
142
 
                COM.append(line.strip())
143
 
                state = 1
144
 
                pointer = pointer + 1
145
 
            elif msgid.match(line):
146
 
                MSGID.append(msgid.match(line).group(1))
147
 
                state = 2
148
 
                pointer = pointer + 1
149
 
            elif blank.match(line):
150
 
                pointer = pointer + 1
151
 
            else:
152
 
                raise ParseError(0, pointer + 1)
153
 
        elif state == 1:
154
 
            if com.match(line):
155
 
                COM.append(line.strip())
156
 
                state = 1
157
 
                pointer = pointer + 1
158
 
            elif msgid.match(line):
159
 
                MSGID.append(msgid.match(line).group(1))
160
 
                state = 2
161
 
                pointer = pointer + 1
162
 
            elif blank.match(line):
163
 
                pointer = pointer + 1
164
 
            else:
165
 
                raise ParseError(1, pointer + 1)
166
 
 
167
 
        elif state == 2:
168
 
            if com.match(line):
169
 
                COM.append(line.strip())
170
 
                state = 2
171
 
                pointer = pointer + 1
172
 
            elif re_str.match(line):
173
 
                MSGID.append(re_str.match(line).group(1))
174
 
                state = 2
175
 
                pointer = pointer + 1
176
 
            elif msgstr.match(line):
177
 
                MSGSTR.append(msgstr.match(line).group(1))
178
 
                state = 3
179
 
                pointer = pointer + 1
180
 
            elif blank.match(line):
181
 
                pointer = pointer + 1
182
 
            else:
183
 
                raise ParseError(2, pointer + 1)
184
 
 
185
 
        elif state == 3:
186
 
            if com.match(line) or msgid.match(line):
187
 
                # print "\nEn", language, "detected", MSGID
188
 
                trans[tuple(MSGID)] = (COM, MSGSTR)
189
 
                state = 0
190
 
            elif re_str.match(line):
191
 
                MSGSTR.append(re_str.match(line).group(1))
192
 
                state = 3
193
 
                pointer = pointer + 1
194
 
            elif blank.match(line):
195
 
                pointer = pointer + 1
196
 
            else:
197
 
                raise ParseError(3, pointer + 1)
198
 
 
199
 
    # the last also goes in
200
 
    if tuple(MSGID):
201
 
        trans[tuple(MSGID)] = (COM, MSGSTR)
202
 
 
203
 
    return COM, MSGID, MSGSTR, trans
204
 
 
205
 
 
206
 
_file_header = '''
207
 
msgid ""
208
 
msgstr ""
209
 
"Project-Id-Version: Zope 3\\n"
210
 
"PO-Revision-Date: %s\\n"
211
 
"Last-Translator: Zope 3 Gettext Export Filter\\n"
212
 
"Zope-Language: %s\\n"
213
 
"Zope-Domain: %s\\n"
214
 
"MIME-Version: 1.0\\n"
215
 
"Content-Type: text/plain; charset=UTF-8\\n"
216
 
"Content-Transfer-Encoding: 8bit\\n"
217
 
'''
218
 
 
219
 
_msg_template = '''
220
 
msgid "%s"
221
 
msgstr "%s"
222
 
'''