Skip to content

Query builder: notes follow the user's language - #18

Merged
Liebmann5 merged 1 commit into
mainfrom
work/localise-notes
Oct 28, 2026
Merged

Liebmann5 merged 1 commit into
mainfrom
work/localise-notes

Conversation

@Liebmann5

@Liebmann5 Liebmann5 commented Oct 28, 2026 •

Copy link
Copy Markdown
Owner

What this changes

Every note the query builder shows — refusals and explanations, on both the CLI and the GUI — now renders in the user's language. Previously every note was an English sentence even when the rest of the screen was Spanish.

Why

AA's rule is that every user-facing string goes through the locale. The composer built its notes as finished English strings, and format_result_lines printed them verbatim, so a Spanish user saw Spanish labels next to English notes (measured in the GUI: "Google has no place for a location, so 'Seattle, WA' was left out of the search.").

How it was verified

Full suite on Windows:

2419 passed, 5 skipped, 1 xfailed   (was 2415 / 5 / 1; +4 tests)
  • CLI checked with the

Summary by Sourcery

Localize query-builder notes across the CLI and GUI while retaining safe English fallbacks.

New Features:

  • Render query-builder notes in the user's active language across CLI and GUI surfaces.
  • Add localized templates and parameter substitution for query-builder notes with English fallbacks.

Bug Fixes:

  • Prevent untranslated or malformed note templates from producing raw locale keys or rendering failures.

Enhancements:

  • Extend query notes with locale metadata while preserving English source messages as fallbacks.

Tests:

  • Add coverage for localized CLI and GUI notes, parameter substitution, fallback behavior, and malformed templates.

@sourcery-ai

sourcery-ai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

Query-builder notes now carry locale keys and interpolation parameters, allowing the shared CLI and GUI rendering paths to display English or Spanish templates while safely falling back to the original English sentence; tests cover translation, integration, and failure handling.

Sequence diagram for localized query-builder note rendering

sequenceDiagram
    participant Composer as QueryComposer
    participant Result as QueryResult
    participant Renderer as format_result_lines
    participant Locale as LocaleTranslator
    participant Surface as CLI_or_GUI

    Composer->>Result: QueryNote(message, message_key, message_params)
    Surface->>Renderer: format_result_lines(result, translate)
    Renderer->>Locale: translate(message_key)
    alt localized template exists and formats successfully
        Locale-->>Renderer: localized template
        Renderer-->>Surface: formatted localized note
    else key missing or formatting fails
        Renderer-->>Surface: note.message
    end
Loading

File-Level Changes

Change Details Files
Adds locale-aware metadata to query-builder notes and renders translated templates with parameter substitution and safe English fallback.
  • Extends QueryNote with a message key and template parameters.
  • Annotates composer and builder-service notes with locale keys and values.
  • Updates shared result formatting to translate notes and fall back when keys or formatting fail.
  • Adds English and Spanish locale templates for builder notes.
packages/auto_apply/src/auto_apply/domain/models/search_query.py
packages/auto_apply/src/auto_apply/domain/services/query_composer.py
packages/auto_apply/src/auto_apply/application/services/query_builder.py
packages/auto_apply/src/auto_apply/resources/locales/en.json
packages/auto_apply/src/auto_apply/resources/locales/es.json
Routes GUI and CLI query-builder output through the locale-aware note renderer.
  • Updates CLI rendering documentation and uses the shared translated formatter.
  • Adds GUI locale lookup for strings not included in the window label dictionary.
  • Preserves English note text when a locale key is unavailable or cannot be formatted.
packages/auto_apply/src/auto_apply/adapters/primary/cli/search_builder_screen.py
packages/auto_apply/src/auto_apply/adapters/primary/gui/app.py
packages/auto_apply/src/auto_apply/adapters/primary/gui/strings.py
Adds regression coverage for translated notes, parameter substitution, fallback behavior, and GUI locale integration.
  • Verifies Spanish location notes on both CLI and GUI paths.
  • Verifies missing or malformed translations fall back to the English sentence without crashing.
  • Verifies translated templates receive note parameters.
