Skip to content

feat(validator): HTML-tag-mismatch + _maintainer shape + wire validate-packs into CI - #72

Merged
teamssUTXO merged 4 commits into
btcpayserver:mainfrom
r1ckstardev:feat/anti-slop-html-maintainer-ci
May 29, 2026
Merged

feat(validator): HTML-tag-mismatch + _maintainer shape + wire validate-packs into CI#72
teamssUTXO merged 4 commits into
btcpayserver:mainfrom
r1ckstardev:feat/anti-slop-html-maintainer-ci

Conversation

@r1ckstardev

Copy link
Copy Markdown
Collaborator

@teamssUTXO - opening this PR from the anti-slop pass discussion in -5292199939 2026-05-26. Closes 3 of the 4 gaps I surfaced when walking the existing validator infrastructure (msg 486); the 4th (broader identical-to-English check) is deliberately left for a follow-up because expanding the ShortKeyHotspotKeys list requires per-language maintainer judgment on which anglicisms are acceptable.

What

(a) HTML-tag-mismatch rule

TranslationValidationRules.HasMatchingHtmlTags(source, translation) compares the multiset of structural HTML tags between source and translation. Restricted to a curated allowlist of real markup elements (strong/em/b/i/code/pre/kbd/a/span/p/div/br/ul/ol/li/h1-6/table family/abbr/del/ins/q/cite/var/samp/mark/small/sub/sup/u) so localized example data (<email@primer.com>, <John Doe>) doesn't trip the rule. Catches the same shape today's anti-slop pass found on hindi.json (3), indonesian.json (1), and thai.json (2) - translation drops a closing </strong> or </code> pair, silently breaks UI rendering. No auto-fix path - restoring the English source would lose the translated prose around the tags.

(d) _maintainer field validation

TranslationValidationRules.IsValidMaintainerValue(value) checks the field shape ManifestGenerator expects: <display name or handle>|<https URL>. Missing pipe, missing URL, or non-https URL all fail. LanguagePackValidator skips the _maintainer entry from the translation-entry pipeline (it's metadata, not a translation) and runs the shape check separately.

(c) Wire validate-packs into tests.yml CI

New step in the existing unit-tests job runs dotnet run -- validate-packs after the test step, with Translation__OutputDirectory pointed at the repo's translations folder. Step is continue-on-error: true initially so the new HTML-tag rule surfaces the existing hindi/indonesian/thai issues without blocking unrelated PRs. Once those fixes land, drop continue-on-error to gate new slop from landing.

Tests

5 new tests in LanguagePackValidatorTests:

  • ValidateAsync_FlagsHtmlTagMismatch
  • ValidateAsync_IgnoresExampleEmailAngleBrackets
  • ValidateAsync_FlagsInvalidMaintainerField
  • ValidateAsync_AcceptsWellFormedMaintainerField
  • ValidateAsync_RejectsMaintainerWithHttpScheme

9/9 LanguagePackValidatorTests passing locally. Build clean.

Out of scope

Item (b) - broader identical-to-English check beyond ShortKeyHotspotKeys. The anti-slop pass found ~30 per-language identical-to-English entries (Checkout, Downgrade, Hostname, etc.); many are acceptable anglicisms (Login, Logo, Online, Token) and which to translate is per-language maintainer judgment. Adding a generic rule risks false-positive churn. Either expand the hotspot list incrementally as patterns surface, OR add a --strict report-only flag in a follow-up.

Pre-existing issues this surfaces

The validate-packs step (continue-on-error) will report:

  • hindi.json: 3 HTML-tag-mismatch entries (Khush + Abhijay7 to fix)
  • indonesian.json: 1 HTML-tag-mismatch entry (no maintainer set)
  • thai.json: 2 HTML-tag-mismatch entries (no maintainer set)
  • romanian.json: Text pre-existing hotspot-key issue

None are introduced by this PR; they were latent before. The CI step makes them visible.

…re validate-packs into CI

Anti-slop pass on Phase 4 surfaced 4 gaps in the existing validator
infrastructure (Tim msg 486 in TG -5292199939 2026-05-26). This PR
closes 3 of them; the 4th (broader identical-to-English check beyond
the curated ShortKeyHotspotKeys list) is deliberately left for a
follow-up because expanding the hotspot list requires per-language
maintainer judgment on which anglicisms are acceptable.

## What

### (a) HTML-tag-mismatch rule

`TranslationValidationRules.HasMatchingHtmlTags(source, translation)`
compares the multiset of structural HTML tags between source and
translation. Restricted to a curated allowlist of real markup
elements (strong/em/b/i/code/pre/kbd/a/span/p/div/br/ul/ol/li/h1-6/
table family/abbr/del/ins/q/cite/var/samp/mark/small/sub/sup/u) so
localized example data ('<email@primer.com>', '<John Doe>') doesn't
trip the rule. Catches the same shape my anti-slop pass found on
hindi.json (3 entries) + indonesian.json (1) + thai.json (2):
translation drops a closing </strong> or </code> pair, silently
breaks UI rendering.

No auto-fix path - restoring the English source would lose the
translated prose around the tags. Maintainer needs to re-anchor the
markup by hand.

### (d) _maintainer field validation

`TranslationValidationRules.IsValidMaintainerValue(value)` checks
the field shape ManifestGenerator expects:
`<display name or handle>|<https URL>`. Missing pipe, missing URL,
or non-https URL fail validation. Empty / whitespace value (field
present-but-unset) also fails. LanguagePackValidator skips the
_maintainer entry from the translation-entry pipeline (it's
metadata, not a translation) and runs the shape check separately.

### (c) Wire validate-packs into tests.yml CI

New step in the existing 'unit-tests' job runs
`dotnet run -- validate-packs` after the test step, with
Translation__OutputDirectory pointed at the repo's translations
folder. Step is marked continue-on-error: true initially so the new
HTML-tag rule surfaces the existing hindi/indonesian/thai issues
without blocking unrelated PRs. Once those land follow-up fixes,
drop continue-on-error to gate new slop from landing.

## Tests

5 new tests in LanguagePackValidatorTests:

- ValidateAsync_FlagsHtmlTagMismatch
- ValidateAsync_IgnoresExampleEmailAngleBrackets
- ValidateAsync_FlagsInvalidMaintainerField
- ValidateAsync_AcceptsWellFormedMaintainerField
- ValidateAsync_RejectsMaintainerWithHttpScheme

9/9 LanguagePackValidatorTests passing. Build clean.

## Out of scope

Item (b) - broader identical-to-English check beyond the
ShortKeyHotspotKeys list. The anti-slop pass found ~30 per-language
identical-to-English entries (Checkout, Downgrade, Hostname, etc.);
many are acceptable anglicisms (Login, Logo, Online, Token) and
which to translate is per-language maintainer judgment. Adding a
generic rule risks false-positive churn. Either expand the hotspot
list incrementally as patterns surface, OR add a strict-mode
report-only check in a follow-up.

## Pre-existing issues this surfaces

The validate-packs step (continue-on-error) will report:

- hindi.json: 3 HTML-tag-mismatch entries (Khush + Abhijay007 to fix)
- indonesian.json: 1 HTML-tag-mismatch entry (no maintainer set)
- thai.json: 2 HTML-tag-mismatch entries (no maintainer set)
- romanian.json: 'Text' pre-existing hotspot-key issue

None of these are introduced by this PR; they were latent before.
The CI step makes them visible.
Forgotten in the previous commit on this branch. Step runs the
validate-packs CLI after the unit-tests step with the in-repo
translations/ folder as input. continue-on-error: true keeps the
step report-only until the pre-existing HTML-tag-mismatch issues
in hindi/indonesian/thai are fixed by their maintainers.
@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@teamssUTXO, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 41 minutes and 51 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 76a7cc6e-3f7a-4a5c-b2d9-eb615915a485

📥 Commits

Reviewing files that changed from the base of the PR and between 5729180 and 0cb2734.

📒 Files selected for processing (3)
  • Translator.Tests/Services/LanguagePackValidatorTests.cs
  • Translator/Services/LanguagePackValidator.cs
  • Translator/Services/TranslationValidationRules.cs
📝 Walkthrough

Walkthrough

The PR enhances the language pack validator by adding two new validation rules: structural HTML tag matching between source and translated strings, and maintainer field format validation. Integration into the validator's control flow, comprehensive test coverage, and CI enablement follow.

Changes

Translation Validation Enhancement

Layer / File(s) Summary
Validation rules for HTML tags and maintainer
Translator/Services/TranslationValidationRules.cs
New HasMatchingHtmlTags and IsValidMaintainerValue validators with regex patterns for allowed structural tags (strong, em, code, tables, etc.) and maintainer format (name|https://...). Helper methods extract and count tag occurrences.
Integrate validators into LanguagePackValidator
Translator/Services/LanguagePackValidator.cs
_maintainer field receives dedicated validation via IsValidMaintainerValue, skipping general string validation on invalid formats. HTML tag mismatches are reported without auto-fix. Short-key English-fallback conditions now continue to prevent fallthrough.
Test HTML tag and maintainer validation
Translator.Tests/Services/LanguagePackValidatorTests.cs
New tests verify HTML tag structural mismatch detection, email example angle-bracket allowlisting, _maintainer rejection of invalid/http-scheme formats, and acceptance of well-formed values.
Add validation step to CI workflow
.github/workflows/tests.yml
New non-blocking workflow step runs validate-packs with Translation__OutputDirectory pointing to the workspace translations directory.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • btcpayserver/btcpayserver-translator#50: Extended validation pipeline that introduced the base LanguagePackValidator and TranslationValidationRules architecture, now augmented with the _maintainer and HTML tag validation rules.

Poem

🐰 Tags aligned, maintainers now checked,
With HTML rigor and URLs stacked,
Translation packs dance in CI's delight,
Structure validated, everything's right!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the three main changes: HTML-tag-mismatch validation, _maintainer field validation, and CI integration with validate-packs.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, covering the implementation details, test coverage, and pre-existing issues surfaced.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Translator/Services/TranslationValidationRules.cs`:
- Around line 281-283: IsValidMaintainerValue currently returns true for
null/whitespace which lets blank _maintainer fields pass; change the logic so
that string.IsNullOrWhiteSpace(value) causes the method to return false (reject
blank values when the field is present) and then continue enforcing the existing
required "name|https://..." shape check (the same validation already applied
elsewhere in IsValidMaintainerValue). Update the branch in
TranslationValidationRules.cs inside IsValidMaintainerValue (remove/flip the
current if that returns true for whitespace) so blank or whitespace values fail
validation while preserving the subsequent pattern validation logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a9b634bc-0d5f-48dc-a9a0-f6a719ad6aa7

📥 Commits

Reviewing files that changed from the base of the PR and between 81c63d8 and 5729180.

📒 Files selected for processing (4)
  • .github/workflows/tests.yml
  • Translator.Tests/Services/LanguagePackValidatorTests.cs
  • Translator/Services/LanguagePackValidator.cs
  • Translator/Services/TranslationValidationRules.cs

Comment thread Translator/Services/TranslationValidationRules.cs
@teamssUTXO
teamssUTXO merged commit 202b171 into btcpayserver:main May 29, 2026
2 checks passed
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