Skip to content

feat(plugins): mark plugin user-facing strings for translation - #603

Open
hamza-56 wants to merge 1 commit into
i18n-mark-core-apifrom
i18n-mark-plugins
Open

feat(plugins): mark plugin user-facing strings for translation#603
hamza-56 wants to merge 1 commit into
i18n-mark-core-apifrom
i18n-mark-plugins

Conversation

@hamza-56

@hamza-56 hamza-56 commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Part of: Sparkth UI, emails, API errors, and AI-generated content are English-only

Third layer of the i18n stack (#601#602#603#604#606#607).

What

Marks the user-facing strings owned by the plugins and the RAG ingestion path, covering route error details, the chat streaming error map, the Slack bot's canned replies, and each plugin's frontend metadata.

Changes

  • feat(plugins): gettext_noop-mark the DisplayInfo/SidebarEntry registrations of all five plugins
  • feat(plugins): chat — completion/attachment/conversation route details and the streaming_error_message / rag_retrieval_error_message maps wrapped in _()
  • feat(plugins): slack — the bot's canned messages become lazy_gettext constants rendered with str() at dispatch; OAuth and workspace route details marked
  • feat(plugins): googledrive — route details and the persisted document-failure messages marked; throwaway _ unpacking variables renamed so they cannot shadow the gettext alias
  • feat(rag): ScannedPDFError.USER_MESSAGE becomes a lazy translation rendered where the failure is stored

How to Test

  1. uv run pytest sparkth/plugins/chat/tests/test_i18n.py sparkth/plugins/slack/tests/test_i18n.py tests/rag/test_extraction_scanned_pdf.py
  2. Full run: uv run pytest (1760 passed on this layer)
  3. make mypy and make lint.backend are clean

Notes

Deferred, per the phase-1 plan: the chat refusal message (lives in scope_keywords.json, entangled with the LLM system prompt), LLM prompts, MCP tool descriptions, Slack webhook plumbing responses, and hand-rolled pagination-parameter validation messages.

This PR description was written with the assistance of an LLM (Claude).

Covers the chat, slack, googledrive, canvas, and openedx plugins plus the
RAG scanned-PDF ingestion message. DisplayInfo/SidebarEntry registrations
are gettext_noop-marked, the Slack bot's canned replies become lazy_gettext
constants rendered with str() at dispatch, and route details and the chat
streaming error map are wrapped in _(). Throwaway underscore variables in
googledrive routes are renamed so they cannot shadow the gettext alias.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hamza-56

Copy link
Copy Markdown
Contributor Author

@claude-review

@claude

claude Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Claude finished @hamza-56's task in 6m 6s —— View job


Review — mark plugin user-facing strings for translation

  • Read the full diff vs origin/i18n-mark-core-api
  • Review chat plugin changes (routes, stream_processor)
  • Review slack plugin changes (lazy_gettext constants)
  • Review googledrive plugin changes (_ shadowing)
  • Review rag exception + DisplayInfo marking
  • Check test coverage
  • Post review

Solid, well-scoped i18n pass. The three marking strategies are applied correctly and consistently:

  • _() (eager) in request-scoped route handlers and stream_processor — evaluated under the active request locale. ✅
  • lazy_gettext(...) + str() at use-site for module-level constants (slack/constants.py, ScannedPDFError.USER_MESSAGE) that are built at import before any locale exists. ✅
  • gettext_noop(...) for DisplayInfo/SidebarEntry extraction markers translated downstream. ✅

Placeholders were correctly converted to translator-friendly named form ({status}, {status_code}, {limit:.0f}, {conversation_uuid}), and the throwaway _ unpacking vars were renamed (_redirect_uri, _client_secret, _drive_file) so they can't shadow the gettext alias — good, necessary detail. New test_i18n.py suites for chat + slack plus the RAG assertion update give the lazy/active-locale paths real coverage.

🔴 High — invalid except syntax in touched code (pre-existing)

sparkth/plugins/googledrive/routes/oauth.py uses Python 2 multi-type except clauses (no parentheses) at lines 60, 91, and 139, e.g.:

except BadSignature, KeyError, ValueError, TypeError:   # line 60
except KeyError, ValueError:                            # line 91
except ValueError, HTTPException:                       # line 139

Under Python 3 each is a SyntaxError: multiple exception types must be parenthesized, so the module cannot import. This predates the PR (it's on main), but:

  • the PR edits the detail=_(...) lines inside these blocks, and
  • the sibling slack/routes/oauth.py — modified in this same PR — already uses the correct except (A, B) as exc: form.

Since googledrive/tests/test_routes.py patches sparkth.plugins.googledrive.routes.oauth.* (which requires the module to import), please verify uv run pytest sparkth/plugins/googledrive actually collects rather than erroring at import. Trivial fix (add parens) — worth doing here given the file is already being edited. See the inline comment. Fix this →

🟢 Low / optional

  • stream_processor.py (Google branch) — the grpc_status_code null-handling was expanded to a 3-line if status_code is None: block. It reads fine, but the original one-liner intent is preserved more concisely with .format(status_code=exc.grpc_status_code or "unknown"). Purely stylistic.
  • Persisted, pre-translated messagesgoogledrive/utils.py stores the translated failure text (_("Processing failed"), str(ScannedPDFError.USER_MESSAGE)) into the document status at write time, so the DB freezes whichever locale was active during processing; a later viewer in another locale sees the original. This matches the PR's stated design ("rendered where the failure is stored") and is a reasonable tradeoff for persisted state — just flagging it as a known limitation, not a defect.
  • Nice incidental fix: the deactivated-key message in completions.py gained the missing space ("...reactivate it, "), correcting a pre-existing it,or concatenation.

Verdict

Approve in spirit — the i18n work is correct and consistent. Only the except-syntax item warrants attention before merge (and even a quick confirmation that the googledrive route suite still collects would be reassuring). Everything else is optional polish.
· branch i18n-mark-plugins

except SignatureExpired:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="OAuth state expired. Please try again.")
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=_("OAuth state expired. Please try again."))
except BadSignature, KeyError, ValueError, TypeError:

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.

Invalid Python 3 exception syntax (pre-existing, but inside code this PR edits).

except BadSignature, KeyError, ValueError, TypeError: is Python 2 syntax. Under Python 3 this is a SyntaxError: multiple exception types must be parenthesized — the module cannot be imported as written. The same problem appears on line 91 (except KeyError, ValueError:) and line 139 (except ValueError, HTTPException:).

Notably, the sibling slack/routes/oauth.py touched in this very PR uses the correct parenthesized form (except (BadSignature, KeyError, ValueError, TypeError) as exc:), so the fix is a one-liner here too:

Suggested change
except BadSignature, KeyError, ValueError, TypeError:
except (BadSignature, KeyError, ValueError, TypeError):

This is pre-existing (it's on main as well), so it predates this PR — but since the PR edits the detail= lines inside these blocks and the googledrive route tests patch sparkth.plugins.googledrive.routes.oauth.* (which requires the module to import), please double-check that uv run pytest sparkth/plugins/googledrive actually collects rather than erroring. If CI is green, this suite may be silently failing at collection.

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