Skip to content

fix: load this plugin's locales by absolute path, not via ep_ai_core#20

Merged
JohnMcLear merged 1 commit intomainfrom
fix/i18n-load-own-locales
May 2, 2026
Merged

fix: load this plugin's locales by absolute path, not via ep_ai_core#20
JohnMcLear merged 1 commit intomainfrom
fix/i18n-load-own-locales

Conversation

@JohnMcLear
Copy link
Copy Markdown
Member

Bug

Users see literal i18n keys in chat (e.g. AI Assistant: ep_ai_chat.error_auth) instead of the translated message.

Root cause

ep_ai_core/i18n.js's loadLocale() does:

require.resolve(`${pluginName}/locales/${lang}.json`)

That lookup runs from ep_ai_core's context, but in every real install ep_ai_core and ep_ai_chat are siblings under plugins/, so ep_ai_chat isn't reachable from ep_ai_core/node_modules/. The resolve throws, the catch returns {}, and t() falls back to the literal key.

Reproduced cleanly:

$ cd plugins/ep_ai_core && node -e "console.log(require('./i18n').t('ep_ai_chat.error_auth'))"
ep_ai_chat.error_auth

Spotted when the running server was launched without ANTHROPIC_API_KEY in its env, which makes Anthropic return 401 on every call. The auth-error branch then sent the bare key to chat.

Fix

Ship a tiny i18n.js inside ep_ai_chat that reads ./locales/<lang>.json by absolute path rooted at __dirname. No cross-plugin require.resolve, no silent fallback. index.js now imports t from ./i18n instead of ep_ai_core/i18n.

$ node -e "console.log(require('./i18n').t('ep_ai_chat.error_auth'))"
Sorry, the AI service rejected the request. Please check the API key configuration.

A follow-up in ep_ai_core could harden its loadLocale to accept an explicit basePath, but that's a separate repo and a bigger surface; this PR fixes ep_ai_chat's chat output regardless of what ep_ai_core does.

🤖 Generated with Claude Code

ep_ai_core/i18n.js's loadLocale() does
  require.resolve(`${pluginName}/locales/${lang}.json`)
which only works if `pluginName` is reachable from ep_ai_core's own
node_modules. In every real install ep_ai_core and ep_ai_chat are
sibling plugins, so this lookup silently fails for any ep_ai_chat
key — loadLocale catches the resolve error, returns {}, and t()
falls back to the literal key.

User-visible symptom: chat replies for AI errors say things like
"ep_ai_chat.error_auth" instead of the translated string. Spotted
when the running server was launched without ANTHROPIC_API_KEY in
its env, which makes Anthropic return 401 on every call; the
auth-error branch then sent the bare key to chat.

Fix: ship a tiny i18n.js inside ep_ai_chat that reads
./locales/<lang>.json by absolute path rooted at __dirname. No more
cross-plugin require.resolve and no more silent fallback. index.js
imports from './i18n' instead of 'ep_ai_core/i18n'.

Verified: `node -e "console.log(require('./i18n').t('ep_ai_chat.error_auth'))"`
prints the English string instead of the key.

A follow-up in ep_ai_core could harden its loadLocale to accept an
explicit basePath, but that's a separate repo and a bigger surface;
this PR fixes ep_ai_chat's chat output regardless of what
ep_ai_core does.
@qodo-code-review
Copy link
Copy Markdown

ⓘ You've reached your Qodo monthly free-tier limit. Reviews pause until next month — upgrade your plan to continue now, or link your paid account if you already have one.

@JohnMcLear JohnMcLear merged commit 9ccd1ae into main May 2, 2026
3 checks passed
JohnMcLear added a commit that referenced this pull request May 3, 2026
…lay name

Override the default "@<name> " chat-input prefill with the configured
AI trigger ("@ai " by default) when a user clicks the AI's row in the
user list. Without this, clicking the AI chip would prefill
"@AI_Assistant ", which doesn't match anything the server-side mention
extractor recognises.

What this PR adds:
- clientVars server hook exposing { trigger, authorName, authorId } at
  clientVars.ep_ai_chat so the client can recognise the AI's row.
- chatPrefillFromUser client hook that returns the trigger string when
  the clicked authorId matches the AI's; otherwise returns nothing so
  core's default ("@<name> ") wins.
- Mocha unit test (static/tests/backend/specs/chat_prefill.ts) covering
  AI/non-AI/missing-clientVars/custom-trigger/missing-trigger paths.

Depends on ether/etherpad#7660 which adds the chatPrefillFromUser hook
to core. On older cores the hook is never fired and this PR is a
benign no-op — graceful degradation, no install requirement bump.

Originally this PR shipped the entire user-list click handler inside
the plugin. Per review feedback, the generic "click a user → prefill
@-mention" UX belongs in core (it's a discoverability win for any
multi-user pad, AI or no AI), so the bulk moved to ether/etherpad#7660
and this PR is now ~40 lines of glue.

(Replaces the previous 3-commit history on this branch with a clean
rebase against the new main, which absorbed PRs #18 and #20 since the
branch was opened.)
JohnMcLear added a commit that referenced this pull request May 3, 2026
…lay name (#19)

Override the default "@<name> " chat-input prefill with the configured
AI trigger ("@ai " by default) when a user clicks the AI's row in the
user list. Without this, clicking the AI chip would prefill
"@AI_Assistant ", which doesn't match anything the server-side mention
extractor recognises.

What this PR adds:
- clientVars server hook exposing { trigger, authorName, authorId } at
  clientVars.ep_ai_chat so the client can recognise the AI's row.
- chatPrefillFromUser client hook that returns the trigger string when
  the clicked authorId matches the AI's; otherwise returns nothing so
  core's default ("@<name> ") wins.
- Mocha unit test (static/tests/backend/specs/chat_prefill.ts) covering
  AI/non-AI/missing-clientVars/custom-trigger/missing-trigger paths.

Depends on ether/etherpad#7660 which adds the chatPrefillFromUser hook
to core. On older cores the hook is never fired and this PR is a
benign no-op — graceful degradation, no install requirement bump.

Originally this PR shipped the entire user-list click handler inside
the plugin. Per review feedback, the generic "click a user → prefill
@-mention" UX belongs in core (it's a discoverability win for any
multi-user pad, AI or no AI), so the bulk moved to ether/etherpad#7660
and this PR is now ~40 lines of glue.

(Replaces the previous 3-commit history on this branch with a clean
rebase against the new main, which absorbed PRs #18 and #20 since the
branch was opened.)
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 3, 2026

🎉 This PR is included in version 1.2.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant