@@ -305,11 +305,86 @@ if not ok:
305305
306306## 8) i18n (async) {#8 -i18n-async}
307307
308- - Place a languages/ folder in your package; load with API_SDK helpers:
308+ Goal
309+ - Ship a languages/ folder with your plugin so UI strings are localized.
310+ - Load translations at runtime with the SDK helper and always provide safe English fallbacks.
311+ - Use string placeholders and tr.get(...) consistently, as illustrated in API/cleaner.
312+
313+ Folder layout
314+ ```
315+ API/
316+ └── my_plugin/
317+ ├── __init__.py
318+ └── languages/
319+ ├── en.json
320+ ├── fr.json
321+ ├── es.json
322+ └── de.json
323+ ```
324+
325+ Minimal en.json (example keys)
326+ ``` json
327+ {
328+ "_meta" : { "code" : " en" , "name" : " English" },
329+ "title" : " MyPlugin" ,
330+ "start" : " Starting {plugin}…" ,
331+ "done" : " Done" ,
332+ "confirm_run" : " Run this step now?" ,
333+ "canceled" : " Canceled by user" ,
334+ "error_fmt" : " Error: {error}"
335+ }
336+ ```
337+
338+ Loading translations (async helper)
309339``` python
310340import asyncio
311341from API_SDK .BCASL_SDK import load_plugin_translations
312- tr = asyncio.run(load_plugin_translations(__file__ , " System" ))
342+
343+ # Language can be a code ("en", "fr" …) or "System" for auto-detection
344+ tr = asyncio.run(load_plugin_translations(__file__ , " System" )) or {}
345+ ```
346+
347+ Using translations with robust fallbacks and placeholders
348+ ``` python
349+ # Always provide an English fallback when using tr.get
350+ sctx.log_info(tr.get(" start" , " Starting {plugin} …" ).format(plugin = BCASL_NAME ))
351+
352+ # Guarded prompt (respect non-interactive mode)
353+ noninteractive = bool (getattr (sctx, " noninteractive" , False ) or getattr (sctx, " is_noninteractive" , False ))
354+ if (not noninteractive):
355+ if not sctx.msg_question(tr.get(" title" , BCASL_NAME ), tr.get(" confirm_run" , " Run this step now?" ), default_yes = False ):
356+ sctx.log_warn(tr.get(" canceled" , " Canceled by user" ))
357+ return
358+
359+ # Formatting example for errors
360+ try :
361+ ...
362+ except Exception as e:
363+ sctx.log_warn(tr.get(" error_fmt" , " Error: {error} " ).format(error = e))
364+ ```
365+
366+ Keys and conventions (inspired by API/cleaner)
367+ - Use explicit, short keys: title, confirm_ * , progress_ * , * _ fmt for formatted messages.
368+ - Keep placeholders explicit and named (e.g., {file}, {error}, {current}, {total}).
369+ - Provide a complete en.json as the baseline and add locales incrementally (fr, es, de …).
370+ - For progress handles, update text with translated strings and placeholders:
371+ - tr.get("deleting_pyc", "Deleting .pyc ({current}/{total})").format(current=i, total=n)
372+
373+ Best practices
374+ - Do not block UI for i18n; loading JSON is local I/O.
375+ - Normalize the language via the SDK helper (System auto-detect). Keep values UTF-8.
376+ - Keep English as the code fallback when a key is missing.
377+ - Avoid string concatenation; prefer .format with named placeholders.
378+
379+ Complete pattern (typical flow)
380+ ``` python
381+ from API_SDK .BCASL_SDK import progress
382+ tr = asyncio.run(load_plugin_translations(__file__ , " System" )) or {}
383+
384+ with progress(tr.get(" title" , BCASL_NAME ), tr.get(" start" , " Starting {plugin} …" ).format(plugin = BCASL_NAME ), maximum = 1 ) as ph:
385+ # … work …
386+ ph.update(1 , tr.get(" done" , " Done" ))
387+ sctx.log_info(tr.get(" done" , " Done" ))
313388```
314389
315390---
0 commit comments