A web application for translating English LaTeX paper projects into Chinese at the source-code level.
The app takes a complete LaTeX project zip, compiles the original PDF, extracts translatable LaTeX blocks, lets you review an automatically generated glossary, translates the source with an OpenAI-compatible LLM, rebuilds a Chinese LaTeX project, and provides PDF previews and downloads.
- Upload complete LaTeX projects as
.zipfiles. - Detect the main
.texfile and compile the original English PDF. - Parse LaTeX source into translatable blocks while protecting formulas, citations, references, labels, URLs, graphics, and structural commands.
- Extract a domain glossary with an OpenAI-compatible LLM and edit it before translation.
- Translate block by block with retry support, progress tracking, and manual block editing.
- Generate a translated LaTeX project without modifying the original source.
- Compile the translated Chinese PDF with XeLaTeX and
ctex. - Preview and download original, translated, and generated side-by-side comparison PDFs.
- Manage LLM settings from the web UI, including model, base URL, API key, timeout, and concurrency.
- Run with Docker Compose using FastAPI, Vue 3, SQLite, Redis, and TeX Live.
- Log in with the configured account.
- Create a task and upload a LaTeX project zip.
- Wait for the original PDF compilation.
- Extract and review the glossary.
- Start translation.
- Review translation blocks and edit translations if needed.
- Compile the translated PDF.
- Generate or download the side-by-side comparison PDF.
Backend:
- Python 3.12 in Docker
- FastAPI
- SQLAlchemy
- SQLite
- httpx
- latexmk / XeLaTeX / TeX Live
Frontend:
- Vue 3
- Vite
- Element Plus
- lucide-vue-next
- Browser-native PDF iframe preview
Runtime:
- Docker Compose
- Redis container for deployment parity and future worker expansion
- Local
workspace/anddata/volumes for task files and SQLite data
.
├── backend/
│ ├── app/
│ │ ├── api/ # FastAPI routes
│ │ ├── core/ # settings
│ │ ├── db/ # SQLAlchemy session setup
│ │ ├── models/ # database models
│ │ ├── services/ # LaTeX, LLM, glossary, compile, PDF services
│ │ └── workers/ # background task runner and task orchestration
│ ├── Dockerfile
│ └── requirements.txt
├── frontend/
│ ├── src/
│ │ ├── api/
│ │ ├── components/
│ │ ├── router/
│ │ └── views/
│ ├── Dockerfile
│ └── package.json
├── data/ # SQLite database, ignored by git
├── workspace/ # uploaded and generated task files, ignored by git
├── docker-compose.yml
└── .env.example
Requirements:
- Docker
- Docker Compose
Start the app:
cp .env.example .env
docker compose up --buildOpen:
- Frontend: http://localhost:3000
- Backend health check: http://localhost:18000/api/health
Default login:
username: admin
password: admin
For a real deployment, change APP_PASSWORD or set APP_PASSWORD_HASH, and replace JWT_SECRET_KEY with a long random value.
Docker is recommended because the backend image includes the TeX Live packages needed to compile common academic templates.
If you run locally without Docker, install Python dependencies, Node dependencies, and a TeX Live distribution that includes XeLaTeX, latexmk, ctex, texlive-publishers, texlive-fonts-recommended, and texlive-science.
Backend:
cd backend
pip install -r requirements.txt
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000Frontend:
cd frontend
npm install
npm run devWhen running the frontend dev server, configure CORS_ORIGINS to include http://localhost:5173.
Environment variables are loaded from .env by Docker Compose.
| Variable | Default | Description |
|---|---|---|
APP_USERNAME |
admin |
Single login username. |
APP_PASSWORD |
admin |
Plain password used when APP_PASSWORD_HASH is empty. |
APP_PASSWORD_HASH |
empty | Optional bcrypt hash. Prefer this for deployments. |
JWT_SECRET_KEY |
change-me-in-production |
Secret used to sign JWT tokens. |
SESSION_EXPIRE_HOURS |
24 |
Login token lifetime. |
DATABASE_URL |
sqlite:////app/data/app.db in Docker |
SQLAlchemy database URL. |
WORKSPACE_DIR |
/app/workspace/tasks in Docker |
Root directory for task files. |
CORS_ORIGINS |
localhost origins | Comma-separated allowed frontend origins. |
LLM configuration is managed in the web UI. The backend calls OpenAI-compatible chat completion APIs at:
{base_url}/v1/chat/completions
Example model settings:
base_url: https://api.openai.com
model: gpt-4o-mini
base_url: http://127.0.0.1:11434
model: qwen2.5:14b
api_key: ollama
All task, file, glossary, block, and LLM configuration APIs require authentication.
Auth:
POST /api/auth/loginPOST /api/auth/logoutGET /api/auth/me
LLM configuration:
GET /api/llm-configsPOST /api/llm-configsPUT /api/llm-configs/{config_id}DELETE /api/llm-configs/{config_id}POST /api/llm-configs/{config_id}/test
Tasks:
GET /api/tasksPOST /api/tasksGET /api/tasks/{task_id}DELETE /api/tasks/{task_id}POST /api/tasks/{task_id}/uploadPOST /api/tasks/{task_id}/compile-originalPOST /api/tasks/{task_id}/extract-glossaryPOST /api/tasks/{task_id}/start-translationPOST /api/tasks/{task_id}/compile-translatedPOST /api/tasks/{task_id}/generate-comparison-pdf
Task resources:
GET /api/tasks/{task_id}/glossaryGET /api/tasks/{task_id}/blocksGET /api/tasks/{task_id}/logsGET /api/tasks/{task_id}/pdf/originalGET /api/tasks/{task_id}/pdf/translatedGET /api/tasks/{task_id}/pdf/comparisonGET /api/tasks/{task_id}/download/translated-project
Each task stores files under:
workspace/tasks/{task_id}/
├── upload/
├── source/
├── translated/
├── build_original/
├── build_translated/
├── build_comparison/
├── output/
└── logs/
Important outputs:
output/original.pdfoutput/translated.pdfoutput/comparison.pdfoutput/translated_project.zip
workspace/ and data/ are ignored by git.
The translator works on LaTeX source, not rendered PDFs.
It extracts natural-language blocks such as titles, abstracts, section headings, captions, and paragraphs. Before sending a block to the LLM, it protects LaTeX structures with placeholders and validates that placeholders survive the translation.
The generated Chinese project is written to translated/. The original source under source/ is not overwritten.
By default, .bib files are copied but not translated.
- LLM output quality depends on the configured model and glossary.
- Complex custom LaTeX macros may require parser improvements.
- Table body translation is conservative; captions are the primary supported table text.
- Browser-native PDF viewers do not expose reliable scroll control to JavaScript, so the app uses generated comparison PDFs for stable side-by-side viewing.
- Uploaded LaTeX projects are compiled inside the backend container with fixed
latexmkarguments, but this is still intended for trusted or controlled deployments.
Health check:
curl --noproxy '*' http://127.0.0.1:18000/api/healthService status:
docker compose ps
docker compose logs --tail=120 backendIf local curl requests to 127.0.0.1 return proxy-related errors, use --noproxy '*'.
If PDF compilation fails, check the task logs in the web UI or under:
workspace/tasks/{task_id}/logs/
- Keep translation block parsing conservative. Preserving LaTeX validity is more important than translating every possible token.
- Do not send an entire paper to the LLM in one request; translate by block.
- Do not write translated files back into
source/. - Do not translate
.bibfiles unless this becomes an explicit optional feature. - Prefer adding focused tests or real-task validation when changing parsing, generation, or compile behavior.
This project is licensed under the Apache-2.0 License. See the LICENSE file for details.
