forked from Shinonome/dots-hyprland
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:
@@ -145,12 +145,17 @@ Singleton {
|
|||||||
if (root.translations.hasOwnProperty(key)) {
|
if (root.translations.hasOwnProperty(key)) {
|
||||||
var translation = root.translations[key]
|
var translation = root.translations[key]
|
||||||
if (translation && translation.toString().trim().length > 0) {
|
if (translation && translation.toString().trim().length > 0) {
|
||||||
return translation.toString()
|
var str = translation.toString().trim()
|
||||||
|
if (str.endsWith("/*keep*/")) {
|
||||||
|
return str.substring(0, str.length - 8).trim()
|
||||||
|
} else {
|
||||||
|
return str
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return translation.toString()
|
return translation.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return key // Fallback to key name
|
return key // Fallback to key name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -419,7 +419,7 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
|
|||||||
return {
|
return {
|
||||||
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "prompt ") : ""}${file.target}`,
|
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "prompt ") : ""}${file.target}`,
|
||||||
displayName: `${FileUtils.trimFileExt(FileUtils.fileNameForPath(file.target))}`,
|
displayName: `${FileUtils.trimFileExt(FileUtils.fileNameForPath(file.target))}`,
|
||||||
description: `Load prompt from ${file.target}`,
|
description: Translation.tr("Load prompt from %1").arg(file.target),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else if (messageInputField.text.startsWith(`${root.commandPrefix}save`)) {
|
} else if (messageInputField.text.startsWith(`${root.commandPrefix}save`)) {
|
||||||
@@ -438,7 +438,7 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
|
|||||||
return {
|
return {
|
||||||
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "save ") : ""}${chatName}`,
|
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "save ") : ""}${chatName}`,
|
||||||
displayName: `${chatName}`,
|
displayName: `${chatName}`,
|
||||||
description: `Save chat from ${chatName}`,
|
description: Translation.tr("Save chat from %1").arg(chatName),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else if (messageInputField.text.startsWith(`${root.commandPrefix}load`)) {
|
} else if (messageInputField.text.startsWith(`${root.commandPrefix}load`)) {
|
||||||
@@ -457,7 +457,7 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
|
|||||||
return {
|
return {
|
||||||
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "load ") : ""}${chatName}`,
|
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "load ") : ""}${chatName}`,
|
||||||
displayName: `${chatName}`,
|
displayName: `${chatName}`,
|
||||||
description: `Load chat from ${file.target}`,
|
description: Translation.tr(`Load chat from %1`).arg(file.target),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else if(messageInputField.text.startsWith(root.commandPrefix)) {
|
} else if(messageInputField.text.startsWith(root.commandPrefix)) {
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ Item {
|
|||||||
Repeater {
|
Repeater {
|
||||||
model: CalendarLayout.weekDays
|
model: CalendarLayout.weekDays
|
||||||
delegate: CalendarDayButton {
|
delegate: CalendarDayButton {
|
||||||
day: modelData.day
|
day: Translation.tr(modelData.day)
|
||||||
isToday: modelData.today
|
isToday: modelData.today
|
||||||
bold: true
|
bold: true
|
||||||
enabled: false
|
enabled: false
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.leftMargin: 10
|
anchors.leftMargin: 10
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
text: `${Notifications.list.length} ${Translation.tr("notifications")}`
|
text: Translation.tr("%1 notifications").arg(Notifications.list.length)
|
||||||
|
|
||||||
opacity: Notifications.list.length > 0 ? 1 : 0
|
opacity: Notifications.list.length > 0 ? 1 : 0
|
||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
{
|
{
|
||||||
|
"Mo": "Mo/*keep*/",
|
||||||
|
"Tu": "Tu/*keep*/",
|
||||||
|
"We": "We/*keep*/",
|
||||||
|
"Th": "Th/*keep*/",
|
||||||
|
"Fr": "Fr/*keep*/",
|
||||||
|
"Sa": "Sa/*keep*/",
|
||||||
|
"Su": "Su/*keep*/",
|
||||||
"%1 characters": "%1 characters",
|
"%1 characters": "%1 characters",
|
||||||
"**Pricing**: free. Data use policy varies depending on your OpenRouter account settings.\n\n**Instructions**: Log into OpenRouter account, go to Keys on the topright menu, click Create API Key": "**Pricing**: free. Data use policy varies depending on your OpenRouter account settings.\n\n**Instructions**: Log into OpenRouter account, go to Keys on the topright menu, click Create API Key",
|
"**Pricing**: free. Data use policy varies depending on your OpenRouter account settings.\n\n**Instructions**: Log into OpenRouter account, go to Keys on the topright menu, click Create API Key": "**Pricing**: free. Data use policy varies depending on your OpenRouter account settings.\n\n**Instructions**: Log into OpenRouter account, go to Keys on the topright menu, click Create API Key",
|
||||||
"**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key": "**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key",
|
"**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key": "**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key",
|
||||||
@@ -152,7 +159,6 @@
|
|||||||
"Set the system prompt for the model.": "Set the system prompt for the model.",
|
"Set the system prompt for the model.": "Set the system prompt for the model.",
|
||||||
"To Do": "To Do",
|
"To Do": "To Do",
|
||||||
"Calendar": "Calendar",
|
"Calendar": "Calendar",
|
||||||
"notifications": "notifications",
|
|
||||||
"Advanced": "Advanced",
|
"Advanced": "Advanced",
|
||||||
"About": "About",
|
"About": "About",
|
||||||
"Services": "Services",
|
"Services": "Services",
|
||||||
@@ -306,5 +312,9 @@
|
|||||||
"Page %1": "Page %1",
|
"Page %1": "Page %1",
|
||||||
"Local Ollama model | %1": "Local Ollama model | %1",
|
"Local Ollama model | %1": "Local Ollama model | %1",
|
||||||
"The current system prompt is\n\n---\n\n%1": "The current system prompt is\n\n---\n\n%1",
|
"The current system prompt is\n\n---\n\n%1": "The current system prompt is\n\n---\n\n%1",
|
||||||
"Unknown function call: %1": "Unknown function call: %1"
|
"Unknown function call: %1": "Unknown function call: %1",
|
||||||
|
"%1 notifications": "%1 notifications",
|
||||||
|
"Save chat from %1": "Save chat from %1",
|
||||||
|
"Load chat from %1": "Load chat from %1",
|
||||||
|
"Load prompt from %1": "Load prompt from %1"
|
||||||
}
|
}
|
||||||
@@ -163,7 +163,6 @@ Translation.tr("Say \"Hello\"")
|
|||||||
|
|
||||||
// With parameter placeholders
|
// With parameter placeholders
|
||||||
Translation.tr("Hello, %1!").arg(name)
|
Translation.tr("Hello, %1!").arg(name)
|
||||||
Translation.tr("{0} files selected").arg(count)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example Output
|
## Example Output
|
||||||
@@ -235,20 +234,15 @@ Original key count: 470, after cleaning: 420
|
|||||||
--source-dir /path/to/source
|
--source-dir /path/to/source
|
||||||
```
|
```
|
||||||
|
|
||||||
### Batch Processing
|
### Ignore Mark Feature
|
||||||
|
|
||||||
```bash
|
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.
|
||||||
# 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
|
|
||||||
|
|
||||||
chmod +x update-all-translations.sh
|
Example:
|
||||||
./update-all-translations.sh
|
```json
|
||||||
|
{
|
||||||
|
"dynamic_key": "Some dynamic value /*keep*/"
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Notes
|
## 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
|
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**:
|
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
|
- Must use the `Translation.tr()` format
|
||||||
|
|
||||||
3. **File encoding**: All files must use UTF-8 encoding
|
3. **File encoding**: All files must use UTF-8 encoding
|
||||||
@@ -267,13 +262,16 @@ chmod +x update-all-translations.sh
|
|||||||
|
|
||||||
### Common Issues
|
### 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.
|
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.
|
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.
|
A: Restore from the automatically created backup file and check whether `Translation.tr()` is used correctly in the source code.
|
||||||
|
|
||||||
### Restore Backup
|
### Restore Backup
|
||||||
@@ -285,4 +283,3 @@ cp .config/quickshell/translations/zh_CN.json.backup .config/quickshell/translat
|
|||||||
# Restore all files
|
# Restore all files
|
||||||
cp .config/quickshell/translations.backup/* .config/quickshell/translations/
|
cp .config/quickshell/translations.backup/* .config/quickshell/translations/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
+16
-17
@@ -163,7 +163,6 @@ Translation.tr("Say \"Hello\"")
|
|||||||
|
|
||||||
// 带参数占位符
|
// 带参数占位符
|
||||||
Translation.tr("Hello, %1!").arg(name)
|
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
|
--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. **备份重要**:在执行清理操作前,工具会自动创建备份,但建议手动备份重要文件
|
1. **备份重要**:在执行清理操作前,工具会自动创建备份,但建议手动备份重要文件
|
||||||
|
|
||||||
2. **文本提取限制**:
|
2. **文本提取限制**:
|
||||||
- 只支持静态字符串,不支持动态构建的字符串
|
- ~~只支持静态字符串,不支持动态构建的字符串~~
|
||||||
|
- 动态资源(如变量拼接、运行时生成的文本)无法自动提取,需要在翻译文件中手动添加,并使用 `/*keep*/` 标记进行忽略管理。
|
||||||
- 必须使用 `Translation.tr()` 格式
|
- 必须使用 `Translation.tr()` 格式
|
||||||
|
### 忽略标记功能
|
||||||
|
|
||||||
|
对于动态资源或特殊文本,如果不希望被自动清理,可在翻译值末尾添加 `/*keep*/`,工具会自动忽略这些键,不会在清理和同步时删除。
|
||||||
|
|
||||||
|
示例:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"dynamic_key": "Some dynamic value /*keep*/"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
3. **文件编码**:所有文件必须使用 UTF-8 编码
|
3. **文件编码**:所有文件必须使用 UTF-8 编码
|
||||||
|
|
||||||
@@ -267,6 +262,10 @@ chmod +x update-all-translations.sh
|
|||||||
|
|
||||||
### 常见问题
|
### 常见问题
|
||||||
|
|
||||||
|
|
||||||
|
**Q: 添加了 Translation.tr 后文字不显示?**
|
||||||
|
A: 需要在 QML 文件中使用 `import "root:/"` 导入翻译功能,否则无法正常显示翻译文本。
|
||||||
|
|
||||||
**Q: 提取的文本数量与预期不符?**
|
**Q: 提取的文本数量与预期不符?**
|
||||||
A: 检查是否所有可翻译文本都使用了 `Translation.tr()` 格式,确保没有动态构建的字符串。
|
A: 检查是否所有可翻译文本都使用了 `Translation.tr()` 格式,确保没有动态构建的字符串。
|
||||||
|
|
||||||
+15
-17
@@ -163,7 +163,6 @@ Translation.tr("Say \"Hello\"")
|
|||||||
|
|
||||||
// With parameter placeholders
|
// With parameter placeholders
|
||||||
Translation.tr("Hello, %1!").arg(name)
|
Translation.tr("Hello, %1!").arg(name)
|
||||||
Translation.tr("{0} files selected").arg(count)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example Output
|
## Example Output
|
||||||
@@ -235,20 +234,15 @@ Original key count: 470, after cleaning: 420
|
|||||||
--source-dir /path/to/source
|
--source-dir /path/to/source
|
||||||
```
|
```
|
||||||
|
|
||||||
### Batch Processing
|
### Ignore Mark Feature
|
||||||
|
|
||||||
```bash
|
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.
|
||||||
# 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
|
|
||||||
|
|
||||||
chmod +x update-all-translations.sh
|
Example:
|
||||||
./update-all-translations.sh
|
```json
|
||||||
|
{
|
||||||
|
"dynamic_key": "Some dynamic value /*keep*/"
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Notes
|
## 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
|
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**:
|
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
|
- Must use the `Translation.tr()` format
|
||||||
|
|
||||||
3. **File encoding**: All files must use UTF-8 encoding
|
3. **File encoding**: All files must use UTF-8 encoding
|
||||||
@@ -267,13 +262,16 @@ chmod +x update-all-translations.sh
|
|||||||
|
|
||||||
### Common Issues
|
### 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.
|
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.
|
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.
|
A: Restore from the automatically created backup file and check whether `Translation.tr()` is used correctly in the source code.
|
||||||
|
|
||||||
### Restore Backup
|
### Restore Backup
|
||||||
@@ -50,29 +50,34 @@ def clean_translation_files(translations_dir: str, source_dir: str, backup: bool
|
|||||||
translations = manager.load_translation_file(lang)
|
translations = manager.load_translation_file(lang)
|
||||||
original_count = len(translations)
|
original_count = len(translations)
|
||||||
|
|
||||||
if backup:
|
# Find unused keys, skip those whose value ends with /*keep*/
|
||||||
# Create backup
|
unused_keys = set()
|
||||||
backup_file = Path(translations_dir) / f"{lang}.json.bak"
|
for k in translations.keys():
|
||||||
with open(backup_file, 'w', encoding='utf-8') as f:
|
v = translations[k]
|
||||||
json.dump(translations, f, ensure_ascii=False, indent=2)
|
if k not in current_texts:
|
||||||
print(f"Created backup: {backup_file}")
|
if isinstance(v, str) and v.strip().endswith('/*keep*/'):
|
||||||
|
continue
|
||||||
# Find unused keys
|
unused_keys.add(k)
|
||||||
unused_keys = set(translations.keys()) - current_texts
|
|
||||||
|
|
||||||
if unused_keys:
|
if unused_keys:
|
||||||
print(f"Found {len(unused_keys)} unused keys:")
|
print(f"Found {len(unused_keys)} unused keys:")
|
||||||
for i, key in enumerate(sorted(unused_keys)[:10], 1): # Only show first 10
|
for i, key in enumerate(sorted(unused_keys)[:10], 1): # Only show first 10
|
||||||
print(f" {i}. \"{key[:50]}{'...' if len(key) > 50 else ''}\"")
|
print(f" {i}. \"{key[:50]}{'...' if len(key) > 50 else ''}\"")
|
||||||
if len(unused_keys) > 10:
|
if len(unused_keys) > 10:
|
||||||
print(f" ... and {len(unused_keys) - 10} more keys")
|
print(f" ... and {len(unused_keys) - 10} more keys")
|
||||||
|
|
||||||
response = input(f"Delete these {len(unused_keys)} unused keys? (y/n): ")
|
response = input(f"Delete these {len(unused_keys)} unused keys? (y/n): ")
|
||||||
if response.lower().strip() in ['y', 'yes']:
|
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
|
# Delete unused keys
|
||||||
for key in unused_keys:
|
for key in unused_keys:
|
||||||
del translations[key]
|
del translations[key]
|
||||||
|
|
||||||
# Save cleaned file
|
# Save cleaned file
|
||||||
manager.save_translation_file(lang, translations)
|
manager.save_translation_file(lang, translations)
|
||||||
removed_count = len(unused_keys)
|
removed_count = len(unused_keys)
|
||||||
@@ -82,7 +87,7 @@ def clean_translation_files(translations_dir: str, source_dir: str, backup: bool
|
|||||||
print("Skipped deletion")
|
print("Skipped deletion")
|
||||||
else:
|
else:
|
||||||
print("No unused keys found")
|
print("No unused keys found")
|
||||||
|
|
||||||
new_count = len(translations)
|
new_count = len(translations)
|
||||||
print(f"Original key count: {original_count}, after cleanup: {new_count}")
|
print(f"Original key count: {original_count}, after cleanup: {new_count}")
|
||||||
|
|
||||||
|
|||||||
@@ -138,35 +138,52 @@ class TranslationManager:
|
|||||||
return missing_keys, extra_keys
|
return missing_keys, extra_keys
|
||||||
|
|
||||||
def interactive_update(self, lang_code: str, missing_keys: Set[str], extra_keys: Set[str]):
|
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)
|
translations = self.load_translation_file(lang_code)
|
||||||
modified = False
|
modified = False
|
||||||
|
backup_created = False
|
||||||
|
|
||||||
# Handle missing keys
|
# Handle missing keys
|
||||||
if missing_keys:
|
if missing_keys:
|
||||||
print(f"\nFound {len(missing_keys)} missing translation keys:")
|
print(f"\nFound {len(missing_keys)} missing translation keys:")
|
||||||
for i, key in enumerate(sorted(missing_keys), 1):
|
for i, key in enumerate(sorted(missing_keys), 1):
|
||||||
print(f"{i}. \"{key}\"")
|
print(f"{i}. \"{key}\"")
|
||||||
|
|
||||||
if self.ask_yes_no(f"\nAdd these {len(missing_keys)} missing keys?"):
|
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:
|
for key in missing_keys:
|
||||||
translations[key] = key # Default value is the key itself
|
translations[key] = key # Default value is the key itself
|
||||||
modified = True
|
modified = True
|
||||||
print(f"Added {len(missing_keys)} keys")
|
print(f"Added {len(missing_keys)} keys")
|
||||||
|
|
||||||
# Handle extra keys
|
# Handle extra keys
|
||||||
if extra_keys:
|
if extra_keys:
|
||||||
print(f"\nFound {len(extra_keys)} extra translation keys:")
|
# Only show extra keys that are not marked with /*keep*/
|
||||||
for i, key in enumerate(sorted(extra_keys), 1):
|
filtered_extra_keys = [key for key in extra_keys if not (isinstance(translations.get(key, ""), str) and translations.get(key, "").strip().endswith('/*keep*/'))]
|
||||||
print(f"{i}. \"{key}\" -> \"{translations.get(key, '')}\"")
|
if filtered_extra_keys:
|
||||||
|
print(f"\nFound {len(filtered_extra_keys)} extra translation keys:")
|
||||||
if self.ask_yes_no(f"\nDelete these {len(extra_keys)} extra keys?"):
|
for i, key in enumerate(sorted(filtered_extra_keys), 1):
|
||||||
for key in extra_keys:
|
print(f"{i}. \"{key}\" -> \"{translations.get(key, '')}\"")
|
||||||
if key in translations:
|
if self.ask_yes_no(f"\nDelete these {len(filtered_extra_keys)} extra keys?"):
|
||||||
del translations[key]
|
if not backup_created:
|
||||||
modified = True
|
backup_file = self.translations_dir / f"{lang_code}.json.bak"
|
||||||
print(f"Deleted {len(extra_keys)} keys")
|
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
|
# Save changes
|
||||||
if modified:
|
if modified:
|
||||||
self.save_translation_file(lang_code, translations)
|
self.save_translation_file(lang_code, translations)
|
||||||
@@ -288,7 +305,13 @@ def main():
|
|||||||
|
|
||||||
print(f"Analysis results:")
|
print(f"Analysis results:")
|
||||||
print(f" Missing keys: {len(missing_keys)}")
|
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:
|
if missing_keys or extra_keys:
|
||||||
manager.interactive_update(lang, missing_keys, extra_keys)
|
manager.interactive_update(lang, missing_keys, extra_keys)
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
{
|
{
|
||||||
|
"Mo": "一/*keep*/",
|
||||||
|
"Tu": "二/*keep*/",
|
||||||
|
"We": "三/*keep*/",
|
||||||
|
"Th": "四/*keep*/",
|
||||||
|
"Fr": "五/*keep*/",
|
||||||
|
"Sa": "六/*keep*/",
|
||||||
|
"Su": "日/*keep*/",
|
||||||
"%1 characters": "%1 个字符",
|
"%1 characters": "%1 个字符",
|
||||||
"**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key": "**价格**:免费。数据用于训练。\n\n**说明**:登录 Google 账户,允许 AI Studio 创建 Google Cloud 项目或其他要求,然后返回并点击获取 API 密钥",
|
"**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key": "**价格**:免费。数据用于训练。\n\n**说明**:登录 Google 账户,允许 AI Studio 创建 Google Cloud 项目或其他要求,然后返回并点击获取 API 密钥",
|
||||||
"**Pricing**: free. Data use policy varies depending on your OpenRouter account settings.\n\n**Instructions**: Log into OpenRouter account, go to Keys on the topright menu, click Create API Key": "**价格**:免费。数据使用政策取决于您的 OpenRouter 账户设置。\n\n**说明**:登录 OpenRouter 账户,在右上角菜单中选择 Keys,点击创建 API 密钥",
|
"**Pricing**: free. Data use policy varies depending on your OpenRouter account settings.\n\n**Instructions**: Log into OpenRouter account, go to Keys on the topright menu, click Create API Key": "**价格**:免费。数据使用政策取决于您的 OpenRouter 账户设置。\n\n**说明**:登录 OpenRouter 账户,在右上角菜单中选择 Keys,点击创建 API 密钥",
|
||||||
@@ -96,7 +103,7 @@
|
|||||||
"Save": "保存",
|
"Save": "保存",
|
||||||
"Save to Downloads": "保存到下载文件夹",
|
"Save to Downloads": "保存到下载文件夹",
|
||||||
"Search": "搜索",
|
"Search": "搜索",
|
||||||
"Search the web": "搜索网络",
|
"Search the web": "在网络上搜索",
|
||||||
"Search, calculate or run": "搜索、计算或运行",
|
"Search, calculate or run": "搜索、计算或运行",
|
||||||
"Select Language": "选择语言",
|
"Select Language": "选择语言",
|
||||||
"Session": "会话",
|
"Session": "会话",
|
||||||
@@ -170,7 +177,6 @@
|
|||||||
"Set the system prompt for the model.": "为模型设置系统提示。",
|
"Set the system prompt for the model.": "为模型设置系统提示。",
|
||||||
"To Do": "待办",
|
"To Do": "待办",
|
||||||
"Calendar": "日历",
|
"Calendar": "日历",
|
||||||
"notifications": "条通知",
|
|
||||||
"Advanced": "高级",
|
"Advanced": "高级",
|
||||||
"About": "关于",
|
"About": "关于",
|
||||||
"Services": "服务",
|
"Services": "服务",
|
||||||
@@ -212,7 +218,7 @@
|
|||||||
"Policies": "策略",
|
"Policies": "策略",
|
||||||
"Weeb": "二次元",
|
"Weeb": "二次元",
|
||||||
"Closet": "隐藏",
|
"Closet": "隐藏",
|
||||||
"Bar style": "Bar 样式",
|
"Bar style": "条栏样式",
|
||||||
"Show next time": "下次显示",
|
"Show next time": "下次显示",
|
||||||
"Usage": "用法",
|
"Usage": "用法",
|
||||||
"Plain rectangle": "纯矩形",
|
"Plain rectangle": "纯矩形",
|
||||||
@@ -281,7 +287,7 @@
|
|||||||
"Screen snip": "屏幕截图",
|
"Screen snip": "屏幕截图",
|
||||||
"Mic toggle": "麦克风切换",
|
"Mic toggle": "麦克风切换",
|
||||||
"Hover to reveal": "悬停显示",
|
"Hover to reveal": "悬停显示",
|
||||||
"Bar": "Bar",
|
"Bar": "条栏",
|
||||||
"Show background": "显示背景",
|
"Show background": "显示背景",
|
||||||
"Show regions of potential interest": "显示可能感兴趣的区域",
|
"Show regions of potential interest": "显示可能感兴趣的区域",
|
||||||
"Color picker": "取色器",
|
"Color picker": "取色器",
|
||||||
@@ -303,8 +309,12 @@
|
|||||||
"Drag or click a region • LMB: Copy • RMB: Edit": "拖动或点击一个区域 • 鼠标左键:复制 • 鼠标右键:编辑",
|
"Drag or click a region • LMB: Copy • RMB: Edit": "拖动或点击一个区域 • 鼠标左键:复制 • 鼠标右键:编辑",
|
||||||
"Current model: %1\nSet it with %2model MODEL": "当前模型:%1\n使用 %2model MODEL 设置",
|
"Current model: %1\nSet it with %2model MODEL": "当前模型:%1\n使用 %2model MODEL 设置",
|
||||||
"Message the model... \"%1\" for commands": "与模型对话... \"%1\" 查看命令",
|
"Message the model... \"%1\" for commands": "与模型对话... \"%1\" 查看命令",
|
||||||
"The current system prompt is\n\n---\n\n%1": "The current system prompt is\n\n---\n\n%1",
|
"The current system prompt is\n\n---\n\n%1": "当前系统提示词为\n\n---\n\n%1",
|
||||||
"Model set to %1": "Model set to %1",
|
"Model set to %1": "模型已设置为 %1",
|
||||||
"Online models disallowed for %1\n\nControlled by `policies.ai` config option": "Online models disallowed for %1\n\nControlled by `policies.ai` config option",
|
"Online models disallowed for %1\n\nControlled by `policies.ai` config option": "%1 禁止使用在线模型\n\n由 `policies.ai` 配置项控制",
|
||||||
"Loaded the following system prompt\n\n---\n\n%1": "Loaded the following system prompt\n\n---\n\n%1"
|
"Loaded the following system prompt\n\n---\n\n%1": "已加载以下系统提示词\n\n---\n\n%1",
|
||||||
|
"%1 notifications": "%1 条通知",
|
||||||
|
"Save chat from %1": "保存聊天记录到 %1",
|
||||||
|
"Load chat from %1": "从 %1 加载聊天记录",
|
||||||
|
"Load prompt from %1": "从 %1 加载提示词"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user