Compare commits

..

2 Commits

25 changed files with 67847 additions and 11633 deletions

Binary file not shown.

Binary file not shown.

View File

@ -5,31 +5,17 @@ idioma_var = Spanish
idioma_var2 = English_US idioma_var2 = English_US
[TextContent] [TextContent]
output_text = Ejecutando x1_importar_to_master.run() output_text = Ejecutando x4B_integrate_manual_translates_to_master.run()
Se han agregado 939 nuevas filas válidas al archivo maestro. Archivo leído y limpiado exitosamente: .\data\1_hmi_master_translates_allenbradley.xlsx
Ejecutando x2_master_export2translate.run() Archivo leído y limpiado exitosamente: .\data\2_master_export2translate_allenbradley.xlsxEjecutando x4B_integrate_manual_translates_to_master.run()
Archivo leído y limpiado exitosamente: .\data\1_hmi_master_translates_allenbradley.xlsx Archivo leído y limpiado exitosamente: .\data\1_hmi_master_translates_allenbradley.xlsx
Archivo exportado para traducción: .\data\2_master_export2translate_allenbradley.xlsx
Ejecutando x3_llm_auto_translate.run()
Archivo leído y limpiado exitosamente: .\data\2_master_export2translate_allenbradley.xlsx Archivo leído y limpiado exitosamente: .\data\2_master_export2translate_allenbradley.xlsx
Número total de textos a traducir: 0
Archivo guardado exitosamente. Archivo guardado exitosamente.
Archivo traducido guardado en: .\data\3_master_export2translate_translated_allenbradley.xlsx Se han formateado 0 celdas modificadas en negrita en el archivo maestro.
Ejecutando x4_integrate_translates_to_master.run() Se han marcado 3 celdas con errores en rojo en el archivo fuente.
Archivo leído y limpiado exitosamente: .\data\1_hmi_master_translates_allenbradley.xlsx Traducciones manuales importadas y archivo maestro actualizado: .\data\1_hmi_master_translates_allenbradley.xlsx.
Archivo leído y limpiado exitosamente: .\data\3_master_export2translate_translated_allenbradley.xlsx Se han actualizado 0 celdas en el maestro y se han encontrado 3 errores en el archivo fuente.
Archivo guardado exitosamente.
Traducciones importadas y archivo maestro actualizado: .\data\1_hmi_master_translates_allenbradley.xlsx.
Ejecutando x4_integrate_translates_to_master.run()
Archivo leído y limpiado exitosamente: .\data\1_hmi_master_translates_allenbradley.xlsx
Archivo leído y limpiado exitosamente: .\data\3_master_export2translate_translated_allenbradley.xlsx
Archivo guardado exitosamente.
Traducciones importadas y archivo maestro actualizado: .\data\1_hmi_master_translates_allenbradley.xlsx.
Ejecutando x6_update_from_master.run()
Archivo leído y limpiado exitosamente: .\data\1_hmi_master_translates_allenbradley.xlsx
Archivo leído y limpiado exitosamente: C:/Trabajo/VM/31 - 9.3953 - Omega - Mexico - (ABradley)/Reporte/Languages/HMI_93953_30.xlsx
Archivo guardado exitosamente.
Se han actualizado las filas en C:/Trabajo/VM/31 - 9.3953 - Omega - Mexico - (ABradley)/Reporte/Languages/HMI_93953_30.xlsx desde el archivo maestro.
[Directorios]
work_dir = C:/Trabajo/VM/31 - 9.3953 - Omega - Mexico - (ABradley)/Reporte/Languages

File diff suppressed because it is too large Load Diff

View File

