""" Translate mineral property values (category, crystal_system, luster, streak, specific_gravity, color_description) into Russian using Google Translate via the deep-translator library. Results are stored in the properties_ru JSON field. Usage: python manage.py translate_minerals # translate all python manage.py translate_minerals --skip-existing # skip already done python manage.py translate_minerals --limit 50 # translate first 50 """ import time from django.core.management.base import BaseCommand from dailystone.models import Mineral # Hard-coded dictionary for standard mineralogical terms that translate # inconsistently with machine translation. CRYSTAL_SYSTEMS = { 'triclinic': 'Триклинная', 'monoclinic': 'Моноклинная', 'orthorhombic': 'Ромбическая', 'tetragonal': 'Тетрагональная', 'trigonal': 'Тригональная', 'hexagonal': 'Гексагональная', 'cubic': 'Кубическая', 'isometric': 'Кубическая', 'amorphous': 'Аморфная', 'rhombohedral': 'Ромбоэдрическая', } def _dict_translate(value, lookup): """Try a case-insensitive dictionary lookup, return None on miss.""" if not value: return None key = value.strip().lower() for k, v in lookup.items(): if k in key: return v return None class Command(BaseCommand): help = 'Translate mineral property values to Russian using Google Translate' def add_arguments(self, parser): parser.add_argument('--limit', type=int, default=0, help='Max minerals to process (0 = all)') parser.add_argument('--skip-existing', action='store_true', help='Skip minerals that already have properties_ru') def handle(self, *args, **options): try: from deep_translator import GoogleTranslator except ImportError: self.stderr.write('deep-translator not installed. Run: pip install deep-translator') return translator = GoogleTranslator(source='en', target='ru') qs = Mineral.objects.all() if options['skip_existing']: qs = qs.exclude(properties_ru__isnull=False).exclude(properties_ru={}) if options['limit']: qs = qs[:options['limit']] total = qs.count() self.stdout.write(f'Translating properties for {total} minerals...') done = 0 errors = 0 for mineral in qs: props = dict(mineral.properties_ru or {}) changed = False fields = { 'category': mineral.category, 'crystal_system': mineral.crystal_system, 'luster': mineral.luster, 'streak': mineral.streak, 'specific_gravity': mineral.specific_gravity, 'color_description': mineral.color_description_ru or mineral.color_description, } for key, value in fields.items(): if not value or key in props: continue # Try dictionary first for crystal system if key == 'crystal_system': result = _dict_translate(value, CRYSTAL_SYSTEMS) if result: props[key] = result changed = True continue # Machine translate try: translated = translator.translate(value) if translated and translated != value: props[key] = translated changed = True time.sleep(0.3) except Exception as e: self.stderr.write(f' [{mineral.name}] {key}: {e}') errors += 1 time.sleep(1) if changed: mineral.properties_ru = props mineral.save(update_fields=['properties_ru']) done += 1 self.stdout.write(f' [{done}/{total}] {mineral.name}') self.stdout.write(self.style.SUCCESS( f'Done. Translated {done} minerals, {errors} errors.' ))