fora
← Docs

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:

  1. Detects text regions in each image
  2. Translates the detected text into each target locale
  3. Inpaints the translated text back into the image, matching the original style
  4. Writes the result to your S3-compatible bucket
  5. 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

FieldReqDescription
bucket_nameYesS3 bucket name
regionNoAWS region (default: us-east-1)
access_key_idNoAWS access key (falls back to IAM role / env vars)
secret_access_keyNoAWS secret key
key_prefixNoPrefix for all output keys (e.g. translated/)
endpointNoCustom S3 endpoint for R2 / MinIO
public_urlNoCDN base URL (required when using a custom endpoint)