@@ -336,36 +336,38 @@ def scan_and_process_po_files(
336
336
logging .info ("Discovered .po file: %s" , po_file_path )
337
337
338
338
# Prepare the PO file, if it returns None then skip this file
339
- po_file = self ._prepare_po_file (po_file_path , languages )
340
- if po_file is None :
339
+ po_file_result = self ._prepare_po_file (po_file_path , languages )
340
+ if po_file_result is None :
341
341
logging .info ("Skipping file %s due to language mismatch or other issues" , po_file_path )
342
342
continue
343
343
344
- # Process the file
345
- self .process_po_file (po_file_path , languages , detail_languages )
344
+ # Process the file, passing the prepared po_file and file_lang
345
+ self .process_po_file (po_file_path , languages , detail_languages , po_file_result )
346
346
347
347
def process_po_file (
348
348
self ,
349
349
po_file_path : str ,
350
350
languages : List [str ],
351
- detail_languages : Optional [Dict [str , str ]] = None
351
+ detail_languages : Optional [Dict [str , str ]] = None ,
352
+ po_file_result = None ,
352
353
):
353
354
"""Processes a single .po file with translations."""
354
355
try :
355
- po_file = self ._prepare_po_file (po_file_path , languages )
356
- if not po_file :
357
- return
356
+ # Only prepare the po_file if not provided (for backward compatibility)
357
+ if po_file_result is None :
358
+ po_file_result = self ._prepare_po_file (po_file_path , languages )
359
+ if po_file_result is None :
360
+ return
358
361
359
- file_lang = self .po_file_handler .get_file_language (
360
- po_file_path ,
361
- po_file ,
362
- languages ,
363
- self .config .folder_language
364
- )
362
+ po_file , file_lang = po_file_result
365
363
366
364
# Get the detailed language name if available
367
365
detail_lang = detail_languages .get (file_lang ) if detail_languages else None
368
366
367
+ if self .config .fix_fuzzy :
368
+ self .fix_fuzzy_entries (po_file , po_file_path , file_lang , detail_lang )
369
+ return
370
+
369
371
texts_to_translate = [entry .msgid for entry in po_file if not entry .msgstr .strip () and entry .msgid ]
370
372
translations = self .get_translations (texts_to_translate , file_lang , po_file_path , detail_lang )
371
373
@@ -384,6 +386,9 @@ def process_po_file(
384
386
def _prepare_po_file (self , po_file_path : str , languages : List [str ]):
385
387
"""Prepares the .po file for translation."""
386
388
if self .config .fuzzy :
389
+ logging .warning (
390
+ "Consider running with '--fix-fuzzy' to clean and update the fuzzy translations properly." ,
391
+ )
387
392
self .po_file_handler .disable_fuzzy_translations (po_file_path )
388
393
po_file = polib .pofile (po_file_path )
389
394
file_lang = self .po_file_handler .get_file_language (
@@ -395,7 +400,7 @@ def _prepare_po_file(self, po_file_path: str, languages: List[str]):
395
400
if not file_lang :
396
401
logging .warning ("Skipping .po file due to language mismatch: %s" , po_file_path )
397
402
return None
398
- return po_file
403
+ return po_file , file_lang
399
404
400
405
def get_translations (
401
406
self ,
@@ -424,6 +429,22 @@ def _update_po_entries(
424
429
else :
425
430
self ._handle_empty_translation (entry , target_language , detail_language )
426
431
432
+ def _update_fuzzy_po_entries (
433
+ self ,
434
+ po_file ,
435
+ translations : List [str ],
436
+ entries_to_update : list
437
+ ):
438
+ """Update only fuzzy entries, remove 'fuzzy' flag, and log cleanly."""
439
+ for entry , translation in zip (entries_to_update , translations ):
440
+ if translation .strip ():
441
+ self .po_file_handler .update_po_entry (po_file , entry .msgid , translation )
442
+ if 'fuzzy' in entry .flags :
443
+ entry .flags .remove ('fuzzy' )
444
+ logging .info ("Fixed fuzzy entry '%s' -> '%s'" , entry .msgid , translation )
445
+ else :
446
+ logging .warning ("Translation for fuzzy '%s' is still empty, leaving fuzzy." , entry .msgid )
447
+
427
448
def _handle_empty_translation (self , entry , target_language : str , detail_language : Optional [str ] = None ):
428
449
"""Handles cases where the initial translation is empty."""
429
450
logging .warning ("Empty translation for '%s'. Attempting individual translation." , entry .msgid )
@@ -453,3 +474,34 @@ def _handle_untranslated_entries(self, po_file, target_language: str, detail_lan
453
474
)
454
475
else :
455
476
logging .error ("Failed to translate '%s' after final attempt." , entry .msgid )
477
+
478
+ def fix_fuzzy_entries (
479
+ self ,
480
+ po_file ,
481
+ po_file_path : str ,
482
+ target_language : str ,
483
+ detail_language : Optional [str ] = None ,
484
+ ):
485
+ """Find and fix fuzzy entries in a PO file using AI translation."""
486
+ fuzzy_entries = [entry for entry in po_file if 'fuzzy' in entry .flags ]
487
+
488
+ if not fuzzy_entries :
489
+ logging .info ("No fuzzy entries found in %s" , po_file_path )
490
+ return
491
+
492
+ logging .info ("Found %d fuzzy entries to fix in %s" , len (fuzzy_entries ), po_file_path )
493
+
494
+ texts_to_translate = [entry .msgid for entry in fuzzy_entries ]
495
+ translations = self .get_translations (texts_to_translate , target_language , po_file_path , detail_language )
496
+
497
+ self ._update_fuzzy_po_entries (po_file , translations , entries_to_update = fuzzy_entries )
498
+
499
+ po_file .save (po_file_path )
500
+
501
+ self .po_file_handler .log_translation_status (
502
+ po_file_path ,
503
+ texts_to_translate ,
504
+ [entry .msgstr for entry in fuzzy_entries ]
505
+ )
506
+
507
+ logging .info ("Fuzzy fix completed for %s" , po_file_path )
0 commit comments