1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
|
# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""View class for requesting translation exports."""
__metaclass__ = type
__all__ = ['BaseExportView']
from datetime import timedelta
from zope.component import getUtility
from lp import _
from lp.app.browser.tales import DurationFormatterAPI
from lp.services.propertycache import cachedproperty
from lp.services.webapp import (
canonical_url,
LaunchpadView,
)
from lp.translations.interfaces.hastranslationtemplates import (
IHasTranslationTemplates,
)
from lp.translations.interfaces.poexportrequest import IPOExportRequestSet
from lp.translations.interfaces.translationexporter import (
ITranslationExporter,
)
from lp.translations.interfaces.translationfileformat import (
TranslationFileFormat,
)
class BaseExportView(LaunchpadView):
"""Base class for PO export views."""
@cachedproperty
def uses_translations(self):
return self.context.has_current_translation_templates
@property
def export_queue_status(self):
"""Summary of queue status."""
queue_size = self.request_set.entry_count
estimated_backlog = self.request_set.estimateBacklog()
size_text = self.describeQueueSize(queue_size)
backlog_text = self.describeBacklog(estimated_backlog)
return " ".join((size_text, backlog_text))
def describeQueueSize(self, queue_size):
"""Return string describing the given queue size."""
if queue_size == 0:
return "The export queue is currently empty."
elif queue_size == 1:
return "There is 1 file request on the export queue."
else:
return (
"There are %d file requests on the export queue."
% queue_size)
def describeBacklog(self, estimated_backlog):
"""Return string describing the current export backlog."""
threshold = timedelta(minutes=10)
if estimated_backlog is None or estimated_backlog < threshold:
return ""
formatter = DurationFormatterAPI(estimated_backlog)
time_string = formatter.approximateduration()
return "The backlog is approximately %s." % time_string
def getDefaultFormat(self):
"""Overridable: return default file format to use for the export."""
if not IHasTranslationTemplates.providedBy(self.context):
raise NotImplementedError(
'Subclass not implementing `IHasTranslationsTemplates` '
'interface. Either override getDefaultFormat implementation '
'or implement `IHasTranslationsTemplates`.')
templates = self.context.getCurrentTranslationTemplates()
if not bool(templates.any()):
return None
formats = self.context.getTranslationTemplateFormats()
format = formats[0]
if len(formats) > 1:
self.request.response.addInfoNotification(
"This package has templates with different native "
"file formats. If you proceed, all translations will be "
"exported in the single format you specify.")
return format
def processForm(self):
"""Return templates and translations requested to be exported.
Overridable in a child class. Must do one of:
a. Add an error notification to the page and return `None`
b. Return a tuple of two iterables or None, of requested templates
and of requested pofiles IDs.
c. Redirect and return `None`.
"""
if not IHasTranslationTemplates.providedBy(self.context):
raise NotImplementedError(
'Subclass not implementing `IHasTranslationsTemplates` '
'interface. Either override getDefaultFormat implementation '
'or implement `IHasTranslationsTemplates`.')
translation_templates_ids = (
self.context.getCurrentTranslationTemplates(just_ids=True))
pofiles_ids = self.context.getCurrentTranslationFiles(just_ids=True)
if not bool(pofiles_ids.any()):
pofiles_ids = None
return (translation_templates_ids, pofiles_ids)
def getExportFormat(self):
"""Optional overridable: The requested export format."""
return self.request.form.get("format")
def initialize(self):
self.request_set = getUtility(IPOExportRequestSet)
# Ask our derived class to figure out the default file format for this
# export. We do that here because the method may issue warnings,
# which must be attached to our response early on.
self.default_format = self.getDefaultFormat()
if self.request.method != "POST":
return
bad_format_message = _("Please select a valid format for download.")
format_name = self.getExportFormat()
if format_name is None:
self.request.response.addErrorNotification(bad_format_message)
return
try:
format = TranslationFileFormat.items[format_name]
except KeyError:
self.request.response.addErrorNotification(bad_format_message)
return
requested_files = self.processForm()
if requested_files is None:
return
templates, pofiles = requested_files
if not templates and not pofiles:
self.request.response.addErrorNotification(
"Please select at least one translation or template.")
else:
self.request_set.addRequest(self.user, templates, pofiles, format)
self.nextURL()
def nextURL(self):
self.request.response.addInfoNotification(_(
"Your request has been received. Expect to receive an email "
"shortly."))
self.request.response.redirect(
canonical_url(self.context, rootsite='translations'))
def formats(self):
"""Return a list of formats available for translation exports."""
class BrowserFormat:
def __init__(self, title, value, is_default=False):
self.title = title
self.value = value
self.is_default = is_default
translation_exporter = getUtility(ITranslationExporter)
exporters = translation_exporter.getExportersForSupportedFileFormat(
self.default_format)
for exporter in exporters:
format = exporter.format
if format == self.default_format:
is_default = True
else:
is_default = False
yield BrowserFormat(format.title, format.name, is_default)
|