From d05797d900c9671258ad7630e3b5dbc11717b915 Mon Sep 17 00:00:00 2001 From: "Dr.-Ing. Amilcar do Carmo Lucas" Date: Wed, 20 Nov 2024 21:59:08 +0100 Subject: [PATCH] IMPROVEMENT: Portuguse translation --- .../frontend_tkinter_connection_selection.py | 2 +- .../locale/MethodicConfigurator.pot | 6 +- .../pt/LC_MESSAGES/MethodicConfigurator.mo | Bin 62820 -> 62727 bytes .../pt/LC_MESSAGES/MethodicConfigurator.po | 12 +- .../extract_missing_translations.py | 43 ------ extract_missing_translations.py | 125 ++++++++++++++++++ 6 files changed, 131 insertions(+), 57 deletions(-) delete mode 100644 MethodicConfigurator/locale/pt/LC_MESSAGES/extract_missing_translations.py create mode 100644 extract_missing_translations.py diff --git a/MethodicConfigurator/frontend_tkinter_connection_selection.py b/MethodicConfigurator/frontend_tkinter_connection_selection.py index b56c3ed..9e88d85 100644 --- a/MethodicConfigurator/frontend_tkinter_connection_selection.py +++ b/MethodicConfigurator/frontend_tkinter_connection_selection.py @@ -132,7 +132,7 @@ def reconnect(self, selected_connection: str = "") -> bool: # defaults to auto- self.previous_selection = self.flight_controller.comport.device if self.destroy_parent_on_connect: self.parent.root.destroy() - if self.download_params_on_connect and hasattr(self.parent, _("download_flight_controller_parameters")): + if self.download_params_on_connect and hasattr(self.parent, "download_flight_controller_parameters"): self.parent.download_flight_controller_parameters(redownload=False) return False diff --git a/MethodicConfigurator/locale/MethodicConfigurator.pot b/MethodicConfigurator/locale/MethodicConfigurator.pot index 06785d2..a7e89e8 100644 --- a/MethodicConfigurator/locale/MethodicConfigurator.pot +++ b/MethodicConfigurator/locale/MethodicConfigurator.pot @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2024-11-20 18:33+0100\n" +"POT-Creation-Date: 2024-11-20 21:54+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -821,10 +821,6 @@ msgstr "" msgid "Connection step {} of {}" msgstr "" -#: MethodicConfigurator/frontend_tkinter_connection_selection.py:135 -msgid "download_flight_controller_parameters" -msgstr "" - #: MethodicConfigurator/frontend_tkinter_connection_selection.py:151 msgid "Flight controller connection" msgstr "" diff --git a/MethodicConfigurator/locale/pt/LC_MESSAGES/MethodicConfigurator.mo b/MethodicConfigurator/locale/pt/LC_MESSAGES/MethodicConfigurator.mo index e2b3350092b2b747c94ba4d1458c5cad8ac0e26e..49142703d60f1b3f6e388022e0cad826fa759f28 100644 GIT binary patch delta 7471 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 R@&5T;wf@gh##g`W`9I#A+du#S diff --git a/MethodicConfigurator/locale/pt/LC_MESSAGES/MethodicConfigurator.po b/MethodicConfigurator/locale/pt/LC_MESSAGES/MethodicConfigurator.po index c9b05f9..e38171d 100644 --- a/MethodicConfigurator/locale/pt/LC_MESSAGES/MethodicConfigurator.po +++ b/MethodicConfigurator/locale/pt/LC_MESSAGES/MethodicConfigurator.po @@ -5,8 +5,8 @@ msgid "" msgstr "" "Project-Id-Version: 0.9.9\n" -"POT-Creation-Date: 2024-11-20 18:33+0100\n" -"PO-Revision-Date: 2024-11-20 19:23+0100\n" +"POT-Creation-Date: 2024-11-20 21:54+0100\n" +"PO-Revision-Date: 2024-11-20 21:55+0100\n" "Last-Translator: Dr.-Ing. Amilcar do Carmo Lucas \n" "Language-Team: \n" "Language: pt\n" @@ -997,10 +997,6 @@ msgstr "Conectando com o FC" msgid "Connection step {} of {}" msgstr "Passo de conexão {} de {}" -#: MethodicConfigurator/frontend_tkinter_connection_selection.py:135 -msgid "download_flight_controller_parameters" -msgstr "download_flight_controller_parameters" - #: MethodicConfigurator/frontend_tkinter_connection_selection.py:151 msgid "Flight controller connection" msgstr "Conexão do controlador de voo" @@ -1573,7 +1569,7 @@ msgstr "Não disponível" #: MethodicConfigurator/frontend_tkinter_parameter_editor.py:253 msgid "This parameter is not available on the connected flight controller" -msgstr "Este parâmetro não está dísponivel no controlador de voo conectado." +msgstr "Este parâmetro não está dísponivel no controlador de voo conectado" #: MethodicConfigurator/frontend_tkinter_parameter_editor.py:255 msgid "Not editable" @@ -1693,7 +1689,7 @@ msgstr "3. Use " #: MethodicConfigurator/frontend_tkinter_parameter_editor.py:362 #: MethodicConfigurator/frontend_tkinter_parameter_editor_table.py:238 msgid "Del" -msgstr "Del" +msgstr "Rem" #: MethodicConfigurator/frontend_tkinter_parameter_editor.py:363 msgid " and " diff --git a/MethodicConfigurator/locale/pt/LC_MESSAGES/extract_missing_translations.py b/MethodicConfigurator/locale/pt/LC_MESSAGES/extract_missing_translations.py deleted file mode 100644 index f57672d..0000000 --- a/MethodicConfigurator/locale/pt/LC_MESSAGES/extract_missing_translations.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python3 - -""" -This file is part of Ardupilot methodic configurator. https://github.com/ArduPilot/MethodicConfigurator - -SPDX-FileCopyrightText: 2024 Amilcar do Carmo Lucas - -SPDX-License-Identifier: GPL-3.0-or-later -""" - -import gettext -import os - - -def extract_missing_translations(po_file, output_file) -> None: - # Set up the translation catalog - language = gettext.translation("messages", localedir=os.path.dirname(po_file), languages=["zh_CN"], fallback=True) - - # Read the .po file entries - with open(po_file, encoding="utf-8") as f: - lines = f.readlines() - - missing_translations = [] - - # Iterate through lines to find untranslated msgid - for i, f_line in enumerate(lines): - line = f_line.strip() - - if line.startswith("msgid"): - msgid = line.split('"')[1] # Get the msgid string - - # Check if the translation exists - if language.gettext(msgid) == msgid: # If translation is the same as msgid, it's missing - missing_translations.append((i, msgid)) - - # Write untranslated msgids along with their indices to the output file - with open(output_file, "w", encoding="utf-8") as f: - for index, item in missing_translations: - f.write(f"{index}:{item}\n") - - -if __name__ == "__main__": - extract_missing_translations("MethodicConfigurator.po", "missing_translations.txt") diff --git a/extract_missing_translations.py b/extract_missing_translations.py new file mode 100644 index 0000000..3aa4b06 --- /dev/null +++ b/extract_missing_translations.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 + +""" +This file is part of Ardupilot methodic configurator. https://github.com/ArduPilot/MethodicConfigurator + +SPDX-FileCopyrightText: 2024 Amilcar do Carmo Lucas + +SPDX-License-Identifier: GPL-3.0-or-later +""" + +import argparse +import gettext +import glob +import os + + +def parse_arguments() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Extract missing translations from a .po (GNU gettext) file.") + + # Add argument for language code + parser.add_argument( + "--lang-code", + default="zh_CN", + type=str, + help="The language code for which to extract missing translations (e.g., 'zh_CN', 'pt'). Defaults to %(default)s", + ) + + # Add argument for output file + parser.add_argument( + "--output-file", + default="missing_translation", + type=str, + help="The base name of the file(s) where the missing translations will be written. " + "This file will contain lines in the format 'index:msgid'. Defaults to %(default)s", + ) + + # Add argument for maximum number of translations per output file + parser.add_argument( + "--max-translations", + default=80, + type=int, + help="The maximum number of missing translations to write to each output file. Defaults to %(default)s", + ) + + return parser.parse_args() + + +def extract_missing_translations(lang_code: str) -> list[tuple[int, str]]: + # Set up the translation catalog + po_file = os.path.join("MethodicConfigurator", "locale", lang_code, "LC_MESSAGES", "MethodicConfigurator.po") + language = gettext.translation( + "MethodicConfigurator", localedir="MethodicConfigurator\\locale", languages=[lang_code], fallback=True + ) + + # Read the .po file entries + with open(po_file, encoding="utf-8") as f: + lines = f.readlines() + + missing_translations: list[tuple[int, str]] = [] + + # Iterate through lines to find untranslated msgid + msgid = "" + in_msgid = False + for i, f_line in enumerate(lines): + line = f_line.strip() + + if line.startswith("msgid "): + msgid = "" + in_msgid = True + + if in_msgid and not line.startswith("msgstr "): + line_split = line.split('"') + if len(line_split) > 1: + msgid += '"'.join(line_split[1:-1]) # Get the msgid string + else: + print(f"Error on line {i}") + continue + + if in_msgid and line.startswith("msgstr "): + in_msgid = False + # escape \ characters in a string + msgid_escaped = msgid.replace("\\", "\\\\") + # Check if the translation exists + if language.gettext(msgid_escaped) == msgid: # If translation is the same as msgid, it's missing + missing_translations.append((i - 1, msgid)) + + return missing_translations + + +def output_to_files(missing_translations: list[tuple[int, str]], output_file_base_name: str, max_translations: int) -> None: + # Remove any existing output files with the same base name + existing_files = glob.glob(f"{output_file_base_name}.txt") + existing_files += glob.glob(f"{output_file_base_name}_*.txt") + + for existing_file in existing_files: + os.remove(existing_file) + + # Determine the number of files needed + total_missing = len(missing_translations) + num_files = (total_missing // max_translations) + (1 if total_missing % max_translations else 0) + + # Write untranslated msgids along with their indices to the output file(s) + for file_index in range(num_files): + start_index = file_index * max_translations + end_index = start_index + max_translations + + # Set the name of the output file based on the index + current_output_file = output_file_base_name + current_output_file += f"_{file_index + 1}" if num_files > 1 else "" + current_output_file += ".txt" + + # Write untranslated msgids along with their indices to the output file + with open(current_output_file, "w", encoding="utf-8") as f: + for index, item in missing_translations[start_index:end_index]: + f.write(f"{index}:{item}\n") + + +def main() -> None: + args = parse_arguments() + missing_translations = extract_missing_translations(args.lang_code) + output_to_files(missing_translations, args.output_file, args.max_translations) + + +if __name__ == "__main__": + main()