From 3e2def4743b975be5c61fcf37c88a5540a71fd5c Mon Sep 17 00:00:00 2001 From: Miguel Date: Mon, 14 Oct 2024 15:47:49 +0200 Subject: [PATCH] Mejorados en el menu y la creacion de ProgressBar --- .../menu_pasos_traduccion.cpython-310.pyc | Bin 12616 -> 14682 bytes .../x1_importar_to_master.cpython-310.pyc | Bin 3074 -> 3270 bytes ...x2_master_export2translate.cpython-310.pyc | Bin 1551 -> 4063 bytes .../x3_llm_auto_translate.cpython-310.pyc | Bin 9345 -> 9620 bytes ...anual_translates_to_master.cpython-310.pyc | Bin 3258 -> 3355 bytes ...grate_translates_to_master.cpython-310.pyc | Bin 2423 -> 2588 bytes ...omplete_empty_cells_master.cpython-310.pyc | Bin 1593 -> 1690 bytes .../x6_update_from_master.cpython-310.pyc | Bin 3159 -> 3225 bytes menu_pasos_traduccion.py | 438 +++++++++++++----- translation_config.json | 2 +- x1_importar_to_master.py | 42 +- x2_master_export2translate.py | 144 +++++- x3_llm_auto_translate.py | 72 +-- x4B_integrate_manual_translates_to_master.py | 2 + x4_integrate_translates_to_master.py | 6 + x5_complete_empty_cells_master.py | 2 + x6_update_from_master.py | 5 +- 17 files changed, 525 insertions(+), 188 deletions(-) diff --git a/__pycache__/menu_pasos_traduccion.cpython-310.pyc b/__pycache__/menu_pasos_traduccion.cpython-310.pyc index 4716be23cd3a63df8f058821872b219e1431546e..a4243fc144ec97cdfbbb4fc92c72535b1ee94222 100644 GIT binary patch literal 14682 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 delta 1728 zcmZuxL5mzk6t1eS?&SK;kASi2((pVG+%$3}si(*pr^= zNp;PVgla}yCF>zzXu*R7dQQ=sCk0O$!Ha)D`lL7U>P^J>swXi9?51D8diCnPs`tIG zer$fQT#sut7r}FfyS?A$?$mczf;nE@!5G2c(|?XP%dcI#^VQnK1791y^YA4ur*nsiiE1n<%YFoD)@<;$&4Cs=7{nkdqDAkk9lDp%pFhIkd+L7(DMt11MJZWB$3 z{%@dbXB5pnW$P6GNlKLism;6QEVab_nu25W9d6wwX;oD>QM+=fK!2JS!-%!UFT+XC zv|j3Er^p!Bv-{-eA?nAY8wKh5#gZQnM$DH?bo?OVtm8*)I}ld3V4U@w3rw<$f(?SU zm-)u!?7ndsuV#z1yR{BMsnH-dUNI9qfhgS!T`Y2((XIEsPFbLH*VvU3{6>uy1-mY zK&x>InxTy3v_v`PWnDPhM5Px1lu}uT^>aFgq7v;;urw6W<0i`Irzl^Ld!~2?rzW(7 zrRXGIEPLW4^hD)jEcfi*?yM=DyF5wP$ zKeTsofA0n83Frtb-=~}szAMT~J}o0v^;mCP(f(u^`lOM%aDrypANQbRNPl@7i+da? zQg+8@(#|0ioUaNMS^;adN4Upp&;?MJ{wi27uiqvZl?mqLer4@o*l1(cw($B&wjN|VVa$(d~|*ljBP_K!B5n+XlMf|$oh%G@Z;!9A`WVE zQw!}Z_Jb(g4IcVZH`}?_Gh%;l9~Araq?i3KO^5*0NbOu z*9(L=1}kSs=nQQ<1FyvGF?fcUjE5tbPbdfvb}gO*rLa3tzHr#-j5lHUVj_c9;)`%3 zTReCd^gy(Ne&CNK<1v^L9<+j}H3)`3eB08<_~D2}tu-)=J0q6FNk+MEijo6R_ zWM#`8&3>=G0C(bX@4%pJM}0>LU5S4WIE34;(-F^V+vBo4u8qAhi1|1Q&S^lB!ys$~ b7azPHywtFb`r-QXwnZ>0FG&KIBK_+h4g{er diff --git a/__pycache__/x2_master_export2translate.cpython-310.pyc b/__pycache__/x2_master_export2translate.cpython-310.pyc index a8f9a64b69ee1ee7c6c834770c55c7716edf9100..ae0cef5bdafd91cb5ef76fb00ce48e6acdc96c79 100644 GIT binary patch literal 4063 zcmcgv&5s;M74NUWfCh$gT#U@2*@^uwbxcGIgZ6fGHKarwWn%!d)?DL zuB!2VsOPl4ftA2DMA}tO91$E)PDuF&IG4nUlkc1&A@h4RGwV-~;Xt>#>$6|gd%suj z{W`DLD;BQNQhohbihUwke&^F{K;2ru0J3l%;_m&e=5A zNrOQ-EStKWR>BJU+_XBVg*DUXrS(B0Yz&%V6Ky+gu@dtiTj4yLV*$!GE3*p9Bdp5H zeTUUp{jnD=Oj`}sMC&L&###>?@k_JzVz|f`_m3Y~ByY_;-T9~3xpk{+>-kSaoXIp+ zNuFKJvwpIU&U%{1EZWM&gZp{@pzG-B?N});vg=8j>hemOtY-tBsUAt0T{bFYnX7o@ zdw4OMIgc%6ZQA?JfwgMw*<(w&`(9xk*re;4)pc+6=(E{HpO^5g;gM(XTDJ=8UiGds zw#QE4?Bk;Yo7qd&Z=8n?K6kYJJwXDn=aL+ziR!xAS^j~xBklEa#(!^#Du%!PkX^WY zTjV>ur*e6BttXP9LYZ)AA@6?p(T&c`4E*l)`DhSJXdChEVJ_5pHMJ059`5MMr8JSM zmk)-QTeM3DuQS%}_j|^6BN2;;aYgHhC}BwsQOlRoycehPGAgrgyCv=PdwTB1>Wz;- zT3OTnqc|OLsr@w0))N-iC07yENAWtBT{~<*on$?iQ=vw!$*YDP=#&3p{U+_x!)w8A z*rJU}k9Iw~$lyL6gWDBUl(lacHc)cLjv}+W2f&Wm4=mAQF#B#rdHbcpIj{kYJN63q z4iK}={V6=$;QExX)N`ZkL6&c2U0*b)T~Cw2FoBH}-&VPHQ=S1h1vtb!#>1eO#!@Ez z9oVNdnG>jFm`As7Uez_z5g8G=_9xaAWqkLlHJTF$u+C)C0_I49t7f-s&vsx3-`wI9 zI$v`^vX!yMcTsunzxV2gj_8sPi*{i<(0a{!SfZ2Fb#8^#RW1QV-b+~C^^DSj>@R3_ zU6CplN^T`;qw9vX38YaEP6mCld~jcI?N54NRq1GcU-1l1Ihi(9>>Wsz6s+2I#SU!e zndgWOtpq7_mS0khtPtQas{Ic56xP0VV2y2MZvy1PKCop=dCcCM9#2);gL=x}pQAB2 zL$F`Qe7A5mE6iE40KHRqOIG0)-X#llYqM%vC@&$b6)vNGYrlrCN-Ef_7bOa3Pn^#_ z8~cU3*(iJpYpndlwXMS6Y>wyfZm|He12xYotjcOnoN<}eSFL;Pais`~$`V4!z0$Z^ zl#6QAet3^HieU2y^+yX2?_jq_X&=~cO&w!R+$}c$#2wc$Ymv2&TjPfEH;)$$c7!dk zqZnzbC3b8wx@he=kp81_3+)p{iydQ&Pn^w@_k!e!urx7Y|uJ6El*MT1|0wKf5P#%{{xN-FW~6UaQxhUxbh;BXkYv< zusr>5vHajoSblDcuU+=eNhxq{cJ1c28eRJF)0( zB#-jWAm)gZc_+&|d>dJWFPp@tt*~{&q?u^dq@9@MI>?7S8}4kUNQ*v4KFRoX?XPWc zuFfH6mXeI|Z3H9gh_ZOVKhdtrhZrhviFjy&vko3{p%UaR%CalkzVh@uVn^t&tgim# z+6Rc*d73b!+p39a2x4h2beU&tR_%i;L~3WqpHhb2ok#xdaT#YU?_emF7j)$+(rC&R z_KZdRq2T>wTl;dv zdcEYEKV}y?yBBZ9veV-!qax2bla$a&GQ?d$iMq29XB~-v4I_(QO!IiwiFZfo^5|nM zv&J!_6MyrEn9(Gj0t5=x9fs;u+BD%{xHmE?a@k=?p9`?0$wV%P9Q(?bcgwKEy5KUu z&^@c0>%d^jH-@p=&`vJ3XKKCyTI$kJB$+aady+-Z3J!Y4ViorV(2FRaM7@;9*=QIE zj&uqp;S8BBuVT)1nxp3?7L@wLH0w+@9!Z{Zm@3c6aoV(*L%I{0T~x1a!+3W@0!E|* zm4g+btvzCfz>0iG3gQsD9M5>6o}a81v4jW~q(h6Xgh9Qf$+|L<8%TTD3-613K&7Cx ztLFysc0`a@r&f|zVxdc*VCx*5j)Q-e3|BI#TQ{fL9Fhc&+-{l!M?=^M8MU8eiQLd- zKrV>!sqTV!7mJ0}7Y$!weE?xjSy)DW;#6T1)*k>la%;F?99G3h#nVykZ%qv|Bg;5K zpv}fCVZ)rJ=T>ncLXby=&8hWgP9c6ly%m+KI3?|+t_>$nBBT4U5I@GSI8Jj~(=QJl zPS;;z1h4Xj4Yz_49O~JEM~n&*Fr!5e?uv8jZ;kgsM@SOnysi8Sv9mYG_aVQ6T}?^Y%U5bjOv%CP-3Utgz_L9oN$1t`4f5f`wqxQLey?#Gf- zoYg@T!9RHviJ#Ia?Y!$4Uql==eoK)f; z=ed_^kFt(+e3|YV`6C{9lM62{1=Yq}V;ltNbG(24 E3%|BS(f|Me delta 867 zcmYLHO=}ZD7@l`#KV~J8B%OIaM+&tBDZ|CshS;d_+_w!MFkK zyNQdZHe@Jx#y5pCLlV0+rKW|O@EJ0IDyhx9+UBaHs4!)n;3&0%SiL$xB~~)C9HgurMrpa;ZTC7+O*A`U6yr_ADXTYRY92O) zYWM}o^pC>UymQ!<`+4P*HN_Febla(mb!%8;Pc=RexuCzomj2>Z*Rz)t-$mfy0S5zI z#+l1Jpc((e&2cu4wh6eAd#?b!nEN$RkV}|S2fYNdH)oM5G6cLtI)Z>HBf%+NP6f7n zQUuhlw1Gpg16QfeIpkqBZri4Ivr z(BDccP}cU?)k2nSm_qGa01l$ F{TKIp$MygK diff --git a/__pycache__/x3_llm_auto_translate.cpython-310.pyc b/__pycache__/x3_llm_auto_translate.cpython-310.pyc index e603e56f0953287e1593bc2559969287ed33d094..9935c54007c162e0ba88ccfe61d0b917491a3f8d 100644 GIT binary patch delta 4634 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 delta 4299 zcmbtXU2GiH6`ngYJNy6Z^?KL4_O9a};+R+vAZ=2UKtoFS3u!|LOh{M5-m$as?5=a? zIwaOz)|G=$OOc3%mx>12s-WeiDvByqLKS^Rw5rNeM^)9g7WLt20M+MnUe;pqc${Cll+zwTeFQdg@#`x<`9jTc^Wkflvu+wM&s8MvuGFB z6thGVGzp^-nxbiVj?xSrfM=Oz=^#8SG)ITvIY#re0M9*i*v`$Xv`98}ciG`)k~6F6Iu^HSmD^W1%Ye2^2GB0G&}uC>c6H0_PLR3=kOT>l2w}yW@99sG z2X{@&Fx#S4_o~b7MsEz13*Wa2%^)-S7P%G)4}2KMQ>_d@s7X56M9! zdyz~d+2{Q#T!@SU>yz1cRMYz?JbBLy4nqywb*%;4H6sn{N|m=3?WSu+A%`WKS$vt< zjGzbUde)nXoF`M>4{*m1MjVi361o zuP?Q#ryf7HZR;X)PTl1-sQnS_P z*IKj(P^e3VumJwt&dMC zW$X+Z@Ap1R-8J$wu%_YGT2SV0d7eY1g!iELZeox$yo2d8WZ~wI)8`1OdjH5AnEje6 zp#up83%TdL69W%)ozW^{J=aQfHN#gFLBergW0;f_dKw>2BQrEqHTu zk8wAD48}$>55y118tlN;(QJ;q?LD2nfA2-KFlw#le0`yYscrt1fx$P+G5B}?67b&3 z&UXY^H#U@ql=EkvQ`_Noga<`Ls0C$>w4*{3S3vFJVQ$$>ZM08HMbdV?3lduMO+aPY|iioYJHsC`7 zFVa_bx^Q2Hak}er1GL**WJCx8Oz_zH01b%58_ErJgAj#hH%DtQsw?dzAEbsz@Z6dP zDgL6J;zJ_Eb3=+qtf}oZ&v$r1gw}^QATyB?>6f~hXQbnxNWG!ZkVpd!-w5;;h)8L4 zQ;G}GSbKmEih(r(i!8UZD`{R783?|_wGF~Y*0lDZNUo2HLG*D}AxiUkUE$@|$konC zqO{?wwsJ;f#Q=@xl||(>!logB3QdSCjSnfXd~#bTDUkz7`bM}H(AQXDfP8Fy56z%` zvk0EY>A48Q^(5z(nR96bcyaS5~yEY_- zdNu*HISX?y&G*Xrey^GpndOj(LK1nb*9{%hqlN7=>98OjiBO~KXfs1}*v}D10Hyp6 zD1H28DE$v46*tQb;q;MI0%=E~JE1hP4NAWTD8>0+J}okkcR}O9@9=;ihnf$SET#Rm=jqK(KgQNlFv@$*6eKx$0_}=;AKJWeFo_l3)GY2o}mC{qp zqRTbt7-_3=xKgtnYPl6^yVO2hSlNw+qKXbIxLu2g9giX zr&T||TikMd9j4a2-#7oU6}~gxedMR z3$CxZoXKycpM*xBzR;>}HZb0&qcd4-EqvADzPdzxz3w(GHs&2HSAyNP;4be%c|0TA z1Z+(F0QhaV?5uaATs$hOVfqR`a(;p10o_7aDT*aVvDyxy?kOX%44k{`fm7z;`t z?gb0FyrTEl@@R}LfT-JbT=Wu^!$W1Zh(;=%HzRIqnbquSt>u_rwX$c<9H?EeYm5CB zM5Q}4q{pdau-~yoQpww?CG&F&m3tkOWl<43Qz5#qqI@Y{GHgG?5V9 zy(Jo3ZeE7XaPh#$pkVAxVEj?AJ0I@R=7n=Zy5{3ngH4Iry3mFrcOIWg4 z7qFGEFJ!D`Ea6CDtYMtZkis;VxtWoXp@g%B0Ys-T1T$zd`&IGqdgf&&XC~&Q7 zMVSR9@gQ|Y<{()xVF8k3E-K9{1Tu;_fCLW{52FAh4`Wftq;c2e~D=Sbz*3CLYG3fXOeo4>AT!Ud5Be M&c?yW!^H9z0RHqAE&u=k diff --git a/__pycache__/x4_integrate_translates_to_master.cpython-310.pyc b/__pycache__/x4_integrate_translates_to_master.cpython-310.pyc index 3e71af01fcd1da4601f234150939078e147ecc05..21db7713479fb2b87f93842606c37ec264ab3fcb 100644 GIT binary patch delta 565 zcmZ8d&ubGw6rMNxBa_YUCJpP4-WC+npiL1x^;Uv{AR>sDdRQhqQ%$nj(b;JVVZ}qw zf-pC0CHW5uz4*86!CU`^iXe41MFk(ck8kGtc)a&rcE3cS2m%k8I=Kl)-aSz6u@QBJfGSY zz_u1n4orV{UWGRHz`Y7>4@X$;obS2!;lq~MzamFMPDesaE2ntFxsv_*w~>nMaF)}3 zXHGLA_nnkyjLL1JUBjSecMUu?T|@>5xDeqGd?4Uq3=xp4wIcx~{f)+Yw(x@|`8XZZoQd7|Cj@;@x5?Hh zFe7DXpduq$@SM(gMUv!Tobe=)om$;7(8toLO|2r8RTM;`9;}D`T5zmSc@}KQ%j08 zK%(r)`8lPzd5KZ1Wr;cYMNzEDsW~Z$MLIw^2%!sNDFX?o$=}&!?Ln+$Mj!zLAT~1) zI|FgC1du3USio4rkj1o+F_F21rG^3SXhuIx*2xVV8hUy_Rho=NtUwCQqFc;GrFnrM zlURTR4-*e#k=(- diff --git a/__pycache__/x5_complete_empty_cells_master.cpython-310.pyc b/__pycache__/x5_complete_empty_cells_master.cpython-310.pyc index 6d634d8b8bd4791032ff186f0c750f44506fcfe0..72f4fb0c75b159b863fd6f59b7a89cf5bdb6b36f 100644 GIT binary patch delta 235 zcmdnVGmDoupO=@50SFe0@}}S2$a{<>nhD5b0b*w$E;a!YB@7D~YZ$Va7BVI>m#}29 zE?_HRU&vU?Si+IQSi?A*A%$r!b2B3&LkVXM1Bgyx2xib^_N(II^~}pm&P>cp$+uGY z#mKA4HJOoBBZ(7eWD&^DTO3J=#i@CTxv94};^WgYb5i5ui+Dh?DnLS$sfZb*h`Tts zD6^m>9;B{F2_y?9ltFULMWuPVKt?eKklw Ljf0VgiRCW<+!YjJ diff --git a/__pycache__/x6_update_from_master.cpython-310.pyc b/__pycache__/x6_update_from_master.cpython-310.pyc index dddbb95e89054c9accef0f3b7eecd6e09d7f26fc..b79170ecc974d58d4f238442e258f6a166912396 100644 GIT binary patch delta 300 zcmcaEF;kK^pO=@50SK0h@}^(e$Q#2|&jjK^0W*+h0b*w$F17;_B@7D~YZ$Va7BVI> z*Dw~zmat^8E?_HRU&vU?RKk(MSi>}%A%$r!b2B3&LkVXMLk(jy6C*sH7_wY z^%h5bd|GBsYJ7YVKS z1KBJoj0+iS8EY7eL`qm|7-|@snHU*T7=poAlgaNEOGQp`g(lnNTU_eyx44T_b5fH_ z;?pv7Qj4sBrfD)2u>q+fbr4|zCoF-iTg*kJd4)hmG01s5Ok9jCjC_nN|BFH<=W_31 S44JIOlfllx!N|kJ@)rPTxG1^+ diff --git a/menu_pasos_traduccion.py b/menu_pasos_traduccion.py index 0e6f7ba..fb7b2a8 100644 --- a/menu_pasos_traduccion.py +++ b/menu_pasos_traduccion.py @@ -12,7 +12,19 @@ from translation_config import TranslationConfig import sys import threading import os -import subprocess +import queue + + +class RedirectText: + def __init__(self, queue): + self.queue = queue + + def write(self, string): + self.queue.put(string) + + def flush(self): + pass + class TranslationApp: def __init__(self, master): @@ -26,142 +38,265 @@ class TranslationApp: self.create_widgets() self.place_widgets() + self.queue = queue.Queue() + self.update_output() + + # Cargar el log existente al iniciar + self.load_existing_log() + def create_variables(self): 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.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) self.master_name_var = tk.StringVar(value=self.config.master_name) self.translate_name_var = tk.StringVar(value=self.config.translate_name) - self.auto_translate_name_var = tk.StringVar(value=self.config.auto_translate_name) + self.auto_translate_name_var = tk.StringVar( + value=self.config.auto_translate_name + ) def create_widgets(self): self.main_frame = ttk.Frame(self.master) - self.main_frame.grid(row=0, column=0, sticky='nsew') + self.main_frame.grid(row=0, column=0, sticky="nsew") self.master.grid_rowconfigure(0, weight=1) self.master.grid_columnconfigure(0, weight=1) self.frame_combos = ttk.Frame(self.main_frame) - - self.label_tipo_PLC = ttk.Label(self.frame_combos, text="Selecciona el tipo de PLC:") + + self.label_tipo_PLC = ttk.Label( + self.frame_combos, text="Selecciona el tipo de PLC:" + ) self.combo_tipo_PLC = ttk.Combobox(self.frame_combos, state="readonly") self.combo_tipo_PLC["values"] = [nombre for nombre, _ in fc.PLCs.values()] - self.combo_tipo_PLC.bind('<>', self.update_tipo_PLC) + self.combo_tipo_PLC.bind("<>", self.update_tipo_PLC) self.set_combo_value(self.combo_tipo_PLC, self.codigo_tipo_PLC_var.get()) - self.label_codigo_maestra = ttk.Label(self.frame_combos, text="Idioma Columna Maestra:") + self.label_codigo_maestra = ttk.Label( + self.frame_combos, text="Idioma Columna Maestra:" + ) self.combo_codigo_maestra = ttk.Combobox(self.frame_combos, state="readonly") - self.combo_codigo_maestra["values"] = [nombre for nombre, _ in fc.IDIOMAS.values()] - self.combo_codigo_maestra.bind('<>', self.update_codigo_maestra) - self.set_combo_value(self.combo_codigo_maestra, self.codigo_columna_maestra_var.get()) + self.combo_codigo_maestra["values"] = [ + nombre for nombre, _ in fc.IDIOMAS.values() + ] + self.combo_codigo_maestra.bind( + "<>", self.update_codigo_maestra + ) + self.set_combo_value( + self.combo_codigo_maestra, self.codigo_columna_maestra_var.get() + ) self.label1 = ttk.Label(self.frame_combos, text="Idioma de Traducción:") self.combo = ttk.Combobox(self.frame_combos, state="readonly") self.combo["values"] = [nombre for nombre, _ in fc.IDIOMAS.values()] - self.combo.bind('<>', self.update_idioma) + self.combo.bind("<>", self.update_idioma) self.set_combo_value(self.combo, self.codigo_idioma_var.get()) self.label2 = ttk.Label(self.frame_combos, text="Selecciona segundo idioma:") self.combo2 = ttk.Combobox(self.frame_combos, state="readonly") self.combo2["values"] = [nombre for nombre, _ in fc.IDIOMAS.values()] - self.combo2.bind('<>', self.update_idioma2) + self.combo2.bind("<>", self.update_idioma2) self.set_combo_value(self.combo2, self.codigo_idioma_var2.get()) self.work_dir_frame = ttk.Frame(self.main_frame) - self.work_dir_label = ttk.Label(self.work_dir_frame, text="Directorio de trabajo:") - 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) + self.work_dir_label = ttk.Label( + self.work_dir_frame, text="Directorio de trabajo:" + ) + 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 + ) style = ttk.Style() - style.configure('TButton', padding=(10, 10), font=('Helvetica', 10, 'bold')) - style.configure('Excel.TButton', padding=(10, 10), font=('Helvetica', 10), background='#69cf81') + style.configure("TButton", padding=(10, 10), font=("Helvetica", 10, "bold")) + style.configure( + "Excel.TButton", + padding=(10, 10), + font=("Helvetica", 10), + background="#69cf81", + ) self.button_width = 60 self.entry_width = 50 - - 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) - 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') - 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) - 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') + 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, + ) + 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", + ) - 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) - 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') + 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, + ) + 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", + ) - 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) + 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, + ) + 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", + ) - 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) + 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, + ) - 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) + 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, + ) - 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) + 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, + ) - self.output_text = tk.Text(self.main_frame, wrap='none', height=20) - self.scrollbar_y = ttk.Scrollbar(self.main_frame, orient='vertical', command=self.output_text.yview) - 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) + 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, + ) - self.clear_button = ttk.Button(self.main_frame, text="Limpiar salida", command=self.clear_output) - self.open_log_button = ttk.Button(self.main_frame, text="Abrir Log", command=self.open_log_file) + self.output_text = tk.Text(self.main_frame, wrap="none", height=20) + self.scrollbar_y = ttk.Scrollbar( + self.main_frame, orient="vertical", command=self.output_text.yview + ) + 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 + ) + + self.clear_button = ttk.Button( + self.main_frame, text="Limpiar salida", command=self.clear_output + ) + self.open_log_button = ttk.Button( + self.main_frame, text="Abrir Log", command=self.open_log_file + ) def place_widgets(self): self.main_frame.grid_columnconfigure(0, weight=1) self.main_frame.grid_columnconfigure(1, weight=1) - self.frame_combos.grid(row=0, column=0, columnspan=2, pady=10, sticky='ew') - self.label_tipo_PLC.grid(row=0, column=0, padx=5, pady=5, sticky='e') - self.combo_tipo_PLC.grid(row=0, column=1, padx=5, pady=5, sticky='w') - self.label_codigo_maestra.grid(row=1, column=0, padx=5, pady=5, sticky='e') - self.combo_codigo_maestra.grid(row=1, column=1, padx=5, pady=5, sticky='w') - self.label1.grid(row=0, column=2, padx=5, pady=5, sticky='e') - 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') + self.frame_combos.grid(row=0, column=0, columnspan=2, pady=10, sticky="ew") + self.label_tipo_PLC.grid(row=0, column=0, padx=5, pady=5, sticky="e") + self.combo_tipo_PLC.grid(row=0, column=1, padx=5, pady=5, sticky="w") + self.label_codigo_maestra.grid(row=1, column=0, padx=5, pady=5, sticky="e") + self.combo_codigo_maestra.grid(row=1, column=1, padx=5, pady=5, sticky="w") + self.label1.grid(row=0, column=2, padx=5, pady=5, sticky="e") + 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") - self.work_dir_frame.grid(row=1, column=0, columnspan=2, pady=10, sticky='ew') - self.work_dir_label.grid(row=0, column=0, padx=5, sticky='w') - 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(row=1, column=0, columnspan=2, pady=10, sticky="ew") + self.work_dir_label.grid(row=0, column=0, padx=5, sticky="w") + 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) current_row = 2 - self.paso1.grid(row=current_row, column=0, pady=5, padx=5, sticky='ew') - self.master_name_button.grid(row=current_row, column=1, pady=5, padx=5, sticky='ew') - - current_row += 1 - self.paso2.grid(row=current_row, column=0, pady=5, padx=5, sticky='ew') - self.translate_name_button.grid(row=current_row, column=1, pady=5, padx=5, sticky='ew') - - current_row += 1 - self.paso3.grid(row=current_row, column=0, pady=5, padx=5, sticky='ew') - self.auto_translate_name_button.grid(row=current_row, column=1, pady=5, padx=5, sticky='ew') - - current_row += 1 - self.paso4.grid(row=current_row, column=0, pady=5, padx=5, sticky='ew') - - current_row += 1 - self.paso4B.grid(row=current_row, column=0, pady=5, padx=5, sticky='ew') - - current_row += 1 - self.paso5.grid(row=current_row, column=0, columnspan=2, pady=5, padx=5, sticky='ew') - - current_row += 1 - self.paso6.grid(row=current_row, column=0, columnspan=2, pady=5, padx=5, sticky='ew') + self.paso1.grid(row=current_row, column=0, pady=5, padx=5, sticky="ew") + self.master_name_button.grid( + row=current_row, column=1, pady=5, padx=5, sticky="ew" + ) current_row += 1 - self.output_text.grid(row=current_row, column=0, columnspan=2, padx=(10, 0), pady=10, sticky='nsew') - 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') + self.paso2.grid(row=current_row, column=0, pady=5, padx=5, sticky="ew") + self.translate_name_button.grid( + row=current_row, column=1, pady=5, padx=5, sticky="ew" + ) + + current_row += 1 + self.paso3.grid(row=current_row, column=0, pady=5, padx=5, sticky="ew") + self.auto_translate_name_button.grid( + row=current_row, column=1, pady=5, padx=5, sticky="ew" + ) + + current_row += 1 + self.paso4.grid(row=current_row, column=0, pady=5, padx=5, sticky="ew") + + current_row += 1 + self.paso4B.grid(row=current_row, column=0, pady=5, padx=5, sticky="ew") + + current_row += 1 + self.paso5.grid( + row=current_row, column=0, columnspan=2, pady=5, padx=5, sticky="ew" + ) + + current_row += 1 + self.paso6.grid( + row=current_row, column=0, columnspan=2, pady=5, padx=5, sticky="ew" + ) + + current_row += 1 + self.output_text.grid( + row=current_row, + column=0, + columnspan=2, + padx=(10, 0), + pady=10, + sticky="nsew", + ) + 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" + ) current_row += 2 - 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') + 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" + ) - self.main_frame.grid_rowconfigure(current_row-2, weight=1) + self.main_frame.grid_rowconfigure(current_row - 2, weight=1) def set_combo_value(self, combo, codigo): for nombre, code in fc.IDIOMAS.values(): @@ -222,8 +357,21 @@ class TranslationApp: dir_path = filedialog.askdirectory() if dir_path: self.work_dir_var.set(dir_path) + self.config.work_dir = dir_path self.save_config() - self.update_file_names() + self.load_existing_log() # Cargar el log del nuevo directorio + + def load_existing_log(self): + log_file = os.path.join(self.config.work_dir, "logs", "app_log.txt") + if os.path.exists(log_file): + with open(log_file, "r", encoding="utf-8") as f: + log_content = f.read() + self.output_text.delete("1.0", tk.END) + self.output_text.insert(tk.END, log_content) + self.output_text.see(tk.END) + else: + self.output_text.delete("1.0", tk.END) + self.output_text.insert(tk.END, "No se encontró un log existente.\n") def open_file(self, file_path): if os.path.exists(file_path): @@ -235,73 +383,115 @@ class TranslationApp: 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.") + 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) + if sys.platform == "win32": + os.startfile(log_file_path) + else: + opener = "open" if sys.platform == "darwin" else "xdg-open" + subprocess.call([opener, 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.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() + # No limpiar el texto anterior + # self.output_text.delete('1.0', tk.END) + + sys.stdout = RedirectText(self.queue) + + def run_script(): + try: + if funcion_run == x1_importar_to_master.run: + archivo_importacion = filedialog.askopenfilename( + title="Seleccione el archivo para Importar", + filetypes=[("Excel files", "*.xls*")], + ) + if archivo_importacion: + funcion_run(self.config,archivo_importacion) + 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: + self.queue.put(f"Error: {str(e)}\n") + finally: + sys.stdout = sys.__stdout__ + self.save_config() + self.save_log() + self.queue.put("DONE") + + threading.Thread(target=run_script, daemon=True).start() + + def update_output(self): + while True: + try: + message = self.queue.get_nowait() + if message == "DONE": + break + self.output_text.insert(tk.END, message) + self.output_text.see(tk.END) + self.output_text.update_idletasks() + except queue.Empty: + break + self.master.after(100, self.update_output) + def clear_output(self): - self.output_text.delete('1.0', tk.END) + self.output_text.delete("1.0", tk.END) + self.save_log() - class RedirectText: - def __init__(self, text_widget): - self.text_widget = text_widget + def save_log(self): + log_content = self.output_text.get("1.0", tk.END) + log_dir = os.path.join(self.config.work_dir, "logs") + os.makedirs(log_dir, exist_ok=True) + log_file = os.path.join(log_dir, "app_log.txt") - def write(self, string): - self.text_widget.insert(tk.END, string) - self.text_widget.see(tk.END) + with open(log_file, "w", encoding="utf-8") as f: + f.write(log_content) - def flush(self): - pass def main(): root = tk.Tk() app = TranslationApp(root) root.mainloop() + if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/translation_config.json b/translation_config.json index 39ff6d7..c2f8afc 100644 --- a/translation_config.json +++ b/translation_config.json @@ -1,6 +1,6 @@ { "codigo_tipo_PLC": "allenbradley", - "codigo_columna_maestra": "es-ES", + "codigo_columna_maestra": "en-US", "codigo_idioma_seleccionado": "es-ES", "codigo_idioma_secundario": "en-US", "work_dir": "C:/Trabajo/VM/31 - 9.3953 - Omega - Mexico - (ABradley)/Reporte/Languages", diff --git a/x1_importar_to_master.py b/x1_importar_to_master.py index 8f8500c..97647c6 100644 --- a/x1_importar_to_master.py +++ b/x1_importar_to_master.py @@ -14,6 +14,10 @@ def preprocesar_importacion( ): filas_validas = [] + progress_bar = fc.ProgressBar( + len(df_importacion), prefix="Preprocesando filas:", suffix="Completado" + ) + for index, fila in df_importacion.iterrows(): clave_original = fila[codigo_columna_maestra] @@ -22,6 +26,7 @@ def preprocesar_importacion( logger.info( f"Fila {index}: Ignorada - Celda de columna maestra vacía o solo con espacios en blanco" ) + progress_bar.increment() continue nueva_fila = fila.copy() @@ -40,27 +45,28 @@ def preprocesar_importacion( filas_validas.append(nueva_fila) logger.info(f"Fila {index}: Aceptada - Clave '{clave_sustituida}' procesada") + progress_bar.increment() + progress_bar.finish() df_valido = pd.DataFrame(filas_validas, columns=df_importacion.columns) return df_valido -def importar(config: TranslationConfig): +def importar(config: TranslationConfig, archivo_importacion): logger.info(" .... ") logger.info(f"Iniciando importacion en {config.master_name}") archivo_maestro = os.path.join(config.work_dir, config.master_name) + if not archivo_importacion: + logger.info("No se seleccionó ningún archivo para importar.") + return + if not os.path.exists(archivo_maestro): df_maestro = pd.DataFrame(columns=[config.codigo_columna_maestra]) else: df_maestro = fc.read_dataframe_with_cleanup_retries(archivo_maestro) - archivo_importacion = fc.select_file("xlsx") - if not archivo_importacion: - logger.info("No se seleccionó ningún archivo para importar.") - return - df_importacion = fc.read_dataframe_with_cleanup_retries(archivo_importacion) df_importacion = preprocesar_importacion( @@ -71,6 +77,10 @@ def importar(config: TranslationConfig): filas_a_agregar = [] + progress_bar = fc.ProgressBar( + len(df_importacion), prefix="Procesando filas:", suffix="Completado" + ) + for index, fila in df_importacion.iterrows(): clave = str(fila[config.codigo_columna_maestra]) @@ -78,6 +88,7 @@ def importar(config: TranslationConfig): logger.info( f"Fila {index}: Ignorada - Clave '{clave}' ya existe en el archivo maestro" ) + progress_bar.increment() continue claves_maestro.add(clave) @@ -88,9 +99,13 @@ def importar(config: TranslationConfig): if col == config.codigo_columna_maestra or fc.es_columna_tipo_xxYY(col) } filas_a_agregar.append(fila_filtrada) + progress_bar.increment() + + progress_bar.finish() if not filas_a_agregar: logger.info("No hay nuevas filas válidas para agregar.") + print("No hay nuevas filas válidas para agregar.") return for columna in df_importacion.columns: @@ -109,16 +124,15 @@ def importar(config: TranslationConfig): ) -def run(config: TranslationConfig): +def run(config: TranslationConfig, archivo_importacion): global logger logger = fc.configurar_logger(config.work_dir) - importar(config) + script_name = os.path.basename(__file__) + print(f"\rIniciando: {script_name}\r") + importar(config, archivo_importacion) if __name__ == "__main__": - print( - "Este script debe ser ejecutado desde el menú principal (menu_pasos_traduccion.py)." - ) - print( - "Por favor, ejecute menu_pasos_traduccion.py para utilizar esta funcionalidad." - ) + import menu_pasos_traduccion + + menu_pasos_traduccion.main() diff --git a/x2_master_export2translate.py b/x2_master_export2translate.py index e8c00ea..6f1cab4 100644 --- a/x2_master_export2translate.py +++ b/x2_master_export2translate.py @@ -1,52 +1,170 @@ import pandas as pd import os +import sys +import time import PyLibrary.funciones_comunes as fc from translation_config import TranslationConfig +import langid +from openpyxl import load_workbook +from openpyxl.styles import PatternFill, Alignment # Definir el logger a nivel de módulo logger = None +def configurar_detector_idiomas(): + codigos_idioma = [code.split("-")[0] for _, code in fc.IDIOMAS.values()] + langid.set_languages(codigos_idioma) + + +def detectar_idioma(texto, tipo_PLC): + texto_limpio = fc.limpiar_texto(tipo_PLC, texto) + if len(texto_limpio.strip()) < 3: # No detectar idioma en textos muy cortos + return "unknown" + try: + idioma, _ = langid.classify(texto_limpio) + return idioma + except: + return "unknown" + + +def obtener_nombre_idioma(codigo_corto): + for nombre, codigo in fc.IDIOMAS.values(): + if codigo.startswith(codigo_corto): + return nombre + return "Desconocido" + + def exportar_para_traduccion(config: TranslationConfig): master_path = config.get_master_path() if not os.path.exists(master_path): print("El archivo maestro no existe.") return - # Leer el archivo maestro + configurar_detector_idiomas() + df_maestro = fc.read_dataframe_with_cleanup_retries(master_path) - # Crear un nuevo DataFrame para la exportación df_export = pd.DataFrame() - - # Copiar la primera columna y la columna del idioma de destino primera_columna = df_maestro.columns[0] df_export[primera_columna] = df_maestro[primera_columna] df_export[config.codigo_idioma_seleccionado] = df_maestro[ config.codigo_idioma_seleccionado ] + df_export["Idioma_Detectado"] = "" - # Guardar el archivo exportado ruta_export = config.get_translate_path() - # Usar ExcelWriter para tener más control sobre el proceso de escritura with pd.ExcelWriter(ruta_export, engine="openpyxl") as writer: df_export.to_excel(writer, index=False, sheet_name="Sheet1") - # Ajustar el ancho de las columnas + workbook = writer.book worksheet = writer.sheets["Sheet1"] - for idx, col in enumerate(df_export.columns): - max_length = max(df_export[col].astype(str).map(len).max(), len(col)) - if max_length > 50: - max_length = 50 - worksheet.column_dimensions[chr(65 + idx)].width = max_length + 2 - print(f"Archivo exportado para traducción: {ruta_export}") + wrap_alignment = Alignment(wrap_text=True, vertical="top") + for col in ["A", "B"]: + for cell in worksheet[col]: + cell.alignment = wrap_alignment + worksheet.column_dimensions[col].width = 50 + + idioma_esperado = fc.idiomas_shortcodefromcode( + config.codigo_idioma_seleccionado + ) + fill = PatternFill(start_color="ADD8E6", end_color="ADD8E6", fill_type="solid") + + total_rows = worksheet.max_row - 1 # Excluimos la fila de encabezado + progress_bar = fc.ProgressBar( + total_rows, prefix="Procesando filas:", suffix="Completado" + ) + + for row in range(2, worksheet.max_row + 1): + texto = worksheet.cell(row=row, column=2).value + if texto: + idioma_detectado = detectar_idioma(texto, config.codigo_tipo_PLC) + if ( + idioma_detectado != "unknown" + and idioma_detectado != idioma_esperado + ): + worksheet.cell(row=row, column=2).fill = fill + nombre_idioma = obtener_nombre_idioma(idioma_detectado) + worksheet.cell(row=row, column=3).value = nombre_idioma + progress_bar.update(row - 1) + + progress_bar.finish() + + print(f"\nArchivo exportado para traducción: {ruta_export}") + print("Las celdas con idioma incorrecto han sido marcadas en azul.") + print( + "Se ha añadido el nombre del idioma detectado cuando es diferente del esperado." + ) + master_path = config.get_master_path() + if not os.path.exists(master_path): + print("El archivo maestro no existe.") + return + + configurar_detector_idiomas() + + df_maestro = fc.read_dataframe_with_cleanup_retries(master_path) + + df_export = pd.DataFrame() + primera_columna = df_maestro.columns[0] + df_export[primera_columna] = df_maestro[primera_columna] + df_export[config.codigo_idioma_seleccionado] = df_maestro[ + config.codigo_idioma_seleccionado + ] + df_export["Idioma_Detectado"] = "" + + ruta_export = config.get_translate_path() + + with pd.ExcelWriter(ruta_export, engine="openpyxl") as writer: + df_export.to_excel(writer, index=False, sheet_name="Sheet1") + + workbook = writer.book + worksheet = writer.sheets["Sheet1"] + + wrap_alignment = Alignment(wrap_text=True, vertical="top") + for col in ["A", "B"]: + for cell in worksheet[col]: + cell.alignment = wrap_alignment + worksheet.column_dimensions[col].width = 50 + + idioma_esperado = fc.idiomas_shortcodefromcode( + config.codigo_idioma_seleccionado + ) + fill = PatternFill(start_color="ADD8E6", end_color="ADD8E6", fill_type="solid") + + total_rows = worksheet.max_row - 1 # Excluimos la fila de encabezado + progress_bar = fc.ProgressBar( + total_rows, prefix="Progreso:", suffix="Completado" + ) + + for row in range(2, worksheet.max_row + 1): + texto = worksheet.cell(row=row, column=2).value + if texto: + idioma_detectado = detectar_idioma(texto, config.codigo_tipo_PLC) + if ( + idioma_detectado != "unknown" + and idioma_detectado != idioma_esperado + ): + worksheet.cell(row=row, column=2).fill = fill + nombre_idioma = obtener_nombre_idioma(idioma_detectado) + worksheet.cell(row=row, column=3).value = nombre_idioma + progress_bar.increment() + + progress_bar.finish() + + print(f"\nArchivo exportado para traducción: {ruta_export}") + print("Las celdas con idioma incorrecto han sido marcadas en azul.") + print( + "Se ha añadido el nombre del idioma detectado cuando es diferente del esperado." + ) def run(config: TranslationConfig): global logger logger = fc.configurar_logger(config.work_dir) + script_name = os.path.basename(__file__) + print(f"\rIniciando: {script_name}\r") exportar_para_traduccion(config) diff --git a/x3_llm_auto_translate.py b/x3_llm_auto_translate.py index 561337b..8a63d3a 100644 --- a/x3_llm_auto_translate.py +++ b/x3_llm_auto_translate.py @@ -1,7 +1,6 @@ import pandas as pd from openai import OpenAI import os -import re from openai_api_key import openai_api_key from google_api_key import google_api_key import ollama @@ -220,48 +219,40 @@ def main(config: TranslationConfig): texts_to_translate = {} + # Inicializar ProgressBar para la fase de preparación + prep_progress = fc.ProgressBar(len(df), prefix='Preparando textos:', suffix='Completado') + for index, row in df.iterrows(): celda_clave = str(row[source_col]) - source_translated_text = ( - str(row[source_translated_col]) - if source_translated_col in df.columns - else "" - ) - celda_clave_compactada = fc.compactar_celda_traducida( - config.codigo_tipo_PLC, celda_clave - ) + source_translated_text = str(row[source_translated_col]) if source_translated_col in df.columns else "" + celda_clave_compactada = fc.compactar_celda_traducida(config.codigo_tipo_PLC, celda_clave) if config.traducir_todo: - if fc.texto_requiere_traduccion( - config.codigo_tipo_PLC, celda_clave_compactada, logger - ): + if fc.texto_requiere_traduccion(config.codigo_tipo_PLC, celda_clave_compactada, logger): df.at[index, source_translated_col] = "" texts_to_translate[celda_clave] = celda_clave_compactada else: - if ( - pd.isna(row[source_translated_col]) - or source_translated_text.strip() == "" - ): - 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 - ): + if pd.isna(row[source_translated_col]) or source_translated_text.strip() == "": + 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 + + prep_progress.update(index + 1) + + prep_progress.finish() num_texts = len(texts_to_translate) - # num_texts = 40 - logger.info(f"Número total de textos a traducir: {num_texts}") - print(f"Número total de textos a traducir: {num_texts}") + print(f"\nNúmero total de textos a traducir: {num_texts}") - # Traducciones + # Inicializar ProgressBar para la fase de traducción + trans_progress = fc.ProgressBar(num_texts, prefix='Traduciendo:', suffix='Completado') + + # Traducciones translations = {} for start_idx in range(0, num_texts, batch_size): end_idx = min(start_idx + batch_size, num_texts) batch_texts = dict(list(texts_to_translate.items())[start_idx:end_idx]) - logger.info(f"Traduciendo: celdas desde {start_idx} a {end_idx}.") - print(f"Traduciendo : celdas desde: {start_idx} a :{end_idx}.") + logger.info(f"Traduciendo: celdas desde {start_idx} a {end_idx}.") retries = 4 for attempt in range(retries): @@ -281,11 +272,17 @@ def main(config: TranslationConfig): else: logger.error(f"Error en todos los intentos de traducción de celdas desde {start_idx} a {end_idx}: {e}") print(f"Error en todos los intentos de traducción de celdas desde {start_idx} a {end_idx}: {e}") + + trans_progress.update(end_idx) + trans_progress.finish() logger.info(f"Número total de traducciones recibidas: {len(translations)}") + # Inicializar ProgressBar para la fase de actualización del DataFrame + update_progress = fc.ProgressBar(len(df), prefix='Actualizando DataFrame:', suffix='Completado') + # Actualizar el DataFrame con las traducciones y hacemos la Traduccion inversa - for index, row in tqdm(df.iterrows(), total=df.shape[0], desc="Procesando traducciones"): + for index, row in df.iterrows(): celda_clave = str(row[source_col]) if celda_clave in translations: df.at[index, target_col] = translations[celda_clave] @@ -299,14 +296,18 @@ def main(config: TranslationConfig): logger.error(f"Error en la traducción de Google para el texto '{celda_clave}': {e}") df.at[index, check_translate_col] = "Error en la traducción" df.at[index, affinity_col] = 0.0 + update_progress.increment() + + update_progress.finish() + # Inicializar ProgressBar para la fase de cálculo de afinidad + affinity_progress = fc.ProgressBar(num_texts, prefix='Calculando afinidad:', suffix='Completado') # Afinidades affinities = {} for start_idx in range(0, num_texts, batch_size): end_idx = min(start_idx + batch_size, num_texts) batch_texts = dict(list(texts_to_translate.items())[start_idx:end_idx]) - logger.info(f"Afinidad: celdas desde {start_idx} a {end_idx}.") - print(f"Afinidad: celdas desde: {start_idx} a :{end_idx}.") + logger.info(f"Afinidad: celdas desde {start_idx} a {end_idx}.") retries = 2 for attempt in range(retries): @@ -330,7 +331,10 @@ def main(config: TranslationConfig): affinities[key] = "0" logger.error(f"Error en el cálculo individual de Afinidad para el texto '{key}': {ind_e}") print(f"Error en el cálculo individual de Afinidad para el texto '{key}': {ind_e}") + + affinity_progress.increment() + affinity_progress.finish() # Actualizar el DataFrame con las Afinidades for index, row in df.iterrows(): celda_clave = str(row[source_col]) @@ -340,15 +344,15 @@ def main(config: TranslationConfig): output_path = config.get_auto_translate_path() fc.save_dataframe_with_retries(df, output_path=output_path) logger.info(f"Archivo traducido guardado en: {output_path}") - print(f"Archivo traducido guardado en: {output_path}") + print(f"\nArchivo traducido guardado en: {output_path}") def run(config: TranslationConfig): global logger logger = fc.configurar_logger(config.work_dir) + script_name = os.path.basename(__file__) + print(f"\rIniciando: {script_name}\r") main(config) - if __name__ == "__main__": import menu_pasos_traduccion - - menu_pasos_traduccion.main() + menu_pasos_traduccion.main() \ No newline at end of file diff --git a/x4B_integrate_manual_translates_to_master.py b/x4B_integrate_manual_translates_to_master.py index 064c5ed..fdd6a08 100644 --- a/x4B_integrate_manual_translates_to_master.py +++ b/x4B_integrate_manual_translates_to_master.py @@ -113,6 +113,8 @@ def marcar_errores_archivo_fuente(archivo, celdas_con_errores): def run(config: TranslationConfig): global logger logger = fc.configurar_logger(config.work_dir) + script_name = os.path.basename(__file__) + print(f"\rIniciando: {script_name}\r") importar_traduccion_manual(config) diff --git a/x4_integrate_translates_to_master.py b/x4_integrate_translates_to_master.py index a3fe09b..17caf09 100644 --- a/x4_integrate_translates_to_master.py +++ b/x4_integrate_translates_to_master.py @@ -55,6 +55,10 @@ def importar_traduccion(config: TranslationConfig): ) columna_excel = df_maestro.columns.get_loc(master_col) + 1 celdas_modificadas[(fila_excel, columna_excel)] = valor_traducido + else : + logger.error( + f'Clave {clave} no encontrada en master.' + ) fc.save_dataframe_with_retries(df_maestro, output_path=archivo_maestro) @@ -81,6 +85,8 @@ def aplicar_negrita_celdas_modificadas(archivo, celdas_modificadas): def run(config: TranslationConfig): global logger logger = fc.configurar_logger(config.work_dir) + script_name = os.path.basename(__file__) + print(f"\rIniciando: {script_name}\r") importar_traduccion(config) diff --git a/x5_complete_empty_cells_master.py b/x5_complete_empty_cells_master.py index 5403d54..cd83531 100644 --- a/x5_complete_empty_cells_master.py +++ b/x5_complete_empty_cells_master.py @@ -45,6 +45,8 @@ def complete_emptys(config: TranslationConfig): def run(config: TranslationConfig): global logger logger = fc.configurar_logger(config.work_dir) + script_name = os.path.basename(__file__) + print(f"\rIniciando: {script_name}\r") complete_emptys(config) diff --git a/x6_update_from_master.py b/x6_update_from_master.py index 90544a8..7a6e296 100644 --- a/x6_update_from_master.py +++ b/x6_update_from_master.py @@ -110,11 +110,12 @@ def marcar_celdas_con_errores(archivo_maestro, celdas_con_errores, target_lang_c ) -def run(config: TranslationConfig): +def run(config: TranslationConfig, archivo_to_update): global logger logger = fc.configurar_logger(config.work_dir) - archivo_to_update = fc.select_file("xlsx") if archivo_to_update: + script_name = os.path.basename(__file__) + print(f"\rIniciando: {script_name}\r") update_from_master(config, archivo_to_update)