src/Services/I18nService.ps1
|
# I18nService — Catálogo de strings UI en español e inglés. # # Centraliza los strings que el usuario ve para que un solo lugar controle # qué se muestra. Soporta los locales 'es' y 'en' (Settings.Language). # Si una key no existe en el locale activo, fallback al 'es' (default histórico # del proyecto). Si tampoco existe ahí, devuelve `[key]` para que el bug sea # visible en la UI (preferible a string vacío silencioso). # # Uso: # $svc = [I18nService]::new('es') # $svc.T('hint.move') # → '↑↓' (mismo en ambos) # $svc.T('hint.search') # → 'Buscar' o 'Search' según locale # # Convención de keys: # - dot.notation jerárquica (hint.X, prefs.X, status.X, alias.X, tab.X, …) # - el archivo lee los catálogos lazy via Get-RepoNavI18nCatalog (mantiene # los hashes data afuera de la clase para no inflarla) class I18nService { [string] $Locale = 'es' # Catálogo activo, cacheado en la primera llamada a EnsureCatalog. Se rebuilda # cuando cambia Locale. hidden [hashtable] $_catalog = $null I18nService() { } I18nService([string]$lc) { $this.SetLocale($lc) } # Param se llama $lc (no $locale) porque PS classes son case-insensitive en # scope: `$locale` chocaría con $this.Locale y rompería la asignación. [void] SetLocale([string]$lc) { $effective = if ([string]::IsNullOrWhiteSpace($lc)) { 'es' } elseif ($lc -notin @('es', 'en')) { 'es' } else { $lc } $this.Locale = $effective $this._catalog = $null # invalidar cache } # Devuelve el string para una key. Fallback chain: # 1) catálogo del locale activo # 2) catálogo 'es' (default histórico) # 3) literal `[key]` para que el bug sea visible [string] T([string]$key) { if ([string]::IsNullOrWhiteSpace($key)) { return '' } $cat = $this._GetCatalog() if ($cat.ContainsKey($key)) { return [string]$cat[$key] } # Fallback al español default si la key falta en el locale activo. $fallback = Get-RepoNavI18nCatalog -Locale 'es' if ($fallback.ContainsKey($key)) { return [string]$fallback[$key] } return "[$key]" } # Versión con interpolación posicional. Útil para mensajes con valores # dinámicos. Ej: T('alias.confirmRemove', 'TEST') → "¿Eliminar alias TEST?". # Param se llama $values (no $args) porque $args es automatic en PS y # llega vacío cuando se usa como nombre formal en métodos de class. [string] T([string]$key, [object[]]$values) { $template = $this.T($key) if ($values -and $values.Count -gt 0) { try { return [string]::Format($template, $values) } catch { return $template } } return $template } hidden [hashtable] _GetCatalog() { if ($null -eq $this._catalog) { $this._catalog = Get-RepoNavI18nCatalog -Locale $this.Locale } return $this._catalog } } |