Skip to content

fix: HTML and lazy formatting#18213

Merged
nijel merged 1 commit intoWeblateOrg:mainfrom
nijel:html-format
Feb 25, 2026
Merged

fix: HTML and lazy formatting#18213
nijel merged 1 commit intoWeblateOrg:mainfrom
nijel:html-format

Conversation

@nijel
Copy link
Member

@nijel nijel commented Feb 25, 2026

  • use format_html to format HTML safe blocks, otherwise they end up double escaped
  • avoid formatting lazy strings, these would be evaluated prematurely
  • add pre-commit rules to catch these

@nijel nijel added this to the 5.16.1 milestone Feb 25, 2026
@nijel nijel self-assigned this Feb 25, 2026
@nijel nijel enabled auto-merge (rebase) February 25, 2026 13:52
@nijel nijel requested a review from Copilot February 25, 2026 13:52
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request fixes HTML double-escaping issues and prevents premature evaluation of lazy translation strings. The changes replace percent-formatting operations on format_html_join_comma() results with format_html() to properly combine HTML-safe strings, and switch from gettext_lazy() to gettext() where string formatting is needed.

Changes:

  • Refactored HTML formatting to use format_html() instead of percent-formatting with format_html_join_comma() to avoid double escaping
  • Changed gettext_lazy() to gettext() where dynamic formatting is required to prevent premature evaluation
  • Added pre-commit hooks to catch these patterns in future code
  • Added test coverage for HTML entity escaping in ICU check descriptions

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
weblate/trans/views/edit.py Fixed display_fixups to use format_html with ngettext and format_html_join_comma
weblate/trans/models/component.py Fixed error message formatting in clean_new_lang validation
weblate/trans/forms.py Fixed ValidationError message in project access control validation
weblate/middleware.py Changed gettext_lazy to gettext for formatted message
weblate/memory/forms.py Moved help_text formatting to init to use gettext instead of gettext_lazy
weblate/checks/tests/test_icu_checks.py Added test to verify HTML entity escaping in check descriptions
weblate/checks/icu.py Updated format_result method to use format_html pattern throughout
weblate/checks/format.py Fixed format_result to use format_html pattern
weblate/checks/consistency.py Fixed get_description to use format_html pattern
.pre-commit-config.yaml Added hooks to detect percent-formatting with format_html_join_comma and formatting lazy strings
Comments suppressed due to low confidence (2)

.pre-commit-config.yaml:155

  • The regex pattern has a potential issue: the dot before 'format' should be escaped as '.' to match a literal dot character. Currently, '.' matches any single character, which could lead to false positives. The pattern should be: 'gettext_lazy([^\)])(\s%|.format('
    entry: gettext_lazy\([^\)]*\)(\s*%|.format\()

weblate/checks/consistency.py:198

  • The percent formatting operation on the gettext result could lead to improper HTML escaping if the source string contains HTML special characters like '<', '>', or '&'. Consider using format_html() to properly escape the source value before passing it to format_html_join_comma. For example: format_html_join_comma("{}", ((format_html('"{}"', source),) for source in other_sources))
                "{}", ((gettext("“%s”") % source,) for source in other_sources)

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

.pre-commit-config.yaml:156

  • The py-lazy-format hook regex looks incorrect: .format\( is using an unescaped . (matches any char) and also doesn’t allow whitespace before the dot, so it won’t match common patterns like gettext_lazy(...) .format(...) or gettext_lazy(...) .format(...). Consider adjusting the pattern to something like \s*%|\s*\.format\( (with the dot escaped) so the hook reliably catches lazy-string formatting.
  - id: py-lazy-format
    name: Formatting a lazy translation
    types: [python]
    args: [--multiline]
    entry: gettext_lazy\([^\)]*\)(\s*%|.format\()
    language: pygrep

weblate/trans/views/edit.py:89

  • fixups can contain lazy translation objects (e.g., AutoFix.name is often gettext_lazy(...)), not just plain str. The new annotation fixups: list[str] is therefore misleading for typing/mypy; consider using a type like Sequence[StrOrPromise] (or similar) to reflect actual values passed in.
def display_fixups(request: AuthenticatedHttpRequest, fixups: list[str]) -> None:

@codecov
Copy link

codecov bot commented Feb 25, 2026

Codecov Report

❌ Patch coverage is 62.50000% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.02%. Comparing base (f3d0988) to head (aaaf383).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
weblate/checks/icu.py 16.66% 10 Missing ⚠️
weblate/checks/consistency.py 50.00% 1 Missing ⚠️
weblate/trans/models/component.py 0.00% 1 Missing ⚠️

❌ Your patch status has failed because the patch coverage (62.50%) is below the target coverage (100.00%). You can increase the patch coverage or adjust the target coverage.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- use format_html to format HTML safe blocks, otherwise they end up
  double escaped
- avoid formatting lazy strings, these would be evaluated prematurely
- add pre-commit rules to catch these
@nijel nijel merged commit 8f6b6a7 into WeblateOrg:main Feb 25, 2026
51 of 52 checks passed
@nijel nijel deleted the html-format branch February 25, 2026 15:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants