Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

11085 bilingual file upload #12713

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Not yet released.
* :kbd:`?` now displays available :ref:`keyboard`.
* Translation and language view in the project now include basic information about the language and plurals.
* :ref:`bulk-edit` shows a preview of matched strings.
* Creating component via file upload (Translate document) now supports bilingual files.

**Bug fixes**

Expand Down
7 changes: 7 additions & 0 deletions weblate/trans/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -1850,6 +1850,13 @@ class ComponentDocCreateForm(ComponentProjectForm):
validators=[validate_file_extension],
)

target_language = forms.ModelChoiceField(
widget=SortedSelect,
label=gettext_lazy("Target language"),
help_text=gettext_lazy("Target language of the document for bilingual files"),
queryset=Language.objects.all(),
required=False,
)
field_order = ["docfile", "project", "name", "slug"]

def __init__(self, *args, **kwargs) -> None:
Expand Down
23 changes: 22 additions & 1 deletion weblate/trans/tests/test_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
from django.test.utils import modify_settings, override_settings
from django.urls import reverse

from weblate.lang.models import get_default_lang
from weblate.lang.models import Language, get_default_lang
from weblate.trans.tests.test_views import ViewTestCase
from weblate.trans.tests.utils import create_test_billing, get_test_file
from weblate.vcs.git import GitRepository

TEST_ZIP = get_test_file("translations.zip")
TEST_HTML = get_test_file("cs.html")
TEST_PO = get_test_file("cs.po")


class CreateTest(ViewTestCase):
Expand Down Expand Up @@ -370,6 +371,26 @@ def test_create_doc_category(self) -> None:
self.assertContains(response, "Adding new translation")
self.assertContains(response, "*.html")

@modify_settings(INSTALLED_APPS={"remove": "weblate.billing"})
def test_create_doc_bilingual(self) -> None:
self.user.is_superuser = True
self.user.save()

with open(TEST_PO) as handle, override_settings(CREATE_GLOSSARIES=False):
response = self.client.post(
reverse("create-component-doc"),
{
"docfile": handle,
"name": "Bilingual Component From Doc",
"slug": "bilingual-component-from-doc",
"project": self.project.pk,
"source_language": get_default_lang(),
"target_language": Language.objects.get(code="cs").id,
},
)
self.assertContains(response, "Choose translation files to import")
self.assertNotContains(response, "gettext PO file (monolingual)")

@modify_settings(INSTALLED_APPS={"remove": "weblate.billing"})
def test_create_scratch(self) -> None:
@override_settings(CREATE_GLOSSARIES=self.CREATE_GLOSSARIES)
Expand Down
5 changes: 3 additions & 2 deletions weblate/trans/views/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,9 +415,10 @@ def form_valid(self, form):
return super().form_valid(form)

fake = create_component_from_doc(
form.cleaned_data, form.cleaned_data.pop("docfile")
form.cleaned_data,
form.cleaned_data.pop("docfile"),
form.cleaned_data.pop("target_language", None),
)

# Move to discover phase
self.stage = "discover"
self.initial = form.cleaned_data
Expand Down
17 changes: 11 additions & 6 deletions weblate/utils/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@
if sort_by:
object_list, sort_by = sort_objects(object_list, sort_by)
paginator = Paginator(object_list, limit)
paginator.sort_by = sort_by

Check failure on line 152 in weblate/utils/views.py

View workflow job for this annotation

GitHub Actions / mypy

"Paginator[Any]" has no attribute "sort_by"
try:
return paginator.page(page)
except EmptyPage:
Expand Down Expand Up @@ -240,7 +240,7 @@
# First level is always project
project = get_object_or_404(Project, slug=path.pop(0))
if not skip_acl:
request.user.check_access(project)

Check failure on line 243 in weblate/utils/views.py

View workflow job for this annotation

GitHub Actions / mypy

Item "None" of "AuthenticatedHttpRequest | None" has no attribute "user"
project.acting_user = acting_user
if not path:
check_type(Project)
Expand Down Expand Up @@ -271,14 +271,14 @@
with suppress(Component.DoesNotExist):
current = current.component_set.get(slug=slug, **category_args)
if not skip_acl:
request.user.check_access_component(current)

Check failure on line 274 in weblate/utils/views.py

View workflow job for this annotation

GitHub Actions / mypy

Item "None" of "AuthenticatedHttpRequest | None" has no attribute "user"
current.acting_user = acting_user
break

# Try category
with suppress(Category.DoesNotExist):
current = current.category_set.get(slug=slug, **category_args)

Check failure on line 280 in weblate/utils/views.py

View workflow job for this annotation

GitHub Actions / mypy

Item "Component" of "Project | Category | Component" has no attribute "category_set"
current.acting_user = acting_user

Check failure on line 281 in weblate/utils/views.py

View workflow job for this annotation

GitHub Actions / mypy

Item "Category" of "Any | Category" has no attribute "acting_user"
category_args = {}
continue

Expand All @@ -296,7 +296,7 @@
if not allowed_types & {Translation, Unit}:
raise UnsupportedPathObjectError("No remaining supported object type")

translation = get_object_or_404(current.translation_set, language__code=path.pop(0))

Check failure on line 299 in weblate/utils/views.py

View workflow job for this annotation

GitHub Actions / mypy

Item "Project" of "Project | Category | Component" has no attribute "translation_set"

Check failure on line 299 in weblate/utils/views.py

View workflow job for this annotation

GitHub Actions / mypy

Item "Category" of "Project | Category | Component" has no attribute "translation_set"
if not path:
check_type(Translation)
return translation
Expand Down Expand Up @@ -386,26 +386,31 @@
data["filemask"] = "{}/{}{}".format(data.get("slug", "translations"), "*", ext)


def create_component_from_doc(data, docfile):
def create_component_from_doc(data, docfile, target_language: Language | None = None):
# Calculate filename
uploaded = docfile or data["docfile"]
guess_filemask_from_doc(data, uploaded)
filemask = data["filemask"]
filename = filemask.replace(
"*",
data["source_language"].code
file_language_code = (
target_language.code
if target_language # bilingual file
else data["source_language"].code
if "source_language" in data
else settings.DEFAULT_LANGUAGE,
else settings.DEFAULT_LANGUAGE
)
filename = filemask.replace("*", file_language_code)
# Create fake component (needed to calculate path)
fake = Component(
project=data["project"],
slug=data["slug"],
name=data["name"],
category=data.get("category", None),
template=filename,
filemask=filemask,
)

if not target_language:
fake.template = filename

# Create repository
LocalRepository.from_files(fake.full_path, {filename: uploaded.read()})
return fake
Expand Down Expand Up @@ -465,7 +470,7 @@
extra: dict[str, bytes] | None = None,
):
response = HttpResponse(content_type="application/zip")
with ZipFile(response, "w", strict_timestamps=False) as zipfile:

Check failure on line 473 in weblate/utils/views.py

View workflow job for this annotation

GitHub Actions / mypy

No overload variant of "ZipFile" matches argument types "HttpResponse", "str", "bool"
for filename in iter_files(filenames):
try:
zipfile.write(filename, arcname=os.path.relpath(filename, root))
Expand Down Expand Up @@ -539,7 +544,7 @@
else:
extension = ".zip"
response = zip_download(
translation.get_filename(),

Check failure on line 547 in weblate/utils/views.py

View workflow job for this annotation

GitHub Actions / mypy

Argument 1 to "zip_download" has incompatible type "str | None"; expected "str"
filenames,
translation.full_slug.replace("/", "-"),
)
Expand Down Expand Up @@ -590,6 +595,6 @@
show_form_errors(self.request, form)
return HttpResponseRedirect(self.get_success_url())

def get(self, request: AuthenticatedHttpRequest, *args, **kwargs):

Check failure on line 598 in weblate/utils/views.py

View workflow job for this annotation

GitHub Actions / mypy

Argument 1 of "get" is incompatible with supertype "ProcessFormView"; supertype defines the argument type as "HttpRequest"
"""There is no GET view here."""
return HttpResponseRedirect(self.get_success_url())
Loading