packages/auto_apply/tests/adapters/test_search_builder_cli.py
packages/auto_apply/tests/adapters/test_gui_search_window.py
Documents the localized query-builder note behavior and its remaining English-only text.
  • Records locale keys, fallback behavior, and known untranslated item names, errors, and catalog text.
CHANGELOG.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 4 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="packages/auto_apply/src/auto_apply/domain/services/query_composer.py" line_range="337" />
<code_context>
             "takes a location.",
+            message_key="builder.note.location_unsupported",
+            surface=spec.display_name,
+            location=request.location,
         ))

</code_context>
<issue_to_address>
**Location escapes terminal output**

When a scripted CLI invocation supplies an unsupported location containing terminal control sequences, the CLI passes the formatted note to `print`, where terminal control sequences in `request.location` are interpreted, allowing crafted input to forge or hide output and trigger terminal-side actions.

Escape or remove terminal control characters from user-supplied values before printing CLI notes.

Also at `packages/auto_apply/src/auto_apply/domain/models/search_query.py:202`.
</issue_to_address>

### Comment 2
<location path="packages/auto_apply/src/auto_apply/domain/models/search_query.py" line_range="202-203" />
<code_context>
+        template = translate(note.message_key)
+        if template and template != note.message_key:
+            try:
+                return template.format(**dict(note.message_params))
+            except (KeyError, IndexError, ValueError):
+                pass
+    return note.message
</code_context>
<issue_to_address>
**Result rendering fails**

When a locale template uses an attribute-style placeholder whose lookup fails, `template.format(**dict(note.message_params))` raises an uncaught `AttributeError`, so `note_text` cannot return the English fallback and CLI or GUI result rendering fails.

Catch `AttributeError` alongside the existing formatting exceptions so `note_text` returns the English fallback.
</issue_to_address>

### Comment 3
<location path="packages/auto_apply/src/auto_apply/adapters/primary/gui/app.py" line_range="769-770" />
<code_context>
         strings = get_strings()
-        SearchBuilderWindow(self, builder, translate=lambda key: strings.get(key, key))
+        SearchBuilderWindow(
+            self, builder, translate=lambda key: strings.get(key) or locale_text(key)
+        )

     # =====================================================================
</code_context>
<issue_to_address>
**Builder labels and notes diverge**

When the active locale changes while a query-builder window is open, `strings` keeps the window labels in the original locale, while `locale_text` reads the changed global locale for notes, so the window displays labels and notes in different languages.

Make the note translator use the same locale snapshot as the window labels.

Also at `packages/auto_apply/src/auto_apply/adapters/primary/gui/strings.py:30-36`.
</issue_to_address>

### Comment 4
<location path="packages/auto_apply/tests/adapters/test_gui_search_window.py" line_range="180" />
<code_context>
+    labels = {"builder.result.bar": "Texto", "builder.result.link": "Enlace"}
+    try:
+        configure_locale(language="es")
+        lines = gw.result_lines(result, lambda key: labels.get(key) or locale_text(key))
+    finally:
+        configure_locale(language="en")  # restore default for other tests
</code_context>
<issue_to_address>
**Broken GUI wiring goes unnoticed**

When the GUI's `_open_search_builder` translator is changed to return untranslated keys for note templates, `test_gui_notes_follow_the_locale_and_never_crash__teeth` passes using the lambda on this line even if the application's GUI translator stops calling `locale_text`; the test calls `gw.result_lines` directly and never exercises `_open_search_builder`, so the real GUI can show English notes.

Exercise `_open_search_builder` and assert that the translator it passes to the window renders a note in Spanish.
</issue_to_address>

Sourcery assessment

Approval pending. 4 findings to address first.

Blocking findings: packages/auto_apply/src/auto_apply/domain/services/query_composer.py:337, packages/auto_apply/src/auto_apply/domain/models/search_query.py:203, packages/auto_apply/src/auto_apply/adapters/primary/gui/app.py:770, packages/auto_apply/tests/adapters/test_gui_search_window.py:180


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

"takes a location.",
message_key="builder.note.location_unsupported",
surface=spec.display_name,
location=request.location,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium · Location escapes terminal output

