From 79d75f79261bb810b13882a421094bd987e6980e Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Sun, 26 Apr 2026 20:36:50 +1000 Subject: [PATCH] Translations - Playwright macro unused, add extra linting for translations, add TRANSLATORS.md (#4087) --- .github/workflows/test-only.yml | 60 ++++- README.md | 2 + .../blueprint/ui/templates/edit.html | 2 +- changedetectionio/templates/_helpers.html | 9 - changedetectionio/translations/README.md | 254 +++++++++++++----- .../translations/cs/LC_MESSAGES/messages.mo | Bin 40713 -> 40713 bytes .../translations/cs/LC_MESSAGES/messages.po | 21 +- .../translations/de/LC_MESSAGES/messages.mo | Bin 51159 -> 50187 bytes .../translations/de/LC_MESSAGES/messages.po | 25 +- .../en_GB/LC_MESSAGES/messages.mo | Bin 493 -> 493 bytes .../en_GB/LC_MESSAGES/messages.po | 21 +- .../en_US/LC_MESSAGES/messages.mo | Bin 807 -> 807 bytes .../en_US/LC_MESSAGES/messages.po | 21 +- .../translations/es/LC_MESSAGES/messages.mo | Bin 72614 -> 71673 bytes .../translations/es/LC_MESSAGES/messages.po | 25 +- .../translations/fr/LC_MESSAGES/messages.mo | Bin 37047 -> 37047 bytes .../translations/fr/LC_MESSAGES/messages.po | 21 +- .../translations/it/LC_MESSAGES/messages.mo | Bin 21800 -> 21800 bytes .../translations/it/LC_MESSAGES/messages.po | 21 +- .../translations/ja/LC_MESSAGES/messages.mo | Bin 90610 -> 89615 bytes .../translations/ja/LC_MESSAGES/messages.po | 23 +- .../translations/ko/LC_MESSAGES/messages.mo | Bin 32696 -> 32696 bytes .../translations/ko/LC_MESSAGES/messages.po | 21 +- changedetectionio/translations/messages.pot | 21 +- .../pt_BR/LC_MESSAGES/messages.mo | Bin 70837 -> 69905 bytes .../pt_BR/LC_MESSAGES/messages.po | 25 +- .../translations/tr/LC_MESSAGES/messages.mo | Bin 71731 -> 70781 bytes .../translations/tr/LC_MESSAGES/messages.po | 25 +- .../translations/uk/LC_MESSAGES/messages.mo | Bin 85442 -> 84357 bytes .../translations/uk/LC_MESSAGES/messages.po | 23 +- .../translations/zh/LC_MESSAGES/messages.mo | Bin 58537 -> 57681 bytes .../translations/zh/LC_MESSAGES/messages.po | 23 +- .../zh_Hant_TW/LC_MESSAGES/messages.mo | Bin 44637 -> 43774 bytes .../zh_Hant_TW/LC_MESSAGES/messages.po | 23 +- 34 files changed, 264 insertions(+), 402 deletions(-) diff --git a/.github/workflows/test-only.yml b/.github/workflows/test-only.yml index 04958b7e..246d254c 100644 --- a/.github/workflows/test-only.yml +++ b/.github/workflows/test-only.yml @@ -44,10 +44,60 @@ jobs: exit 1 fi + lint-template-i18n: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: Check for fragmented gettext calls in templates + run: | + python3 << 'PYEOF' + import re, sys + from pathlib import Path + + # Detects adjacent {{ _(...) }} calls on the same line separated only by HTML + # tags, whitespace, or non-translating Jinja2 variables — the anti-pattern of + # splitting a single sentence across multiple msgids. + # See https://github.com/dgtlmoon/changedetection.io/issues/4074 for background. + # + # The correct fix is to consolidate fragments into one entire-sentence msgid, + # injecting dynamic values via %(name)s kwargs — per the GNU gettext manual + # sections "Entire sentences" and "No string concatenation". See PR #4076 for + # worked examples of each consolidation pattern. + # + # BASELINE: this limit reflects pre-existing violations present when this check + # was introduced. It must only ever go DOWN. Each time you fix a template, lower + # the limit by the number of lines fixed so the improvement is locked in. + # When the count reaches 0, replace the baseline check with a hard sys.exit(1). + BASELINE_LIMIT = 44 + + FRAGMENT_RE = re.compile( + r'\{\{[^{}]*\b_\s*\([^)]*\)[^{}]*\}\}' + r'(?:\s*(?:<[^>]+>|\{\{(?![^}]*\b_\s*\()[^}]*\}\})\s*)+' + r'\{\{[^{}]*\b_\s*\([^)]*\)[^{}]*\}\}' + ) + + violations = [] + for f in sorted(Path('changedetectionio').rglob('*.html')): + for lineno, line in enumerate(f.read_text().splitlines(), 1): + if FRAGMENT_RE.search(line): + violations.append(f"{f}:{lineno}: {line.strip()[:120]}") + + count = len(violations) + print(f"Fragmented i18n calls found: {count} (limit: {BASELINE_LIMIT})") + for v in violations: + print(v) + + if count > BASELINE_LIMIT: + print(f"\nERROR: {count} fragmented gettext calls exceed the baseline of {BASELINE_LIMIT}.") + print("Consolidate adjacent _() calls into a single entire-sentence msgid.") + print("See https://github.com/dgtlmoon/changedetection.io/issues/4074 for patterns.") + sys.exit(1) + PYEOF + test-application-3-10: # Only run on push to master (including PR merges) if: github.event_name == 'push' && github.ref == 'refs/heads/master' - needs: [lint-code, lint-translations] + needs: [lint-code, lint-translations, lint-template-i18n] uses: ./.github/workflows/test-stack-reusable-workflow.yml with: python-version: '3.10' @@ -55,7 +105,7 @@ jobs: test-application-3-11: # Always run - needs: [lint-code, lint-translations] + needs: [lint-code, lint-translations, lint-template-i18n] uses: ./.github/workflows/test-stack-reusable-workflow.yml with: python-version: '3.11' @@ -63,7 +113,7 @@ jobs: test-application-3-12: # Only run on push to master (including PR merges) if: github.event_name == 'push' && github.ref == 'refs/heads/master' - needs: [lint-code, lint-translations] + needs: [lint-code, lint-translations, lint-template-i18n] uses: ./.github/workflows/test-stack-reusable-workflow.yml with: python-version: '3.12' @@ -72,7 +122,7 @@ jobs: test-application-3-13: # Only run on push to master (including PR merges) if: github.event_name == 'push' && github.ref == 'refs/heads/master' - needs: [lint-code, lint-translations] + needs: [lint-code, lint-translations, lint-template-i18n] uses: ./.github/workflows/test-stack-reusable-workflow.yml with: python-version: '3.13' @@ -81,7 +131,7 @@ jobs: test-application-3-14: #if: github.event_name == 'push' && github.ref == 'refs/heads/master' - needs: [lint-code, lint-translations] + needs: [lint-code, lint-translations, lint-template-i18n] uses: ./.github/workflows/test-stack-reusable-workflow.yml with: python-version: '3.14' diff --git a/README.md b/README.md index 4eedf4e9..db10fe57 100644 --- a/README.md +++ b/README.md @@ -352,4 +352,6 @@ changedetectionio.html_tools.elementpath_tostring: Copyright (c), 2018-2021, SIS Recognition of fantastic contributors to the project +Developer note: see [translation guide](changedetectionio/translations/README.md) for i18n template patterns and workflow. + - Constantin Hong https://github.com/Constantin1489 diff --git a/changedetectionio/blueprint/ui/templates/edit.html b/changedetectionio/blueprint/ui/templates/edit.html index 73aa0d2e..799133ae 100644 --- a/changedetectionio/blueprint/ui/templates/edit.html +++ b/changedetectionio/blueprint/ui/templates/edit.html @@ -1,6 +1,6 @@ {% extends 'base.html' %} {% block content %} -{% from '_helpers.html' import render_field, render_checkbox_field, render_button, render_time_schedule_form, playwright_warning, only_playwright_type_watches_warning, highlight_trigger_ignored_explainer, render_conditions_fieldlist_of_formfields_as_table, render_ternary_field %} +{% from '_helpers.html' import render_field, render_checkbox_field, render_button, render_time_schedule_form, only_playwright_type_watches_warning, highlight_trigger_ignored_explainer, render_conditions_fieldlist_of_formfields_as_table, render_ternary_field %} {% from '_common_fields.html' import render_common_settings_form %} diff --git a/changedetectionio/templates/_helpers.html b/changedetectionio/templates/_helpers.html index 882373b6..2b30ab00 100644 --- a/changedetectionio/templates/_helpers.html +++ b/changedetectionio/templates/_helpers.html @@ -179,15 +179,6 @@ {% endmacro %} - -{% macro playwright_warning() %} -

{{ _('Error - This watch needs Chrome (with playwright/sockpuppetbrowser), but Chrome based fetching is not enabled.') }} {{ _('Alternatively try our') }} {{ _('very affordable subscription based service which has all this setup for you') }}.

-

{{ _('You may need to Enable playwright environment variable and uncomment the sockpuppetbrowser in the docker-compose.yml file.', - url_pinned='https://github.com/dgtlmoon/changedetection.io/blob/09ebc6ec6338545bdd694dc6eee57f2e9d2b8075/docker-compose.yml#L31', - url_master='https://github.com/dgtlmoon/changedetection.io/blob/master/docker-compose.yml')|safe }}

-
-{% endmacro %} - {% macro render_time_schedule_form(form, available_timezones, timezone_default_config) %}