Skip to content

fix(cli): make lint-translations exit non-zero when translations differ - #2996

Open
Zuhef wants to merge 2 commits into
Chainlit:mainfrom
Zuhef:fix/lint-translations-exit-code
Open

fix(cli): make lint-translations exit non-zero when translations differ#2996
Zuhef wants to merge 2 commits into
Chainlit:mainfrom
Zuhef:fix/lint-translations-exit-code

Conversation

@Zuhef

@Zuhef Zuhef commented Jul 29, 2026

Copy link
Copy Markdown

Problem

chainlit lint-translations reports differences and then exits 0, so it cannot gate anything. Issue #2993 identified this as the reason locale keys drift unnoticed, and it is true even for the app translations the command is actually pointed at.

The chain is silent end to end:

  • lint_translation_json prints the differences and returns None
  • lint_translations returns None
  • chainlit_lint_translations calls it and ignores the result, so Click exits 0

Change

  • lint_translation_json returns the differences it printed. Additive - existing callers that ignore the return value are unaffected, and the printed output is unchanged.
  • lint_translations returns the total count across all linted files.
  • The CLI command prints a summary and raises SystemExit(1) when the count is non-zero.

Two incidental cleanups in the same function: the per-file loop was nested inside the ground-truth with open(...) block, holding that handle open for the entire run, so it is dedented; and os.listdir is now sorted so the report order is deterministic. Happy to drop either if you would rather keep the diff to the exit code alone.

Verification

Ran on Windows against a directory containing all 23 packaged locales, comparing a clean main worktree with the patched tree:

files linted differences reported exit code
main 23 6 0
patched 23 6 1

Same six differences either way - only the exit code changes. A directory whose translations match the ground truth still exits 0.

The six it finds are the real gaps from #2993, which is a useful independent cross-check: this is the CLI path rather than the test suite, and it reports exactly chat.favorites.remove (ar-SA, da-DK), components.DatePickerInput (de-DE, it, ko) and chat.fileUpload.browse (ja).

pytest backend/tests/test_translations.py - 41 passed. That is the 39 from this PR plus the two cp1252 regression tests added by #3006, both preserved through the rebase. New tests here cover the returned error list, the aggregate count for both clean and broken input, and that non-JSON files in the directory are ignored.

ruff format --check clean on all four files. ruff check reports two RUF036 findings at config.py:477-478 (on_app_startup / on_app_shutdown), which are pre-existing on main and untouched by this change.

Note

The UnicodeEncodeError I originally flagged in this section - a stock Windows console cannot encode the / markers - was filed as #2997 and fixed upstream by #3006 while this PR was open. So that note is resolved, and #3006 touching the same two files is what produced the merge conflicts.

Now rebased onto current main. The conflicts were both mechanical:

One follow-through worth calling out: the summary line this PR adds also carries a , so it now goes through #3006's _safe_print rather than a bare print. Otherwise the CLI layer would reintroduce in the command exactly the crash #3006 just fixed in the library. Verified against a cp1252 stdout - the command still exits 1 and the marker degrades to ? instead of raising. Happy to add a regression test for that CLI path, or to drop the change, whichever you prefer.


Summary by cubic

Make chainlit lint-translations fail fast when translations differ. Previously it printed differences and exited 0; now it exits 1 so CI can gate locale changes.

  • lint_translation_json returns the list of differences (printed output unchanged).
  • lint_translations returns the total difference count and sorts the directory listing for deterministic reports.
  • The CLI prints a summary and exits 1 when the count is non-zero.
  • Moved the per-file loop out of the ground-truth with open(...) block to avoid holding the handle open.
  • Tests cover returned errors, aggregate counts for clean/broken inputs, and ignoring non-JSON files.

Written for commit af2f7ad. Summary will update on new commits.

Review in cubic

@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. bug Something isn't working translation Translation or localisation of strings. unit-tests Has unit tests. labels Jul 29, 2026

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 4 files

Re-trigger cubic

@dokterbob

Copy link
Copy Markdown
Collaborator

@codex review

Copilot AI 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.

Pull request overview

Updates the translation linter so translation differences can reliably fail CI.

Changes:

  • Returns detected differences and aggregates their count.
  • Produces deterministic file ordering.
  • Exits with status 1 and prints a summary when differences exist.
  • Adds coverage for return values, counting, and file filtering.

Reviewed changes

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