When a scripted CLI invocation supplies an unsupported location containing terminal control sequences, the CLI passes the formatted note to print, where terminal control sequences in request.location are interpreted, allowing crafted input to forge or hide output and trigger terminal-side actions.

Escape or remove terminal control characters from user-supplied values before printing CLI notes.

Also at packages/auto_apply/src/auto_apply/domain/models/search_query.py:202.

Prompt for AI agents
In `packages/auto_apply/src/auto_apply/domain/services/query_composer.py` at line 337:

**Location escapes terminal output**

When a scripted CLI invocation supplies an unsupported location containing terminal control sequences, the CLI passes the formatted note to `print`, where terminal control sequences in `request.location` are interpreted, allowing crafted input to forge or hide output and trigger terminal-side actions.

Escape or remove terminal control characters from user-supplied values before printing CLI notes.

Also at `packages/auto_apply/src/auto_apply/domain/models/search_query.py:202`.

Comment on lines +202 to +203
return template.format(**dict(note.message_params))
except (KeyError, IndexError, ValueError):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium · Result rendering fails

When a locale template uses an attribute-style placeholder whose lookup fails, template.format(**dict(note.message_params)) raises an uncaught AttributeError, so note_text cannot return the English fallback and CLI or GUI result rendering fails.

Catch AttributeError alongside the existing formatting exceptions so note_text returns the English fallback.

Prompt for AI agents
In `packages/auto_apply/src/auto_apply/domain/models/search_query.py` at lines 202-203:

**Result rendering fails**

When a locale template uses an attribute-style placeholder whose lookup fails, `template.format(**dict(note.message_params))` raises an uncaught `AttributeError`, so `note_text` cannot return the English fallback and CLI or GUI result rendering fails.

Catch `AttributeError` alongside the existing formatting exceptions so `note_text` returns the English fallback.

Comment on lines +769 to +770
self, builder, translate=lambda key: strings.get(key) or locale_text(key)
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium · Builder labels and notes diverge

When the active locale changes while a query-builder window is open, strings keeps the window labels in the original locale, while locale_text reads the changed global locale for notes, so the window displays labels and notes in different languages.

Make the note translator use the same locale snapshot as the window labels.

Also at packages/auto_apply/src/auto_apply/adapters/primary/gui/strings.py:30-36.

Prompt for AI agents
In `packages/auto_apply/src/auto_apply/adapters/primary/gui/app.py` at lines 769-770:

**Builder labels and notes diverge**

When the active locale changes while a query-builder window is open, `strings` keeps the window labels in the original locale, while `locale_text` reads the changed global locale for notes, so the window displays labels and notes in different languages.

Make the note translator use the same locale snapshot as the window labels.

Also at `packages/auto_apply/src/auto_apply/adapters/primary/gui/strings.py:30-36`.

labels = {"builder.result.bar": "Texto", "builder.result.link": "Enlace"}
try:
configure_locale(language="es")
lines = gw.result_lines(result, lambda key: labels.get(key) or locale_text(key))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium · Broken GUI wiring goes unnoticed

When the GUI's _open_search_builder translator is changed to return untranslated keys for note templates, test_gui_notes_follow_the_locale_and_never_crash__teeth passes using the lambda on this line even if the application's GUI translator stops calling locale_text; the test calls gw.result_lines directly and never exercises _open_search_builder, so the real GUI can show English notes.

Exercise _open_search_builder and assert that the translator it passes to the window renders a note in Spanish.

Prompt for AI agents
In `packages/auto_apply/tests/adapters/test_gui_search_window.py` at line 180:

**Broken GUI wiring goes unnoticed**

When the GUI's `_open_search_builder` translator is changed to return untranslated keys for note templates, `test_gui_notes_follow_the_locale_and_never_crash__teeth` passes using the lambda on this line even if the application's GUI translator stops calling `locale_text`; the test calls `gw.result_lines` directly and never exercises `_open_search_builder`, so the real GUI can show English notes.

Exercise `_open_search_builder` and assert that the translator it passes to the window renders a note in Spanish.

@Liebmann5
Liebmann5 merged commit cc990de into main Oct 28, 2026
19 checks passed
@Liebmann5
Liebmann5 deleted the work/localise-notes branch October 28, 2026 22:40
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.

1 participant