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/listsupport 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
dictandlist - 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->enen_US->en-usen-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:
placeholdertitlealtaria-labelvaluefor button-like inputs
-
frontend UI dictionaries
What is skipped
The parser skips:
scriptstylenoscript
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:
- Render HTML as usual
- Translate rendered HTML through
translate_html() - Pass JS UI strings through
translate_dict() - Run background worker to complete missing translations
- 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
12875b666f9d6f136f0bc59dcc6c56f84f7527fcfa43b5529a065e794bb75fdc
|
|
| MD5 |
f1011d6d42328aecd0c400b27cfb26d7
|
|
| BLAKE2b-256 |
c09ba8da83f14432495e366c9183cbf4430c471b58009370ed9822fc3edd4bf5
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
427f6501fef22a8b8f56ad9667dc13d6e35a081ba4af6f6596700a6d00afe2f4
|
|
| MD5 |
d1bdecebbe73277e4d7dab388763e7bb
|
|
| BLAKE2b-256 |
c357560f7439aff4c739be25cd2a80a16d247b59ab7b442276fd4ed9eefcc55e
|