Image translation
Translate text inside images
Fora detects text in images, translates it, and inpaints the result — preserving the original font style, color, and background. Works for storefront signs, product banners, menu boards, and any image with visible text.
How it works
When you include source_image_urls in a translation job, Fora:
- Detects text regions in each image
- Translates the detected text into each target locale
- Inpaints the translated text back into the image, matching the original style
- Writes the result to your S3-compatible bucket
- Returns the output URLs in the job result
Fora holds no images at rest — they flow through and land in your bucket. Your source images must be publicly accessible URLs at job submission time.
1. Configure storage
Image output requires an S3-compatible bucket. Configure it once per account:
curl -X POST https://api.getfora.ai/v1/accounts/storage \
-H "Authorization: Bearer $FORA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"bucket_name": "my-translated-assets",
"region": "us-east-1",
"access_key_id": "AKIA...",
"secret_access_key": "..."
}'Cloudflare R2 / MinIO
Add endpoint and public_url for custom S3 endpoints:
{
"bucket_name": "my-translated-assets",
"endpoint": "https://<account>.r2.cloudflarestorage.com",
"public_url": "https://cdn.example.com",
"access_key_id": "...",
"secret_access_key": "..."
}2. Submit a job with images
Include source_image_urls alongside (or instead of) source_text. Both fields are optional — you can translate text only, images only, or both together.
curl -X POST https://api.getfora.ai/v1/translate \
-H "Authorization: Bearer $FORA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_image_urls": [
"https://cdn.example.com/storefront.jpg",
"https://cdn.example.com/menu-board.jpg"
],
"target_locales": ["es", "fr", "pt-BR"],
"webhook_url": "https://yourapp.com/webhooks/translations"
}'{
"job_id": "f3a8b2c1-...",
"status": "pending"
}Image jobs typically take 10–30 seconds per image depending on complexity. Use a webhook rather than polling for production workloads.
3. Receive translated image URLs
The webhook payload includes translated_image_urls for each locale:
{
"job_id": "f3a8b2c1-...",
"status": "completed",
"results": [
{
"locale": "es",
"translated_text": null,
"translated_image_urls": [
"https://my-bucket.s3.us-east-1.amazonaws.com/fora/f3a8b2c1/es/storefront_es.jpg",
"https://my-bucket.s3.us-east-1.amazonaws.com/fora/f3a8b2c1/es/menu-board_es.jpg"
]
},
{
"locale": "fr",
"translated_text": null,
"translated_image_urls": [
"https://my-bucket.s3.us-east-1.amazonaws.com/fora/f3a8b2c1/fr/storefront_fr.jpg",
"https://my-bucket.s3.us-east-1.amazonaws.com/fora/f3a8b2c1/fr/menu-board_fr.jpg"
]
}
]
}Output keys follow the pattern fora/{job_id}/{locale}/{filename}_{locale}.ext.
Using images with the Postgres connector
If you use the Fora connector, add image_fields to any table config. The connector generates pre-signed PUT URLs; the Fora server writes translated images directly to your bucket.
# fora.yaml
config:
tables:
- table: products
id_column: id
fields:
- name
- description
image_fields:
- hero_image_url # must contain a publicly accessible URL
s3:
bucket: my-app-translations
region: us-east-1
access_key_id: AKIA...
secret_access_key: ...Translated image URLs are stored in fora_translations and surfaced through the _localized view alongside the text fields — no extra queries needed.
Storage configuration reference
| Field | Req | Description |
|---|---|---|
| bucket_name | Yes | S3 bucket name |
| region | No | AWS region (default: us-east-1) |
| access_key_id | No | AWS access key (falls back to IAM role / env vars) |
| secret_access_key | No | AWS secret key |
| key_prefix | No | Prefix for all output keys (e.g. translated/) |
| endpoint | No | Custom S3 endpoint for R2 / MinIO |
| public_url | No | CDN base URL (required when using a custom endpoint) |