mirror of
https://github.com/kyantech/Palmr.git
synced 2025-10-23 06:11:58 +00:00
- Added a new translation management system to automate synchronization, validation, and translation of internationalization files. - Introduced scripts for running translation operations, including checking status, synchronizing keys, and auto-translating strings. - Updated package.json with new translation-related commands for easier access. - Enhanced localization files across multiple languages with new keys and improved translations. - Integrated download functionality for share files in the UI, allowing users to download multiple files seamlessly. - Refactored components to support new download features and improved user experience.
231 lines
8.5 KiB
Python
Executable File
231 lines
8.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Script to check translation status and identify strings that need translation.
|
|
"""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Dict, Any, List, Tuple
|
|
import argparse
|
|
|
|
|
|
def load_json_file(file_path: Path) -> Dict[str, Any]:
|
|
"""Load a JSON file."""
|
|
try:
|
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
return json.load(f)
|
|
except Exception as e:
|
|
print(f"Error loading {file_path}: {e}")
|
|
return {}
|
|
|
|
|
|
def get_all_string_values(data: Dict[str, Any], prefix: str = '') -> List[Tuple[str, str]]:
|
|
"""Extract all strings from nested JSON with their keys."""
|
|
strings = []
|
|
|
|
for key, value in data.items():
|
|
current_key = f"{prefix}.{key}" if prefix else key
|
|
|
|
if isinstance(value, str):
|
|
strings.append((current_key, value))
|
|
elif isinstance(value, dict):
|
|
strings.extend(get_all_string_values(value, current_key))
|
|
|
|
return strings
|
|
|
|
|
|
def check_untranslated_strings(file_path: Path) -> Tuple[int, int, List[str]]:
|
|
"""Check for untranslated strings in a file."""
|
|
data = load_json_file(file_path)
|
|
if not data:
|
|
return 0, 0, []
|
|
|
|
all_strings = get_all_string_values(data)
|
|
untranslated = []
|
|
|
|
for key, value in all_strings:
|
|
if value.startswith('[TO_TRANSLATE]'):
|
|
untranslated.append(key)
|
|
|
|
return len(all_strings), len(untranslated), untranslated
|
|
|
|
|
|
def compare_languages(reference_file: Path, target_file: Path) -> Dict[str, Any]:
|
|
"""Compare two language files."""
|
|
reference_data = load_json_file(reference_file)
|
|
target_data = load_json_file(target_file)
|
|
|
|
if not reference_data or not target_data:
|
|
return {}
|
|
|
|
reference_strings = dict(get_all_string_values(reference_data))
|
|
target_strings = dict(get_all_string_values(target_data))
|
|
|
|
# Find common keys
|
|
common_keys = set(reference_strings.keys()) & set(target_strings.keys())
|
|
|
|
# Check identical strings (possibly untranslated)
|
|
identical_strings = []
|
|
for key in common_keys:
|
|
if reference_strings[key] == target_strings[key] and len(reference_strings[key]) > 3:
|
|
identical_strings.append(key)
|
|
|
|
return {
|
|
'total_reference': len(reference_strings),
|
|
'total_target': len(target_strings),
|
|
'common_keys': len(common_keys),
|
|
'identical_strings': identical_strings
|
|
}
|
|
|
|
|
|
def generate_translation_report(messages_dir: Path, reference_file: str = 'en-US.json'):
|
|
"""Generate complete translation report."""
|
|
reference_path = messages_dir / reference_file
|
|
if not reference_path.exists():
|
|
print(f"Reference file not found: {reference_path}")
|
|
return
|
|
|
|
# Load reference data
|
|
reference_data = load_json_file(reference_path)
|
|
reference_strings = dict(get_all_string_values(reference_data))
|
|
total_reference_strings = len(reference_strings)
|
|
|
|
print(f"📊 TRANSLATION REPORT")
|
|
print(f"Reference: {reference_file} ({total_reference_strings} strings)")
|
|
print("=" * 80)
|
|
|
|
# Find all JSON files
|
|
json_files = [f for f in messages_dir.glob('*.json') if f.name != reference_file]
|
|
|
|
if not json_files:
|
|
print("No translation files found")
|
|
return
|
|
|
|
reports = []
|
|
|
|
for json_file in sorted(json_files):
|
|
total_strings, untranslated_count, untranslated_keys = check_untranslated_strings(json_file)
|
|
comparison = compare_languages(reference_path, json_file)
|
|
|
|
# Calculate percentages
|
|
completion_percentage = (total_strings / total_reference_strings) * 100 if total_reference_strings > 0 else 0
|
|
untranslated_percentage = (untranslated_count / total_strings) * 100 if total_strings > 0 else 0
|
|
|
|
reports.append({
|
|
'file': json_file.name,
|
|
'total_strings': total_strings,
|
|
'untranslated_count': untranslated_count,
|
|
'untranslated_keys': untranslated_keys,
|
|
'completion_percentage': completion_percentage,
|
|
'untranslated_percentage': untranslated_percentage,
|
|
'identical_strings': comparison.get('identical_strings', [])
|
|
})
|
|
|
|
# Sort by completion percentage
|
|
reports.sort(key=lambda x: x['completion_percentage'], reverse=True)
|
|
|
|
print(f"{'LANGUAGE':<15} {'COMPLETENESS':<12} {'STRINGS':<15} {'UNTRANSLATED':<15} {'POSSIBLE MATCHES'}")
|
|
print("-" * 80)
|
|
|
|
for report in reports:
|
|
language = report['file'].replace('.json', '')
|
|
completion = f"{report['completion_percentage']:.1f}%"
|
|
strings_info = f"{report['total_strings']}/{total_reference_strings}"
|
|
untranslated_info = f"{report['untranslated_count']} ({report['untranslated_percentage']:.1f}%)"
|
|
identical_count = len(report['identical_strings'])
|
|
|
|
# Choose icon based on completeness
|
|
if report['completion_percentage'] >= 100:
|
|
icon = "✅" if report['untranslated_count'] == 0 else "⚠️"
|
|
elif report['completion_percentage'] >= 90:
|
|
icon = "🟡"
|
|
else:
|
|
icon = "🔴"
|
|
|
|
print(f"{icon} {language:<13} {completion:<12} {strings_info:<15} {untranslated_info:<15} {identical_count}")
|
|
|
|
print("\n" + "=" * 80)
|
|
|
|
# Show details of problematic files
|
|
problematic_files = [r for r in reports if r['untranslated_count'] > 0 or r['completion_percentage'] < 100]
|
|
|
|
if problematic_files:
|
|
print("📋 DETAILS OF FILES THAT NEED ATTENTION:")
|
|
print()
|
|
|
|
for report in problematic_files:
|
|
language = report['file'].replace('.json', '')
|
|
print(f"🔍 {language.upper()}:")
|
|
|
|
if report['completion_percentage'] < 100:
|
|
missing_count = total_reference_strings - report['total_strings']
|
|
print(f" • Missing {missing_count} strings ({100 - report['completion_percentage']:.1f}%)")
|
|
|
|
if report['untranslated_count'] > 0:
|
|
print(f" • {report['untranslated_count']} strings marked as [TO_TRANSLATE]")
|
|
|
|
if report['untranslated_count'] <= 10:
|
|
print(" • Untranslated keys:")
|
|
for key in report['untranslated_keys']:
|
|
print(f" - {key}")
|
|
else:
|
|
print(" • First 10 untranslated keys:")
|
|
for key in report['untranslated_keys'][:10]:
|
|
print(f" - {key}")
|
|
print(f" ... and {report['untranslated_count'] - 10} more")
|
|
|
|
if report['identical_strings']:
|
|
identical_count = len(report['identical_strings'])
|
|
print(f" • {identical_count} strings identical to English (possibly untranslated)")
|
|
|
|
if identical_count <= 5:
|
|
for key in report['identical_strings']:
|
|
value = reference_strings.get(key, '')[:50]
|
|
print(f" - {key}: \"{value}...\"")
|
|
else:
|
|
for key in report['identical_strings'][:5]:
|
|
value = reference_strings.get(key, '')[:50]
|
|
print(f" - {key}: \"{value}...\"")
|
|
print(f" ... and {identical_count - 5} more")
|
|
|
|
print()
|
|
|
|
else:
|
|
print("🎉 All translations are complete!")
|
|
|
|
print("=" * 80)
|
|
print("💡 TIPS:")
|
|
print("• Use 'python3 sync_translations.py --dry-run' to see what would be added")
|
|
print("• Use 'python3 sync_translations.py' to synchronize all translations")
|
|
print("• Strings marked with [TO_TRANSLATE] need manual translation")
|
|
print("• Strings identical to English may need translation")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description='Check translation status and identify strings that need translation'
|
|
)
|
|
parser.add_argument(
|
|
'--messages-dir',
|
|
type=Path,
|
|
default=Path(__file__).parent.parent / 'messages',
|
|
help='Directory containing message files (default: ../messages)'
|
|
)
|
|
parser.add_argument(
|
|
'--reference',
|
|
default='en-US.json',
|
|
help='Reference file (default: en-US.json)'
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
if not args.messages_dir.exists():
|
|
print(f"Directory not found: {args.messages_dir}")
|
|
return 1
|
|
|
|
generate_translation_report(args.messages_dir, args.reference)
|
|
return 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
exit(main()) |