From f0df7263397c7bcf3350cb1a4b338ea4f2d80697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C4=85browski?= <64841871+dabrt@users.noreply.github.com> Date: Thu, 18 Jun 2026 18:14:57 +0200 Subject: [PATCH 01/15] IBX-10684: Document translation management --- docs/api/event_reference/event_reference.md | 1 + .../translations_management_events.md | 29 ++++++ docs/ibexa_products/editions.md | 1 + .../translations_management_flow.drawio | 1 + .../img/managing_translations_sxs_view.png | Bin 0 -> 79236 bytes .../img/translations_management_flow.png | Bin 0 -> 63076 bytes .../translations_management_guide.md | 89 ++++++++++++++++++ mkdocs.yml | 6 ++ 8 files changed, 127 insertions(+) create mode 100644 docs/api/event_reference/translations_management_events.md create mode 100644 docs/multisite/img/diagram_source/translations_management_flow.drawio create mode 100644 docs/multisite/img/managing_translations_sxs_view.png create mode 100644 docs/multisite/img/translations_management_flow.png create mode 100644 docs/multisite/translations_management/translations_management_guide.md diff --git a/docs/api/event_reference/event_reference.md b/docs/api/event_reference/event_reference.md index 6cc5792d69..49396a4264 100644 --- a/docs/api/event_reference/event_reference.md +++ b/docs/api/event_reference/event_reference.md @@ -37,6 +37,7 @@ For example, copying a content item is connected with two events: `BeforeCopyCon "api/event_reference/segmentation_events", "api/event_reference/site_events", "api/event_reference/taxonomy_events", + "api/event_reference/translations_management_events", "api/event_reference/trash_events", "api/event_reference/twig_component_events", "api/event_reference/url_events", diff --git a/docs/api/event_reference/translations_management_events.md b/docs/api/event_reference/translations_management_events.md new file mode 100644 index 0000000000..a94a153a0e --- /dev/null +++ b/docs/api/event_reference/translations_management_events.md @@ -0,0 +1,29 @@ +--- +description: Events that are triggered when working with taxonomy. +edition: lts-update +page_type: reference +--- + +# Translations management events + +The [Translations management](configure_translations_management.md) package dispatches events at two levels. + +## Translation events + +Translation events are thrown once per field value per translation operation. +They are used for logging, analytics, and observability. +Both events are read-only, you can't use them to override the translation result. + +| Event | Dispatched by | Dispatched when | Properties | +|---|---|---|----| +[`BeforeTranslateEvent`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Event-BeforeTranslateEvent.html) | `TranslationService` | Before a translation request is sent to the provider | `TranslationProviderInterface $provider`
`string $text`
`string $sourceLanguage`
`string $targetLanguage` | +| [`TranslateEvent`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Event-TranslateEvent.html) | `TranslationService` | After a translation response is received | `string $result`
`TranslationProviderInterface $provider`
`string $text`
`string $sourceLanguage`
`string $targetLanguage` | + +## Side-by-side creation events + +Side-by-side creation events are dispatched when a new translation draft is being prepared. + +| Event | Dispatched by | Dispatched when | Properties | +|---|---|---|---| +| [`OnContentSideBySideTranslationCreateEvent`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-SideBySide-Event-OnContentSideBySideTranslationCreateEvent.html) | `SideBySideTranslationService` | When a draft side-by-side translation of a content item is being created | `Request $request`
`Content $sourceContent`
`string $sourceLanguageCode`
`string $targetLanguageCode`
`?Content $targetDraft` | +| [`OnProductSideBySideTranslationCreateEvent`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-SideBySide-Event-OnProductSideBySideTranslationCreateEvent.html) | `SideBySideTranslationService` | When a draft side-by-side translation of a product is being created | `Request $request`
`ContentAwareProductInterface $sourceProduct`
`ContentAwareProductInterface $targetProduct`
`string $sourceLanguageCode`
`string $targetLanguageCode`
`?ProductUpdateData $productUpdateData` | diff --git a/docs/ibexa_products/editions.md b/docs/ibexa_products/editions.md index fc5296196e..5bc7c73bf9 100644 --- a/docs/ibexa_products/editions.md +++ b/docs/ibexa_products/editions.md @@ -71,3 +71,4 @@ The features brought by LTS Updates become standard parts of the next LTS releas | [Integrated help](integrated_help.md) | ✔ | ✔ | ✔ | | [MCP servers](mcp_guide.md) | ✔ | ✔ | ✔ | | [Shopping list](shopping_list_guide.md) | | | ✔ | +| [Translations management](translations_management_guide.md) | ✔ | ✔ | ✔ | diff --git a/docs/multisite/img/diagram_source/translations_management_flow.drawio b/docs/multisite/img/diagram_source/translations_management_flow.drawio new file mode 100644 index 0000000000..e289d5a54e --- /dev/null +++ b/docs/multisite/img/diagram_source/translations_management_flow.drawio @@ -0,0 +1 @@ +5Zptc6M2EIB/DTPtB2d4MRh/tB3Hcc5pPfW0l/uUkUEG9WTkCuGX+/WVQNiAyJn0iJ1cZzxjWEmw++xqWQk0a7TeTyjYhI/Eh1gzdX+vWbeaaRqGaWrip/sHKbFtJ5MEFPlSdhIs0DcohbqUJsiHcakjIwQztCkLPRJF0GMlGaCU7MrdVgSX77oBAVQECw9gVfoZ+SzMDdP1U8M9REEob+3asmEN8s5SEIfAJ7uCyBpr1ogSwrKj9X4EsaCXc8nG3b3QelSMwog1GTDIBmwBTqRtA3+NIqEZZDH/SzYCLgVRjAFDRLRsKNly/jSWJrBDzoWSJPKhuLShWcNdiBhcbIAnWnc8FLgsZGssm1cI4xHBhKZjLR9Ad+Vxecwo+QoLLY7nwuWKt6jGSXu3kDK4L4iksRNI1pDRA+8iW007GyEjr2PkIbUr+NGVsrDgQkfKgAyd4HjpE11+IAHXwx4qsMc+YtxMU6fwnwTGKfEI7qrI28RsQ9fv1mF2zaXlOC1h7l+T80jh/AeMCd7CuBC9mulgfs/hUhwF4ugXDKIg4VO3swFIOEXckM+AWHTm8wHzVMLd8Wur/litVqZXG/a+s3TslvxhdPWKP1R3HHNS0R29Ftxxp4b9noe3l0Z7HudgyWnyVIwg9ttNLJchXEks/QuG+0Thu4CRn8IlLybvj4i4fz3G9zUpxYMoSyk5YU5PIKUoCj5iCBvlHGFahpoj9DfiO1X4jijkRFO8gAaQdfLsLApHClbsAxI23Ssifvhe9bFFcBenj7zqUxFEIqrXxEc8N6fuCOGHr0+MbjmVWOYFHfFJzddgC7OLvkVsXwhpObS7NUQNu4ao3QLRmUo05LbE6e353fMIb/mxdyGwPfs82d4bkX1UyM6TJUZxCFte/V0EpeU0CNK6MrgNlLBmcS5FMUmol6+/M1H20NOK6xnol3YlVCspFAl5W96k+CGVzUYqD9+TylYjlUeqyndtq5wOHVAKDoUOG4IiFheuPBeC4jqiPNtdvWJ9dsETi6NmzfB0G+G5U/FMruZRW8lB2sjUBr1GlrSudr3bjlt/x8qukjEylHLUyfjXhofllsPD6Ff2987oVen/4/HkNPLCvRpP06vFU7PAmaoqP7yLDGFVFhF57dqaS91GfB5UPp+u5tL+f1V5djWV83r59To/XktnFPT8ER3iu0n09LsxGuyecNLJi7BCdq4WhnEINuLQSyg+DCnwvgpTzlWI5XJyhdHmXh5r9WVfDcsXK0G7slzpHMu+0gpQUyrBrtlCKVgL0vopQFp63Upa5Wj0+m/EsatwnM/+nEx/U2i+ClsbqKwyKkeNuNrFRxt7DrWkHIXUYno77gy/dMQ/b/lrOv787rDxRdyNfWVy7vm5KmxGHsAzsIR4TmKUbpVZt0vCGFlzNHmHAUaBaGCkQjKf7et9IN6j3yxBjLyb7nNaIDzH/JHwzLEN0/fq+o3bDu3jZD2+m3cU1k4N6jZeFNWi7v9/UNckhLqofrMnUJ7KC2hFkbGQp4SykAQkAnh8khbmu87PTn1mREBO6f4NGTvIrzhAwkiZPdwj9pRyteXZl0LL7V5eOT05FE7mkCJuN6RSptVVRWfrq+9N72LR9XK/qxVeDSqvn2RmHLfi258Z/PT0tU22Wjp9tGSN/wU= \ No newline at end of file diff --git a/docs/multisite/img/managing_translations_sxs_view.png b/docs/multisite/img/managing_translations_sxs_view.png new file mode 100644 index 0000000000000000000000000000000000000000..8a27800397a02b1754b83dd96ab186eb7c0549ff GIT binary patch literal 79236 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 Ll%QpjCW!w7Vj^{B literal 0 HcmV?d00001 diff --git a/docs/multisite/img/translations_management_flow.png b/docs/multisite/img/translations_management_flow.png new file mode 100644 index 0000000000000000000000000000000000000000..61a7d0447121b8b589ea4f677a0ea4426a0b0bcb GIT binary patch literal 63076 zcmcG#XFyZk(m#rb(gXrX@6tP=g(fACgcf?J(n2SJ5Nap_A{}Xhf)uGDBE1Mo7Z3z# ziqeZ9(gg$r1>|ndbI$wT|GD?$y&tl(v-a$@X3d)Qn^`lH1S10k6$L8=5fKrUj<%Kw z5fO0|@UbSl4z#r93s?{lkqKX-l^DDYdy+usEXd;`tE)zB2USOOnud3zaqurP3^;p2mKv2a1_ zdHC~7!{uZk5;F2Yvyh&)8B(8LS`)a(dSG0DFNBK|26y?2v#(>2ga-~F2g^#xOMqp7 zHcfY5oEJa^S5TCYl8}`FzQEE7z=Qvt9~>+VJc0mirjD+Tz8?R#;V!4{;_vA8&$J1$ zj@AgYHN?+_ zwU57(JW?8_0|*qZWoG0Lm3Edznz#eM{Gl@1PEK+@My?i8fSBO{C=3dQP_!_^Xa*nv zL0`UMVQy^Tp%JX>E#;vLcCrp3cv`@`g8uakO2AtfW277*W-eyIo>uNU06EMZ>=xpD z`EH;E+Qre)1dnjE@b&Nk9{FkOq2d0za!4552y5!>uHz@A<%Dxb<59YP9@n8B?N+lYM2|tG=mh~%w2JS20=|jkXp`0V3Yz< z(F6v=p@AkDM?Wu^fr6i$DNM&zLl+XD84UID1>@XIgM9To6)k09evX=!P72-#8MKVC z3)U1FgmVKU%(Qf%UO`YZyotXCpbt<39X!n1T1y+?+BC#UQ{TC&JV+KnA0wC#x^(f$=jj&;k2s znP>oH3LX|xQV>Ki%+pue2&02W`Cf8~F!%G-ax=!b>bYqIJIiW&`oO@zvO{$=v@L@O zvUoovux+4L{sbgS-ZjWO$PA(93e$n$eRZT2O#F-$T?4^haOn_7ORS+L*c}3>0MtxD z%JWh+G+dCH&JfK2sHUP<0M^ab4`_2oxd*{z1KcdN^mN>0%?)Mzg5WxaFiR&4pn*^g z3vDwmg&^$^bELkrf<*wpAsp-BZ;rRNL;$yr0EwTBnIATg;O=Z>p=Sg(kFA+wnx1kVn$SS3HUjSG?t}AG z)N=JO1Y62_dU#??;D!or8ji-!uKIrZ8a~>ZShSx8K}TA~)X&2;(A`B54Tn2HUA#RZ zA$Sx44%5N=S`uJR3I_770h)#gZC?Phph&c*m$`+Z6FZ{I)rWdHnaaVDC@&lqK)cIbiUey*OBopI z$rHSBSQ#s#G+jA!QRgPc)1`$ZF3Dh zEgZ@aA*N(Fw)lyH1RQ#k`IKVAVwNqjySv#Bv@Yy0XK)c!{s2(ct=x3Fv1lo zhcW`71R5ac4`3?P6>Ki&>}g@HAmb~iXm$zdmKc9;xRIFx%tXc`K+0Q6QQwb%2ncp@ z0(8g&0@ZZJ%UZa5!*mP+^o>n}-GDx{G`)iY-F(bKuogOUmb$_2&e~ptb2ojdK%9>;+(%vp<>M%4;d!YK09eBT zl<^Pp26hD;Xz+#+fE$!FU^1YZSU)sgFDO_K<6;nC;0re)_(QaOEil?TmMAN490cNa z2`)Dze&5N`uV9j%Z{Xw%gW3ekrd z08GPO@c?r;8MIb_jHk60V3MF-GEOKkMizL}+68W4;QO8 zat`uT^f3wccd@j_O6luE%;j7R&7|buFo+jMQ#Zgs-o(_$-`w29!qxYZEky%}G=Q6y zdcgR2g1L*9DL&9!+Qds+-_=7}P64n4z=})xqok!RJbe`X5vB$}OAzYP6v_Y&0Q^5T z^j`)Q`2BA;Mg}%OU#CVy#7(55rC~;}+s?mcX*N6gZV?li%*?b{WPnrtWR0&`6n!fz48vdH!v~qT^ zHd>&z^o}H(h~9x%KazYPr|SWWjMUvfheCJDZChWRT-4S|-Ff3rE+8OK|AUvb<}UF? zEoeg3?A5@(-%+Ucm_3(7RES1=Rk`lq`D{=K6ui*EzzS9cfMHD6(;=`gXoGE&51 zBvfKWa~%I6s~~Ii_;g*|=9Sjy)7va`^dJ&TvY+bznt{|60S7)3^GeHmh*VC;&lM>6 zN2edIVF1B9M0~`^zq#&GCu?bG=~`Ie%#yU1PvgWxWcjdF&PAxAIp ze$P;rqzfH5?ga+mA^@4aBXi{+Hpb|QX=!PtAP|JQdgN2BUPnH;D~wS(`B#38{zo=Y zVqud~bpoL!nsfS*D*f0S(BTnHZ2yWO;c$kl;Ost#^_NY->1Z7b?G@9EZv(DR8DUk! z#zorlmf6q2#S2?O7M<7czP-J>Mc6n6+22>aC8lE5dG-7HgV;zN3R7o;T#nyjiAB!U zg9CZyfBUP?4o20MvJzQ_K`G58)(lanlI>kb2reTPdumG?SLovh9*&+5Z!K`25DRc$ zyEj(r6ZV@idUE%CZ)ug(Od{v%&gQqQw{oZP_q#SoTk(^#4DwbL-8>7YA@AZ$eWdM_bEVH0<+3jr zKs;q1MV=-Uw!V|NG^XxfDMhkj`hBS@YNF7^B{>(EB!3 zq=QtxZpMt>>ol%x?5u+mz6S~HCh!@|Z_74b@^cUU`C;>3-w%z>uO4bT7L=7o4>a!F*0Xwn49CXOo_bg*yyu$GBKNA-O z_=kOz+O7r3K2Y(MY*deoDP-iXaEyv6WKBDvn+D)TDAx>MC<1`Ux1w&6zXe2;8XmF4 zz(t{f$>S1QVr4?dIe<<1#%buW3mkY~mfVR)h|2BPEh?b(qmQfP8(u)Cg0R!|A1>(y z9K}eUef?lp$^*2rj%>q%0NmJ25x05Fa!Jqk0O%oaI!P92)$MuGzMcY%IA7;7Bz@US zPITSBMof>r}PxtPh5m|xO zOBVbQT@KL>T3RH3wY0c{6K}pL>3d9-b4mGe=)Wn|cVm_&B|FMZR0KEW8~bv+;!qE# zngYbDZ587l<^FmJ+gclS$gF=K>E~_e;F4iq6-wtf9=Z!@3F^O!%xTv9u#@mcP)zJ5 zf@WK*!JH#qDIiB{+UU4UPH$~_^+3?ax(>A}p1x9)RJv5{eU@J1#FNeJN!}S3DR<~i_glF5SH<`s4I(SMn$#Ps)IXXV88OLYs+VPH~IbcmZzP>?i>{iCf(}K z=)2X*H%I@;gE1uN>}u^XqNS< z_Re({^4E`&*nPIgye+>E-p5Xh@1KVfF;*?4NQh%fV6zfaofw&qWqPSaCC`_;eu%e( z@6d@@)ZBlqC(mtF@4WuGgO;&sntCyntJdS_);CGBo1x7(t?y!1`!y>RnGzPl*ZTrQ zzdK!2i<6O4!=H1WgWbP5kA1;*=pJ{5oloO>T%~`)VNw->soG*6ww;auI*SkZZnwU$Zq`32B|D&_?>3lCfL= zIjZ)(g^+IE{Om*z)ugD9StE)3u4>Gc+tx*THTR}kJZa6n6e9}@xe9d`hPNh-iv5G9 zsMu0}KB`DkEnfzKmQq&@WMb?O^sS@<2ic9EC5w@8Ep*bqoFCZ7PT|>0t_L#AHLMN9 zP`af!e#M4{?FGk)eBN@HnR8h_ZEddVd7i4e7rqsP$r>%Pd|#j48P+gJL%d0K+){() zDW^)@pLO72R^#n}ssf8LC}_d%u}yMlP1X_iml^4q33{YX2X0omQ+v9O8mFh@Gkr(h zyNAD6o~)5Fmcx!UGB8%o36yajFo`8Pu9P{heg6!-8L<9^rfCb(w`Av4>%3zy;o&Y? zt-SSzS#<$7{!)_{A2DfnzZTnlgYQ(3C6Mzqd(6!I><{Lt5(abJ?daoOJIV{2<9yi2 zonWJ;X#O|H9EtCSXVK>rf;_~KAF2snTUm}nZ(OEow@BVboF^Xredr=0bRI@?L;ZEs z6a4tOqVH;*hC>%5Q!*1~cC1pZOi2s7>oMP<{H4a9E-LWz`k2E~n~ z$m=}ur_`*;PtW5@yfQ?}&6*gM0=ME;;*OU#V?HV1S0(21BrCqv;y*)MlZ)h70L15p1r$u17FB=GU(G3-}cq3 zosN^~qR^8XO9j1eStNfRB=n3m9dqB{kU_b14grV~E1&52|3I1$agwZ&f|Pz5mA)DE zQ5(ouk(C@^;I0hKePLFsWcncE)>pb=5H*sf8Zo&f9L-JMC?dDHyw|a_Jfkdm7Q=jt z2l4jhahEYTx^Qg>r=20sQEjJkpEfYR_jda13#U_XafBdtHiDW#WD-OyWcpo90q-m+ zUuE||w7Fd?U~FsERJOwWhQx6je(|8p*VFRzxmCleb{dH9iYpo|QsLe-II~o3;gGqp zGhkZxq`|UKyV}g>&Kp`UrC(-=>()m(@s^_ns)=~b(B;3mTrB}TFtY9`g*4DXTL8zw zW1Pl4C=5S4&j8bV-2J#oFB6*98;lLq48Jb=yy8=?iB$l#b3UpBA3beJiDpM-|Dj@GgOR1M%yD?rg!Rfb-<}(L5lp3W%FG$V-X|Mu7QsH# zii{t8l^^2x;2f(koD;p1YyPedmT}#rjk)>tE`UN#OHhv5I0~k9WkhOsj87147tUwo;PZQWA8<$t^u) zpBXS%1wgLyf6savz{jZL?EpS>{flttlo9T=~q>Vk_e`(C%p`^>lY^RAeBNb>+2)G zh8z*Q8nC7q)4RQ0J6Be)SGvCwCy{vSL2>dsBTmS;OeIe;A4Q>oI{suLtK9xI=)2_X0|D{bm7}3G zce~~XCS(=Md)x0dzl}IiMO@Uh`1}!aolYf57-|rtPDose-~WV~LGhCqa!x1p)9fZT zWlTK19Zoc>^sF!QAm>@i$>G=Au9DXMP^0!mm+3ptym(HO&mezwex+IpbSIN*BLVH1 z=$$TjMZR7IYUJ_~{E{TBMI4YP&pY-#eI-lftM8FY%8$i+{9A!MVq!OL&wN2lC!zvG zNSdqdV_z~EI*sRWXcsKpn75vUWiamax>8wZG_UOO*ZoHK3|^b63vL48MzTiH9|yvh z7iS?giAUkqHs$USf6p|giJwUM^lBZhE8nCxg*z^eAdSC}c~1qiGgM66+`6TspT0A& zCMfcS;c1I6P4EH3P17C<9&I-0jNFS`Ki+2x%eWeF-fN$Q#BZ!Bb9x)`lX!T!6czJ> zoilGoMRg>-Sm;^vULK6efRa7rws6U+c-=UXzWn}CzqM7uGo)y5ntWR3OEV;vHTdsg zktId#2aoHN8eSK#wi4P;qL&7*y{z@@u3#RwUTb(qp0xt*PodsEn7V?)aMU)*yoXk#RTguE7 zjQ#2UG}@gJa6CDL*)p>u?I<+*SR#hxw~Y6qwr8U?EFPO7d?w0BOWpDs`H-g_V) zm0hMA^Lwb7tccbER;&IMjSjKGKb=1f!kJMN4*Wj(`I~-5wvw-`+`}_FaJ70qklB?* z#_`7?eyYv2t|jlws<>T)=C;wV^Y#0WkB07ldAFkyrn7pUem*8ZP6wT^ZrT<2q9`Jt zWV9-Ss+d4qX9Z4vG_d|j-)`KOS%$Bf3yHB_{ki;LNR!7h;cMg%as2Ny9XzGiM4>L` zbIwt(S+fWaVScq9G&_OwMA|emeOBsIjOw+0WUFKiryc#hWe8hM6L}h3dEj_h=#5^X znSK^tb-o*K*~5|xDm{9fuEy+s8Wi(9wh1X47`jj1&0rvk|Fk2({#Zc^oF?s}>pbLG zWI`6WJx$v@k1HX(SSF*Qf_;Ab+2{SiEwTFkHbl--&qckiW}^1(tW12BZ9TPQL3{5R z>cEURh24-bNo){bltgn4@YU5uri&X%4uSoYv=l^8Sm+2QPr@obB8JU}(uZ)b!H@ibu%6`T~v?tUl#sD-lL}ZpdT{cOs)aKIQbG zk=#4hWww2IWZZbVq^s-qy1+;BInE!lb=YC_tgKOEX&`5*A!b3w8FFN?VrqaL-X1G1 z(OR+0Q>Tx5r(*v5;o-297zzEUO?vI=1Z`C657pj^9q`MjZyTXqK_6ZfBr9`16*4W7 zRs9nNE%{D0{t9Drh*{(^zI_8u(!UzJN2!(yY~sb zQ5l*=rQ?DblU1$xzMdbCy#TYnIqBp$>5M=W>NQBLPrT%nubGKjwRz0r^`1YV`a zsWJwljwASyIVvZHJJ> z3-%w2uT#ZeHgiW5olQ00Rg-pm|3En9mk_G@Ch=9`x{n_G2Arzb4)nh>-*&m_38_pT zfbNZ-BkE?7*++9YFjC%23Sf!))qz+&Hwnl6ZT^$>1KLLw7H>0O|5`r9;}bE_4Iurg zT{Ziv2oh&;k|Ubu-n=Gc-B+L2Y<)>jw|3(ZLN0%%jbbveRljh&uu;}aXAm(b`%Uq^ z=L5M6ekDiwdI~EUjYSaqRIt$**g~JG!2kBWW87j%grKt6eB(`&CklSBDQ;A&tud9n zPLnkxae_M!%bD{(O#YxLXgZXd7SS{!zpaNlu!f9F~B$=2<1rZ>N~V*hfS z^4_-!Ib``rI+>4i==n+2@^^x&GyEKyyet7ox4g2omZ-+lq8&fT~`=IW`@JAvRbWM7nyNiz~ z)4Rp4em4w)zN8i(_gh;0bmeBUNaahW>UU#!&9oXL)ekxAkrM67PD|_eM9u+UiAxx1 zf}UyfU{)g#8?dX~3JJGd%9ZL^*EvQ%C90VM0joHT!8ni3jdwgwd+;%nv%dk8N1!f(WW69)S7CcQ67$!FmFlz!^9{UW%fxv}(M5 z@8076V!GGcAZ*_CWR{z2l7MaSc*^#l6L-}Y@lUb}Rr{vwS4#p&;ofP$!TYK@2ak3{ zTGC@7R{lcHt07&lyksWCj45T9M%44+0nwH(O&(SX`5X9Eq$<;jj77cb(_|d*kSyK3Qt+{YN zO0#i3p7s5Y93CIbXrpkA^UUd@aS7Bdp!%#4c&Ru)H7jhig(_n<+1a~3Cuh%XU1@OSbyHQNVTs(bqWZ4 z$Rm2$W)6;CBHg8dW*e6XuZ1@67I|!yiJX6u^{aZ=RJV5MePdJJQh(@Sq^M1uSesp& zi8*A2E{ek2f4Ew_weLE2#l!FQgV%N;3%Weo42U(-2>Y8$8($Nuhg-?L3sl42W?ylN zAu0_Gp+eU|=r2^E8Qx&Kps z`8H)uap^&nTXRMCl!3SpGD?m%N<%G5OAfdAx_vOwabEgpEP|l+2)ehk)yzESMK<^J z4Nve-=i-MJFVtNsXPX#1dBgifNmA{V1->wdl&QU7Eh`r@c_x9V&O^`qw3w27HdXv$ z=W9Dc2#5iV+CNe&ISQJtw~0Rrk{xEtZBHvub3~(Wi9~u^%r8lK$iwy7Q?9?F%6ug8 z$7-ory-qWSo8KU=ss6ZyU-TKixm}#`o&wew46@~EYE@9 zVc@enC*Loqm<;WE*-u|{3|%ZHciwpK(hz2JSm|LrTi*z{hI(_%ya==d80 z40u%^!|b%u3q;k{h(mRh042;wX}5m5fx;}{?41_sk>Kj*noS!4*qEe8W399|JLQR%ajyB3tf(Zj zo+%Hfu~&LFEp`EY%&m1kq01DbHcve%H6qj^%p|R^Iz3N@HUG8!8q!B~zmB;rn$*;x!qMHcGT&ZoKSKS0qs*ZtO~aXu#XFeND3&zt#|r5vKe)hvbZ@ zv+i-^ZIj|F~@RDRrmZ zR*n}&SFES|JX3{xHwGGa&k7VIXS14WByp0pyG z8(cc9dLK?j;w4{XyL39b)AN~f1WFdTyNG;dOShUx(AF0zi+xWGwrOyZ8#EUYl}~OX z{2>-?t^%C_LCS+04w8Rhz>y_o5Qc6r-F| zqZz71*`@+Oz!$GwnMRZ{C)xkvpf^(vU)bc+kfjhmERt@6 zC0^@TyK2l}x?1o<5WE1mC3P7&XP+{P_7=WXA+$MoZ&GQJlzEb#>S) zpKXOSnF+)AzS={?wDJ#*UpG^j_9e*7CvgjM|9R}QVDH+0!oWN>N~1W-MQZn{O1VI9 zThYq#)6^|l_v;~|1DntMj4H4&_UTT|Hr5|+pExZqIV-t7(>+qkmJfQ;;-j}c8o-MF`5|V&{V5A+AdZ#+7NSRr+<%ZSjcD^t4dl*s8@%&2vvHxx$=FE$rs8yYEwWj z2%W)kBgj@@DI{{H=m$1xxn@N%>W+OS&)L^;mK7(de(gbi}Bsq82LgWgi|SdAn;i3Nxc_`QO&2xO_>{xn$1^f)9nd=nqh8(-mTjM{G#75fPF}kjYuG!w z#GN^aiM^n<>!QjUTE5%o@8H+2d(AN)qBaw-aW!O!oP!w&l}duin~6J;hiK}oeD|sg zkD*`x(3y{rND8_l8JH)~>v&PLvcCt!l>aB%XMOg-ZUbI3BJ&G~_UF(RQUMmBG~pPU z3%*6!-D|U~e3TDF`0tK_`kA-@Jlm&DTw4Q<k~Hxj&b_JTKC$s1HXe^;>g7I}Af$@X}yC+!^J z(Aezf&0TJR%R?pIzXNp9hBaA+fAe!|y?QA2aY|t!?|L2g{t2+ren!w` z0MRv#%?S@#KAwwND&>0!z2O?|WDWshAw6P1nCW!I5H0f9 zx>Mp+xzTH-K~zP`U)$W35z2`D^Yp;{bn!TTf%6MI&Ec!`hhH}EdzH!`pN~dfM^UV7 z=1*G6x+M~9D3G%sUw+Xh``8*YS#u|{K_bHb1;Q(r;#Co{$C0$_U)}8^dKIB5O(%tjqVLzqi_g9Pz-SyX`9nZ`VW6H_Al-;N#x0U^#*1_Xd)zCAdR{^@B z&s}HbtHljTT4#S2l1JXMjfeBX}Luxo!i1ctKN0B^W{ z^uO~wfPfMAxQG5z3lNKCV9>Chh4`NNv#Yg{uEhT8O%Oc>?F~yNg2D(F)Nh)qlcb$Gtq6cLF?OkCQAZ5h>R%RhLs9r-Fh)M*t;T4@8e zC+n6hP%AQgE--~Zd1(1kdl}dN{d3Fr-{yDdU*A$_v0%F?Voj$BpH4bHH5bAb-OOh# zPCLJZ4;>zW^Z!o2vDTx=y3zcDk|yZ6!(&vwz;IHI<3a+}9F- z0Me8#xxD;$MvrP*BzmdJ&Hge|B<(UHLSlC(nS=|q^3!rvZ!cHl?7U+s)FIMxk?FT> z!MD-fEw`}W+mxcYVN!C)XVN4y#`??BKpdjf;NW=vo~yt|FX#czvWmX;ZUD#UAIF| zW7;wSVSgqb8&_gF5E&I^Kag6tlq!uSS$Htp*Y>IBGOu2$@9jCq-Ev$nxVIG~WUx3J z1!SY&S4bY3i-fESLj=@GfONQlGOpxb`S5HoQh*ynynFZR68=K&U4XFYR`>wV3Dt<7 z(ZAE-aXyN0fx?GfS-ZRY+das`mtZUNOd!1_Vyi@B&dWo1`2Iuax z3P4zt{!#Po7yuB4LU_Wx$6)llh28Eas!$vhiMc&jMNcP}XL zJqexRQbH=}S@_9-w^w0tKM;K@2-R#e6@^N13*FdCQHivQl`Xd(j18h?Th<2Gs*d~D zZrMtbkX-MncEM*qlLOasZbk%k#F03p_Uo2{ha=IiD}G9#&kdi9BeXwt)3n>tva`mg zFvN1-6$$pvbmnnC)KsJ(sv^^ff#nEv{9V7AxHfbJGo(N85GaUVl=pwFk+wXyw2^^OOiBOfmlFTKV8u)@LPjW?8Db0L*7o>*mhT*?3Ox*@*t0_}sfLim}&pQEifT3)!r$5I{mxZ97?uYlEaS9m=E zHv|IY_lwhK3)K?up8o0^Nay{XTAZGG&1qfr?g^0fCYSe~8{i6m!1ML`6oN78dbSzW z8{jB*l@PXdLDm+00FUnmDkc&(9X2Oku+Y#;2@$JB{Jn|lGAvLfr*(I6aWOhy8DXXY zJeYSGn1GN$s1b*5Sn>=BJef6yl1YLLY*~kfHSMlYK8aMN_X!GOx>ak}9%9)>s8fv_ ztOMU80QmTTDc#t%3p!T*Q5@+8@tWbQxNj!6@#%T0tid!T{TS^P&QT@eA=eC`c%qw6 zvnDIWifq%x`Wx3xl#%w0FE#cBqC!6npO62F6qy5R+?cpLTi$v#_H->NjX=kiOe&1y z02xH5;!=``s$SdzuWxM)VJZma1BsF7;g>NnG0d%P-%;ipD-J7whmaPh?F^higH_h^ zh`7Kde!bi3NhBxk%;ImIO+$15h_ox?e;NO6^KCW|YLP9&_Agoh9-qvzXrq2)YWBFa zk^FPoE2^yUOZWB$AdpPQkN(Wklo}jwT|QNi@1?V=C>`D-O4YnOK-|xLS$SqcKZ%PF zBRNu5yUxJ@Ffq3A`E+D|Tq>mC7PS%LvQUDoQh&G}l4K2*1`qYW13-MvEc1-?q7PDH@PvzWV58D6S!z53c|OK@_fR+sP2~5x-E0F{Xof`ChV*ZiFiAS9=O`g_OesoCH?62ulK7ZsqG-xoYD>!fyM z9yP!iqkKm=`>XkYWnlj60Epm*TK}BpKb2DrciMo}(koLiXd>IAmGN|ZI1dYxeXwov z?#dPz(6*4gJU+7I7za9ax2!k(KHF2^I`6bHkf1?cxs4mvc8!FcgQL$CWKA>G7VMXQ z>O`vFHFhbx!yAH?fR@s~OR9NHenk}x7f49t)d$w+ui`h(bwQx#KTons6BA<`Ow!#t zAA*<_efcEp+Jpib5P-rB4^s&mKJBfvYT!$_pIos!|RbggqSE|5T<~{$$ z5&*CjCt`hIj{tjj#l<^Y8eG@ zOAd7jy_1tn09?j2H$(K1Nc`@??VDnjQVGSPu~Cbz(8XuO5}}-`Dl0*>v_<~zKwR-}LGtoB_ZbK-=qht|WH;cEy88%!F4q(zk$c+@ z8A>KX75|ufeSfwYxAO6sUQ5J9NA|5U(v{Yr-84l%*Vh3$f&1a-e^Bu%6@SMwrK;#F zO`lT_W(wc0cNy|^F%M)}jaFnVo<-g{S~S_Q#iv=N^uhlacJ~ z_oDyPZDq2q<1Is#kd4$C20vD4kn?!l&<|CioKbehC#FNU?3(VM39^`EJF8dR2u_pN zv&vqrO!+3T@wp>k(wW%ga>rkD`F--w#^>Bvb8FpO{cN0Vm8t$mUtar>gtAF?X^+|k zUxo@}-~h=t^`+4Qvgo*T^?}sXlOJm_M2n{b51X&mGj5B;?J2@}FLhFzuF4ex=p^}I zwglz*SE_>6A%`3#-umw^qB6@^9=tf6vk)khBkqJ=-Tz(128{^U95Lx}%t?Xpc~D8P z>B<6Yod9=Bg8)E{d}MdT!{Q6q9s{!0h0cF*^KeN zip0abOW-uTXLk(%mzt01huwtN4-oGvuUV1^+!awEzRIhP-kV)pt9>EA*cI|_KAjC1 z#&;;&d&PyP+@_#VSkjWy4`GB@uOI$rV>>hw89eMqq zofxB3I7zN_PCf@M2gSX-r^1;XnL=)al0ub94>-?j^*^0bp^v`|t#GoW10eKmpPQ_$ zRgsOQ;T!DFhigyBfSPY5zP}Y1YwpsnTPEdZ7q~+Ft6L&apjC)X!ZhU9|#NX{^wNegEl6)f8 zPY^h-aVVYl2GAzTEw*9zvq zxb!_Ixk??S04U>hJCEROh6#{VJXQTrUF!c2+)nq>l9f&_(9^W`H zzj_%oIIrUAmlC;CLBJDc2Vy#U;0f3#u>bOj$mP_!FQ@ju-6;c71Wu|ynd5Vb45<#t z9RIg7(;k)U1kddLNLFCPiYp0{j>LfRh8pQ{PwN+x?YX9FIm%4s5OlI; zk{vnZ?oeQp2^^l-A%W2*G7BB&N1plkl#vHEIK-jE=04 z!hpM(rsd^-FQ!mlsGdrokn<9ofHExq%cH1w%iw1bN{!d921ED;&;;Nk^^+`fUpiV-<_)Hay%0xrdvHhqoYJW!}Dm@t+h1z@Mnt%piC{#C30 z`!qE^UR|q~t5iGv&folTJk2GvO68{hOYGeL(H7>HptEyjV&M;>aF%NupPp&#u&&lQ zFED>=dNr|0_WJwxgje(LRz3|iST~72syoP<8*f_7v|O=o*e4pXYfHJWoL5SLcohyD z9OVP9(*g&+``RU6l)9lt7@<|KfvK3K4zB~F25Xk|-kR_$wO(p;U(6NpU#C2)1inlk zQRg(V-BT}kdD%Dk0(Xz_=Zs3kLWs5pu<%C>|FZUB&wgFXSk+X~#+gTGZQBDJ=)@GY zmRb#MpSgH>W5oYX>X8l2*ZGxHpf^v#(G-Vcb$XVsTp`}` z!4J$|HPxZNk~nJ@Fs2rSIPSS4_Rrs5tE!vA->5)IT#EsPeXHa0dXv)k{qrZ|N^QHZ zPKTwifqYSAIMv2OhlupJw{KTx_sEddKfVb<-Oza%9$uPsbRW)go(R0 z^lD|V`WhL{1qUXNFIu??6YtHDOYv#;IIs6bLp8HpBjtCoDY1%hSq2r%!u9RBAXf9& zeqGYfuMrbR#24H>J7nM$5bJVTvk^kI5q%$KPmz8`@pWYWd3L)4ugD|Gl$}t6uhm-; z;wk9gfb|EwE*5kt@E;QJ%Yk$9PpxBp; z$le!z)$TKaEg(}E#Z2Mx(#HB?gWUCFTxzBKQC-kW-VZXaUCgI_>(hOVntz%Re?L|k z6}yM)bIy{wNwhd_RM-;m$F=2U!Xi<9B7y47DM%>~eH_WP3#~WXay}cq)@L`!k!hXd znyqk_r2FvUYp6AIG3He0wMwu0`Aga(8;#cV(hm3ltws&SKv@an|gk8?Li$lMi~ZPHs}+e`v~TiL5}C%fINzKX63D~MrcdYn8|zyH>mRQj@Jyi+ElV7dKM%Tjz=-R9UGmZa zHNiN<^Z-#){c7)krgyZUXfNb|6FGB(=~E})n{t-{D|$@UG_QpLew`aZQr0 zVglnP@0Zk$WSGWpZU1H?H%7ASkf|Q4M4tuwVFGRpy$51iiY`NYXcr!Lg5u{=1mJ8G zxv3wswt`CKqJTiD&2DP>ESCFCAU5iAl3o)@u}8nCo8@{4r9iV z#DQ2@ew2%Tb5e9_w|e_C+b>wF`H@kzKkYM6*#0I5MW(lSS%KiF<-I(``nULZwIrva zX_AIFc(MfoM4qX){=jpgHjm%~ZjjPJ>uaehzlyYZ*ed7!ja>42NCTr#U>k*D)`S8c z9?QDG8c=0ABq^($7f-DA{2h<*=Ikc_FQv3B4Zlr<7%X|K2-UKSi0f zx*uqH4`HE1=gMwXC&!VhUcIjLfC{Cn1WOy!$~08Qe2Oz)0?J~IqmBAzZjZJ5$=u*t zi=G`(?p1md{b#mroF^7^b|iYos(Y^XNNU@y`t9lS=UTA6{o!-;{4y$QR%E5p`URiB zsAU2KrxqU&k<4b+XVgk<9L=3D`>SfpskdHf z@-B25P1p+!CHMYuTufHPu=NW)HT4@kJojmq6sAPKxqH&l$)E!(k&9CPmG}0XEi_FU zMq!*^a#9|`WJUJS(u_gSE4nC|!v%9@8=-ycp~&NO(Wu5?*V7*vQw;$UP|b*<>K*ku z9@ly4(7M2n?;T0X>$T4X9nY5D*`53*tp$~?vzWDWfAVahjWYst_ zdJ7`}pn_oF6;nB{)i>?TN`W1ql*ao(D}x^EpW0)}r9Zx-@7o8fa;f&z8_|RLRUFL> zf%2-ZW0KP(2@+xRKL5aJlNda97fs7cu3^3P+|r_4#31H&4r6m&y;(Knff$Ke*jdyc z@#{&RTyird%@m*S z2LeXN4_v->TgDW=d0(_K57||XA7n!9u4`1dAKsmjW4l|$Nv^be+%bT0BDZeHN_)&4 zL2+tE%eSxO1&s*%yD3S6xr5A5*f@ETWw%glT|UKJvIkQx^7xeKGE#}QkZZmG+@ygL z9$~;}>g)dbvz80|gJqRZ=N907@=XOSoAHpW8E{q5pJL7YfT)I?+W;e-VPuTM@-)kG z{y%nP9k3%>>YqN@tk3nBl?jxaHncs34>;C=zJb#+FIAEM?)kwm)ab(ZAs;Q^5z%dL zPiOZV+g9B6w6tKr@pLCGUE#2VV!fNr z!>2&~8}Rbs1@Q8>BG9FBbJ9eq12u47tp;5yUo`hQ7uH*?lI6tHgH|hgBB}9Z4X5st zb?mG=tYsWi1$Ix7W-W)_YY+P<;~^dT1+COIizg04IU5P}pF_uP?CZ8MA~6D+;Ye@b zUmWDOJ1k5uXUy+zdE5Y!tqc=*12Li0P>O$IHwuqqb88r2Ukz*33VKWA%_niFx;)6B zTmG31$Q3Spa4ff~s2gxcSYRx{6WJ~|p)%aqE3j?vT3Q+eO=$Fioptg>? zheG4hC3Y6?*E|FMdH3wra5x$`IHvW({)zmM5nm43`Qt4E4g1_z5~V13vUT!0i%FP8ecSgWmQV+K*Q` z(a*g;zDenp`WDy~>br-x-?*i(KOZ`3wQTc^Q`kzGnTyG-yE`fz9T%76x3>;jZ`ocQ zc|`T2nKN;6&^Ro46UE3d{Nc$5^aH-ltNA?Z!Mnn9bGs!v_bV*F%Tlv^eBQUyYAEH_ zEuhdElITaiaig0RHMI0SACcYQ(6Ce=d}_=SxNv%M3zm4(vh^@x?Pt17&P=J_-}ORI zB_iwb_^ONM-E8TOniED2YmS?TrYD7otnGhOs5`t}Y}iB@4M6*#W?Fj2rTPQ$Oc6Vx z16OJ$oMMsYGdIbpc-_?`N(29{z;BO@LdRp40M|~P)b!$iJ-cGbW3CROo$!w1CB+=M z>J%%}>yBF^D?Ztsw6Dd)YlA=gJe}UeWzOM_B%i48R*NZJD-`1(YRN8_-NJ=zin`G);>mp_L_r zREsw1@cM%}SdQaNba=U0k%EAseF7TxGa=~Yqv){qzTOt22t)A@%_rjXqPVW=Ua)7twE(b08|Dx?JqpFO)eo=u9Y?@6; z3T(PNMY^Oxq`OOz?(PohE@@O!I;0V4P!MSZk(Lq#?%Mi)-*e9$7-e{()zxU%I!=2^BXNf(b8Ek33`wrJN#e1q=XE!J<;{Va{Kee;$O_RD2pX zQCD!S0c+Iwp}_X8n0 zmHY|MrEr!;onp-{R_Ot`Ra6z}lj;vtP9`_bM5|}MVjGR-gW4wn*Fgkj134>Kz!)qQ z{^T5gV{x``5vM8BUZj;@u(99wA7hKQ;AYjBAl^ankZVG%OsGnhL}iPP=Yr@>R;l>x z`VxI&98r_hQQz!zkF6sNrEBMNi;KtE-V&vn@?Dsmj@x?S>xwLNV0LahUiSVt_p3D( zNByPzPCBOK7mtqBX<`i?2-4 z)n=;?>a>?02CO{Q&RP){rNvDzuQpqEeRi_`i_HJ@CYD-C0`&{Q;Hl;NChHB!?b)b| zxTBOc!;W9U_;1dR$`h(FD8M}@apw8;{RitxCrlrzb$;0Yb5^=j)|o>zk;Iv;c+6z0 zTnU<*RrdXA8*8XkSJx0I$c>#zjXzLK`CmC-2Mx7%Z$_J9nEY<#^_uNU@Ig6vq2B}P z+s?MqE1w@XJen6o(#ac4zcKri-kjyW^Ny=LOQUro9f3f&?^#3N@Sk0=b$x><;$=@ zs^D@PDF&Mh{ZpNfajZs?ag}ur2RL>PHh!lZ$i0EiH2vIt95+CH>$Os7CgH|#`z1h& zg{DB?|KPu{07KY6B0B}!w3q1CC7;wyf4TYLH|5sbV=A8zoryTe!z5zkO0cB%ob5hy z)fx#)MeF4(l*^Z7vep$`7R2ao%Q=JU6zO`n&!*9AMa-k>SXPs;iepvj#PXf{b)R4R zU%GC!S`dcLvu2Xae#QHGmwEqsN|N}?hTJJzgutRpmkZuJ`B`6KZ|-~cgs8)t3f72X z?IaXHz7!jYdKe;b5jTS1S8qiEz=yd&0+skxlxv1lJpI1pP8F4_dnfaqAR^pssqLsq z3yQn{h2*QKU;-S{Xf+Xi+fTW6ci5n}s^GZeO5#*o3%wv0Hf~c+FDHD=pNd~rWldn) z@opSu@p1saj-gb*rh5P2vmd7IM92DRl?Oc1wCDZF+O%^01Q&b*4}L2feKZ>~Au}{i zD50y}Dd_YF`*(KDnr|TCX{JL&ouh4$%nvl+3?x*#59+|Q86b~)Ygb*N!3*{k z?bSS&B%L39tm9Lzn%d**-{>2qN4gL+G=!b_=d^=%0c+-W79M36bNQwvVd&XeiwLy=%_U#0!4Gin(mNSHuQCcDA^Yf$Q|XO<4$%3#5H4C3CrJ=|e4U<=U<)+?slz8}r28 zs%TpsL{7@@&6R&{w?S*r`$R~gqga-h-KnQy{v>biz5yoWe_(e;z_!4xN!WlEhHg^~BZLTO1kodbyO-@RZ0uoxl0AL#O_FUz+qK zx3+(wEDgr5Q9hm6{FSEl?Y_-S@1GZ8_|g2<67Ku{DV7FWk{ihj>N9QeE*Mg=g`SR2 znl;A&a!zS!pG_3O!;A3x_w{y0X$7Ar-@Dl< zv}$!d(8;^l6+M-qVAguY8zaC8Iw=r(Ers7+{h2p~=8YsQFx!l!A=%HC$tx<7N=wTO zo-f&fo*+RLBW_m2H?hmnkDe-FZG9lz{w>ufG5C$-L!SQNYYUHD#tY_8?m>3DT=je+ zuC;v|Vy{N4i^(Np8u%PaSYJp-`?D=jGdceee8i|y^)KH=W_X7Vl*b{ z(+GmuCTn$Ci2XY@p&L5Mbh#y2zJS#Htv=AUfKudPylij;4PMkgnTroem4<2!?hJf) z+~9!aw0v?7c(I?xXVU4~pExsokvN+0Q!yaxBv~6v$0^MRJWf z4o~r#sgMw;7HdBYM8JWz3H#0f1RM%2n|-s0q&4b#ui%Vk!C)8UW?I&B48T!W%77Gu z-1NN$N+XbWl*tg5mqBDZK#qDc5d6b-#hq9H#H3QvvyH)MWzr}%L_ZemeDOtefRnpm znR7q~G$F3=PXOC-J`{HSg@}ar3!!z6JKFRz?j!&kB z^M@|w7){gx1WJL**;XGq6gMKw39?m`KHp6C&;f^Dr=VLVfQA+IHsTk7jeiplKp2Gd zLdt-@qanJm&%%h{V^%nrY-BSef+h)xkp_`oB|x$D(gZ&K7Sez64@v4?^6S;5CzBGR zS-Ai56+7yXf>uuHl%Wpy-3V1aqkjaV zSl&K($%}pQYyhM=>;^`YUi|=4O$>@0_(q*};0V{1#BMlJGRNJPspqqo|pWc zt3#v)ZCE6gLhXoG=ubkY_U&h{3#p-Eo!$tk^TE_L|*<)g~ z-vX{6jlzG5gkSd?F%2_@e_#t%PoTHU)8t_Y0{KymR<2?jR*U-Z#|TQUHS!6d9q2n? z*$(K;V{Mqw?fWk^WmZsHORoEq0pznPm3!~{pZWj(Ln%1_t;P?_bQt1}NKUA|9a~_= zl3FZR6AFpCJsvW=)E`N$5sQ=hN@G(auNW-5cK;}Mr6n%r|6n9oR0CuC$Vl$PzssGP{$`Bl-@)aguHH6TO=N zr?iHlW_AgJ1Nd1y#%hjeJ)NSMd~pPdg`;RyGu8^2FWvojn|N@L4;@3HQ|8m_<`Vd) zn{?g3eQ0|x#T&Ms^*JIF%BFBFAmASDjO<*1K-=kDqouFD4j_qt!av&6o%UFrw~Tuetr4bprDIGml1z&dOTrNgQp%-<@18SjS8CKAf=mf7 zmQyZTytAnbVEbKG}fn>WPGRS>H$>t ztK9+pUpu^9{#?1#8otBr^1B>LWl**V2aQck`9@rLLLdaYD_tGZTr2#$Wa1wRW@5`gj-Vl_LY`%(y`#>UOY2apK49Evphb%VQ z-hV3f9GpKl(ld-c)~D4)`i(YOyw;d9=^{wz=;(REF38WHKL-yLDB~7l4A87?Z9z;; zO{aAK^AJ=j2N(R2Jc(Pz4!fs%Q1SSsyol;Ju~h#E+hr(**_W1Q7Dz$?+kYEqO=&}C zhLU56*)~4r3W-rUN%qH-$ADz{+TkImU^0mO6m7Zc#^?5C^Vz<&n}+|_B&rc>b5&1Z z1O)FJvC)Lnh7u^Ew5znt7i#r^+~V$8W}stO`~E!!0Hi{?T>-2i7{iVgRALvEmeM)Q zR}XUI#P_DN>2kYl$kyv5vxTB%7#${_5L_Lvql{&6U|o+TfZa0|RpImV@on0hqfp6% z4n4ua_duR4$MP@(Mi341Um!Vt^83=6ZvT;2HW==KQR$ah)c&dJN9LPZF67uhu5ubZ zr|+k^krJR&(>(5pG*oB*-iuFxD(U|O!0Rn&NvUal?(!mvI)4sN^M#N? z;Dtn!-hUgG{l|p^YsOeJ$FNXR9Jo9u+eK|lF$Y$jkDSrJ-D zp+peyHO`=TcuAKI0CEOTJqP96K$GIGkYb2=AKwEA8zN`i#~JL|!mQ;0SU40N`g8F4<^&&PPbxAFBclD>@+|lGQ>g-; z(@G~gu&=|FF9Zw%Xh{sQgtoSSW*%a5=5Lv zdeFYHbT+m{e}L4{#)!h9U@V_6#gZ~`1IhUX*Ec3z2Ft_J+*R^IzparC7&QQDsnhpd zNrj@)VY(&|w6}=SI#POndPr8lHmGw5R+ETbp{F~h&1lP;SoV*{!rq5WO zzNi*nu!6UzLs==lPizVIl zIM$%1TW&#Gz!Wkr-E4K{Wgb!d#!l`}`U@XC8+vz{X zD0&{q6N`;IJiUKk)afZacCtI5 zX%>986n!4yg3$-`6M)0v&z7r()zs9SK>Ln0g1lFA@Mh<1-oAZ3x}pAa^+`*SCGy#e z%YXplVhNPwnq}`YZUJ52GIfu$7iH?hXH~)g6KG*f{S>WjucB+<*iFWdeKD0Evf=w& zkub!wQ)Au{EUL(Usx_w@t8c^+LU&2W2|@<44<7l_3uZ7c0aK^mYLsBAu`m#HljNyi zFLT?O7;{8MK}liLgfnt#xjeXxsRZ>zDhO=}=# zq=AKS9W5Vke(}@Oz3Hfl^DLdNkh<2cuw!{ruFd)2TXo?DLH{JqLA{mo3_44b-WXl@+rHn*0>S^zM;_l}hP{K>+TSBol>O{P-oK^wqR`LtR~+>r3<-oL09T zTt)8L9Epa_tu6Y)1ZRh=Khx|4PmLbi5juw559O~Tgk58ZoC;0(yEmXRCPN_Nox)L8 z<%6N6$-kDP>E4M9l>6Od=j7ycyfKL7f~{oq5p*o*{w6=x+60H#CnU)g zC@ETI7><2jyiYhK8nPDbbsXR))25^G1NU=L>OBb|Z*EddBoT3;T@FfZ)F+e_{lN8= zw|xJ*n3(qJ%t*a}L`~SQTLuqK?Kwdv|`Og`Fuc&W6<1PMUu)&sZhZTTc1h{c0;l;Mk>+UHzU< z843ffj0<8Hrk4MkMf4*$c=^Gus3c9yW0KHRGaDuXSn?OQu<#;)kQd&d?;euo7MDJ~ z6~U77*-0w>goM=gXv!m4lHetPiuaAH(ZgwmcOu)7)xZ9rm;U%10NW#qGC~?eei0^b zq8KO60jN2TBV{8ivaA2|zZO!WLX;TrOM$m9>_A0;7!)P!Zj%#HG%?k%PEYgSZ%e)R zuwxDxI6(%%BaGN_!IadyuH(QR7qLmO{01V&NHPc<>J;zT%`^flmjJ7_22&ekUBR>Q zlQ-RDzA6>Ae;TEKN@?>if5jbQ2idxk%(NukzNOfdbGm z?+5OWh6hs?Qtatm1Cx%iYJ>z@!Uner9~7`HV*N)Aw1t=5XUYmwodz9 zity>l>9jw9)iiUT$nnzt-AlT-$D5artA$nmLG+AZb5Xz$20c!DdFfw5?l!%2zMN4$*48-nX|F^Tz z+SUe)>$l6UUi<)n2WmqwTGJ!Ukj+kB`Klv0(t|A&SQT=LiqO2gyfbk;O0)OScnTq0 zP~rC;z_)=9jGe!3eDm8Yd{_H)YqV*h?MNatMKm2)@`|rhJ{}*hl7CTDyyxm)#8eh^ z?OInZ%?*bmJFf(UKRw)6%uw;$)ag^$bE)9+;b{^s8!JVe2xeb}dSQvhV6509C$k>P zSbK9XFE1iiZN;8&0IV%md|78uJ97ElL-zN=x#f+%ogJy?{-Xr719G_Po;G;}JI}>R z=kI%$xp+^9DqS@0oP!@cXW@JL{-q(hMrCliQsdqbpWU31)w_}SAf`pR`d6JrrxYRR>+92d z_dK65>k4!|k(}J&x1TWs$wWA7mjPYn)u4Ejn^e5SEs6fe6hYNJJ&7-zO&Ef{GMT*D}5WQ4fbdw>K2PKADk1(%PF_65jq&x=I&O&h9zCE*xW%q?^5-doKA>jI zfp?r!wBdIi91NiDYI(x63uvr4ptacLhc6n%PSd0#L+ZwnUPlrZ!)WM#exbM@@{w(S zAR4T4<80mcSN4A|?q-K-;7%DKb+csN*Ki=*>4;=koyw{{@w(vsVYuca%~A(4^B{o8 zdt2B>u!N>_r|AQHBV|ThCdk&bu`% z1i;SkM06~jGae+cXdFr0GzG3CE?y&x#%}opd4<#4z3>X{M~Zqdv3}_4{lW_i;`M0_ z-w3y@pDGm9%L|WFiZJw#>G_RqQ108@eH$-Zh3eH!s$n&+rvdX%eyVzSsC&1ios`8F z$xf*x{AM_FBn?>Lpm5d^hxLKN+~c!FHUMU%nrBV#9e*4EWAd!!c2&#kj$c8kz`S8g zV~J<6^rJOLPU04?{@R)}_3Lt3zusn))aB+a(gCDO=+kNzRO|R~!5RMGQD9`G2b8JRYe{p|8#VcxN|L#M|wUF}SAb_V%Li(Z+VE`a2tobQ<9+ zEG2EH1W%41W~bxCP+Z&)FD|a8=O(lGC_^fzgxj#740f7t-F=Vy27+$W4 z?L&D*$;ru?_3+s}Me0~8)1E-Nbj(3+b1Sc@I2~Eftab%vPclNOC!4rbd_wW!O*xV$ z!H4xVpN?{xq7H3iZABVvdjBxo(L64J9Op0NMPO}VTK+J(Bh+htUf~_XMA>Monk4cB zJ$fFyXFK=(=SPmNLFSi6J?B@a+ic{Y-b8DLJv4vc^vav!?7_?7Ga^gVZeMg0sz{5U zOI4Mhny7U+DH-0D={+AynzKEL{g}1UK|n3;Fa0tyou|^-kw@r`c@{q22!Arfud|Bg z5KpmS1;I$}?Ue+PE_C2UzrQ-!^toR@-#GA#%1)#e6p6HYpTI%YUJ~#cm~){7J|kPd zdMHls|A8ZmrX<(?+Us?`zz+`(FG-rzHj-#Wy8mWbIwB{(-h2?E&HNMHf`KhkxZbkF z>r?se!U-1<`#kom*d2vj5`lW(ubfl;n=>Z@@S-W+sWXg#WEM*Y_a6^oVb{$h%4##- zvfs39svrhAiPT)2zBqZI-x8`zY z`|7S8EzWi{c4RZJ_(cvYX{q{mU-B8sH=f2oC-hq%^rN>ZT)VSOIreJLy*44|V>}ZW zq3w9-lcA95iKFq(hAh6Yo#<#K2>YibBR6uQspPaPNBxpBKY(P1oQc#V3O^J6FDyXZ zt9AD5nd}2+6$sz04hm7Up+HTDeWULBNd3=HC|Z=i)H&LtdY5zh<&HbZvyQ}pf{%@w z+@`o4E5;7kyPl}MiD3*XS@@u?jfAefy*-jPJPG%me2YauU4}eaA7dRlMuR+;)ga~$ zj4Mbh!10cj4}w7{)LG+gZnyFrdf}WO7y8RBnnAXm+E!&hu19Ep=>02-lV3jf3c9=_ z+(oKG4r}~<8jF)A`Rn&pWM6EYS$}T4gX{(_)&FMpmmiltj=Kk}3v&00Od%GXG!A3v zBG#PT>-_@KsSXCu!$+)#{f0Yt#5{5iM8m9~zO!yXzwVszDq23-FUiz~=Udl!4Rn4- zfk~K9&N(hnyOsNvN-s)`FS*>#;JmzqT3^t^y-!X#UT$hF^DNj7Eeo{z9r1jdJPxrf z$YDHad-0uQY<@S|U|y-z@`o=C@8k2FA^QCNSKi88`_ByK2wajahTrtuh6d@X64W3K zd9Jqq#P32=>B}n42VJ4LV8wP*6M1+6iGFv7uG@l%%^-cd^-YalIcJKyaJP7~pfy_W0TVUjM?Dk#KE9nd z*$3))RtDq`M2k3hcj^-EdtFAOuP^@mbmDh16bfBwJ->IJdpW%Fu~Dvz)>xfvc59Si z@jP*Fxmd(s*Qn)3me}Vz{OAXdM5}e*B*N-S1^QVM*zEDf&W;X_F12wVXV$NpbH-)ip z(tX)vld;77R%YHakp^r0`i)C5P){yHK3ss6>0F|9@Y;ebV+2(omCx&1^3T(E(pgnz zokYsv(Y$x+&kymfVjEsKuXNvM!%RXhjH$hEjr!Z&*=7M3?o)mUgX*=)22E+hA?uc59)wOl3xch$Omk`R`k_7h2G1dm_IVcFmk zY;qd3U~HDN4{Z}V2Knm9ZU@d2!sz|&P)1L;Kh)b!J^*!zsNe$~ahOia3TTjxp@g{o z#l})l6K*$C7W0|ZqM9WYnqx@Lh*BmhZGf2^9m4|m-rh2>`jEOJ`8+ZqpKIkTrf7Ox_{o1;Efz72!?Ns7fc^dev78DwjV#Qc=ZhKnYK+P;SmG9p0g8bRQ?kh3jH>I z7^9OPX*oK^v4QkszO0>Q?BX-2mD5Xdly>ZTdL=jkgHpKe8U!`Ck@h=BWP_i>>hs(;>B`aCjYB_^OqR?2BNBd%P1g41(uVa+t0rZNiDyC~v1ax@Q0bZhD= z0mb}QHat`d=j%a7(pq*$xp&PQ(;CX>%k5k%fiX~mlOiW#jwc!qeZIw3s?bCVyGN6eyT3R`I(1;*(=}8=F6Hd(TyH*5AP|~nULaiEp@*8hbSm&gHuA22Rwg>X zR#>nuJ08>{#TLd~O*tSxqoI5MVrPSK>I0!bjHG5{O2bbr?BtBX82>5C3RjHk;#c=G zUI#GJh}m-|K1vIyF?jQEMeOXp>-XBgq%?;5&BAPppJ^^}(a?)s34Ny~gD&qTZ}T!0 z>iLbwWKvH&vpN(i)imLufDQ_fs>qqVM}^|3aSRJly6-R=0UZO-R0WK@4u&3CeK6In zC9gH;;KPQM`F>~@7%Q5+dwH;kwSci~kCDZj`0)!4D$L@2q)FPVvU?mjZ~pj2=}X*d z4q-9G-6Zzie1RITcKSqBOq$YqO^loG6_twK&65gcLFMPaEbUh)!WBO}?Aab6LUY0V zCUqnZ)q3YT&8#6=yd((s*LEY2@US-$y?v+GAh4n$CHFBxN$CE=SbH~_OmRZ)pc4rT zdugkZ>Zaif96niduV3W(Q?CM0>iO9d?w@XBDLr+Fb3>|;)d`NK>9Tg#|7{wn;b7?X zK>kBwe*~q$bKVK4R){D^$js^N4eI@^kB(={)EET~A>uwEn9ZVb zsz^;Dy_7I)kPjIMPN-puYj2Y0K##rVgNF*-?J+pu+hhBll)0wxMd{EuAKr1i(a6w> zC2mqt{WLX%>sw#!Le780#jCzPIXAA`iLvB6FW-^T9JC~&z7+>$tJ6;IA_{8vatObD zWSG?qghncpu8j6At5a2!9$RtA3#Z<>QfJ&lu( z**4mg?-2Y-aAQ8wsVESt{mJ%q&xuH=cA1*~eTSym)Az4(H;@YXA4_j>Ey}Xbr+h5i zEEjl^OcQ9-vEr`+IY6l>1u^ja+9t}jqu$3nc+o^@Y{rUnYcQ9RUs|tBgm}~|r{yCB z;)bKM%wwT5ab)R&Qvof3o8r?^84N5F_^`62uM#yaLhO?>yp3sXLh@t6IvN-GybGy; zL|D6njQ*ttW=rczC*Qsupqo$3l;JRY)$75l|T>1D(SXrjKTOfUdnk~yrXUdTAJAW}PdS$2S?AnyC z#6Vxm+h>q~qT1$x(aXg~TGl)N&KhErv<_~9Y1AAY--T`u{0;@;{ygk3dWV5!6# zZ;1-SgO`HhkNCHV=^5!P{m=Gl#Q9fI3cF?7`R~3axgXI-AHmk|2eY>+z{x-5iDxWX zVmemC^2FRk5)X~B-)BMnWKF}0mnJ(dspE(VS^MfQqM6+S%dQma)6{Z{#_O6l9XOtI z!8wf4zs#PRX$3G%?= zMLn0FSVAj#ifX1&RUq@b0t<_j$l%;mAU@(0biK04J1BI=cmD?X{2P!RLo12co$30P_F^~!Q9y>(%VfFm|SCKaK^$W%2bJN3A?QE!{JXeju#7!lp4=oqst z(i7r6Daizvu$Us>Z<&-iys$JB>x^Pd1a+Pwv2)?nOsm#5Mu5E`2tL&&+7=&Eq(=GC zMm`ZN*LO>Yn)1?YC}v0zO~~l9~5ue=AzT?Wiezh^%S;og|r?0*e7R zOgolI53hm_5a7^#s-);1IE~;TW1=|3X%I>csxehC+YrJ!yE{b0e!i38zb{n5JSk0v zk3MwhV}8R%c5rTh81JMbMaGqopQU#OGA;wn}?_FfRKd`ug%Se6%d|_s_GXLpFkWeZ# z&LPlZSUETc@3uT$L~%=_0dvv_B~cyox_G5s(OQ}6`*AT)RhLCX#ml#kdJ_u*Fp zTR0E$AK<+seV~~78gc|*7(bhOP1{ua^UsP@xIeCRwSU0+28n6M5bGRoA_b-gc8xU& zQr!Tcs@P}(>@5~74Xtdu;9b%UOhW(pKw=@%^ZHb7maSjqq!8xlD1ZM%JmSSsq9J-GvMYIRNLU5Z zyspq99R;NnafJ}GYWGg$Kh$ip)1-p;GAe}Mli2qO%#sP-L7T*}gk(Wa{mmfSvArNV zSr3qTP2jVW0G_5>MO@obioX`sRhsxyo*1o7j&o5D3!-?T5g58Yz{Rq zcB^FbhBSmC8uio}zH@qzgg!-r{O9eb42c7KoJkzNlB(PKENJy=lv9Wj{^u?~p}qN< zC;+S}0nWFe{muR&pVedm6~M_zzYoW7*&ZXNSIwC#=V@zfK`goDkG;C1_w&z$s^>|A zvKlwyR#@7hy+u-C0Kb)_^-9TnAQ~oU-{teu=IZ*|0)S#F_3GgO?-UL&g^T=*UJL){ zwJ_^9l&!aBqM+k`E<0cA3zNHB?~m%gIugVg%NK|Mq!rj!>mcuU>wo>CIuMwK)n2p| zMQ9LdX=#9jOe`v*0bQ;DUWybTFEw?(3S-&jQN^DIFKfC%kNZvBIGb~&#DwixX(qh;cJ zW=xUg$@VlEQpmk|bgj}Q$;}=G)Pfq_HzmI3d#ye{%Znc#(5y7s6M}9)BWtl{jwT#iB^1R36dupgK`|y2PEbDH1ii!qVCK}N?gY6+D-&K;t!K2 zh|1o?^E?6gE_V#opm^Ju?32CZoQRxUBO}4Ra%>z%|<4?eiY_ zk%0KTGyvR9gBDjc-4CQ?T`%?*L1R!X(1j}+0I4iMGbxEt92}g8ni{rl|6ifI)1?%F zLYGG=tP}U`NDvosp;?e($gST7Dj;x=P)fD!Wr7O{va21(4l-j-)y7`sKBo|SUF)F^$En&p^bWLam_ZIX}R{QSU|GL8ilu0^#E$bdPp z$+n=q4b{k}39t_DW|Ur~Y-!O?J!qtNwEMq3VFnO}Z#@qTPClAD<}#cIWz4}0*fQVf zGJ&JltytZf%GrseWUf&F3hewUR^X`!viq((z+}C3*_5y87L~S{OYDCHFM6(3k&Ld*g@_~3L~Qxc{`kr(n{q|^Fg2E#E2zwttj zR(t4d#4IZJ?m*dTq_+WPE)?^_y0E5YZCT(=-3afMgOZZT&K#c5rvww&n ztjKo`h+zv5kX+(Vu4}*m^9c4;v`wf$1a`Cp71^K~#%n=KBrf<)|@mtXU2g*t`R)G9;h;{onxOHBYG zw#j@iWb`Fd9LfiKFHs@+UW6auWAZ{ic?T$ASqLtbs1=R1EF|Hv{>DHI)$7H$`&`)i z3h*M}9H^KBDMrOvh$@U50u)VbBWsm7KM<#hgadRng}j9_ z=X;CfW}W)i;~}SEoSmG&&@({KxIyu-Q|265VB#}=CATgGVIMNl!x3nff@Ga?y(`Dl zpUd?)NTN)L3W8SuU%VGbt4Z@Ux^%j)jYuE)^4lUm3)8vZl?~l{|B-}ZRCdauazBWc zW7TP?2?GfUsnul@joEGM;2@z`CThu)G>I7t`S9@2;+;*W_sM{+?5-nC(^<`eyz(%= z!uLr4ggZI-A|zg>hcr<}wXQ9X==uf{hY&C!FmEuA;|#O`50R*kmI4#q=LIfZ#LC8Z z?TkXY~0@D9jBhbP8N7`uFGUM0DmSI?C<@3hJlDp2fNOo86o|iQE9o{ymML% z1&H8{l|1RhQp{qQ^Geob_-bQZRj_zJ5^icEg1X=@D?KG$vQ>7Cjk5c_+}vATw;? z$d9Mf#CqYd^%5|Le38h`As~y@Uy?d@>{;jAb>76J1gb zR3O&K;vRc*h_D5adza3U&dcLi>Wzgkg(@Lu!71HnR34^~j5Le2sK z=OFd&`PUZ!mZaZ_SF>&i)-J(b%AT?C2<$$*vF2hykomRz(a1D}g`+0O7~|uZJa)&UV}wLots< zR=qJ_guZ-Ql)rhV-|`=`Ovhg4JoN0*Vy=+0{8AEc6!`tt-m93h0rmmvk0$8?uD|BZ zck;8(`ma%_GZqoEN8%Dze53&Oa6bTP)-LdyzYlM9-NsC1RCQ=M0;v4tM}D3FJUzB| z(uQD>T@<9i2jBZAGYr5*)GBl8Omr5bK+^W{S~^#zhzt!4U0YvAbg9%7a!@VZUQx>z zEjDO&u<6iboB~}d-LY|mDTvZRAsdf z0^C05*gU=|Wbg?8pC3fY)KUe8EBYYy63afYHTEtlIgG8ux9|e5dljk3Ak^lRp53o+WsY+8i7o9 z7r+6RO9)l&knS20Q0qXGU{@9dEUQ{R9Eg1|@!0wbwuBx8b` z>Wa4N%?lcW^Q6o}XAV~Y4#2>ej+C4nQ&(4a>aqr?&*yI!mV4MBxH@5o{Q!3=iD(NO zwemgK57U1b!7|CXKh?gRHwb2pNsNh6GYEW1HR<3&1vO-oVvB6(*cNH`i50RzvBka% z==YyfWzZY#fc}3Od14J4<$uxC*0rDR)SAt_q;tyc<;s2i98ArK1 zTa*h}e5n7^OZzN#Df&VE)DW=E285!X*$-NS^qkL#^5S7PrXaM+F$uv^P{+?oH+7Wd(E#u{2m#*DrO4`m0UmVflPn2` zL3jp-VQekUKk36R1=JS<^Y6sve0%qp5a#bWi04fGn=Y_nIhslWW!Zv33IzYQ?Z$Js zkv(PCzI?(D|KB4`sWz7lrH}yZK^Gb7KpVC@8OZ|>Dx;aSda2xRDzmaS{r%)c+ux6UJgJbV0p-}9b&|A2Eo=eNgan0xlU?{%-W_FC6_fmE~#jqj4rm!FWJP*5LS z&!b!~XW>V1^Nt04ol3h{UMB@##^r9+rGggGfD-a#uYS$sfYBc1pF3KGbjk2P2{YrO z-W0SsSP)UPr(MSndKEFgcJQmguZO%xZZbvP(^=It1&xLvOe)Lx2JJ>34Ru=0yZ z_L~-@oRTum_Wjf^q3HEXqq+He)LV+7s}J7A+K;%&xO z3LUAZL1km%M!80iBucQBEqA;0st@34KaizH1^;U-b4>(P{v@;3N>ES=dco#er^+1t z0STdKsm?o0xSFT9`=fkiNM?x0;EVgHig93dKRBXRClVrZykAz+Jw)W3`0ugEr$L3V z-X?!W|Ie?K7(eR&L`xv?x58ZEv9$OflsTPvF1X91BNlC(|14IsljWVN97Eud@$fs% zaR2f9jn&jN`Rr2sJ}j8{p626@9Hfk_cL)$tY$*5cxSkdK?xJi%KC^ab#2lJh11-7Xq4frJIk zs1qPYk0Xn{yhDh;F0TE3>v5(u`( zX$fW+n-{SNXgmj-ht9#E%EMFquKfpZW3{qb1E$pC_D_5DSapC|lDhVAq_9i)w?kp7 zC@(PLGoij$XB2FQSfMD)&vsIoUWkYl#%_mT|IwIv`0eSHYL24~l}J;|VEGCup4;6L z!3P0Xl2hyVuBq6hsi?0`AR!LBC!VkSlcq{bi?+BemOOW6+_A~Dlq>pT!&mzPnq(Ab zJQ9Ez#H^?7ih@X1^XB&>$K@{0w=uL4i#=rz#%hMCo9_-3`U)>N%xu|fthGAr)+vSG z!U>}yAC0^@PNktSs#xBquzXo3V$$PK_qMqY{lend_d1!IfU8jTbfO@Sk*(v$_IZWv z?Ll9t`tH8t^Q3RNnOO0{+U8Mjs8L^*`Qquic)k>NJ55;yy_9E514WGYwyI zm%CE>_nugPYLg;#Cxy>eTLJ04OCxgt5&E0jwn`<^+=ye;8fPj)bg^NW zuPruc_Qs;{jE390y?Fen6Pk^CFceR!n%yE<=S#5Ux5?wQF%<0B*@Up)V-avY!<1D$ z={z~~QEPIvzZj;BB%kIAuk`d(mEF?pAIp1A%VJnb^4wc{xid`Fa=d~I{qzlMGS%j; z*X4&F0zPMtt+iM~(h@Ie>^{6ix0r3A3a|Phv^dhzTl9QI6?+z(tFtL z1Kvxt0SD#uN`07yXM7CB6bbWly7pNavV)6$=h+q_CN9UnN3XlzHFU-csCy?mG5;1P zk%)k%lb$PW{^YnU)#IaNd}f6H^g`Y@geyeGjoug)Z%pGL+!3q7X%{zNB~yQs@MN!3 zl|%yJDkV4CxpmqU&txo;>o>BK1)pgdbC3U)SrrAJe*1Te!ev)j;^K=!kfMOsk`P18 zR={NOJCoTY`j<7fw4y$^vcg}4h<|;eXY%i#29B5_q`SsyVyw;2k5dkM{2v^9EFut~ z%cZuG6e?W|e??Dq{TYl0usBD&TlGRTp_=ljh>4Vyg%<<>Y0r{)E^2JLMVWh*`?iS& zwK2d)H`gd`-FzSZ+__D+0N?l(V6?Q?g4@z@O1+;d1cw9q(cJuocUi1MJv#@^m*9^&+5m)3s}~a2&aZ8z3cXU@B`JL$q}ziI1bk3FtvKS zDfT*)IzW0o9HKTh-{x8l)wFWfl=%_aJ@(O&S2?v7TLHhf_nJhMNwcwmI>x7ozjyvV zBZu3ON%Px!s!t>Oyev2yOfQY%arO-jFE0LYn=n3M>nZrA*6>VQIeYBE|AhKJ5~?i@ z1J7r9pWal)K;cWk^RZ_27biQjzZPA`?Pp3~qzc(QthG;#1@~1#iA7v5y9WYT)avweJN6_b1DA&{saObpzyqBVaw08rESUQQ#E;yJ&wIW^G

