fix(i18n): every refusal the API answers is structured and said in the reader's language
~150 HTTPExceptions carried a hand-written English sentence as their detail,
shown verbatim under the Hungarian UI — in the blocking error dialog and on
every inline surface that printed HttpError.detail (sign-in, setup wizard,
change password, the passphrase gate, live search). Four also quoted an
upstream exception's text back to the user.
- app/refusal.py: `refused(status, reason, **params)` → {code: "refused",
reason, …params}; localizeDetail translates errors.refused.<reason> with the
params interpolated. "Unknown X" 404s use the existing not_found(what).
- sysconfig.set_value raises InvalidSetting (reason + bounds) instead of an
English ValueError; the three writers answer it through setting_refused.
- The Plex connection/write/image failures log what the upstream said and
answer a reason; the search scraper's failure is logged and answered as
youtube/unavailable (it crashed refusal_reason before).
- HttpError.detail now only ever holds a translated reason: a string detail
(only the framework's own can remain) is left out, so reading .detail is
safe everywhere — including destructured, the hole the raw-detail source
scan could not see. That scan and its five-file exception list are gone.
- Enforced: test_http_details.py fails on any HTTPException with a sentence
for a detail; the contract test requires every refused reason and every
not_found "what" in both languages, and no key for one that is gone.
- local/jsx-comment-text: a // inside JSX children renders as text; the rule
is ten lines in eslint.config.js rather than eslint-plugin-react's ~1800
lockfile lines.
This commit is contained in:
@@ -44,6 +44,25 @@ const networkProperties = [
|
||||
},
|
||||
];
|
||||
|
||||
// A `//` or `/* */` inside JSX children is not a comment — it is TEXT, rendered on the page. One
|
||||
// slipped in when a return was wrapped in a fragment (Playlists.tsx) and only a visual check caught
|
||||
// it: tsc, eslint and every test stayed green. `eslint-plugin-react` has this rule, but it would bring
|
||||
// ~1800 lockfile lines of dependencies for ten lines of logic, so it lives here.
|
||||
const jsxCommentText = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
messages: { text: "A comment inside JSX children renders as text. Wrap it in {/* */}." },
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
JSXText(node) {
|
||||
if (/^\s*(\/\/|\/\*)/m.test(node.value)) context.report({ node, messageId: "text" });
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
const localRules = { rules: { "jsx-comment-text": jsxCommentText } };
|
||||
|
||||
export default tseslint.config(
|
||||
{ ignores: ["dist", "node_modules", "playwright-report", "test-results", "e2e/.auth"] },
|
||||
{
|
||||
@@ -56,12 +75,14 @@ export default tseslint.config(
|
||||
plugins: {
|
||||
"react-hooks": reactHooks,
|
||||
"react-refresh": reactRefresh,
|
||||
local: localRules,
|
||||
},
|
||||
linterOptions: {
|
||||
reportUnusedDisableDirectives: "error",
|
||||
},
|
||||
rules: {
|
||||
...reactHooks.configs.recommended.rules,
|
||||
"local/jsx-comment-text": "error",
|
||||
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
|
||||
// tsc already enforces these under strict + noUnusedLocals/Parameters — let it own them so a
|
||||
// finding is reported once, by one tool, and this config stays about hooks + refresh safety.
|
||||
|
||||
Reference in New Issue
Block a user