diff --git a/python_gpt_po/services/translation_service.py b/python_gpt_po/services/translation_service.py index 49b8294..a416a32 100644 --- a/python_gpt_po/services/translation_service.py +++ b/python_gpt_po/services/translation_service.py @@ -89,6 +89,7 @@ class FileStats: total_in_file: int = 0 untranslated: int = 0 translated_in_file: int = 0 + fuzzy: int = 0 class TranslationService: @@ -427,7 +428,10 @@ def _show_results_summary(self, stats: TranslationStats): """Show final results summary after processing.""" logging.info("") logging.info("=" * 70) - logging.info("TRANSLATION RESULTS") + if self.config.flags.fix_fuzzy: + logging.info("FUZZY FIX RESULTS") + else: + logging.info("TRANSLATION RESULTS") logging.info("=" * 70) logging.info("PROCESSING SUMMARY:") @@ -436,8 +440,12 @@ def _show_results_summary(self, stats: TranslationStats): logging.info(" Total files handled: %d", stats.files.processed + stats.files.skipped) logging.info("") - logging.info("TRANSLATION RESULTS:") - logging.info(" Entries successfully translated: %d", stats.entries.translated) + if self.config.flags.fix_fuzzy: + logging.info("FUZZY FIX RESULTS:") + logging.info(" Fuzzy entries fixed: %d", stats.entries.translated) + else: + logging.info("TRANSLATION RESULTS:") + logging.info(" Entries successfully translated: %d", stats.entries.translated) if stats.entries.failed > 0: logging.info(" Entries failed/skipped: %d", stats.entries.failed) @@ -515,7 +523,10 @@ def _show_mode_info(self, total_entries: int): def _show_translation_summary(self, scan_results, languages): """Show summary of files to translate.""" logging.info("=" * 70) - logging.info("TRANSLATION OVERVIEW") + if self.config.flags.fix_fuzzy: + logging.info("FUZZY FIX OVERVIEW") + else: + logging.info("TRANSLATION OVERVIEW") logging.info("=" * 70) logging.info("SCAN RESULTS:") logging.info(" Total PO files found: %d", scan_results['files_scanned']) @@ -523,14 +534,23 @@ def _show_translation_summary(self, scan_results, languages): logging.info(" Files matching languages: %d", files_matched) logging.info(" Files with language mismatch: %d", scan_results['language_mismatch_files']) logging.info("") - logging.info("TRANSLATION STATUS:") - logging.info(" Files needing translation: %d", len(scan_results['files_to_process'])) - logging.info(" Files already fully translated: %d", len(scan_results['skipped_files'])) - logging.info("") - logging.info("ENTRY STATISTICS:") - logging.info(" Total entries in all files: %d", scan_results['total_entries_in_all_files']) - logging.info(" Already translated entries: %d", scan_results['total_translated_in_all_files']) - logging.info(" Entries to translate: %d", scan_results['total_entries']) + if self.config.flags.fix_fuzzy: + logging.info("FUZZY STATUS:") + logging.info(" Files with fuzzy entries: %d", len(scan_results['files_to_process'])) + logging.info(" Files without fuzzy entries: %d", len(scan_results['skipped_files'])) + logging.info("") + logging.info("ENTRY STATISTICS:") + logging.info(" Total entries in all files: %d", scan_results['total_entries_in_all_files']) + logging.info(" Fuzzy entries to fix: %d", scan_results['total_entries']) + else: + logging.info("TRANSLATION STATUS:") + logging.info(" Files needing translation: %d", len(scan_results['files_to_process'])) + logging.info(" Files already fully translated: %d", len(scan_results['skipped_files'])) + logging.info("") + logging.info("ENTRY STATISTICS:") + logging.info(" Total entries in all files: %d", scan_results['total_entries_in_all_files']) + logging.info(" Already translated entries: %d", scan_results['total_translated_in_all_files']) + logging.info(" Entries to translate: %d", scan_results['total_entries']) if scan_results['total_entries_in_all_files'] > 0: completion_percent = ( @@ -548,6 +568,15 @@ def _analyze_po_file(self, po_file): stats.total_in_file = len([e for e in po_file if e.msgid]) stats.untranslated = len([e for e in po_file if is_entry_untranslated(e)]) stats.translated_in_file = stats.total_in_file - stats.untranslated + # Also count fuzzy entries when fix_fuzzy is enabled + if self.config.flags.fix_fuzzy: + # Count all fuzzy entries + stats.fuzzy = len([e for e in po_file if 'fuzzy' in e.flags]) + # Also count header if it's fuzzy + if hasattr(po_file, 'metadata_is_fuzzy') and po_file.metadata_is_fuzzy: + stats.fuzzy += 1 + else: + stats.fuzzy = 0 return stats def _scan_po_files(self, input_folder: str, languages: List[str], gitignore_parser): @@ -569,11 +598,24 @@ def _scan_po_files(self, input_folder: str, languages: List[str], gitignore_pars results.total_entries_in_all_files += stats.total_in_file results.total_translated_in_all_files += stats.translated_in_file - if stats.untranslated > 0: - results.files_to_process.append((po_file_path, po_file_result, stats.untranslated)) - results.total_entries += stats.untranslated - logging.debug("File %s: %d/%d entries need translation", - po_file_path, stats.untranslated, stats.total_in_file) + # Include files with fuzzy entries when fix_fuzzy is enabled + if self.config.flags.fix_fuzzy: + # In fix-fuzzy mode, only process files with fuzzy entries + needs_processing = stats.fuzzy > 0 + entries_to_process = stats.fuzzy + else: + # In normal mode, process files with untranslated entries + needs_processing = stats.untranslated > 0 + entries_to_process = stats.untranslated + + if needs_processing: + results.files_to_process.append((po_file_path, po_file_result, entries_to_process)) + results.total_entries += entries_to_process + if self.config.flags.fix_fuzzy: + logging.debug("File %s: %d fuzzy entries to fix", po_file_path, stats.fuzzy) + else: + logging.debug("File %s: %d/%d entries need translation", + po_file_path, stats.untranslated, stats.total_in_file) else: results.skipped_files.append(po_file_path) logging.debug("Skipping fully translated file: %s", po_file_path) @@ -586,7 +628,15 @@ def _track_file_progress(self, po_file_path, initial_count): """Track translation progress for a single file.""" try: po_file = polib.pofile(po_file_path) - remaining = len([e for e in po_file if is_entry_untranslated(e)]) + if self.config.flags.fix_fuzzy: + # In fix-fuzzy mode, count remaining fuzzy entries + remaining = len([e for e in po_file if 'fuzzy' in e.flags]) + # Also check if header is still fuzzy + if hasattr(po_file, 'metadata_is_fuzzy') and po_file.metadata_is_fuzzy: + remaining += 1 + else: + # In normal mode, count untranslated entries + remaining = len([e for e in po_file if is_entry_untranslated(e)]) return initial_count - remaining, remaining except Exception: return initial_count, 0 @@ -919,25 +969,32 @@ def fix_fuzzy_entries( detail_language: Optional[str] = None, ): """Find and fix fuzzy entries in a PO file using AI translation.""" + # Check if the metadata/header is fuzzy + header_was_fuzzy = False + if hasattr(po_file, 'metadata_is_fuzzy') and po_file.metadata_is_fuzzy: + header_was_fuzzy = True + po_file.metadata_is_fuzzy = False + logging.info("Removed fuzzy flag from file header in %s", po_file_path) + + # Find all fuzzy entries fuzzy_entries = [entry for entry in po_file if 'fuzzy' in entry.flags] - - if not fuzzy_entries: + if not fuzzy_entries and not header_was_fuzzy: logging.info("No fuzzy entries found in %s", po_file_path) return + if fuzzy_entries: + logging.info("Found %d fuzzy entries to fix in %s", len(fuzzy_entries), po_file_path) - logging.info("Found %d fuzzy entries to fix in %s", len(fuzzy_entries), po_file_path) - - texts_to_translate = [entry.msgid for entry in fuzzy_entries] - translations = self.get_translations(texts_to_translate, target_language, po_file_path, detail_language) + texts_to_translate = [entry.msgid for entry in fuzzy_entries] + translations = self.get_translations(texts_to_translate, target_language, po_file_path, detail_language) - self._update_fuzzy_po_entries(po_file, translations, entries_to_update=fuzzy_entries) + self._update_fuzzy_po_entries(po_file, translations, entries_to_update=fuzzy_entries) - po_file.save(po_file_path) - - self.po_file_handler.log_translation_status( - po_file_path, - texts_to_translate, - [entry.msgstr for entry in fuzzy_entries] - ) - - logging.info("Fuzzy fix completed for %s", po_file_path) + self.po_file_handler.log_translation_status( + po_file_path, + texts_to_translate, + [entry.msgstr for entry in fuzzy_entries] + ) + # Save the file if any changes were made (header fuzzy removal or entry translations) + if header_was_fuzzy or fuzzy_entries: + po_file.save(po_file_path) + logging.info("Fuzzy fix completed for %s", po_file_path)