From 2f468205bdf7d59ebd7893751618fa65d4258e07 Mon Sep 17 00:00:00 2001 From: Brian Read Date: Sat, 19 Jul 2025 14:47:24 +0100 Subject: [PATCH] Fix up menu code, add comment on front --- lex_scan.py | 154 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 133 insertions(+), 21 deletions(-) diff --git a/lex_scan.py b/lex_scan.py index a09b690..d4217a0 100644 --- a/lex_scan.py +++ b/lex_scan.py @@ -1,3 +1,12 @@ +# +# lex_scan.py - Audit .lex files +# -a - Make sure all lex stringsa in code and tmeplates are in en lex file +# - delete any that aren't needed +# -e - Move all single word vqalues for lex strings to gthe general category +# -m - Examine all the controller files and make sure all headings and Descriptions are in the en general file +# - remove them from the controller en.lex file +# -l - Copy all panel and general files to each equivalent language file, fill in all translations over english where they exist in old .lex file +# import argparse import logging import os @@ -264,25 +273,6 @@ def read_lex_file(filepath): lex_data[key] = value return lex_data -def write_lex_file(filepath, lex_data): - """ - Writes a dictionary to a lex file, sorted alphabetically by key (case-insensitive). - Adds a header with the current date and time. - """ - # Sort the dictionary by key, case-insensitive - sorted_items = sorted(lex_data.items(), key=lambda item: item[0].lower()) - now = datetime.now().strftime('%Y-%m-%d %H:%M:%S') - # Extract panel name using regex - match = re.search(r'.*/output/([^/]+)/', filepath) - panel_name = match.group(1) if match else 'Unknown' - logger.info(f"{filepath} {panel_name}") - header = f"#\n# Lex file for {panel_name} generated on {now}\n#\n" - with open(filepath, 'w', encoding='utf-8') as f: - f.write(header) - for key, value in sorted_items: - value = value.replace("'", '"') - f.write(f"'{key}' => '{value}',{os.linesep}") - def read_languages_json(filepath): if not os.path.exists(filepath): @@ -348,6 +338,50 @@ def update_file_with_new_lexical_string(filepath, old_string, new_string, filepa except Exception as e: logger.error(f"❌Error updating file {filepath} (writing to {filepath_new}): {e}") +def parse_smeserver_db(filepath): + """ + Parses SME Server navigation DB entries from '|' delimited format lines like: + + key=panel|Description|Text|...|Heading|Text|... + + Returns: + list[dict]: List of dictionaries with 'Description' and/or 'Heading' fields. + """ + filepath = os.path.expanduser(filepath) + entries = [] + + if not os.path.isfile(filepath): + logger.error(f"SME server DB file not found: {filepath}") + return entries + + try: + with open(filepath, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + + if not line or line.startswith('#') or '=' not in line: + continue + + key, data = line.split('=', 1) + parts = data.split('|') + + # Skip first part ("panel"), then parse key-value fields + entry = {} + for i in range(1, len(parts) - 1, 2): + field = parts[i].strip() + value = parts[i + 1].strip() + if field in ("Description", "Heading"): + entry[field] = value + + if entry: + entries.append(entry) + + except Exception as e: + logger.error(f"Error parsing SME server DB: {e}") + + logger.info(f"Parsed {len(entries)} navigation entries with Description or Heading.") + return entries + def export_sorted_missing_lex(input_file1, input_file2, output_file): """ Reads two lex files, finds all entries in input_file1 missing from input_file2, @@ -426,7 +460,52 @@ def delete_lex_output_files(panel_lex_output_dir): return deleted_files - +def write_lex_file(filepath, lex_data): + """ + Writes a dictionary to a lex file, sorted alphabetically by key (case-insensitive). + Adds a header with the current date and time. + """ + # Sort the dictionary by key, case-insensitive + sorted_items = sorted(lex_data.items(), key=lambda item: item[0].lower()) + now = datetime.now().strftime('%Y-%m-%d %H:%M:%S') + + # Extract panel name using regex + match = re.search(r'.*/output/([^/]+)/', filepath) + panel_name = match.group(1) if match else 'Unknown' + logger.info(f"{filepath} {panel_name}") + + header = f"#\n# Lex file for {panel_name} generated on {now}\n#\n" + with open(filepath, 'w', encoding='utf-8') as f: + f.write(header) + for key, value in sorted_items: + # Properly escape single quotes in values instead of replacing with double quotes + escaped_value = value.replace("'", "\\'") + f.write(f"'{key}' => '{escaped_value}',{os.linesep}") + + +def find_new_lex_entries(general_lex_entries, menu_lex_strings): + existing_keys = set(general_lex_entries.keys()) + new_entries = {} + + for item in menu_lex_strings: + if isinstance(item, dict): + for key in ("Description", "Heading"): + val = item.get(key, "").strip() + if val and val not in existing_keys: + existing_keys.add(val) + new_entries[val] = val + logger.info(f"New entry detected: {val}={val}") + else: + val = str(item).strip() + if val and val not in existing_keys: + existing_keys.add(val) + new_entries[val] = val + logger.info(f"New entry detected: {val}={val}") + + logger.info(f"Found {len(new_entries)} new entries for general lex file") + return new_entries + + def main(): parser = argparse.ArgumentParser(description="Scan and audit Mojolicious application files for lexical strings.") parser.add_argument("-p", "--panel", required=True, help="Name of the Mojolicious panel (e.g., MyPanel).") @@ -434,6 +513,7 @@ def main(): parser.add_argument("-a", "--audit", action="store_true", help="Enable audit of all strings (default: False).") parser.add_argument("-e", "--edit", action="store_true", help="Enable audit of single words (default: False).") parser.add_argument("-l", "--lang", action="store_true", help="Enable other language processing (default: False).") + parser.add_argument("-m", "--menu", action="store_true", help="Check that all mewnu items are in the general lex(default: False).") args = parser.parse_args() @@ -443,6 +523,7 @@ def main(): edit_files = args.edit do_lang = args.lang do_audit = args.audit + do_menu = args.menu if panel in ['Support','Manual','Initial','Legacypanel','Roundcubepanel','Module','Request','Swttheme','','','','','','','','','']: logger.warning(f"Skipping {panel}") @@ -585,8 +666,39 @@ def main(): logger.info(f"New General English general lex file lines: {len(new_general_en_lex_data)} written to {general_en_lex_new_path}") logger.info(f"New English panel-specific lex file lines: {len(en_lex_data)} written to {en_lex_new_path}") + logger.info("") + + if do_menu: + logger.info(f"Running menu update procedure") + + # Look in the menu DB and check that all descriptions and headings are in the general lex + general_en_lex_path_orig = os.path.join(general_lex_output_dir, "general_en.lex.new1") + general_en_lex_data_orig = read_lex_file(general_en_lex_path_orig) + + # Test write to verify original data integrity + general_en_lex_path_test = os.path.join(general_lex_output_dir, "general_en.lex.new11") + write_lex_file(general_en_lex_path_test, general_en_lex_data_orig) + + # Get menu descriptions + menu_lex_strings = parse_smeserver_db('~/SME11/home/e-smith/db/navigation2/navigation.en') + + # Find new items that need to be added to the lex file + new_items_dict = find_new_lex_entries(general_en_lex_data_orig, menu_lex_strings) + + # CORRECTED: Merge dictionaries instead of working with string lists + # Start with original data to preserve existing key-value pairs + final_lex_dict = general_en_lex_data_orig.copy() + + # Add new entries + final_lex_dict.update(new_items_dict) + + # Write the final updated lex file + general_en_lex_path_new = os.path.join(general_lex_output_dir, "general_en.lex.new2") + write_lex_file(general_en_lex_path_new, final_lex_dict) + + logger.info(f"Updated lex file written to {general_en_lex_path_new}") + logger.info(f"Total entries: {len(final_lex_dict)} (original: {len(general_en_lex_data_orig)}, new: {len(new_items_dict)})") - logger.info("") if do_lang: # Panel specific lex files languages_json_path = os.path.join(".", "Templates", "languages.json") # Corrected path