mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-12 21:23:45 +01:00
LanguageTool module
Grammar and style checking in the Overleaf source editor, powered by an external LanguageTool server (API v2).
Based on the upstream PR:
https://github.com/yu-i-i/overleaf-cep/pull/179 (commit 8337e00), adapted
for ext-ce-v6.3.1 with:
- Picky level as the default and an on/off "Picky mode" toggle in the
project settings (the deployed LT fork,
erikvl87/languagetool, supportsdefault+picky; other levels return HTTP 400). - Project-wide settings (stored on the project document, shared by all
collaborators, synced over the editor socket):
languageToolEnabled— grammar check on/off (default: on)languageToolPicky— picky level on/off (default: on →level=picky)languageToolLanguage— LT language code, e.g.en-US,de(default:auto)
- Dark/light theme support: tooltip + underlines use the Overleaf themed
CSS variables (
--bg-primary-themed,--content-primary-themed, ...) with light-mode fallbacks (fixes the dark-theme tooltip bug from the PR).
Server (Overleaf) environment
| Variable | Default | Notes |
|---|---|---|
LANGUAGE_TOOL_ENABLED |
unset | must be exactly true to activate |
LANGUAGE_TOOL_HOST |
languagetool |
host of the LT service |
LANGUAGE_TOOL_PORT |
8010 |
LT API port |
LANGUAGE_TOOL_URL |
derived | overrides host+port when set |
The overleaf container needs network access to the LT service. In this
deployment the overleaf service joins the external
languagetools_server_compose_default network (see
/data_1/docker/compose/overleaf/compose.yaml) and talks to
http://languagetool:8010.
Endpoints (authenticated)
GET /languagetool/languages— LT language list (used by the settings UI)POST /languagetool/check— JSON body{ language, level?, text? | data? }; proxied to LT/v2/checkwith a 100 KB cap and LaTeX-noisedisabledRules. Exempt from CSRF (webRouter.csrf.disableDefaultCsrfProtectionin the router): it is a stateless, login-gated query — and long-lived editor tabs outlive session rotations, where the page's meta token would stale out and 403 every check. The client still sendsX-CSRF-Token; it passes when the session is fresh.
Frontend
frontend/js/languagetool-extension.ts— CodeMirror 6 extension (wired via thesourceEditorExtensionsslot inservices/web/config/settings.defaults.js). Wavy underlines + hover tooltip with replacement buttons; LaTeX-aware annotation via the Lezer syntax tree (regex fallback); debounced 2 s; aborts stale requests; filters TYPOS while the Hunspell spellchecker is active.frontend/js/languagetool-section.tsx+frontend/js/components/languagetool-settings.tsx— Settings modal, Spelling and Language → LanguageTool (wired via thesettingsModalSpellcheckSectionsslot).
Settings reach the editor through options.languageTool
(use-codemirror-scope.ts) and the lt:settings-changed window event.
Files
index.mjs module entry (env-gated router)
app/src/LanguageToolRouter.mjs
app/src/LanguageToolController.mjs
frontend/js/languagetool-extension.ts
frontend/js/languagetool-section.tsx
frontend/js/components/languagetool-settings.tsx
frontend/js/utils/latex-to-annotations.ts
Core Overleaf changes (see git diff):
services/web/config/settings.defaults.js(sourceEditorExtensions,settingsModalSpellcheckSections,moduleImportSequence)services/web/app/src/infrastructure/ExpressLocals.mjs(exposed settinglanguageToolAvailable)services/web/types/exposed-settings.tsservices/web/app/src/Features/Project/ProjectController.mjs(project-settings schema + update)services/web/app/src/Features/Project/ProjectOptionsHandler.mjs(persist)services/web/app/src/Features/Editor/EditorController.mjs(socket emit)services/web/frontend/js/features/ide-settings/...(settings UI context, hooks, socket listener,api.ts)services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts