### Set up Environment for Manga Image Translator (Python)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/run_as_colab.ipynb
This snippet clones the repository, navigates into the project directory, and installs the necessary Python dependencies from the requirements file. It's designed for environments like Google Colab.
```python
# Set up the environment.
!git clone https://github.com/zyddnys/manga-image-translator
%cd manga-image-translator/
!python -m pip install -r requirements.txt
```
--------------------------------
### Install and Launch MangaStudio GUI
Source: https://context7.com/zyddnys/manga-image-translator/llms.txt
Instructions for installing the necessary Python dependencies and launching the MangaStudio graphical user interface. The GUI supports drag-and-drop functionality and visual configuration of translation settings.
```bash
# Install GUI dependencies
pip install PySide6 Pillow
# Launch the GUI application
python MangaStudioMain.py
```
--------------------------------
### Start Docker Compose Services
Source: https://context7.com/zyddnys/manga-image-translator/llms.txt
Starts the services defined in the docker-compose.yml file in detached mode. This command is used to deploy and run the manga-translator application.
```bash
# Start services
docker-compose up -d
```
--------------------------------
### Start Manga Image Translator Web Server
Source: https://context7.com/zyddnys/manga-image-translator/llms.txt
Launch the web server for Manga Image Translator, which provides both a user interface and REST API endpoints. Supports GPU acceleration and automatic translator instance startup.
```bash
# Start web server with GPU support
cd server
python main.py --use-gpu --host 0.0.0.0 --port 8000
# Start with automatic translator instance
python main.py --use-gpu --start-instance
# The web UI is available at: http://127.0.0.1:8000
# API documentation at: http://127.0.0.1:8000/docs
# API endpoint at: http://127.0.0.1:8001
```
--------------------------------
### Run Manga Image Translator Web Interface with GPU (Python)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/run_as_colab.ipynb
This snippet demonstrates how to run the Manga Image Translator in web mode using a GPU. It obtains a proxy URL for accessing the web interface and starts the translator. Ensure a GPU is selected at runtime in environments like Google Colab.
```python
# Run with colab. GPU must be selected at runtime!
from google.colab.output import eval_js
url = eval_js("google.colab.kernel.proxyPort(5003)")
print('Open the link to use manga-image-translator! -> ', url)
!python -m manga_translator --verbose --mode web --use-gpu
```
--------------------------------
### Install Testing Dependencies with Pip
Source: https://github.com/zyddnys/manga-image-translator/blob/main/test/README.md
Installs the necessary packages for running tests, including pytest and pytest-asyncio. These are essential for the testing framework.
```bash
pip install pytest pytest-asyncio
```
--------------------------------
### Configure Pre/Post Translation Dictionaries
Source: https://context7.com/zyddnys/manga-image-translator/llms.txt
Examples of text replacement dictionaries for pre- and post-translation processing. Pre-dictionaries fix OCR errors before translation, while post-dictionaries standardize translated output and honorifics.
```text
# dict/pre_dict.txt - Applied before translation (fix OCR errors)
# Format: pattern replacement
# Fix common OCR mistakes
力ノレ カル
カ力 カカ
[00][Oo] oo
# Remove unwanted characters
♪
♫
# dict/post_dict.txt - Applied after translation (standardize output)
# Fix common translation mistakes
Mr\. -san
Mrs\. -san
Miss -chan
# Standardize honorifics
\bsenpai\b Senpai
\bkouhai\b Kouhai
```
--------------------------------
### Start Image Translation Process (JavaScript)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
Initiates the translation process for a given image file. It checks if a translation is already in progress and either adds the new image to the queue or starts processing it immediately. This function manages the initial state and queuing of translation tasks.
```javascript
startTranslation() {
if (!this.file) return;
// Clear any finished items from queue
this.clearFinishedItems();
const currentFile = this.file;
// Check if something is actually currently translating (has a real processing step status)
const processingSteps = ['upload', 'pending', 'detection', 'ocr', 'mask-generation', 'inpainting', 'upscaling', 'translating', 'rendering'];
const isCurrentlyTranslating = this.queuedImages.some(item => processingSteps.includes(item.status));
console.log('Currently translating:', isCurrentlyTranslating);
console.log('Current queue statuses:', this.queuedImages.map(item => ({ id: item.id, status: item.status })));
if (isCurrentlyTranslating) {
// Add to back of queue with 'queued' status
const queuedImage = {
id: Date.now() + Math.random(),
file: currentFile,
addedAt: new Date(),
status: 'queued' // Explicitly set as queued
};
this.queuedImages.push(queuedImage);
this.file = null; // Clear current file
console.log('Added image to queue with status:', queuedImage.status);
} else {
// Start translating immediately with 'processing' status
const queuedImage = {
id: Date.now() + Math.random(),
file: currentFile,
addedAt: new Date(),
status: 'processing' // This one will be processing
};
this.queuedImages.push(queuedImage);
this.file = null; // Clear current file
console.log('Starting translation with status:', queuedImage.status);
// Start the translation process
this.processTranslation(queuedImage);
}
}
```
--------------------------------
### Add Multiple Files to Queue (JavaScript)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
Adds an array of files to the translation queue, assigning a unique ID, timestamp, and initial 'queued' status. It then checks if any translation is in progress and starts processing the first queued item if the queue is idle.
```javascript
addMultipleFilesToQueue(files) {
console.log(`Adding ${files.length} files to queue`);
// Clear any finished items from queue first
this.clearFinishedItems();
files.forEach((file, index) => {
const queuedImage = {
id: Date.now() + Math.random() + index,
file: file,
addedAt: new Date(),
status: 'queued'
};
this.queuedImages.push(queuedImage);
});
console.log(`Queue now has ${this.queuedImages.length} items`);
// If nothing is currently processing, start the first one
const processingSteps = ['upload', 'pending', 'detection', 'ocr', 'mask-generation', 'inpainting', 'upscaling', 'translating', 'rendering'];
const isCurrentlyTranslating = this.queuedImages.some(item => processingSteps.includes(item.status));
if (!isCurrentlyTranslating && this.queuedImages.length > 0) {
// Start processing the first queued item
const firstQueuedIndex = this.queuedImages.findIndex(item => item.status === 'queued');
if (firstQueuedIndex !== -1) {
this.queuedImages[firstQueuedIndex].status = 'processing';
this.processTranslation(this.queuedImages[firstQueuedIndex]);
}
}
}
```
--------------------------------
### Customize AI Translator Behavior with YAML
Source: https://context7.com/zyddnys/manga-image-translator/llms.txt
Customizes AI translator behavior using a YAML configuration file for prompt engineering and model parameters. This file allows setting global defaults, system prompt templates, per-translator overrides, and few-shot examples.
```yaml
# gpt_config.yaml - GPT/AI Translator Configuration
# Global defaults
temperature: 0.5
top_p: 1
verbose_logging: false
# System prompt template
chat_system_template: >
You are an untrammelled professional translation engine.
Please translate the text into colloquial, elegant and fluent {to_lang},
without referencing machine translations.
You must only translate the story, never interpret it.
If already in {to_lang} or looks like gibberish, output it as is.
Translate to {to_lang}.
# Per-translator overrides
chatgpt:
include_template: true
gpt-4o-mini:
temperature: 0.4
gpt-3.5-turbo:
temperature: 0.3
gemini:
temperature: 0.5
top_p: 0.95
ollama:
deepseek-r1:
rgx_capture: '.*\s*(.*)|(.*)'
# Prompt template prepended to user messages
prompt_template: 'Please help me to translate the following text from a manga to {to_lang}:'
# Few-shot examples for each target language
chat_sample:
English:
- "<|1|>Original Japanese text\n<|2|>More text"
- "<|1|>Translated English text\n<|2|>More translation"
Chinese (Simplified):
- "<|1|>Original Japanese text"
- "<|1|>Translated Chinese text"
```
--------------------------------
### Get User-Friendly Step Name (JavaScript)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
Translates internal step status strings into human-readable names for display. It uses a mapping object to provide user-friendly labels for various stages of the image processing pipeline. Returns the original step string if no mapping is found.
```javascript
getStepName(step) {
const stepNames = {
'upload': 'Uploading',
'pending': 'Queuing',
'detection': 'Detecting texts',
'ocr': 'Running OCR',
'mask-generation': 'Generating text mask',
'inpainting': 'Running inpainting',
'upscaling': 'Running upscaling',
'translating': 'Translating',
'rendering': 'Rendering translated texts',
'finished': 'Finished'
};
return stepNames[step] || step;
}
```
--------------------------------
### Response Processing Logic (JavaScript)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/manual.html
Processes the streaming response from the translation API. It decodes the data, handles different status codes (0 for data, 1 for step, 2 for error, 3 for queue, 4 for started), and updates the UI accordingly. It supports downloading text or byte data.
```javascript
async function process(response, statusField, errorField, image) {
if (response.ok) {
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let buffer = new Uint8Array();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const newBuffer = new Uint8Array(buffer.length + value.length);
newBuffer.set(buffer);
newBuffer.set(value, buffer.length);
buffer = newBuffer;
while (buffer.length >= 5) {
const dataSize = new DataView(buffer.buffer).getUint32(1, false);
const totalSize = 5 + dataSize;
if (buffer.length < totalSize) {
break;
}
const statusCode = buffer[0];
const data = buffer.slice(5, totalSize);
if(statusCode === 0) {
if(image) {
gdata = new Blob([data], { type: 'application/octet-stream' });
statusField.innerHTML = '';
} else {
gdata = decoder.decode(data);
statusField.innerHTML = '';
}
} else if(statusCode === 1) {
const parsed_data = decoder.decode(data);
statusField.innerHTML = `translation step ${parsed_data}`;
} else if(statusCode === 2) {
statusField.innerHTML = decoder.decode(data);
errorField.innerHTML = "";
} else if(statusCode === 3) {
const parsed_data = decoder.decode(data);
statusField.innerHTML = `in queue: ${parsed_data}`;
} else if(statusCode === 4) {
statusField.innerHTML = `started translation`;
}
buffer = buffer.slice(totalSize);
}
}
} else {
errorField.innerHTML = response.statusText;
}
}
```
--------------------------------
### Configure Environment Variables
Source: https://context7.com/zyddnys/manga-image-translator/llms.txt
Sets up environment variables for API keys and service endpoints in a .env file. This includes configurations for OpenAI, DeepL, DeepSeek, Groq, Google Gemini, and custom OpenAI-compatible endpoints.
```bash
# .env file - Place in project root
# OpenAI/ChatGPT Configuration
OPENAI_API_KEY=sk-your-api-key-here
OPENAI_MODEL=chatgpt-4o-latest
OPENAI_API_BASE=https://api.openai.com/v1
OPENAI_HTTP_PROXY=
OPENAI_GLOSSARY_PATH=./dict/mit_glossary.txt
# DeepL Translation
DEEPL_AUTH_KEY=your-deepl-key
# DeepSeek
DEEPSEEK_API_KEY=your-deepseek-key
DEEPSEEK_API_BASE=https://api.deepseek.com
DEEPSEEK_MODEL=deepseek-chat
# Groq
GROQ_API_KEY=your-groq-key
GROQ_MODEL=mixtral-8x7b-32768
# Google Gemini
GEMINI_API_KEY=your-gemini-key
GEMINI_MODEL=gemini-1.5-flash-002
# Custom OpenAI-compatible endpoint (Ollama, etc.)
CUSTOM_OPENAI_API_KEY=ollama
CUSTOM_OPENAI_API_BASE=http://localhost:11434/v1
CUSTOM_OPENAI_MODEL=qwen2.5:7b
```
--------------------------------
### Use Dictionaries via CLI
Source: https://context7.com/zyddnys/manga-image-translator/llms.txt
Command-line interface usage for the manga translator, demonstrating how to specify input directories and apply pre- and post-translation dictionaries. The `--use-gpu` flag indicates GPU acceleration.
```bash
# Use dictionaries via CLI
python -m manga_translator local -i /path/to/manga \
--pre-dict ./dict/pre_dict.txt \
--post-dict ./dict/post_dict.txt \
--use-gpu
```
--------------------------------
### Run CLI Translation via Docker
Source: https://context7.com/zyddnys/manga-image-translator/llms.txt
Executes command-line interface (CLI) translation using Docker. This command mounts local input and output directories, enables GPU usage, and passes the OpenAI API key.
```bash
# Run CLI translation via Docker
docker run --rm \
-v $(pwd)/input:/app/input \
-v $(pwd)/output:/app/output \
--gpus all \
-e OPENAI_API_KEY="sk-xxx" \
zyddnys/manga-image-translator:main \
local -i /app/input -o /app/output --use-gpu
```
--------------------------------
### Download File Functionality (JavaScript)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/manual.html
Provides functions to download data as a file. `downloadFile` handles text data, while `download_bytes` handles binary data (like images). It dynamically creates links to trigger downloads.
```javascript
var gdata = null;
function downloadFile() {
download("text.json", gdata)
}
function download(filename, text) {
let element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
function download_bytes() {
const url = URL.createObjectURL(gdata);
const element = document.createElement('a');
element.setAttribute('href', url);
element.setAttribute('download', "image.png");
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
URL.revokeObjectURL(url);
}
```
--------------------------------
### Handle Keyboard Navigation for Modal (JavaScript)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
Manages keyboard input for image modal interactions. It supports closing the modal with 'Escape', navigating images with arrow keys, and toggling zoom with 'z'. Requires 'showImageModal', 'closeImageModal', 'previousImage', 'nextImage', and 'toggleZoom' functions to be defined.
```javascript
handleKeydown(event) {
if (!this.showImageModal) return;
switch (event.key) {
case 'Escape':
this.closeImageModal();
break;
case 'ArrowLeft':
this.previousImage();
break;
case 'ArrowRight':
this.nextImage();
break;
case 'z':
case 'Z':
this.toggleZoom();
break;
}
}
```
--------------------------------
### Handle Middle Mouse Button Drag on Image (JavaScript)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
Implements drag functionality for an image using the middle mouse button. It captures the drag start position and updates the image's translation based on mouse movement. Requires 'isDragging', 'dragStart', and 'dragStartTransform' properties to be managed.
```javascript
onImageMouseDown(event) {
if (event.button === 1) { // Middle mouse button
event.preventDefault();
this.isDragging = true;
this.dragStart = { x: event.clientX, y: event.clientY };
this.dragStartTransform = { ...this.imageTransform };
}
},
onImageMouseMove(event) {
if (this.isDragging && this.isImageZoomed) {
const deltaX = event.clientX - this.dragStart.x;
const deltaY = event.clientY - this.dragStart.y;
this.imageTransform.translateX = this.dragStartTransform.translateX + deltaX;
this.imageTransform.translateY = this.dragStartTransform.translateY + deltaY;
}
},
onImageMouseUp() {
this.isDragging = false;
}
```
--------------------------------
### Run All Tests with Pytest
Source: https://github.com/zyddnys/manga-image-translator/blob/main/test/README.md
Executes all tests within the 'test/' directory. This command is the standard way to ensure the entire project's test suite passes.
```bash
pytest test/
```
--------------------------------
### Utility Functions for File Formatting (JavaScript)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
Provides functions to format file sizes into human-readable units (B, KB, MB, etc.) and to display upload progress. These utilities are essential for user feedback during file operations.
```javascript
const BASE_URI = "./";
const acceptTypes = [
"image/png",
"image/jpeg",
"image/bmp",
"image/webp",
];
function formatSize(bytes) {
const k = 1024;
const sizes = ["B", "KB", "MB", "GB", "TB"];
if (bytes === 0) return "0B";
const i = Math.floor(Math.log(bytes) / Math.log(k));
return `${(bytes / k ** i).toFixed(2)}${sizes[i]}`;
}
function formatProgress(loaded, total) {
return `${formatSize(loaded)}/${formatSize(total)}`;
}
```
--------------------------------
### View Docker Compose Logs
Source: https://context7.com/zyddnys/manga-image-translator/llms.txt
Follows the logs of the manga-translator service running via Docker Compose. This command is useful for monitoring the application's activity and debugging issues.
```bash
# Check logs
docker-compose logs -f manga-translator
```
--------------------------------
### Deploy Translator with Docker Compose
Source: https://context7.com/zyddnys/manga-image-translator/llms.txt
Deploys the translator using Docker for containerized execution with GPU support. This Docker Compose file defines the service, image, ports, volumes, environment variables, and resource reservations for GPU usage.
```yaml
# docker-compose.yml
version: '3.8'
services:
manga-translator:
image: zyddnys/manga-image-translator:main
container_name: manga_translator
ports:
- "5003:5003"
- "8000:8000"
volumes:
- ./result:/app/result
- ./input:/app/input
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
- DEEPL_AUTH_KEY=${DEEPL_AUTH_KEY}
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
command: >
python server/main.py
--verbose
--start-instance
--host=0.0.0.0
--port=5003
--use-gpu
```
--------------------------------
### Sync Gallery with Results Directory
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
Fetches the list of completed translation folders from the server and synchronizes them with the local gallery state. It ensures new results are added and persists the gallery to localStorage.
```javascript
async syncGalleryWithResults() {
try {
const response = await fetch(`${BASE_URI}results/list`);
if (response.ok) {
const data = await response.json();
const folders = data.directories || [];
for (const folder of folders) {
const existingImage = this.finishedImages.find(img => img.result && img.result.includes(folder));
if (!existingImage) {
const finalResponse = await fetch(`${BASE_URI}result/${folder}/final.png`);
if (finalResponse.ok) {
this.finishedImages.unshift({ id: Date.now(), originalName: folder, result: `${BASE_URI}result/${folder}/final.png` });
}
}
}
}
} catch (error) {
console.warn('Failed to sync gallery:', error);
}
}
```
--------------------------------
### Manage Image Processing Queue in Vue
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
Handles the transition of images from 'queued' to 'processing' and 'finished' states. It includes logic for auto-triggering the next item in the queue and updating the UI state reactively.
```javascript
processNextInQueue() {
const nextItemIndex = this.queuedImages.findIndex(item => item.status === 'queued');
if (nextItemIndex !== -1) {
const nextItem = this.queuedImages[nextItemIndex];
this.queuedImages[nextItemIndex] = { ...nextItem, status: 'processing' };
this.processTranslation(this.queuedImages[nextItemIndex]);
}
}
```
--------------------------------
### Queue Management Functions (JavaScript)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
Provides functions to clear the currently selected single file, clear all selected files, and add selected files to the translation queue. It also includes a function to add multiple files to the queue and initiate processing.
```javascript
// Queue management
clearFile() {
this.file = null;
},
clearSelectedFiles() {
this.selectedFiles = [];
},
addSelectedFilesToQueue() {
if (this.selectedFiles.length > 0) {
this.addMultipleFilesToQueue(this.selectedFiles);
this.selectedFiles = [];
}
}
```
--------------------------------
### POST /translate/batch/images
Source: https://context7.com/zyddnys/manga-image-translator/llms.txt
Translates a batch of images provided as base64 strings and returns the result as a ZIP archive.
```APIDOC
## POST /translate/batch/images
### Description
Translates multiple manga images in one request and returns a ZIP archive containing the translated files.
### Method
POST
### Endpoint
/translate/batch/images
### Request Body
- **images** (array) - Required - List of base64 encoded image strings.
- **config** (object) - Required - Translation configuration settings (translator, target_lang).
- **batch_size** (integer) - Optional - Number of images to process in a single batch.
### Request Example
{
"images": ["data:image/png;base64,..."],
"config": {"translator": {"translator": "sugoi", "target_lang": "ENG"}},
"batch_size": 2
}
### Response
#### Success Response (200)
- **file** (binary) - ZIP archive containing translated images.
#### Response Example
Binary ZIP data
```
--------------------------------
### CLI Batch Translation with Manga Image Translator
Source: https://context7.com/zyddnys/manga-image-translator/llms.txt
Translate local images or folders using the command-line interface. Supports various options for specifying input, output, GPU acceleration, and translation models.
```bash
# Basic translation of a single image (Japanese to English)
python -m manga_translator local -v -i /path/to/manga_page.jpg
# Translate entire folder with GPU acceleration
python -m manga_translator local -v -i /path/to/manga_folder --use-gpu
# Specify target language (Chinese Simplified)
python -m manga_translator local -v -i /path/to/image.png \
--translator sugoi \
--target-lang CHS
# Full example with multiple options
python -m manga_translator local \
-v \
-i /path/to/images \
--use-gpu \
--translator chatgpt \
--target-lang ENG \
--detector ctd \
--ocr 48px \
--inpainter lama_large \
--font-path /path/to/custom_font.ttf \
--format png \
--overwrite
# Output is saved to: /path/to/images-translated/
```
--------------------------------
### POST /translate/with-form/image
Source: https://context7.com/zyddnys/manga-image-translator/llms.txt
Uploads an image file using multipart form data and returns the translated image file directly.
```APIDOC
## POST /translate/with-form/image
### Description
Uploads an image file and receives the processed, translated image as a binary response.
### Method
POST
### Endpoint
/translate/with-form/image
### Parameters
#### Request Body
- **image** (file) - Required - The image file to translate.
- **config** (string) - Optional - JSON string containing translation configurations.
### Request Example
curl -X POST "http://127.0.0.1:8000/translate/with-form/image" \
-F "image=@manga_page.png" \
-F 'config={"translator":{"translator":"chatgpt","target_lang":"ENG"}}' \
--output translated_page.png
### Response
#### Success Response (200)
- **image/png** (binary) - The translated image file.
```
--------------------------------
### Manga Image Translator Application Logic (JavaScript)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
The core logic for the Manga Image Translator application, built with Petite-Vue. It handles file uploads, settings persistence, translation queue management, gallery display, and real-time synchronization with results. It also includes extensive configuration options for translation and image processing.
```javascript
PetiteVue.createApp({
onmounted() {
window.addEventListener("paste", this.onpaste);
this.loadSettings();
this.loadFinishedImages();
// Sync gallery with results folder on page load
setTimeout(() => {
this.syncGalleryWithResults();
}, 1000);
// Periodically sync gallery with results folder
setInterval(() => {
this.syncGalleryWithResults();
}, 30000); // Sync every 30 seconds
// Add keyboard event listeners for modal navigation
window.addEventListener('keydown', this.handleKeydown);
},
file: null,
get fileUri() {
return this.file ? URL.createObjectURL(this.file) : null;
},
// New features: Queue and Gallery
queuedImages: [],
finishedImages: [],
showGallery: false,
selectedFiles: [], // Store multiple selected files before adding to queue
// Gallery modal
selectedImage: null,
showImageModal: false,
isImageZoomed: false,
imageTransform: {
scale: 1,
translateX: 0,
translateY: 0,
},
isDragging: false,
// Step tracking for progress
translationSteps: [
'upload',
'pending',
'detection',
'ocr',
'mask-generation',
'inpainting',
'upscaling',
'translating',
'rendering',
'finished',
],
// Map actual server status to step numbers for better progress tracking
statusToStep: {
'upload': 1,
'pending': 2,
'detection': 3,
'ocr': 4,
'mask-generation': 5,
'inpainting': 6,
'upscaling': 7,
'translating': 8,
'rendering': 9,
'finished': 10,
},
detectionResolution: "1536",
textDetector: "default",
renderTextDirection: "auto",
translator: "youdao",
validTranslators: [
"youdao",
"baidu",
"deepl",
"papago",
"caiyun",
"sakura",
"offline",
"openai",
"deepseek",
"groq",
"gemini",
"custom_openai",
"nllb",
"nllb_big",
"m2m100",
"m2m100_big",
"mbart50",
"qwen2",
"qwen2_big",
"none",
"original",
],
getTranslatorName(key) {
if (key === "none") return "No Text";
return key ? key[0].toUpperCase() + key.slice(1) : "";
},
targetLanguage: "CHS",
inpaintingSize: "2048",
customUnclipRatio: 2.3,
customBoxThreshold: 0.7,
maskDilationOffset: 30,
inpainter: "lama_large",
uploadController: null,
// Settings change handlers for auto-saving
onSettingChange() {
this.saveSettings();
},
// Settings persistence
loadSettings() {
try {
const saved = localStorage.getItem('manga-translator-settings');
if (saved) {
const settings = JSON.parse(saved);
if (settings.detectionResolution) this.detectionResolution = settings.detectionResolution;
if (settings.textDetector) this.textDetector = settings.textDetector;
if (settings.renderTextDirection) this.renderTextDirection = settings.renderTextDirection;
if (settings.translator) this.translator = settings.translator;
if (settings.targetLanguage) this.targetLanguage = settings.targetLanguage;
if (settings.inpaintingSize) this.inpaintingSize = settings.inpaintingSize;
if (settings.customUnclipRatio) this.customUnclipRatio = settings.customUnclipRatio;
if (settings.customBoxThreshold) this.customBoxThreshold = settings.customBoxThreshold;
if (settings.maskDilationOffset) this.maskDilationOffset = settings.maskDilationOffset;
if (settings.inpainter) this.inpainter = settings.inpainter;
}
} catch (error) {
console.warn('Failed to load settings:', error);
}
},
saveSettings() {
try {
const settings = {
detectionResolution: this.detectionResolution,
textDetector: this.textDetector,
renderTextDirection: this.renderTextDirection,
translator: this.translator,
targetLanguage: this.targetLanguage,
inpaintingSize: this.inpaintingSize,
customUnclipRatio: this.customUnclipRatio,
customBoxThreshold: this.customBoxThreshold,
maskDilationOffset: this.maskDilationOffset,
inpainter: this.inpainter,
};
localStorage.setItem('manga-translator-settings', JSON.stringify(settings));
} catch (error) {
console.warn('Failed to save settings:', error);
}
},
ondrop(e) {
const files = Array.from(e.dataTransfer?.files || []);
const validFiles = files.filter(file => acceptTypes.includes(file.type));
if (validFiles.length === 1 && !this.file && this.selectedFiles.length === 0) {
// Single file and no current file or selected files - maintain existing behavior
this.file = validFiles[0];
this.selectedFiles = []; // Clear any selected files
} else if (validFiles.length > 0) {
// Multiple files o
```
--------------------------------
### Configure Translation Settings with JSON
Source: https://context7.com/zyddnys/manga-image-translator/llms.txt
Defines comprehensive translation settings in a JSON configuration file. This file allows customization of rendering, upscaling, translation, detection, colorization, inpainting, and OCR parameters.
```json
{
"filter_text": null,
"render": {
"renderer": "default",
"alignment": "auto",
"disable_font_border": false,
"font_size_offset": 0,
"font_size_minimum": -1,
"direction": "auto",
"uppercase": false,
"lowercase": false,
"gimp_font": "Sans-serif",
"no_hyphenation": false,
"font_color": null,
"line_spacing": null,
"font_size": null,
"rtl": true
},
"upscale": {
"upscaler": "esrgan",
"revert_upscaling": false,
"upscale_ratio": null
},
"translator": {
"translator": "chatgpt",
"target_lang": "ENG",
"no_text_lang_skip": false,
"skip_lang": "ENG",
"gpt_config": "gpt_config.yaml",
"translator_chain": null,
"selective_translation": null,
"enable_post_translation_check": true,
"post_check_max_retry_attempts": 3
},
"detector": {
"detector": "default",
"detection_size": 2048,
"text_threshold": 0.5,
"det_rotate": false,
"det_auto_rotate": false,
"det_invert": false,
"det_gamma_correct": false,
"box_threshold": 0.7,
"unclip_ratio": 2.3
},
"colorizer": {
"colorization_size": 576,
"denoise_sigma": 30,
"colorizer": "none"
},
"inpainter": {
"inpainter": "lama_large",
"inpainting_size": 2048,
"inpainting_precision": "bf16"
},
"ocr": {
"use_mocr_merge": false,
"ocr": "48px",
"min_text_length": 0,
"ignore_bubble": 0
},
"kernel_size": 3,
"mask_dilation_offset": 20
}
```
--------------------------------
### Navigate Between Images (JavaScript)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
Provides functions to move to the next or previous image in a list. When switching images, it resets the zoom and translation state. Assumes 'finishedImages' and 'selectedImage' are managed, and 'isImageZoomed' and 'imageTransform' are available for reset.
```javascript
nextImage() {
if (this.selectedImage) {
const currentIndex = this.finishedImages.findIndex(img => img.id === this.selectedImage.id);
if (currentIndex < this.finishedImages.length - 1) {
this.selectedImage = this.finishedImages[currentIndex + 1];
// Reset transform when switching images
this.isImageZoomed = false;
this.imageTransform = { scale: 1, translateX: 0, translateY: 0 };
}
}
},
previousImage() {
if (this.selectedImage) {
const currentIndex = this.finishedImages.findIndex(img => img.id === this.selectedImage.id);
if (currentIndex > 0) {
this.selectedImage = this.finishedImages[currentIndex - 1];
// Reset transform when switching images
this.isImageZoomed = false;
this.imageTransform = { scale: 1, translateX: 0, translateY: 0 };
}
}
}
```
--------------------------------
### File Selection Dialogs (JavaScript)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
Dynamically creates and triggers hidden file input elements to allow users to select multiple files or an entire folder of images. The selected valid image files are then stored in 'this.selectedFiles'.
```javascript
selectMultipleFiles() {
// Create a temporary file input for multiple file selection
const input = document.createElement('input');
input.type = 'file';
input.accept = 'image/png,image/jpeg,image/bmp,image/webp';
input.multiple = true;
input.onchange = (e) => {
const files = Array.from(e.target.files || []);
const validFiles = files.filter(file => acceptTypes.includes(file.type));
if (validFiles.length > 0) {
this.selectedFiles = validFiles;
this.file = null; // Clear single file
}
};
input.click();
},
selectFolder() {
// Create a temporary file input for folder selection
const input = document.createElement('input');
input.type = 'file';
input.accept = 'image/png,image/jpeg,image/bmp,image/webp';
input.webkitdirectory = true;
input.multiple = true;
input.onchange = (e) => {
const files = Array.from(e.target.files || []);
const validFiles = files.filter(file => acceptTypes.includes(file.type));
if (validFiles.length > 0) {
this.selectedFiles = validFiles;
this.file = null; // Clear single file
}
};
input.click();
}
```
--------------------------------
### Calculate Step Progress for Queued Image (JavaScript)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
Calculates the progress percentage for a queued image based on its status. It maps specific status strings to numerical steps and computes the overall progress. Handles 'queued', 'finished', 'error', and 'processing' statuses, with fallback for unknown statuses. Relies on a 'stepMap' and 'totalSteps' for calculation.
```javascript
getStepProgress(queuedImage) {
console.log('Calculating progress for status:', queuedImage.status);
if (!queuedImage.status || queuedImage.status === 'queued') {
return { percentage: 0 };
}
// Map status to step number for progress calculation
const stepMap = {
'upload': 1,
'pending': 2,
'detection': 3,
'ocr': 4,
'mask-generation': 5,
'inpainting': 6,
'upscaling': 7,
'translating': 8,
'rendering': 9,
'finished': 10
};
const currentStep = stepMap[queuedImage.status];
console.log('Status maps to step:', currentStep);
if (currentStep === undefined) {
// If status is not in our map, estimate based on known steps
if (queuedImage.status === 'error') {
return { percentage: 0 };
}
if (queuedImage.status === 'processing') { // For 'processing' status, show 0% until we get actual step updates
return { percentage: 0 };
}
// For unknown status, assume it's in the middle
return { percentage: 50 };
}
const totalSteps = 10;
const percentage = Math.round(((currentStep - 1) / (totalSteps - 1)) * 100);
console.log('Progress result:', { percentage });
return { percentage: percentage };
}
```
--------------------------------
### Image Upload and Translation Logic (JavaScript)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/manual.html
Handles the core logic for uploading an image file and sending it for translation. It manages UI element states, constructs form data, and initiates the fetch request. It also includes error handling and status updates.
```javascript
async function uploadAndTranslate() {
const errorField = document.getElementById('error');
const statusField = document.getElementById('status');
let submitButton = document.getElementById("submit-button")
const fileInput = document.getElementById('fileInput');
const generateImage = document.getElementById('generate-image');
const configField = document.getElementById('config-json');
submitButton.classList.add("hidden");
fileInput.classList.add("hidden");
generateImage.classList.add("hidden");
configField.classList.add("hidden");
statusField.innerHTML = '';
errorField.innerHTML = '';
const file = fileInput.files[0];
if (!file) {
alert('Please select an image file.');
return;
}
statusField.innerHTML = 'Uploading...';
const formData = new FormData();
formData.append('image', file);
const text = configField.innerText;
if (text.length > 2) {
formData.append('config', text)
}
try {
const response = await fetch( generateImage.checked ? '/translate/with-form/image/stream' : '/translate/with-form/json/stream', {
method: 'POST',
body: formData,
/*headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ image: base64Image, config: { translator: { target_lang: "ENG" } } }) */
});
await process(response, statusField, errorField, generateImage.checked)
} catch (error) {
errorField.innerHTML = response.statusText;
} finally {
submitButton.classList.remove("hidden");
fileInput.classList.remove("hidden");
generateImage.classList.remove("hidden");
configField.classList.remove("hidden");
}
}
```
--------------------------------
### Load and Add Finished Images (JavaScript)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
Handles loading previously translated images from local storage and adding new translated images to this collection. It includes error handling for local storage access and stores relevant metadata for each finished image.
```javascript
loadFinishedImages() {
try {
const saved = localStorage.getItem('manga-translator-finished-images');
if (saved) {
this.finishedImages = JSON.parse(saved);
}
} catch (error) {
console.warn('Failed to load finished images:', error);
}
},
addToFinishedImages(imageData) {
const finishedImage = {
id: Date.now() + Math.random(),
originalName: imageData.name || 'Unknown',
result: imageData.result,
finishedAt: new Date(),
settings: {
detectionResolution: this.detectionResolution,
textDetector: this.textDetector,
renderTextDirection: this.renderTextDirection,
translator: this.translator,
targetLanguage: this.targetLanguage,
inpaintingSize: this.inpaintingSize,
customUnc
}
};
this.finishedImages.push(finishedImage);
// Optionally save to local storage here
}
```
--------------------------------
### REST API: Batch Translation with Manga Image Translator
Source: https://context7.com/zyddnys/manga-image-translator/llms.txt
Perform batch translation of multiple images in a single request using the REST API. Specify a list of image URLs and configure translation settings and batch size.
```bash
# Batch translate multiple images
curl -X POST "http://127.0.0.1:8000/translate/batch/json" \
-H "Content-Type: application/json" \
-d '{
"images": [
"https://example.com/page1.jpg",
"https://example.com/page2.jpg",
"https://example.com/page3.jpg"
],
"config": {
"translator": {"translator": "chatgpt", "target_lang": "ENG"}
},
"batch_size": 4
}'
```
--------------------------------
### POST /translate/batch/json
Source: https://context7.com/zyddnys/manga-image-translator/llms.txt
Translates multiple images in a single request for improved throughput.
```APIDOC
## POST /translate/batch/json
### Description
Processes a list of image URLs in a single batch request.
### Method
POST
### Endpoint
/translate/batch/json
### Request Body
- **images** (array) - Required - List of image URLs.
- **config** (object) - Optional - Translation settings.
- **batch_size** (integer) - Optional - Number of images to process concurrently.
### Request Example
{
"images": ["https://example.com/page1.jpg", "https://example.com/page2.jpg"],
"config": {"translator": {"translator": "chatgpt", "target_lang": "ENG"}},
"batch_size": 4
}
```
--------------------------------
### Manage Image Lifecycle and Queue Processing
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
Handles the post-processing of translated images by updating the local gallery and triggering queue automation. It includes methods to clear finished items and automatically process the next item in the queue after specified delays.
```javascript
this.addToFinishedImages({ name: item.file.name, result: `${BASE_URI}result/${this.currentFolder || 'test'}/final.png` });
setTimeout(() => { this.clearFinishedItems(); }, 2000);
setTimeout(() => { this.processNextInQueue(); }, 1000);
```
--------------------------------
### Handle Image Modal Zoom Interaction
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
Provides functionality to toggle zoom levels on images within the modal. It calculates the transform origin based on the user's click coordinates for a localized zoom effect.
```javascript
toggleZoom(event) {
if (this.isImageZoomed) {
this.isImageZoomed = false;
this.imageTransform = { scale: 1, translateX: 0, translateY: 0 };
} else {
this.isImageZoomed = true;
this.imageTransform.scale = 2;
if (event) {
const rect = event.target.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
event.target.style.transformOrigin = `${x}px ${y}px`;
}
}
}
```
--------------------------------
### Handle File Input Changes (JavaScript)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
Processes file inputs from user selections, filtering for accepted image types. It distinguishes between single file uploads (setting 'this.file') and multiple file uploads (setting 'this.selectedFiles').
```javascript
onfilechange(e) {
const files = Array.from(e.target.files || []);
const validFiles = files.filter(file => acceptTypes.includes(file.type));
if (validFiles.length === 1) {
// Single file - maintain existing behavior
this.file = validFiles[0];
this.selectedFiles = []; // Clear any selected files
} else if (validFiles.length > 1) {
// Multiple files - store them for preview, don't add to queue yet
this.selectedFiles = validFiles;
this.file = null; // Clear single file
// Clear the file input
e.target.value = '';
}
}
```
--------------------------------
### Skip Current Translation and Move to Next (JavaScript)
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
Allows skipping the current translation process. It aborts any ongoing upload, marks the current item as 'error' with a 'Skipped by user' message, and then clears finished items and proceeds to the next item in the queue. Requires 'uploadController', 'clearFinishedItems', and 'processNextInQueue' to be available.
```javascript
skipCurrentTranslation() {
console.log('Skip current translation called');
console.log('Current queued images:', this.queuedImages);
const processingItemIndex = this.queuedImages.findIndex(item => item.status === 'processing');
console.log('Processing item index:', processingItemIndex);
if (processingItemIndex !== -1) {
const processingItem = this.queuedImages[processingItemIndex];
console.log('Found processing item:', processingItem);
// Abort current translation
this.uploadController?.abort();
console.log('Aborted upload controller');
// Mark current item as skipped/error
this.queuedImages[processingItemIndex] = { ...processingItem, status: 'error', error: 'Skipped by user' };
console.log('Marked item as skipped');
// Clear finished/error items and move to next
setTimeout(() => {
this.clearFinishedItems();
this.processNextInQueue();
}, 1000);
} else {
}
}
```
--------------------------------
### Reset Application State
Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html
Resets the application state variables to their initial values and aborts any active upload controllers. This is used to clear the current session data.
```javascript
clear() {
this.uploadController?.abort();
this.file = null;
this.result = null;
this.currentFolder = null;
this.finalPngDisplayed = false;
this.useFileResult = true;
this.status = null;
this.progress = null;
this.queuePos = null;
this.errorMessage = null;
}
```