File Description
backend/chainlit/translations.py Returns detected structural differences.
backend/chainlit/config.py Aggregates differences across sorted translation files.
backend/chainlit/cli/__init__.py Exits non-zero when differences are found.
backend/tests/test_translations.py Tests difference reporting and aggregation.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@dokterbob
dokterbob enabled auto-merge August 17, 2026 17:16

@dokterbob dokterbob left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM.

@dokterbob
dokterbob added this pull request to the merge queue Aug 17, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Aug 17, 2026

@dokterbob dokterbob left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@Zuhef Would you be able to resolve the merge conflicts, please?

`chainlit lint-translations` reported differences and then exited 0, so it
could not be used as a CI gate - which is how missing locale keys accumulate
unnoticed.

The chain was silent end to end: `lint_translation_json` printed the
differences and returned None, `lint_translations` returned None, and the
command ignored the result. On a checkout of main the command reports six real
missing keys across the packaged locales and still exits 0.

`lint_translation_json` now returns the differences it printed, and
`lint_translations` returns the total count, so the command can fail. Both are
additive: existing callers that ignore the return value are unaffected.

Also dedent the per-file loop out of the ground-truth `with open(...)` block,
which held that handle open for the whole run, and sort the directory listing
so the report order is deterministic.

Rebased onto main after Chainlit#3006, which introduced `_safe_print`. The new summary
line carries a marker that cp1252 cannot encode, so it goes through
`_safe_print` too rather than a bare `print` - otherwise the CLI layer would
reintroduce the UnicodeEncodeError that Chainlit#3006 just fixed in the library layer.

Verified on Windows against a directory holding all 23 packaged locales:
before, 6 differences reported and exit 0; after, the same 6 differences and
exit 1. A clean directory still exits 0, and a broken one on a cp1252 stdout
still exits 1 with the marker degraded instead of crashing.
@Zuhef
Zuhef force-pushed the fix/lint-translations-exit-code branch from af2f7ad to c700d1a Compare August 25, 2026 17:33
@Zuhef

Zuhef commented Aug 25, 2026

Copy link
Copy Markdown
Author

Done — rebased onto main and the conflicts are resolved. Force-pushed as c700d1a, so this is a single commit again and GitHub now reports it mergeable.

The conflicts came from #3006, which landed in the same two functions while this was open. Both sides were mechanical:

One change beyond the merge itself, which I want to flag explicitly rather than slip in: the summary line this PR adds also carries a , so I routed it through _safe_print instead of a bare print. Otherwise the CLI layer would reintroduce in the command the exact crash #3006 just fixed in the library. Verified against a cp1252 stdout — the command still exits 1 and the marker degrades to ? instead of raising. Happy to add a regression test for that CLI path, or to drop the change entirely, whichever you prefer.

ruff format --check is clean on all four files. ruff check still reports the two pre-existing RUF036 findings at config.py:477-478 (on_app_startup / on_app_shutdown), which are on main already and untouched here.

Two notes:

@dokterbob

Copy link
Copy Markdown
Collaborator

Done — rebased onto main and the conflicts are resolved. Force-pushed as c700d1a, so this is a single commit again and GitHub now reports it mergeable.

The conflicts came from #3006, which landed in the same two functions while this was open. Both sides were mechanical:

One change beyond the merge itself, which I want to flag explicitly rather than slip in: the summary line this PR adds also carries a , so I routed it through _safe_print instead of a bare print. Otherwise the CLI layer would reintroduce in the command the exact crash #3006 just fixed in the library. Verified against a cp1252 stdout — the command still exits 1 and the marker degrades to ? instead of raising. Happy to add a regression test for that CLI path, or to drop the change entirely, whichever you prefer.

ruff format --check is clean on all four files. ruff check still reports the two pre-existing RUF036 findings at config.py:477-478 (on_app_startup / on_app_shutdown), which are on main already and untouched here.

Two notes:

I'll need to take some time to manual review as this is clearly a bot talking.

Please consider marking bot posts and PR's as such (e.g. through a GH app or marked-as-such bot account).

@Zuhef

Zuhef commented Aug 25, 2026

Copy link
Copy Markdown
Author

I manually reviewed the changes, conflict resolution, and tests before pushing. AI was only used to help rephrase the PR documentation..

@dokterbob
dokterbob enabled auto-merge August 26, 2026 09:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working size:M This PR changes 30-99 lines, ignoring generated files. translation Translation or localisation of strings. unit-tests Has unit tests.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants