import re import time import pandas as pd from openpyxl import load_workbook import logging import os # Diccionario de idiomas IDIOMAS = { 0: ("Italian", "it-IT"), 1: ("English", "en-GB"), 2: ("Portuguese", "pt-PT"), 3: ("Spanish", "es-ES"), 4: ("Russian", "ru-RU"), 5: ("French", "fr-FR"), 6: ("German", "de-DE"), } def mostrar_idiomas(): print("Selecciona el idioma de destino:") for numero, (nombre, _) in IDIOMAS.items(): print(f"{numero}: {nombre}") def configurar_logger(): logger = logging.getLogger("translate_logger") logger.setLevel(logging.DEBUG) os.makedirs(".\\logs", exist_ok=True) fh = logging.FileHandler(".\\logs\\translate_log.log", encoding="utf-8") fh.setLevel(logging.DEBUG) formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s : ") fh.setFormatter(formatter) logger.addHandler(fh) return logger # # Salvar archivo Excel controlando que no este abierto. Sino espera. # def save_dataframe_with_retries(df, output_path, max_retries=5, retry_delay=5): """ Guarda un DataFrame en un archivo Excel, reintentando si el archivo está en uso. :param df: El DataFrame a guardar. :param output_path: La ruta del archivo donde se guardará el DataFrame. :param max_retries: El número máximo de reintentos en caso de error. :param retry_delay: El tiempo de espera (en segundos) entre cada reintento. """ retries = 0 while retries < max_retries: try: df.to_excel(output_path, sheet_name="User Texts", index=False) print("Archivo guardado exitosamente.") return except PermissionError as e: print( f"Error de permiso: {e}. Por favor cierre el archivo. Reintentando en {retry_delay} segundos..." ) retries += 1 time.sleep(retry_delay) print(f"No se pudo guardar el archivo después de {max_retries} intentos.") def cambiar_nombre_hoja(archivo_excel, nombre_hoja_actual, nombre_hoja_nuevo): # Cargar el archivo Excel existente libro = load_workbook(archivo_excel) # Verificar si la hoja existe en el archivo if nombre_hoja_actual in libro.sheetnames: # Obtener la hoja actual hoja = libro[nombre_hoja_actual] # Cambiar el nombre de la hoja hoja.title = nombre_hoja_nuevo # Guardar los cambios en el archivo Excel libro.save(archivo_excel) print( f"El nombre de la hoja ha sido cambiado de '{nombre_hoja_actual}' a '{nombre_hoja_nuevo}'." ) else: print(f"La hoja '{nombre_hoja_actual}' no existe en el archivo.") # Verificar si la columna es del tipo "xx-YY" usando una expresión regular def es_columna_tipo_xxYY(columna): # Verificar si la columna es del tipo "xx-YY" usando una expresión regular return bool(re.match(r"^[a-z]{2}-[A-Z]{2}$", columna)) def compactar_celda_clave_siemens(celda_original): if pd.isnull(celda_original): return celda_original def reemplazar(match): if match.group(1): # Si hay contenido dentro de <> return f"<{match.group(1)}>" return "[[digits]]" # Reemplaza dígitos fuera de <> con [[digits]], y preserva el contenido dentro de <> return re.sub(r"<(.*?)>|\d+", reemplazar, str(celda_original)) def compactar_celda_traducida(tipo_PLC, celda_traducida): if tipo_PLC == "siemens" : return compactar_celda_traducida_siemens(celda_traducida) else : return compactar_celda_traducida_ab(celda_traducida) def obtener_digitos_celda_original(tipo_PLC, celda_original): if tipo_PLC == "siemens" : return obtener_digitos_celda_original_siemens(celda_original) else : return obtener_digitos_celda_original_ab(celda_original) def decompactar_celda_traducida(tipo_PLC, celda_original, celda_traducida): if tipo_PLC == "siemens" : decompactar_celda_traducida_siemens(celda_original, celda_traducida) else : decompactar_celda_traducida_ab(celda_original, celda_traducida) def verificar_celda_traducida(tipo_PLC, celda_clave, celda_traducida): if tipo_PLC == "siemens" : verificar_celda_traducida_siemens(celda_clave, celda_traducida) else : verificar_celda_traducida_ab(celda_clave, celda_traducida) # SIEMENS # # Transforma: "A271/47/6 Air - M - Necessaria Manutenzione Filtro" -> # "A[[digits]]/[[digits]]/[[digits]] Air - M - Necessaria Manutenzione Filtro" # # Este procesamiento se aplica a las celdas clave def compactar_celda_clave_siemens(celda_original): if pd.isnull(celda_original): return celda_original def reemplazar(match): if match.group(1): # Si hay contenido dentro de <> return f"<{match.group(1)}>" return "[[digits]]" # Reemplaza dígitos fuera de <> con [[digits]], y preserva el contenido dentro de <> return re.sub(r"<(.*?)>|\d+", reemplazar, str(celda_original)) # SIEMENS # # Transforma: "A[[digits]]/[[digits]]/[[digits]] Air - M - Necessaria Manutenzione Filtro" -> # "A<>/<>/<> Air - M<#>" /> - Necessaria Manutenzione Filtro" # # Este procesamiento se aplica a las celdas traducidas def compactar_celda_traducida_siemens(celda_traducida): if pd.isnull(celda_traducida): return celda_traducida celda_traducida = compactar_celda_clave(celda_traducida) def reemplazar(match): if match.group(1): # Si hay contenido dentro de <> return "<#>" return "<>" # Reemplaza <...> con <#> y [[digits]] con <> return re.sub(r"<(.*?)>|\[\[digits\]\]", reemplazar, str(celda_traducida)) # SIEMENS # de "A271/47/6 Air - M - Necessaria Manutenzione Filtro" -> [271,47,6] # Obtener la secuencias de dígitos por [[digits]] def obtener_digitos_celda_original_siemens(celda_original): if pd.isnull(celda_original): return [] # Primero, reemplazamos temporalmente el contenido de los tags con un marcador texto_sin_tags = re.sub(r'<[^>]*>', '<>', str(celda_original)) # Ahora buscamos los dígitos digitos = re.findall(r'\d+', texto_sin_tags) return digitos # SIEMENS # Original Traducida # Transforma: "A271/47/6 Air - M - Necessaria Manutenzione Filtro" , "A<>/<>/<> Air - M<#> - Filter Maintenance Required" -> # "A271/47/6 Air - M - Necessaria Manutenzione Filtro" # # Este procesamiento se aplica a las celdas traducidas para regresar al valor original def decompactar_celda_traducida_siemens(celda_original, celda_traducida): digitos = obtener_digitos_celda_original(celda_original) celda_destino = celda_traducida # Replace <> with digits for d in digitos: celda_destino = celda_destino.replace("<>", d, 1) # Replace <#> with original content within <> original_tags = re.findall(r"<.*?>", celda_original) translated_tags = re.findall(r"<#>", celda_destino) for orig, trans in zip(original_tags, translated_tags): celda_destino = celda_destino.replace(trans, orig, 1) return celda_destino # # SIEMENS # def verificar_celda_traducida_siemens(celda_clave, celda_traducida): # Contar los placeholders de dígitos digitos_clave = celda_clave.count("[[digits]]") digitos_traducida = celda_traducida.count("<>") # Contar los placeholders de tags tags_clave = sum(1 for tag in re.findall(r"<.*?>", celda_clave) if tag != "[[digits]]") tags_traducida = celda_traducida.count("<#>") # Verificar si las cantidades coinciden if digitos_clave == digitos_traducida and tags_clave == tags_traducida: return True , "" else: text_error = f"Error de verificación:" + f" - Celda clave: {celda_clave}" + f" - Celda traducida: {celda_traducida}" text_error += f" - Dígitos en clave: {digitos_clave}, Dígitos en traducida: {digitos_traducida}" text_error += f" - Tags en clave: {tags_clave}, Tags en traducida: {tags_traducida}" return False, text_error # ALLEN BRADLEY # Transforma: "A271/47/6 Air - M/*field ref="0" */ - Necessaria Manutenzione Filtro" -> # "A[[digits]]/[[digits]]/[[digits]] Air - M/*field ref="[[digits]]" */ - Necessaria Manutenzione Filtro" # # Este procesamiento se aplica a las celdas clave def compactar_celda_clave_ab(celda_original): if pd.isnull(celda_original): return celda_original def reemplazar(match): if match.group(1): # Si hay contenido dentro de /*...*/ return f"/*{match.group(1)}*/" return "[[digits]]" # Reemplaza dígitos fuera de /*...*/ con [[digits]], y preserva el contenido dentro de /*...*/ return re.sub(r"/\*(.*?)\*/|\d+", reemplazar, str(celda_original)) # ALLEN BRADLEY # Transforma: "A[[digits]]/[[digits]]/[[digits]] Air - M/*field ref="[[digits]]" */ - Necessaria Manutenzione Filtro" -> # "A<>/<>/<> Air - M/*#*/ - Necessaria Manutenzione Filtro" # # Este procesamiento se aplica a las celdas traducidas def compactar_celda_traducida_ab(celda_traducida): if pd.isnull(celda_traducida): return celda_traducida celda_traducida = compactar_celda_clave_ab(celda_traducida) def reemplazar(match): if match.group(1): # Si hay contenido dentro de /*...*/ return "/*#*/" return "<>" # Reemplaza /*...*/ con /*#*/ y [[digits]] con <> return re.sub(r"/\*(.*?)\*/|\[\[digits\]\]", reemplazar, str(celda_traducida)) # ALLEN BRADLEY # De "A271/47/6 Air - M/*field ref="0" */ - Necessaria Manutenzione Filtro" -> [271,47,6] # Obtener las secuencias de dígitos para [[digits]] def obtener_digitos_celda_original_ab(celda_original): if pd.isnull(celda_original): return [] # Reemplazamos temporalmente el contenido de los comentarios con un marcador texto_sin_tags = re.sub(r'/\*[^*]*\*/', '<>', str(celda_original)) # Ahora buscamos los dígitos digitos = re.findall(r'\d+', texto_sin_tags) return digitos # ALLEN BRADLEY # Transformación para regresar al valor original def decompactar_celda_traducida_ab(celda_original, celda_traducida): digitos = obtener_digitos_celda_original_ab(celda_original) celda_destino = celda_traducida # Reemplaza <> con dígitos for d in digitos: celda_destino = celda_destino.replace("<>", d, 1) # Reemplaza /*#*/ con el contenido original dentro de /*...*/ original_tags = re.findall(r"/\*.*?\*/", celda_original) translated_tags = re.findall(r"/\*#\*/", celda_destino) for orig, trans in zip(original_tags, translated_tags): celda_destino = celda_destino.replace(trans, orig, 1) return celda_destino # # ALLEN BRADLEY # def verificar_celda_traducida_ab(celda_clave, celda_traducida): # Contar los placeholders de dígitos digitos_clave = celda_clave.count("[[digits]]") digitos_traducida = celda_traducida.count("<>") # Contar los placeholders de comentarios tags_clave = sum(1 for tag in re.findall(r"/\*.*?\*/", celda_clave) if tag != "[[digits]]") tags_traducida = celda_traducida.count("/*#*/") # Verificar si las cantidades coinciden if digitos_clave == digitos_traducida and tags_clave == tags_traducida: return True, "" else: text_error = f"Error de verificación:" + f" - Celda clave: {celda_clave}" + f" - Celda traducida: {celda_traducida}" text_error += f" - Dígitos en clave: {digitos_clave}, Dígitos en traducida: {digitos_traducida}" text_error += f" - Comentarios en clave: {tags_clave}, Comentarios en traducida: {tags_traducida}" return False, text_error if __name__ == "__main__": # SIEMENS celda_original = 'A271/47/6 Air - M - Necessaria Manutenzione Filtro' celda_original = 'DB/DB/DB' celda_original = 'Text' celda_clave = compactar_celda_clave(celda_original) celda_tradc = compactar_celda_traducida(celda_original) + " TEXTO " print() print("Celda Original : " +celda_original) print("Celda Clave : " + celda_clave) print("Celda Traducida: " + celda_tradc) print("Digitos : " + ','.join(obtener_digitos_celda_original(celda_original))) print("Celda : " + decompactar_celda_traducida(celda_original, celda_tradc)) print("Celda Original : " + celda_original) print(verificar_celda_traducida(celda_clave=celda_clave, celda_traducida= celda_tradc)) # ALLEN BRADLEY celda_original = 'Z2-A5-128: Drive Unload Channel Overload /*N:3 {[PLC_Connection]Buttons[#1].Program_Nr} NOFILL DP:0*/ - /*S:0 {[PLC_Connection]Buttons[#1].Program_Description}*/' # Simulando una celda traducida después del procesamiento celda_traducida = 'Z[[digits]]-A[[digits]]-[[digits]]: Drive Unload Channel Overload /*#*/ - /*#*/' celda_clave = compactar_celda_clave_ab(celda_original) celda_tradc = compactar_celda_traducida_ab(celda_traducida) print() print("Celda Original : " + celda_original) print("Celda Clave : " + celda_clave) print("Celda Traducida Compactada : " + celda_tradc) print("Dígitos : " + ','.join(obtener_digitos_celda_original_ab(celda_original))) print("Celda Reconstituida : " + decompactar_celda_traducida_ab(celda_original, celda_tradc)) print("Verificación : ", verificar_celda_traducida_ab(celda_clave=celda_clave, celda_traducida=celda_tradc))