Skip to content

Commit

Permalink
FEATURE: i18n markup added
Browse files Browse the repository at this point in the history
Both logging and output/display strings are marked, please double check before merging
  • Loading branch information
BloodSakura3774 authored and amilcarlucas committed Oct 25, 2024
1 parent f8f9ee5 commit 2e58281
Show file tree
Hide file tree
Showing 19 changed files with 521 additions and 461 deletions.
16 changes: 9 additions & 7 deletions MethodicConfigurator/ardupilot_methodic_configurator.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@

from MethodicConfigurator.common_arguments import add_common_arguments_and_parse

from MethodicConfigurator.internationalization import _

from MethodicConfigurator.version import VERSION


Expand All @@ -46,7 +48,7 @@ def argument_parser():
Returns:
argparse.Namespace: An object containing the parsed arguments.
"""
parser = argparse.ArgumentParser(description='ArduPilot methodic configurator is a simple GUI with a table that lists '
parser = argparse.ArgumentParser(description=_('ArduPilot methodic configurator is a simple GUI with a table that lists '
'parameters. The GUI reads intermediate parameter files from a directory and '
'displays their parameters in a table. Each row displays the parameter name, '
'its current value on the flight controller, its new value from the selected '
Expand All @@ -55,7 +57,7 @@ def argument_parser():
'When "Upload Selected to FC" is clicked, it uploads the selected parameters to the '
'flight controller. '
'When "Skip" is pressed, it skips to the next intermediate parameter file. '
'The process gets repeated for each intermediate parameter file.')
'The process gets repeated for each intermediate parameter file.'))
parser = FlightController.add_argparse_arguments(parser)
parser = LocalFilesystem.add_argparse_arguments(parser)
parser = ComponentEditorWindow.add_argparse_arguments(parser)
Expand All @@ -68,7 +70,7 @@ def connect_to_fc_and_read_parameters(args):

error_str = flight_controller.connect(args.device, log_errors=False)
if error_str:
if args.device and "No serial ports found" not in error_str:
if args.device and _("No serial ports found") not in error_str:
logging_error(error_str)
conn_sel_window = ConnectionSelectionWindow(flight_controller, error_str)
conn_sel_window.root.mainloop()
Expand All @@ -77,9 +79,9 @@ def connect_to_fc_and_read_parameters(args):
if vehicle_type == "": # not explicitly set, to try to guess it
if flight_controller.info.vehicle_type is not None:
vehicle_type = flight_controller.info.vehicle_type
logging_debug("Vehicle type not set explicitly, auto-detected %s.", vehicle_type)
logging_debug(_("Vehicle type not set explicitly, auto-detected %s."), vehicle_type)
else:
logging_info("Vehicle type explicitly set to %s.", vehicle_type)
logging_info(_("Vehicle type explicitly set to %s."), vehicle_type)

return flight_controller,vehicle_type

Expand Down Expand Up @@ -110,7 +112,7 @@ def component_editor(args, flight_controller, vehicle_type, local_filesystem, ve
flight_controller.fc_parameters)
if error_message:
logging_error(error_message)
show_error_message("Error in derived parameters", error_message)
show_error_message(_("Error in derived parameters"), error_message)
sys_exit(1)


Expand All @@ -131,7 +133,7 @@ def main():
local_filesystem = LocalFilesystem(args.vehicle_dir, vehicle_type, flight_controller.info.flight_sw_version,
args.allow_editing_template_files)
except SystemExit as exp:
show_error_message("Fatal error reading parameter files", f"{exp}")
show_error_message(_("Fatal error reading parameter files"), f"{exp}")
raise

param_default_values_dirty = False
Expand Down
6 changes: 3 additions & 3 deletions MethodicConfigurator/argparse_check_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from operator import ge
from operator import lt
from operator import le

from MethodicConfigurator.internationalization import _

class CheckRange(Action):
'''
Expand All @@ -29,9 +29,9 @@ class CheckRange(Action):

def __init__(self, *args, **kwargs):
if "min" in kwargs and "inf" in kwargs:
raise ValueError("either min or inf, but not both")
raise ValueError(_("either min or inf, but not both"))
if "max" in kwargs and "sup" in kwargs:
raise ValueError("either max or sup, but not both")
raise ValueError(_("either max or sup, but not both"))

for name in self.ops:
if name in kwargs:
Expand Down
50 changes: 26 additions & 24 deletions MethodicConfigurator/backend_filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
from MethodicConfigurator.backend_filesystem_configuration_steps import ConfigurationSteps
from MethodicConfigurator.backend_filesystem_program_settings import ProgramSettings

from MethodicConfigurator.internationalization import _

TOOLTIP_MAX_LENGTH = 105


Expand Down Expand Up @@ -111,7 +113,7 @@ def re_init(self, vehicle_dir: str, vehicle_type: str):
vehicle_type = self.get_fc_fw_type_from_vehicle_components_json()
if vehicle_type == "":
vehicle_type = "ArduCopter"
logging_warning("Could not detect vehicle type. Defaulting to %s.", vehicle_type)
logging_warning(_("Could not detect vehicle type. Defaulting to %s."), vehicle_type)
self.vehicle_type = vehicle_type

ConfigurationSteps.re_init(self, vehicle_dir, vehicle_type)
Expand Down Expand Up @@ -232,7 +234,7 @@ def read_params_from_files(self):
continue
parameters[filename] = Par.load_param_file_into_dict(os_path.join(self.vehicle_dir, filename))
else:
logging_error("Error: %s is not a directory.", self.vehicle_dir)
logging_error(_("Error: %s is not a directory."), self.vehicle_dir)
return parameters

@staticmethod
Expand Down Expand Up @@ -419,7 +421,7 @@ def zip_files(self, files_to_zip: List[Tuple[bool, str]]):
if wrote:
self.add_configuration_file_to_zip(zipf, filename)

logging_info("Intermediate parameter files and summary files zipped to %s", zip_file_path)
logging_info(_("Intermediate parameter files and summary files zipped to %s"), zip_file_path)

def vehicle_image_filepath(self):
return os_path.join(self.vehicle_dir, 'vehicle.jpg')
Expand Down Expand Up @@ -464,24 +466,24 @@ def copy_fc_values_to_file(self, selected_file: str, params: Dict[str, float]):
v.value = params[param]
ret += 1
else:
logging_warning("Parameter %s not found in the current parameter file", param)
logging_warning(_("Parameter %s not found in the current parameter file"), param)
return ret

def write_last_uploaded_filename(self, current_file: str):
try:
with open(os_path.join(self.vehicle_dir, 'last_uploaded_filename.txt'), 'w', encoding='utf-8') as file:
file.write(current_file)
except Exception as e: # pylint: disable=broad-except
logging_error("Error writing last uploaded filename: %s", e)
logging_error(_("Error writing last uploaded filename: %s"), e)

def __read_last_uploaded_filename(self) -> str:
try:
with open(os_path.join(self.vehicle_dir, 'last_uploaded_filename.txt'), 'r', encoding='utf-8') as file:
return file.read().strip()
except FileNotFoundError as e:
logging_debug("last_uploaded_filename.txt not found: %s", e)
logging_debug(_("last_uploaded_filename.txt not found: %s"), e)
except Exception as e: # pylint: disable=broad-except
logging_error("Error reading last uploaded filename: %s", e)
logging_error(_("Error reading last uploaded filename: %s"), e)
return ""

def get_start_file(self, explicit_index: int, tcal_available: bool) -> str:
Expand All @@ -496,27 +498,27 @@ def get_start_file(self, explicit_index: int, tcal_available: bool) -> str:
start_file_index = explicit_index # Ensure the index is within the range of available files
if start_file_index >= len(files):
start_file_index = len(files) - 1
logging_warning("Starting file index %s is out of range. Starting with file %s instead.",
logging_warning(_("Starting file index %s is out of range. Starting with file %s instead."),
explicit_index, files[start_file_index])
return files[start_file_index]

if tcal_available:
start_file = files[0]
info_msg = "Starting with the first file."
info_msg = _("Starting with the first file.")
else:
start_file = files[2]
info_msg = "Starting with the first non-tcal file."
info_msg = _("Starting with the first non-tcal file.")

last_uploaded_filename = self.__read_last_uploaded_filename()
if last_uploaded_filename:
logging_info("Last uploaded file was %s.", last_uploaded_filename)
logging_info(_("Last uploaded file was %s."), last_uploaded_filename)
else:
logging_info("No last uploaded file found. %s.", info_msg)
logging_info(_("No last uploaded file found. %s."), info_msg)
return start_file

if last_uploaded_filename not in files:
# Handle the case where last_uploaded_filename is not found in the list
logging_warning("Last uploaded file not found in the list of files. %s.", info_msg)
logging_warning(_("Last uploaded file not found in the list of files. %s."), info_msg)
return start_file

# Find the index of last_uploaded_filename in files
Expand All @@ -525,7 +527,7 @@ def get_start_file(self, explicit_index: int, tcal_available: bool) -> str:
start_file_index = last_uploaded_index + 1
if start_file_index >= len(files):
# Handle the case where last_uploaded_filename is the last file in the list
logging_warning("Last uploaded file is the last file in the list. Starting from there.")
logging_warning(_("Last uploaded file is the last file in the list. Starting from there."))
start_file_index = len(files) - 1
return files[start_file_index]

Expand Down Expand Up @@ -589,38 +591,38 @@ def get_upload_local_and_remote_filenames(self, selected_file: str) -> Tuple[str
@staticmethod
def download_file_from_url(url: str, local_filename: str, timeout: int=5) -> bool:
if not url or not local_filename:
logging_error("URL or local filename not provided.")
logging_error(_("URL or local filename not provided."))
return False
logging_info("Downloading %s from %s", local_filename, url)
logging_info(_("Downloading %s from %s"), local_filename, url)
response = requests_get(url, timeout=timeout)

if response.status_code == 200:
with open(local_filename, "wb") as file:
file.write(response.content)
return True

logging_error("Failed to download the file")
logging_error(_("Failed to download the file"))
return False

@staticmethod
def add_argparse_arguments(parser):
parser.add_argument('-t', '--vehicle-type',
choices=VehicleComponents.supported_vehicles(),
default='',
help='The type of the vehicle. Defaults to ArduCopter')
help=_('The type of the vehicle. Defaults to ArduCopter'))
parser.add_argument('--vehicle-dir',
type=str,
default=os_getcwd(),
help='Directory containing vehicle-specific intermediate parameter files. '
'Defaults to the current working directory')
help=_('Directory containing vehicle-specific intermediate parameter files. '
'Defaults to the current working directory'))
parser.add_argument('--n',
type=int,
default=-1,
help='Start directly on the nth intermediate parameter file (skips previous files). '
help=_('Start directly on the nth intermediate parameter file (skips previous files). '
'Default is to start on the file next to the last that you wrote to the flight controller.'
'If the file does not exist, it will start on the first file.')
'If the file does not exist, it will start on the first file.'))
parser.add_argument('--allow-editing-template-files',
action='store_true',
help='Allow opening and editing template files directly. '
'Only for software developers that know what they are doing.')
help=_('Allow opening and editing template files directly. '
'Only for software developers that know what they are doing.'))
return parser
39 changes: 20 additions & 19 deletions MethodicConfigurator/backend_filesystem_configuration_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@

from json import load as json_load
from json import JSONDecodeError

from typing import Tuple

from MethodicConfigurator.annotate_params import Par

from MethodicConfigurator.internationalization import _


class ConfigurationSteps:
"""
Expand Down Expand Up @@ -56,24 +57,24 @@ def re_init(self, vehicle_dir: str, vehicle_type: str):
file_found = True
if self.log_loaded_file:
if i == 0:
logging_warning("Configuration steps '%s' loaded from %s " \
"(overwriting default configuration steps).",
logging_warning(_("Configuration steps '%s' loaded from %s " \
"(overwriting default configuration steps)."),
self.configuration_steps_filename, directory)
if i == 1:
logging_info("Configuration steps '%s' loaded from %s.",
logging_info(_("Configuration steps '%s' loaded from %s."),
self.configuration_steps_filename, directory)
break
except FileNotFoundError:
pass
except JSONDecodeError as e:
logging_error("Error in file '%s': %s", self.configuration_steps_filename, e)
logging_error(_("Error in file '%s': %s"), self.configuration_steps_filename, e)
break
if file_found:
for filename, file_info in self.configuration_steps.items():
self.__validate_parameters_in_configuration_steps(filename, file_info, 'forced')
self.__validate_parameters_in_configuration_steps(filename, file_info, 'derived')
else:
logging_warning("No configuration steps documentation and no forced and derived parameters will be available.")
logging_warning(_("No configuration steps documentation and no forced and derived parameters will be available."))
self.log_loaded_file = True

def __validate_parameters_in_configuration_steps(self, filename: str, file_info: dict, parameter_type: str) -> None:
Expand All @@ -85,17 +86,17 @@ def __validate_parameters_in_configuration_steps(self, filename: str, file_info:
"""
if parameter_type + '_parameters' in file_info:
if not isinstance(file_info[parameter_type + '_parameters'], dict):
logging_error("Error in file '%s': '%s' %s parameter is not a dictionary",
logging_error(_("Error in file '%s': '%s' %s parameter is not a dictionary"),
self.configuration_steps_filename, filename, parameter_type)
return
for parameter, parameter_info in file_info[parameter_type + '_parameters'].items():
if "New Value" not in parameter_info:
logging_error("Error in file '%s': '%s' %s parameter '%s'"
" 'New Value' attribute not found.",
logging_error(_("Error in file '%s': '%s' %s parameter '%s'"
" 'New Value' attribute not found."),
self.configuration_steps_filename, filename, parameter_type, parameter)
if "Change Reason" not in parameter_info:
logging_error("Error in file '%s': '%s' %s parameter '%s'"
" 'Change Reason' attribute not found.",
logging_error(_("Error in file '%s': '%s' %s parameter '%s'"
" 'Change Reason' attribute not found."),
self.configuration_steps_filename, filename, parameter_type, parameter)

def compute_parameters(self, filename: str, file_info: dict, parameter_type: str, variables: dict) -> str:
Expand All @@ -112,8 +113,8 @@ def compute_parameters(self, filename: str, file_info: dict, parameter_type: str
try:
if ('fc_parameters' in str(parameter_info["New Value"])) and \
('fc_parameters' not in variables or variables['fc_parameters'] == {}):
error_msg = f"In file '{self.configuration_steps_filename}': '{filename}' {parameter_type} " \
f"parameter '{parameter}' could not be computed: 'fc_parameters' not found, is an FC connected?"
error_msg = _(f"In file '{self.configuration_steps_filename}': '{filename}' {parameter_type} " \
f"parameter '{parameter}' could not be computed: 'fc_parameters' not found, is an FC connected?")
if parameter_type == 'forced':
logging_error(error_msg)
return error_msg
Expand All @@ -136,8 +137,8 @@ def compute_parameters(self, filename: str, file_info: dict, parameter_type: str
destination[filename] = {}
destination[filename][parameter] = Par(float(result), parameter_info["Change Reason"])
except (SyntaxError, NameError, KeyError, StopIteration) as e:
error_msg = f"In file '{self.configuration_steps_filename}': '{filename}' {parameter_type} " \
f"parameter '{parameter}' could not be computed: {e}"
error_msg = _(f"In file '{self.configuration_steps_filename}': '{filename}' {parameter_type} " \
f"parameter '{parameter}' could not be computed: {e}")
if parameter_type == 'forced':
logging_error(error_msg)
return error_msg
Expand All @@ -158,11 +159,11 @@ def get_documentation_text_and_url(self, selected_file: str, prefix_key: str) ->
documentation = self.configuration_steps.get(selected_file, {}) if \
self.configuration_steps else None
if documentation is None:
text = f"File '{self.configuration_steps_filename}' not found. " \
"No intermediate parameter configuration steps available"
text = _(f"File '{self.configuration_steps_filename}' not found. " \
"No intermediate parameter configuration steps available")
url = None
else:
text = documentation.get(prefix_key + "_text", f"No documentation available for {selected_file} in the "
f"{self.configuration_steps_filename} file")
text = documentation.get(prefix_key + "_text", _(f"No documentation available for {selected_file} in the "
f"{self.configuration_steps_filename} file"))
url = documentation.get(prefix_key + "_url", None)
return text, url
Loading

0 comments on commit 2e58281

Please sign in to comment.