@ -1,269 +1,307 @@
import tkinter as tk import tkinter as tk
from tkinter import ttk from tkinter import ttk, filedialog, messagebox
from tkinter import messagebox
import PyLibrary.funciones_comunes as fc import PyLibrary.funciones_comunes as fc
import x1_importar_to_master import x1_importar_to_master
import x2_master_export2translate import x2_master_export2translate
import x3_llm_auto_translate import x3_llm_auto_translate
import x4_integrate_translates_to_master import x4_integrate_translates_to_master
import x4B_integrate_manual_translates_to_master
import x5_complete_empty_cells_master import x5_complete_empty_cells_master
import x6_update_from_master import x6_update_from_master
from translation_config import TranslationConfig
import sys import sys
import threading import threading
import configparser # Para manejar el archivo de configuración import os
import os # Para verificar si el archivo existe import subprocess
# Crear la ventana principal class TranslationApp:
ventana = tk.Tk() def __init__(self, master):
ventana.title("Ayuda para traducir textos de TIA Portal y Allen Bradley") self.master = master
ventana.geometry("800x600") # Ajustamos el tamaño de la ventana self.master.title("Ayuda para traducir textos de TIA Portal y Allen Bradley")
self.master.geometry("1200x800")
# Diccionario para tipo_PLC self.config = TranslationConfig.load()
tipo_PLC_dict = {'Siemens': 'siemens', 'AllenBradley': 'allenbradley'}
# Variables para almacenar las selecciones del usuario self.create_variables()
tipo_PLC_var = tk.StringVar() self.create_widgets()
codigo_columna_maestra_var = tk.StringVar() self.place_widgets()
idioma_var = tk.StringVar()
idioma_var2 = tk.StringVar()
# Crear listas de idiomas con sus códigos def create_variables(self):
idiomas_lista = [(nombre, codigo) for _, (nombre, codigo) in fc.IDIOMAS.items()] self.codigo_tipo_PLC_var = tk.StringVar(value=self.config.codigo_tipo_PLC)
self.codigo_columna_maestra_var = tk.StringVar(value=self.config.codigo_columna_maestra)
self.codigo_idioma_var = tk.StringVar(value=self.config.codigo_idioma_seleccionado)
self.codigo_idioma_var2 = tk.StringVar(value=self.config.codigo_idioma_secundario)
self.work_dir_var = tk.StringVar(value=self.config.work_dir)
# Ruta del archivo de configuración self.master_name_var = tk.StringVar(value=self.config.master_name)
config_file = 'config.ini' self.translate_name_var = tk.StringVar(value=self.config.translate_name)
self.auto_translate_name_var = tk.StringVar(value=self.config.auto_translate_name)
# Función para cargar las opciones guardadas def create_widgets(self):
def cargar_configuracion(): self.main_frame = ttk.Frame(self.master)
config = configparser.ConfigParser() self.main_frame.grid(row=0, column=0, sticky='nsew')
if os.path.exists(config_file): self.master.grid_rowconfigure(0, weight=1)
config.read(config_file) self.master.grid_columnconfigure(0, weight=1)
# Cargar tipo_PLC
tipo_PLC_var.set(config.get('Seleccion', 'tipo_PLC', fallback='Siemens'))
# Cargar codigo_columna_maestra
codigo_columna_maestra_var.set(config.get('Seleccion', 'codigo_columna_maestra', fallback=idiomas_lista[0][0]))
# Cargar idioma_var
idioma_var.set(config.get('Seleccion', 'idioma_var', fallback=idiomas_lista[4][0]))
# Cargar idioma_var2
idioma_var2.set(config.get('Seleccion', 'idioma_var2', fallback=idiomas_lista[1][0]))
else:
# Valores por defecto si no existe el archivo
tipo_PLC_var.set('Siemens')
codigo_columna_maestra_var.set(idiomas_lista[0][0])
idioma_var.set(idiomas_lista[4][0])
idioma_var2.set(idiomas_lista[1][0])
# Función para guardar las opciones seleccionadas self.frame_combos = ttk.Frame(self.main_frame)
def guardar_configuracion():
config = configparser.ConfigParser()
config['Seleccion'] = {
'tipo_PLC': tipo_PLC_var.get(),
'codigo_columna_maestra': codigo_columna_maestra_var.get(),
'idioma_var': idioma_var.get(),
'idioma_var2': idioma_var2.get()
}
# Guardar el contenido del cuadro de texto
config['TextContent'] = {
'output_text': output_text.get("1.0", tk.END)
}
with open(config_file, 'w') as configfile:
config.write(configfile)
# Crear un Frame para la grilla de comboboxes self.label_tipo_PLC = ttk.Label(self.frame_combos, text="Selecciona el tipo de PLC:")
frame_combos = tk.Frame(ventana) self.combo_tipo_PLC = ttk.Combobox(self.frame_combos, state="readonly")
frame_combos.pack(pady=10) self.combo_tipo_PLC["values"] = [nombre for nombre, _ in fc.PLCs.values()]
self.combo_tipo_PLC.bind('<<ComboboxSelected>>', self.update_tipo_PLC)
self.set_combo_value(self.combo_tipo_PLC, self.codigo_tipo_PLC_var.get())
# Crear los labels y comboboxes self.label_codigo_maestra = ttk.Label(self.frame_combos, text="Idioma Columna Maestra:")
label_tipo_PLC = tk.Label(frame_combos, text="Selecciona el tipo de PLC:") self.combo_codigo_maestra = ttk.Combobox(self.frame_combos, state="readonly")
combo_tipo_PLC = ttk.Combobox(frame_combos, textvariable=tipo_PLC_var, state="readonly") self.combo_codigo_maestra["values"] = [nombre for nombre, _ in fc.IDIOMAS.values()]
combo_tipo_PLC["values"] = list(tipo_PLC_dict.keys()) self.combo_codigo_maestra.bind('<<ComboboxSelected>>', self.update_codigo_maestra)
self.set_combo_value(self.combo_codigo_maestra, self.codigo_columna_maestra_var.get())
label_codigo_maestra = tk.Label(frame_combos, text="Idioma Columna Maestra:") self.label1 = ttk.Label(self.frame_combos, text="Idioma de Traducción:")
combo_codigo_maestra = ttk.Combobox(frame_combos, textvariable=codigo_columna_maestra_var, state="readonly") self.combo = ttk.Combobox(self.frame_combos, state="readonly")
combo_codigo_maestra["values"] = [nombre for nombre, _ in idiomas_lista] self.combo["values"] = [nombre for nombre, _ in fc.IDIOMAS.values()]
self.combo.bind('<<ComboboxSelected>>', self.update_idioma)
self.set_combo_value(self.combo, self.codigo_idioma_var.get())
label1 = tk.Label(frame_combos, text="Idioma de Traducción:") self.label2 = ttk.Label(self.frame_combos, text="Selecciona segundo idioma:")
combo = ttk.Combobox(frame_combos, textvariable=idioma_var, state="readonly") self.combo2 = ttk.Combobox(self.frame_combos, state="readonly")
combo["values"] = [nombre for nombre, _ in idiomas_lista] self.combo2["values"] = [nombre for nombre, _ in fc.IDIOMAS.values()]
self.combo2.bind('<<ComboboxSelected>>', self.update_idioma2)
self.set_combo_value(self.combo2, self.codigo_idioma_var2.get())
label2 = tk.Label(frame_combos, text="Selecciona segundo idioma:") self.work_dir_frame = ttk.Frame(self.main_frame)
combo2 = ttk.Combobox(frame_combos, textvariable=idioma_var2, state="readonly") self.work_dir_label = ttk.Label(self.work_dir_frame, text="Directorio de trabajo:")
combo2["values"] = [nombre for nombre, _ in idiomas_lista] self.work_dir_entry = ttk.Entry(self.work_dir_frame, textvariable=self.work_dir_var, width=50)
self.work_dir_button = ttk.Button(self.work_dir_frame, text="Seleccionar", command=self.select_work_dir)
self.open_explorer_button = ttk.Button(self.work_dir_frame, text="Abrir Explorador", command=self.open_explorer)
# Organizar los labels y comboboxes en una grilla 2x2 style = ttk.Style()
label_tipo_PLC.grid(row=0, column=0, padx=5, pady=5, sticky='e') style.configure('TButton', padding=(10, 10), font=('Helvetica', 10, 'bold'))
combo_tipo_PLC.grid(row=0, column=1, padx=5, pady=5, sticky='w') style.configure('Excel.TButton', padding=(10, 10), font=('Helvetica', 10), background='#69cf81')
label_codigo_maestra.grid(row=1, column=0, padx=5, pady=5, sticky='e') self.button_width = 60
combo_codigo_maestra.grid(row=1, column=1, padx=5, pady=5, sticky='w') self.entry_width = 50
label1.grid(row=0, column=2, padx=5, pady=5, sticky='e') self.paso1 = ttk.Button(self.main_frame, text="1 - Importar al Master", command=lambda: self.ejecutar_run(x1_importar_to_master.run), width=self.button_width)
combo.grid(row=0, column=3, padx=5, pady=5, sticky='w') self.master_name_button = ttk.Button(self.main_frame, textvariable=self.master_name_var, command=lambda: self.open_file(self.config.get_master_path()), width=self.entry_width, style='Excel.TButton')
label2.grid(row=1, column=2, padx=5, pady=5, sticky='e') self.paso2 = ttk.Button(self.main_frame, text="2 - Exportar Idioma a 2_master_export2translate.xlsx", command=lambda: self.ejecutar_run(x2_master_export2translate.run), width=self.button_width)
combo2.grid(row=1, column=3, padx=5, pady=5, sticky='w') self.translate_name_button = ttk.Button(self.main_frame, textvariable=self.translate_name_var, command=lambda: self.open_file(self.config.get_translate_path()), width=self.entry_width, style='Excel.TButton')
# Función para actualizar combo_codigo_maestra según la selección en combo_tipo_PLC self.paso3 = ttk.Button(self.main_frame, text="3 - Traducir y generar 3_master_export2translate_translated.xlsx", command=lambda: self.ejecutar_run(x3_llm_auto_translate.run), width=self.button_width)
def actualizar_codigo_maestra(event): self.auto_translate_name_button = ttk.Button(self.main_frame, textvariable=self.auto_translate_name_var, command=lambda: self.open_file(self.config.get_auto_translate_path()), width=self.entry_width, style='Excel.TButton')
plc_seleccionado = tipo_PLC_var.get()
if plc_seleccionado == 'Siemens':
# Buscar el índice de 'Italian' en idiomas_lista
indice_italiano = next((i for i, (nombre, _) in enumerate(idiomas_lista) if nombre == 'Italian'), None)
if indice_italiano is not None:
combo_codigo_maestra.current(indice_italiano)
elif plc_seleccionado == 'AllenBradley':
# Buscar el índice de 'English_US' en idiomas_lista
indice_ingles = next((i for i, (nombre, _) in enumerate(idiomas_lista) if nombre == 'English_US'), None)
if indice_ingles is not None:
combo_codigo_maestra.current(indice_ingles)
guardar_configuracion() # Guardar la configuración cuando se cambia el tipo de PLC
# Vincular la función al evento de cambio de selección en combo_tipo_PLC self.paso4 = ttk.Button(self.main_frame, text="4 - Integrar las traducciones al 1_hmi_master_translates", command=lambda: self.ejecutar_run(x4_integrate_translates_to_master.run), width=self.button_width)
combo_tipo_PLC.bind('<<ComboboxSelected>>', actualizar_codigo_maestra)
# Vincular eventos de cambio en los comboboxes para guardar la configuración self.paso4B = ttk.Button(self.main_frame, text="4B - Integrar traducciones manuales al 1_hmi_master_translates", command=lambda: self.ejecutar_run(x4B_integrate_manual_translates_to_master.run), width=self.button_width)
def on_combobox_changed(event):
guardar_configuracion()
combo_codigo_maestra.bind('<<ComboboxSelected>>', on_combobox_changed) self.paso5 = ttk.Button(self.main_frame, text="5 - Completar en 1_hmi_master_translates el idioma seleccionado usando el segundo idioma", command=lambda: self.ejecutar_run(x5_complete_empty_cells_master.run), width=self.button_width)
combo.bind('<<ComboboxSelected>>', on_combobox_changed)
combo2.bind('<<ComboboxSelected>>', on_combobox_changed)
# Clase para redirigir la salida estándar a la caja de texto self.paso6 = ttk.Button(self.main_frame, text="6 - Exportar usando un archivo exportado desde TIA Portal usando 1_hmi_master_translates", command=lambda: self.ejecutar_run(x6_update_from_master.run), width=self.button_width)
class RedirectText(object):
def __init__(self, text_widget):
self.output = text_widget
def write(self, string): self.output_text = tk.Text(self.main_frame, wrap='none', height=20)
self.output.insert(tk.END, string) self.scrollbar_y = ttk.Scrollbar(self.main_frame, orient='vertical', command=self.output_text.yview)
self.output.see(tk.END) # Desplaza hacia el final self.scrollbar_x = ttk.Scrollbar(self.main_frame, orient='horizontal', command=self.output_text.xview)
self.output_text.configure(yscrollcommand=self.scrollbar_y.set, xscrollcommand=self.scrollbar_x.set)
def flush(self): self.clear_button = ttk.Button(self.main_frame, text="Limpiar salida", command=self.clear_output)
pass # No se requiere implementación para flush self.open_log_button = ttk.Button(self.main_frame, text="Abrir Log", command=self.open_log_file)
# Función para obtener el código del idioma seleccionado a partir del nombre def place_widgets(self):
def obtener_codigo_idioma_por_nombre(nombre_idioma): self.main_frame.grid_columnconfigure(0, weight=1)
for nombre, codigo in idiomas_lista: self.main_frame.grid_columnconfigure(1, weight=1)
if nombre == nombre_idioma:
return codigo
return None
# Función para ejecutar las funciones run() y redirigir la salida self.frame_combos.grid(row=0, column=0, columnspan=2, pady=10, sticky='ew')
def ejecutar_run(funcion_run): self.label_tipo_PLC.grid(row=0, column=0, padx=5, pady=5, sticky='e')
# Obtener los parámetros necesarios self.combo_tipo_PLC.grid(row=0, column=1, padx=5, pady=5, sticky='w')
tipo_PLC = tipo_PLC_dict[tipo_PLC_var.get()] self.label_codigo_maestra.grid(row=1, column=0, padx=5, pady=5, sticky='e')
codigo_columna_maestra = obtener_codigo_idioma_por_nombre(codigo_columna_maestra_var.get()) self.combo_codigo_maestra.grid(row=1, column=1, padx=5, pady=5, sticky='w')
codigo_idioma = obtener_codigo_idioma_por_nombre(idioma_var.get()) self.label1.grid(row=0, column=2, padx=5, pady=5, sticky='e')
codigo_idioma2 = obtener_codigo_idioma_por_nombre(idioma_var2.get()) self.combo.grid(row=0, column=3, padx=5, pady=5, sticky='w')
self.label2.grid(row=1, column=2, padx=5, pady=5, sticky='e')
self.combo2.grid(row=1, column=3, padx=5, pady=5, sticky='w')
# Obtener los índices de los idiomas self.work_dir_frame.grid(row=1, column=0, columnspan=2, pady=10, sticky='ew')
indice_seleccionado = idiomas_lista.index((idioma_var.get(), codigo_idioma)) self.work_dir_label.grid(row=0, column=0, padx=5, sticky='w')
indice_seleccionado2 = idiomas_lista.index((idioma_var2.get(), codigo_idioma2)) self.work_dir_entry.grid(row=0, column=1, padx=5, sticky='ew')
self.work_dir_button.grid(row=0, column=2, padx=5, sticky='e')
self.open_explorer_button.grid(row=0, column=3, padx=5, sticky='e')
self.work_dir_frame.grid_columnconfigure(1, weight=1)
# Redirigir stdout current_row = 2
original_stdout = sys.stdout self.paso1.grid(row=current_row, column=0, pady=5, padx=5, sticky='ew')
sys.stdout = RedirectText(output_text) self.master_name_button.grid(row=current_row, column=1, pady=5, padx=5, sticky='ew')
try: current_row += 1
# Ejecutar la función correspondiente self.paso2.grid(row=current_row, column=0, pady=5, padx=5, sticky='ew')
if funcion_run == x1_importar_to_master.run: self.translate_name_button.grid(row=current_row, column=1, pady=5, padx=5, sticky='ew')
print("Ejecutando x1_importar_to_master.run()")
funcion_run(tipo_PLC, codigo_columna_maestra)
elif funcion_run == x2_master_export2translate.run:
print("Ejecutando x2_master_export2translate.run()")
funcion_run(tipo_PLC, codigo_columna_maestra, indice_seleccionado)
elif funcion_run == x3_llm_auto_translate.run:
traducir_todo = messagebox.askyesno("Traducir todo", "¿Desea traducir todas las celdas?")
print("Ejecutando x3_llm_auto_translate.run()")
funcion_run(tipo_PLC, codigo_columna_maestra, indice_seleccionado, traducir_todo)
elif funcion_run == x4_integrate_translates_to_master.run:
print("Ejecutando x4_integrate_translates_to_master.run()")
funcion_run(tipo_PLC, codigo_columna_maestra, indice_seleccionado, 0.5)
elif funcion_run == x5_complete_empty_cells_master.run:
print("Ejecutando x5_complete_empty_cells_master.run()")
funcion_run(tipo_PLC, codigo_columna_maestra, indice_seleccionado, indice_seleccionado2)
elif funcion_run == x6_update_from_master.run:
print("Ejecutando x6_update_from_master.run()")
funcion_run(tipo_PLC, codigo_columna_maestra, indice_seleccionado)
finally:
# Restaurar stdout
sys.stdout = original_stdout
guardar_configuracion() # Guardar el contenido del cuadro de texto
# Crear los botones con el mismo ancho current_row += 1
button_width = 70 self.paso3.grid(row=current_row, column=0, pady=5, padx=5, sticky='ew')
paso1 = tk.Button(ventana, text="1 - Importar al Master", command=lambda: threading.Thread(target=ejecutar_run, args=(x1_importar_to_master.run,)).start(), width=button_width) self.auto_translate_name_button.grid(row=current_row, column=1, pady=5, padx=5, sticky='ew')
paso2 = tk.Button(ventana, text="2 - Exportar Idioma a 2_master_export2translate.xlsx.", command=lambda: threading.Thread(target=ejecutar_run, args=(x2_master_export2translate.run,)).start(), width=button_width)
paso3 = tk.Button(ventana, text="3 - Traducir y generar 3_master_export2translate_translated.xlsx.", command=lambda: threading.Thread(target=ejecutar_run, args=(x3_llm_auto_translate.run,)).start(), width=button_width)
paso4 = tk.Button(ventana, text="4 - Integrar las traducciones al 1_hmi_master_translates.", command=lambda: threading.Thread(target=ejecutar_run, args=(x4_integrate_translates_to_master.run,)).start(), width=button_width)
paso5 = tk.Button(ventana, text="5 - Completar en 1_hmi_master_translates el idioma seleccionado usando el segundo idioma.", command=lambda: threading.Thread(target=ejecutar_run, args=(x5_complete_empty_cells_master.run,)).start(), width=button_width)
paso6 = tk.Button(ventana, text="6 - Exportar usando un archivo exportado desde TIA Portal usando 1_hmi_master_translates.", command=lambda: threading.Thread(target=ejecutar_run, args=(x6_update_from_master.run,)).start(), width=button_width)
# Ubicar los botones en la ventana current_row += 1
paso1.pack(pady=(10,2)) self.paso4.grid(row=current_row, column=0, pady=5, padx=5, sticky='ew')
paso2.pack(pady=2)
paso3.pack(pady=2)
paso4.pack(pady=2)
paso5.pack(pady=2)
paso6.pack(pady=2)
# Crear un Frame para el cuadro de texto, los scrollbars y el botón current_row += 1
frame_texto = tk.Frame(ventana) self.paso4B.grid(row=current_row, column=0, pady=5, padx=5, sticky='ew')
frame_texto.pack(fill='both', expand=True, pady=10)
# Crear los scrollbars current_row += 1
scrollbar_vertical = tk.Scrollbar(frame_texto, orient='vertical') self.paso5.grid(row=current_row, column=0, columnspan=2, pady=5, padx=5, sticky='ew')
scrollbar_horizontal = tk.Scrollbar(frame_texto, orient='horizontal')
# Crear la caja de texto para mostrar la salida current_row += 1
output_text = tk.Text( self.paso6.grid(row=current_row, column=0, columnspan=2, pady=5, padx=5, sticky='ew')
frame_texto,
wrap='none',
yscrollcommand=scrollbar_vertical.set,
xscrollcommand=scrollbar_horizontal.set
)
# Configurar los scrollbars current_row += 1
scrollbar_vertical.config(command=output_text.yview) self.output_text.grid(row=current_row, column=0, columnspan=2, padx=(10, 0), pady=10, sticky='nsew')
scrollbar_horizontal.config(command=output_text.xview) self.scrollbar_y.grid(row=current_row, column=2, pady=10, sticky='ns')
self.scrollbar_x.grid(row=current_row+1, column=0, columnspan=2, padx=10, sticky='ew')
# Crear el botón para borrar el contenido current_row += 2
boton_limpiar = tk.Button(frame_texto, text="Borrar contenido", command=lambda: limpiar_texto()) self.clear_button.grid(row=current_row, column=0, pady=10, padx=5, sticky='e')
self.open_log_button.grid(row=current_row, column=1, pady=10, padx=5, sticky='w')
# Ubicar los widgets en frame_texto usando grid self.main_frame.grid_rowconfigure(current_row-2, weight=1)
output_text.grid(row=0, column=0, sticky='nsew')
scrollbar_vertical.grid(row=0, column=1, sticky='ns')
scrollbar_horizontal.grid(row=1, column=0, sticky='ew')
boton_limpiar.grid(row=1, column=1, padx=5, pady=5)
# Configurar la expansión de filas y columnas def set_combo_value(self, combo, codigo):
frame_texto.grid_rowconfigure(0, weight=1) for nombre, code in fc.IDIOMAS.values():
frame_texto.grid_columnconfigure(0, weight=1) if code == codigo:
combo.set(nombre)
return
for nombre, code in fc.PLCs.values():
if code == codigo:
combo.set(nombre)
return
# Función para borrar el contenido del cuadro de texto def update_tipo_PLC(self, event):
def limpiar_texto(): nombre_seleccionado = self.combo_tipo_PLC.get()
output_text.delete('1.0', tk.END) for nombre, codigo in fc.PLCs.values():
guardar_configuracion() if nombre == nombre_seleccionado:
self.codigo_tipo_PLC_var.set(codigo)
break
self.update_file_names()
# Cargar las opciones guardadas al iniciar def update_codigo_maestra(self, event):
cargar_configuracion() nombre_seleccionado = self.combo_codigo_maestra.get()
for nombre, codigo in fc.IDIOMAS.values():
if nombre == nombre_seleccionado:
self.codigo_columna_maestra_var.set(codigo)
break
self.update_file_names()
# Cargar el contenido del cuadro de texto desde la configuración def update_idioma(self, event):
def cargar_texto(): nombre_seleccionado = self.combo.get()
config = configparser.ConfigParser() for nombre, codigo in fc.IDIOMAS.values():
if os.path.exists(config_file): if nombre == nombre_seleccionado:
config.read(config_file) self.codigo_idioma_var.set(codigo)
texto = config.get('TextContent', 'output_text', fallback='') break
output_text.insert('1.0', texto) self.update_file_names()
cargar_texto() def update_idioma2(self, event):
nombre_seleccionado = self.combo2.get()
for nombre, codigo in fc.IDIOMAS.values():
if nombre == nombre_seleccionado:
self.codigo_idioma_var2.set(codigo)
break
self.update_file_names()
# Guardar la configuración al cerrar la ventana def save_config(self):
def on_closing(): self.config.update(
guardar_configuracion() codigo_tipo_PLC=self.codigo_tipo_PLC_var.get(),
ventana.destroy() codigo_columna_maestra=self.codigo_columna_maestra_var.get(),
codigo_idioma_seleccionado=self.codigo_idioma_var.get(),
codigo_idioma_secundario=self.codigo_idioma_var2.get(),
work_dir=self.work_dir_var.get(),
master_name=self.master_name_var.get(),
translate_name=self.translate_name_var.get(),
auto_translate_name=self.auto_translate_name_var.get(),
)
self.config.save()
ventana.protocol("WM_DELETE_WINDOW", on_closing) def select_work_dir(self):
dir_path = filedialog.askdirectory()
if dir_path:
self.work_dir_var.set(dir_path)
self.save_config()
self.update_file_names()
# Iniciar el bucle principal de la interfaz def open_file(self, file_path):
ventana.mainloop() if os.path.exists(file_path):
os.startfile(file_path)
else:
messagebox.showerror("Error", f"El archivo {file_path} no existe.")
def open_explorer(self):
if os.path.exists(self.config.work_dir):
os.startfile(self.config.work_dir)
else:
messagebox.showerror("Error", f"El directorio {self.config.work_dir} no existe.")
def open_log_file(self):
log_file_path = os.path.join(self.config.work_dir, "logs", "translate_log.log")
if os.path.exists(log_file_path):
os.startfile(log_file_path)
else:
messagebox.showerror("Error", f"El archivo de log {log_file_path} no existe.")
def update_file_names(self, event=None):
codigo_tipo_PLC = self.codigo_tipo_PLC_var.get()
codigo_idioma_seleccionado = self.codigo_idioma_var.get()
self.master_name_var.set(f"1_hmi_master_translates_{codigo_tipo_PLC}.xlsx")
self.translate_name_var.set(f'2_master_export2translate_{codigo_tipo_PLC}_{codigo_idioma_seleccionado}.xlsx')
self.auto_translate_name_var.set(f"3_master_export2translate_translated_{codigo_tipo_PLC}_{codigo_idioma_seleccionado}.xlsx")
self.save_config()
def ejecutar_run(self, funcion_run):
self.save_config()
original_stdout = sys.stdout
sys.stdout = self.RedirectText(self.output_text)
try:
if funcion_run == x1_importar_to_master.run:
funcion_run(self.config)
elif funcion_run == x2_master_export2translate.run:
funcion_run(self.config)
elif funcion_run == x3_llm_auto_translate.run:
traducir_todo = messagebox.askyesno("Traducir todo", "¿Desea traducir todas las celdas?")
self.config.traducir_todo = traducir_todo
funcion_run(self.config)
elif funcion_run == x4_integrate_translates_to_master.run:
funcion_run(self.config)
elif funcion_run == x4B_integrate_manual_translates_to_master.run:
funcion_run(self.config)
elif funcion_run == x5_complete_empty_cells_master.run:
funcion_run(self.config)
elif funcion_run == x6_update_from_master.run:
archivo_to_update = filedialog.askopenfilename(title="Seleccione el archivo a actualizar", filetypes=[("Excel files", "*.xlsx")])
if archivo_to_update:
funcion_run(self.config, archivo_to_update)
except Exception as e:
messagebox.showerror("Error", str(e))
finally:
sys.stdout = original_stdout
self.save_config()
def clear_output(self):
self.output_text.delete('1.0', tk.END)
class RedirectText:
def __init__(self, text_widget):
self.text_widget = text_widget
def write(self, string):
self.text_widget.insert(tk.END, string)
self.text_widget.see(tk.END)
def flush(self):
pass
def main():
root = tk.Tk()
app = TranslationApp(root)
root.mainloop()
if __name__ == "__main__":
main()

