1818BCASL_TAGS = ["pre-compilation" , "license" , "SPDX" ]
1919
2020import re
21+ import asyncio
2122from pathlib import Path
2223from typing import Optional
2324
@@ -221,12 +222,47 @@ def _inject_license_for_file(path: Path, text: str, spdx_id: str) -> str:
221222 description = "Injecte une ligne de licence (SPDX) en tête des fichiers ciblés" ,
222223)
223224class LicenseInjector (PluginBase ):
225+ _i18n : dict | None = None
226+
227+ def _ensure_i18n (self ) -> None :
228+ if self ._i18n is not None :
229+ return
230+ try :
231+ try :
232+ self ._i18n = asyncio .run (API_SDK .load_plugin_translations (Path (__file__ )))
233+ except RuntimeError :
234+ loop = asyncio .new_event_loop ()
235+ try :
236+ self ._i18n = loop .run_until_complete (API_SDK .load_plugin_translations (Path (__file__ )))
237+ finally :
238+ try :
239+ loop .close ()
240+ except Exception :
241+ pass
242+ except Exception :
243+ self ._i18n = {}
244+
245+ def _t (self , sctx , key : str , fr : str , en : str , ** fmt ) -> str :
246+ text = None
247+ try :
248+ if isinstance (self ._i18n , dict ):
249+ text = self ._i18n .get (key )
250+ except Exception :
251+ text = None
252+ if not isinstance (text , str ) or not text .strip ():
253+ text = sctx .tr (fr , en )
254+ try :
255+ return text .format (** fmt ) if fmt else text
256+ except Exception :
257+ return text
258+
224259 def on_pre_compile (self , ctx : PreCompileContext ) -> None :
225260 try :
226261 sctx = wrap_context (ctx )
227262 except RuntimeError as exc :
228263 print (f"[ERROR][license_injector] { exc } " )
229264 return
265+ self ._ensure_i18n ()
230266
231267 cfg = sctx .config_view
232268 subcfg = cfg .for_plugin (getattr (self , "id" , "license_injector" ))
@@ -235,7 +271,9 @@ def on_pre_compile(self, ctx: PreCompileContext) -> None:
235271 spdx_id , lic_name = _detect_workspace_license (sctx .workspace_root )
236272 if not spdx_id :
237273 sctx .log_info (
238- sctx .tr (
274+ self ._t (
275+ sctx ,
276+ "no_license" ,
239277 "license_injector: aucune licence détectée (pyproject ou fichiers LICENSE/LICENCE/COPYING/NOTICE). Aucune injection." ,
240278 "license_injector: no license detected (pyproject or LICENSE/LICENCE/COPYING/NOTICE files). No injection performed." ,
241279 )
@@ -252,20 +290,24 @@ def on_pre_compile(self, ctx: PreCompileContext) -> None:
252290
253291 # Demande confirmation
254292 if not sctx .msg_question (
255- sctx .tr ("License Injector" , "License Injector" ),
256- sctx .tr (
257- f"Injecter la licence (SPDX: { spdx_id } ) dans les fichiers correspondant aux motifs: { patterns } ?" ,
258- f"Inject license (SPDX: { spdx_id } ) into files matching: { patterns } ?" ,
293+ self ._t (sctx , "title" , "License Injector" , "License Injector" ),
294+ self ._t (
295+ sctx ,
296+ "confirm" ,
297+ "Injecter la licence (SPDX: {spdx}) dans les fichiers correspondant aux motifs: {patterns} ?" ,
298+ "Inject license (SPDX: {spdx}) into files matching: {patterns} ?" ,
299+ spdx = spdx_id ,
300+ patterns = patterns ,
259301 ),
260302 default_yes = False ,
261303 ):
262- sctx .log_warn (sctx . tr ( "license_injector: opération annulée par l'utilisateur" , "license_injector: operation canceled by user" ))
304+ sctx .log_warn (self . _t ( sctx , "canceled" , "license_injector: opération annulée par l'utilisateur" , "license_injector: operation canceled by user" ))
263305 return
264306
265307 # Phase 1: analyse des cibles
266308 ph = API_SDK .progress (
267- sctx . tr ( "Injection de licence" , "License Injection" ),
268- sctx . tr ( "Analyse des fichiers cibles..." , "Scanning target files..." ),
309+ self . _t ( sctx , "progress_title" , "Injection de licence" , "License Injection" ),
310+ self . _t ( sctx , "progress_scan" , "Analyse des fichiers cibles..." , "Scanning target files..." ),
269311 maximum = 0 ,
270312 cancelable = True ,
271313 )
@@ -275,7 +317,7 @@ def on_pre_compile(self, ctx: PreCompileContext) -> None:
275317 skipped_dup = 0
276318 for p in sctx .iter_files (patterns , exclude = exclude , enforce_workspace = True ):
277319 if ph .canceled :
278- sctx .log_warn (sctx . tr ( "license_injector: opération annulée par l'utilisateur" , "license_injector: operation canceled by user" ))
320+ sctx .log_warn (self . _t ( sctx , "canceled" , "license_injector: opération annulée par l'utilisateur" , "license_injector: operation canceled by user" ))
279321 return
280322 found += 1
281323 try :
@@ -310,7 +352,7 @@ def on_pre_compile(self, ctx: PreCompileContext) -> None:
310352 changed = 0
311353 for i , p in enumerate (to_modify , start = 1 ):
312354 if ph .canceled :
313- sctx .log_warn (sctx . tr ( "license_injector: opération annulée par l'utilisateur" , "license_injector: operation canceled by user" ))
355+ sctx .log_warn (self . _t ( sctx , "canceled" , "license_injector: opération annulée par l'utilisateur" , "license_injector: operation canceled by user" ))
314356 return
315357 rel = p .relative_to (sctx .workspace_root )
316358 ph .update (i , f"{ i } /{ len (to_modify )} : { rel } " )
@@ -328,9 +370,14 @@ def on_pre_compile(self, ctx: PreCompileContext) -> None:
328370 sctx .log_warn (f"Écriture échouée pour { rel } : { e } " )
329371
330372 sctx .log_info (
331- sctx .tr (
332- f"license_injector: terminé. Modifiés={ changed } , déjà avec SPDX={ skipped_dup } , total scannés={ found } " ,
333- f"license_injector: done. Changed={ changed } , already SPDX={ skipped_dup } , total scanned={ found } " ,
373+ self ._t (
374+ sctx ,
375+ "done" ,
376+ "license_injector: terminé. Modifiés={changed}, déjà avec SPDX={skipped}, total scannés={found}" ,
377+ "license_injector: done. Changed={changed}, already SPDX={skipped}, total scanned={found}" ,
378+ changed = changed ,
379+ skipped = skipped_dup ,
380+ found = found ,
334381 )
335382 )
336383 finally :
0 commit comments