24 |
import os |
import os |
25 |
import codecs |
import codecs |
26 |
from types import DictType, StringType, UnicodeType |
from types import DictType, StringType, UnicodeType |
27 |
|
from OFS.Traversable import Traversable |
28 |
|
from Persistence import Persistent |
29 |
|
from Acquisition import Implicit |
30 |
|
from App.Management import Tabs |
31 |
|
from PlacelessTranslationService import log |
32 |
|
|
33 |
|
try: |
34 |
|
from Products.OpenPT.OpenPTFile import OpenPTFile as ptFile |
35 |
|
except ImportError: |
36 |
|
#FIXME: ZPT |
37 |
|
ptFile = None |
38 |
|
|
39 |
# template to use to write missing entries to .missing |
# template to use to write missing entries to .missing |
40 |
missing_template = u"""msgid "%(id)s" |
missing_template = u"""msgid "%(id)s" |
47 |
|
|
48 |
orig_text_line_joiner = u"\n#. " |
orig_text_line_joiner = u"\n#. " |
49 |
|
|
50 |
class GettextMessageCatalog: |
permission = 'View management screens' |
51 |
""" """ |
|
52 |
|
class GettextMessageCatalog(Persistent, Implicit, Traversable, Tabs): |
53 |
|
""" |
54 |
|
Message catalog that wraps a .mo file in the filesystem |
55 |
|
""" |
56 |
|
meta_type = title = 'Gettext Message Catalog' |
57 |
|
icon = 'misc_/PlacelessTranslationService/GettextMessageCatalog.png' |
58 |
|
__roles__=('Manager',) |
59 |
|
|
60 |
def __init__(self, path_to_file): |
def __init__(self, path_to_file): |
61 |
"""Initialize the message catalog""" |
"""Initialize the message catalog""" |
62 |
self._path_to_file = path_to_file |
self._path_to_file = path_to_file |
63 |
|
self.id = os.path.split(self._path_to_file)[-1] |
64 |
|
#self.id = self._path_to_file.replace('/', '::') |
65 |
self.__translation_object = None |
self.__translation_object = None |
66 |
self._prepareTranslations() |
self._prepareTranslations() |
67 |
|
|
|
|
|
68 |
def _prepareTranslations(self): |
def _prepareTranslations(self): |
69 |
""" """ |
""" """ |
70 |
if self.__translation_object is None: |
if self.__translation_object is None: |
73 |
file.close() |
file.close() |
74 |
self._language = (tro._info.get('language-code', None) # new way |
self._language = (tro._info.get('language-code', None) # new way |
75 |
or tro._info.get('language', None)) # old way |
or tro._info.get('language', None)) # old way |
76 |
|
self._language = self._language.lower().replace('_', '-') |
77 |
self._domain = tro._info.get('domain', None) |
self._domain = tro._info.get('domain', None) |
78 |
if self._language is None or self._domain is None: |
if self._language is None or self._domain is None: |
79 |
raise ValueError, 'potfile has no metadata' |
raise ValueError, 'potfile has no metadata' |
80 |
self.preferred_encodings = tro._info.get('preferred-encodings', '').split() |
self.preferred_encodings = tro._info.get('preferred-encodings', '').split() |
81 |
self.name = unicode(tro._info.get('language-name', ''), tro._charset) |
self.name = unicode(tro._info.get('language-name', ''), tro._charset) |
82 |
|
self.default_zope_data_encoding = tro._charset |
83 |
self.__translation_object = tro |
self.__translation_object = tro |
84 |
missing = self._path_to_file[:-1] + 'issing' |
self._missing = self._path_to_file[:-1] + 'issing' |
85 |
if os.access(missing, os.W_OK): |
if not os.access(self._missing, os.W_OK): |
86 |
self.__missing = codecs.open(missing, 'a', |
self._v_missing = None |
87 |
self.__translation_object._charset) |
if self.name: |
88 |
|
self.title = '%s language (%s) for %s' % (self._language, self.name, self._domain) |
89 |
else: |
else: |
90 |
self.__missing = None |
self.title = '%s language for %s' % (self._language, self._domain) |
91 |
|
|
92 |
|
def filtered_manage_options(self, REQUEST=None): |
93 |
|
return self.manage_options |
94 |
|
|
95 |
|
def reload(self, REQUEST=None): |
96 |
|
"Forcibly re-read the file" |
97 |
|
self.__translation_object = None |
98 |
|
self._prepareTranslations() |
99 |
|
log('reloading %s: %s' % (self.id, self.title)) |
100 |
|
if hasattr(REQUEST, 'RESPONSE'): |
101 |
|
REQUEST.RESPONSE.redirect(self.absolute_url()) |
102 |
|
|
103 |
|
def _log_missing(self, id, orig_text): |
104 |
|
if self._missing is None: |
105 |
|
return |
106 |
|
if getattr(self, '_v_missing', None) is None: |
107 |
|
self._v_missing = codecs.open(self._missing, 'a', |
108 |
|
self.__translation_object._charset) |
109 |
|
if orig_text: |
110 |
|
orig_text = orig_text_line_joiner.join(orig_text.split('\n')) |
111 |
|
self._v_missing.write(orig_text_template % {'text': orig_text}) |
112 |
|
self._v_missing.write(missing_template % {'id':id.replace('"', r'\"')}) |
113 |
|
self._v_missing.flush() |
114 |
|
|
115 |
def getMessage(self, id, orig_text=None): |
def getMessage(self, id, orig_text=None, testing=False): |
116 |
""" |
""" |
117 |
""" |
""" |
118 |
self._prepareTranslations() |
self._prepareTranslations() |
119 |
msg = self.__translation_object.gettext(id) |
msg = self.__translation_object.gettext(id) |
120 |
if msg is id: |
if msg is id: |
121 |
if self.__missing: |
if not testing: |
122 |
if orig_text: |
self._log_missing(id, orig_text) |
|
orig_text = orig_text_line_joiner.join(orig_text.split('\n')) |
|
|
self.__missing.write(orig_text_template % {'text': orig_text}) |
|
|
self.__missing.write(missing_template % {'id':id.replace('"', r'\"')}) |
|
|
self.__missing.flush() |
|
123 |
raise KeyError |
raise KeyError |
124 |
if type(msg) is StringType: |
if type(msg) is StringType: |
125 |
msg = unicode(msg, self.__translation_object._charset) |
msg = unicode(msg, self.__translation_object._charset) |
126 |
return msg |
return msg |
127 |
|
|
128 |
|
queryMessage__roles__=None # Public |
129 |
def queryMessage(self, id, default=None): |
def queryMessage(self, id, default=None): |
130 |
""" |
""" |
131 |
""" |
""" |
132 |
try: |
try: |
133 |
return self.getMessage(id, default) |
return self.getMessage(id, default, testing=True) |
134 |
except KeyError: |
except KeyError: |
135 |
if default is None: |
if default is None: |
136 |
default = id |
default = id |
141 |
""" |
""" |
142 |
return self._language |
return self._language |
143 |
|
|
144 |
|
def getLanguageName(self): |
145 |
|
""" |
146 |
|
""" |
147 |
|
return self.name or self._language |
148 |
|
|
149 |
def getDomain(self): |
def getDomain(self): |
150 |
""" |
""" |
151 |
""" |
""" |
154 |
def getIdentifier(self): |
def getIdentifier(self): |
155 |
""" |
""" |
156 |
""" |
""" |
157 |
return self._path_to_file |
return self.id |
158 |
|
|
159 |
|
def getId(self): |
160 |
|
""" |
161 |
|
""" |
162 |
|
return self.id |
163 |
|
|
164 |
def getInfo(self, name): |
def getInfo(self, name): |
165 |
""" |
""" |
166 |
""" |
""" |
167 |
return self.__translation_object._info.get(name, None) |
return self.__translation_object._info.get(name, None) |
168 |
|
|
169 |
|
############################################################ |
170 |
|
# Zope/OFS integration |
171 |
|
|
172 |
|
def manage_afterAdd(self, item, container): pass |
173 |
|
def manage_beforeDelete(self, item, container): pass |
174 |
|
def manage_afterClone(self, item): pass |
175 |
|
|
176 |
|
manage_options = ( |
177 |
|
{'label':'Info', 'action':''}, |
178 |
|
{'label':'Test', 'action':'zmi_test'}, |
179 |
|
) |
180 |
|
|
181 |
|
index_html = ptFile('index_html', globals(), 'www', 'catalog_info') |
182 |
|
|
183 |
|
zmi_test = ptFile('zmi_test', globals(), 'www', 'catalog_test') |
184 |
|
|
185 |
|
def file_exists(self): |
186 |
|
try: |
187 |
|
file = open(self._path_to_file, 'rb') |
188 |
|
except: |
189 |
|
return False |
190 |
|
return True |
191 |
|
|
192 |
|
def displayInfo(self): |
193 |
|
self._prepareTranslations() |
194 |
|
info = self.__translation_object._info |
195 |
|
keys = info.keys() |
196 |
|
keys.sort() |
197 |
|
return [{'name': k, 'value': info[k]} for k in keys] + [ |
198 |
|
{'name': 'full path', 'value': self._path_to_file}, |
199 |
|
] |
200 |
# |
# |
201 |
############################################################ |
############################################################ |