Skip to main content

Post-render HTML and frontend UI dictionary translation for Python projects with OpenAI-backed caching

Project description

auto-i18n-lib

Lightweight post-render translation for Python applications.

auto-i18n-lib translates already rendered HTML and frontend UI dictionaries without changing templates, business logic, or database structure.

The library uses file-based language caches and background translation processing.

Features

  • Post-render HTML translation
  • Frontend UI dictionary translation for JS interfaces
  • No synchronous translation calls during page render
  • Per-language JSON cache
  • Shared cache for HTML and UI strings
  • Background translation worker
  • Nested dict / list support for UI dictionaries
  • Language normalization
  • Fallback language chain
  • Legacy page cache compatibility

Installation

pip install auto-i18n-lib

## Requirements

* Python 3.9+
* OpenAI API key

## Environment

You can configure the library via constructor arguments or environment variables.

```bash
export OPENAI_API_KEY="your_key"
export SOURCE_LANG="ru"

Windows PowerShell:

$env:OPENAI_API_KEY="your_key"
$env:SOURCE_LANG="ru"

Core idea

Render mode

During page render, the library:

  • reads translations only from ready cache files
  • does not call the translation API
  • returns original text if translation is missing

Background mode

In the background, the library:

  • scans registered pages
  • finds missing strings
  • adds them to pending queue
  • translates them in batches
  • updates language cache files

This keeps page rendering fast and stable.

Quick start

from autoi18n import Translator

translator = Translator(
    api_key="YOUR_OPENAI_API_KEY",
    cache_dir="./translations",
    source_lang="ru",
)

html = """
<h1>Главная</h1>
<p>Добро пожаловать в систему</p>
<button>Сохранить</button>
"""

translated_html = translator.translate_html(
    html=html,
    target_lang="en",
    page_name="home",
)

print(translated_html)

UI dictionary translation

Use translate_dict() for frontend tables, modals, forms, and other JS-driven UI.

ui = {
    "title": "Грузы",
    "filters": {
        "search": "Поиск",
        "reset": "Сбросить"
    },
    "modal": {
        "save": "Сохранить",
        "cancel": "Отмена"
    }
}

translated_ui = translator.translate_dict(
    page_name="cargo",
    dict_name="table",
    source_dict=ui,
    target_lang="en",
)

You can also restrict translation to specific keys:

translated_ui = translator.translate_dict(
    page_name="cargo",
    dict_name="table",
    source_dict=ui,
    target_lang="en",
    filter_keys=["title", "search", "save", "cancel"],
)

Django example

View

import json
from django.shortcuts import render
from autoi18n import Translator

translator = Translator(
    api_key="YOUR_OPENAI_API_KEY",
    cache_dir="./translations",
    source_lang="ru",
)

def cargo_page(request):
    target_lang = translator.detect_browser_lang(
        request.headers.get("Accept-Language", "")
    )

    html = """
    <h1>Грузы</h1>
    <button>Сохранить</button>
    """

    translated_html = translator.translate_html(
        html=html,
        target_lang=target_lang,
        page_name="cargo_page",
    )

    ui = {
        "title": "Грузы",
        "search": "Поиск",
        "empty": "Нет данных",
        "save": "Сохранить",
        "cancel": "Отмена",
    }

    translated_ui = translator.translate_dict(
        page_name="cargo_page",
        dict_name="table_ui",
        source_dict=ui,
        target_lang=target_lang,
    )

    return render(request, "cargo/page.html", {
        "translated_html": translated_html,
        "ui_json": json.dumps(translated_ui, ensure_ascii=False),
    })

Template

<div>
    {{ translated_html|safe }}
</div>

<script>
    window.CARGO_I18N = {{ ui_json|safe }};
</script>

JavaScript

const i18n = window.CARGO_I18N || {};

document.querySelector("#title").textContent = i18n.title || "Грузы";
document.querySelector("#search").placeholder = i18n.search || "Поиск";
document.querySelector("#empty").textContent = i18n.empty || "Нет данных";

Background page registration

Register pages for automatic background scanning.

def render_dashboard():
    return """
    <h1>Панель управления</h1>
    <button>Продолжить</button>
    """

translator.register_page(
    page_name="dashboard",
    html_getter=render_dashboard,
    target_langs=["en", "az", "tr"],
)

Background processing

Process all registered pages once:

report = translator.process_all_translations(batch_size=50)
print(report)

Run background loop:

translator.run_translation_loop(interval=300, batch_size=50)

Run in a separate thread:

import threading

threading.Thread(
    target=translator.run_translation_loop,
    kwargs={"interval": 300, "batch_size": 50},
    daemon=True,
).start()

Public API

Translator(...)

Translator(
    cache_dir="./translations",
    api_key=None,
    source_lang=None,
    model="gpt-4o-mini",
)

register_page(page_name, html_getter, target_langs, context=None)

Registers a page for background scanning.

scan_page(page_name, target_lang)

Scans one registered page and returns missing items.

scan_all_pages()

Scans all registered pages and all configured target languages.

process_page_translations(page_name, target_lang, batch_size=50)

Processes missing translations for one page and one language.

process_all_translations(batch_size=50)

Processes all registered pages.

run_translation_loop(interval=300, target_lang=None, page_name="page", stop_event=None, batch_size=50)

Runs continuous background translation loop.

translate_text(text, target_lang, page_name="page", prompt_type="normal")

Returns translated text from cache if available. If translation is missing, returns original text and adds it to pending queue.

translate_html(html, target_lang, page_name="page")

Translates rendered HTML using cache. Missing strings remain unchanged until background processing fills them.

translate_dict(page_name, dict_name, source_dict, target_lang=None, filter_keys=None)

Translates frontend UI dictionaries.

Rules:

  • supports nested dict and list
  • stores keys as ui::page_name::dict_name::path
  • returns original values if translation is missing
  • uses the same cache and pending queue as HTML translation

enqueue_missing_texts(items, target_lang, page_name="page")

Adds missing items to pending queue.

get_pending_entries(target_lang=None)

Returns current pending items.

process_pending_translations(target_lang=None, page_name="page", batch_size=50)

Processes pending queue.

get_translation_coverage(lang)

Returns translation statistics for one language.

Example response:

{
    "lang": "en",
    "translated": 120,
    "pending": 8,
    "total": 128,
    "percent": 93.75
}

detect_browser_lang(accept_language)

Extracts and normalizes browser language from Accept-Language.

get_alternative_lang(current_lang, browser_lang)

Returns helper language for language switch logic.

Language normalization

The library normalizes language codes before using them in cache files.

Examples:

  • EN -> en
  • en_US -> en-us
  • en-US -> en-us

Fallback chain

When translation is missing, the library checks fallback languages.

Example:

en-us -> en -> source_lang

If nothing is found, the original text is returned.

Cache structure

Translations are stored as JSON files in the cache directory.

translations/
  en.json
  az.json
  tr.json
  _pending.json

Example cache content:

{
  "Сохранить": "Save",
  "ui::cargo::table::title": "Cargo",
  "ui::cargo::table::filters.search": "Search"
}

What is translated

The library translates:

  • visible HTML text nodes

  • button labels

  • selected HTML attributes:

    • placeholder
    • title
    • alt
    • aria-label
    • value for button-like inputs
  • frontend UI dictionaries

What is skipped

The parser skips:

  • script
  • style
  • noscript

It also skips:

  • elements with translate="no"
  • elements with data-translate="no"
  • element with id="langSwitch"
  • pure numbers
  • number-like strings
  • hashes / UUID-like strings
  • many technical values

PDF usage

Do not translate a generated PDF file.

Correct flow:

render HTML -> translate_html -> generate PDF

Recommended integration pattern

Use the library like this:

  1. Render HTML as usual
  2. Translate rendered HTML through translate_html()
  3. Pass JS UI strings through translate_dict()
  4. Run background worker to complete missing translations
  5. Generate PDF only from already translated HTML

Limitations

  • The library works on rendered HTML, not templates
  • Translation quality depends on source text quality
  • Highly unstable HTML reduces cache reuse efficiency
  • JS string extraction is manual: developer passes UI dictionaries explicitly

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

auto_i18n_lib-0.5.0.tar.gz (15.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

auto_i18n_lib-0.5.0-py3-none-any.whl (16.6 kB view details)

Uploaded Python 3

File details

Details for the file auto_i18n_lib-0.5.0.tar.gz.

File metadata

  • Download URL: auto_i18n_lib-0.5.0.tar.gz
  • Upload date:
  • Size: 15.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.0

File hashes

Hashes for auto_i18n_lib-0.5.0.tar.gz
Algorithm Hash digest
SHA256 12875b666f9d6f136f0bc59dcc6c56f84f7527fcfa43b5529a065e794bb75fdc
MD5 f1011d6d42328aecd0c400b27cfb26d7
BLAKE2b-256 c09ba8da83f14432495e366c9183cbf4430c471b58009370ed9822fc3edd4bf5

See more details on using hashes here.

File details

Details for the file auto_i18n_lib-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: auto_i18n_lib-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 16.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.0

File hashes

Hashes for auto_i18n_lib-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 427f6501fef22a8b8f56ad9667dc13d6e35a081ba4af6f6596700a6d00afe2f4
MD5 d1bdecebbe73277e4d7dab388763e7bb
BLAKE2b-256 c357560f7439aff4c739be25cd2a80a16d247b59ab7b442276fd4ed9eefcc55e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page