Skip to content

Commit

Permalink
files: support converted downloads on all levels
Browse files Browse the repository at this point in the history
  • Loading branch information
nijel committed Oct 5, 2023
1 parent 6f399ae commit cc3cda4
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 26 deletions.
7 changes: 7 additions & 0 deletions weblate/formats/exporters.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ def __init__(
self.language = translation.language
self.url = get_site_url(translation.get_absolute_url())
else:
# TODO: is needed?
raise ValueError("Translation missing")
self.project = project
self.language = language
self.source_language = source_language
Expand Down Expand Up @@ -179,6 +181,11 @@ def get_response(self, filetemplate="{project}-{language}.{extension}"):
project=self.project.slug,
language=self.language.code,
extension=self.extension,
path="-".join(
self.translation.get_url_path()
if self.translation
else (self.project.slug, self.language.code)
),
)

response = HttpResponse(content_type=f"{self.content_type}; charset=utf-8")
Expand Down
54 changes: 34 additions & 20 deletions weblate/trans/views/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@
)


def download_multi(translations, commit_objs, fmt=None, name="translations"):
def download_multi(request, translations, commit_objs, fmt=None, name="translations"):
filenames = set()
components = set()
extra = {}

for obj in commit_objs:
try:
Expand All @@ -43,25 +44,32 @@ def download_multi(translations, commit_objs, fmt=None, name="translations"):
else:
report_error(cause="Download commit", project=obj.project)

for translation in translations:
# Add translation files
if translation.filename:
filenames.add(translation.get_filename())
# Add templates for all components
if translation.component_id in components:
continue
components.add(translation.component_id)
for filename in (
translation.component.template,
translation.component.new_base,
translation.component.intermediate,
):
if filename:
fullname = os.path.join(translation.component.full_path, filename)
if os.path.exists(fullname):
filenames.add(fullname)

return zip_download(data_dir("vcs"), sorted(filenames), name)
if fmt and fmt.startswith("zip:"):
for translation in translations:
response = download_translation_file(request, translation, fmt=fmt[4:])
filename = response["Content-Disposition"].split("=", 1)[1]
extra[filename] = response.content

else:
for translation in translations:
# Add translation files
if translation.filename:
filenames.add(translation.get_filename())
# Add templates for all components
if translation.component_id in components:
continue
components.add(translation.component_id)
for filename in (
translation.component.template,
translation.component.new_base,
translation.component.intermediate,
):
if filename:
fullname = os.path.join(translation.component.full_path, filename)
if os.path.exists(fullname):
filenames.add(fullname)

return zip_download(data_dir("vcs"), sorted(filenames), name, extra=extra)


def download_component_list(request, name):
Expand All @@ -70,6 +78,7 @@ def download_component_list(request, name):
raise PermissionDenied
components = obj.components.filter_access(request.user)
return download_multi(
request,
Translation.objects.filter(component__in=components),
components,
request.GET.get("format"),
Expand Down Expand Up @@ -103,6 +112,7 @@ def download(request, path):
if isinstance(obj, ProjectLanguage):
components = obj.project.component_set.filter_access(request.user)
return download_multi(
request,
Translation.objects.filter(component__in=components, language=obj.language),
[obj.project],
request.GET.get("format"),
Expand All @@ -111,6 +121,7 @@ def download(request, path):
if isinstance(obj, Project):
components = obj.component_set.filter_access(request.user)
return download_multi(
request,
Translation.objects.filter(component__in=components),
[obj],
request.GET.get("format"),
Expand All @@ -121,6 +132,7 @@ def download(request, path):
request.user
).filter(pk__in=obj.category.all_component_ids)
return download_multi(
request,
Translation.objects.filter(component__in=components, language=obj.language),
[obj.category.project],
request.GET.get("format"),
Expand All @@ -131,13 +143,15 @@ def download(request, path):
pk__in=obj.all_component_ids
)
return download_multi(
request,
Translation.objects.filter(component__in=components),
[obj.project],
request.GET.get("format"),
name=obj.slug,
)
if isinstance(obj, Component):
return download_multi(
request,
obj.translation_set.all(),
[obj],
request.GET.get("format"),
Expand Down
17 changes: 11 additions & 6 deletions weblate/utils/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,15 +396,22 @@ def iter_files(filenames):
yield filename


def zip_download(root: str, filenames: list[str], name: str = "translations"):
def zip_download(
root: str,
filenames: list[str],
name: str = "translations",
extra: dict[str, bytes] | None = None,
):
response = HttpResponse(content_type="application/zip")
with ZipFile(response, "w") as zipfile:
for filename in iter_files(filenames):
try:
with open(filename, "rb") as handle:
zipfile.writestr(os.path.relpath(filename, root), handle.read())
zipfile.write(filename, arcname=os.path.relpath(filename, root))
except FileNotFoundError:
continue
if extra:
for filename, content in extra.items():
zipfile.writestr(filename, content)
response["Content-Disposition"] = f'attachment; filename="{name}.zip"'
return response

Expand All @@ -428,9 +435,7 @@ def download_translation_file(
if query_string:
units = units.search(query_string)
exporter.add_units(units)
response = exporter.get_response(
f"{{project}}-{translation.component.slug}-{{language}}.{{extension}}"
)
response = exporter.get_response()
else:
# Force flushing pending units
try:
Expand Down

0 comments on commit cc3cda4

Please sign in to comment.