i18n: Refactor translation management tools and add ignore feature for dynamic resources

- Updated README.md to reflect changes in translation management tools and added ignore mark feature for dynamic resources.
- Created Chinese translation guide for the translation management tools.
- Created English translation guide for the translation management tools.
- Enhanced translation-cleaner.py to skip keys marked with /*keep*/ during cleanup.
- Improved translation-manager.py to create backups only when updating keys interactively.
- Updated zh_CN.json with new translations and added ignore marks for dynamic values.
This commit is contained in:
月月
2025-07-16 23:36:47 +08:00
parent 2ad60a40a8
commit 8a68cf207a
11 changed files with 145 additions and 98 deletions
+15 -18
View File
@@ -163,7 +163,6 @@ Translation.tr("Say \"Hello\"")
// With parameter placeholders
Translation.tr("Hello, %1!").arg(name)
Translation.tr("{0} files selected").arg(count)
```
## Example Output
@@ -235,20 +234,15 @@ Original key count: 470, after cleaning: 420
--source-dir /path/to/source
```
### Batch Processing
### Ignore Mark Feature
```bash
# Create a processing script
cat > update-all-translations.sh << 'EOF'
#!/bin/bash
for lang in zh_CN ja_JP ko_KR; do
echo "Processing $lang..."
./manage-translations.sh update -l $lang
done
EOF
For dynamic resources or special texts that should not be automatically cleaned, you can add `/*keep*/` at the end of the translation value. The tool will automatically ignore these keys and will not delete them during cleaning or syncing.
chmod +x update-all-translations.sh
./update-all-translations.sh
Example:
```json
{
"dynamic_key": "Some dynamic value /*keep*/"
}
```
## Notes
@@ -256,7 +250,8 @@ chmod +x update-all-translations.sh
1. **Backup is important**: The tool automatically creates backups before cleaning, but it is recommended to manually back up important files
2. **Text extraction limitations**:
- Only supports static strings, not dynamically constructed strings
- ~~Only supports static strings, not dynamically constructed strings~~
- Dynamic resources (such as variable concatenation or runtime-generated text) cannot be automatically extracted. You need to manually add them to the translation file and use the `/*keep*/` mark for ignore management.
- Must use the `Translation.tr()` format
3. **File encoding**: All files must use UTF-8 encoding
@@ -267,13 +262,16 @@ chmod +x update-all-translations.sh
### Common Issues
**Q: The number of extracted texts does not match expectations?**
**Q: Text does not appear after adding Translation.tr?**
A: You need to import the translation feature in your QML file using `import "root:/"`, otherwise the translation text will not be displayed correctly.
**Q: The number of extracted texts does not match expectations?**
A: Check whether all translatable texts use the `Translation.tr()` format and ensure there are no dynamically constructed strings.
**Q: Some translations are missing after syncing?**
**Q: Some translations are missing after syncing?**
A: Check whether the source language file contains all necessary keys, and consider using a different source language for syncing.
**Q: The cleaning operation deleted needed keys?**
**Q: The cleaning operation deleted needed keys?**
A: Restore from the automatically created backup file and check whether `Translation.tr()` is used correctly in the source code.
### Restore Backup
@@ -285,4 +283,3 @@ cp .config/quickshell/translations/zh_CN.json.backup .config/quickshell/translat
# Restore all files
cp .config/quickshell/translations.backup/* .config/quickshell/translations/
```
@@ -163,7 +163,6 @@ Translation.tr("Say \"Hello\"")
// 带参数占位符
Translation.tr("Hello, %1!").arg(name)
Translation.tr("{0} files selected").arg(count)
```
## 示例输出
@@ -235,29 +234,25 @@ $ ./manage-translations.sh clean
--source-dir /path/to/source
```
### 批量处理
```bash
# 创建处理脚本
cat > update-all-translations.sh << 'EOF'
#!/bin/bash
for lang in zh_CN ja_JP ko_KR; do
echo "Processing $lang..."
./manage-translations.sh update -l $lang
done
EOF
chmod +x update-all-translations.sh
./update-all-translations.sh
```
## 注意事项
1. **备份重要**:在执行清理操作前,工具会自动创建备份,但建议手动备份重要文件
2. **文本提取限制**
- 只支持静态字符串,不支持动态构建的字符串
- ~~只支持静态字符串,不支持动态构建的字符串~~
- 动态资源(如变量拼接、运行时生成的文本)无法自动提取,需要在翻译文件中手动添加,并使用 `/*keep*/` 标记进行忽略管理。
- 必须使用 `Translation.tr()` 格式
### 忽略标记功能
对于动态资源或特殊文本,如果不希望被自动清理,可在翻译值末尾添加 `/*keep*/`,工具会自动忽略这些键,不会在清理和同步时删除。
示例:
```json
{
"dynamic_key": "Some dynamic value /*keep*/"
}
```
3. **文件编码**:所有文件必须使用 UTF-8 编码
@@ -267,6 +262,10 @@ chmod +x update-all-translations.sh
### 常见问题
**Q: 添加了 Translation.tr 后文字不显示?**
A: 需要在 QML 文件中使用 `import "root:/"` 导入翻译功能,否则无法正常显示翻译文本。
**Q: 提取的文本数量与预期不符?**
A: 检查是否所有可翻译文本都使用了 `Translation.tr()` 格式,确保没有动态构建的字符串。
@@ -163,7 +163,6 @@ Translation.tr("Say \"Hello\"")
// With parameter placeholders
Translation.tr("Hello, %1!").arg(name)
Translation.tr("{0} files selected").arg(count)
```
## Example Output
@@ -235,20 +234,15 @@ Original key count: 470, after cleaning: 420
--source-dir /path/to/source
```
### Batch Processing
### Ignore Mark Feature
```bash
# Create a processing script
cat > update-all-translations.sh << 'EOF'
#!/bin/bash
for lang in zh_CN ja_JP ko_KR; do
echo "Processing $lang..."
./manage-translations.sh update -l $lang
done
EOF
For dynamic resources or special texts that should not be automatically cleaned, you can add `/*keep*/` at the end of the translation value. The tool will automatically ignore these keys and will not delete them during cleaning or syncing.
chmod +x update-all-translations.sh
./update-all-translations.sh
Example:
```json
{
"dynamic_key": "Some dynamic value /*keep*/"
}
```
## Notes
@@ -256,7 +250,8 @@ chmod +x update-all-translations.sh
1. **Backup is important**: The tool automatically creates backups before cleaning, but it is recommended to manually back up important files
2. **Text extraction limitations**:
- Only supports static strings, not dynamically constructed strings
- ~~Only supports static strings, not dynamically constructed strings~~
- Dynamic resources (such as variable concatenation or runtime-generated text) cannot be automatically extracted. You need to manually add them to the translation file and use the `/*keep*/` mark for ignore management.
- Must use the `Translation.tr()` format
3. **File encoding**: All files must use UTF-8 encoding
@@ -267,13 +262,16 @@ chmod +x update-all-translations.sh
### Common Issues
**Q: The number of extracted texts does not match expectations?**
**Q: Text does not appear after adding Translation.tr?**
A: You need to import the translation feature in your QML file using `import "root:/"`, otherwise the translation text will not be displayed correctly.
**Q: The number of extracted texts does not match expectations?**
A: Check whether all translatable texts use the `Translation.tr()` format and ensure there are no dynamically constructed strings.
**Q: Some translations are missing after syncing?**
**Q: Some translations are missing after syncing?**
A: Check whether the source language file contains all necessary keys, and consider using a different source language for syncing.
**Q: The cleaning operation deleted needed keys?**
**Q: The cleaning operation deleted needed keys?**
A: Restore from the automatically created backup file and check whether `Translation.tr()` is used correctly in the source code.
### Restore Backup
@@ -50,29 +50,34 @@ def clean_translation_files(translations_dir: str, source_dir: str, backup: bool
translations = manager.load_translation_file(lang)
original_count = len(translations)
if backup:
# Create backup
backup_file = Path(translations_dir) / f"{lang}.json.bak"
with open(backup_file, 'w', encoding='utf-8') as f:
json.dump(translations, f, ensure_ascii=False, indent=2)
print(f"Created backup: {backup_file}")
# Find unused keys
unused_keys = set(translations.keys()) - current_texts
# Find unused keys, skip those whose value ends with /*keep*/
unused_keys = set()
for k in translations.keys():
v = translations[k]
if k not in current_texts:
if isinstance(v, str) and v.strip().endswith('/*keep*/'):
continue
unused_keys.add(k)
if unused_keys:
print(f"Found {len(unused_keys)} unused keys:")
for i, key in enumerate(sorted(unused_keys)[:10], 1): # Only show first 10
print(f" {i}. \"{key[:50]}{'...' if len(key) > 50 else ''}\"")
if len(unused_keys) > 10:
print(f" ... and {len(unused_keys) - 10} more keys")
response = input(f"Delete these {len(unused_keys)} unused keys? (y/n): ")
if response.lower().strip() in ['y', 'yes']:
if backup:
# Create backup only when user confirms deletion
backup_file = Path(translations_dir) / f"{lang}.json.bak"
with open(backup_file, 'w', encoding='utf-8') as f:
json.dump(translations, f, ensure_ascii=False, indent=2)
print(f"Created backup: {backup_file}")
# Delete unused keys
for key in unused_keys:
del translations[key]
# Save cleaned file
manager.save_translation_file(lang, translations)
removed_count = len(unused_keys)
@@ -82,7 +87,7 @@ def clean_translation_files(translations_dir: str, source_dir: str, backup: bool
print("Skipped deletion")
else:
print("No unused keys found")
new_count = len(translations)
print(f"Original key count: {original_count}, after cleanup: {new_count}")
@@ -138,35 +138,52 @@ class TranslationManager:
return missing_keys, extra_keys
def interactive_update(self, lang_code: str, missing_keys: Set[str], extra_keys: Set[str]):
"""Interactively update translation file"""
"""Interactively update translation file, create backup only if updating"""
translations = self.load_translation_file(lang_code)
modified = False
backup_created = False
# Handle missing keys
if missing_keys:
print(f"\nFound {len(missing_keys)} missing translation keys:")
for i, key in enumerate(sorted(missing_keys), 1):
print(f"{i}. \"{key}\"")
if self.ask_yes_no(f"\nAdd these {len(missing_keys)} missing keys?"):
if not backup_created:
backup_file = self.translations_dir / f"{lang_code}.json.bak"
with open(backup_file, 'w', encoding='utf-8') as f:
json.dump(translations, f, ensure_ascii=False, indent=2)
print(f"Created backup: {backup_file}")
backup_created = True
for key in missing_keys:
translations[key] = key # Default value is the key itself
modified = True
print(f"Added {len(missing_keys)} keys")
# Handle extra keys
if extra_keys:
print(f"\nFound {len(extra_keys)} extra translation keys:")
for i, key in enumerate(sorted(extra_keys), 1):
print(f"{i}. \"{key}\" -> \"{translations.get(key, '')}\"")
if self.ask_yes_no(f"\nDelete these {len(extra_keys)} extra keys?"):
for key in extra_keys:
if key in translations:
del translations[key]
modified = True
print(f"Deleted {len(extra_keys)} keys")
# Only show extra keys that are not marked with /*keep*/
filtered_extra_keys = [key for key in extra_keys if not (isinstance(translations.get(key, ""), str) and translations.get(key, "").strip().endswith('/*keep*/'))]
if filtered_extra_keys:
print(f"\nFound {len(filtered_extra_keys)} extra translation keys:")
for i, key in enumerate(sorted(filtered_extra_keys), 1):
print(f"{i}. \"{key}\" -> \"{translations.get(key, '')}\"")
if self.ask_yes_no(f"\nDelete these {len(filtered_extra_keys)} extra keys?"):
if not backup_created:
backup_file = self.translations_dir / f"{lang_code}.json.bak"
with open(backup_file, 'w', encoding='utf-8') as f:
json.dump(translations, f, ensure_ascii=False, indent=2)
print(f"Created backup: {backup_file}")
backup_created = True
deleted_count = 0
for key in filtered_extra_keys:
if key in translations:
del translations[key]
modified = True
deleted_count += 1
print(f"Deleted {deleted_count} keys")
# Save changes
if modified:
self.save_translation_file(lang_code, translations)
@@ -288,7 +305,13 @@ def main():
print(f"Analysis results:")
print(f" Missing keys: {len(missing_keys)}")
print(f" Extra keys: {len(extra_keys)}")
# Load translation file for current lang to get values
current_translations = manager.load_translation_file(lang)
filtered_extra_keys = [key for key in extra_keys if not (isinstance(current_translations.get(key, ""), str) and current_translations.get(key, "").strip().endswith('/*keep*/'))]
ignored_extra_keys = [key for key in extra_keys if (isinstance(current_translations.get(key, ""), str) and current_translations.get(key, "").strip().endswith('/*keep*/'))]
print(f" Extra keys: {len(filtered_extra_keys)}")
if ignored_extra_keys:
print(f" Ignored keys: {len(ignored_extra_keys)} (marked with /*keep*/)")
if missing_keys or extra_keys:
manager.interactive_update(lang, missing_keys, extra_keys)