mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-30 08:22:51 -05:00
Localization framework
This commit is contained in:
64
translations/README.md
Normal file
64
translations/README.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# DankMaterialShell Translations
|
||||
|
||||
This directory contains translation files for DankMaterialShell extracted from all qsTr() calls in the QML codebase.
|
||||
|
||||
## Files
|
||||
|
||||
- **en.json** - Source language file with English strings and file references
|
||||
- **template.json** - Empty template for creating new translations
|
||||
- **extract_translations.py** - Script to regenerate translation files
|
||||
|
||||
## POEditor Format
|
||||
|
||||
The JSON files follow POEditor's import format:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"term": "string to translate",
|
||||
"context": "file:line",
|
||||
"reference": "Modules/Settings/AboutTab.qml:45",
|
||||
"comment": ""
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Field Descriptions
|
||||
|
||||
- **term**: The source string in English (from qsTr() calls)
|
||||
- **context**: Primary location where the string appears (file:line)
|
||||
- **reference**: All locations where this string is used (comma-separated)
|
||||
- **comment**: Additional notes for translators (currently empty)
|
||||
|
||||
## How to Create a New Translation
|
||||
|
||||
1. Copy `template.json` to your language code (e.g., `es.json` for Spanish)
|
||||
2. Fill in the `translation` field for each entry:
|
||||
```json
|
||||
{
|
||||
"term": "Settings",
|
||||
"translation": "Configuración",
|
||||
"context": "Modals/Settings/SettingsModal.qml:147",
|
||||
"reference": "Modals/Settings/SettingsModal.qml:147",
|
||||
"comment": ""
|
||||
}
|
||||
```
|
||||
3. Import to POEditor or use directly in your translation workflow
|
||||
|
||||
## Regenerating Translation Files
|
||||
|
||||
To update the translation files after code changes:
|
||||
|
||||
```bash
|
||||
cd /home/brandon/.config/quickshell/DankMaterialShellGit/translations
|
||||
./extract_translations.py
|
||||
```
|
||||
|
||||
This will scan all QML files and regenerate `en.json` and `template.json`.
|
||||
|
||||
## Notes
|
||||
|
||||
- Strings are deduplicated - if the same string appears in multiple locations, references are merged
|
||||
- File paths are relative to the project root
|
||||
- Line numbers are preserved for accurate context
|
||||
- Empty strings and comments are reserved for translator notes
|
||||
185
translations/WORKFLOW.md
Normal file
185
translations/WORKFLOW.md
Normal file
@@ -0,0 +1,185 @@
|
||||
# Translation Workflow for DankMaterialShell
|
||||
|
||||
## POEditor Integration Guide
|
||||
|
||||
### Initial Setup
|
||||
|
||||
1. **Create POEditor Project**
|
||||
- Go to https://poeditor.com
|
||||
- Create new project "DankMaterialShell"
|
||||
- Add languages you want to support (es, fr, de, etc.)
|
||||
|
||||
2. **Import Source Strings**
|
||||
- Upload `en.json` as the source language
|
||||
- POEditor will detect 336 translatable strings
|
||||
- Format: Key-Value JSON
|
||||
|
||||
### Translation Workflow
|
||||
|
||||
#### Method 1: Using POEditor (Recommended)
|
||||
|
||||
1. **Upload source file**
|
||||
```bash
|
||||
# Upload en.json to POEditor
|
||||
```
|
||||
|
||||
2. **Translate in POEditor**
|
||||
- Use POEditor's web interface
|
||||
- Invite translators
|
||||
- Track progress per language
|
||||
|
||||
3. **Export translations**
|
||||
```bash
|
||||
# Download from POEditor as JSON
|
||||
# Save to translations/{language_code}.json
|
||||
# Example: translations/es.json, translations/fr.json
|
||||
```
|
||||
|
||||
4. **Test translations**
|
||||
```bash
|
||||
# Set your locale and restart shell
|
||||
export LANG=es_ES.UTF-8
|
||||
qs -p .
|
||||
```
|
||||
|
||||
#### Method 2: Manual Translation
|
||||
|
||||
1. **Copy template**
|
||||
```bash
|
||||
cp translations/template.json translations/es.json
|
||||
```
|
||||
|
||||
2. **Fill in translations**
|
||||
```json
|
||||
{
|
||||
"term": "Settings",
|
||||
"context": "Modals/Settings/SettingsModal.qml:147",
|
||||
"reference": "Modals/Settings/SettingsModal.qml:147",
|
||||
"comment": "",
|
||||
"translation": "Configuración"
|
||||
}
|
||||
```
|
||||
|
||||
3. **Upload to POEditor** (optional)
|
||||
|
||||
### Updating Translations After Code Changes
|
||||
|
||||
1. **Re-extract strings**
|
||||
```bash
|
||||
cd translations
|
||||
python3 extract_translations.py
|
||||
```
|
||||
|
||||
2. **Upload updated en.json to POEditor**
|
||||
- POEditor will detect new/removed strings
|
||||
- Preserves existing translations
|
||||
|
||||
3. **Download updated translations**
|
||||
|
||||
### Translation File Format
|
||||
|
||||
POEditor-compatible JSON format:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"term": "source string in English",
|
||||
"context": "file:line where it appears",
|
||||
"reference": "full/path/to/file.qml:123",
|
||||
"comment": "optional context for translators",
|
||||
"translation": "translated string"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Supported Languages
|
||||
|
||||
The shell will auto-detect your system locale. Supported format:
|
||||
- `es.json` → Spanish (es_ES, es_MX, etc.)
|
||||
- `fr.json` → French (fr_FR, fr_CA, etc.)
|
||||
- `de.json` → German
|
||||
- `zh.json` → Chinese
|
||||
- `ja.json` → Japanese
|
||||
- `pt.json` → Portuguese
|
||||
- etc.
|
||||
|
||||
### Testing Translations
|
||||
|
||||
1. **Change system locale**
|
||||
```bash
|
||||
export LANG=es_ES.UTF-8
|
||||
export LC_ALL=es_ES.UTF-8
|
||||
```
|
||||
|
||||
2. **Restart shell**
|
||||
```bash
|
||||
qs -p .
|
||||
```
|
||||
|
||||
3. **Verify translations appear correctly**
|
||||
|
||||
### File Structure
|
||||
|
||||
```
|
||||
translations/
|
||||
├── en.json # Source language (English)
|
||||
├── template.json # Empty template for new languages
|
||||
├── es.json # Spanish translation
|
||||
├── fr.json # French translation
|
||||
├── extract_translations.py # Auto-extraction script
|
||||
├── README.md # Technical documentation
|
||||
└── WORKFLOW.md # This file
|
||||
```
|
||||
|
||||
### Translation Statistics
|
||||
|
||||
- **Total strings:** 336 unique terms
|
||||
- **Most translated components:**
|
||||
- Settings UI: 202 strings (60%)
|
||||
- Weather: 25 strings (7%)
|
||||
- System monitors: Various
|
||||
- Modals: 43 strings (13%)
|
||||
|
||||
### POEditor API Integration (Advanced)
|
||||
|
||||
For automated sync, use POEditor's API:
|
||||
|
||||
```bash
|
||||
# Export from POEditor
|
||||
curl -X POST https://api.poeditor.com/v2/projects/export \
|
||||
-d api_token="YOUR_TOKEN" \
|
||||
-d id="PROJECT_ID" \
|
||||
-d language="es" \
|
||||
-d type="key_value_json"
|
||||
|
||||
# Import to POEditor
|
||||
curl -X POST https://api.poeditor.com/v2/projects/upload \
|
||||
-d api_token="YOUR_TOKEN" \
|
||||
-d id="PROJECT_ID" \
|
||||
-d updating="terms_translations" \
|
||||
-d language="es" \
|
||||
-F file=@"translations/es.json"
|
||||
```
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Context matters:** Use the reference field to understand where strings appear
|
||||
2. **Test before committing:** Always test translations in the actual UI
|
||||
3. **Keep synchronized:** Re-extract after significant UI changes
|
||||
4. **Preserve formatting:** Keep placeholders like `%1`, `{0}` intact
|
||||
5. **Cultural adaptation:** Some strings may need cultural context, not just literal translation
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
**Translations not loading?**
|
||||
- Check file exists: `~/.config/DankMaterialShell/translations/{language_code}.json`
|
||||
- Verify JSON syntax: `python3 -m json.tool translations/es.json`
|
||||
- Check console for errors: `qs -v -p .`
|
||||
|
||||
**Wrong language loading?**
|
||||
- Check system locale: `echo $LANG`
|
||||
- Verify file naming: Must match locale prefix (es_ES → es.json)
|
||||
|
||||
**Missing strings?**
|
||||
- Re-run extraction: `python3 extract_translations.py`
|
||||
- Compare with en.json to find new strings
|
||||
2132
translations/en.json
Normal file
2132
translations/en.json
Normal file
File diff suppressed because it is too large
Load Diff
92
translations/extract_translations.py
Executable file
92
translations/extract_translations.py
Executable file
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
from pathlib import Path
|
||||
from collections import defaultdict
|
||||
|
||||
def extract_qstr_strings(root_dir):
|
||||
translations = defaultdict(list)
|
||||
qstr_pattern = re.compile(r'qsTr\(["\']([^"\']+)["\']\)')
|
||||
|
||||
for qml_file in Path(root_dir).rglob('*.qml'):
|
||||
relative_path = qml_file.relative_to(root_dir)
|
||||
|
||||
with open(qml_file, 'r', encoding='utf-8') as f:
|
||||
for line_num, line in enumerate(f, 1):
|
||||
matches = qstr_pattern.findall(line)
|
||||
for match in matches:
|
||||
translations[match].append({
|
||||
'file': str(relative_path),
|
||||
'line': line_num
|
||||
})
|
||||
|
||||
return translations
|
||||
|
||||
def create_poeditor_json(translations):
|
||||
poeditor_data = []
|
||||
|
||||
for term, occurrences in sorted(translations.items()):
|
||||
references = []
|
||||
contexts = []
|
||||
|
||||
for occ in occurrences:
|
||||
ref = f"{occ['file']}:{occ['line']}"
|
||||
references.append(ref)
|
||||
contexts.append(f"{occ['file']}:{occ['line']}")
|
||||
|
||||
entry = {
|
||||
"term": term,
|
||||
"context": contexts[0] if contexts else "",
|
||||
"reference": ", ".join(references),
|
||||
"comment": ""
|
||||
}
|
||||
poeditor_data.append(entry)
|
||||
|
||||
return poeditor_data
|
||||
|
||||
def create_template_json(translations):
|
||||
template_data = []
|
||||
|
||||
for term in sorted(translations.keys()):
|
||||
entry = {
|
||||
"term": term,
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
}
|
||||
template_data.append(entry)
|
||||
|
||||
return template_data
|
||||
|
||||
def main():
|
||||
script_dir = Path(__file__).parent
|
||||
root_dir = script_dir.parent
|
||||
translations_dir = script_dir
|
||||
|
||||
print("Extracting qsTr() strings from QML files...")
|
||||
translations = extract_qstr_strings(root_dir)
|
||||
|
||||
print(f"Found {len(translations)} unique strings")
|
||||
|
||||
poeditor_data = create_poeditor_json(translations)
|
||||
en_json_path = translations_dir / 'en.json'
|
||||
with open(en_json_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(poeditor_data, f, indent=2, ensure_ascii=False)
|
||||
print(f"Created source language file: {en_json_path}")
|
||||
|
||||
template_data = create_template_json(translations)
|
||||
template_json_path = translations_dir / 'template.json'
|
||||
with open(template_json_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(template_data, f, indent=2, ensure_ascii=False)
|
||||
print(f"Created template file: {template_json_path}")
|
||||
|
||||
print("\nSummary:")
|
||||
print(f" - Unique strings: {len(translations)}")
|
||||
print(f" - Total occurrences: {sum(len(occs) for occs in translations.values())}")
|
||||
print(f" - Source file: {en_json_path}")
|
||||
print(f" - Template file: {template_json_path}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
2487
translations/template.json
Normal file
2487
translations/template.json
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user