`$l{^X2ID)=5&BQ*skWa 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 Uc-kv3aDbnRf+oC1&MM@;0Hh@#y8r+H literal 0 HcmV?d00001 diff --git a/docs/multisite/translations_management/translations_management_guide.md b/docs/multisite/translations_management/translations_management_guide.md new file mode 100644 index 0000000000..cc17a779ce --- /dev/null +++ b/docs/multisite/translations_management/translations_management_guide.md @@ -0,0 +1,89 @@ +--- +description: Translations management helps managers, developers and localization teams with multilingual content delivery. +edition: lts-update +month_change: true +--- + +# Translations management product guide + +## What is Translations management + +Content managers, translators and proofreaders who work with multilingual content in [[= product_name =]] often face a common set of challenges: + +- context is lost when the source text isn't visible alongside the translation +- translation of long and complex content items is time consuming +- quality assurance is slow and error-prone without a direct comparison view +- switching between tools or tabs to cross-reference languages disrupts focus and slows down publishing + +Translations management package addresses these pain points through a side-by-side view, machine translation and ability to invite reviewers to collaborate on content item or product translation. + +The package integrates with the [AI Actions framework](ai_actions.md) to support machine translation providers such as Google Translate and DeepL, and AI powered translation services like OpenAI, Anthropic, and Google Gemini. + +Administrators can manage providers and configure default provider-to-language-pair mappings directly in [[= product_name =]]'s user interface, while editors can trigger machine translation from the content editing interface. + +!!! note + + Translations management is a standalone set of features. + Although some views are similar to those delivered by the [Automated translations](automated_translations.md) opt-in package, Translations management does not require the `ibexa/automated-translation` package to run. + These two packages use different namespaces, service tags, and provider interfaces. + +## Availability + +Translations management is an [LTS Update](editions.md#lts-updates) available in all [[= product_name =]] editions. + +## How it works + +Before the translation flow can happen, an administrator sets up the translation providers and assigns language pairs to them. +Then, when an editor opens a content item and requests a new machine translation, the plugin resolves which provider to use. +It falls back from a language-pair rule to the user's manual selection if necessary. +The plugin then extracts the translatable fields from the source language version of a content item and sends them to the configured provider's API. +The translated strings are written into a target-language draft version of a content item, which opens in a side-by-side view for the editor to review and refine. +The editor can save the result as draft, share it with a reviewer or publish it. + +![Translations management flow](translations_management_flow.png "Translations management flow") + +## Capabilities + +### Translation provider management + +Administrators can manage translation providers and configure [language pair defaults](configure_translations_management.md#manage-language-pairs). +This way they can define which provider handles which language combination. +Editors see the configured default pre-selected when creating a new translation, but can override the selection if needed. + +Translations management supports several built-in translation providers, for example Google Translate, which is accessed through its REST API, or OpenAI, accessed through AI Actions. + +### Side-by-side translation view + +Translations management introduces a [side-by-side translation view]([[= user_doc =]]/content_management/translate_content/#side-by-side-translation-view) that displays the source language read-only next to an editable target language form. +In this view, editors can provide and review translations in context, without having to leave the content editing interface. + +![Side-by-side translation view](managing_translations_sxs_view.png "Side-by-side translation view") + +Editors can: + +- access the side-by-side view when creating a new translation, reviewing an existing one, or editing a draft +- compare source and target content field by field while editing +- copy all content from the source column to the target column with a single action +- provide localized versions of media assets +- use the distraction-free mode for focused editing of individual fields, with AI actions available inline +- choose whether the source column appears on the left or right in user settings + +!!! note "Excluded content types" + + Content types that are editable in Page builder or Form builder are excluded from side-by-side editing. + + Products are editable in the side-by-side view, but product attributes are not translatable. + +### CLI translation + +Translations management package exposes a [console command](configure_translations_management.md#translate-content-items-with-cli) for translating content items from the command line, +useful for batch processing or CI/CD workflows. + +### Extensibility + +Developers can [extend the translations management](extend_translations_management.md) package: + +- create custom translation providers +- add support for custom fields +- add custom content type exclusion rules +- tap into the translation lifecycle with [events](translations_management_events.md) diff --git a/mkdocs.yml b/mkdocs.yml index 6ecfc86c8c..7d32355408 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -105,6 +105,7 @@ nav: - Discounts events: api/event_reference/discounts_events.md - Collaboration events: api/event_reference/collaboration_events.md - Integrated help events: api/event_reference/integrated_help_events.md + - Translations management events: api/event_reference/translations_management_events.md - Other events: api/event_reference/other_events.md - Notification channels: api/notification_channels.md - Administration: @@ -479,6 +480,11 @@ nav: - Language API: multisite/languages/language_api.md - Back office translations: multisite/languages/back_office_translations.md - Automated content translation: multisite/languages/automated_translations.md + - Translations management: + - Translations management: multisite/translations_management/translations_management.md + - Translations management product guide: multisite/translations_management/translations_management_guide.md + - Configure translations management: multisite/translations_management/configure_translations_management.md + - Extend translations management: multisite/translations_management/extend_translations_management.md - Permissions: - Permissions: permissions/permissions.md - Permission overview: permissions/permission_overview.md From 2aec5397af67a7a040310e897e27fbd4bca4a040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C4=85browski?= <64841871+dabrt@users.noreply.github.com> Date: Fri, 19 Jun 2026 16:40:28 +0200 Subject: [PATCH 02/15] Add events and extensions --- .../config/services.yaml | 31 +++ .../ContentProxyTranslateSubscriber.php | 38 ++++ .../ImageAltTextTransformer.php | 30 +++ .../MyCustomExclusionRule.php | 16 ++ .../MyCustomProvider.php | 45 ++++ .../MyTranslationAddExtension.php | 18 ++ .../translations_management_events.md | 2 +- .../extend_translations_management.md | 194 ++++++++++++++++++ .../translations_management.md | 16 ++ 9 files changed, 389 insertions(+), 1 deletion(-) create mode 100644 code_samples/translations_management/config/services.yaml create mode 100644 code_samples/translations_management/src/TranslationsManagement/ContentProxyTranslateSubscriber.php create mode 100644 code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php create mode 100644 code_samples/translations_management/src/TranslationsManagement/MyCustomExclusionRule.php create mode 100644 code_samples/translations_management/src/TranslationsManagement/MyCustomProvider.php create mode 100644 code_samples/translations_management/src/TranslationsManagement/MyTranslationAddExtension.php create mode 100644 docs/multisite/translations_management/extend_translations_management.md create mode 100644 docs/multisite/translations_management/translations_management.md diff --git a/code_samples/translations_management/config/services.yaml b/code_samples/translations_management/config/services.yaml new file mode 100644 index 0000000000..b198c91ba6 --- /dev/null +++ b/code_samples/translations_management/config/services.yaml @@ -0,0 +1,31 @@ +services: + App\TranslationsManagement\MyCustomProvider: + tags: + - name: 'ibexa.translations_management.auto_translate.provider' + identifier: 'my_custom_provider' + validation_profile: 'ai_generic' + App\TranslationsManagement\MyProviderValidator: + tags: + - name: 'ibexa.translations_management.auto_translate.provider.validator' + profile: 'my_custom_profile' + App\TranslationsManagement\MyTranslationAddExtension: + tags: + - { name: form.type_extension } + App\TranslationsManagement\ImageAltTextTransformer: + tags: + - name: 'ibexa.translations_management.auto_translate.field_value_transformer' + field_type_identifier: 'ibexa_image' + App\TranslationsManagement\MyCustomExclusionRule: + tags: + - { name: 'ibexa.translations_management.side_by_side.exclusion_rule' } + app.translations_management.exclusion_rule.custom_field_types: + class: Ibexa\TranslationsManagement\SideBySide\Service\UnsupportedFieldTypeExclusionRule + arguments: + $excludedFieldTypeIdentifiers: ['custom_blog_post', 'custom_landing_page'] + tags: + - { name: 'ibexa.translations_management.side_by_side.exclusion_rule' } + App\TranslationsManagement\TwigComponent\MyTranslationModalFooter: + tags: + - name: ibexa.twig.component + group: 'admin-ui-content-translation-modal-footer' + priority: 10 diff --git a/code_samples/translations_management/src/TranslationsManagement/ContentProxyTranslateSubscriber.php b/code_samples/translations_management/src/TranslationsManagement/ContentProxyTranslateSubscriber.php new file mode 100644 index 0000000000..a4229b1e82 --- /dev/null +++ b/code_samples/translations_management/src/TranslationsManagement/ContentProxyTranslateSubscriber.php @@ -0,0 +1,38 @@ + ['onProxyTranslate', 200], + ]; + } + + public function onProxyTranslate(ContentProxyTranslateEvent $event): void + { + // Read the translation context: + $event->getContentId(); + $event->getFromLanguageCode(); // ?string — null when no source language exists + $event->getToLanguageCode(); + $event->getLocationId(); // ?int — null when no location context is available + + $url = $this->urlGenerator->generate('your_custom_route', [ + 'contentId' => $event->getContentId(), + ]); + + $event->setResponse(new RedirectResponse($url)); + $event->stopPropagation(); + } +} diff --git a/code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php b/code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php new file mode 100644 index 0000000000..b977aef677 --- /dev/null +++ b/code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php @@ -0,0 +1,30 @@ +getValue()->alternativeText ?? ''); + } + + public function decode(string $value, mixed $previousFieldValue, array $metadata): Value + { + $previousFieldValue->alternativeText = $value; + + return $previousFieldValue; + } +} diff --git a/code_samples/translations_management/src/TranslationsManagement/MyCustomExclusionRule.php b/code_samples/translations_management/src/TranslationsManagement/MyCustomExclusionRule.php new file mode 100644 index 0000000000..48a55e68e0 --- /dev/null +++ b/code_samples/translations_management/src/TranslationsManagement/MyCustomExclusionRule.php @@ -0,0 +1,16 @@ +getContentType()->identifier === 'my_excluded_type'; + } +} diff --git a/code_samples/translations_management/src/TranslationsManagement/MyCustomProvider.php b/code_samples/translations_management/src/TranslationsManagement/MyCustomProvider.php new file mode 100644 index 0000000000..3eada2b90f --- /dev/null +++ b/code_samples/translations_management/src/TranslationsManagement/MyCustomProvider.php @@ -0,0 +1,45 @@ +apiClient->translate( + $translationData->getText(), + $translationData->getSourceLanguage(), + $translationData->getTargetLanguage() + ); + } + + /** @return array */ + public function getSupportedLanguageCodes(): array + { + return ['en_GB', 'de_DE', 'fr_FR']; + } +} diff --git a/code_samples/translations_management/src/TranslationsManagement/MyTranslationAddExtension.php b/code_samples/translations_management/src/TranslationsManagement/MyTranslationAddExtension.php new file mode 100644 index 0000000000..c8985f4af8 --- /dev/null +++ b/code_samples/translations_management/src/TranslationsManagement/MyTranslationAddExtension.php @@ -0,0 +1,18 @@ +add('my_custom_field', /* ... */); + } +} diff --git a/docs/api/event_reference/translations_management_events.md b/docs/api/event_reference/translations_management_events.md index a94a153a0e..0bc9b7e386 100644 --- a/docs/api/event_reference/translations_management_events.md +++ b/docs/api/event_reference/translations_management_events.md @@ -1,5 +1,5 @@ --- -description: Events that are triggered when working with taxonomy. +description: Events that are triggered when working with translations management. edition: lts-update page_type: reference --- diff --git a/docs/multisite/translations_management/extend_translations_management.md b/docs/multisite/translations_management/extend_translations_management.md new file mode 100644 index 0000000000..2a467abc03 --- /dev/null +++ b/docs/multisite/translations_management/extend_translations_management.md @@ -0,0 +1,194 @@ +--- +description: Extend translations management - add custom classes, exclude custom content types and intercept the flow. +edition: lts-update +month_change: true +--- + +# Extend translations management + +By extending [Translations management](translations_management_guide.md), you can build custom translation workflows and adapt the feature set's behavior to your specific requirements. +The package is designed to be extended in multiple ways. +You can create custom [translation providers](configure_translations_management.md#configure-translation-providers), field type transformers, exclusion rules, and UI components. +In all cases you follow the same pattern: implement an interface or extend a base class, then register the service with a service tag. +The package discovers and registers tagged services automatically. + +## Add custom translation provider + +Before you build a custom translation provider, make sure that the `ibexa/connector-ai` package has been installed in your system. + +To connect a translation service that is not built into the package, implement [`TranslationProviderInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Provider-TranslationProviderInterface.html). +The `translate()` method receives a `TranslationDataInterface` object that carries the text to translate along with the source and target language codes: + +``` php hl_lines="31-44" +[[= include_code('code_samples/translations_management/src/TranslationsManagement/MyCustomProvider.php') =]] +``` + +Register the provider with the `ibexa.translations_management.auto_translate.provider` tag. +Both `identifier` and `validation_profile` are required attributes. + +``` yaml +[[= include_code('code_samples/translations_management/config/services.yaml', 1, 6) =]] +``` + +The `validation_profile` attribute links the provider to a validator that checks language codes and payload size before each call. +By default, three profiles are available: + +| Profile | Used by | +|---|---| +| `google` | Google Translate provider | +| `deepl` | DeepL provider | +| `ai_generic` | All built-in AI providers. Suitable for custom AI providers. | + +To define a custom validation profile, implement [`ProviderValidatorInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Validator-ProviderValidatorInterface.html) and register it: + +``` yaml +[[= include_code('code_samples/translations_management/config/services.yaml', 1, 1) =]] +[[= include_code('code_samples/translations_management/config/services.yaml', 7, 10) =]] +``` + +The [`DefaultProviderValidator`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Validator-DefaultProviderValidator.html) class is available as a reusable base with configurable maximum payload size and language code regex patterns. + +The package also provides several specialized interfaces for providers with specific requirements: + +| Interface | Purpose | +|---|---| +| [`ConfigurableProviderInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Provider-ConfigurableProviderInterface.html) | Extends `TranslationProviderInterface`. Adds `getConfiguration()` and `isConfigured()` for providers that store API keys and other settings | +| [`AiTranslationProviderInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Provider-AiTranslationProviderInterface.html) | Extends `ConfigurableProviderInterface`. Used as a type marker for AI-based providers, it inherits the configuration methods | +| [`TranslationHttpClientInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Http-TranslationHttpClientInterface.html) | For HTTP-based providers that use a REST API pattern | + +## Add support for custom field types + +The translation engine works by extracting translatable text from fields, sending it to the provider, and writing the translated text back. +This encode/decode cycle is handled by field value transformers, one per field type. +The package includes transformers for standard text and RichText fields. +To add support for a custom or non-standard field type, implement [`FieldValueTransformerInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Transformer-Field-FieldValueTransformerInterface.html): + +- `getFieldTypeIdentifier()` - returns the field type identifier this transformer handles +- `encode(Field $field): EncodedFieldValue` - extracts the translatable string from the field and wraps it in an [`EncodedFieldValue`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Transformer-Field-EncodedFieldValue.html). The constructor takes the extracted string as its first argument and an optional metadata array as its second. +- `decode(string $value, mixed $previousFieldValue, array $metadata): Value` - receives the translated string, the previous field value, and any metadata, and returns the updated field value + + +``` php hl_lines="19 24" +[[= include_code('code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php') =]] +``` + +Register the transformer with the `ibexa.translations_management.auto_translate.field_value_transformer` tag. +The `field_type_identifier` attribute is required and must match the value returned by `getFieldTypeIdentifier()`: + +``` yaml +[[= include_code('code_samples/translations_management/config/services.yaml', 1, 1) =]] +[[= include_code('code_samples/translations_management/config/services.yaml', 14, 17) =]] +``` + +For field types that require metadata, for example, RichText fields with embedded objects that must be preserved after translation, implement [`MetadataAwareFieldValueTransformerInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Transformer-Field-MetadataAwareFieldValueTransformerInterface.html) instead. + +## Define custom exclusion rules + +Content types that should not use the side-by-side view are identified by exclusion rules. +The Translations management package ships with one rule that excludes content types that contain `ibexa_landing_page` or `ibexa_form` fields. + +### Exclude with custom class + +To exclude additional content types, for example, content types with fields that are known to behave poorly in the side-by-side layout, implement [`SideBySideExclusionRuleInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-SideBySide-Service-SideBySideExclusionRuleInterface.html). +The `isExcluded()` method receives a [`ContentInfo`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Core-Repository-Values-Content-ContentInfo.html) object and returns `true` if the content item should be excluded. +Classes that implement this interface are automatically tagged via autoconfigure: + +``` php +[[= include_code('code_samples/translations_management/src/TranslationsManagement/MyCustomExclusionRule.php') =]] +``` + +If autoconfigure is not available, register the tag explicitly: + +``` yaml +[[= include_code('code_samples/translations_management/config/services.yaml', 1, 1) =]] +[[= include_code('code_samples/translations_management/config/services.yaml', 18, 20) =]] +``` + +### Exclude with existing class + +`MyCustomExclusionRule` targets one specific content type by name. +To exclude any content type that contain specific field types without the need to write a custom class, register an additional instance of the built-in [`UnsupportedFieldTypeExclusionRule`](https://github.com/ibexa/translations-management/blob/main/src/lib/SideBySide/Service/UnsupportedFieldTypeExclusionRule.php). +Because this registers a second instance of the service with different arguments, you can't use the class name as the service ID. +Use an arbitrary string ID instead to avoid overwriting the package's own registration: + +``` yaml +[[= include_code('code_samples/translations_management/config/services.yaml', 1, 1) =]] +[[= include_code('code_samples/translations_management/config/services.yaml', 21, 26) =]] +``` + +## Use Twig component extension points + +Two Twig component groups allow you to inject custom UI elements into the translation interface without the need to override their templates. +Such custom elements could be: + +- buttons that allow the editor to create a new translation either in the side-by-side view or the standard single-panel editor +- a disclaimer or policy notice that the editor must acknowledge before a translation is created + + +| Component group | Location | Variables available | +|---|---|---| +| `admin-ui-content-translation-modal-footer` | Footer of the **Add translation** modal | `form`, `content_id`, `location`, `allow_placeholder` | +| `admin-ui-content-edit-translation-select-footer` | Footer of the **Select translation** panel on the content edit screen | `form`, `content_id`, `main_language_code` | + +Both groups follow the same pattern: if any component renders a non-empty output into the group, the default footer buttons are replaced entirely by the component output. +Therefore, if your component template replaces the defaults, make sure it includes its own action buttons. + +Register a component with the `ibexa.twig.component` tag: + + +``` yaml +[[= include_code('code_samples/translations_management/config/services.yaml', 1, 1) =]] +[[= include_code('code_samples/translations_management/config/services.yaml', 27, 31) =]] +``` + +!!! note + + The `admin-ui-content-translation-modal-footer` group receives a `location` variable that may be `null` when the modal is rendered outside a location context. + Always check for `null` before you access location properties in your component template. + +## Extend the modal + +If injecting custom UI elements is not sufficient, you can extend the modal itself. +To add a field to the **Add translation** modal, for example, to let the editor choose a custom workflow or pass extra parameters along with the translation request, extend [`TranslationAddType`](https://github.com/ibexa/admin-ui/blob/main/src/lib/Form/Type/Content/Translation/TranslationAddType.php) with a [Symfony's Form Type extension](https://symfony.com/doc/current/form/create_form_type_extension.html). +It's the same mechanism the translations management package uses internally to inject its provider selector into the modal. + +Create a class that extends [`AbstractTypeExtension`](https://symfony.com/doc/current/reference/forms/types/form.html) and declare the extended type: + +``` php +[[= include_code('code_samples/translations_management/src/TranslationsManagement/MyTranslationAddExtension.php') =]] +``` + +Register it as a service: + +``` yaml +[[= include_code('code_samples/translations_management/config/services.yaml', 1, 1) =]] +[[= include_code('code_samples/translations_management/config/services.yaml', 11, 13) =]] +``` + +The extra field is then available in the submitted form data, which the standard `admin-ui` controller passes through the translation flow. +Use this approach when you need to read extra input from the editor, not to redirect or replace the response. + +## Intercept translation flow + +The `BeforeTranslateEvent` and `TranslateEvent` [events](translations_management_events.md#translation-events) operate at the field-value level and cannot redirect the HTTP flow. +To intercept the "Add translation" action at the HTTP level, for example, to trigger auto-translation and redirect to a custom view, or to bypass the default flow entirely, subscribe to `admin-ui`'s `ContentProxyTranslateEvent`. + +The `translations-management` package listens to this event at priority `100`. +Subscribe at a higher priority to act before the package does: + +``` php hl_lines="35 36" +[[= include_code('code_samples/translations_management/src/TranslationsManagement/ContentProxyTranslateSubscriber.php') =]] +``` + +Both highlighted calls are required: + +- `setResponse()` alone does not prevent the translations management listener at priority 100 from running and overwriting the response. +- `stopPropagation()` stops all lower-priority listeners from executing. + +When a response is set on the event, `admin-ui` uses it and doesn't proceed with the standard translation editor. + +!!! caution "Internal `ContentProxyTranslateEvent`" + + `ContentProxyTranslateEvent` is marked `@internal` in `ibexa/admin-ui`. + While it functions as an extension point in practice, its name and signature may change. + It may even be removed entirely without a deprecation notice. diff --git a/docs/multisite/translations_management/translations_management.md b/docs/multisite/translations_management/translations_management.md new file mode 100644 index 0000000000..468165d855 --- /dev/null +++ b/docs/multisite/translations_management/translations_management.md @@ -0,0 +1,16 @@ +--- +description: Translations management brings multiple features that help managers, developers and localization teams automated multilingual content delivery. +edition: lts-update +page_type: landing_page +--- + +# Translations management + +Translations management helps [[= product_name =]] developers and users deliver automated content item, product and product catalog translations. + +[[= cards([ + "multisite/translations_management/translations_management_guide", + "multisite/translations_management/configure_translations_management", + "multisite/translations_management/extend_translations_management", + "api/event_reference/translations_management_events", +], columns=3) =]] From bffca77bd2eeae261c3be07341079a9133fd7ee4 Mon Sep 17 00:00:00 2001 From: dabrt Date: Fri, 19 Jun 2026 14:48:19 +0000 Subject: [PATCH 03/15] PHP & JS CS Fixes --- .../TranslationsManagement/ContentProxyTranslateSubscriber.php | 3 ++- .../src/TranslationsManagement/MyCustomProvider.php | 3 ++- .../src/TranslationsManagement/MyTranslationAddExtension.php | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/code_samples/translations_management/src/TranslationsManagement/ContentProxyTranslateSubscriber.php b/code_samples/translations_management/src/TranslationsManagement/ContentProxyTranslateSubscriber.php index a4229b1e82..e9442a3115 100644 --- a/code_samples/translations_management/src/TranslationsManagement/ContentProxyTranslateSubscriber.php +++ b/code_samples/translations_management/src/TranslationsManagement/ContentProxyTranslateSubscriber.php @@ -11,7 +11,8 @@ { public function __construct( private UrlGeneratorInterface $urlGenerator, - ) {} + ) { + } public static function getSubscribedEvents(): array { diff --git a/code_samples/translations_management/src/TranslationsManagement/MyCustomProvider.php b/code_samples/translations_management/src/TranslationsManagement/MyCustomProvider.php index 3eada2b90f..fa77ae4595 100644 --- a/code_samples/translations_management/src/TranslationsManagement/MyCustomProvider.php +++ b/code_samples/translations_management/src/TranslationsManagement/MyCustomProvider.php @@ -11,7 +11,8 @@ { public function __construct( private MyApiClient $apiClient, - ) {} + ) { + } public function getIdentifier(): string { diff --git a/code_samples/translations_management/src/TranslationsManagement/MyTranslationAddExtension.php b/code_samples/translations_management/src/TranslationsManagement/MyTranslationAddExtension.php index c8985f4af8..47608fd81e 100644 --- a/code_samples/translations_management/src/TranslationsManagement/MyTranslationAddExtension.php +++ b/code_samples/translations_management/src/TranslationsManagement/MyTranslationAddExtension.php @@ -13,6 +13,6 @@ public static function getExtendedTypes(): iterable public function buildForm(FormBuilderInterface $builder, array $options): void { - $builder->add('my_custom_field', /* ... */); + $builder->add('my_custom_field'/* ... */); } } From 6f128e0162d4015a3764a9ee6874358d884929ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C4=85browski?= <64841871+dabrt@users.noreply.github.com> Date: Fri, 19 Jun 2026 16:51:14 +0200 Subject: [PATCH 04/15] Fix formatting in events --- docs/api/event_reference/translations_management_events.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/event_reference/translations_management_events.md b/docs/api/event_reference/translations_management_events.md index 0bc9b7e386..01c69e1b63 100644 --- a/docs/api/event_reference/translations_management_events.md +++ b/docs/api/event_reference/translations_management_events.md @@ -16,7 +16,7 @@ Both events are read-only, you can't use them to override the translation result | Event | Dispatched by | Dispatched when | Properties | |---|---|---|----| -[`BeforeTranslateEvent`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Event-BeforeTranslateEvent.html) | `TranslationService` | Before a translation request is sent to the provider | `TranslationProviderInterface $provider`
`string $text`
`string $sourceLanguage`
`string $targetLanguage` | +| [`BeforeTranslateEvent`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Event-BeforeTranslateEvent.html) | `TranslationService` | Before a translation request is sent to the provider | `TranslationProviderInterface $provider`
`string $text`
`string $sourceLanguage`
`string $targetLanguage` | | [`TranslateEvent`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Event-TranslateEvent.html) | `TranslationService` | After a translation response is received | `string $result`
`TranslationProviderInterface $provider`
`string $text`
`string $sourceLanguage`
`string $targetLanguage` | ## Side-by-side creation events From 07583df621e963764dbf4db51ebb22e721503e79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C4=85browski?= <64841871+dabrt@users.noreply.github.com> Date: Mon, 22 Jun 2026 06:57:59 +0200 Subject: [PATCH 05/15] Add "Configure..." stem to enable building --- .../configure_translations_management.md | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 docs/multisite/translations_management/configure_translations_management.md diff --git a/docs/multisite/translations_management/configure_translations_management.md b/docs/multisite/translations_management/configure_translations_management.md new file mode 100644 index 0000000000..6007e6b657 --- /dev/null +++ b/docs/multisite/translations_management/configure_translations_management.md @@ -0,0 +1,65 @@ +--- +description: Configure and extend translations management, including side-by-side translation view, and AI-based translation providers. +edition: lts-update +month_change: true +--- + +# Translations management + +`ibexa/translations-management` extends [[= product_name =]]'s content translation capabilities represented by the built-in language management tools. + +## Install + +```bash +composer require ibexa/translations-management +``` + +After installation, run the Ibexa data migrations to complete the setup. +This creates the database records and default configuration the package requires. + +## Configure translation providers + + +### Provider configuration + + +### Provider types + + +### Provider options + + +### Built-in AI providers + + +### Plugin disabled state + + +### Error handling + + +## Manage language pairs + +## User settings + + +### Always use automatic translation + + +### Three-state provider selection + + +### Multiple provider rendering + + +## Side-by-side translation view + +### Side-by-side view functions + +### Architecture + +## Translate content items with CLI + +### CLI command options + +## Design system assets From 9a004638cb5cc51179b6a6058f37747cc0dc09bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C4=85browski?= <64841871+dabrt@users.noreply.github.com> Date: Tue, 23 Jun 2026 13:59:33 +0200 Subject: [PATCH 06/15] Implement reviewer comments --- .../ImageAltTextTransformer.php | 3 ++ .../TranslationsManagement/MyApiClient.php | 15 ++++++++ .../MyCustomProvider.php | 4 +++ .../MyTranslationAddExtension.php | 6 +++- composer.json | 3 +- .../translations_management_events.md | 6 ++-- .../extend_translations_management.md | 34 ++++++++++--------- .../translations_management_guide.md | 10 +++--- 8 files changed, 55 insertions(+), 26 deletions(-) create mode 100644 code_samples/translations_management/src/TranslationsManagement/MyApiClient.php diff --git a/code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php b/code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php index b977aef677..fd7906b722 100644 --- a/code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php +++ b/code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php @@ -21,6 +21,9 @@ public function encode(Field $field): EncodedFieldValue return new EncodedFieldValue($field->getValue()->alternativeText ?? ''); } + /** + * @param array $metadata + */ public function decode(string $value, mixed $previousFieldValue, array $metadata): Value { $previousFieldValue->alternativeText = $value; diff --git a/code_samples/translations_management/src/TranslationsManagement/MyApiClient.php b/code_samples/translations_management/src/TranslationsManagement/MyApiClient.php new file mode 100644 index 0000000000..4091bb5285 --- /dev/null +++ b/code_samples/translations_management/src/TranslationsManagement/MyApiClient.php @@ -0,0 +1,15 @@ +`string $text`
`string $sourceLanguage`
`string $targetLanguage` | | [`TranslateEvent`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Event-TranslateEvent.html) | `TranslationService` | After a translation response is received | `string $result`
`TranslationProviderInterface $provider`
`string $text`
`string $sourceLanguage`
`string $targetLanguage` | @@ -25,5 +25,5 @@ Side-by-side creation events are dispatched when a new translation draft is bein | Event | Dispatched by | Dispatched when | Properties | |---|---|---|---| -| [`OnContentSideBySideTranslationCreateEvent`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-SideBySide-Event-OnContentSideBySideTranslationCreateEvent.html) | `SideBySideTranslationService` | When a draft side-by-side translation of a content item is being created | `Request $request`
`Content $sourceContent`
`string $sourceLanguageCode`
`string $targetLanguageCode`
`?Content $targetDraft` | -| [`OnProductSideBySideTranslationCreateEvent`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-SideBySide-Event-OnProductSideBySideTranslationCreateEvent.html) | `SideBySideTranslationService` | When a draft side-by-side translation of a product is being created | `Request $request`
`ContentAwareProductInterface $sourceProduct`
`ContentAwareProductInterface $targetProduct`
`string $sourceLanguageCode`
`string $targetLanguageCode`
`?ProductUpdateData $productUpdateData` | +| [`OnContentSideBySideTranslationCreateEvent`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-SideBySide-Event-OnContentSideBySideTranslationCreateEvent.html) | `ContentTranslationCreateController` | When a draft side-by-side translation of a content item is being created | `Request $request`
`Content $sourceContent`
`string $sourceLanguageCode`
`string $targetLanguageCode`
`?Content $targetDraft` | +| [`OnProductSideBySideTranslationCreateEvent`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-SideBySide-Event-OnProductSideBySideTranslationCreateEvent.html) | `ProductTranslationViewController` | When a draft side-by-side translation of a product is being created | `Request $request`
`ContentAwareProductInterface $sourceProduct`
`ContentAwareProductInterface $targetProduct`
`string $sourceLanguageCode`
`string $targetLanguageCode`
`?ProductUpdateData $productUpdateData` | diff --git a/docs/multisite/translations_management/extend_translations_management.md b/docs/multisite/translations_management/extend_translations_management.md index 2a467abc03..5438a0c73b 100644 --- a/docs/multisite/translations_management/extend_translations_management.md +++ b/docs/multisite/translations_management/extend_translations_management.md @@ -14,12 +14,12 @@ The package discovers and registers tagged services automatically. ## Add custom translation provider -Before you build a custom translation provider, make sure that the `ibexa/connector-ai` package has been installed in your system. +Before you build a custom translation provider, make sure that the `ibexa/connector-ai` package is installed in your system. To connect a translation service that is not built into the package, implement [`TranslationProviderInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Provider-TranslationProviderInterface.html). The `translate()` method receives a `TranslationDataInterface` object that carries the text to translate along with the source and target language codes: -``` php hl_lines="31-44" +``` php hl_lines="36-49" [[= include_code('code_samples/translations_management/src/TranslationsManagement/MyCustomProvider.php') =]] ``` @@ -59,7 +59,7 @@ The package also provides several specialized interfaces for providers with spec ## Add support for custom field types The translation engine works by extracting translatable text from fields, sending it to the provider, and writing the translated text back. -This encode/decode cycle is handled by field value transformers, one per field type. +Field value transformers handle this encode/decode cycle, one per field type. The package includes transformers for standard text and RichText fields. To add support for a custom or non-standard field type, implement [`FieldValueTransformerInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Transformer-Field-FieldValueTransformerInterface.html): @@ -73,31 +73,32 @@ To add support for a custom or non-standard field type, implement [`FieldValueTr ``` Register the transformer with the `ibexa.translations_management.auto_translate.field_value_transformer` tag. -The `field_type_identifier` attribute is required and must match the value returned by `getFieldTypeIdentifier()`: +The `field_type_identifier` attribute is required. +It must match the value that `getFieldTypeIdentifier()` returns: ``` yaml [[= include_code('code_samples/translations_management/config/services.yaml', 1, 1) =]] [[= include_code('code_samples/translations_management/config/services.yaml', 14, 17) =]] ``` -For field types that require metadata, for example, RichText fields with embedded objects that must be preserved after translation, implement [`MetadataAwareFieldValueTransformerInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Transformer-Field-MetadataAwareFieldValueTransformerInterface.html) instead. +If a field type requires metadata, for example, RichText fields with embedded objects that you must preserved after translation, implement [`MetadataAwareFieldValueTransformerInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Transformer-Field-MetadataAwareFieldValueTransformerInterface.html) instead. ## Define custom exclusion rules -Content types that should not use the side-by-side view are identified by exclusion rules. +Use exclusion rules to identify content types that cannot use the side-by-side view. The Translations management package ships with one rule that excludes content types that contain `ibexa_landing_page` or `ibexa_form` fields. ### Exclude with custom class To exclude additional content types, for example, content types with fields that are known to behave poorly in the side-by-side layout, implement [`SideBySideExclusionRuleInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-SideBySide-Service-SideBySideExclusionRuleInterface.html). The `isExcluded()` method receives a [`ContentInfo`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Core-Repository-Values-Content-ContentInfo.html) object and returns `true` if the content item should be excluded. -Classes that implement this interface are automatically tagged via autoconfigure: +Classes that implement this interface are automatically tagged with `autoconfigure`: ``` php [[= include_code('code_samples/translations_management/src/TranslationsManagement/MyCustomExclusionRule.php') =]] ``` -If autoconfigure is not available, register the tag explicitly: +If `autoconfigure` is not available, register the tag explicitly: ``` yaml [[= include_code('code_samples/translations_management/config/services.yaml', 1, 1) =]] @@ -106,7 +107,7 @@ If autoconfigure is not available, register the tag explicitly: ### Exclude with existing class -`MyCustomExclusionRule` targets one specific content type by name. +`MyCustomExclusionRule` targets one specific content type by name. To exclude any content type that contain specific field types without the need to write a custom class, register an additional instance of the built-in [`UnsupportedFieldTypeExclusionRule`](https://github.com/ibexa/translations-management/blob/main/src/lib/SideBySide/Service/UnsupportedFieldTypeExclusionRule.php). Because this registers a second instance of the service with different arguments, you can't use the class name as the service ID. Use an arbitrary string ID instead to avoid overwriting the package's own registration: @@ -124,17 +125,18 @@ Such custom elements could be: - buttons that allow the editor to create a new translation either in the side-by-side view or the standard single-panel editor - a disclaimer or policy notice that the editor must acknowledge before a translation is created - | Component group | Location | Variables available | |---|---|---| | `admin-ui-content-translation-modal-footer` | Footer of the **Add translation** modal | `form`, `content_id`, `location`, `allow_placeholder` | | `admin-ui-content-edit-translation-select-footer` | Footer of the **Select translation** panel on the content edit screen | `form`, `content_id`, `main_language_code` | -Both groups follow the same pattern: if any component renders a non-empty output into the group, the default footer buttons are replaced entirely by the component output. -Therefore, if your component template replaces the defaults, make sure it includes its own action buttons. +The two groups behave differently: -Register a component with the `ibexa.twig.component` tag: +- `admin-ui-content-translation-modal-footer` — if any of the components renders output that is not empty, it entirely replaces the default footer buttons. +Your component template must therefore include its own action buttons. +- `admin-ui-content-edit-translation-select-footer` — component output is inserted between the existing **Edit** and **Discard** buttons. +Register a component with the `ibexa.twig.component` tag: ``` yaml [[= include_code('code_samples/translations_management/config/services.yaml', 1, 1) =]] @@ -146,7 +148,7 @@ Register a component with the `ibexa.twig.component` tag: The `admin-ui-content-translation-modal-footer` group receives a `location` variable that may be `null` when the modal is rendered outside a location context. Always check for `null` before you access location properties in your component template. -## Extend the modal +## Extend modal If injecting custom UI elements is not sufficient, you can extend the modal itself. To add a field to the **Add translation** modal, for example, to let the editor choose a custom workflow or pass extra parameters along with the translation request, extend [`TranslationAddType`](https://github.com/ibexa/admin-ui/blob/main/src/lib/Form/Type/Content/Translation/TranslationAddType.php) with a [Symfony's Form Type extension](https://symfony.com/doc/current/form/create_form_type_extension.html). @@ -180,9 +182,9 @@ Subscribe at a higher priority to act before the package does: [[= include_code('code_samples/translations_management/src/TranslationsManagement/ContentProxyTranslateSubscriber.php') =]] ``` -Both highlighted calls are required: +Both highlighted calls are required: -- `setResponse()` alone does not prevent the translations management listener at priority 100 from running and overwriting the response. +- `setResponse()` alone does not prevent the translations management listener at priority 100 from running and overwriting the response. - `stopPropagation()` stops all lower-priority listeners from executing. When a response is set on the event, `admin-ui` uses it and doesn't proceed with the standard translation editor. diff --git a/docs/multisite/translations_management/translations_management_guide.md b/docs/multisite/translations_management/translations_management_guide.md index cc17a779ce..60ef33f2b9 100644 --- a/docs/multisite/translations_management/translations_management_guide.md +++ b/docs/multisite/translations_management/translations_management_guide.md @@ -26,7 +26,7 @@ Administrators can manage providers and configure default provider-to-language-p Translations management is a standalone set of features. Although some views are similar to those delivered by the [Automated translations](automated_translations.md) opt-in package, Translations management does not require the `ibexa/automated-translation` package to run. These two packages use different namespaces, service tags, and provider interfaces. - + ## Availability Translations management is an [LTS Update](editions.md#lts-updates) available in all [[= product_name =]] editions. @@ -37,7 +37,7 @@ Before the translation flow can happen, an administrator sets up the translation Then, when an editor opens a content item and requests a new machine translation, the plugin resolves which provider to use. It falls back from a language-pair rule to the user's manual selection if necessary. The plugin then extracts the translatable fields from the source language version of a content item and sends them to the configured provider's API. -The translated strings are written into a target-language draft version of a content item, which opens in a side-by-side view for the editor to review and refine. +The system writes the translated strings into a target-language draft of the content item, which opens in a side-by-side view for the editor to review and refine. The editor can save the result as draft, share it with a reviewer or publish it. ![Translations management flow](translations_management_flow.png "Translations management flow") @@ -71,13 +71,13 @@ Editors can: !!! note "Excluded content types" Content types that are editable in Page builder or Form builder are excluded from side-by-side editing. - + Products are editable in the side-by-side view, but product attributes are not translatable. ### CLI translation -Translations management package exposes a [console command](configure_translations_management.md#translate-content-items-with-cli) for translating content items from the command line, -useful for batch processing or CI/CD workflows. +The Translations management package exposes a [console command](configure_translations_management.md#translate-content-items-with-cli) for translating content items from the command line. +You can use it for batch processing or CI (Continuous Integration) workflows. ### Extensibility From 1196977c22a7bb0ed970aea381b0df77545e20f0 Mon Sep 17 00:00:00 2001 From: dabrt Date: Tue, 23 Jun 2026 12:04:46 +0000 Subject: [PATCH 07/15] PHP & JS CS Fixes --- .../src/TranslationsManagement/MyCustomProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code_samples/translations_management/src/TranslationsManagement/MyCustomProvider.php b/code_samples/translations_management/src/TranslationsManagement/MyCustomProvider.php index 7afe9d4216..947d6f3e04 100644 --- a/code_samples/translations_management/src/TranslationsManagement/MyCustomProvider.php +++ b/code_samples/translations_management/src/TranslationsManagement/MyCustomProvider.php @@ -9,7 +9,7 @@ final readonly class MyCustomProvider implements TranslationProviderInterface { - /** + /** * Replace MyApiClient with your HTTP client, SDK wrapper, or any service * that communicates with the external translation API. */ From 97c540b49d9138fb70cff701cadce0fe825ad723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C4=85browski?= <64841871+dabrt@users.noreply.github.com> Date: Wed, 24 Jun 2026 19:26:51 +0200 Subject: [PATCH 08/15] Add the "Configura" article --- .../configure_translations_management.md | 238 ++++++++++++++++-- .../extend_translations_management.md | 44 ++++ 2 files changed, 265 insertions(+), 17 deletions(-) diff --git a/docs/multisite/translations_management/configure_translations_management.md b/docs/multisite/translations_management/configure_translations_management.md index 6007e6b657..b83ced0789 100644 --- a/docs/multisite/translations_management/configure_translations_management.md +++ b/docs/multisite/translations_management/configure_translations_management.md @@ -1,65 +1,269 @@ --- -description: Configure and extend translations management, including side-by-side translation view, and AI-based translation providers. +description: Install translations management, and configure it, including AI-based translation providers. edition: lts-update month_change: true --- # Translations management -`ibexa/translations-management` extends [[= product_name =]]'s content translation capabilities represented by the built-in language management tools. +`ibexa/translations-management` extends [[= product_name =]]'s built-in language management tools that editors use for content translation. +It introduces a plugin that handles translation provider system by connecting to REST APIs and AI services, a [side-by-side editing interface](#side-by-side-translation-view) where editors can compare source and target languages and provide translations in a single view, and multiple extension points that you can use to [customize different areas of the translation workflow](extend_translations_management.md). -## Install +The package is standalone and does not require the `ibexa/automated-translation` add-on package to run. + +## Install package + +The Translations management LTS Update is optional. +To enable it, run the following command: ```bash composer require ibexa/translations-management ``` -After installation, run the Ibexa data migrations to complete the setup. -This creates the database records and default configuration the package requires. +After installation, run the [[= product_name_base =]] data migrations to complete the setup: + +```bash +php bin/console ibexa:migrations:import --from-bundle=IbexaTranslationsManagementBundle +php bin/console ibexa:migrations:migrate +``` + +This copies the migration files into the project's migrations directory and adds the default action configurations in the database. ## Configure translation providers +Translation providers are the services that perform the actual text translation. +There are two types of translation providers: + +- REST API-based providers call a translation service such as Google Translate or DeepL directly by using an API key. +- AI-based providers send translation requests through the [AI Actions](configure_ai_actions.md) framework, relying on the same model selection and policy controls as other AI features in [[= product_name =]]. -### Provider configuration +Out of the box, Translations management can support the following translation providers: +| Provider | Type | Configuration | +|---|---|---| +| Google Translate | REST API | API key | +| DeepL | REST API | API key | +| OpenAI | AI Actions | Action Configuration identifier | +| Anthropic (Claude) | AI Actions | Action Configuration identifier | +| Google Gemini | AI Actions | Action Configuration identifier | -### Provider types +!!! note "Prerequisites for the default translation providers" + Before you can configure translation providers, you must fulfill the following prerequisites: -### Provider options + - For the REST API-based translation providers, add API keys that you obtain from the machine translation services to the `.env` file in the root directory of your project. + - For the AI-based translation providers, [install and configure](configure_ai_actions.md) the `ibexa/connector-ai` package and their corresponding connectors. -### Built-in AI providers +#### Built-in AI providers +When you install the Translations management package, the installation process automatically creates AI [Action Configurations](extend_ai_actions.md#action-configurations) for OpenAI (`auto_translate_openai`), Google Gemini (`auto_translate_gemini`), and Anthropic Clause (`auto_translate_anthropic`). -### Plugin disabled state +You can use them directly in provider configuration: +| Action Configuration identifier | Handler | Default model | +|---|---|---| +| `auto_translate_openai` | `openai-text-to-text` | `gpt-5` | +| `auto_translate_gemini` | `gemini-text-to-text` | `gemini-pro-latest` | +| `auto_translate_anthropic` | `anthropic-text-to-text` | `claude-sonnet-4-20250514` | -### Error handling +You can then [customize these configurations in the UI]([[= user_doc =]]/ai_actions/work_with_ai_actions/#edit-existing-ai-actions). + +### Add YAML configuration + +In `config/packages` folder, create a `translations_management.yaml` file. +You configure the providers in the SiteAccess-aware `translations_management` namespace. + +``` yaml +ibexa: + system: + default: + translations_management: + auto_translate: + providers: + google: + apiKey: '%env(GOOGLE_TRANSLATE_API_KEY)%' + deepl: + apiKey: '%env(DEEPL_API_KEY)%' + openai: + actionConfigurationIdentifier: 'auto_translate_openai' + anthropic: + actionConfigurationIdentifier: 'auto_translate_anthropic' + gemini: + actionConfigurationIdentifier: 'auto_translate_gemini' +``` + +The `apiKey` values must reference API key values that you added to the `.env` file. +The `actionConfigurationIdentifier` values must reference existing Action Configurations. +If a value is missing or empty, the provider doesn't appear in the UI as a selectable option. + +!!! caution "AI policies required" + + AI-based providers require that AI policies are assigned to user roles. + If an editor can't see AI providers in the translation provider dropdown, check if the appropriate AI policies are granted in their role definition. + +If you fail to configure the providers, the Translations management disables itself in the editor's UI. +The **Use automatic translation** checkbox is disabled, and a message is displayed that prompts the user to contact the administrator + +This state is controlled by `TranslationProviderFormFieldsConfigurator::isAutomaticTranslationDisabled()`, which returns `true` when the provider registry is empty. + +### Advanced translation provider options + +In addition to their required authentication setting, all providers support two optional keys: + +- `supportedLanguageCodes` - overrides the default list of language codes this provider accepts +- `languageCodesMap` - maps language codes used by [[= product_name =]], for example, `eng-GB`, to the provider-specific codes the API expects + +``` yaml +ibexa: + system: + default: + translations_management: + auto_translate: + providers: + # ... + openai: + actionConfigurationIdentifier: 'auto_translate_openai' + supportedLanguageCodes: + - 'eng-GB' + - 'ger-DE' + - 'fre-FR' + languageCodesMap: + eng-GB: 'en' + ger-DE: 'de' + fre-FR: 'fr' +``` +The `supportedLanguageCodes` setting controls which languages are available when creating [language pairs](#manage-language-pairs) for this provider. + +!!! note "Identifier normalization" + + Provider identifiers are normalized from hyphens to underscores during configuration processing. + Use one format consistently. + If you mix `my-provider` and `my_provider` for the same provider, it results in an exception. ## Manage language pairs -## User settings +Language pair definitions decide which provider handles each source-to-target language combination by default. +For example, you can decide that English to French translations should use DeepL. +When an editor [opens the translation modal]([[= user_doc =]]/content_management/translate_content/#add-new-translation) and selects a matching language combination, the provider that you chose is pre-selected in the dropdown. +The editor can override the pre-selection. +You manage language pairs in back office, under **Admin** > **Languages** > **Translation providers**. +The configurations are persisted by `SettingService` and stored in the `ibexa_setting` database table under group `translations_management` with identifier `language_pairs`. + +The list of languages available when creating a language pair is determined by what each provider supports. +You can only select the languages that are present in a provider's [supported list](#advanced-translation-provider-options) for that provider's pairs. + +## User settings -### Always use automatic translation +The Translations management package adds two preferences that editors can configure under their [user settings](getting_started/get_started/#browsing). +Each editor can configure them independently, and they do not affect other users. +- Column order -### Three-state provider selection +Editors can choose whether the target language column appears on the left or right in the side-by-side view. +By default, the target is on the right, and each editor can override this default. +You can change the system-wide default in configuration: -### Multiple provider rendering +``` yaml +ibexa: + system: + default: + translations_management: + default_side_by_side_column_order: 'source_left_target_right' +``` +The accepted values are `source_left_target_right` (default) and `source_right_target_left`. ## Side-by-side translation view -### Side-by-side view functions +The [side-by-side translation view]([[= user_doc =]]/content_management/translate_content/#side-by-side-translation-view) is a two-column content editing interface where the source column is read-only and the target column is an editable form. + +Content types that contain the `ibexa_landing_page` or `ibexa_form` fields are not supported, and editors can open them in the standard single-language editor only. +You can exclude support for additional content types if needed. +To do it, [define custom exclusion rules](extend_translations_management.md#define-custom-exclusion-rules). ### Architecture +The side-by-side view consists of three forms placed in a single Twig template: + +- `view.sourcePreviewForm` — the source language content, rendered as read-only fields +- `view.form` — the target language content, rendered as editable fields +- `view.copyAllForm` — the **Copy all from source** action + +To assemble the view, `SideBySideEditContextBuilder` performs the following actions: + +1. Resolves source and target languages +2. Loads the correct content version +3. Groups fields by their content type field groups + +!!! note "Meta fields" + + The builder excludes the fields that are marked marked as `meta: true` or belong to a field group is listed in `admin_ui_forms.content_edit.meta_field_groups_list`, and does not render them. + +To resolve the column order, `SideBySideTargetLanguagePositionResolver` reads the user setting and falls back to `source_left_target_right` when the setting is not made. +The Twig template applies `order-xl-*` classes for responsive column placement. + +### Side-by-side view behavior + +Editors have multiple ways to arrive at the side-by-side translation view, for example: + +- From the **Create a new translation** modal, by clicking the **Open side-by-side** action. + This submits the modal to the `ibexa.translations_management.side_by_side_create` route, which creates a new draft and redirects to `side_by_side_view` with the resolved `versionNo`. + +- From the **Versions** tab, by clicking the **Edit side-by-side** action next to a draft whose source and target languages differ. + This doesn't create a new draft, and the existing version number is used. + +!!! tip "Routes" + + The Translations management package registers internal back office routes. + To list them with their current paths, run: + + ``` bash + php bin/console debug:router | grep translations_management + ``` + +### Side-by-side view functions + +The side-by-side translation view has several functions, including: + +- Copy all from source + +When an editor clicks the **Copy all from source** action, all translatable field values are copied from the source to target column. +It's a single server-side operation handled by `SideBySideFieldCopyService::copyAllFields()` after which the view is reloaded. + +- Draft conflict warning + +When an user opens the translation modal and selects a target language which already has a draft translation, a warning appears in the modal. +The warning is shown or hidden dynamically by `side-by-side-translation-modal-warning.js` when the user changes the target language selection. + ## Translate content items with CLI +For the purposes of batch processing, automations and other scripted actions, the Translations management package exposes a command that translates content items by using any of the configured providers: + +``` bash +php bin/console ibexa:translations:auto-translate-content \ + --content-id=42 \ + --provider=deepl \ + --from=eng-GB \ + --to=fre-FR +``` + +!!! tip "Command alias" + + You can use `ibexa:translations:translate-content` as an alias. + +The command uses the same provider configuration and field value transformers as the UI, so the results are the same if an editor triggered the translation manually. + ### CLI command options -## Design system assets +| Option | Required | Description | +|---|---|---| +| `--content-id` | Yes | ID of the content item to translate | +| `--provider` | Yes | Identifier of the translation provider to use | +| `--from` | Yes | Source language code | +| `--to` | Yes | Target language code | +| `--user-id` | No | Repository user ID to run the translation (default: `14`) | +| `--draft-only` | No | Create a translated draft without publishing it | diff --git a/docs/multisite/translations_management/extend_translations_management.md b/docs/multisite/translations_management/extend_translations_management.md index 5438a0c73b..574d8af782 100644 --- a/docs/multisite/translations_management/extend_translations_management.md +++ b/docs/multisite/translations_management/extend_translations_management.md @@ -194,3 +194,47 @@ When a response is set on the event, `admin-ui` uses it and doesn't proceed with `ContentProxyTranslateEvent` is marked `@internal` in `ibexa/admin-ui`. While it functions as an extension point in practice, its name and signature may change. It may even be removed entirely without a deprecation notice. + +## Manage language pairs programatically + +To manage language pairs programmatically, inject `LanguagePairServiceInterface`: + +``` php +use Ibexa\TranslationsManagement\AutoTranslate\LanguagePair\LanguagePairServiceInterface; +use Ibexa\Contracts\Core\Repository\LanguageService; + +/** @var LanguagePairServiceInterface $languagePairService */ +/** @var LanguageService $languageService */ + +$sourceLanguage = $languageService->loadLanguage('eng-GB'); +$targetLanguage = $languageService->loadLanguage('fre-FR'); + +// $provider is an instance of TranslationProviderInterface +$languagePairService->createLanguagePair( + $sourceLanguage, + $targetLanguage, + $provider, + false // set to true to replace an existing pair with the same source and target +); +``` + +The service exposes the following methods: + +| Method | Description | +|---|---| +| `createLanguagePair()` | Create a new language pair. Pass `true` as the fourth argument to overwrite an existing pair with the same source and target. | +| `updateLanguagePair()` | Update an existing language pair by ID. | +| `syncLanguagePairsForSourceAndProvider()` | Synchronize all target languages for a given source language and provider. | +| `loadLanguagePairs()` | Load all configured language pairs. | +| `deleteLanguagePairById()` | Delete a language pair by ID. | +| `deleteLanguagePairsForProvider()` | Delete all language pairs associated with a given provider. | + +## Service tags reference + +The following service tags expose additional extension points that you can use to customize and extend translations management behavior. + +| Tag | Purpose | Required attributes | +|---|---|---| +| `ibexa.translations_management.auto_translate.provider.language_normalizer` | Register a language code normalizer for a provider | — | +| `ibexa.translations_management.auto_translate.provider.ai.translation_strategy` | Register a custom AI translation strategy (prompt structure) | `priority` | +| `ibexa.translations_management.auto_translate.metadata_validation.retry_policy` | Register a metadata validation retry policy | `priority` | From 510b6bb2762a2b5a726a79ba371d35f1e7646c5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C4=85browski?= <64841871+dabrt@users.noreply.github.com> Date: Thu, 25 Jun 2026 12:43:13 +0200 Subject: [PATCH 09/15] Clarify configuration article --- .../TranslationPairManager.php | 36 +++++++++++ ...translations_management_language_pairs.png | Bin 0 -> 41554 bytes .../configure_translations_management.md | 58 +++++++++++++++--- .../extend_translations_management.md | 34 ---------- .../translations_management_guide.md | 8 ++- mkdocs.yml | 2 +- 6 files changed, 91 insertions(+), 47 deletions(-) create mode 100644 code_samples/translations_management/src/TranslationsManagement/TranslationPairManager.php create mode 100644 docs/multisite/img/translations_management_language_pairs.png diff --git a/code_samples/translations_management/src/TranslationsManagement/TranslationPairManager.php b/code_samples/translations_management/src/TranslationsManagement/TranslationPairManager.php new file mode 100644 index 0000000000..1d15730c15 --- /dev/null +++ b/code_samples/translations_management/src/TranslationsManagement/TranslationPairManager.php @@ -0,0 +1,36 @@ +languageService->loadLanguage($sourceLanguageCode); + $targetLanguage = $this->languageService->loadLanguage($targetLanguageCode); + + return $this->languagePairService->createLanguagePair( + $sourceLanguage, + $targetLanguage, + $provider, + $replaceExisting, + ); + } +} diff --git a/docs/multisite/img/translations_management_language_pairs.png b/docs/multisite/img/translations_management_language_pairs.png new file mode 100644 index 0000000000000000000000000000000000000000..a15adf7af5cc91ce602535f7ff8ca84748aa098d GIT binary patch literal 41554 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
rzeSwR?Yjd|bB?vA}TM9bdM2k%K&> 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 ZIA+jGP4k%4^TZMO(NNV@!C$lv`wz+*RlWcK literal 0 HcmV?d00001 diff --git a/docs/multisite/translations_management/configure_translations_management.md b/docs/multisite/translations_management/configure_translations_management.md index b83ced0789..3a79a138c7 100644 --- a/docs/multisite/translations_management/configure_translations_management.md +++ b/docs/multisite/translations_management/configure_translations_management.md @@ -134,7 +134,7 @@ ibexa: fre-FR: 'fr' ``` -The `supportedLanguageCodes` setting controls which languages are available when creating [language pairs](#manage-language-pairs) for this provider. +The `supportedLanguageCodes` setting controls which languages are available when creating [language pairs](#define-language-pairs) for this provider. !!! note "Identifier normalization" @@ -142,27 +142,67 @@ The `supportedLanguageCodes` setting controls which languages are available when Use one format consistently. If you mix `my-provider` and `my_provider` for the same provider, it results in an exception. -## Manage language pairs +## Define language pairs Language pair definitions decide which provider handles each source-to-target language combination by default. For example, you can decide that English to French translations should use DeepL. When an editor [opens the translation modal]([[= user_doc =]]/content_management/translate_content/#add-new-translation) and selects a matching language combination, the provider that you chose is pre-selected in the dropdown. The editor can override the pre-selection. -You manage language pairs in back office, under **Admin** > **Languages** > **Translation providers**. -The configurations are persisted by `SettingService` and stored in the `ibexa_setting` database table under group `translations_management` with identifier `language_pairs`. - The list of languages available when creating a language pair is determined by what each provider supports. You can only select the languages that are present in a provider's [supported list](#advanced-translation-provider-options) for that provider's pairs. +The configurations are persisted by `SettingService` and stored in the `ibexa_setting` database table under group `translations_management` with identifier `language_pairs`. + +You can manage language pairs in [[= product_name_base =]]'s back office or programatically. + +### Manage language pairs in UI + +To manage language pairs in the back office, go to **Admin** -> **Languages** -> **Language pairs** tab. +Here you can create, edit and delete language pairs. + +To add a language pair, click **+ Add language pair**. +Then, pick a source language and one or more target languages from their respective drop-down lists. +Finally, from the **Translation service** list, pick a translation provider and click **Save and close** + +![Creating a language pair](translations_management_language_pairs.png "Creating a language pair") + +This will add as many language pairs as you picked target languages. + +!!! note + + The **Add language pair** action is disabled if no translation providers are [configured](#configure-translation-providers). + + If a language pair already exists and is associated with a translation provider, you can't create another language pair with a different provider. + Edit the existing language pair instead. + +## Manage language pairs programmatically + +To manage language pairs programmatically, create a service class and inject `LanguagePairServiceInterface` into its constructor. +Symfony autowires it automatically` so no manual service configuration is needed. + + +``` php hl_lines="2" +[[= include_code('code_samples/translations_management/src/TranslationsManagement/TranslationPairManager.php', 14, 35) =]] +``` + +The service exposes the following methods: + +| Method | Description | +|---|---| +| `createLanguagePair()` | Create a new language pair. Pass `true` as the fourth argument to overwrite an existing pair with the same source and target. | +| `updateLanguagePair()` | Update an existing language pair by ID. | +| `syncLanguagePairsForSourceAndProvider()` | Synchronize all target languages for a given source language and provider. | +| `loadLanguagePairs()` | Load all configured language pairs. | +| `deleteLanguagePairById()` | Delete a language pair by ID. | +| `deleteLanguagePairsForProvider()` | Delete all language pairs associated with a given provider. | + ## User settings -The Translations management package adds two preferences that editors can configure under their [user settings](getting_started/get_started/#browsing). +The Translations management package adds preferences that editors can configure under their [user settings](getting_started/get_started/#browsing). Each editor can configure them independently, and they do not affect other users. -- Column order - -Editors can choose whether the target language column appears on the left or right in the side-by-side view. +For example, editors can choose whether the target language column appears on the left or right in the side-by-side view. By default, the target is on the right, and each editor can override this default. You can change the system-wide default in configuration: diff --git a/docs/multisite/translations_management/extend_translations_management.md b/docs/multisite/translations_management/extend_translations_management.md index 574d8af782..2c16e93e70 100644 --- a/docs/multisite/translations_management/extend_translations_management.md +++ b/docs/multisite/translations_management/extend_translations_management.md @@ -195,40 +195,6 @@ When a response is set on the event, `admin-ui` uses it and doesn't proceed with While it functions as an extension point in practice, its name and signature may change. It may even be removed entirely without a deprecation notice. -## Manage language pairs programatically - -To manage language pairs programmatically, inject `LanguagePairServiceInterface`: - -``` php -use Ibexa\TranslationsManagement\AutoTranslate\LanguagePair\LanguagePairServiceInterface; -use Ibexa\Contracts\Core\Repository\LanguageService; - -/** @var LanguagePairServiceInterface $languagePairService */ -/** @var LanguageService $languageService */ - -$sourceLanguage = $languageService->loadLanguage('eng-GB'); -$targetLanguage = $languageService->loadLanguage('fre-FR'); - -// $provider is an instance of TranslationProviderInterface -$languagePairService->createLanguagePair( - $sourceLanguage, - $targetLanguage, - $provider, - false // set to true to replace an existing pair with the same source and target -); -``` - -The service exposes the following methods: - -| Method | Description | -|---|---| -| `createLanguagePair()` | Create a new language pair. Pass `true` as the fourth argument to overwrite an existing pair with the same source and target. | -| `updateLanguagePair()` | Update an existing language pair by ID. | -| `syncLanguagePairsForSourceAndProvider()` | Synchronize all target languages for a given source language and provider. | -| `loadLanguagePairs()` | Load all configured language pairs. | -| `deleteLanguagePairById()` | Delete a language pair by ID. | -| `deleteLanguagePairsForProvider()` | Delete all language pairs associated with a given provider. | - ## Service tags reference The following service tags expose additional extension points that you can use to customize and extend translations management behavior. diff --git a/docs/multisite/translations_management/translations_management_guide.md b/docs/multisite/translations_management/translations_management_guide.md index 60ef33f2b9..3466bdafc2 100644 --- a/docs/multisite/translations_management/translations_management_guide.md +++ b/docs/multisite/translations_management/translations_management_guide.md @@ -46,11 +46,13 @@ The editor can save the result as draft, share it with a reviewer or publish it. ### Translation provider management -Administrators can manage translation providers and configure [language pair defaults](configure_translations_management.md#manage-language-pairs). +Administrators can manage translation providers and configure [language pair defaults](configure_translations_management.md#define-language-pairs). This way they can define which provider handles which language combination. Editors see the configured default pre-selected when creating a new translation, but can override the selection if needed. -Translations management supports several built-in translation providers, for example Google Translate, which is accessed through its REST API, or OpenAI, accessed through AI Actions. +![Creating a language pair](translations_management_language_pairs.png "Creating a language pair") + +The package provides integrations with several translation providers, including Google Translate through its REST API and OpenAI through [AI Actions](ai_actions.md). ### Side-by-side translation view @@ -74,7 +76,7 @@ Editors can: Products are editable in the side-by-side view, but product attributes are not translatable. -### CLI translation +### Command line translation The Translations management package exposes a [console command](configure_translations_management.md#translate-content-items-with-cli) for translating content items from the command line. You can use it for batch processing or CI (Continuous Integration) workflows. diff --git a/mkdocs.yml b/mkdocs.yml index 7d32355408..dc16cdb66a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -482,7 +482,7 @@ nav: - Automated content translation: multisite/languages/automated_translations.md - Translations management: - Translations management: multisite/translations_management/translations_management.md - - Translations management product guide: multisite/translations_management/translations_management_guide.md + - Translations management guide: multisite/translations_management/translations_management_guide.md - Configure translations management: multisite/translations_management/configure_translations_management.md - Extend translations management: multisite/translations_management/extend_translations_management.md - Permissions: From 9f3f304abaa440028512bb53a7446697951ff2d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C4=85browski?= <64841871+dabrt@users.noreply.github.com> Date: Thu, 25 Jun 2026 14:35:32 +0200 Subject: [PATCH 10/15] Fix issues --- .../configure_translations_management.md | 22 +++++++-------- .../extend_translations_management.md | 23 +++++++-------- .../translations_management_guide.md | 28 +++++++++---------- 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/docs/multisite/translations_management/configure_translations_management.md b/docs/multisite/translations_management/configure_translations_management.md index 3a79a138c7..59bcd89daf 100644 --- a/docs/multisite/translations_management/configure_translations_management.md +++ b/docs/multisite/translations_management/configure_translations_management.md @@ -1,5 +1,5 @@ --- -description: Install translations management, and configure it, including AI-based translation providers. +description: Install translations management configure translation providers, language pairs, and more. edition: lts-update month_change: true --- @@ -7,7 +7,7 @@ month_change: true # Translations management `ibexa/translations-management` extends [[= product_name =]]'s built-in language management tools that editors use for content translation. -It introduces a plugin that handles translation provider system by connecting to REST APIs and AI services, a [side-by-side editing interface](#side-by-side-translation-view) where editors can compare source and target languages and provide translations in a single view, and multiple extension points that you can use to [customize different areas of the translation workflow](extend_translations_management.md). +It introduces a plugin that handles the translation provider system by connecting to REST APIs and AI services, a [side-by-side editing interface](#side-by-side-translation-view) where editors can compare source and target languages and provide translations in a single view, and multiple extension points that you can use to [customize different areas of the translation workflow](extend_translations_management.md). The package is standalone and does not require the `ibexa/automated-translation` add-on package to run. @@ -57,7 +57,7 @@ Out of the box, Translations management can support the following translation pr #### Built-in AI providers -When you install the Translations management package, the installation process automatically creates AI [Action Configurations](extend_ai_actions.md#action-configurations) for OpenAI (`auto_translate_openai`), Google Gemini (`auto_translate_gemini`), and Anthropic Clause (`auto_translate_anthropic`). +When you install the Translations management package, the installation process automatically creates AI [Action Configurations](extend_ai_actions.md#action-configurations) for OpenAI (`auto_translate_openai`), Google Gemini (`auto_translate_gemini`), and Anthropic Claude (`auto_translate_anthropic`). You can use them directly in provider configuration: @@ -71,7 +71,7 @@ You can then [customize these configurations in the UI]([[= user_doc =]]/ai_acti ### Add YAML configuration -In `config/packages` folder, create a `translations_management.yaml` file. +In `config/packages`, create a `translations_management.yaml` file. You configure the providers in the SiteAccess-aware `translations_management` namespace. ``` yaml @@ -102,14 +102,14 @@ If a value is missing or empty, the provider doesn't appear in the UI as a selec AI-based providers require that AI policies are assigned to user roles. If an editor can't see AI providers in the translation provider dropdown, check if the appropriate AI policies are granted in their role definition. -If you fail to configure the providers, the Translations management disables itself in the editor's UI. +If you fail to configure the providers, the Translations management feature disables itself in the editor's UI. The **Use automatic translation** checkbox is disabled, and a message is displayed that prompts the user to contact the administrator This state is controlled by `TranslationProviderFormFieldsConfigurator::isAutomaticTranslationDisabled()`, which returns `true` when the provider registry is empty. ### Advanced translation provider options -In addition to their required authentication setting, all providers support two optional keys: +In addition to their required authentication keys, all providers support two optional ones: - `supportedLanguageCodes` - overrides the default list of language codes this provider accepts - `languageCodesMap` - maps language codes used by [[= product_name =]], for example, `eng-GB`, to the provider-specific codes the API expects @@ -154,7 +154,7 @@ You can only select the languages that are present in a provider's [supported li The configurations are persisted by `SettingService` and stored in the `ibexa_setting` database table under group `translations_management` with identifier `language_pairs`. -You can manage language pairs in [[= product_name_base =]]'s back office or programatically. +You can manage language pairs in [[= product_name_base =]]'s back office or programmatically. ### Manage language pairs in UI @@ -167,7 +167,7 @@ Finally, from the **Translation service** list, pick a translation provider and ![Creating a language pair](translations_management_language_pairs.png "Creating a language pair") -This will add as many language pairs as you picked target languages. +This adds as many language pairs as you picked target languages. !!! note @@ -179,7 +179,7 @@ This will add as many language pairs as you picked target languages. ## Manage language pairs programmatically To manage language pairs programmatically, create a service class and inject `LanguagePairServiceInterface` into its constructor. -Symfony autowires it automatically` so no manual service configuration is needed. +Symfony autowires it automatically so no manual service configuration is needed. ``` php hl_lines="2" @@ -241,7 +241,7 @@ To assemble the view, `SideBySideEditContextBuilder` performs the following acti !!! note "Meta fields" - The builder excludes the fields that are marked marked as `meta: true` or belong to a field group is listed in `admin_ui_forms.content_edit.meta_field_groups_list`, and does not render them. + The builder excludes the fields that are marked marked as `meta: true` or belong to a field group that is listed in `admin_ui_forms.content_edit.meta_field_groups_list`, and does not render them. To resolve the column order, `SideBySideTargetLanguagePositionResolver` reads the user setting and falls back to `source_left_target_right` when the setting is not made. The Twig template applies `order-xl-*` classes for responsive column placement. @@ -305,5 +305,5 @@ The command uses the same provider configuration and field value transformers as | `--provider` | Yes | Identifier of the translation provider to use | | `--from` | Yes | Source language code | | `--to` | Yes | Target language code | -| `--user-id` | No | Repository user ID to run the translation (default: `14`) | +| `--user-id` | No | Repository user ID to run the translation (default: `14`, which is the Administrator user) | | `--draft-only` | No | Create a translated draft without publishing it | diff --git a/docs/multisite/translations_management/extend_translations_management.md b/docs/multisite/translations_management/extend_translations_management.md index 2c16e93e70..d8fe4d8ec8 100644 --- a/docs/multisite/translations_management/extend_translations_management.md +++ b/docs/multisite/translations_management/extend_translations_management.md @@ -6,15 +6,15 @@ month_change: true # Extend translations management -By extending [Translations management](translations_management_guide.md), you can build custom translation workflows and adapt the feature set's behavior to your specific requirements. +By extending [Translations management](translations_management_guide.md), you can build custom translation workflows and adapt the package's behavior to your specific requirements. The package is designed to be extended in multiple ways. You can create custom [translation providers](configure_translations_management.md#configure-translation-providers), field type transformers, exclusion rules, and UI components. -In all cases you follow the same pattern: implement an interface or extend a base class, then register the service with a service tag. +In all cases, you follow the same pattern: implement an interface or extend a base class, then register the service with a service tag. The package discovers and registers tagged services automatically. ## Add custom translation provider -Before you build a custom translation provider, make sure that the `ibexa/connector-ai` package is installed in your system. +Before you build a custom translation provider, if your provider uses the AI Actions framework, make sure that the `ibexa/connector-ai` package is installed in your system. To connect a translation service that is not built into the package, implement [`TranslationProviderInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Provider-TranslationProviderInterface.html). The `translate()` method receives a `TranslationDataInterface` object that carries the text to translate along with the source and target language codes: @@ -30,7 +30,7 @@ Both `identifier` and `validation_profile` are required attributes. [[= include_code('code_samples/translations_management/config/services.yaml', 1, 6) =]] ``` -The `validation_profile` attribute links the provider to a validator that checks language codes and payload size before each call. +The `validation_profile` attribute links the provider to a validator that checks language codes and payload size before each before each translation request. By default, three profiles are available: | Profile | Used by | @@ -46,7 +46,8 @@ To define a custom validation profile, implement [`ProviderValidatorInterface`]( [[= include_code('code_samples/translations_management/config/services.yaml', 7, 10) =]] ``` -The [`DefaultProviderValidator`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Validator-DefaultProviderValidator.html) class is available as a reusable base with configurable maximum payload size and language code regex patterns. +You can extend [`DefaultProviderValidator`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Validator-DefaultProviderValidator.html) as base class. +It exposes configurable maximum payload size and language code regex patterns. The package also provides several specialized interfaces for providers with specific requirements: @@ -81,7 +82,7 @@ It must match the value that `getFieldTypeIdentifier()` returns: [[= include_code('code_samples/translations_management/config/services.yaml', 14, 17) =]] ``` -If a field type requires metadata, for example, RichText fields with embedded objects that you must preserved after translation, implement [`MetadataAwareFieldValueTransformerInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Transformer-Field-MetadataAwareFieldValueTransformerInterface.html) instead. +If a field type requires metadata, for example, RichText fields with embedded objects that you must preserve after translation, implement [`MetadataAwareFieldValueTransformerInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Transformer-Field-MetadataAwareFieldValueTransformerInterface.html) instead. ## Define custom exclusion rules @@ -90,7 +91,7 @@ The Translations management package ships with one rule that excludes content ty ### Exclude with custom class -To exclude additional content types, for example, content types with fields that are known to behave poorly in the side-by-side layout, implement [`SideBySideExclusionRuleInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-SideBySide-Service-SideBySideExclusionRuleInterface.html). +To exclude additional content types, for example, content types whose fields render incorrectly in the side-by-side layout, implement [`SideBySideExclusionRuleInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-SideBySide-Service-SideBySideExclusionRuleInterface.html). The `isExcluded()` method receives a [`ContentInfo`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Core-Repository-Values-Content-ContentInfo.html) object and returns `true` if the content item should be excluded. Classes that implement this interface are automatically tagged with `autoconfigure`: @@ -110,7 +111,7 @@ If `autoconfigure` is not available, register the tag explicitly: `MyCustomExclusionRule` targets one specific content type by name. To exclude any content type that contain specific field types without the need to write a custom class, register an additional instance of the built-in [`UnsupportedFieldTypeExclusionRule`](https://github.com/ibexa/translations-management/blob/main/src/lib/SideBySide/Service/UnsupportedFieldTypeExclusionRule.php). Because this registers a second instance of the service with different arguments, you can't use the class name as the service ID. -Use an arbitrary string ID instead to avoid overwriting the package's own registration: +Use an arbitrary string ID instead to avoid a service definition conflict: ``` yaml [[= include_code('code_samples/translations_management/config/services.yaml', 1, 1) =]] @@ -167,7 +168,7 @@ Register it as a service: [[= include_code('code_samples/translations_management/config/services.yaml', 11, 13) =]] ``` -The extra field is then available in the submitted form data, which the standard `admin-ui` controller passes through the translation flow. +The extra field is then available in the submitted form data, which the standard `admin-ui` controller includes in the translation request data. Use this approach when you need to read extra input from the editor, not to redirect or replace the response. ## Intercept translation flow @@ -184,7 +185,7 @@ Subscribe at a higher priority to act before the package does: Both highlighted calls are required: -- `setResponse()` alone does not prevent the translations management listener at priority 100 from running and overwriting the response. +- `setResponse()` alone does not prevent the Translations management listener at priority 100 from running and overwriting the response. - `stopPropagation()` stops all lower-priority listeners from executing. When a response is set on the event, `admin-ui` uses it and doesn't proceed with the standard translation editor. @@ -201,6 +202,6 @@ The following service tags expose additional extension points that you can use t | Tag | Purpose | Required attributes | |---|---|---| -| `ibexa.translations_management.auto_translate.provider.language_normalizer` | Register a language code normalizer for a provider | — | +| `ibexa.translations_management.auto_translate.provider.language_normalizer` | Register a language code normalizer for a provider | none | | `ibexa.translations_management.auto_translate.provider.ai.translation_strategy` | Register a custom AI translation strategy (prompt structure) | `priority` | | `ibexa.translations_management.auto_translate.metadata_validation.retry_policy` | Register a metadata validation retry policy | `priority` | diff --git a/docs/multisite/translations_management/translations_management_guide.md b/docs/multisite/translations_management/translations_management_guide.md index 3466bdafc2..cebb95ddf1 100644 --- a/docs/multisite/translations_management/translations_management_guide.md +++ b/docs/multisite/translations_management/translations_management_guide.md @@ -8,14 +8,14 @@ month_change: true ## What is Translations management -Content managers, translators and proofreaders who work with multilingual content in [[= product_name =]] often face a common set of challenges: +Content managers, translators, and proofreaders who work with multilingual content in [[= product_name =]] often face a common set of challenges: - context is lost when the source text isn't visible alongside the translation -- translation of long and complex content items is time consuming +- translating long and complex content items is time-consuming - quality assurance is slow and error-prone without a direct comparison view - switching between tools or tabs to cross-reference languages disrupts focus and slows down publishing -Translations management package addresses these pain points through a side-by-side view, machine translation and ability to invite reviewers to collaborate on content item or product translation. +The Translations management package addresses these pain points through a side-by-side view, machine translation and the ability to invite reviewers to collaborate on the translation of a content items or products. The package integrates with the [AI Actions framework](ai_actions.md) to support machine translation providers such as Google Translate and DeepL, and AI powered translation services like OpenAI, Anthropic, and Google Gemini. @@ -35,10 +35,10 @@ Translations management is an [LTS Update](editions.md#lts-updates) available in Before the translation flow can happen, an administrator sets up the translation providers and assigns language pairs to them. Then, when an editor opens a content item and requests a new machine translation, the plugin resolves which provider to use. -It falls back from a language-pair rule to the user's manual selection if necessary. +If no language-pair rule matches, it falls back to the user's manual selection. The plugin then extracts the translatable fields from the source language version of a content item and sends them to the configured provider's API. -The system writes the translated strings into a target-language draft of the content item, which opens in a side-by-side view for the editor to review and refine. -The editor can save the result as draft, share it with a reviewer or publish it. +The system writes the translated strings into a target-language draft of the content item, and opens it in a side-by-side view for the editor to review and refine. +The editor can save the result as a draft, share it with a reviewer or publish it. ![Translations management flow](translations_management_flow.png "Translations management flow") @@ -46,17 +46,17 @@ The editor can save the result as draft, share it with a reviewer or publish it. ### Translation provider management -Administrators can manage translation providers and configure [language pair defaults](configure_translations_management.md#define-language-pairs). -This way they can define which provider handles which language combination. -Editors see the configured default pre-selected when creating a new translation, but can override the selection if needed. +Administrators can manage translation providers and configure translation provider/language combination assignments ([language pairs](configure_translations_management.md#define-language-pairs)). +This allows administrators to define which provider handles which language combination. +Editors see the configured provider pre-selected when creating a new translation, but can override it if needed. ![Creating a language pair](translations_management_language_pairs.png "Creating a language pair") -The package provides integrations with several translation providers, including Google Translate through its REST API and OpenAI through [AI Actions](ai_actions.md). +The package provides integrations with several translation providers, including REST API-based services such as Google Translate and DeepL, and AI-powered services through the [AI Actions](ai_actions.md). ### Side-by-side translation view -Translations management introduces a [side-by-side translation view]([[= user_doc =]]/content_management/translate_content/#side-by-side-translation-view) that displays the source language read-only next to an editable target language form. +Translations management introduces a [side-by-side translation view]([[= user_doc =]]/content_management/translate_content/#side-by-side-translation-view) that displays the read-only source language content next to an editable target language form. In this view, editors can provide and review translations in context, without having to leave the content editing interface. ![Side-by-side translation view](managing_translations_sxs_view.png "Side-by-side translation view") @@ -66,7 +66,7 @@ Editors can: - access the side-by-side view when creating a new translation, reviewing an existing one, or editing a draft - compare source and target content field by field while editing - copy all content from the source column to the target column with a single action -- provide localized versions of media assets +- provide localized versions of media assets and their alternative text - use the distraction-free mode for focused editing of individual fields, with AI actions available inline - choose whether the source column appears on the left or right in user settings @@ -76,10 +76,10 @@ Editors can: Products are editable in the side-by-side view, but product attributes are not translatable. -### Command line translation +### Command-line translation The Translations management package exposes a [console command](configure_translations_management.md#translate-content-items-with-cli) for translating content items from the command line. -You can use it for batch processing or CI (Continuous Integration) workflows. +You can use it for batch processing or automated workflows. ### Extensibility From 5739e698474cb57053d9f79db675d9a1648474c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C4=85browski?= <64841871+dabrt@users.noreply.github.com> Date: Thu, 25 Jun 2026 16:34:09 +0200 Subject: [PATCH 11/15] Remove duplicate blanks --- .../configure_translations_management.md | 7 +++---- .../extend_translations_management.md | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/multisite/translations_management/configure_translations_management.md b/docs/multisite/translations_management/configure_translations_management.md index 59bcd89daf..7d2f2a608b 100644 --- a/docs/multisite/translations_management/configure_translations_management.md +++ b/docs/multisite/translations_management/configure_translations_management.md @@ -32,7 +32,7 @@ This copies the migration files into the project's migrations directory and adds ## Configure translation providers Translation providers are the services that perform the actual text translation. -There are two types of translation providers: +The Translations management package comes with two types of translation providers: - REST API-based providers call a translation service such as Google Translate or DeepL directly by using an API key. - AI-based providers send translation requests through the [AI Actions](configure_ai_actions.md) framework, relying on the same model selection and policy controls as other AI features in [[= product_name =]]. @@ -55,7 +55,7 @@ Out of the box, Translations management can support the following translation pr - For the AI-based translation providers, [install and configure](configure_ai_actions.md) the `ibexa/connector-ai` package and their corresponding connectors. -#### Built-in AI providers +**Built-in AI providers** When you install the Translations management package, the installation process automatically creates AI [Action Configurations](extend_ai_actions.md#action-configurations) for OpenAI (`auto_translate_openai`), Google Gemini (`auto_translate_gemini`), and Anthropic Claude (`auto_translate_anthropic`). @@ -181,7 +181,6 @@ This adds as many language pairs as you picked target languages. To manage language pairs programmatically, create a service class and inject `LanguagePairServiceInterface` into its constructor. Symfony autowires it automatically so no manual service configuration is needed. - ``` php hl_lines="2" [[= include_code('code_samples/translations_management/src/TranslationsManagement/TranslationPairManager.php', 14, 35) =]] ``` @@ -281,7 +280,7 @@ The warning is shown or hidden dynamically by `side-by-side-translation-modal-wa ## Translate content items with CLI -For the purposes of batch processing, automations and other scripted actions, the Translations management package exposes a command that translates content items by using any of the configured providers: +For the purposes of batch processing, automation and other scripted actions, the Translations management package exposes a command that translates content items by using any of the configured providers: ``` bash php bin/console ibexa:translations:auto-translate-content \ diff --git a/docs/multisite/translations_management/extend_translations_management.md b/docs/multisite/translations_management/extend_translations_management.md index d8fe4d8ec8..2f9176c250 100644 --- a/docs/multisite/translations_management/extend_translations_management.md +++ b/docs/multisite/translations_management/extend_translations_management.md @@ -68,7 +68,6 @@ To add support for a custom or non-standard field type, implement [`FieldValueTr - `encode(Field $field): EncodedFieldValue` - extracts the translatable string from the field and wraps it in an [`EncodedFieldValue`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-TranslationsManagement-AutoTranslate-Transformer-Field-EncodedFieldValue.html). The constructor takes the extracted string as its first argument and an optional metadata array as its second. - `decode(string $value, mixed $previousFieldValue, array $metadata): Value` - receives the translated string, the previous field value, and any metadata, and returns the updated field value - ``` php hl_lines="19 24" [[= include_code('code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php') =]] ``` From 45be4c67bb59514c61875cfb6987e8d96b7ba517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C4=85browski?= <64841871+dabrt@users.noreply.github.com> Date: Thu, 25 Jun 2026 17:42:41 +0200 Subject: [PATCH 12/15] Add a release notes entry --- .../configure_translations_management.md | 2 +- docs/release_notes/ibexa_dxp_v5.0.md | 47 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/docs/multisite/translations_management/configure_translations_management.md b/docs/multisite/translations_management/configure_translations_management.md index 7d2f2a608b..32c7939e3a 100644 --- a/docs/multisite/translations_management/configure_translations_management.md +++ b/docs/multisite/translations_management/configure_translations_management.md @@ -4,7 +4,7 @@ edition: lts-update month_change: true --- -# Translations management +# Configure translations management `ibexa/translations-management` extends [[= product_name =]]'s built-in language management tools that editors use for content translation. It introduces a plugin that handles the translation provider system by connecting to REST APIs and AI services, a [side-by-side editing interface](#side-by-side-translation-view) where editors can compare source and target languages and provide translations in a single view, and multiple extension points that you can use to [customize different areas of the translation workflow](extend_translations_management.md). diff --git a/docs/release_notes/ibexa_dxp_v5.0.md b/docs/release_notes/ibexa_dxp_v5.0.md index 02469e686b..8a976a1754 100644 --- a/docs/release_notes/ibexa_dxp_v5.0.md +++ b/docs/release_notes/ibexa_dxp_v5.0.md @@ -10,6 +10,53 @@ month_change: true

+[[% set version = 'v5.0.10' %]] +[[% set date = '2026-07-30' %]] + +[[= release_note_entry_begin( + 'Translations management ' + version, + date, + ['Headless', 'Experience', 'Commerce', 'LTS Update', 'New feature', 'First release'] +) =]] + +Translations management is a new LTS Update that extends [[= product_name =]]'s built-in language management tools with machine translation, a side-by-side editing view, and a command-line translation utility. + +### Machine translation providers + +Translation providers are the services that perform the actual text translation. +Translations management uses two provider types to connect to the translation services: + +- REST API-based providers: Google Translate and DeepL, configured with API keys +- AI-based providers: OpenAI, Anthropic Claude, and Google Gemini, routed through AI Actions + +For more information, see [Configure translation providers](configure_translations_management.md#configure-translation-providers). + +### Side-by-side translation view + +A [side-by-side translation view]([[= user_doc =]]/content_management/translate_content/#side-by-side-translation-view) displays the source and target text of the content item or product on one screen. +Editors can translate or compare source and target content, copy all content from the source column to the target column in a single action, and use the distraction-free mode for focused editing of individual fields. + +For more information, see [User Documentation]([[= user_doc =]]/content_management/translate_content/#side-by-side-translation-view). + +### CLI translation command + +A new console command translates content items from the command line, enabling batch processing and automated workflows. + +For more information, see [Translate content items with CLI](configure_translations_management.md#translate-content-items-with-cli). + +### Developer experience + +The package exposes multiple extension points for custom translation workflows, including: + +- Custom translation providers through `TranslationProviderInterface` +- Custom field type support through `FieldValueTransformerInterface` +- Custom content type exclusion rules through `SideBySideExclusionRuleInterface` +- extension points for adding UI elements and fields to the views used by the feature + +For more information, see [Extend translations management](https://doc.ibexa.co/en/5.0/translations/extend_translations_management/). + +[[= release_note_entry_end() =]] + [[% set version = 'v5.0.8' %]] [[% set date = '2026-05-21' %]] From 866d19c8641a399d8b8869db4fbe271885c89e18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C4=85browski?= <64841871+dabrt@users.noreply.github.com> Date: Fri, 26 Jun 2026 07:58:59 +0200 Subject: [PATCH 13/15] Fix code issues --- .../src/TranslationsManagement/ImageAltTextTransformer.php | 2 +- .../src/TranslationsManagement/TranslationPairManager.php | 6 +++--- .../extend_translations_management.md | 6 ++++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php b/code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php index fd7906b722..6f6f05ca8d 100644 --- a/code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php +++ b/code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php @@ -7,7 +7,7 @@ use Ibexa\Contracts\Core\Repository\Values\Content\Field; use Ibexa\Contracts\TranslationsManagement\AutoTranslate\Transformer\Field\EncodedFieldValue; use Ibexa\Contracts\TranslationsManagement\AutoTranslate\Transformer\Field\FieldValueTransformerInterface; -use Ibexa\Core\FieldType\Value; +use Ibexa\Contracts\Core\FieldType\Value; final class ImageAltTextTransformer implements FieldValueTransformerInterface { diff --git a/code_samples/translations_management/src/TranslationsManagement/TranslationPairManager.php b/code_samples/translations_management/src/TranslationsManagement/TranslationPairManager.php index 1d15730c15..e0324871ff 100644 --- a/code_samples/translations_management/src/TranslationsManagement/TranslationPairManager.php +++ b/code_samples/translations_management/src/TranslationsManagement/TranslationPairManager.php @@ -9,11 +9,11 @@ use Ibexa\TranslationsManagement\AutoTranslate\LanguagePair\LanguagePairInterface; use Ibexa\TranslationsManagement\AutoTranslate\LanguagePair\LanguagePairServiceInterface; -final class TranslationPairManager +final readonly class TranslationPairManager { public function __construct( - private readonly LanguagePairServiceInterface $languagePairService, - private readonly LanguageService $languageService, + private LanguagePairServiceInterface $languagePairService, + private LanguageService $languageService, ) { } diff --git a/docs/multisite/translations_management/extend_translations_management.md b/docs/multisite/translations_management/extend_translations_management.md index 2f9176c250..cd0f02e245 100644 --- a/docs/multisite/translations_management/extend_translations_management.md +++ b/docs/multisite/translations_management/extend_translations_management.md @@ -170,6 +170,12 @@ Register it as a service: The extra field is then available in the submitted form data, which the standard `admin-ui` controller includes in the translation request data. Use this approach when you need to read extra input from the editor, not to redirect or replace the response. +!!! caution "Internal `TranslationAddType`" + + `TranslationAddType` is marked `@internal` in `ibexa/admin-ui`. + While it functions as an extension point in practice, its name and signature may change. + It may even be removed entirely without a deprecation notice. + ## Intercept translation flow The `BeforeTranslateEvent` and `TranslateEvent` [events](translations_management_events.md#translation-events) operate at the field-value level and cannot redirect the HTTP flow. From 00ebddc96d15e487409eb8b9e76d23beab54fe7f Mon Sep 17 00:00:00 2001 From: dabrt Date: Fri, 26 Jun 2026 06:05:58 +0000 Subject: [PATCH 14/15] PHP & JS CS Fixes --- .../src/TranslationsManagement/ImageAltTextTransformer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php b/code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php index 6f6f05ca8d..380932de0d 100644 --- a/code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php +++ b/code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php @@ -4,10 +4,10 @@ namespace App\TranslationsManagement; +use Ibexa\Contracts\Core\FieldType\Value; use Ibexa\Contracts\Core\Repository\Values\Content\Field; use Ibexa\Contracts\TranslationsManagement\AutoTranslate\Transformer\Field\EncodedFieldValue; use Ibexa\Contracts\TranslationsManagement\AutoTranslate\Transformer\Field\FieldValueTransformerInterface; -use Ibexa\Contracts\Core\FieldType\Value; final class ImageAltTextTransformer implements FieldValueTransformerInterface { From 45ce1251fa3a0b843f59eebe99b9b741d529ee7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C4=85browski?= <64841871+dabrt@users.noreply.github.com> Date: Fri, 26 Jun 2026 08:13:54 +0200 Subject: [PATCH 15/15] Add TranslationAddType to deptrack baseline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: dabrt Co-Authored-By: Marek Nocoń --- deptrac.baseline.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deptrac.baseline.yaml b/deptrac.baseline.yaml index b465d1d963..664593c7d1 100644 --- a/deptrac.baseline.yaml +++ b/deptrac.baseline.yaml @@ -245,6 +245,8 @@ deptrac: App\Tab\Dashboard\Everyone\EveryoneArticleTab: - Ibexa\AdminUi\Tab\Dashboard\PagerLocationToDataMapper - Ibexa\Core\Pagination\Pagerfanta\LocationSearchAdapter + App\TranslationsManagement\MyTranslationAddExtension: + - Ibexa\AdminUi\Form\Type\Content\Translation\TranslationAddType App\View\Matcher\Owner: - Ibexa\Core\MVC\Symfony\Matcher\ContentBased\MatcherInterface - Ibexa\Core\MVC\Symfony\View\ContentValueView