12
translation_config.json Normal file
View File

@ -0,0 +1,12 @@
{
"codigo_tipo_PLC": "allenbradley",
"codigo_columna_maestra": "es-ES",
"codigo_idioma_seleccionado": "es-ES",
"codigo_idioma_secundario": "en-US",
"work_dir": "C:/Trabajo/VM/31 - 9.3953 - Omega - Mexico - (ABradley)/Reporte/Languages",
"master_name": "1_hmi_master_translates_allenbradley.xlsx",
"translate_name": "2_master_export2translate_allenbradley_es-ES.xlsx",
"auto_translate_name": "3_master_export2translate_translated_allenbradley_es-ES.xlsx",
"nivel_afinidad_minimo": 0.5,
"traducir_todo": false
}

71
translation_config.py Normal file
View File

@ -0,0 +1,71 @@
from dataclasses import dataclass, asdict
import json
import os
import PyLibrary.funciones_comunes as fc
@dataclass
class TranslationConfig:
codigo_tipo_PLC: str
codigo_columna_maestra: str
codigo_idioma_seleccionado: str
codigo_idioma_secundario: str
work_dir: str
master_name: str
translate_name: str
auto_translate_name: str
nivel_afinidad_minimo: float = 0.5
traducir_todo: bool = False
@classmethod
def load(cls, filename="translation_config.json"):
if os.path.exists(filename):
with open(filename, "r") as f:
data = json.load(f)
return cls(**data)
return cls.default()
def save(self, filename="translation_config.json"):
with open(filename, "w") as f:
json.dump(asdict(self), f, indent=2)
@classmethod
def default(cls):
return cls(
codigo_tipo_PLC="siemens",
codigo_columna_maestra="it-IT",
codigo_idioma_seleccionado="en-GB",
codigo_idioma_secundario="es-ES",
work_dir="",
master_name="1_hmi_master_translates_siemens.xlsx",
translate_name="2_master_export2translate_siemens_en-GB.xlsx",
auto_translate_name="3_master_export2translate_translated_siemens_en-GB.xlsx",
)
def update(self, **kwargs):
for key, value in kwargs.items():
if hasattr(self, key):
setattr(self, key, value)
def get_tipo_PLC_nombre(self) -> str:
return next(nombre for nombre, codigo in fc.PLCs.values() if codigo == self.codigo_tipo_PLC)
def get_idioma_nombre(self, codigo: str) -> str:
return next(nombre for nombre, code in fc.IDIOMAS.values() if code == codigo)
def get_idioma_seleccionado_nombre(self) -> str:
return self.get_idioma_nombre(self.codigo_idioma_seleccionado)
def get_idioma_secundario_nombre(self) -> str:
return self.get_idioma_nombre(self.codigo_idioma_secundario)
def get_full_path(self, filename: str) -> str:
return os.path.join(self.work_dir, filename)
def get_master_path(self) -> str:
return self.get_full_path(self.master_name)
def get_translate_path(self) -> str:
return self.get_full_path(self.translate_name)
def get_auto_translate_path(self) -> str:
return self.get_full_path(self.auto_translate_name)

