diff --git a/README.md b/README.md index 9388501..976485f 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,11 @@ webdrop-bridge/ └── README.md # This file ``` +## Documentation + +- [Architecture Guide](docs/ARCHITECTURE.md) +- [Translations Guide (i18n)](docs/TRANSLATIONS_GUIDE.md) + ## Architecture ``` diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index c1cf8be..2ac38c4 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1,5 +1,9 @@ # Architecture Guide +## Related Docs + +- [Translations Guide (i18n)](TRANSLATIONS_GUIDE.md) + ## High-Level Design ``` diff --git a/docs/TRANSLATIONS_GUIDE.md b/docs/TRANSLATIONS_GUIDE.md new file mode 100644 index 0000000..7896c88 --- /dev/null +++ b/docs/TRANSLATIONS_GUIDE.md @@ -0,0 +1,205 @@ +# Translations Guide (i18n) + +This document explains how to: +- add a new language +- edit an existing language +- update translations when new text is added in the app + +The app uses JSON-based translations loaded from: +- resources/translations/ + +## 1. Translation System Overview + +Main components: +- src/webdrop_bridge/utils/i18n.py + - Loads language JSON files + - Provides tr("key", **kwargs) + - Falls back to English if a key is missing +- src/webdrop_bridge/main.py + - Initializes i18n at app startup +- src/webdrop_bridge/config.py + - Stores selected language in config (language field) +- src/webdrop_bridge/ui/settings_dialog.py + - Language selector in Settings -> General + +Current language files: +- resources/translations/en.json +- resources/translations/de.json +- resources/translations/fr.json +- resources/translations/it.json +- resources/translations/ru.json +- resources/translations/zh.json + +## 2. Add a New Language + +Example: add Spanish (es). + +1. Create a new file: + - resources/translations/es.json + +2. Copy the full structure from English: + - Copy resources/translations/en.json to resources/translations/es.json + +3. Translate all values in es.json: + - Keep all keys exactly the same + - Only change text values + - Keep placeholders unchanged, for example: + - {name} + - {version} + - {error} + +4. Add language display name in i18n helper: + - Edit src/webdrop_bridge/utils/i18n.py + - In Translator.BUILTIN_LANGUAGES add: + - "es": "Español" + +5. Start app and test: + - Choose language in Settings -> General + - Restart app when prompted + - Verify tooltips, dialogs, status texts, settings labels, update dialogs + +## 3. Edit an Existing Language + +1. Open the language file, for example: + - resources/translations/de.json + +2. Update only text values. + +3. Do not: + - remove keys + - rename keys + - change placeholder names + +4. Validate JSON formatting: + - Must be valid JSON + - Keep UTF-8 encoding + +5. Test in app: + - Select language in Settings + - Restart and verify changed text appears + +## 4. When New Text Is Added in the App + +Whenever new UI text is introduced in code, follow this process. + +### Step A: Add a new translation key in code + +Instead of hardcoded text, use tr("...") with a key. + +Example: +- Before: QLabel("Check for Updates") +- After: QLabel(tr("toolbar.tooltip.check_updates")) + +If dynamic text is needed: +- tr("update.status.available", version=release.version) + +### Step B: Add the key to English first + +1. Add the new key in: + - resources/translations/en.json + +2. Use clear key naming by area, for example: +- toolbar.tooltip.* +- dialog.* +- settings.* +- update.* +- status.* +- worker.* + +### Step C: Add the same key to all other language files + +Update each file in resources/translations: +- de.json +- fr.json +- it.json +- ru.json +- zh.json +- and any new language file + +If translation is not ready yet, copy English temporarily (better than missing key text in UI). + +### Step D: Test fallback and real translations + +1. Run app in English and verify new text. +2. Run app in other languages and verify translated text. +3. Confirm no raw key appears in UI (for example: dialog.my_new_key). + +## 5. Placeholder Rules + +Placeholders must match exactly between code and translation values. + +If code uses: +- tr("status.opened", name=file_name) + +Then translation must contain: +- "status.opened": "Opened: {name}" + +Common mistakes: +- wrong placeholder name ({filename} vs {name}) +- missing placeholder +- extra placeholder not passed by code + +## 6. Recommended Workflow for Translation Updates + +1. Implement UI text with tr("key") in code. +2. Add key to en.json. +3. Copy key to all language files. +4. Run tests. +5. Smoke test manually in app. + +Useful test command: +- python -m pytest tests/unit/test_i18n.py -q + +Recommended additional checks when UI changed: +- python -m pytest tests/unit/test_settings_dialog.py tests/unit/test_update_manager_ui.py tests/unit/test_startup_check.py -q + +## 7. Troubleshooting + +### Problem: Language changed in settings but UI language did not change + +Expected behavior: +- language is applied after restart + +Check: +- language value saved in config file +- restart prompt appears after changing language +- selected language JSON file exists and is valid + +### Problem: UI shows translation key text instead of real text + +Example shown in UI: +- settings.title + +Cause: +- key missing in selected language and missing in en.json fallback + +Fix: +- add key to en.json +- add key to selected language file + +### Problem: Text formatting errors + +Cause: +- placeholder mismatch + +Fix: +- compare tr(...) arguments in code with placeholders in translation string + +## 8. Best Practices + +- Keep en.json as complete source of truth. +- Keep key names stable once released. +- Group keys by feature area. +- Prefer short, user-friendly text in UI. +- Use formal, consistent tone per language. +- Review non-Latin languages (RU/ZH) with a native speaker when possible. + +## 9. Quick Checklist + +When adding new text: +- Add tr("new.key") in code +- Add key in en.json +- Add key in all other language files +- Verify placeholders +- Run i18n and impacted UI tests +- Manual in-app check with at least one non-English language