Auto-generated translation updates from the English source file (`web/src/locales/languages/en-US.json`). 🤖 Generated with automated translation workflow Co-authored-by: github-merge-queue[bot] <118344674+github-merge-queue[bot]@users.noreply.github.com> Co-authored-by: Hengfei Yang <hengfei.yang@gmail.com>
Translation Management
Automated translation system for OpenObserve using DeepSeek (an LLM) via its OpenAI-compatible API.
Overview
This system automatically translates the English locale file (en-US.json) into multiple languages during the build process. It intelligently preserves existing translations and only translates new keys, making it safe to run repeatedly.
🚀 How It Works
Automatic workflow triggered by en-US.json changes:
- Developer updates
en-US.jsonand pushes to any branch (main, develop, feature branches) - GitHub Action detects the change and automatically triggers
- Translation script runs using DeepSeek to update all language files
- Changes are committed back to the same branch automatically
- Build workflows use updated files - all subsequent builds have fresh translations
This means translations are always up-to-date without any manual intervention!
Supported Languages
- 🇹🇷 Turkish (tr)
- 🇨🇳 Chinese (zh)
- 🇫🇷 French (fr)
- 🇪🇸 Spanish (es)
- 🇩🇪 German (de)
- 🇮🇹 Italian (it)
- 🇵🇹 Portuguese (pt)
- 🇯🇵 Japanese (ja)
- 🇰🇷 Korean (ko)
- 🇳🇱 Dutch (nl)
How It Works
- Source File: All translations originate from
web/src/locales/languages/en-US.json - Translation: New/changed keys are translated by DeepSeek, in batches, with
interpolation placeholders (
{count},%s,@:linked.key) validated per string - Preservation: Existing translations are never overwritten unless their English source changed
- Nested Support: Handles nested JSON structures correctly
Local Development
Prerequisites
- Python 3.11+
- DeepSeek API key exported as
DEEPSEEK_API_KEY
Setup
# From the web directory
npm run translate:setup
Or manually:
cd scripts/translations
pip3 install -r requirements.txt
Configure the API key for Local Development
export DEEPSEEK_API_KEY=your_api_key
# optional overrides:
export DEEPSEEK_MODEL=deepseek-v4-flash # model id
export DEEPSEEK_BASE_URL=https://api.deepseek.com
export TRANSLATION_BATCH_SIZE=50 # strings per API call
Running Translations
Translate all languages:
# From the web directory
npm run translate
# Or directly
cd scripts/translations
python3 main.py
Translate specific languages:
cd scripts/translations
python3 main.py fr-FR es-ES de-DE
GitHub Actions Workflow
Automatic Translation Updates
The workflow (.github/workflows/update-translations.yml) automatically runs when:
- Trigger: Any push that modifies
web/src/locales/languages/en-US.json - Branches: All branches (
**) - Action:
- Runs Python translation script
- Updates all language JSON files
- Commits changes back to the same branch
- Subsequent builds use the updated files
Setup Requirements
The workflow authenticates to DeepSeek with an API key stored as a repository secret.
GitHub Repository Setup
Add one repository secret:
| Secret | Value |
|---|---|
DEEPSEEK_API_KEY |
Your DeepSeek API key |
Set it under Settings → Secrets and variables → Actions → New repository secret
(or via gh secret set DEEPSEEK_API_KEY). The workflow fails fast with a clear
error if this secret is missing.
Workflow Behavior
graph TD
A[Push Code to Branch] --> B[Update Translations Workflow]
B --> C{en-US.json Changed?}
C -->|Yes| D[Run Translation Script]
C -->|No| E[Skip Translation]
D --> F[Commit Updated Languages]
E --> G[Mark Complete]
F --> G
G --> H[Build Workflows Start]
H --> I[Build with Latest Translations]
Workflow Execution Order:
- Push code →
update-translations.ymlruns - Checks if
en-US.jsonchanged- If YES: Translates and commits back to branch
- If NO: Skips (fast, ~10 seconds)
- If translations were committed → New push event
- Build workflows trigger on the new commit → Use updated translations
Key Features:
- ✅ Always runs - Checks every push for en-US.json changes
- ✅ Smart detection - Only translates if en-US.json actually changed
- ✅ Non-blocking - Quick skip if no translation needed
- ✅ Auto-commit - Updates committed back to same branch
- ✅ Natural flow - Translation commit triggers builds automatically
- ✅ Works everywhere - All branches (main, develop, feature branches)
Manual Workflow Trigger
You can also run translations manually:
- Go to Actions tab in GitHub
- Select Update Translations workflow
- Click Run workflow
- (Optional) Specify specific languages:
fr-FR es-ES de-DE - Translations will be committed to the current branch
File Structure
scripts/translations/
├── README.md # This file
├── main.py # Entry point for translation script
├── translator.py # Core translation logic
└── requirements.txt # Python dependencies
web/src/locales/languages/
├── en-US.json # Source file (English)
├── tr-TR.json # Turkish translations
├── zh-CN.json # Chinese translations
├── fr-FR.json # French translations
├── es-ES.json # Spanish translations
├── de-DE.json # German translations
├── it-IT.json # Italian translations
├── pt-PT.json # Portuguese translations
├── ja-JP.json # Japanese translations
├── ko-KR.json # Korean translations
└── nl-NL.json # Dutch translations
Adding New Languages
- Add language code to
get_supported_languages()intranslator.py - Update the README to reflect the new language
- Run the translation script
Troubleshooting
Workflow Not Detecting en-US.json Changes
Symptom: You changed en-US.json but workflow says "en-US.json not modified"
Solution 1 - Check workflow logs:
- Go to Actions → Update Translations → Click the run
- Look at "Check if en-US.json was modified" step
- It shows debug info: event type, before/after SHAs, and changed files
Solution 2 - Debug detection:
# Locally check what git sees
git show --name-only --pretty="" HEAD
# Should show web/src/locales/languages/en-US.json
# Check last push
git diff HEAD~1 --name-only
Root cause: The detection uses git diff to compare commits. If:
- Multiple commits in one push → Uses
github.event.beforeandgithub.sha - First commit on branch → Uses
git show HEAD - Manual trigger → Uses
git show HEAD
API Key Error
DEEPSEEK_API_KEY is not set — cannot reach the translation service.
Solution: Set the DEEPSEEK_API_KEY secret (CI) or environment variable (local).
Import Error
ModuleNotFoundError: No module named 'openai'
Solution: Run npm run translate:setup or pip3 install -r requirements.txt
Translation Quality Issues
- Machine translations are not perfect
- Review translations before merging PRs
- Consider manual review for critical UI text
- Native speakers should review translations
Build Has Old Translations
Symptom: Build doesn't have the latest translations
Solution: Check if translation workflow ran and committed:
- Go to Actions → Find the Update Translations run
- Check if it detected en-US.json changes and committed translations
- If translations were committed, the commit should trigger a new build
- The new build will have updated translations
Workflow Example
Scenario: Adding New UI Text
-
Developer adds new text to
en-US.json:{ "dashboard": { "newFeature": "This is a new feature" } } -
Merge the
en-US.jsonchange tomain:git add web/src/locales/languages/en-US.json git commit -m "feat: add new dashboard feature text" # open a PR and merge to main -
Workflow automatically (on
mainonly):- Triggers because
web/src/locales/languages/en-US.jsonchanged - Runs translation script
- Translates only the new or modified keys to all 10 languages
- Commits updated
fr-FR.json,es-ES.json, etc. plus.translation_state.json
- Triggers because
-
Build workflows:
- Use the newly updated translation files
- No additional steps needed
Why
mainonly? Running on every feature branch re-translated the same strings repeatedly (per branch, per rebase, again on merge). Gating tomaintranslates each string once, when it actually lands.
Change detection (.translation_state.json)
scripts/translations/.translation_state.json records, per locale, a hash of the
English source each translated value was derived from. On every run the script:
- Translates a key only when it is new, missing in a target file, or its English source text changed since the last run (so editing an existing label re-translates it).
- Keeps already-translated text whose source is unchanged — it is never re-sent to the API, and English is never "translated" to English.
- Prunes keys that were removed from
en-US.json. - Bootstraps safely: the first run after this file is introduced adopts existing translations as-is (no costly full re-translation, no overwriting manual fixes).
Commit .translation_state.json together with the translation files — it is the
source of truth that keeps subsequent runs incremental.
Best Practices
- Review Commits: Check auto-generated translation commits for accuracy
- Test in UI: Verify translations display correctly in the application
- Manual Fixes: Manual edits to a key are preserved until its English source changes
- Context Matters: Some terms may need manual translation for proper context
- Land on
main: Translations are generated whenen-US.jsonis merged tomain
Cost Considerations
Translation is billed per token by DeepSeek. The whole en-US.json is ~205k
characters (~8,300 strings); a full 10-language rebuild is a one-time cost, and
day-to-day runs only translate the handful of new/changed keys per en-US.json
merge.
Cost Optimization:
- ✅ Only new or modified keys are translated (unchanged text is never re-sent)
- ✅ Strings are sent in batches (
TRANSLATION_BATCH_SIZE, default 50) to cut request overhead - ✅ Runs on
mainonly, and only whenen-US.jsonchanges (no per-branch re-billing) - ✅ Superseded runs are cancelled (
concurrencywithcancel-in-progress) - ✅ Failed API calls / placeholder-mismatched outputs are retried next run, not silently kept
Alternative Translation Services
To use a different backend, modify translate_batch() in translator.py. It uses
the OpenAI-compatible chat-completions API, so any provider exposing that interface
(OpenAI, DeepSeek, or a self-hosted model) drops in by changing DEEPSEEK_BASE_URL
and DEEPSEEK_MODEL.
Support
For issues or questions:
- Check this README first
- Review existing GitHub issues
- Create a new issue with the
translationslabel