View File

@ -3,29 +3,39 @@ import os
import re import re
import logging import logging
import PyLibrary.funciones_comunes as fc import PyLibrary.funciones_comunes as fc
from translation_config import TranslationConfig
def preprocesar_importacion(tipo_PLC, codigo_columna_maestra, df_importacion, logger): # Definir el logger a nivel de módulo
logger = None
def preprocesar_importacion(
codigo_tipo_PLC, codigo_columna_maestra, df_importacion, logger
):
filas_validas = [] filas_validas = []
for index, fila in df_importacion.iterrows(): for index, fila in df_importacion.iterrows():
clave_original = fila[codigo_columna_maestra] clave_original = fila[codigo_columna_maestra]
# Verificar si la celda de la columna maestra está vacía o solo contiene espacios en blanco # Verificar si la celda de la columna maestra está vacía o solo contiene espacios en blanco
if pd.isna(clave_original) or str(clave_original).strip() == '': if pd.isna(clave_original) or str(clave_original).strip() == "":
logger.info(f"Fila {index}: Ignorada - Celda de columna maestra vacía o solo con espacios en blanco") logger.info(
f"Fila {index}: Ignorada - Celda de columna maestra vacía o solo con espacios en blanco"
)
continue continue
# Aplicar unescape solo a las filas con valor no vacío en la columna maestra
nueva_fila = fila.copy() nueva_fila = fila.copy()
for col in nueva_fila.index:
nueva_fila[col] = fc.limpiar_caracteres_especiales(str(nueva_fila[col]))
clave_sustituida = fc.compactar_celda_clave(tipo_PLC, str(nueva_fila[codigo_columna_maestra])) clave_sustituida = fc.compactar_celda_clave(
codigo_tipo_PLC, str(nueva_fila[codigo_columna_maestra])
)
nueva_fila[codigo_columna_maestra] = clave_sustituida nueva_fila[codigo_columna_maestra] = clave_sustituida
for columna in df_importacion.columns: for columna in df_importacion.columns:
if columna != codigo_columna_maestra and fc.es_columna_tipo_xxYY(columna): if columna != codigo_columna_maestra and fc.es_columna_tipo_xxYY(columna):
nueva_fila[columna] = fc.compactar_celda_traducida(tipo_PLC, nueva_fila[columna]) nueva_fila[columna] = fc.compactar_celda_traducida(
codigo_tipo_PLC, nueva_fila[columna]
)
filas_validas.append(nueva_fila) filas_validas.append(nueva_fila)
@ -34,30 +44,40 @@ def preprocesar_importacion(tipo_PLC, codigo_columna_maestra, df_importacion, lo
df_valido = pd.DataFrame(filas_validas, columns=df_importacion.columns) df_valido = pd.DataFrame(filas_validas, columns=df_importacion.columns)
return df_valido return df_valido
def importar(tipo_PLC, codigo_columna_maestra, archivo_maestro, archivo_importacion):
logger = fc.configurar_logger() def importar(config: TranslationConfig):
logger.info(" .... ") logger.info(" .... ")
logger.info(f"Iniciando importacion en {archivo_maestro} desde el archivo {archivo_importacion}") logger.info(f"Iniciando importacion en {config.master_name}")
archivo_maestro = os.path.join(config.work_dir, config.master_name)
if not os.path.exists(archivo_maestro): if not os.path.exists(archivo_maestro):
df_maestro = pd.DataFrame(columns=[codigo_columna_maestra]) df_maestro = pd.DataFrame(columns=[config.codigo_columna_maestra])
else: else:
df_maestro = fc.read_dataframe_with_cleanup_retries(archivo_maestro) df_maestro = fc.read_dataframe_with_cleanup_retries(archivo_maestro)
# Aplicar unescape solo a las filas con valor no vacío en la columna maestra
df_importacion = pd.read_excel(archivo_importacion) archivo_importacion = fc.select_file("xlsx")
if not archivo_importacion:
logger.info("No se seleccionó ningún archivo para importar.")
return
df_importacion = preprocesar_importacion(tipo_PLC, codigo_columna_maestra, df_importacion, logger) df_importacion = fc.read_dataframe_with_cleanup_retries(archivo_importacion)
claves_maestro = set(df_maestro[codigo_columna_maestra].dropna().astype(str)) df_importacion = preprocesar_importacion(
config.codigo_tipo_PLC, config.codigo_columna_maestra, df_importacion, logger
)
claves_maestro = set(df_maestro[config.codigo_columna_maestra].dropna().astype(str))
filas_a_agregar = [] filas_a_agregar = []
for index, fila in df_importacion.iterrows(): for index, fila in df_importacion.iterrows():
clave = str(fila[codigo_columna_maestra]) clave = str(fila[config.codigo_columna_maestra])
if clave in claves_maestro: if clave in claves_maestro:
logger.info(f"Fila {index}: Ignorada - Clave '{clave}' ya existe en el archivo maestro") logger.info(
f"Fila {index}: Ignorada - Clave '{clave}' ya existe en el archivo maestro"
)
continue continue
claves_maestro.add(clave) claves_maestro.add(clave)
@ -65,7 +85,7 @@ def importar(tipo_PLC, codigo_columna_maestra, archivo_maestro, archivo_importac
fila_filtrada = { fila_filtrada = {
col: fila[col] col: fila[col]
for col in fila.index for col in fila.index
if col == codigo_columna_maestra or fc.es_columna_tipo_xxYY(col) if col == config.codigo_columna_maestra or fc.es_columna_tipo_xxYY(col)
} }
filas_a_agregar.append(fila_filtrada) filas_a_agregar.append(fila_filtrada)
@ -80,17 +100,25 @@ def importar(tipo_PLC, codigo_columna_maestra, archivo_maestro, archivo_importac
df_nuevas_filas = pd.DataFrame(filas_a_agregar) df_nuevas_filas = pd.DataFrame(filas_a_agregar)
df_maestro = pd.concat([df_maestro, df_nuevas_filas], ignore_index=True) df_maestro = pd.concat([df_maestro, df_nuevas_filas], ignore_index=True)
df_maestro.to_excel(archivo_maestro, index=False) fc.save_dataframe_with_retries(df_maestro, output_path=archivo_maestro)
logger.info(f"Se han agregado {len(filas_a_agregar)} nuevas filas válidas al archivo maestro.") logger.info(
print(f"Se han agregado {len(filas_a_agregar)} nuevas filas válidas al archivo maestro.") f"Se han agregado {len(filas_a_agregar)} nuevas filas válidas al archivo maestro."
)
print(
f"Se han agregado {len(filas_a_agregar)} nuevas filas válidas al archivo maestro."
)
def run(config: TranslationConfig):
global logger
logger = fc.configurar_logger(config.work_dir)
importar(config)
def run(tipo_PLC, codigo_columna_maestra):
archivo_maestro = f".\\data\\1_hmi_master_translates_{tipo_PLC}.xlsx"
archivo_importacion = fc.select_file("xlsx")
if archivo_importacion:
importar(tipo_PLC, codigo_columna_maestra, archivo_maestro, archivo_importacion)
if __name__ == "__main__": if __name__ == "__main__":
tipo_PLC = "siemens" print(
codigo_columna_maestra = "it-IT" "Este script debe ser ejecutado desde el menú principal (menu_pasos_traduccion.py)."
run(tipo_PLC, codigo_columna_maestra) )
print(
"Por favor, ejecute menu_pasos_traduccion.py para utilizar esta funcionalidad."
)

View File

@ -1,15 +1,20 @@
import pandas as pd import pandas as pd
import os import os
import PyLibrary.funciones_comunes as fc import PyLibrary.funciones_comunes as fc
from translation_config import TranslationConfig
# Definir el logger a nivel de módulo
logger = None
def exportar_para_traduccion(tipo_PLC, archivo_maestro, target_lang_code): def exportar_para_traduccion(config: TranslationConfig):
if not os.path.exists(archivo_maestro): master_path = config.get_master_path()
if not os.path.exists(master_path):
print("El archivo maestro no existe.") print("El archivo maestro no existe.")
return return
# Leer el archivo maestro # Leer el archivo maestro
df_maestro = fc.read_dataframe_with_cleanup_retries(archivo_maestro) df_maestro = fc.read_dataframe_with_cleanup_retries(master_path)
# Crear un nuevo DataFrame para la exportación # Crear un nuevo DataFrame para la exportación
df_export = pd.DataFrame() df_export = pd.DataFrame()
@ -17,35 +22,35 @@ def exportar_para_traduccion(tipo_PLC, archivo_maestro, target_lang_code):
# Copiar la primera columna y la columna del idioma de destino # Copiar la primera columna y la columna del idioma de destino
primera_columna = df_maestro.columns[0] primera_columna = df_maestro.columns[0]
df_export[primera_columna] = df_maestro[primera_columna] df_export[primera_columna] = df_maestro[primera_columna]
df_export[target_lang_code] = df_maestro[target_lang_code] df_export[config.codigo_idioma_seleccionado] = df_maestro[
config.codigo_idioma_seleccionado
]
# Guardar el archivo exportado # Guardar el archivo exportado
ruta_export = os.path.join(os.path.dirname(archivo_maestro), f'2_master_export2translate_{tipo_PLC}.xlsx') ruta_export = config.get_translate_path()
# Usar ExcelWriter para tener más control sobre el proceso de escritura # Usar ExcelWriter para tener más control sobre el proceso de escritura
with pd.ExcelWriter(ruta_export, engine='openpyxl') as writer: with pd.ExcelWriter(ruta_export, engine="openpyxl") as writer:
df_export.to_excel(writer, index=False, sheet_name='Sheet1') df_export.to_excel(writer, index=False, sheet_name="Sheet1")
# Ajustar el ancho de las columnas # Ajustar el ancho de las columnas
worksheet = writer.sheets['Sheet1'] worksheet = writer.sheets["Sheet1"]
for idx, col in enumerate(df_export.columns): for idx, col in enumerate(df_export.columns):
max_length = max(df_export[col].astype(str).map(len).max(), len(col)) max_length = max(df_export[col].astype(str).map(len).max(), len(col))
if max_length > 50 : max_length = 50 if max_length > 50:
max_length = 50
worksheet.column_dimensions[chr(65 + idx)].width = max_length + 2 worksheet.column_dimensions[chr(65 + idx)].width = max_length + 2
print(f"Archivo exportado para traducción: {ruta_export}") print(f"Archivo exportado para traducción: {ruta_export}")
def run(tipo_PLC, codigo_columna_maestra, seleccion_idioma):
archivo_maestro = f".\\data\\1_hmi_master_translates_{tipo_PLC}.xlsx" def run(config: TranslationConfig):
if seleccion_idioma not in fc.IDIOMAS: global logger
print("Selección inválida.") logger = fc.configurar_logger(config.work_dir)
else: exportar_para_traduccion(config)
_, target_lang_code = fc.IDIOMAS[seleccion_idioma]
exportar_para_traduccion(tipo_PLC, archivo_maestro, target_lang_code)
if __name__ == "__main__": if __name__ == "__main__":
tipo_PLC = "siemens" import menu_pasos_traduccion
codigo_columna_maestra = "it-IT"
fc.mostrar_idiomas() menu_pasos_traduccion.main()
seleccion_idioma = int(input("Introduce el número del idioma de destino: "))
run(tipo_PLC, codigo_columna_maestra, seleccion_idioma)

View File

@ -12,10 +12,17 @@ import html
from tqdm import tqdm from tqdm import tqdm
import PyLibrary.funciones_comunes as fc import PyLibrary.funciones_comunes as fc
import time import time
import PyLibrary.funciones_comunes as fc
from translation_config import TranslationConfig
from openai import OpenAI
from tqdm import tqdm
openai_client = OpenAI(api_key=openai_api_key()) openai_client = OpenAI(api_key=openai_api_key())
GOOGLE_APPLICATION_CREDENTIALS = "translate-431108-020c17463fbb.json" GOOGLE_APPLICATION_CREDENTIALS = "translate-431108-020c17463fbb.json"
logger = fc.configurar_logger() batch_size = 20
# Definir el logger a nivel de módulo
logger = None
def init_google_translate_client(): def init_google_translate_client():
@ -30,8 +37,10 @@ def init_google_translate_client():
"No se han proporcionado credenciales válidas para Google Translate" "No se han proporcionado credenciales válidas para Google Translate"
) )
google_translate_client = init_google_translate_client() google_translate_client = init_google_translate_client()
def google_translate(text, target_language): def google_translate(text, target_language):
result = google_translate_client.translate(text, target_language=target_language) result = google_translate_client.translate(text, target_language=target_language)
translated_text = result["translatedText"] translated_text = result["translatedText"]
@ -187,27 +196,26 @@ def calcular_afinidad(tipo_PLC, texto1, texto2):
try: try:
score = float(cleaned_response_content) score = float(cleaned_response_content)
except ValueError: except ValueError:
raise ValueError(f"La respuesta no se pudo decodificar como un número: {cleaned_response_content}") raise ValueError(
f"La respuesta no se pudo decodificar como un número: {cleaned_response_content}"
)
return score return score
def main(tipo_PLC, codigo_columna_maestra, file_path, target_lang_code, target_lang, traducir_todo, batch_size=10): def main(config: TranslationConfig):
df = fc.read_dataframe_with_cleanup_retries(file_path) df = fc.read_dataframe_with_cleanup_retries(config.get_translate_path())
source_col = codigo_columna_maestra source_col = config.codigo_columna_maestra
source_translated_col = target_lang_code source_translated_col = config.codigo_idioma_seleccionado
target_col = f"{target_lang_code} Translated" target_col = f"{config.codigo_idioma_seleccionado} Translated"
check_translate_col = f"{target_lang_code} CheckTranslate" check_translate_col = f"{config.codigo_idioma_seleccionado} CheckTranslate"
affinity_col = f"{target_lang_code} Affinity" affinity_col = f"{config.codigo_idioma_seleccionado} Affinity"
# Asegurarse de que la columna de destino existe # Asegurarse de que la columna de destino existe
if target_col not in df.columns: for col in [target_col, check_translate_col, affinity_col]:
df[target_col] = None if col not in df.columns:
if check_translate_col not in df.columns: df[col] = None
df[check_translate_col] = None
if affinity_col not in df.columns:
df[affinity_col] = None
texts_to_translate = {} texts_to_translate = {}
@ -218,18 +226,26 @@ def main(tipo_PLC, codigo_columna_maestra, file_path, target_lang_code, target_l
if source_translated_col in df.columns if source_translated_col in df.columns
else "" else ""
) )
celda_clave_compactada = fc.compactar_celda_traducida(tipo_PLC, celda_clave) celda_clave_compactada = fc.compactar_celda_traducida(
config.codigo_tipo_PLC, celda_clave
)
if traducir_todo: if config.traducir_todo:
if fc.texto_requiere_traduccion(tipo_PLC, celda_clave_compactada, logger): if fc.texto_requiere_traduccion(
df.at[index, source_translated_col] = '' # Necesita ser traducida. config.codigo_tipo_PLC, celda_clave_compactada, logger
):
df.at[index, source_translated_col] = ""
texts_to_translate[celda_clave] = celda_clave_compactada texts_to_translate[celda_clave] = celda_clave_compactada
else: else:
if ( if (
pd.isna(row[source_translated_col]) pd.isna(row[source_translated_col])
or source_translated_text.strip() == "" or source_translated_text.strip() == ""
): ):
if fc.texto_requiere_traduccion(tipo_PLC, celda_clave_compactada, logger) or fc.texto_con_campos_especiales(tipo_PLC, celda_clave_compactada): if fc.texto_requiere_traduccion(
config.codigo_tipo_PLC, celda_clave_compactada, logger
) or fc.texto_con_campos_especiales(
config.codigo_tipo_PLC, celda_clave_compactada
):
texts_to_translate[celda_clave] = celda_clave_compactada texts_to_translate[celda_clave] = celda_clave_compactada
num_texts = len(texts_to_translate) num_texts = len(texts_to_translate)
@ -251,7 +267,9 @@ def main(tipo_PLC, codigo_columna_maestra, file_path, target_lang_code, target_l
for attempt in range(retries): for attempt in range(retries):
try: try:
batch_translations = translate_batch_openai( batch_translations = translate_batch_openai(
batch_texts, fc.idiomas_idiomafromcode(codigo_columna_maestra) , target_lang batch_texts,
fc.idiomas_idiomafromcode(codigo_columna_maestra),
target_lang,
) )
translations.update(batch_translations) translations.update(batch_translations)
break # Si la traducción es exitosa, salimos del bucle de reintentos break # Si la traducción es exitosa, salimos del bucle de reintentos
@ -284,7 +302,10 @@ def main(tipo_PLC, codigo_columna_maestra, file_path, target_lang_code, target_l
df.at[index, target_col] = translations[celda_clave] df.at[index, target_col] = translations[celda_clave]
# Realizar la traducción de verificación con Google Translate # Realizar la traducción de verificación con Google Translate
try: try:
google_translation = google_translate(translations[celda_clave], fc.idiomas_shortcodefromcode(codigo_columna_maestra)) google_translation = google_translate(
translations[celda_clave],
fc.idiomas_shortcodefromcode(codigo_columna_maestra),
)
df.at[index, check_translate_col] = google_translation df.at[index, check_translate_col] = google_translation
except Exception as e: except Exception as e:
logger.error( logger.error(
@ -296,7 +317,7 @@ def main(tipo_PLC, codigo_columna_maestra, file_path, target_lang_code, target_l
# Afinidades # Afinidades
# Se calculan las Afinidades # Se calculan las Afinidades
affinities = {} affinities = {}
for start_idx in range(0, num_texts, batch_size): # num_text for start_idx in range(0, num_texts, batch_size): # num_text
end_idx = min(start_idx + batch_size, num_texts) end_idx = min(start_idx + batch_size, num_texts)
batch_texts = dict(list(texts_to_translate.items())[start_idx:end_idx]) batch_texts = dict(list(texts_to_translate.items())[start_idx:end_idx])
logger.info(f"Afinidad: celdas desde {start_idx} a {end_idx}.") logger.info(f"Afinidad: celdas desde {start_idx} a {end_idx}.")
@ -338,37 +359,25 @@ def main(tipo_PLC, codigo_columna_maestra, file_path, target_lang_code, target_l
f"Error en el cálculo individual de Afinidad para el texto '{key}': {ind_e}" f"Error en el cálculo individual de Afinidad para el texto '{key}': {ind_e}"
) )
# Actualizar el DataFrame con las Afinidades # Actualizar el DataFrame con las Afinidades
for index, row in df.iterrows(): for index, row in df.iterrows():
celda_clave = str(row[source_col]) celda_clave = str(row[source_col])
if celda_clave in affinities: if celda_clave in affinities:
df.at[index, affinity_col] = affinities[celda_clave] df.at[index, affinity_col] = affinities[celda_clave]
output_path = os.path.join( output_path = config.get_auto_translate_path()
os.path.dirname(file_path), f"3_master_export2translate_translated_{tipo_PLC}.xlsx"
)
fc.save_dataframe_with_retries(df, output_path=output_path) fc.save_dataframe_with_retries(df, output_path=output_path)
logger.info(f"Archivo traducido guardado en: {output_path}") logger.info(f"Archivo traducido guardado en: {output_path}")
print(f"Archivo traducido guardado en: {output_path}") print(f"Archivo traducido guardado en: {output_path}")
def run(tipo_PLC, codigo_columna_maestra, seleccion_idioma, traducir_todo):
batch_size = 20
translate_file = f".\\data\\2_master_export2translate_{tipo_PLC}.xlsx"
if seleccion_idioma not in fc.IDIOMAS: def run(config: TranslationConfig):
print("Selección inválida.") global logger
else: logger = fc.configurar_logger(config.work_dir)
target_lang, target_lang_code = fc.IDIOMAS[seleccion_idioma] main(config)
main(tipo_PLC, codigo_columna_maestra, translate_file, target_lang_code, target_lang, traducir_todo, batch_size)
if __name__ == "__main__": if __name__ == "__main__":
tipo_PLC = "siemens" import menu_pasos_traduccion
codigo_columna_maestra = "it-IT"
fc.mostrar_idiomas() menu_pasos_traduccion.main()
seleccion_idioma = int(input("Introduce el número del idioma de destino: "))
traducir_todo = (
input("¿Desea traducir todas las celdas (s/n)? ").strip().lower() == "s"
)
tipo_PLC = "siemens"
run(tipo_PLC, codigo_columna_maestra, seleccion_idioma, traducir_todo)

View File

@ -0,0 +1,122 @@
import PyLibrary.funciones_comunes as fc
import pandas as pd
import os
from translation_config import TranslationConfig
from openpyxl import load_workbook
from openpyxl.styles import Font
from openpyxl.comments import Comment
# Definir el logger a nivel de módulo
logger = None
def importar_traduccion_manual(config: TranslationConfig):
archivo_maestro = config.get_master_path()
if not os.path.exists(archivo_maestro):
print("El archivo maestro no existe.")
return
archivo_traduccion = config.get_translate_path()
master_col = config.codigo_idioma_seleccionado
df_maestro = fc.read_dataframe_with_cleanup_retries(archivo_maestro)
df_traduccion = fc.read_dataframe_with_cleanup_retries(archivo_traduccion)
celdas_modificadas = {}
celdas_con_errores = {}
for index, fila in df_traduccion.iterrows():
clave = fila[df_maestro.columns[0]]
if clave in df_maestro[df_maestro.columns[0]].values:
valor_traducido = fila[master_col]
valor_original = df_maestro.loc[
df_maestro[df_maestro.columns[0]] == clave, master_col
].values[0]
if (
pd.notnull(valor_traducido)
and valor_traducido != ""
and str(valor_original) != str(valor_traducido)
):
okToSave, Error = fc.verificar_celda_traducida(
config.codigo_tipo_PLC, clave, valor_traducido
)
if okToSave:
df_maestro.loc[
df_maestro[df_maestro.columns[0]] == clave, master_col
] = valor_traducido
logger.info(
f'Fila {index}, Columna {master_col}: "{valor_original}" actualizado a "{valor_traducido}"'
)
fila_excel = (
df_maestro.index[
df_maestro[df_maestro.columns[0]] == clave
].tolist()[0]
+ 2
)
columna_excel = df_maestro.columns.get_loc(master_col) + 1
celdas_modificadas[(fila_excel, columna_excel)] = valor_traducido
else:
logger.error(
f"Fila {index}, Columna {master_col}: No actualizado porque: {Error}"
)
fila_excel = index + 2
columna_excel = df_traduccion.columns.get_loc(master_col) + 1
celdas_con_errores[(fila_excel, columna_excel)] = Error
fc.save_dataframe_with_retries(df_maestro, output_path=archivo_maestro)
aplicar_formato_celdas_maestro(archivo_maestro, celdas_modificadas)
marcar_errores_archivo_fuente(archivo_traduccion, celdas_con_errores)
print(
f"Traducciones manuales importadas y archivo maestro actualizado: {archivo_maestro}."
)
print(
f"Se han actualizado {len(celdas_modificadas)} celdas en el maestro y se han encontrado {len(celdas_con_errores)} errores en el archivo fuente."
)
def aplicar_formato_celdas_maestro(archivo, celdas_modificadas):
workbook = load_workbook(archivo)
sheet = workbook.active
for (fila, columna), valor in celdas_modificadas.items():
celda = sheet.cell(row=fila, column=columna)
celda.font = Font(bold=True)
celda.value = valor
workbook.save(archivo)
print(
f"Se han formateado {len(celdas_modificadas)} celdas modificadas en negrita en el archivo maestro."
)
def marcar_errores_archivo_fuente(archivo, celdas_con_errores):
workbook = load_workbook(archivo)
sheet = workbook.active
for (fila, columna), mensaje_error in celdas_con_errores.items():
celda = sheet.cell(row=fila, column=columna)
celda.font = Font(color="FF0000") # Texto en rojo
comment = Comment(mensaje_error, "Sistema de Traducción")
celda.comment = comment
workbook.save(archivo)
print(
f"Se han marcado {len(celdas_con_errores)} celdas con errores en rojo en el archivo fuente."
)
def run(config: TranslationConfig):
global logger
logger = fc.configurar_logger(config.work_dir)
importar_traduccion_manual(config)
if __name__ == "__main__":
import menu_pasos_traduccion
menu_pasos_traduccion.main()

View File

@ -1,67 +1,90 @@
import PyLibrary.funciones_comunes as fc import PyLibrary.funciones_comunes as fc
import pandas as pd import pandas as pd
import os import os
import re from translation_config import TranslationConfig
import logging from openpyxl import load_workbook
from openpyxl.styles import Font
def revertir_transformaciones(texto, digitos, secciones): # Definir el logger a nivel de módulo
# Revertir <> a [[digits]] logger = None
for digito in digitos:
texto = texto.replace('<>', digito, 1)
# Revertir <#> a <...> usando las secciones originales
for seccion in secciones:
texto = texto.replace('<#>', f'<{seccion}>', 1)
return texto
def importar_traduccion(tipo_PLC, archivo_maestro, archivo_traduccion, target_lang_code, nivel_afinidad_minimo):
def importar_traduccion(config: TranslationConfig):
archivo_maestro = config.get_master_path()
if not os.path.exists(archivo_maestro): if not os.path.exists(archivo_maestro):
print("El archivo maestro no existe.") print("El archivo maestro no existe.")
return return
master_col = target_lang_code master_col = config.codigo_idioma_seleccionado
translated_col = f"{target_lang_code} Translated" translated_col = f"{config.codigo_idioma_seleccionado} Translated"
affinity_col = f"{target_lang_code} Affinity" affinity_col = f"{config.codigo_idioma_seleccionado} Affinity"
df_maestro = fc.read_dataframe_with_cleanup_retries(archivo_maestro) df_maestro = fc.read_dataframe_with_cleanup_retries(archivo_maestro)
df_traduccion = fc.read_dataframe_with_cleanup_retries(archivo_traduccion) df_traduccion = fc.read_dataframe_with_cleanup_retries(
config.get_auto_translate_path()
)
# Configurar el logger celdas_modificadas = {}
logger = fc.configurar_logger()
# Iterar sobre las filas del archivo de traducción para actualizar el maestro
for index, fila in df_traduccion.iterrows(): for index, fila in df_traduccion.iterrows():
clave = fila[df_maestro.columns[0]] clave = fila[df_maestro.columns[0]]
if clave in df_maestro[df_maestro.columns[0]].values: if clave in df_maestro[df_maestro.columns[0]].values:
# Comprobar afinidad y valores no nulos/vacíos if (
if fila[affinity_col] >= nivel_afinidad_minimo and pd.notnull(fila[translated_col]) and fila[translated_col] != "": fila[affinity_col] >= config.nivel_afinidad_minimo
and pd.notnull(fila[translated_col])
and fila[translated_col] != ""
):
valor_traducido = fila[translated_col] valor_traducido = fila[translated_col]
valor_original = df_maestro.loc[df_maestro[df_maestro.columns[0]] == clave, master_col].values[0] valor_original = df_maestro.loc[
df_maestro[df_maestro.columns[0]] == clave, master_col
].values[0]
if str(valor_original) != str(valor_traducido): if str(valor_original) != str(valor_traducido):
df_maestro.loc[df_maestro[df_maestro.columns[0]] == clave, master_col] = valor_traducido df_maestro.loc[
logger.info(f'Fila {index}, Columna {translated_col}: "{valor_original}" actualizado a "{valor_traducido}"') df_maestro[df_maestro.columns[0]] == clave, master_col
] = valor_traducido
logger.info(
f'Fila {index}, Columna {translated_col}: "{valor_original}" actualizado a "{valor_traducido}"'
)
fila_excel = (
df_maestro.index[
df_maestro[df_maestro.columns[0]] == clave
].tolist()[0]
+ 2
)
columna_excel = df_maestro.columns.get_loc(master_col) + 1
celdas_modificadas[(fila_excel, columna_excel)] = valor_traducido
fc.save_dataframe_with_retries(df_maestro, output_path=archivo_maestro)
aplicar_negrita_celdas_modificadas(archivo_maestro, celdas_modificadas)
# Guardar el archivo maestro actualizado
fc.save_dataframe_with_retries(df_maestro,output_path=archivo_maestro)
print(f"Traducciones importadas y archivo maestro actualizado: {archivo_maestro}.") print(f"Traducciones importadas y archivo maestro actualizado: {archivo_maestro}.")
def run(tipo_PLC, codigo_columna_maestra, seleccion_idioma , nivel_afinidad_minimo):
archivo_maestro = f".\\data\\1_hmi_master_translates_{tipo_PLC}.xlsx"
archivo_traduccion = f".\\data\\3_master_export2translate_translated_{tipo_PLC}.xlsx"
if seleccion_idioma not in fc.IDIOMAS: def aplicar_negrita_celdas_modificadas(archivo, celdas_modificadas):
print("Selección inválida.") workbook = load_workbook(archivo)
else: sheet = workbook.active
target_lang, target_lang_code = fc.IDIOMAS[seleccion_idioma]
importar_traduccion(tipo_PLC, archivo_maestro, archivo_traduccion, target_lang_code, nivel_afinidad_minimo ) for (fila, columna), valor in celdas_modificadas.items():
celda = sheet.cell(row=fila, column=columna)
celda.font = Font(bold=True)
celda.value = valor
workbook.save(archivo)
print(
f"Se han marcado en negrita {len(celdas_modificadas)} celdas modificadas en {archivo}."
)
def run(config: TranslationConfig):
global logger
logger = fc.configurar_logger(config.work_dir)
importar_traduccion(config)
if __name__ == "__main__": if __name__ == "__main__":
tipo_PLC = "siemens" import menu_pasos_traduccion
codigo_columna_maestra = "it-IT"
nivel_afinidad_minimo = input("Introduce el nivel minimo de afinidad para importar (presiona Enter para usar el valor por defecto 0.5): ")
nivel_afinidad_minimo = float(nivel_afinidad_minimo) if nivel_afinidad_minimo else 0.5
fc.mostrar_idiomas() menu_pasos_traduccion.main()
seleccion_idioma = int(input("Introduce el número del idioma de destino: "))
run(tipo_PLC, codigo_columna_maestra, seleccion_idioma, nivel_afinidad_minimo)

View File

@ -1,80 +1,54 @@
import PyLibrary.funciones_comunes as fc import PyLibrary.funciones_comunes as fc
import pandas as pd import pandas as pd
import os import os
import re from translation_config import TranslationConfig
import logging
from openpyxl.utils.escape import unescape
def complete_emptys(tipo_PLC,codigo_columna_maestra, archivo_maestro, target_lang_code, second_lang_code): # Definir el logger a nivel de módulo
logger = None
def complete_emptys(config: TranslationConfig):
archivo_maestro = config.get_master_path()
if not os.path.exists(archivo_maestro): if not os.path.exists(archivo_maestro):
print("El archivo maestro no existe.") print("El archivo maestro no existe.")
return return
target_col = target_lang_code target_col = config.codigo_idioma_seleccionado
second_col = second_lang_code second_col = config.codigo_idioma_secundario
df_maestro = fc.read_dataframe_with_cleanup_retries(archivo_maestro) df_maestro = fc.read_dataframe_with_cleanup_retries(archivo_maestro)
# Configurar el logger
logger = fc.configurar_logger()
# Iterar sobre las filas del archivo de traducción para actualizar el maestro
for index, fila in df_maestro.iterrows(): for index, fila in df_maestro.iterrows():
clave = fila[codigo_columna_maestra] clave = fila[config.codigo_columna_maestra]
if fila[target_col] == "" or pd.isnull(fila[target_col]): if fila[target_col] == "" or pd.isnull(fila[target_col]):
if pd.notnull(fila[second_col]) and fila[second_col] != "": if pd.notnull(fila[second_col]) and fila[second_col] != "":
df_maestro.loc[ df_maestro.loc[
df_maestro[codigo_columna_maestra] == clave, target_col df_maestro[config.codigo_columna_maestra] == clave, target_col
] = fila[second_col] ] = fila[second_col]
logger.info( logger.info(
f'Fila {index}, Columna {target_col}: " actualizado a "{fila[second_col]}"' f'Fila {index}, Columna {target_col}: "" actualizado a "{fila[second_col]}"'
) )
else: else:
df_maestro.loc[ df_maestro.loc[
df_maestro[codigo_columna_maestra] == clave, target_col df_maestro[config.codigo_columna_maestra] == clave, target_col
] = fc.compactar_celda_traducida(tipo_PLC, fila[codigo_columna_maestra]) ] = fc.compactar_celda_traducida(
config.codigo_tipo_PLC, fila[config.codigo_columna_maestra]
)
logger.info( logger.info(
f'Fila {index}, Columna {target_col}: " actualizado a "{fila[codigo_columna_maestra]}"' f'Fila {index}, Columna {target_col}: "" actualizado a "{fila[config.codigo_columna_maestra]}"'
) )
# Guardar el archivo maestro actualizado fc.save_dataframe_with_retries(df_maestro, output_path=archivo_maestro)
fc.save_dataframe_with_retries( print(f"Traducciones importadas y archivo maestro actualizado: {archivo_maestro}.")
df_maestro, output_path=archivo_maestro
)
print(
f"Traducciones importadas y archivo maestro actualizado: {archivo_maestro}."
)
def run(tipo_PLC, codigo_columna_maestra, seleccion_idioma, seleccion_idioma_secundario):
archivo_maestro = f".\\data\\1_hmi_master_translates_{tipo_PLC}.xlsx"
if seleccion_idioma not in fc.IDIOMAS: def run(config: TranslationConfig):
print("Selección inválida.") global logger
exit logger = fc.configurar_logger(config.work_dir)
complete_emptys(config)
if seleccion_idioma_secundario not in fc.IDIOMAS:
print("Selección inválida.")
exit
_, target_lang_code = fc.IDIOMAS[seleccion_idioma]
_, second_lang_code = fc.IDIOMAS[seleccion_idioma_secundario]
complete_emptys(tipo_PLC, codigo_columna_maestra, archivo_maestro, target_lang_code, second_lang_code)
if __name__ == "__main__": if __name__ == "__main__":
tipo_PLC = "siemens" import menu_pasos_traduccion
codigo_columna_maestra = "it-IT"
fc.mostrar_idiomas()
seleccion_idioma = int(input("Introduce el número del idioma de destino: "))
if seleccion_idioma not in fc.IDIOMAS:
print("Selección inválida.")
exit
seleccion_idioma_secundario = int(
input(
"Introduce el número del idioma de secundario para copiar desde en caso de vacios: "
)
)
if seleccion_idioma_secundario not in fc.IDIOMAS:
print("Selección inválida.")
exit
run(tipo_PLC, codigo_columna_maestra, seleccion_idioma, seleccion_idioma_secundario)
menu_pasos_traduccion.main()

View File

@ -1,88 +1,124 @@
import pandas as pd import pandas as pd
import os import os
import re
import logging
import PyLibrary.funciones_comunes as fc import PyLibrary.funciones_comunes as fc
from openpyxl.utils.escape import unescape from translation_config import TranslationConfig
from openpyxl import load_workbook
from openpyxl.styles import Font
from openpyxl.comments import Comment
def update_from_master(tipo_PLC, codigo_columna_maestra, archivo_maestro, archivo_to_update, target_lang_code): # Definir el logger a nivel de módulo
logger = None
def update_from_master(config: TranslationConfig, archivo_to_update):
archivo_maestro = config.get_master_path()
if not os.path.exists(archivo_maestro): if not os.path.exists(archivo_maestro):
print("El archivo maestro no existe.") print("El archivo maestro no existe.")
return return
# Configurar el logger
logger = fc.configurar_logger()
logger.info(" .... ") logger.info(" .... ")
logger.info( logger.info(
f"Iniciando actualizacion en {archivo_to_update} desde el archivo maestro. Para {target_lang_code} " f"Iniciando actualización en {archivo_to_update} desde el archivo maestro. Para {config.codigo_idioma_seleccionado}"
) )
df_maestro = fc.read_dataframe_with_cleanup_retries(archivo_maestro) df_maestro = fc.read_dataframe_with_cleanup_retries(archivo_maestro)
df_to_update = fc.read_dataframe_with_cleanup_retries(archivo_to_update) df_to_update = fc.read_dataframe_with_cleanup_retries(archivo_to_update)
col_clave = codigo_columna_maestra col_clave = config.codigo_columna_maestra
celdas_con_errores = {}
# Iterar sobre las filas del archivo de actualización para actualizarlas
for index, fila in df_to_update.iterrows(): for index, fila in df_to_update.iterrows():
valor_original = fila[col_clave] valor_original = fila[col_clave]
clave = fc.compactar_celda_clave(tipo_PLC, valor_original) clave = fc.compactar_celda_clave(config.codigo_tipo_PLC, valor_original)
logger.info( logger.info(f"Fila {index} : Clave: {clave}")
f'Fila {index} : Clave: {clave}'
)
if not pd.isnull(clave) and clave in df_maestro[col_clave].values: if not pd.isnull(clave) and clave in df_maestro[col_clave].values:
# Obtenemos los valores indice_maestro = df_maestro.index[df_maestro[col_clave] == clave].tolist()[
0
]
valor_traducido_compacto = df_maestro.loc[ valor_traducido_compacto = df_maestro.loc[
df_maestro[col_clave] == clave, target_lang_code indice_maestro, config.codigo_idioma_seleccionado
].values[0] ]
# Descompactamos
valor_traducido = fc.decompactar_celda_traducida(tipo_PLC, valor_traducido = fc.decompactar_celda_traducida(
celda_original=valor_original, celda_traducida=valor_traducido_compacto config.codigo_tipo_PLC,
celda_original=valor_original,
celda_traducida=valor_traducido_compacto,
) )
if ( if (
not pd.isnull(valor_traducido) not pd.isnull(valor_traducido)
and fila[target_lang_code] != valor_traducido and fila[config.codigo_idioma_seleccionado] != valor_traducido
): ):
# Salvamos en el file to Update okToSave, Error = fc.verificar_celda_traducida(
okToSave, Error = fc.verificar_celda_traducida(tipo_PLC, config.codigo_tipo_PLC, clave, valor_traducido_compacto
clave, valor_traducido_compacto
) )
if okToSave: if okToSave:
logger.info("Actualizado.") logger.info("Actualizado.")
df_to_update.at[index, target_lang_code] = valor_traducido df_to_update.at[index, config.codigo_idioma_seleccionado] = (
else: valor_traducido
df_to_update.at[index, target_lang_code] = valor_original
logger.error(
f'No actualizado porque: {Error}'
) )
else:
df_to_update.at[index, config.codigo_idioma_seleccionado] = (
valor_original
)
logger.error(f"No actualizado porque: {Error}")
celdas_con_errores[indice_maestro] = Error
# Guardar el archivo actualizado
nombre, extension = os.path.splitext(archivo_to_update) nombre, extension = os.path.splitext(archivo_to_update)
nuevo_nombre = f"{nombre}_import{extension}" nuevo_nombre = f"{nombre}_import{extension}"
fc.save_dataframe_with_retries(df_to_update, output_path=nuevo_nombre) fc.save_dataframe_with_retries(df_to_update, output_path=nuevo_nombre)
marcar_celdas_con_errores(
archivo_maestro, celdas_con_errores, config.codigo_idioma_seleccionado
)
print( print(
f"Se han actualizado las filas en {archivo_to_update} desde el archivo maestro. " f"Se han actualizado las filas en {archivo_to_update} desde el archivo maestro. "
f"Se han marcado {len(celdas_con_errores)} celdas con errores en el archivo maestro."
) )
logger.info( logger.info(
f"Se han actualizado las filas en {archivo_to_update} desde el archivo maestro. " f"Se han actualizado las filas en {archivo_to_update} desde el archivo maestro. "
f"Se han marcado {len(celdas_con_errores)} celdas con errores en el archivo maestro."
) )
logger.info(" .... ") logger.info(" .... ")
def run(tipo_PLC, codigo_columna_maestra, seleccion_idioma) :
archivo_maestro = f".\\data\\1_hmi_master_translates_{tipo_PLC}.xlsx" def marcar_celdas_con_errores(archivo_maestro, celdas_con_errores, target_lang_code):
workbook = load_workbook(archivo_maestro)
sheet = workbook.active
for col in range(1, sheet.max_column + 1):
if sheet.cell(row=1, column=col).value == target_lang_code:
target_col = col
break
else:
print(f"No se encontró la columna para el idioma {target_lang_code}")
return
for indice_maestro, mensaje_error in celdas_con_errores.items():
row = indice_maestro + 2
cell = sheet.cell(row=row, column=target_col)
cell.font = Font(color="FF0000")
comment = Comment(mensaje_error, "Sistema de Traducción")
cell.comment = comment
workbook.save(archivo_maestro)
print(
f"Se han marcado {len(celdas_con_errores)} celdas con errores en rojo en el archivo maestro {archivo_maestro}"
)
def run(config: TranslationConfig):
global logger
logger = fc.configurar_logger(config.work_dir)
archivo_to_update = fc.select_file("xlsx") archivo_to_update = fc.select_file("xlsx")
if archivo_to_update: if archivo_to_update:
if seleccion_idioma not in fc.IDIOMAS: update_from_master(config, archivo_to_update)
print("Selección inválida.")
else:
_, target_lang_code = fc.IDIOMAS[seleccion_idioma]
update_from_master(tipo_PLC, codigo_columna_maestra, archivo_maestro, archivo_to_update, target_lang_code)
if __name__ == "__main__": if __name__ == "__main__":
tipo_PLC = "siemens" import menu_pasos_traduccion
codigo_columna_maestra = "it-IT"
fc.mostrar_idiomas() menu_pasos_traduccion.main()
seleccion_idioma = int(input("Introduce el número del idioma de destino: "))
run(tipo_PLC, codigo_columna_maestra)