@praxisui/settings-panel 3.0.0-beta.7 → 3.0.0-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,21 +3,21 @@ import { inject, DestroyRef, ViewContainerRef, HostListener, ViewChild, ChangeDe
3
3
  import { ComponentPortal } from '@angular/cdk/portal';
4
4
  import * as i3 from '@angular/common';
5
5
  import { CommonModule } from '@angular/common';
6
+ import { CdkTrapFocus } from '@angular/cdk/a11y';
6
7
  import * as i3$1 from '@angular/material/button';
7
8
  import { MatButtonModule } from '@angular/material/button';
9
+ import * as i1 from '@angular/material/dialog';
10
+ import { MatDialogModule } from '@angular/material/dialog';
8
11
  import * as i4 from '@angular/material/icon';
9
12
  import { MatIconModule } from '@angular/material/icon';
10
- import { PraxisIconDirective, SETTINGS_PANEL_DATA as SETTINGS_PANEL_DATA$1, SETTINGS_PANEL_BRIDGE, GlobalConfigService, FieldControlType, IconPickerService, LoggerService } from '@praxisui/core';
11
- import * as i5 from '@angular/material/tooltip';
12
- import { MatTooltipModule } from '@angular/material/tooltip';
13
- import { CdkTrapFocus } from '@angular/cdk/a11y';
14
13
  import * as i6 from '@angular/material/progress-spinner';
15
14
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
16
- import * as i1 from '@angular/material/dialog';
17
- import { MatDialogModule } from '@angular/material/dialog';
15
+ import * as i5 from '@angular/material/tooltip';
16
+ import { MatTooltipModule } from '@angular/material/tooltip';
18
17
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
19
- import { isObservable, firstValueFrom, of, Subject, BehaviorSubject } from 'rxjs';
20
18
  import { filter, switchMap, debounceTime, distinctUntilChanged } from 'rxjs/operators';
19
+ import { isObservable, firstValueFrom, of, Subject, BehaviorSubject } from 'rxjs';
20
+ import { providePraxisI18n, PraxisI18nService, PraxisIconDirective, SETTINGS_PANEL_DATA as SETTINGS_PANEL_DATA$1, SETTINGS_PANEL_BRIDGE, GlobalConfigService, FieldControlType, IconPickerService, LoggerService } from '@praxisui/core';
21
21
  import { ConfirmDialogComponent } from '@praxisui/dynamic-fields';
22
22
  import * as i1$1 from '@angular/cdk/overlay';
23
23
  import * as i2 from '@angular/material/snack-bar';
@@ -28,6 +28,457 @@ import * as i9 from '@angular/material/chips';
28
28
  import { MatChipsModule } from '@angular/material/chips';
29
29
  import { AiBackendApiService } from '@praxisui/ai';
30
30
 
31
+ const PRAXIS_SETTINGS_PANEL_GLOBAL_CONFIG_EDITOR_PT_BR = {
32
+ CRUD: 'CRUD',
33
+ 'Dynamic Fields': 'Campos Dinâmicos',
34
+ 'Cache & Persistence': 'Cache & Persistência',
35
+ Table: 'Tabela',
36
+ Dialog: 'Dialog',
37
+ 'Settings saved': 'Configurações salvas',
38
+ 'Save failed.': 'Falha ao salvar configurações.',
39
+ 'Global settings': 'Configurações globais',
40
+ 'Global policies for opening, back and header': 'Políticas globais de abertura, back e header',
41
+ 'Server defaults (env vars)': 'Padrões do servidor (env vars)',
42
+ 'Saved configuration (UI) - overrides server defaults': 'Configuração salva (UI) - sobrescreve os defaults do servidor',
43
+ 'Failed to test connection.': 'Falha ao testar conexão.',
44
+ 'Connection established successfully!': 'Conexão estabelecida com sucesso!',
45
+ 'Unknown error': 'Erro desconhecido',
46
+ 'Key provided': 'Chave informada',
47
+ 'Saved key (****{{last4}})': 'Chave salva (****{{last4}})',
48
+ 'Saved key': 'Chave salva',
49
+ 'Test connection with the provided key': 'Testar conexão com a chave informada',
50
+ 'Test connection': 'Testar conexão',
51
+ 'Refresh model list': 'Atualizar lista de modelos',
52
+ Close: 'Fechar',
53
+ 'This provider has no model catalog.': 'Este provedor não oferece catálogo de modelos.',
54
+ 'Enter an API key to fetch models.': 'Insira uma chave de API para buscar modelos.',
55
+ 'Error fetching models.': 'Erro ao buscar modelos.',
56
+ 'Error fetching models. Check your API key.': 'Erro ao buscar modelos. Verifique a chave de API.',
57
+ 'Model list updated ({{count}} models)': 'Lista de modelos atualizada ({{count}} modelos)',
58
+ 'Enter an API key to test.': 'Insira uma chave de API para testar.',
59
+ 'No model details available.': 'Detalhes do modelo não disponíveis.',
60
+ 'Model: {{model}} | Tokens (in/out): {{in}}/{{out}} | Methods: {{methods}}': 'Modelo: {{model}} | Tokens (in/out): {{in}}/{{out}} | Métodos: {{methods}}',
61
+ 'Global config cleared. Using server defaults.': 'Configuração global limpa. Usando defaults do servidor.',
62
+ 'Clear saved config and return to server defaults': 'Apaga o config salvo e volta aos defaults do servidor',
63
+ 'Failed to clear global config.': 'Falha ao limpar a configuração global.',
64
+ 'No key required': 'Sem chave necessária',
65
+ 'Model & Behavior': 'Modelo & Comportamento',
66
+ 'Choose the model after validating the key.': 'Escolha o modelo após validar a chave.',
67
+ 'API key validated required': 'Requer chave de API validada',
68
+ 'Configure and test your API key to unlock model selection.': 'Configure e teste sua chave de API para desbloquear a seleção de modelos.',
69
+ 'Embeddings (RAG)': 'Embeddings (RAG)',
70
+ 'Use the LLM provider and key for embeddings': 'Aplicar provedor e chave do LLM aos embeddings',
71
+ 'Provider has no embeddings': 'Provedor sem embeddings',
72
+ 'Configure the embeddings provider for vector search (templates and schemas).': 'Configure o provedor de embeddings para buscas vetoriais (templates e schemas).',
73
+ 'Embedding dimension mismatch with database (768). Adjust to 768 or redo the migration.': 'Dimensão de embeddings diferente do banco (768). Ajuste para 768 ou refaça a migração.',
74
+ 'Toolbar, appearance and advanced filter': 'Toolbar, aparência e filtro avançado',
75
+ 'Defaults and variants (danger, info, success, question, error)': 'Defaults e variants (danger, info, success, question, error)',
76
+ 'Icons by profile (shortcuts)': 'Ícones por perfil (atalhos)',
77
+ 'Pick icon': 'Escolher ícone',
78
+ 'Pick icon for {{key}}': 'Escolher ícone para {{key}}',
79
+ 'Clear icon': 'Limpar ícone',
80
+ 'Clear icon for {{key}}': 'Limpar ícone de {{key}}',
81
+ 'The text field above remains editable. These buttons only help with selection/clear preview.': 'O campo de texto acima permanece editável. Estes botões apenas ajudam na seleção/limpeza com preview.',
82
+ 'Fast multimodal models from Google.': 'Modelos rápidos e multimodais do Google.',
83
+ 'Grok models focused on reasoning.': 'Modelos Grok focados em raciocínio.',
84
+ 'Local mode for tests without a key.': 'Modo local para testes sem chave.',
85
+ 'No saved key': 'Sem chave salva',
86
+ 'Aparência: densidade': 'Aparência: densidade',
87
+ compact: 'compact',
88
+ comfortable: 'comfortable',
89
+ spacious: 'spacious',
90
+ 'Aparência: padding das células': 'Aparência: padding das células',
91
+ 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 6px 12px': 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 6px 12px',
92
+ 'Use 1 a 4 medidas CSS válidas, como 6px 12px.': 'Use 1 a 4 medidas CSS válidas, como 6px 12px.',
93
+ 'Aparência: padding do cabeçalho': 'Aparência: padding do cabeçalho',
94
+ 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 8px 12px': 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 8px 12px',
95
+ 'Use 1 a 4 medidas CSS válidas, como 8px 12px.': 'Use 1 a 4 medidas CSS válidas, como 8px 12px.',
96
+ 'Aparência: fonte das células': 'Aparência: fonte das células',
97
+ 'Aceita uma medida CSS com unidade, var(...) ou calc(...). Ex.: 13px': 'Aceita uma medida CSS com unidade, var(...) ou calc(...). Ex.: 13px',
98
+ 'Use uma medida CSS válida, como 13px.': 'Use uma medida CSS válida, como 13px.',
99
+ 'Aparência: fonte do cabeçalho': 'Aparência: fonte do cabeçalho',
100
+ 'Filtro: modo de abertura': 'Filtro: modo de abertura',
101
+ overlay: 'overlay',
102
+ 'Filtro: overlay (visual)': 'Filtro: overlay (visual)',
103
+ card: 'card',
104
+ frosted: 'frosted',
105
+ 'Filtro: backdrop no overlay': 'Filtro: backdrop no overlay',
106
+ 'Excluir — confirmação': 'Excluir — confirmação',
107
+ 'Excluir (múltiplos) — confirmação': 'Excluir (múltiplos) — confirmação',
108
+ 'Salvar — confirmação': 'Salvar — confirmação',
109
+ 'Cancelar — confirmação': 'Cancelar — confirmação',
110
+ 'Exportar — confirmação': 'Exportar — confirmação',
111
+ 'Excluir — progresso': 'Excluir — progresso',
112
+ 'Excluir (múltiplos) — progresso': 'Excluir (múltiplos) — progresso',
113
+ 'Excluir — sucesso': 'Excluir — sucesso',
114
+ 'Salvar — sucesso': 'Salvar — sucesso',
115
+ 'Exportar — sucesso': 'Exportar — sucesso',
116
+ 'Importar — sucesso': 'Importar — sucesso',
117
+ 'Excluir — erro': 'Excluir — erro',
118
+ 'Salvar — erro': 'Salvar — erro',
119
+ 'Exportar — erro': 'Exportar — erro',
120
+ 'Rede — erro': 'Rede — erro',
121
+ 'Permissão — erro': 'Permissão — erro',
122
+ 'Modo de abertura padrão': 'Modo de abertura padrão',
123
+ Rota: 'Rota',
124
+ 'Aplicado quando ação/metadado não definem modo.': 'Aplicado quando ação/metadado não definem modo.',
125
+ 'Confirmar ao sair com alterações': 'Confirmar ao sair com alterações',
126
+ 'Back: estratégia': 'Back: estratégia',
127
+ 'Modal: largura (ex.: 900px)': 'Modal: largura (ex.: 900px)',
128
+ 'Modal: largura máxima (ex.: 96vw)': 'Modal: largura máxima (ex.: 96vw)',
129
+ 'Modal: backdrop': 'Modal: backdrop',
130
+ blur: 'blur',
131
+ dim: 'dim',
132
+ transparent: 'transparent',
133
+ 'Estratégia de primeira carga quando metadado não definir.': 'Estratégia de primeira carga quando metadado não definir.',
134
+ 'Async Select, cascade and pagination': 'Async Select, cascata e paginação',
135
+ 'Cascata nativa habilitada': 'Cascata nativa habilitada',
136
+ 'Cascata: loadOnChange': 'Cascata: loadOnChange',
137
+ respectLoadOn: 'respectLoadOn',
138
+ immediate: 'immediate',
139
+ manual: 'manual',
140
+ 'Cascata: debounce (ms)': 'Cascata: debounce (ms)',
141
+ 'Async Select: loadOn': 'Async Select: loadOn',
142
+ open: 'open',
143
+ init: 'init',
144
+ none: 'none',
145
+ 'Async Select: pageSize': 'Async Select: pageSize',
146
+ 'Async Select: usar cursor': 'Async Select: usar cursor',
147
+ 'LLM provider': 'Provedor LLM',
148
+ 'Select the provider to list models and test the key.': 'Selecione o provedor para listar modelos e testar a chave.',
149
+ 'API key': 'Chave de API',
150
+ 'Enter the selected provider key to test.': 'Informe a chave do provedor selecionado para testar.',
151
+ 'AI model': 'Modelo de IA',
152
+ 'Temperature (Creativity)': 'Temperatura (Criatividade)',
153
+ '0.0 (deterministic) to 1.0 (creative)': '0.0 (determinístico) a 1.0 (criativo)',
154
+ 'Assistant: risk validation': 'Assistente: validação de risco',
155
+ 'Standard': 'Padrão',
156
+ 'Strict requires confirmation for medium/high risk. Standard follows the indication returned by the backend.': 'Estrito exige confirmação em risco médio/alto. Padrão segue a indicação retornada pelo backend.',
157
+ 'Use same LLM for embeddings': 'Embeddings: usar mesmo LLM',
158
+ 'Replicates the LLM provider and key for embeddings.': 'Replica provedor e chave do LLM para embeddings.',
159
+ 'Embeddings provider': 'Embeddings: provedor',
160
+ 'Provider used to generate embeddings (RAG).': 'Provedor usado para gerar embeddings (RAG).',
161
+ 'Embeddings API key': 'Embeddings: chave de API',
162
+ 'Embeddings provider key.': 'Chave do provedor de embeddings.',
163
+ 'Embeddings model': 'Embeddings: modelo',
164
+ 'Provider default': 'Padrão do provedor',
165
+ 'OpenAI models for embeddings.': 'Modelos OpenAI para embeddings.',
166
+ 'Embeddings: dimensions': 'Embeddings: dimensões',
167
+ 'Embedding vector dimensions (default 768).': 'Dimensões do vetor de embedding (default 768).',
168
+ 'Artificial Intelligence': 'Inteligência Artificial',
169
+ 'LLM integration': 'Integração com LLM',
170
+ 'Appearance: density': 'Aparência: densidade',
171
+ 'Appearance: cell padding': 'Aparência: padding das células',
172
+ 'Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 6px 12px': 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 6px 12px',
173
+ 'Use 1 to 4 valid CSS measures, such as 6px 12px.': 'Use 1 a 4 medidas CSS válidas, como 6px 12px.',
174
+ 'Appearance: header padding': 'Aparência: padding do cabeçalho',
175
+ 'Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 8px 12px': 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 8px 12px',
176
+ 'Use 1 to 4 valid CSS measures, such as 8px 12px.': 'Use 1 a 4 medidas CSS válidas, como 8px 12px.',
177
+ 'Appearance: cell font size': 'Aparência: fonte das células',
178
+ 'Accepts a CSS measure with units, var(...) or calc(...). Example: 13px': 'Aceita uma medida CSS com unidade, var(...) ou calc(...). Ex.: 13px',
179
+ 'Use a valid CSS measure, such as 13px.': 'Use uma medida CSS válida, como 13px.',
180
+ 'Appearance: header font size': 'Aparência: fonte do cabeçalho',
181
+ 'Provedor LLM': 'Provedor LLM',
182
+ 'Selecione o provedor para listar modelos e testar a chave.': 'Selecione o provedor para listar modelos e testar a chave.',
183
+ 'Chave de API': 'Chave de API',
184
+ 'Informe a chave do provedor selecionado para testar.': 'Informe a chave do provedor selecionado para testar.',
185
+ 'Modelo de IA': 'Modelo de IA',
186
+ 'Temperatura (Criatividade)': 'Temperatura (Criatividade)',
187
+ '0.0 (determinístico) a 1.0 (criativo)': '0.0 (determinístico) a 1.0 (criativo)',
188
+ 'Max tokens': 'Max tokens',
189
+ 'Limite maximo de tokens na resposta.': 'Limite maximo de tokens na resposta.',
190
+ 'Assistente: validação de risco': 'Assistente: validação de risco',
191
+ 'Estrito (recomendado)': 'Estrito (recomendado)',
192
+ 'Padrão': 'Padrão',
193
+ 'Estrito exige confirmação em risco médio/alto. Padrão segue a indicação retornada pelo backend.': 'Estrito exige confirmação em risco médio/alto. Padrão segue a indicação retornada pelo backend.',
194
+ 'Embeddings: usar mesmo LLM': 'Embeddings: usar mesmo LLM',
195
+ 'Replica provedor e chave do LLM para embeddings.': 'Replica provedor e chave do LLM para embeddings.',
196
+ 'Embeddings: provedor': 'Embeddings: provedor',
197
+ 'Provedor usado para gerar embeddings (RAG).': 'Provedor usado para gerar embeddings (RAG).',
198
+ 'Embeddings: chave de API': 'Embeddings: chave de API',
199
+ 'Chave do provedor de embeddings.': 'Chave do provedor de embeddings.',
200
+ 'Embeddings: modelo': 'Embeddings: modelo',
201
+ 'Padrão do provedor': 'Padrão do provedor',
202
+ 'Modelos OpenAI para embeddings.': 'Modelos OpenAI para embeddings.',
203
+ 'Embeddings: dimensoes': 'Embeddings: dimensões',
204
+ 'Dimensoes do vetor de embedding (default 768).': 'Dimensões do vetor de embedding (default 768).',
205
+ 'GPT models for text and chat.': 'Modelos GPT para texto e chat.',
206
+ 'Synchronized with the LLM. The fields below follow the primary credential.': 'Sincronizado com o LLM. Os campos abaixo acompanham a credencial principal.',
207
+ 'Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}': 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}',
208
+ 'Example JSON array: [{"id":"cancel","text":"Cancel","role":"secondary","close":true,"cssClass":"btn"},{"id":"confirm","text":"Delete","role":"primary","close":true,"cssClass":"btn btn-danger","icon":"delete"}]': 'Ex.: [{"id":"cancel","text":"Cancelar","role":"secondary","close":true,"cssClass":"btn"},{"id":"confirm","text":"Excluir","role":"primary","close":true,"cssClass":"btn btn-danger","icon":"delete"}]',
209
+ 'Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}': 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}',
210
+ 'Desabilitar cache de schema (LocalStorage)': 'Desabilitar cache de schema (LocalStorage)',
211
+ 'Se ativo, sempre baixa o schema do servidor (ignora cache local). Útil para desenvolvimento.': 'Se ativo, sempre baixa o schema do servidor (ignora cache local). Útil para desenvolvimento.',
212
+ 'Paginação habilitada': 'Paginação habilitada',
213
+ 'Tamanho da página': 'Tamanho da página',
214
+ 'Ordenação habilitada': 'Ordenação habilitada',
215
+ 'Seleção habilitada': 'Seleção habilitada',
216
+ 'Paginação: estratégia': 'Paginação: estratégia',
217
+ 'Ordenação: estratégia': 'Ordenação: estratégia',
218
+ 'Paginação: botões Primeiro/Último': 'Paginação: botões Primeiro/Último',
219
+ 'Toolbar visível': 'Toolbar visível',
220
+ 'Cache & Persistência': 'Cache & Persistence',
221
+ Tabela: 'Table',
222
+ Salvar: 'Save',
223
+ Cancelar: 'Cancel',
224
+ Redefinir: 'Reset',
225
+ };
226
+ const PRAXIS_SETTINGS_PANEL_GLOBAL_CONFIG_EDITOR_EN_US = {
227
+ CRUD: 'CRUD',
228
+ 'Dynamic Fields': 'Dynamic Fields',
229
+ 'Cache & Persistence': 'Cache & Persistence',
230
+ Table: 'Table',
231
+ Dialog: 'Dialog',
232
+ 'Settings saved': 'Settings saved',
233
+ 'Save failed.': 'Save failed.',
234
+ 'Global settings': 'Global settings',
235
+ 'Global policies for opening, back and header': 'Global policies for opening, back and header',
236
+ 'Server defaults (env vars)': 'Server defaults (env vars)',
237
+ 'Saved configuration (UI) - overrides server defaults': 'Saved configuration (UI) - overrides server defaults',
238
+ 'Failed to test connection.': 'Failed to test connection.',
239
+ 'Connection established successfully!': 'Connection established successfully!',
240
+ 'Unknown error': 'Unknown error',
241
+ 'Key provided': 'Key provided',
242
+ 'Saved key (****{{last4}})': 'Saved key (****{{last4}})',
243
+ 'Saved key': 'Saved key',
244
+ 'Test connection with the provided key': 'Test connection with the provided key',
245
+ 'Test connection': 'Test connection',
246
+ 'Refresh model list': 'Refresh model list',
247
+ Close: 'Close',
248
+ 'This provider has no model catalog.': 'This provider has no model catalog.',
249
+ 'Enter an API key to fetch models.': 'Enter an API key to fetch models.',
250
+ 'Error fetching models.': 'Error fetching models.',
251
+ 'Error fetching models. Check your API key.': 'Error fetching models. Check your API key.',
252
+ 'Model list updated ({{count}} models)': 'Model list updated ({{count}} models)',
253
+ 'Enter an API key to test.': 'Enter an API key to test.',
254
+ 'No model details available.': 'No model details available.',
255
+ 'Model: {{model}} | Tokens (in/out): {{in}}/{{out}} | Methods: {{methods}}': 'Model: {{model}} | Tokens (in/out): {{in}}/{{out}} | Methods: {{methods}}',
256
+ 'Global config cleared. Using server defaults.': 'Global config cleared. Using server defaults.',
257
+ 'Clear saved config and return to server defaults': 'Clear saved config and return to server defaults',
258
+ 'Failed to clear global config.': 'Failed to clear global config.',
259
+ 'No key required': 'No key required',
260
+ 'Model & Behavior': 'Model & Behavior',
261
+ 'Choose the model after validating the key.': 'Choose the model after validating the key.',
262
+ 'API key validated required': 'Validated API key required',
263
+ 'Configure and test your API key to unlock model selection.': 'Configure and test your API key to unlock model selection.',
264
+ 'Embeddings (RAG)': 'Embeddings (RAG)',
265
+ 'Use the LLM provider and key for embeddings': 'Apply the LLM provider and key to embeddings',
266
+ 'Provider has no embeddings': 'Provider has no embeddings',
267
+ 'Configure the embeddings provider for vector search (templates and schemas).': 'Configure the embeddings provider for vector search (templates and schemas).',
268
+ 'Embedding dimension mismatch with database (768). Adjust to 768 or redo the migration.': 'Embedding dimension mismatch with the database (768). Adjust to 768 or redo the migration.',
269
+ 'Toolbar, appearance and advanced filter': 'Toolbar, appearance and advanced filter',
270
+ 'Defaults and variants (danger, info, success, question, error)': 'Defaults and variants (danger, info, success, question, error)',
271
+ 'Icons by profile (shortcuts)': 'Icons by profile (shortcuts)',
272
+ 'Pick icon': 'Pick icon',
273
+ 'Pick icon for {{key}}': 'Pick icon for {{key}}',
274
+ 'Clear icon': 'Clear icon',
275
+ 'Clear icon for {{key}}': 'Clear icon for {{key}}',
276
+ 'The text field above remains editable. These buttons only help with selection/clear preview.': 'The text field above remains editable. These buttons only help with selection/clear preview.',
277
+ 'No saved key': 'No saved key',
278
+ 'Aparência: densidade': 'Appearance: density',
279
+ compact: 'compact',
280
+ comfortable: 'comfortable',
281
+ spacious: 'spacious',
282
+ 'Aparência: padding das células': 'Appearance: cell padding',
283
+ 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 6px 12px': 'Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 6px 12px',
284
+ 'Use 1 a 4 medidas CSS válidas, como 6px 12px.': 'Use 1 to 4 valid CSS measures, such as 6px 12px.',
285
+ 'Aparência: padding do cabeçalho': 'Appearance: header padding',
286
+ 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 8px 12px': 'Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 8px 12px',
287
+ 'Use 1 a 4 medidas CSS válidas, como 8px 12px.': 'Use 1 to 4 valid CSS measures, such as 8px 12px.',
288
+ 'Aparência: fonte das células': 'Appearance: cell font size',
289
+ 'Aceita uma medida CSS com unidade, var(...) ou calc(...). Ex.: 13px': 'Accepts a CSS measure with units, var(...) or calc(...). Example: 13px',
290
+ 'Use uma medida CSS válida, como 13px.': 'Use a valid CSS measure, such as 13px.',
291
+ 'Aparência: fonte do cabeçalho': 'Appearance: header font size',
292
+ 'Filtro: modo de abertura': 'Filter: open mode',
293
+ overlay: 'overlay',
294
+ 'Filtro: overlay (visual)': 'Filter: overlay (visual)',
295
+ card: 'card',
296
+ frosted: 'frosted',
297
+ 'Filtro: backdrop no overlay': 'Filter: overlay backdrop',
298
+ 'Excluir — confirmação': 'Delete - confirmation',
299
+ 'Excluir (múltiplos) — confirmação': 'Delete (multiple) - confirmation',
300
+ 'Salvar — confirmação': 'Save - confirmation',
301
+ 'Cancelar — confirmação': 'Cancel - confirmation',
302
+ 'Exportar — confirmação': 'Export - confirmation',
303
+ 'Excluir — progresso': 'Delete - progress',
304
+ 'Excluir (múltiplos) — progresso': 'Delete (multiple) - progress',
305
+ 'Excluir — sucesso': 'Delete - success',
306
+ 'Salvar — sucesso': 'Save - success',
307
+ 'Exportar — sucesso': 'Export - success',
308
+ 'Importar — sucesso': 'Import - success',
309
+ 'Excluir — erro': 'Delete - error',
310
+ 'Salvar — erro': 'Save - error',
311
+ 'Exportar — erro': 'Export - error',
312
+ 'Rede — erro': 'Network - error',
313
+ 'Permissão — erro': 'Permission - error',
314
+ 'Modo de abertura padrão': 'Default opening mode',
315
+ Rota: 'Route',
316
+ 'Aplicado quando ação/metadado não definem modo.': 'Applied when the action/metadata does not define a mode.',
317
+ 'Confirmar ao sair com alterações': 'Confirm when leaving with unsaved changes',
318
+ 'Back: estratégia': 'Back: strategy',
319
+ 'Modal: largura (ex.: 900px)': 'Modal: width (e.g. 900px)',
320
+ 'Modal: largura máxima (ex.: 96vw)': 'Modal: max width (e.g. 96vw)',
321
+ 'Modal: backdrop': 'Modal: backdrop',
322
+ blur: 'blur',
323
+ dim: 'dim',
324
+ transparent: 'transparent',
325
+ 'Estratégia de primeira carga quando metadado não definir.': 'First-load strategy when metadata does not define one.',
326
+ 'Async Select, cascade and pagination': 'Async Select, cascade and pagination',
327
+ 'Cascata nativa habilitada': 'Native cascade enabled',
328
+ 'Cascata: loadOnChange': 'Cascade: loadOnChange',
329
+ respectLoadOn: 'respectLoadOn',
330
+ immediate: 'immediate',
331
+ manual: 'manual',
332
+ 'Cascata: debounce (ms)': 'Cascade: debounce (ms)',
333
+ 'Async Select: loadOn': 'Async Select: loadOn',
334
+ open: 'open',
335
+ init: 'init',
336
+ none: 'none',
337
+ 'Async Select: pageSize': 'Async Select: pageSize',
338
+ 'Async Select: usar cursor': 'Async Select: use cursor',
339
+ 'LLM provider': 'LLM provider',
340
+ 'Select the provider to list models and test the key.': 'Select the provider to list models and test the key.',
341
+ 'API key': 'API key',
342
+ 'Enter the selected provider key to test.': 'Enter the selected provider key to test.',
343
+ 'AI model': 'AI model',
344
+ 'Temperature (Creativity)': 'Temperature (Creativity)',
345
+ '0.0 (deterministic) to 1.0 (creative)': '0.0 (deterministic) to 1.0 (creative)',
346
+ 'Assistant: risk validation': 'Assistant: risk validation',
347
+ 'Standard': 'Standard',
348
+ 'Strict requires confirmation for medium/high risk. Standard follows the indication returned by the backend.': 'Strict requires confirmation for medium/high risk. Standard follows the indication returned by the backend.',
349
+ 'Use same LLM for embeddings': 'Use same LLM for embeddings',
350
+ 'Replicates the LLM provider and key for embeddings.': 'Replicates the LLM provider and key for embeddings.',
351
+ 'Embeddings provider': 'Embeddings provider',
352
+ 'Provider used to generate embeddings (RAG).': 'Provider used to generate embeddings (RAG).',
353
+ 'Embeddings API key': 'Embeddings API key',
354
+ 'Embeddings provider key.': 'Embeddings provider key.',
355
+ 'Embeddings model': 'Embeddings model',
356
+ 'Provider default': 'Provider default',
357
+ 'OpenAI models for embeddings.': 'OpenAI models for embeddings.',
358
+ 'Embeddings: dimensions': 'Embeddings: dimensions',
359
+ 'Embedding vector dimensions (default 768).': 'Embedding vector dimensions (default 768).',
360
+ 'Artificial Intelligence': 'Artificial Intelligence',
361
+ 'LLM integration': 'LLM integration',
362
+ 'Appearance: density': 'Appearance: density',
363
+ 'Appearance: cell padding': 'Appearance: cell padding',
364
+ 'Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 6px 12px': 'Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 6px 12px',
365
+ 'Use 1 to 4 valid CSS measures, such as 6px 12px.': 'Use 1 to 4 valid CSS measures, such as 6px 12px.',
366
+ 'Appearance: header padding': 'Appearance: header padding',
367
+ 'Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 8px 12px': 'Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 8px 12px',
368
+ 'Use 1 to 4 valid CSS measures, such as 8px 12px.': 'Use 1 to 4 valid CSS measures, such as 8px 12px.',
369
+ 'Appearance: cell font size': 'Appearance: cell font size',
370
+ 'Accepts a CSS measure with units, var(...) or calc(...). Example: 13px': 'Accepts a CSS measure with units, var(...) or calc(...). Example: 13px',
371
+ 'Use a valid CSS measure, such as 13px.': 'Use a valid CSS measure, such as 13px.',
372
+ 'Appearance: header font size': 'Appearance: header font size',
373
+ 'Provedor LLM': 'LLM provider',
374
+ 'Selecione o provedor para listar modelos e testar a chave.': 'Select the provider to list models and test the key.',
375
+ 'Chave de API': 'API key',
376
+ 'Informe a chave do provedor selecionado para testar.': 'Enter the selected provider key to test.',
377
+ 'Modelo de IA': 'AI model',
378
+ 'Temperatura (Criatividade)': 'Temperature (Creativity)',
379
+ '0.0 (determinístico) a 1.0 (criativo)': '0.0 (deterministic) to 1.0 (creative)',
380
+ 'Max tokens': 'Max tokens',
381
+ 'Limite maximo de tokens na resposta.': 'Maximum token limit for the response.',
382
+ 'Assistente: validação de risco': 'Assistant: risk validation',
383
+ 'Estrito (recomendado)': 'Strict (recommended)',
384
+ 'Padrão': 'Standard',
385
+ 'Estrito exige confirmação em risco médio/alto. Padrão segue a indicação retornada pelo backend.': 'Strict requires confirmation for medium/high risk. Standard follows the indication returned by the backend.',
386
+ 'Embeddings: usar mesmo LLM': 'Embeddings: use same LLM',
387
+ 'Replica provedor e chave do LLM para embeddings.': 'Replicates the LLM provider and key for embeddings.',
388
+ 'Embeddings: provedor': 'Embeddings: provider',
389
+ 'Provedor usado para gerar embeddings (RAG).': 'Provider used to generate embeddings (RAG).',
390
+ 'Embeddings: chave de API': 'Embeddings: API key',
391
+ 'Chave do provedor de embeddings.': 'Embeddings provider key.',
392
+ 'Embeddings: modelo': 'Embeddings: model',
393
+ 'Padrão do provedor': 'Provider default',
394
+ 'Modelos OpenAI para embeddings.': 'OpenAI models for embeddings.',
395
+ 'Embeddings: dimensoes': 'Embeddings: dimensions',
396
+ 'Dimensoes do vetor de embedding (default 768).': 'Embedding vector dimensions (default 768).',
397
+ 'GPT models for text and chat.': 'GPT models for text and chat.',
398
+ 'Synchronized with the LLM. The fields below follow the primary credential.': 'Synchronized with the LLM. The fields below follow the primary credential.',
399
+ 'Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}': 'Example: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}',
400
+ 'Example JSON array: [{"id":"cancel","text":"Cancel","role":"secondary","close":true,"cssClass":"btn"},{"id":"confirm","text":"Delete","role":"primary","close":true,"cssClass":"btn btn-danger","icon":"delete"}]': 'Example: [{"id":"cancel","text":"Cancel","role":"secondary","close":true,"cssClass":"btn"},{"id":"confirm","text":"Delete","role":"primary","close":true,"cssClass":"btn btn-danger","icon":"delete"}]',
401
+ 'Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}': 'Example: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}',
402
+ 'Desabilitar cache de schema (LocalStorage)': 'Disable schema cache (LocalStorage)',
403
+ 'Se ativo, sempre baixa o schema do servidor (ignora cache local). Útil para desenvolvimento.': 'If enabled, always downloads the schema from the server (ignores local cache). Useful for development.',
404
+ 'Paginação habilitada': 'Pagination enabled',
405
+ 'Tamanho da página': 'Page size',
406
+ 'Ordenação habilitada': 'Sorting enabled',
407
+ 'Seleção habilitada': 'Selection enabled',
408
+ 'Paginação: estratégia': 'Pagination: strategy',
409
+ 'Ordenação: estratégia': 'Sorting: strategy',
410
+ 'Paginação: botões Primeiro/Último': 'Pagination: First/Last buttons',
411
+ 'Toolbar visível': 'Toolbar visible',
412
+ 'Cache & Persistência': 'Cache & Persistence',
413
+ Tabela: 'Table',
414
+ Salvar: 'Save',
415
+ Cancelar: 'Cancel',
416
+ Redefinir: 'Reset',
417
+ };
418
+
419
+ const PRAXIS_SETTINGS_PANEL_EN_US = {
420
+ 'Operation in progress...': 'Operation in progress...',
421
+ 'The form contains errors that need to be fixed.': 'The form contains errors that need to be fixed.',
422
+ 'No changes to apply or save.': 'No changes to apply or save.',
423
+ 'Unsaved changes': 'Unsaved changes',
424
+ 'Saved at {{time}}': 'Saved at {{time}}',
425
+ 'No changes': 'No changes',
426
+ 'Reset Changes': 'Reset Changes',
427
+ 'Are you sure you want to reset all changes?': 'Are you sure you want to reset all changes?',
428
+ Reset: 'Reset',
429
+ Cancel: 'Cancel',
430
+ 'Discard Changes': 'Discard Changes',
431
+ 'You have unsaved changes. Are you sure you want to discard them?': 'You have unsaved changes. Are you sure you want to discard them?',
432
+ Discard: 'Discard',
433
+ 'Continue Editing': 'Continue Editing',
434
+ 'Collapse panel': 'Collapse panel',
435
+ 'Expand panel': 'Expand panel',
436
+ Close: 'Close',
437
+ Apply: 'Apply',
438
+ 'Save & Close': 'Save & Close',
439
+ };
440
+
441
+ const PRAXIS_SETTINGS_PANEL_PT_BR = {
442
+ 'Operation in progress...': 'Operação em andamento...',
443
+ 'The form contains errors that need to be fixed.': 'O formulário contém erros que precisam ser corrigidos.',
444
+ 'No changes to apply or save.': 'Nenhuma alteração para aplicar ou salvar.',
445
+ 'Unsaved changes': 'Alterações não salvas',
446
+ 'Saved at {{time}}': 'Salvo às {{time}}',
447
+ 'No changes': 'Sem alterações',
448
+ 'Reset Changes': 'Redefinir Alterações',
449
+ 'Are you sure you want to reset all changes?': 'Tem certeza de que deseja redefinir todas as alterações?',
450
+ Reset: 'Redefinir',
451
+ Cancel: 'Cancelar',
452
+ 'Discard Changes': 'Descartar Alterações',
453
+ 'You have unsaved changes. Are you sure you want to discard them?': 'Você tem alterações não salvas. Tem certeza de que deseja descartá-las?',
454
+ Discard: 'Descartar',
455
+ 'Continue Editing': 'Continuar Editando',
456
+ 'Collapse panel': 'Reduzir painel',
457
+ 'Expand panel': 'Expandir painel',
458
+ Close: 'Fechar',
459
+ Apply: 'Aplicar',
460
+ 'Save & Close': 'Salvar & Fechar',
461
+ };
462
+
463
+ const PRAXIS_SETTINGS_PANEL_I18N_NAMESPACE = 'praxis-settings-panel';
464
+ const PRAXIS_SETTINGS_PANEL_DEFAULT_TITLE = 'Global settings';
465
+ function providePraxisSettingsPanelI18n() {
466
+ return providePraxisI18n({
467
+ namespaces: {
468
+ [PRAXIS_SETTINGS_PANEL_I18N_NAMESPACE]: {
469
+ 'pt-BR': {
470
+ ...PRAXIS_SETTINGS_PANEL_PT_BR,
471
+ ...PRAXIS_SETTINGS_PANEL_GLOBAL_CONFIG_EDITOR_PT_BR,
472
+ },
473
+ 'en-US': {
474
+ ...PRAXIS_SETTINGS_PANEL_EN_US,
475
+ ...PRAXIS_SETTINGS_PANEL_GLOBAL_CONFIG_EDITOR_EN_US,
476
+ },
477
+ },
478
+ },
479
+ });
480
+ }
481
+
31
482
  class SettingsPanelComponent {
32
483
  cdr;
33
484
  dialog;
@@ -42,6 +493,13 @@ class SettingsPanelComponent {
42
493
  isValid = true;
43
494
  isBusy = false;
44
495
  lastSavedAt = null;
496
+ destroyRef = inject(DestroyRef);
497
+ i18n = inject(PraxisI18nService);
498
+ contentHost;
499
+ constructor(cdr, dialog) {
500
+ this.cdr = cdr;
501
+ this.dialog = dialog;
502
+ }
45
503
  get canApply() {
46
504
  return this.isDirty && this.isValid && !this.isBusy;
47
505
  }
@@ -50,13 +508,13 @@ class SettingsPanelComponent {
50
508
  }
51
509
  get disabledReason() {
52
510
  if (this.isBusy) {
53
- return 'Operação em andamento...';
511
+ return this.tx('Operation in progress...');
54
512
  }
55
513
  if (!this.isValid) {
56
- return 'O formulário contém erros que precisam ser corrigidos.';
514
+ return this.tx('The form contains errors that need to be fixed.');
57
515
  }
58
516
  if (!this.isDirty) {
59
- return 'Nenhuma alteração para aplicar ou salvar.';
517
+ return this.tx('No changes to apply or save.');
60
518
  }
61
519
  return '';
62
520
  }
@@ -71,21 +529,20 @@ class SettingsPanelComponent {
71
529
  }
72
530
  get statusMessage() {
73
531
  if (this.statusTone === 'busy') {
74
- return 'Operação em andamento...';
532
+ return this.tx('Operation in progress...');
75
533
  }
76
534
  if (this.statusTone === 'dirty') {
77
- return 'Alterações não salvas';
535
+ return this.tx('Unsaved changes');
78
536
  }
79
537
  if (this.statusTone === 'saved' && this.lastSavedAt) {
80
- return `Salvo às ${this.formatClock(this.lastSavedAt)}`;
538
+ return this.tx('Saved at {{time}}', {
539
+ time: this.formatClock(this.lastSavedAt),
540
+ });
81
541
  }
82
- return 'Sem alterações';
542
+ return this.tx('No changes');
83
543
  }
84
- destroyRef = inject(DestroyRef);
85
- contentHost;
86
- constructor(cdr, dialog) {
87
- this.cdr = cdr;
88
- this.dialog = dialog;
544
+ tx(text, params) {
545
+ return this.i18n.t(text, params, text, PRAXIS_SETTINGS_PANEL_I18N_NAMESPACE);
89
546
  }
90
547
  attachContent(component, injector, ref, inputs) {
91
548
  this.ref = ref;
@@ -118,7 +575,6 @@ class SettingsPanelComponent {
118
575
  this.cdr.markForCheck();
119
576
  });
120
577
  }
121
- // Generic output bridging: if the embedded component emits `selected`, save and close.
122
578
  try {
123
579
  const selected$ = instance?.selected;
124
580
  if (selected$ && typeof selected$.subscribe === 'function') {
@@ -126,7 +582,6 @@ class SettingsPanelComponent {
126
582
  ? selected$.pipe(takeUntilDestroyed(this.destroyRef))
127
583
  : selected$;
128
584
  obs.subscribe((value) => {
129
- // Apply emits value to the opener without closing the panel.
130
585
  this.ref.apply(value);
131
586
  });
132
587
  }
@@ -164,10 +619,10 @@ class SettingsPanelComponent {
164
619
  }
165
620
  onReset() {
166
621
  const dialogData = {
167
- title: 'Redefinir Alterações',
168
- message: 'Tem certeza de que deseja redefinir todas as alterações?',
169
- confirmText: 'Redefinir',
170
- cancelText: 'Cancelar',
622
+ title: this.tx('Reset Changes'),
623
+ message: this.tx('Are you sure you want to reset all changes?'),
624
+ confirmText: this.tx('Reset'),
625
+ cancelText: this.tx('Cancel'),
171
626
  type: 'warning',
172
627
  icon: 'restart_alt',
173
628
  };
@@ -219,15 +674,21 @@ class SettingsPanelComponent {
219
674
  this.cdr.markForCheck();
220
675
  }
221
676
  formatClock(timestamp) {
677
+ const options = {
678
+ hour: '2-digit',
679
+ minute: '2-digit',
680
+ second: '2-digit',
681
+ };
222
682
  try {
223
- return new Intl.DateTimeFormat('pt-BR', {
224
- hour: '2-digit',
225
- minute: '2-digit',
226
- second: '2-digit',
227
- }).format(timestamp);
683
+ return new Intl.DateTimeFormat(this.i18n.getLocale(), options).format(timestamp);
228
684
  }
229
685
  catch {
230
- return '';
686
+ try {
687
+ return new Intl.DateTimeFormat(this.i18n.getFallbackLocale(), options).format(timestamp);
688
+ }
689
+ catch {
690
+ return '';
691
+ }
231
692
  }
232
693
  }
233
694
  toggleExpand() {
@@ -241,10 +702,10 @@ class SettingsPanelComponent {
241
702
  return of(true);
242
703
  }
243
704
  const dialogData = {
244
- title: 'Descartar Alterações',
245
- message: 'Você tem alterações não salvas. Tem certeza de que deseja descartá-las?',
246
- confirmText: 'Descartar',
247
- cancelText: 'Continuar Editando',
705
+ title: this.tx('Discard Changes'),
706
+ message: this.tx('You have unsaved changes. Are you sure you want to discard them?'),
707
+ confirmText: this.tx('Discard'),
708
+ cancelText: this.tx('Continue Editing'),
248
709
  type: 'warning',
249
710
  icon: 'warning',
250
711
  };
@@ -265,13 +726,14 @@ class SettingsPanelComponent {
265
726
  event.preventDefault();
266
727
  this.onSave();
267
728
  }
268
- else if ((event.key === 's' || event.key === 'S') && (event.ctrlKey || event.metaKey)) {
729
+ else if ((event.key === 's' || event.key === 'S') &&
730
+ (event.ctrlKey || event.metaKey)) {
269
731
  event.preventDefault();
270
732
  this.onSave();
271
733
  }
272
734
  }
273
735
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SettingsPanelComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
274
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: SettingsPanelComponent, isStandalone: true, selector: "praxis-settings-panel", host: { listeners: { "document:keydown": "handleKeydown($event)" } }, viewQueries: [{ propertyName: "contentHost", first: true, predicate: ["contentHost"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: "<div\n class=\"settings-panel\"\n data-testid=\"settings-panel-root\"\n [class.expanded]=\"expanded\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-labelledby]=\"titleId\"\n cdkTrapFocus\n cdkTrapFocusAutoCapture\n>\n <header class=\"settings-panel-header\">\n <h2 class=\"settings-panel-title\" [id]=\"titleId\">\n <mat-icon *ngIf=\"titleIcon\" class=\"title-icon\" [praxisIcon]=\"titleIcon\"></mat-icon>\n <span>{{ title }}</span>\n </h2>\n <span class=\"spacer\"></span>\n <button\n mat-icon-button\n type=\"button\"\n data-testid=\"settings-panel-toggle-expand\"\n [attr.aria-label]=\"expanded ? 'Reduzir painel' : 'Expandir painel'\"\n [attr.aria-expanded]=\"expanded\"\n [matTooltip]=\"expanded ? 'Reduzir painel' : 'Expandir painel'\"\n (click)=\"toggleExpand()\"\n >\n <mat-icon [praxisIcon]=\"expanded ? 'close_fullscreen' : 'open_in_full'\"></mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n data-testid=\"settings-panel-close-icon\"\n aria-label=\"Fechar\"\n matTooltip=\"Fechar\"\n (click)=\"onCancel()\"\n >\n <mat-icon [praxisIcon]=\"'close'\"></mat-icon>\n </button>\n </header>\n <div\n class=\"settings-panel-status\"\n [attr.data-status]=\"statusTone\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <mat-icon\n aria-hidden=\"true\"\n [praxisIcon]=\"\n statusTone === 'dirty'\n ? 'warning'\n : statusTone === 'saved'\n ? 'check_circle'\n : statusTone === 'busy'\n ? 'autorenew'\n : 'info'\n \"\n ></mat-icon>\n <span>{{ statusMessage }}</span>\n </div>\n <div class=\"settings-panel-body\">\n <ng-template #contentHost></ng-template>\n </div>\n <footer class=\"settings-panel-footer\">\n <button mat-button type=\"button\" data-testid=\"settings-panel-reset\" (click)=\"onReset()\" [disabled]=\"isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'restart_alt'\"></mat-icon>\n <span>Redefinir</span>\n </button>\n <span class=\"spacer\"></span>\n <button\n mat-button\n type=\"button\"\n data-testid=\"settings-panel-cancel\"\n (click)=\"onCancel()\"\n [disabled]=\"isBusy\"\n >\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'close'\"></mat-icon>\n <span>Cancelar</span>\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n data-testid=\"settings-panel-apply\"\n (click)=\"onApply()\"\n [disabled]=\"!canApply\"\n [matTooltip]=\"disabledReason\"\n [matTooltipDisabled]=\"canApply\"\n [attr.aria-busy]=\"isBusy\"\n >\n <mat-progress-spinner\n *ngIf=\"isBusy\"\n mode=\"indeterminate\"\n diameter=\"20\"\n ></mat-progress-spinner>\n <ng-container *ngIf=\"!isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'done'\"></mat-icon>\n <span>Aplicar</span>\n </ng-container>\n </button>\n <button\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n data-testid=\"settings-panel-save\"\n (click)=\"onSave()\"\n [disabled]=\"!canSave\"\n [matTooltip]=\"disabledReason\"\n [matTooltipDisabled]=\"canSave\"\n [attr.aria-busy]=\"isBusy\"\n >\n <mat-progress-spinner\n *ngIf=\"isBusy\"\n mode=\"indeterminate\"\n diameter=\"20\"\n ></mat-progress-spinner>\n <ng-container *ngIf=\"!isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'save'\"></mat-icon>\n <span>Salvar &amp; Fechar</span>\n </ng-container>\n </button>\n </footer>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;height:100%}.settings-panel{display:grid;grid-template-rows:auto auto 1fr auto;grid-template-areas:\"header\" \"status\" \"body\" \"footer\";height:100%;background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface);border-left:1px solid var(--md-sys-color-outline-variant);width:var(--pfx-settings-panel-width, 720px);transition:width .3s ease;overflow:hidden}.settings-panel.expanded{width:min(var(--pfx-settings-panel-width-expanded, 95vw),var(--pfx-settings-panel-max-width, 2400px))}.settings-panel-header{grid-area:header;display:flex;align-items:center;gap:var(--pfx-settings-panel-header-gap, 8px);padding:0 var(--pfx-settings-panel-header-padding-x, 16px);height:var(--pfx-settings-panel-header-height, 64px);border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);box-shadow:var(--pfx-settings-panel-header-shadow, var(--md-sys-elevation-level1, 0 2px 6px rgba(0, 0, 0, .08)));flex-shrink:0}.settings-panel-header .spacer{flex:1}.settings-panel-status{grid-area:status;display:flex;align-items:center;gap:8px;min-height:36px;padding:6px 16px;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);font-size:.85rem;font-weight:500}.settings-panel-status mat-icon{width:18px;height:18px;font-size:18px}.settings-panel-status[data-status=dirty]{color:var(--md-sys-color-error);background:color-mix(in srgb,var(--md-sys-color-error-container) 30%,var(--md-sys-color-surface-container-high))}.settings-panel-status[data-status=saved]{color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 28%,var(--md-sys-color-surface-container-high))}.settings-panel-body{grid-area:body;overflow-y:auto;min-height:0;padding:var(--pfx-settings-panel-body-padding, 8px 8px 24px 8px);background:var(--md-sys-color-surface);display:flex;flex-direction:column}.settings-panel-content{display:block}.settings-panel-footer{grid-area:footer;border-top:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);box-shadow:var(--pfx-settings-panel-footer-shadow, var(--md-sys-elevation-level1, 0 -2px 6px rgba(0, 0, 0, .08)));display:flex;align-items:center;padding:var(--pfx-settings-panel-footer-padding, 12px 16px);column-gap:var(--pfx-settings-panel-footer-gap, 12px);flex-shrink:0}.spacer{flex:1}.settings-panel-title{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-title-gap, 8px);font-weight:700;letter-spacing:.2px;margin:0}.settings-panel-title mat-icon{color:var(--md-sys-color-primary)}.settings-panel-title .title-icon{width:20px;height:20px;font-size:20px}.settings-panel-footer button+button{margin-left:var(--pfx-settings-panel-footer-gap, 12px)}.settings-panel-footer button{display:inline-flex;align-items:center}.settings-panel-footer button .mat-icon{font-size:20px;width:20px;height:20px;line-height:1;display:inline-flex;align-items:center;justify-content:center}.settings-panel-footer .mat-button-wrapper{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-button-gap, 8px)}.settings-panel-footer .mat-progress-spinner{margin-right:8px}.settings-panel-footer .mat-flat-button[color=primary]{font-weight:600}:host ::ng-deep .settings-panel .mdc-button__label{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-button-gap, 8px);line-height:1}:host ::ng-deep .settings-panel .mdc-button__label>span{display:inline-flex;align-items:center;line-height:1}:host ::ng-deep .settings-panel .mdc-button__label .mat-icon{display:inline-flex;align-items:center;justify-content:center;line-height:1}:host ::ng-deep .praxis-settings-panel-backdrop{background:var(--pfx-backdrop, var(--md-sys-color-scrim, rgba(0, 0, 0, .45)));backdrop-filter:blur(var(--pfx-backdrop-blur, 6px)) saturate(110%);-webkit-backdrop-filter:blur(var(--pfx-backdrop-blur, 6px)) saturate(110%)}.settings-panel .mat-divider{background-color:var(--md-sys-color-outline-variant)!important}.settings-panel .mat-expansion-panel{background:var(--md-sys-color-surface-container);border:1px solid var(--md-sys-color-outline-variant);border-radius:var(--md-sys-shape-corner-medium, 12px);box-shadow:var(--md-sys-elevation-level1, 0 2px 8px rgba(0, 0, 0, .08))}.settings-panel .mat-expansion-panel-header{background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface)}.settings-panel .mat-expansion-panel-header mat-icon,.settings-panel .mat-expansion-panel-header .mat-icon{color:var(--md-sys-color-on-surface)!important}.settings-panel .mat-expansion-panel-header .mat-expansion-panel-header-title,.settings-panel .mat-expansion-panel-header .mat-expansion-panel-header-description{color:var(--md-sys-color-on-surface)}.settings-panel .mat-expansion-panel-header .mat-expansion-indicator,.settings-panel .mat-expansion-panel-header .mat-expansion-indicator:after{color:var(--md-sys-color-on-surface-variant);border-color:var(--md-sys-color-on-surface-variant)}:host ::ng-deep .settings-panel .mat-expansion-panel .mat-expansion-panel-body{padding:8px}.settings-panel .mat-mdc-tab-group .mat-mdc-tab-header{border-bottom:1px solid var(--md-sys-color-outline-variant)}.settings-panel .mat-mdc-tab-group .mdc-tab .mdc-tab__text-label{color:var(--md-sys-color-on-surface-variant)}.settings-panel .mat-mdc-tab-group .mdc-tab.mdc-tab--active .mdc-tab__text-label{color:var(--md-sys-color-on-surface)}.settings-panel .mat-mdc-tab-group .mdc-tab-indicator__content--underline{border-color:var(--md-sys-color-primary)}.settings-panel .mat-mdc-form-field{--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-secondary, var(--md-sys-color-primary));--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary)}:host ::ng-deep .praxis-settings-panel-pane{position:fixed!important;top:0!important;right:0!important;height:100vh!important;z-index:1000}:host ::ng-deep .praxis-settings-panel-pane .settings-panel{pointer-events:auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i6.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatDialogModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
736
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: SettingsPanelComponent, isStandalone: true, selector: "praxis-settings-panel", host: { listeners: { "document:keydown": "handleKeydown($event)" } }, providers: [providePraxisSettingsPanelI18n()], viewQueries: [{ propertyName: "contentHost", first: true, predicate: ["contentHost"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: "<div\n class=\"settings-panel\"\n data-testid=\"settings-panel-root\"\n [class.expanded]=\"expanded\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-labelledby]=\"titleId\"\n cdkTrapFocus\n cdkTrapFocusAutoCapture\n>\n <header class=\"settings-panel-header\">\n <h2 class=\"settings-panel-title\" [id]=\"titleId\">\n <mat-icon *ngIf=\"titleIcon\" class=\"title-icon\" [praxisIcon]=\"titleIcon\"></mat-icon>\n <span>{{ title }}</span>\n </h2>\n <span class=\"spacer\"></span>\n <button\n mat-icon-button\n type=\"button\"\n data-testid=\"settings-panel-toggle-expand\"\n [attr.aria-label]=\"expanded ? tx('Collapse panel') : tx('Expand panel')\"\n [attr.aria-expanded]=\"expanded\"\n [matTooltip]=\"expanded ? tx('Collapse panel') : tx('Expand panel')\"\n (click)=\"toggleExpand()\"\n >\n <mat-icon [praxisIcon]=\"expanded ? 'close_fullscreen' : 'open_in_full'\"></mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n data-testid=\"settings-panel-close-icon\"\n [attr.aria-label]=\"tx('Close')\"\n [matTooltip]=\"tx('Close')\"\n (click)=\"onCancel()\"\n >\n <mat-icon [praxisIcon]=\"'close'\"></mat-icon>\n </button>\n </header>\n <div\n class=\"settings-panel-status\"\n [attr.data-status]=\"statusTone\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <mat-icon\n aria-hidden=\"true\"\n [praxisIcon]=\"\n statusTone === 'dirty'\n ? 'warning'\n : statusTone === 'saved'\n ? 'check_circle'\n : statusTone === 'busy'\n ? 'autorenew'\n : 'info'\n \"\n ></mat-icon>\n <span>{{ statusMessage }}</span>\n </div>\n <div class=\"settings-panel-body\">\n <ng-template #contentHost></ng-template>\n </div>\n <footer class=\"settings-panel-footer\">\n <button mat-button type=\"button\" data-testid=\"settings-panel-reset\" (click)=\"onReset()\" [disabled]=\"isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'restart_alt'\"></mat-icon>\n <span>{{ tx('Reset') }}</span>\n </button>\n <span class=\"spacer\"></span>\n <button\n mat-button\n type=\"button\"\n data-testid=\"settings-panel-cancel\"\n (click)=\"onCancel()\"\n [disabled]=\"isBusy\"\n >\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'close'\"></mat-icon>\n <span>{{ tx('Cancel') }}</span>\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n data-testid=\"settings-panel-apply\"\n (click)=\"onApply()\"\n [disabled]=\"!canApply\"\n [matTooltip]=\"disabledReason\"\n [matTooltipDisabled]=\"canApply\"\n [attr.aria-busy]=\"isBusy\"\n >\n <mat-progress-spinner\n *ngIf=\"isBusy\"\n mode=\"indeterminate\"\n diameter=\"20\"\n ></mat-progress-spinner>\n <ng-container *ngIf=\"!isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'done'\"></mat-icon>\n <span>{{ tx('Apply') }}</span>\n </ng-container>\n </button>\n <button\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n data-testid=\"settings-panel-save\"\n (click)=\"onSave()\"\n [disabled]=\"!canSave\"\n [matTooltip]=\"disabledReason\"\n [matTooltipDisabled]=\"canSave\"\n [attr.aria-busy]=\"isBusy\"\n >\n <mat-progress-spinner\n *ngIf=\"isBusy\"\n mode=\"indeterminate\"\n diameter=\"20\"\n ></mat-progress-spinner>\n <ng-container *ngIf=\"!isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'save'\"></mat-icon>\n <span>{{ tx('Save & Close') }}</span>\n </ng-container>\n </button>\n </footer>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;height:100%}.settings-panel{display:grid;grid-template-rows:auto auto 1fr auto;grid-template-areas:\"header\" \"status\" \"body\" \"footer\";height:100%;background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface);border-left:1px solid var(--md-sys-color-outline-variant);width:var(--pfx-settings-panel-width, 720px);transition:width .3s ease;overflow:hidden}.settings-panel.expanded{width:min(var(--pfx-settings-panel-width-expanded, 95vw),var(--pfx-settings-panel-max-width, 2400px))}.settings-panel-header{grid-area:header;display:flex;align-items:center;gap:var(--pfx-settings-panel-header-gap, 8px);padding:0 var(--pfx-settings-panel-header-padding-x, 16px);height:var(--pfx-settings-panel-header-height, 64px);border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);box-shadow:var(--pfx-settings-panel-header-shadow, var(--md-sys-elevation-level1, 0 2px 6px rgba(0, 0, 0, .08)));flex-shrink:0}.settings-panel-header .spacer{flex:1}.settings-panel-status{grid-area:status;display:flex;align-items:center;gap:8px;min-height:36px;padding:6px 16px;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);font-size:.85rem;font-weight:500}.settings-panel-status mat-icon{width:18px;height:18px;font-size:18px}.settings-panel-status[data-status=dirty]{color:var(--md-sys-color-error);background:color-mix(in srgb,var(--md-sys-color-error-container) 30%,var(--md-sys-color-surface-container-high))}.settings-panel-status[data-status=saved]{color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 28%,var(--md-sys-color-surface-container-high))}.settings-panel-body{grid-area:body;overflow-y:auto;min-height:0;padding:var(--pfx-settings-panel-body-padding, 8px 8px 24px 8px);background:var(--md-sys-color-surface);display:flex;flex-direction:column}.settings-panel-content{display:block}.settings-panel-footer{grid-area:footer;border-top:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);box-shadow:var(--pfx-settings-panel-footer-shadow, var(--md-sys-elevation-level1, 0 -2px 6px rgba(0, 0, 0, .08)));display:flex;align-items:center;padding:var(--pfx-settings-panel-footer-padding, 12px 16px);column-gap:var(--pfx-settings-panel-footer-gap, 12px);flex-shrink:0}.spacer{flex:1}.settings-panel-title{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-title-gap, 8px);font-weight:700;letter-spacing:.2px;margin:0}.settings-panel-title mat-icon{color:var(--md-sys-color-primary)}.settings-panel-title .title-icon{width:20px;height:20px;font-size:20px}.settings-panel-footer button+button{margin-left:var(--pfx-settings-panel-footer-gap, 12px)}.settings-panel-footer button{display:inline-flex;align-items:center}.settings-panel-footer button .mat-icon{font-size:20px;width:20px;height:20px;line-height:1;display:inline-flex;align-items:center;justify-content:center}.settings-panel-footer .mat-button-wrapper{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-button-gap, 8px)}.settings-panel-footer .mat-progress-spinner{margin-right:8px}.settings-panel-footer .mat-flat-button[color=primary]{font-weight:600}:host ::ng-deep .settings-panel .mdc-button__label{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-button-gap, 8px);line-height:1}:host ::ng-deep .settings-panel .mdc-button__label>span{display:inline-flex;align-items:center;line-height:1}:host ::ng-deep .settings-panel .mdc-button__label .mat-icon{display:inline-flex;align-items:center;justify-content:center;line-height:1}:host ::ng-deep .praxis-settings-panel-backdrop{background:var(--pfx-backdrop, var(--md-sys-color-scrim, rgba(0, 0, 0, .45)));backdrop-filter:blur(var(--pfx-backdrop-blur, 6px)) saturate(110%);-webkit-backdrop-filter:blur(var(--pfx-backdrop-blur, 6px)) saturate(110%)}.settings-panel .mat-divider{background-color:var(--md-sys-color-outline-variant)!important}.settings-panel .mat-expansion-panel{background:var(--md-sys-color-surface-container);border:1px solid var(--md-sys-color-outline-variant);border-radius:var(--md-sys-shape-corner-medium, 12px);box-shadow:var(--md-sys-elevation-level1, 0 2px 8px rgba(0, 0, 0, .08))}.settings-panel .mat-expansion-panel-header{background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface)}.settings-panel .mat-expansion-panel-header mat-icon,.settings-panel .mat-expansion-panel-header .mat-icon{color:var(--md-sys-color-on-surface)!important}.settings-panel .mat-expansion-panel-header .mat-expansion-panel-header-title,.settings-panel .mat-expansion-panel-header .mat-expansion-panel-header-description{color:var(--md-sys-color-on-surface)}.settings-panel .mat-expansion-panel-header .mat-expansion-indicator,.settings-panel .mat-expansion-panel-header .mat-expansion-indicator:after{color:var(--md-sys-color-on-surface-variant);border-color:var(--md-sys-color-on-surface-variant)}:host ::ng-deep .settings-panel .mat-expansion-panel .mat-expansion-panel-body{padding:8px}.settings-panel .mat-mdc-tab-group .mat-mdc-tab-header{border-bottom:1px solid var(--md-sys-color-outline-variant)}.settings-panel .mat-mdc-tab-group .mdc-tab .mdc-tab__text-label{color:var(--md-sys-color-on-surface-variant)}.settings-panel .mat-mdc-tab-group .mdc-tab.mdc-tab--active .mdc-tab__text-label{color:var(--md-sys-color-on-surface)}.settings-panel .mat-mdc-tab-group .mdc-tab-indicator__content--underline{border-color:var(--md-sys-color-primary)}.settings-panel .mat-mdc-form-field{--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-secondary, var(--md-sys-color-primary));--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary)}:host ::ng-deep .praxis-settings-panel-pane{position:fixed!important;top:0!important;right:0!important;height:100vh!important;z-index:1000}:host ::ng-deep .praxis-settings-panel-pane .settings-panel{pointer-events:auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i6.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatDialogModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
275
737
  }
276
738
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SettingsPanelComponent, decorators: [{
277
739
  type: Component,
@@ -284,7 +746,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
284
746
  CdkTrapFocus,
285
747
  MatProgressSpinnerModule,
286
748
  MatDialogModule,
287
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"settings-panel\"\n data-testid=\"settings-panel-root\"\n [class.expanded]=\"expanded\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-labelledby]=\"titleId\"\n cdkTrapFocus\n cdkTrapFocusAutoCapture\n>\n <header class=\"settings-panel-header\">\n <h2 class=\"settings-panel-title\" [id]=\"titleId\">\n <mat-icon *ngIf=\"titleIcon\" class=\"title-icon\" [praxisIcon]=\"titleIcon\"></mat-icon>\n <span>{{ title }}</span>\n </h2>\n <span class=\"spacer\"></span>\n <button\n mat-icon-button\n type=\"button\"\n data-testid=\"settings-panel-toggle-expand\"\n [attr.aria-label]=\"expanded ? 'Reduzir painel' : 'Expandir painel'\"\n [attr.aria-expanded]=\"expanded\"\n [matTooltip]=\"expanded ? 'Reduzir painel' : 'Expandir painel'\"\n (click)=\"toggleExpand()\"\n >\n <mat-icon [praxisIcon]=\"expanded ? 'close_fullscreen' : 'open_in_full'\"></mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n data-testid=\"settings-panel-close-icon\"\n aria-label=\"Fechar\"\n matTooltip=\"Fechar\"\n (click)=\"onCancel()\"\n >\n <mat-icon [praxisIcon]=\"'close'\"></mat-icon>\n </button>\n </header>\n <div\n class=\"settings-panel-status\"\n [attr.data-status]=\"statusTone\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <mat-icon\n aria-hidden=\"true\"\n [praxisIcon]=\"\n statusTone === 'dirty'\n ? 'warning'\n : statusTone === 'saved'\n ? 'check_circle'\n : statusTone === 'busy'\n ? 'autorenew'\n : 'info'\n \"\n ></mat-icon>\n <span>{{ statusMessage }}</span>\n </div>\n <div class=\"settings-panel-body\">\n <ng-template #contentHost></ng-template>\n </div>\n <footer class=\"settings-panel-footer\">\n <button mat-button type=\"button\" data-testid=\"settings-panel-reset\" (click)=\"onReset()\" [disabled]=\"isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'restart_alt'\"></mat-icon>\n <span>Redefinir</span>\n </button>\n <span class=\"spacer\"></span>\n <button\n mat-button\n type=\"button\"\n data-testid=\"settings-panel-cancel\"\n (click)=\"onCancel()\"\n [disabled]=\"isBusy\"\n >\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'close'\"></mat-icon>\n <span>Cancelar</span>\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n data-testid=\"settings-panel-apply\"\n (click)=\"onApply()\"\n [disabled]=\"!canApply\"\n [matTooltip]=\"disabledReason\"\n [matTooltipDisabled]=\"canApply\"\n [attr.aria-busy]=\"isBusy\"\n >\n <mat-progress-spinner\n *ngIf=\"isBusy\"\n mode=\"indeterminate\"\n diameter=\"20\"\n ></mat-progress-spinner>\n <ng-container *ngIf=\"!isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'done'\"></mat-icon>\n <span>Aplicar</span>\n </ng-container>\n </button>\n <button\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n data-testid=\"settings-panel-save\"\n (click)=\"onSave()\"\n [disabled]=\"!canSave\"\n [matTooltip]=\"disabledReason\"\n [matTooltipDisabled]=\"canSave\"\n [attr.aria-busy]=\"isBusy\"\n >\n <mat-progress-spinner\n *ngIf=\"isBusy\"\n mode=\"indeterminate\"\n diameter=\"20\"\n ></mat-progress-spinner>\n <ng-container *ngIf=\"!isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'save'\"></mat-icon>\n <span>Salvar &amp; Fechar</span>\n </ng-container>\n </button>\n </footer>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;height:100%}.settings-panel{display:grid;grid-template-rows:auto auto 1fr auto;grid-template-areas:\"header\" \"status\" \"body\" \"footer\";height:100%;background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface);border-left:1px solid var(--md-sys-color-outline-variant);width:var(--pfx-settings-panel-width, 720px);transition:width .3s ease;overflow:hidden}.settings-panel.expanded{width:min(var(--pfx-settings-panel-width-expanded, 95vw),var(--pfx-settings-panel-max-width, 2400px))}.settings-panel-header{grid-area:header;display:flex;align-items:center;gap:var(--pfx-settings-panel-header-gap, 8px);padding:0 var(--pfx-settings-panel-header-padding-x, 16px);height:var(--pfx-settings-panel-header-height, 64px);border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);box-shadow:var(--pfx-settings-panel-header-shadow, var(--md-sys-elevation-level1, 0 2px 6px rgba(0, 0, 0, .08)));flex-shrink:0}.settings-panel-header .spacer{flex:1}.settings-panel-status{grid-area:status;display:flex;align-items:center;gap:8px;min-height:36px;padding:6px 16px;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);font-size:.85rem;font-weight:500}.settings-panel-status mat-icon{width:18px;height:18px;font-size:18px}.settings-panel-status[data-status=dirty]{color:var(--md-sys-color-error);background:color-mix(in srgb,var(--md-sys-color-error-container) 30%,var(--md-sys-color-surface-container-high))}.settings-panel-status[data-status=saved]{color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 28%,var(--md-sys-color-surface-container-high))}.settings-panel-body{grid-area:body;overflow-y:auto;min-height:0;padding:var(--pfx-settings-panel-body-padding, 8px 8px 24px 8px);background:var(--md-sys-color-surface);display:flex;flex-direction:column}.settings-panel-content{display:block}.settings-panel-footer{grid-area:footer;border-top:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);box-shadow:var(--pfx-settings-panel-footer-shadow, var(--md-sys-elevation-level1, 0 -2px 6px rgba(0, 0, 0, .08)));display:flex;align-items:center;padding:var(--pfx-settings-panel-footer-padding, 12px 16px);column-gap:var(--pfx-settings-panel-footer-gap, 12px);flex-shrink:0}.spacer{flex:1}.settings-panel-title{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-title-gap, 8px);font-weight:700;letter-spacing:.2px;margin:0}.settings-panel-title mat-icon{color:var(--md-sys-color-primary)}.settings-panel-title .title-icon{width:20px;height:20px;font-size:20px}.settings-panel-footer button+button{margin-left:var(--pfx-settings-panel-footer-gap, 12px)}.settings-panel-footer button{display:inline-flex;align-items:center}.settings-panel-footer button .mat-icon{font-size:20px;width:20px;height:20px;line-height:1;display:inline-flex;align-items:center;justify-content:center}.settings-panel-footer .mat-button-wrapper{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-button-gap, 8px)}.settings-panel-footer .mat-progress-spinner{margin-right:8px}.settings-panel-footer .mat-flat-button[color=primary]{font-weight:600}:host ::ng-deep .settings-panel .mdc-button__label{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-button-gap, 8px);line-height:1}:host ::ng-deep .settings-panel .mdc-button__label>span{display:inline-flex;align-items:center;line-height:1}:host ::ng-deep .settings-panel .mdc-button__label .mat-icon{display:inline-flex;align-items:center;justify-content:center;line-height:1}:host ::ng-deep .praxis-settings-panel-backdrop{background:var(--pfx-backdrop, var(--md-sys-color-scrim, rgba(0, 0, 0, .45)));backdrop-filter:blur(var(--pfx-backdrop-blur, 6px)) saturate(110%);-webkit-backdrop-filter:blur(var(--pfx-backdrop-blur, 6px)) saturate(110%)}.settings-panel .mat-divider{background-color:var(--md-sys-color-outline-variant)!important}.settings-panel .mat-expansion-panel{background:var(--md-sys-color-surface-container);border:1px solid var(--md-sys-color-outline-variant);border-radius:var(--md-sys-shape-corner-medium, 12px);box-shadow:var(--md-sys-elevation-level1, 0 2px 8px rgba(0, 0, 0, .08))}.settings-panel .mat-expansion-panel-header{background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface)}.settings-panel .mat-expansion-panel-header mat-icon,.settings-panel .mat-expansion-panel-header .mat-icon{color:var(--md-sys-color-on-surface)!important}.settings-panel .mat-expansion-panel-header .mat-expansion-panel-header-title,.settings-panel .mat-expansion-panel-header .mat-expansion-panel-header-description{color:var(--md-sys-color-on-surface)}.settings-panel .mat-expansion-panel-header .mat-expansion-indicator,.settings-panel .mat-expansion-panel-header .mat-expansion-indicator:after{color:var(--md-sys-color-on-surface-variant);border-color:var(--md-sys-color-on-surface-variant)}:host ::ng-deep .settings-panel .mat-expansion-panel .mat-expansion-panel-body{padding:8px}.settings-panel .mat-mdc-tab-group .mat-mdc-tab-header{border-bottom:1px solid var(--md-sys-color-outline-variant)}.settings-panel .mat-mdc-tab-group .mdc-tab .mdc-tab__text-label{color:var(--md-sys-color-on-surface-variant)}.settings-panel .mat-mdc-tab-group .mdc-tab.mdc-tab--active .mdc-tab__text-label{color:var(--md-sys-color-on-surface)}.settings-panel .mat-mdc-tab-group .mdc-tab-indicator__content--underline{border-color:var(--md-sys-color-primary)}.settings-panel .mat-mdc-form-field{--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-secondary, var(--md-sys-color-primary));--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary)}:host ::ng-deep .praxis-settings-panel-pane{position:fixed!important;top:0!important;right:0!important;height:100vh!important;z-index:1000}:host ::ng-deep .praxis-settings-panel-pane .settings-panel{pointer-events:auto}\n"] }]
749
+ ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [providePraxisSettingsPanelI18n()], template: "<div\n class=\"settings-panel\"\n data-testid=\"settings-panel-root\"\n [class.expanded]=\"expanded\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-labelledby]=\"titleId\"\n cdkTrapFocus\n cdkTrapFocusAutoCapture\n>\n <header class=\"settings-panel-header\">\n <h2 class=\"settings-panel-title\" [id]=\"titleId\">\n <mat-icon *ngIf=\"titleIcon\" class=\"title-icon\" [praxisIcon]=\"titleIcon\"></mat-icon>\n <span>{{ title }}</span>\n </h2>\n <span class=\"spacer\"></span>\n <button\n mat-icon-button\n type=\"button\"\n data-testid=\"settings-panel-toggle-expand\"\n [attr.aria-label]=\"expanded ? tx('Collapse panel') : tx('Expand panel')\"\n [attr.aria-expanded]=\"expanded\"\n [matTooltip]=\"expanded ? tx('Collapse panel') : tx('Expand panel')\"\n (click)=\"toggleExpand()\"\n >\n <mat-icon [praxisIcon]=\"expanded ? 'close_fullscreen' : 'open_in_full'\"></mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n data-testid=\"settings-panel-close-icon\"\n [attr.aria-label]=\"tx('Close')\"\n [matTooltip]=\"tx('Close')\"\n (click)=\"onCancel()\"\n >\n <mat-icon [praxisIcon]=\"'close'\"></mat-icon>\n </button>\n </header>\n <div\n class=\"settings-panel-status\"\n [attr.data-status]=\"statusTone\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <mat-icon\n aria-hidden=\"true\"\n [praxisIcon]=\"\n statusTone === 'dirty'\n ? 'warning'\n : statusTone === 'saved'\n ? 'check_circle'\n : statusTone === 'busy'\n ? 'autorenew'\n : 'info'\n \"\n ></mat-icon>\n <span>{{ statusMessage }}</span>\n </div>\n <div class=\"settings-panel-body\">\n <ng-template #contentHost></ng-template>\n </div>\n <footer class=\"settings-panel-footer\">\n <button mat-button type=\"button\" data-testid=\"settings-panel-reset\" (click)=\"onReset()\" [disabled]=\"isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'restart_alt'\"></mat-icon>\n <span>{{ tx('Reset') }}</span>\n </button>\n <span class=\"spacer\"></span>\n <button\n mat-button\n type=\"button\"\n data-testid=\"settings-panel-cancel\"\n (click)=\"onCancel()\"\n [disabled]=\"isBusy\"\n >\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'close'\"></mat-icon>\n <span>{{ tx('Cancel') }}</span>\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n data-testid=\"settings-panel-apply\"\n (click)=\"onApply()\"\n [disabled]=\"!canApply\"\n [matTooltip]=\"disabledReason\"\n [matTooltipDisabled]=\"canApply\"\n [attr.aria-busy]=\"isBusy\"\n >\n <mat-progress-spinner\n *ngIf=\"isBusy\"\n mode=\"indeterminate\"\n diameter=\"20\"\n ></mat-progress-spinner>\n <ng-container *ngIf=\"!isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'done'\"></mat-icon>\n <span>{{ tx('Apply') }}</span>\n </ng-container>\n </button>\n <button\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n data-testid=\"settings-panel-save\"\n (click)=\"onSave()\"\n [disabled]=\"!canSave\"\n [matTooltip]=\"disabledReason\"\n [matTooltipDisabled]=\"canSave\"\n [attr.aria-busy]=\"isBusy\"\n >\n <mat-progress-spinner\n *ngIf=\"isBusy\"\n mode=\"indeterminate\"\n diameter=\"20\"\n ></mat-progress-spinner>\n <ng-container *ngIf=\"!isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'save'\"></mat-icon>\n <span>{{ tx('Save & Close') }}</span>\n </ng-container>\n </button>\n </footer>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;height:100%}.settings-panel{display:grid;grid-template-rows:auto auto 1fr auto;grid-template-areas:\"header\" \"status\" \"body\" \"footer\";height:100%;background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface);border-left:1px solid var(--md-sys-color-outline-variant);width:var(--pfx-settings-panel-width, 720px);transition:width .3s ease;overflow:hidden}.settings-panel.expanded{width:min(var(--pfx-settings-panel-width-expanded, 95vw),var(--pfx-settings-panel-max-width, 2400px))}.settings-panel-header{grid-area:header;display:flex;align-items:center;gap:var(--pfx-settings-panel-header-gap, 8px);padding:0 var(--pfx-settings-panel-header-padding-x, 16px);height:var(--pfx-settings-panel-header-height, 64px);border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);box-shadow:var(--pfx-settings-panel-header-shadow, var(--md-sys-elevation-level1, 0 2px 6px rgba(0, 0, 0, .08)));flex-shrink:0}.settings-panel-header .spacer{flex:1}.settings-panel-status{grid-area:status;display:flex;align-items:center;gap:8px;min-height:36px;padding:6px 16px;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);font-size:.85rem;font-weight:500}.settings-panel-status mat-icon{width:18px;height:18px;font-size:18px}.settings-panel-status[data-status=dirty]{color:var(--md-sys-color-error);background:color-mix(in srgb,var(--md-sys-color-error-container) 30%,var(--md-sys-color-surface-container-high))}.settings-panel-status[data-status=saved]{color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 28%,var(--md-sys-color-surface-container-high))}.settings-panel-body{grid-area:body;overflow-y:auto;min-height:0;padding:var(--pfx-settings-panel-body-padding, 8px 8px 24px 8px);background:var(--md-sys-color-surface);display:flex;flex-direction:column}.settings-panel-content{display:block}.settings-panel-footer{grid-area:footer;border-top:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);box-shadow:var(--pfx-settings-panel-footer-shadow, var(--md-sys-elevation-level1, 0 -2px 6px rgba(0, 0, 0, .08)));display:flex;align-items:center;padding:var(--pfx-settings-panel-footer-padding, 12px 16px);column-gap:var(--pfx-settings-panel-footer-gap, 12px);flex-shrink:0}.spacer{flex:1}.settings-panel-title{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-title-gap, 8px);font-weight:700;letter-spacing:.2px;margin:0}.settings-panel-title mat-icon{color:var(--md-sys-color-primary)}.settings-panel-title .title-icon{width:20px;height:20px;font-size:20px}.settings-panel-footer button+button{margin-left:var(--pfx-settings-panel-footer-gap, 12px)}.settings-panel-footer button{display:inline-flex;align-items:center}.settings-panel-footer button .mat-icon{font-size:20px;width:20px;height:20px;line-height:1;display:inline-flex;align-items:center;justify-content:center}.settings-panel-footer .mat-button-wrapper{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-button-gap, 8px)}.settings-panel-footer .mat-progress-spinner{margin-right:8px}.settings-panel-footer .mat-flat-button[color=primary]{font-weight:600}:host ::ng-deep .settings-panel .mdc-button__label{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-button-gap, 8px);line-height:1}:host ::ng-deep .settings-panel .mdc-button__label>span{display:inline-flex;align-items:center;line-height:1}:host ::ng-deep .settings-panel .mdc-button__label .mat-icon{display:inline-flex;align-items:center;justify-content:center;line-height:1}:host ::ng-deep .praxis-settings-panel-backdrop{background:var(--pfx-backdrop, var(--md-sys-color-scrim, rgba(0, 0, 0, .45)));backdrop-filter:blur(var(--pfx-backdrop-blur, 6px)) saturate(110%);-webkit-backdrop-filter:blur(var(--pfx-backdrop-blur, 6px)) saturate(110%)}.settings-panel .mat-divider{background-color:var(--md-sys-color-outline-variant)!important}.settings-panel .mat-expansion-panel{background:var(--md-sys-color-surface-container);border:1px solid var(--md-sys-color-outline-variant);border-radius:var(--md-sys-shape-corner-medium, 12px);box-shadow:var(--md-sys-elevation-level1, 0 2px 8px rgba(0, 0, 0, .08))}.settings-panel .mat-expansion-panel-header{background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface)}.settings-panel .mat-expansion-panel-header mat-icon,.settings-panel .mat-expansion-panel-header .mat-icon{color:var(--md-sys-color-on-surface)!important}.settings-panel .mat-expansion-panel-header .mat-expansion-panel-header-title,.settings-panel .mat-expansion-panel-header .mat-expansion-panel-header-description{color:var(--md-sys-color-on-surface)}.settings-panel .mat-expansion-panel-header .mat-expansion-indicator,.settings-panel .mat-expansion-panel-header .mat-expansion-indicator:after{color:var(--md-sys-color-on-surface-variant);border-color:var(--md-sys-color-on-surface-variant)}:host ::ng-deep .settings-panel .mat-expansion-panel .mat-expansion-panel-body{padding:8px}.settings-panel .mat-mdc-tab-group .mat-mdc-tab-header{border-bottom:1px solid var(--md-sys-color-outline-variant)}.settings-panel .mat-mdc-tab-group .mdc-tab .mdc-tab__text-label{color:var(--md-sys-color-on-surface-variant)}.settings-panel .mat-mdc-tab-group .mdc-tab.mdc-tab--active .mdc-tab__text-label{color:var(--md-sys-color-on-surface)}.settings-panel .mat-mdc-tab-group .mdc-tab-indicator__content--underline{border-color:var(--md-sys-color-primary)}.settings-panel .mat-mdc-form-field{--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-secondary, var(--md-sys-color-primary));--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary)}:host ::ng-deep .praxis-settings-panel-pane{position:fixed!important;top:0!important;right:0!important;height:100vh!important;z-index:1000}:host ::ng-deep .praxis-settings-panel-pane .settings-panel{pointer-events:auto}\n"] }]
288
750
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1.MatDialog }], propDecorators: { contentHost: [{
289
751
  type: ViewChild,
290
752
  args: ['contentHost', { read: ViewContainerRef, static: true }]
@@ -348,6 +810,7 @@ class SettingsPanelService {
348
810
  overlay;
349
811
  injector;
350
812
  currentRef;
813
+ i18n = inject(PraxisI18nService);
351
814
  constructor(overlay, injector) {
352
815
  this.overlay = overlay;
353
816
  this.injector = injector;
@@ -373,7 +836,9 @@ class SettingsPanelService {
373
836
  const ref = new SettingsPanelRef(overlayRef);
374
837
  const panelPortal = new ComponentPortal(SettingsPanelComponent);
375
838
  const panelRef = overlayRef.attach(panelPortal);
376
- panelRef.instance.title = config.title;
839
+ panelRef.instance.title = config.title?.trim()
840
+ ? config.title
841
+ : this.i18n.t(PRAXIS_SETTINGS_PANEL_DEFAULT_TITLE, undefined, PRAXIS_SETTINGS_PANEL_DEFAULT_TITLE, PRAXIS_SETTINGS_PANEL_I18N_NAMESPACE);
377
842
  panelRef.instance.titleIcon = config.titleIcon;
378
843
  panelRef.instance.expanded = config.expanded || false;
379
844
  const inputs = config.content.inputs;
@@ -473,6 +938,38 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
473
938
  args: [{ providedIn: 'root' }]
474
939
  }] });
475
940
 
941
+ function normalizeMojibakeText(text) {
942
+ if (!text.includes('\u00C3') &&
943
+ !text.includes('\u00C2') &&
944
+ !text.includes('\u00E2') &&
945
+ !text.includes('\u00AA') &&
946
+ !text.includes('\u00AB')) {
947
+ return text;
948
+ }
949
+ let current = text;
950
+ for (let i = 0; i < 3; i++) {
951
+ let next = current;
952
+ try {
953
+ next = decodeURIComponent(escape(current));
954
+ }
955
+ catch {
956
+ break;
957
+ }
958
+ if (next === current) {
959
+ break;
960
+ }
961
+ current = next;
962
+ if (!current.includes('\u00C3') &&
963
+ !current.includes('\u00C2') &&
964
+ !current.includes('\u00E2') &&
965
+ !current.includes('\u00AA') &&
966
+ !current.includes('\u00AB')) {
967
+ break;
968
+ }
969
+ }
970
+ return current;
971
+ }
972
+
476
973
  const TABLE_COMPACT_LENGTH_TOKEN$1 = '(?:0|(?:\\d+|\\d*\\.\\d+)(?:px|rem|em|%|vh|vw|svh|svw|lvh|lvw|dvh|dvw|ch|ex))';
477
974
  const TABLE_COMPACT_SPACING_PATTERN = `^(?:var\\(.+\\)|calc\\(.+\\)|${TABLE_COMPACT_LENGTH_TOKEN$1}(?:\\s+${TABLE_COMPACT_LENGTH_TOKEN$1}){0,3})$`;
478
975
  const TABLE_COMPACT_FONT_SIZE_PATTERN = `^(?:var\\(.+\\)|calc\\(.+\\)|${TABLE_COMPACT_LENGTH_TOKEN$1})$`;
@@ -483,30 +980,31 @@ function safeName(path) {
483
980
  * Minimal FormConfig schema for the Global Config editor UI.
484
981
  * This can be extended incrementally as new domains/settings are added.
485
982
  */
486
- function buildGlobalConfigFormConfig() {
983
+ function buildGlobalConfigFormConfig(translate = (text) => text) {
984
+ const tx = (text, params) => translate(normalizeMojibakeText(text), params);
487
985
  const fields = [
488
986
  // CRUD
489
987
  {
490
988
  name: safeName('crud.defaults.openMode'),
491
- label: 'Modo de abertura padrão',
989
+ label: tx('Modo de abertura padrão'),
492
990
  controlType: FieldControlType.SELECT,
493
991
  selectOptions: [
494
- { text: 'Rota', value: 'route' },
992
+ { text: tx('Rota'), value: 'route' },
495
993
  { text: 'Modal', value: 'modal' },
496
994
  { text: 'Drawer', value: 'drawer' },
497
995
  ],
498
- hint: 'Aplicado quando ação/metadado não definem modo.',
996
+ hint: tx('Aplicado quando ação/metadado não definem modo.'),
499
997
  dataAttributes: { globalPath: 'crud.defaults.openMode' },
500
998
  },
501
999
  {
502
1000
  name: safeName('crud.defaults.back.confirmOnDirty'),
503
- label: 'Confirmar ao sair com alterações',
1001
+ label: tx('Confirmar ao sair com alterações'),
504
1002
  controlType: FieldControlType.TOGGLE,
505
1003
  dataAttributes: { globalPath: 'crud.defaults.back.confirmOnDirty' },
506
1004
  },
507
1005
  {
508
1006
  name: safeName('crud.defaults.back.strategy'),
509
- label: 'Back: estratégia',
1007
+ label: tx('Back: estratégia'),
510
1008
  controlType: FieldControlType.SELECT,
511
1009
  selectOptions: [
512
1010
  { text: 'auto', value: 'auto' },
@@ -517,13 +1015,13 @@ function buildGlobalConfigFormConfig() {
517
1015
  },
518
1016
  {
519
1017
  name: safeName('crud.defaults.header.showBack'),
520
- label: 'Header: mostrar voltar',
1018
+ label: tx('Header: show back'),
521
1019
  controlType: FieldControlType.TOGGLE,
522
1020
  dataAttributes: { globalPath: 'crud.defaults.header.showBack' },
523
1021
  },
524
1022
  {
525
1023
  name: safeName('crud.defaults.header.variant'),
526
- label: 'Header: variante',
1024
+ label: tx('Header: variant'),
527
1025
  controlType: FieldControlType.SELECT,
528
1026
  selectOptions: [
529
1027
  { text: 'ghost', value: 'ghost' },
@@ -534,31 +1032,31 @@ function buildGlobalConfigFormConfig() {
534
1032
  },
535
1033
  {
536
1034
  name: safeName('crud.defaults.header.sticky'),
537
- label: 'Header: fixo (sticky)',
1035
+ label: tx('Header: sticky'),
538
1036
  controlType: FieldControlType.TOGGLE,
539
1037
  dataAttributes: { globalPath: 'crud.defaults.header.sticky' },
540
1038
  },
541
1039
  {
542
1040
  name: safeName('crud.defaults.header.divider'),
543
- label: 'Header: mostrar divisor',
1041
+ label: tx('Header: show divider'),
544
1042
  controlType: FieldControlType.TOGGLE,
545
1043
  dataAttributes: { globalPath: 'crud.defaults.header.divider' },
546
1044
  },
547
1045
  {
548
1046
  name: safeName('crud.defaults.modal.width'),
549
- label: 'Modal: largura (ex.: 900px)',
1047
+ label: tx('Modal: width (e.g. 900px)'),
550
1048
  controlType: FieldControlType.INPUT,
551
1049
  dataAttributes: { globalPath: 'crud.defaults.modal.width' },
552
1050
  },
553
1051
  {
554
1052
  name: safeName('crud.defaults.modal.maxWidth'),
555
- label: 'Modal: largura máxima (ex.: 96vw)',
1053
+ label: tx('Modal: largura máxima (ex.: 96vw)'),
556
1054
  controlType: FieldControlType.INPUT,
557
1055
  dataAttributes: { globalPath: 'crud.defaults.modal.maxWidth' },
558
1056
  },
559
1057
  {
560
1058
  name: safeName('crud.defaults.modal.backdropStyle'),
561
- label: 'Modal: backdrop',
1059
+ label: tx('Modal: backdrop'),
562
1060
  controlType: FieldControlType.SELECT,
563
1061
  selectOptions: [
564
1062
  { text: 'blur', value: 'blur' },
@@ -570,25 +1068,25 @@ function buildGlobalConfigFormConfig() {
570
1068
  // Dynamic Fields
571
1069
  {
572
1070
  name: safeName('dynamicFields.asyncSelect.loadOn'),
573
- label: 'Async Select: loadOn',
1071
+ label: tx('Async Select: loadOn'),
574
1072
  controlType: FieldControlType.SELECT,
575
1073
  selectOptions: [
576
1074
  { text: 'open', value: 'open' },
577
1075
  { text: 'init', value: 'init' },
578
1076
  { text: 'none', value: 'none' },
579
1077
  ],
580
- hint: 'Estratégia de primeira carga quando metadado não definir.',
1078
+ hint: tx('Estratégia de primeira carga quando metadado não definir.'),
581
1079
  dataAttributes: { globalPath: 'dynamicFields.asyncSelect.loadOn' },
582
1080
  },
583
1081
  {
584
1082
  name: safeName('dynamicFields.cascade.enable'),
585
- label: 'Cascata nativa habilitada',
1083
+ label: tx('Native cascade enabled'),
586
1084
  controlType: FieldControlType.TOGGLE,
587
1085
  dataAttributes: { globalPath: 'dynamicFields.cascade.enable' },
588
1086
  },
589
1087
  {
590
1088
  name: safeName('dynamicFields.cascade.loadOnChange'),
591
- label: 'Cascata: loadOnChange',
1089
+ label: tx('Cascade: loadOnChange'),
592
1090
  controlType: FieldControlType.SELECT,
593
1091
  selectOptions: [
594
1092
  { text: 'respectLoadOn', value: 'respectLoadOn' },
@@ -599,42 +1097,42 @@ function buildGlobalConfigFormConfig() {
599
1097
  },
600
1098
  {
601
1099
  name: safeName('dynamicFields.cascade.debounceMs'),
602
- label: 'Cascata: debounce (ms)',
1100
+ label: tx('Cascade: debounce (ms)'),
603
1101
  controlType: FieldControlType.NUMERIC_TEXT_BOX,
604
1102
  dataAttributes: { globalPath: 'dynamicFields.cascade.debounceMs' },
605
1103
  },
606
1104
  // Dynamic Fields async-select extra
607
1105
  {
608
1106
  name: safeName('dynamicFields.asyncSelect.pageSize'),
609
- label: 'Async Select: pageSize',
1107
+ label: tx('Async Select: pageSize'),
610
1108
  controlType: FieldControlType.NUMERIC_TEXT_BOX,
611
1109
  dataAttributes: { globalPath: 'dynamicFields.asyncSelect.pageSize' },
612
1110
  },
613
1111
  {
614
1112
  name: safeName('dynamicFields.asyncSelect.useCursor'),
615
- label: 'Async Select: usar cursor',
1113
+ label: tx('Async Select: use cursor'),
616
1114
  controlType: FieldControlType.TOGGLE,
617
1115
  dataAttributes: { globalPath: 'dynamicFields.asyncSelect.useCursor' },
618
1116
  },
619
1117
  // AI
620
1118
  {
621
1119
  name: safeName('ai.provider'),
622
- label: 'Provedor LLM',
1120
+ label: tx('LLM provider'),
623
1121
  controlType: FieldControlType.SELECT,
624
1122
  selectOptions: [],
625
- hint: 'Selecione o provedor para listar modelos e testar a chave.',
1123
+ hint: tx('Select the provider to list models and test the key.'),
626
1124
  dataAttributes: { globalPath: 'ai.provider' },
627
1125
  },
628
1126
  {
629
1127
  name: safeName('ai.apiKey'),
630
- label: 'Chave de API',
1128
+ label: tx('API key'),
631
1129
  controlType: FieldControlType.INPUT,
632
- hint: 'Informe a chave do provedor selecionado para testar.',
1130
+ hint: tx('Enter the selected provider key to test.'),
633
1131
  dataAttributes: { globalPath: 'ai.apiKey' },
634
1132
  },
635
1133
  {
636
1134
  name: safeName('ai.model'),
637
- label: 'Modelo de IA',
1135
+ label: tx('AI model'),
638
1136
  controlType: FieldControlType.SEARCHABLE_SELECT,
639
1137
  selectOptions: [],
640
1138
  resourcePath: '',
@@ -642,113 +1140,113 @@ function buildGlobalConfigFormConfig() {
642
1140
  },
643
1141
  {
644
1142
  name: safeName('ai.temperature'),
645
- label: 'Temperatura (Criatividade)',
1143
+ label: tx('Temperature (Creativity)'),
646
1144
  controlType: FieldControlType.NUMERIC_TEXT_BOX,
647
- hint: '0.0 (determinístico) a 1.0 (criativo)',
1145
+ hint: tx('0.0 (deterministic) to 1.0 (creative)'),
648
1146
  dataAttributes: { globalPath: 'ai.temperature' },
649
1147
  },
650
1148
  {
651
1149
  name: safeName('ai.maxTokens'),
652
- label: 'Max tokens',
1150
+ label: tx('Max tokens'),
653
1151
  controlType: FieldControlType.NUMERIC_TEXT_BOX,
654
- hint: 'Limite maximo de tokens na resposta.',
1152
+ hint: tx('Maximum token limit for the response.'),
655
1153
  dataAttributes: { globalPath: 'ai.maxTokens' },
656
1154
  },
657
1155
  {
658
1156
  name: safeName('ai.riskPolicy'),
659
- label: 'Assistente: validação de risco',
1157
+ label: tx('Assistant: risk validation'),
660
1158
  controlType: FieldControlType.SELECT,
661
1159
  selectOptions: [
662
- { text: 'Estrito (recomendado)', value: 'strict' },
663
- { text: 'Padrão', value: 'standard' },
1160
+ { text: 'Strict (recommended)', value: 'strict' },
1161
+ { text: tx('Standard'), value: 'standard' },
664
1162
  ],
665
- hint: 'Estrito exige confirmação em risco médio/alto. Padrão segue a indicação retornada pelo backend.',
1163
+ hint: tx('Strict requires confirmation for medium/high risk. Standard follows the indication returned by the backend.'),
666
1164
  dataAttributes: { globalPath: 'ai.riskPolicy' },
667
1165
  },
668
1166
  {
669
1167
  name: safeName('ai.embedding.useSameAsLlm'),
670
- label: 'Embeddings: usar mesmo LLM',
1168
+ label: tx('Use same LLM for embeddings'),
671
1169
  controlType: FieldControlType.TOGGLE,
672
- hint: 'Replica provedor e chave do LLM para embeddings.',
1170
+ hint: tx('Replicates the LLM provider and key for embeddings.'),
673
1171
  dataAttributes: { globalPath: 'ai.embedding.useSameAsLlm' },
674
1172
  },
675
1173
  {
676
1174
  name: safeName('ai.embedding.provider'),
677
- label: 'Embeddings: provedor',
1175
+ label: tx('Embeddings provider'),
678
1176
  controlType: FieldControlType.SELECT,
679
1177
  selectOptions: [],
680
- hint: 'Provedor usado para gerar embeddings (RAG).',
1178
+ hint: tx('Provider used to generate embeddings (RAG).'),
681
1179
  dataAttributes: { globalPath: 'ai.embedding.provider' },
682
1180
  },
683
1181
  {
684
1182
  name: safeName('ai.embedding.apiKey'),
685
- label: 'Embeddings: chave de API',
1183
+ label: tx('Embeddings API key'),
686
1184
  controlType: FieldControlType.INPUT,
687
- hint: 'Chave do provedor de embeddings.',
1185
+ hint: tx('Embeddings provider key.'),
688
1186
  dataAttributes: { globalPath: 'ai.embedding.apiKey' },
689
1187
  },
690
1188
  {
691
1189
  name: safeName('ai.embedding.model'),
692
- label: 'Embeddings: modelo',
1190
+ label: tx('Embeddings model'),
693
1191
  controlType: FieldControlType.SEARCHABLE_SELECT,
694
1192
  selectOptions: [
695
1193
  { text: 'text-embedding-3-large', value: 'text-embedding-3-large' },
696
1194
  { text: 'text-embedding-3-small', value: 'text-embedding-3-small' },
697
1195
  { text: 'text-embedding-ada-002 (legacy)', value: 'text-embedding-ada-002' },
698
1196
  ],
699
- emptyOptionText: 'Padrão do provedor',
700
- hint: 'Modelos OpenAI para embeddings.',
1197
+ emptyOptionText: tx('Provider default'),
1198
+ hint: tx('OpenAI models for embeddings.'),
701
1199
  dataAttributes: { globalPath: 'ai.embedding.model' },
702
1200
  },
703
1201
  {
704
1202
  name: safeName('ai.embedding.dimensions'),
705
- label: 'Embeddings: dimensoes',
1203
+ label: tx('Embeddings: dimensions'),
706
1204
  controlType: FieldControlType.NUMERIC_TEXT_BOX,
707
- hint: 'Dimensoes do vetor de embedding (default 768).',
1205
+ hint: tx('Embedding vector dimensions (default 768).'),
708
1206
  dataAttributes: { globalPath: 'ai.embedding.dimensions' },
709
1207
  },
710
- // Cache
1208
+ // Cache // Cache
711
1209
  {
712
1210
  name: safeName('cache.disableSchemaCache'),
713
- label: 'Desabilitar cache de schema (LocalStorage)',
1211
+ label: tx('Desabilitar cache de schema (LocalStorage)'),
714
1212
  controlType: FieldControlType.TOGGLE,
715
- hint: 'Se ativo, sempre baixa o schema do servidor (ignora cache local). Útil para desenvolvimento.',
1213
+ hint: tx('Se ativo, sempre baixa o schema do servidor (ignora cache local). Útil para desenvolvimento.'),
716
1214
  dataAttributes: { globalPath: 'cache.disableSchemaCache' },
717
1215
  },
718
1216
  // Table
719
1217
  {
720
1218
  name: safeName('table.behavior.pagination.enabled'),
721
- label: 'Paginação habilitada',
1219
+ label: tx('Paginação habilitada'),
722
1220
  controlType: FieldControlType.TOGGLE,
723
1221
  dataAttributes: { globalPath: 'table.behavior.pagination.enabled' },
724
1222
  },
725
1223
  {
726
1224
  name: safeName('table.behavior.pagination.pageSize'),
727
- label: 'Tamanho da página',
1225
+ label: tx('Tamanho da página'),
728
1226
  controlType: FieldControlType.NUMERIC_TEXT_BOX,
729
1227
  dataAttributes: { globalPath: 'table.behavior.pagination.pageSize' },
730
1228
  },
731
1229
  {
732
1230
  name: safeName('table.behavior.filtering.debounceTime'),
733
- label: 'Debounce do filtro (ms)',
1231
+ label: tx('Filter debounce (ms)'),
734
1232
  controlType: FieldControlType.NUMERIC_TEXT_BOX,
735
1233
  dataAttributes: { globalPath: 'table.behavior.filtering.debounceTime' },
736
1234
  },
737
1235
  {
738
1236
  name: safeName('table.behavior.sorting.enabled'),
739
- label: 'Ordenação habilitada',
1237
+ label: tx('Ordenação habilitada'),
740
1238
  controlType: FieldControlType.TOGGLE,
741
1239
  dataAttributes: { globalPath: 'table.behavior.sorting.enabled' },
742
1240
  },
743
1241
  {
744
1242
  name: safeName('table.behavior.selection.enabled'),
745
- label: 'Seleção habilitada',
1243
+ label: tx('Seleção habilitada'),
746
1244
  controlType: FieldControlType.TOGGLE,
747
1245
  dataAttributes: { globalPath: 'table.behavior.selection.enabled' },
748
1246
  },
749
1247
  {
750
1248
  name: safeName('table.behavior.pagination.strategy'),
751
- label: 'Paginação: estratégia',
1249
+ label: tx('Paginação: estratégia'),
752
1250
  controlType: FieldControlType.SELECT,
753
1251
  selectOptions: [
754
1252
  { text: 'client', value: 'client' },
@@ -758,7 +1256,7 @@ function buildGlobalConfigFormConfig() {
758
1256
  },
759
1257
  {
760
1258
  name: safeName('table.behavior.sorting.strategy'),
761
- label: 'Ordenação: estratégia',
1259
+ label: tx('Ordenação: estratégia'),
762
1260
  controlType: FieldControlType.SELECT,
763
1261
  selectOptions: [
764
1262
  { text: 'client', value: 'client' },
@@ -768,114 +1266,113 @@ function buildGlobalConfigFormConfig() {
768
1266
  },
769
1267
  {
770
1268
  name: safeName('table.behavior.pagination.showFirstLastButtons'),
771
- label: 'Paginação: botões Primeiro/Último',
1269
+ label: tx('Paginação: botões Primeiro/Último'),
772
1270
  controlType: FieldControlType.CHECKBOX,
773
1271
  dataAttributes: { globalPath: 'table.behavior.pagination.showFirstLastButtons' },
774
1272
  },
775
1273
  {
776
1274
  name: safeName('table.toolbar.visible'),
777
- label: 'Toolbar visível',
1275
+ label: tx('Toolbar visível'),
778
1276
  controlType: FieldControlType.CHECKBOX,
779
1277
  dataAttributes: { globalPath: 'table.toolbar.visible' },
780
1278
  },
781
1279
  {
782
1280
  name: safeName('table.appearance.density'),
783
- label: 'Aparência: densidade',
1281
+ label: tx('Appearance: density'),
784
1282
  controlType: FieldControlType.SELECT,
785
1283
  selectOptions: [
786
- { text: 'compact', value: 'compact' },
787
- { text: 'comfortable', value: 'comfortable' },
788
- { text: 'spacious', value: 'spacious' },
1284
+ { text: tx('compact'), value: 'compact' },
1285
+ { text: tx('comfortable'), value: 'comfortable' },
1286
+ { text: tx('spacious'), value: 'spacious' },
789
1287
  ],
790
1288
  dataAttributes: { globalPath: 'table.appearance.density' },
791
1289
  },
792
1290
  {
793
1291
  name: safeName('table.appearance.spacing.cellPadding'),
794
- label: 'Aparência: padding das células',
1292
+ label: tx('Appearance: cell padding'),
795
1293
  controlType: FieldControlType.INPUT,
796
- hint: 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 6px 12px',
1294
+ hint: tx('Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 6px 12px'),
797
1295
  pattern: TABLE_COMPACT_SPACING_PATTERN,
798
- patternMessage: 'Use 1 a 4 medidas CSS válidas, como 6px 12px.',
1296
+ patternMessage: tx('Use 1 to 4 valid CSS measures, such as 6px 12px.'),
799
1297
  dataAttributes: { globalPath: 'table.appearance.spacing.cellPadding' },
800
1298
  },
801
1299
  {
802
1300
  name: safeName('table.appearance.spacing.headerPadding'),
803
- label: 'Aparência: padding do cabeçalho',
1301
+ label: tx('Appearance: header padding'),
804
1302
  controlType: FieldControlType.INPUT,
805
- hint: 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 8px 12px',
1303
+ hint: tx('Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 8px 12px'),
806
1304
  pattern: TABLE_COMPACT_SPACING_PATTERN,
807
- patternMessage: 'Use 1 a 4 medidas CSS válidas, como 8px 12px.',
1305
+ patternMessage: tx('Use 1 to 4 valid CSS measures, such as 8px 12px.'),
808
1306
  dataAttributes: { globalPath: 'table.appearance.spacing.headerPadding' },
809
1307
  },
810
1308
  {
811
1309
  name: safeName('table.appearance.typography.fontSize'),
812
- label: 'Aparência: fonte das células',
1310
+ label: tx('Appearance: cell font size'),
813
1311
  controlType: FieldControlType.INPUT,
814
- hint: 'Aceita uma medida CSS com unidade, var(...) ou calc(...). Ex.: 13px',
1312
+ hint: tx('Accepts a CSS measure with units, var(...) or calc(...). Example: 13px'),
815
1313
  pattern: TABLE_COMPACT_FONT_SIZE_PATTERN,
816
- patternMessage: 'Use uma medida CSS válida, como 13px.',
1314
+ patternMessage: tx('Use a valid CSS measure, such as 13px.'),
817
1315
  dataAttributes: { globalPath: 'table.appearance.typography.fontSize' },
818
1316
  },
819
1317
  {
820
1318
  name: safeName('table.appearance.typography.headerFontSize'),
821
- label: 'Aparência: fonte do cabeçalho',
1319
+ label: tx('Appearance: header font size'),
822
1320
  controlType: FieldControlType.INPUT,
823
- hint: 'Aceita uma medida CSS com unidade, var(...) ou calc(...). Ex.: 13px',
1321
+ hint: tx('Accepts a CSS measure with units, var(...) or calc(...). Example: 13px'),
824
1322
  pattern: TABLE_COMPACT_FONT_SIZE_PATTERN,
825
- patternMessage: 'Use uma medida CSS válida, como 13px.',
1323
+ patternMessage: tx('Use a valid CSS measure, such as 13px.'),
826
1324
  dataAttributes: { globalPath: 'table.appearance.typography.headerFontSize' },
827
- },
828
- {
1325
+ }, {
829
1326
  name: safeName('table.filteringUi.advancedOpenMode'),
830
- label: 'Filtro: modo de abertura',
1327
+ label: tx('Filtro: modo de abertura'),
831
1328
  controlType: FieldControlType.SELECT,
832
1329
  selectOptions: [
833
- { text: 'overlay', value: 'overlay' },
834
- { text: 'modal', value: 'modal' },
835
- { text: 'drawer', value: 'drawer' },
1330
+ { text: tx('overlay'), value: 'overlay' },
1331
+ { text: tx('modal'), value: 'modal' },
1332
+ { text: tx('drawer'), value: 'drawer' },
836
1333
  ],
837
1334
  dataAttributes: { globalPath: 'table.filteringUi.advancedOpenMode' },
838
1335
  },
839
1336
  {
840
1337
  name: safeName('table.filteringUi.overlayVariant'),
841
- label: 'Filtro: overlay (visual)',
1338
+ label: tx('Filtro: overlay (visual)'),
842
1339
  controlType: FieldControlType.SELECT,
843
1340
  selectOptions: [
844
- { text: 'card', value: 'card' },
845
- { text: 'frosted', value: 'frosted' },
1341
+ { text: tx('card'), value: 'card' },
1342
+ { text: tx('frosted'), value: 'frosted' },
846
1343
  ],
847
1344
  dataAttributes: { globalPath: 'table.filteringUi.overlayVariant' },
848
1345
  },
849
1346
  {
850
1347
  name: safeName('table.filteringUi.overlayBackdrop'),
851
- label: 'Filtro: backdrop no overlay',
1348
+ label: tx('Filtro: backdrop no overlay'),
852
1349
  controlType: FieldControlType.CHECKBOX,
853
1350
  dataAttributes: { globalPath: 'table.filteringUi.overlayBackdrop' },
854
1351
  },
855
1352
  // Table messages - confirmations
856
- { name: safeName('table.messages.actions.confirmations.delete'), label: 'Excluir — confirmação', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.delete' } },
857
- { name: safeName('table.messages.actions.confirmations.deleteMultiple'), label: 'Excluir (múltiplos) — confirmação', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.deleteMultiple' } },
858
- { name: safeName('table.messages.actions.confirmations.save'), label: 'Salvar — confirmação', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.save' } },
859
- { name: safeName('table.messages.actions.confirmations.cancel'), label: 'Cancelar — confirmação', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.cancel' } },
860
- { name: safeName('table.messages.actions.confirmations.export'), label: 'Exportar — confirmação', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.export' } },
1353
+ { name: safeName('table.messages.actions.confirmations.delete'), label: tx('Excluir — confirmação'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.delete' } },
1354
+ { name: safeName('table.messages.actions.confirmations.deleteMultiple'), label: tx('Excluir (múltiplos) — confirmação'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.deleteMultiple' } },
1355
+ { name: safeName('table.messages.actions.confirmations.save'), label: tx('Salvar — confirmação'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.save' } },
1356
+ { name: safeName('table.messages.actions.confirmations.cancel'), label: tx('Cancelar — confirmação'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.cancel' } },
1357
+ { name: safeName('table.messages.actions.confirmations.export'), label: tx('Exportar — confirmação'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.export' } },
861
1358
  // Table messages - progress
862
- { name: safeName('table.messages.actions.progress.delete'), label: 'Excluir — progresso', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.progress.delete' } },
863
- { name: safeName('table.messages.actions.progress.deleteMultiple'), label: 'Excluir (múltiplos) — progresso', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.progress.deleteMultiple' } },
1359
+ { name: safeName('table.messages.actions.progress.delete'), label: tx('Excluir — progresso'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.progress.delete' } },
1360
+ { name: safeName('table.messages.actions.progress.deleteMultiple'), label: tx('Excluir (múltiplos) — progresso'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.progress.deleteMultiple' } },
864
1361
  // Table messages - success
865
- { name: safeName('table.messages.actions.success.delete'), label: 'Excluir — sucesso', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.success.delete' } },
866
- { name: safeName('table.messages.actions.success.save'), label: 'Salvar — sucesso', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.success.save' } },
867
- { name: safeName('table.messages.actions.success.export'), label: 'Exportar — sucesso', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.success.export' } },
868
- { name: safeName('table.messages.actions.success.import'), label: 'Importar — sucesso', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.success.import' } },
1362
+ { name: safeName('table.messages.actions.success.delete'), label: tx('Excluir — sucesso'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.success.delete' } },
1363
+ { name: safeName('table.messages.actions.success.save'), label: tx('Salvar — sucesso'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.success.save' } },
1364
+ { name: safeName('table.messages.actions.success.export'), label: tx('Exportar — sucesso'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.success.export' } },
1365
+ { name: safeName('table.messages.actions.success.import'), label: tx('Importar — sucesso'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.success.import' } },
869
1366
  // Table messages - errors
870
- { name: safeName('table.messages.actions.errors.delete'), label: 'Excluir — erro', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.delete' } },
871
- { name: safeName('table.messages.actions.errors.save'), label: 'Salvar — erro', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.save' } },
872
- { name: safeName('table.messages.actions.errors.export'), label: 'Exportar — erro', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.export' } },
873
- { name: safeName('table.messages.actions.errors.network'), label: 'Rede — erro', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.network' } },
874
- { name: safeName('table.messages.actions.errors.permission'), label: 'Permissão — erro', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.permission' } },
875
- // Dialog Defaults by type
1367
+ { name: safeName('table.messages.actions.errors.delete'), label: tx('Excluir — erro'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.delete' } },
1368
+ { name: safeName('table.messages.actions.errors.save'), label: tx('Salvar — erro'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.save' } },
1369
+ { name: safeName('table.messages.actions.errors.export'), label: tx('Exportar — erro'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.export' } },
1370
+ { name: safeName('table.messages.actions.errors.network'), label: tx('Rede — erro'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.network' } },
1371
+ { name: safeName('table.messages.actions.errors.permission'), label: tx('Permissão — erro'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.permission' } },
1372
+ // Dialog - Defaults by type
876
1373
  {
877
1374
  name: safeName('dialog.defaults.confirm.ariaRole'),
878
- label: 'Dialog Defaults: confirm ariaRole',
1375
+ label: tx('Dialog defaults: confirm - ariaRole'),
879
1376
  controlType: FieldControlType.SELECT,
880
1377
  selectOptions: [
881
1378
  { text: 'dialog', value: 'dialog' },
@@ -883,24 +1380,24 @@ function buildGlobalConfigFormConfig() {
883
1380
  ],
884
1381
  dataAttributes: { globalPath: 'dialog.defaults.confirm.ariaRole' },
885
1382
  },
886
- { name: safeName('dialog.defaults.confirm.title'), label: 'Dialog Defaults: confirm título', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.confirm.title' } },
887
- { name: safeName('dialog.defaults.confirm.icon'), label: 'Dialog Defaults: confirm ícone', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.confirm.icon' } },
888
- { name: safeName('dialog.defaults.confirm.message'), label: 'Dialog Defaults: confirm mensagem', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.confirm.message' } },
889
- { name: safeName('dialog.defaults.confirm.themeColor'), label: 'Dialog Defaults: confirm themeColor', controlType: FieldControlType.SELECT, selectOptions: [{ text: 'light', value: 'light' }, { text: 'primary', value: 'primary' }, { text: 'dark', value: 'dark' }], dataAttributes: { globalPath: 'dialog.defaults.confirm.themeColor' } },
1383
+ { name: safeName('dialog.defaults.confirm.title'), label: tx('Dialog defaults: confirm - title'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.confirm.title' } },
1384
+ { name: safeName('dialog.defaults.confirm.icon'), label: tx('Dialog defaults: confirm - icon'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.confirm.icon' } },
1385
+ { name: safeName('dialog.defaults.confirm.message'), label: tx('Dialog defaults: confirm - message'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.confirm.message' } },
1386
+ { name: safeName('dialog.defaults.confirm.themeColor'), label: tx('Dialog defaults: confirm - themeColor'), controlType: FieldControlType.SELECT, selectOptions: [{ text: 'light', value: 'light' }, { text: 'primary', value: 'primary' }, { text: 'dark', value: 'dark' }], dataAttributes: { globalPath: 'dialog.defaults.confirm.themeColor' } },
890
1387
  {
891
1388
  name: safeName('dialog.defaults.confirm.closeOnBackdropClick'),
892
- label: 'Dialog Defaults: confirm fechar ao clicar no backdrop',
1389
+ label: tx('Dialog defaults: confirm - close on backdrop click'),
893
1390
  controlType: FieldControlType.TOGGLE,
894
1391
  dataAttributes: { globalPath: 'dialog.defaults.confirm.closeOnBackdropClick' },
895
1392
  },
896
- { name: safeName('dialog.defaults.confirm.disableClose'), label: 'Dialog Defaults: confirm disableClose', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.confirm.disableClose' } },
897
- { name: safeName('dialog.defaults.confirm.hasBackdrop'), label: 'Dialog Defaults: confirm hasBackdrop', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.confirm.hasBackdrop' } },
898
- { name: safeName('dialog.defaults.confirm.panelClass'), label: 'Dialog Defaults: confirm panelClass', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.confirm.panelClass' } },
899
- { name: safeName('dialog.defaults.confirm.styles'), label: 'Dialog Defaults: confirm styles (JSON)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.confirm.styles', monospace: true }, hint: 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}' },
900
- { name: safeName('dialog.defaults.confirm.animation'), label: 'Dialog Defaults: confirm animation (JSON/boolean)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.confirm.animation', monospace: true } },
1393
+ { name: safeName('dialog.defaults.confirm.disableClose'), label: tx('Dialog defaults: confirm - disableClose'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.confirm.disableClose' } },
1394
+ { name: safeName('dialog.defaults.confirm.hasBackdrop'), label: tx('Dialog defaults: confirm - hasBackdrop'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.confirm.hasBackdrop' } },
1395
+ { name: safeName('dialog.defaults.confirm.panelClass'), label: tx('Dialog defaults: confirm - panelClass'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.confirm.panelClass' } },
1396
+ { name: safeName('dialog.defaults.confirm.styles'), label: tx('Dialog defaults: confirm - styles (JSON)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.confirm.styles', monospace: true }, hint: tx('Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}') },
1397
+ { name: safeName('dialog.defaults.confirm.animation'), label: tx('Dialog defaults: confirm - animation (JSON/boolean)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.confirm.animation', monospace: true } },
901
1398
  {
902
1399
  name: safeName('dialog.defaults.alert.ariaRole'),
903
- label: 'Dialog Defaults: alert ariaRole',
1400
+ label: tx('Dialog defaults: alert - ariaRole'),
904
1401
  controlType: FieldControlType.SELECT,
905
1402
  selectOptions: [
906
1403
  { text: 'dialog', value: 'dialog' },
@@ -908,24 +1405,24 @@ function buildGlobalConfigFormConfig() {
908
1405
  ],
909
1406
  dataAttributes: { globalPath: 'dialog.defaults.alert.ariaRole' },
910
1407
  },
911
- { name: safeName('dialog.defaults.alert.title'), label: 'Dialog Defaults: alert título', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.alert.title' } },
912
- { name: safeName('dialog.defaults.alert.icon'), label: 'Dialog Defaults: alert ícone', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.alert.icon' } },
913
- { name: safeName('dialog.defaults.alert.message'), label: 'Dialog Defaults: alert mensagem', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.alert.message' } },
914
- { name: safeName('dialog.defaults.alert.themeColor'), label: 'Dialog Defaults: alert themeColor', controlType: FieldControlType.SELECT, selectOptions: [{ text: 'light', value: 'light' }, { text: 'primary', value: 'primary' }, { text: 'dark', value: 'dark' }], dataAttributes: { globalPath: 'dialog.defaults.alert.themeColor' } },
1408
+ { name: safeName('dialog.defaults.alert.title'), label: tx('Dialog defaults: alert - title'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.alert.title' } },
1409
+ { name: safeName('dialog.defaults.alert.icon'), label: tx('Dialog defaults: alert - icon'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.alert.icon' } },
1410
+ { name: safeName('dialog.defaults.alert.message'), label: tx('Dialog defaults: alert - message'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.alert.message' } },
1411
+ { name: safeName('dialog.defaults.alert.themeColor'), label: tx('Dialog defaults: alert - themeColor'), controlType: FieldControlType.SELECT, selectOptions: [{ text: 'light', value: 'light' }, { text: 'primary', value: 'primary' }, { text: 'dark', value: 'dark' }], dataAttributes: { globalPath: 'dialog.defaults.alert.themeColor' } },
915
1412
  {
916
1413
  name: safeName('dialog.defaults.alert.closeOnBackdropClick'),
917
- label: 'Dialog Defaults: alert fechar ao clicar no backdrop',
1414
+ label: tx('Dialog defaults: alert - close on backdrop click'),
918
1415
  controlType: FieldControlType.TOGGLE,
919
1416
  dataAttributes: { globalPath: 'dialog.defaults.alert.closeOnBackdropClick' },
920
1417
  },
921
- { name: safeName('dialog.defaults.alert.disableClose'), label: 'Dialog Defaults: alert disableClose', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.alert.disableClose' } },
922
- { name: safeName('dialog.defaults.alert.hasBackdrop'), label: 'Dialog Defaults: alert hasBackdrop', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.alert.hasBackdrop' } },
923
- { name: safeName('dialog.defaults.alert.panelClass'), label: 'Dialog Defaults: alert panelClass', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.alert.panelClass' } },
924
- { name: safeName('dialog.defaults.alert.styles'), label: 'Dialog Defaults: alert styles (JSON)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.alert.styles', monospace: true }, hint: 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}' },
925
- { name: safeName('dialog.defaults.alert.animation'), label: 'Dialog Defaults: alert animation (JSON/boolean)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.alert.animation', monospace: true } },
1418
+ { name: safeName('dialog.defaults.alert.disableClose'), label: tx('Dialog defaults: alert - disableClose'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.alert.disableClose' } },
1419
+ { name: safeName('dialog.defaults.alert.hasBackdrop'), label: tx('Dialog defaults: alert - hasBackdrop'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.alert.hasBackdrop' } },
1420
+ { name: safeName('dialog.defaults.alert.panelClass'), label: tx('Dialog defaults: alert - panelClass'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.alert.panelClass' } },
1421
+ { name: safeName('dialog.defaults.alert.styles'), label: tx('Dialog defaults: alert - styles (JSON)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.alert.styles', monospace: true }, hint: tx('Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}') },
1422
+ { name: safeName('dialog.defaults.alert.animation'), label: tx('Dialog defaults: alert - animation (JSON/boolean)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.alert.animation', monospace: true } },
926
1423
  {
927
1424
  name: safeName('dialog.defaults.prompt.ariaRole'),
928
- label: 'Dialog Defaults: prompt ariaRole',
1425
+ label: tx('Dialog defaults: prompt - ariaRole'),
929
1426
  controlType: FieldControlType.SELECT,
930
1427
  selectOptions: [
931
1428
  { text: 'dialog', value: 'dialog' },
@@ -933,79 +1430,79 @@ function buildGlobalConfigFormConfig() {
933
1430
  ],
934
1431
  dataAttributes: { globalPath: 'dialog.defaults.prompt.ariaRole' },
935
1432
  },
936
- { name: safeName('dialog.defaults.prompt.title'), label: 'Dialog Defaults: prompt título', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.prompt.title' } },
937
- { name: safeName('dialog.defaults.prompt.icon'), label: 'Dialog Defaults: prompt ícone', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.prompt.icon' } },
938
- { name: safeName('dialog.defaults.prompt.message'), label: 'Dialog Defaults: prompt mensagem', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.prompt.message' } },
939
- { name: safeName('dialog.defaults.prompt.themeColor'), label: 'Dialog Defaults: prompt themeColor', controlType: FieldControlType.SELECT, selectOptions: [{ text: 'light', value: 'light' }, { text: 'primary', value: 'primary' }, { text: 'dark', value: 'dark' }], dataAttributes: { globalPath: 'dialog.defaults.prompt.themeColor' } },
1433
+ { name: safeName('dialog.defaults.prompt.title'), label: tx('Dialog defaults: prompt - title'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.prompt.title' } },
1434
+ { name: safeName('dialog.defaults.prompt.icon'), label: tx('Dialog defaults: prompt - icon'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.prompt.icon' } },
1435
+ { name: safeName('dialog.defaults.prompt.message'), label: tx('Dialog defaults: prompt - message'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.prompt.message' } },
1436
+ { name: safeName('dialog.defaults.prompt.themeColor'), label: tx('Dialog defaults: prompt - themeColor'), controlType: FieldControlType.SELECT, selectOptions: [{ text: 'light', value: 'light' }, { text: 'primary', value: 'primary' }, { text: 'dark', value: 'dark' }], dataAttributes: { globalPath: 'dialog.defaults.prompt.themeColor' } },
940
1437
  {
941
1438
  name: safeName('dialog.defaults.prompt.closeOnBackdropClick'),
942
- label: 'Dialog Defaults: prompt fechar ao clicar no backdrop',
1439
+ label: tx('Dialog defaults: prompt - close on backdrop click'),
943
1440
  controlType: FieldControlType.TOGGLE,
944
1441
  dataAttributes: { globalPath: 'dialog.defaults.prompt.closeOnBackdropClick' },
945
1442
  },
946
- { name: safeName('dialog.defaults.prompt.disableClose'), label: 'Dialog Defaults: prompt disableClose', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.prompt.disableClose' } },
947
- { name: safeName('dialog.defaults.prompt.hasBackdrop'), label: 'Dialog Defaults: prompt hasBackdrop', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.prompt.hasBackdrop' } },
948
- { name: safeName('dialog.defaults.prompt.panelClass'), label: 'Dialog Defaults: prompt panelClass', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.prompt.panelClass' } },
949
- { name: safeName('dialog.defaults.prompt.styles'), label: 'Dialog Defaults: prompt styles (JSON)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.prompt.styles', monospace: true }, hint: 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}' },
950
- { name: safeName('dialog.defaults.prompt.animation'), label: 'Dialog Defaults: prompt animation (JSON/boolean)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.prompt.animation', monospace: true } },
951
- // Dialog Variants per profile (danger, info, success, question, error)
1443
+ { name: safeName('dialog.defaults.prompt.disableClose'), label: tx('Dialog defaults: prompt - disableClose'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.prompt.disableClose' } },
1444
+ { name: safeName('dialog.defaults.prompt.hasBackdrop'), label: tx('Dialog defaults: prompt - hasBackdrop'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.prompt.hasBackdrop' } },
1445
+ { name: safeName('dialog.defaults.prompt.panelClass'), label: tx('Dialog defaults: prompt - panelClass'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.prompt.panelClass' } },
1446
+ { name: safeName('dialog.defaults.prompt.styles'), label: tx('Dialog defaults: prompt - styles (JSON)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.prompt.styles', monospace: true }, hint: tx('Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}') },
1447
+ { name: safeName('dialog.defaults.prompt.animation'), label: tx('Dialog defaults: prompt - animation (JSON/boolean)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.prompt.animation', monospace: true } },
1448
+ // Dialog - Variants per profile (danger, info, success, question, error)
952
1449
  // Each variant exposes commonly customized fields + JSON editors for actions/styles
953
1450
  // danger
954
- { name: safeName('dialog.variants.danger.title'), label: 'Variant danger título', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.danger.title' } },
955
- { name: safeName('dialog.variants.danger.icon'), label: 'Variant danger ícone', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.danger.icon' } },
956
- { name: safeName('dialog.variants.danger.message'), label: 'Variant danger mensagem', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.danger.message' } },
957
- { name: safeName('dialog.variants.danger.ariaRole'), label: 'Variant danger ariaRole', controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.danger.ariaRole' } },
958
- { name: safeName('dialog.variants.danger.closeOnBackdropClick'), label: 'Variant danger fechar ao clicar no backdrop', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.danger.closeOnBackdropClick' } },
959
- { name: safeName('dialog.variants.danger.panelClass'), label: 'Variant danger panelClass', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.danger.panelClass' } },
960
- { name: safeName('dialog.variants.danger.actions'), label: 'Variant danger actions (JSON array)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.danger.actions', monospace: true }, hint: 'Ex.: [{"id":"cancel","text":"Cancelar","role":"secondary","close":true,"cssClass":"btn"},{"id":"confirm","text":"Excluir","role":"primary","close":true,"cssClass":"btn btn-danger","icon":"delete"}]' },
961
- { name: safeName('dialog.variants.danger.styles'), label: 'Variant danger styles (JSON)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.danger.styles', monospace: true }, hint: 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}' },
962
- { name: safeName('dialog.variants.danger.animation'), label: 'Variant danger animation (JSON/boolean)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.danger.animation', monospace: true } },
1451
+ { name: safeName('dialog.variants.danger.title'), label: tx('Variant danger - title'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.danger.title' } },
1452
+ { name: safeName('dialog.variants.danger.icon'), label: tx('Variant danger - icon'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.danger.icon' } },
1453
+ { name: safeName('dialog.variants.danger.message'), label: tx('Variant danger - message'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.danger.message' } },
1454
+ { name: safeName('dialog.variants.danger.ariaRole'), label: tx('Variant danger - ariaRole'), controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.danger.ariaRole' } },
1455
+ { name: safeName('dialog.variants.danger.closeOnBackdropClick'), label: tx('Variant danger - close on backdrop click'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.danger.closeOnBackdropClick' } },
1456
+ { name: safeName('dialog.variants.danger.panelClass'), label: tx('Variant danger - panelClass'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.danger.panelClass' } },
1457
+ { name: safeName('dialog.variants.danger.actions'), label: tx('Variant danger - actions (JSON array)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.danger.actions', monospace: true }, hint: tx('Example JSON array: [{"id":"cancel","text":"Cancel","role":"secondary","close":true,"cssClass":"btn"},{"id":"confirm","text":"Delete","role":"primary","close":true,"cssClass":"btn btn-danger","icon":"delete"}]') },
1458
+ { name: safeName('dialog.variants.danger.styles'), label: tx('Variant danger - styles (JSON)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.danger.styles', monospace: true }, hint: tx('Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}') },
1459
+ { name: safeName('dialog.variants.danger.animation'), label: tx('Variant danger - animation (JSON/boolean)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.danger.animation', monospace: true } },
963
1460
  // info
964
- { name: safeName('dialog.variants.info.title'), label: 'Variant info título', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.info.title' } },
965
- { name: safeName('dialog.variants.info.icon'), label: 'Variant info ícone', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.info.icon' } },
966
- { name: safeName('dialog.variants.info.message'), label: 'Variant info mensagem', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.info.message' } },
967
- { name: safeName('dialog.variants.info.ariaRole'), label: 'Variant info ariaRole', controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.info.ariaRole' } },
968
- { name: safeName('dialog.variants.info.closeOnBackdropClick'), label: 'Variant info fechar ao clicar no backdrop', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.info.closeOnBackdropClick' } },
969
- { name: safeName('dialog.variants.info.panelClass'), label: 'Variant info panelClass', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.info.panelClass' } },
970
- { name: safeName('dialog.variants.info.actions'), label: 'Variant info actions (JSON array)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.info.actions', monospace: true } },
971
- { name: safeName('dialog.variants.info.styles'), label: 'Variant info styles (JSON)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.info.styles', monospace: true }, hint: 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}' },
972
- { name: safeName('dialog.variants.info.animation'), label: 'Variant info animation (JSON/boolean)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.info.animation', monospace: true } },
1461
+ { name: safeName('dialog.variants.info.title'), label: tx('Variant info - title'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.info.title' } },
1462
+ { name: safeName('dialog.variants.info.icon'), label: tx('Variant info - icon'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.info.icon' } },
1463
+ { name: safeName('dialog.variants.info.message'), label: tx('Variant info - message'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.info.message' } },
1464
+ { name: safeName('dialog.variants.info.ariaRole'), label: tx('Variant info - ariaRole'), controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.info.ariaRole' } },
1465
+ { name: safeName('dialog.variants.info.closeOnBackdropClick'), label: tx('Variant info - close on backdrop click'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.info.closeOnBackdropClick' } },
1466
+ { name: safeName('dialog.variants.info.panelClass'), label: tx('Variant info - panelClass'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.info.panelClass' } },
1467
+ { name: safeName('dialog.variants.info.actions'), label: tx('Variant info - actions (JSON array)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.info.actions', monospace: true } },
1468
+ { name: safeName('dialog.variants.info.styles'), label: tx('Variant info - styles (JSON)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.info.styles', monospace: true }, hint: tx('Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}') },
1469
+ { name: safeName('dialog.variants.info.animation'), label: tx('Variant info - animation (JSON/boolean)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.info.animation', monospace: true } },
973
1470
  // success
974
- { name: safeName('dialog.variants.success.title'), label: 'Variant success título', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.success.title' } },
975
- { name: safeName('dialog.variants.success.icon'), label: 'Variant success ícone', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.success.icon' } },
976
- { name: safeName('dialog.variants.success.message'), label: 'Variant success mensagem', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.success.message' } },
977
- { name: safeName('dialog.variants.success.ariaRole'), label: 'Variant success ariaRole', controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.success.ariaRole' } },
978
- { name: safeName('dialog.variants.success.closeOnBackdropClick'), label: 'Variant success fechar ao clicar no backdrop', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.success.closeOnBackdropClick' } },
979
- { name: safeName('dialog.variants.success.panelClass'), label: 'Variant success panelClass', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.success.panelClass' } },
980
- { name: safeName('dialog.variants.success.actions'), label: 'Variant success actions (JSON array)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.success.actions', monospace: true } },
981
- { name: safeName('dialog.variants.success.styles'), label: 'Variant success styles (JSON)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.success.styles', monospace: true }, hint: 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}' },
982
- { name: safeName('dialog.variants.success.animation'), label: 'Variant success animation (JSON/boolean)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.success.animation', monospace: true } },
1471
+ { name: safeName('dialog.variants.success.title'), label: tx('Variant success - title'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.success.title' } },
1472
+ { name: safeName('dialog.variants.success.icon'), label: tx('Variant success - icon'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.success.icon' } },
1473
+ { name: safeName('dialog.variants.success.message'), label: tx('Variant success - message'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.success.message' } },
1474
+ { name: safeName('dialog.variants.success.ariaRole'), label: tx('Variant success - ariaRole'), controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.success.ariaRole' } },
1475
+ { name: safeName('dialog.variants.success.closeOnBackdropClick'), label: tx('Variant success - close on backdrop click'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.success.closeOnBackdropClick' } },
1476
+ { name: safeName('dialog.variants.success.panelClass'), label: tx('Variant success - panelClass'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.success.panelClass' } },
1477
+ { name: safeName('dialog.variants.success.actions'), label: tx('Variant success - actions (JSON array)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.success.actions', monospace: true } },
1478
+ { name: safeName('dialog.variants.success.styles'), label: tx('Variant success - styles (JSON)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.success.styles', monospace: true }, hint: tx('Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}') },
1479
+ { name: safeName('dialog.variants.success.animation'), label: tx('Variant success - animation (JSON/boolean)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.success.animation', monospace: true } },
983
1480
  // question
984
- { name: safeName('dialog.variants.question.title'), label: 'Variant question título', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.question.title' } },
985
- { name: safeName('dialog.variants.question.icon'), label: 'Variant question ícone', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.question.icon' } },
986
- { name: safeName('dialog.variants.question.message'), label: 'Variant question mensagem', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.question.message' } },
987
- { name: safeName('dialog.variants.question.ariaRole'), label: 'Variant question ariaRole', controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.question.ariaRole' } },
988
- { name: safeName('dialog.variants.question.closeOnBackdropClick'), label: 'Variant question fechar ao clicar no backdrop', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.question.closeOnBackdropClick' } },
989
- { name: safeName('dialog.variants.question.panelClass'), label: 'Variant question panelClass', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.question.panelClass' } },
990
- { name: safeName('dialog.variants.question.actions'), label: 'Variant question actions (JSON array)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.question.actions', monospace: true } },
991
- { name: safeName('dialog.variants.question.styles'), label: 'Variant question styles (JSON)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.question.styles', monospace: true }, hint: 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}' },
992
- { name: safeName('dialog.variants.question.animation'), label: 'Variant question animation (JSON/boolean)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.question.animation', monospace: true } },
1481
+ { name: safeName('dialog.variants.question.title'), label: tx('Variant question - title'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.question.title' } },
1482
+ { name: safeName('dialog.variants.question.icon'), label: tx('Variant question - icon'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.question.icon' } },
1483
+ { name: safeName('dialog.variants.question.message'), label: tx('Variant question - message'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.question.message' } },
1484
+ { name: safeName('dialog.variants.question.ariaRole'), label: tx('Variant question - ariaRole'), controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.question.ariaRole' } },
1485
+ { name: safeName('dialog.variants.question.closeOnBackdropClick'), label: tx('Variant question - close on backdrop click'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.question.closeOnBackdropClick' } },
1486
+ { name: safeName('dialog.variants.question.panelClass'), label: tx('Variant question - panelClass'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.question.panelClass' } },
1487
+ { name: safeName('dialog.variants.question.actions'), label: tx('Variant question - actions (JSON array)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.question.actions', monospace: true } },
1488
+ { name: safeName('dialog.variants.question.styles'), label: tx('Variant question - styles (JSON)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.question.styles', monospace: true }, hint: tx('Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}') },
1489
+ { name: safeName('dialog.variants.question.animation'), label: tx('Variant question - animation (JSON/boolean)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.question.animation', monospace: true } },
993
1490
  // error
994
- { name: safeName('dialog.variants.error.title'), label: 'Variant error título', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.error.title' } },
995
- { name: safeName('dialog.variants.error.icon'), label: 'Variant error ícone', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.error.icon' } },
996
- { name: safeName('dialog.variants.error.message'), label: 'Variant error mensagem', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.error.message' } },
997
- { name: safeName('dialog.variants.error.ariaRole'), label: 'Variant error ariaRole', controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.error.ariaRole' } },
998
- { name: safeName('dialog.variants.error.closeOnBackdropClick'), label: 'Variant error fechar ao clicar no backdrop', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.error.closeOnBackdropClick' } },
999
- { name: safeName('dialog.variants.error.panelClass'), label: 'Variant error panelClass', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.error.panelClass' } },
1000
- { name: safeName('dialog.variants.error.actions'), label: 'Variant error actions (JSON array)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.error.actions', monospace: true } },
1001
- { name: safeName('dialog.variants.error.styles'), label: 'Variant error styles (JSON)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.error.styles', monospace: true }, hint: 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}' },
1002
- { name: safeName('dialog.variants.error.animation'), label: 'Variant error animation (JSON/boolean)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.error.animation', monospace: true } },
1491
+ { name: safeName('dialog.variants.error.title'), label: tx('Variant error - title'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.error.title' } },
1492
+ { name: safeName('dialog.variants.error.icon'), label: tx('Variant error - icon'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.error.icon' } },
1493
+ { name: safeName('dialog.variants.error.message'), label: tx('Variant error - message'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.error.message' } },
1494
+ { name: safeName('dialog.variants.error.ariaRole'), label: tx('Variant error - ariaRole'), controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.error.ariaRole' } },
1495
+ { name: safeName('dialog.variants.error.closeOnBackdropClick'), label: tx('Variant error - close on backdrop click'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.error.closeOnBackdropClick' } },
1496
+ { name: safeName('dialog.variants.error.panelClass'), label: tx('Variant error - panelClass'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.error.panelClass' } },
1497
+ { name: safeName('dialog.variants.error.actions'), label: tx('Variant error - actions (JSON array)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.error.actions', monospace: true } },
1498
+ { name: safeName('dialog.variants.error.styles'), label: tx('Variant error - styles (JSON)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.error.styles', monospace: true }, hint: tx('Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}') },
1499
+ { name: safeName('dialog.variants.error.animation'), label: tx('Variant error - animation (JSON/boolean)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.error.animation', monospace: true } },
1003
1500
  ];
1004
1501
  const cfg = {
1005
1502
  sections: [
1006
1503
  {
1007
1504
  id: 'crud',
1008
- title: 'CRUD',
1505
+ title: tx('CRUD'),
1009
1506
  rows: [
1010
1507
  {
1011
1508
  id: 'crud-row-1',
@@ -1032,7 +1529,7 @@ function buildGlobalConfigFormConfig() {
1032
1529
  },
1033
1530
  {
1034
1531
  id: 'dynamic-fields',
1035
- title: 'Dynamic Fields',
1532
+ title: tx('Dynamic Fields'),
1036
1533
  rows: [
1037
1534
  {
1038
1535
  id: 'df-row-1',
@@ -1053,7 +1550,7 @@ function buildGlobalConfigFormConfig() {
1053
1550
  },
1054
1551
  {
1055
1552
  id: 'ai-credentials',
1056
- title: 'Credenciais', // Internal title, UI might override
1553
+ title: tx('Credentials'), // Internal title, UI might override
1057
1554
  rows: [
1058
1555
  {
1059
1556
  id: 'ai-cred-row-1',
@@ -1066,7 +1563,7 @@ function buildGlobalConfigFormConfig() {
1066
1563
  },
1067
1564
  {
1068
1565
  id: 'ai-model',
1069
- title: 'Modelo & Comportamento',
1566
+ title: tx('Model & Behavior'),
1070
1567
  rows: [
1071
1568
  {
1072
1569
  id: 'ai-mod-row-1',
@@ -1079,7 +1576,7 @@ function buildGlobalConfigFormConfig() {
1079
1576
  },
1080
1577
  {
1081
1578
  id: 'ai-embedding',
1082
- title: 'Embeddings',
1579
+ title: tx('Embeddings (RAG)'),
1083
1580
  rows: [
1084
1581
  {
1085
1582
  id: 'ai-embed-row-1',
@@ -1093,7 +1590,7 @@ function buildGlobalConfigFormConfig() {
1093
1590
  },
1094
1591
  {
1095
1592
  id: 'cache',
1096
- title: 'Cache & Persistência',
1593
+ title: tx('Cache & Persistência'),
1097
1594
  rows: [
1098
1595
  {
1099
1596
  id: 'cache-row-1',
@@ -1105,7 +1602,7 @@ function buildGlobalConfigFormConfig() {
1105
1602
  },
1106
1603
  {
1107
1604
  id: 'table',
1108
- title: 'Tabela',
1605
+ title: tx('Tabela'),
1109
1606
  rows: [
1110
1607
  {
1111
1608
  id: 'tbl-row-1',
@@ -1166,7 +1663,7 @@ function buildGlobalConfigFormConfig() {
1166
1663
  },
1167
1664
  {
1168
1665
  id: 'dialog',
1169
- title: 'Dialog',
1666
+ title: tx('Dialog'),
1170
1667
  rows: [
1171
1668
  {
1172
1669
  id: 'dlg-row-defaults',
@@ -1291,9 +1788,9 @@ function buildGlobalConfigFormConfig() {
1291
1788
  actions: {
1292
1789
  placement: 'afterSections',
1293
1790
  // Hide internal form actions; Settings Panel footer handles Apply/Save
1294
- submit: { visible: false, label: 'Salvar' },
1295
- cancel: { visible: false, label: 'Cancelar' },
1296
- reset: { visible: false, label: 'Redefinir', type: 'reset' },
1791
+ submit: { visible: false, label: tx('Salvar') },
1792
+ cancel: { visible: false, label: tx('Cancelar') },
1793
+ reset: { visible: false, label: tx('Redefinir'), type: 'reset' },
1297
1794
  },
1298
1795
  fieldMetadata: fields,
1299
1796
  };
@@ -1319,10 +1816,10 @@ const TABLE_COMPACT_FONT_SIZE_PATHS = new Set([
1319
1816
  'table.appearance.typography.headerFontSize',
1320
1817
  ]);
1321
1818
  const TABLE_COMPACT_FIELD_LABELS = {
1322
- 'table.appearance.spacing.cellPadding': 'padding das células',
1323
- 'table.appearance.spacing.headerPadding': 'padding do cabeçalho',
1324
- 'table.appearance.typography.fontSize': 'fonte das células',
1325
- 'table.appearance.typography.headerFontSize': 'fonte do cabeçalho',
1819
+ 'table.appearance.spacing.cellPadding': 'cell padding',
1820
+ 'table.appearance.spacing.headerPadding': 'header padding',
1821
+ 'table.appearance.typography.fontSize': 'cell font size',
1822
+ 'table.appearance.typography.headerFontSize': 'header font size',
1326
1823
  };
1327
1824
  const TABLE_COMPACT_LENGTH_TOKEN = '(?:0|(?:\\d+|\\d*\\.\\d+)(?:px|rem|em|%|vh|vw|svh|svw|lvh|lvw|dvh|dvw|ch|ex))';
1328
1825
  const TABLE_COMPACT_SPACING_REGEX = new RegExp(`^(?:var\\(.+\\)|calc\\(.+\\)|${TABLE_COMPACT_LENGTH_TOKEN}(?:\\s+${TABLE_COMPACT_LENGTH_TOKEN}){0,3})$`, 'i');
@@ -1349,6 +1846,7 @@ class GlobalConfigEditorComponent {
1349
1846
  hostAiModel;
1350
1847
  hostAiEmbedding;
1351
1848
  destroyRef = inject(DestroyRef);
1849
+ i18n = inject(PraxisI18nService);
1352
1850
  iconPicker = inject(IconPickerService);
1353
1851
  aiApi = inject(AiBackendApiService);
1354
1852
  cdr = inject(ChangeDetectorRef);
@@ -1382,7 +1880,7 @@ class GlobalConfigEditorComponent {
1382
1880
  apiKeyLast4 = null;
1383
1881
  hasStoredApiKey = false;
1384
1882
  hasStoredGlobalConfig = false;
1385
- configSourceLabel = 'Padrões do servidor (env vars)';
1883
+ configSourceLabel = this.tx('Server defaults (env vars)');
1386
1884
  // UX: API Key monitoring
1387
1885
  apiKeyChanged$ = new Subject();
1388
1886
  hasApiKey = false;
@@ -1394,12 +1892,12 @@ class GlobalConfigEditorComponent {
1394
1892
  get apiKeyStatusLabel() {
1395
1893
  const apiKey = this.currentValues?.[this.safeName('ai.apiKey')] || '';
1396
1894
  if (apiKey)
1397
- return 'Chave informada';
1895
+ return this.tx('Key provided');
1398
1896
  if (this.apiKeyLast4)
1399
- return `Chave salva (****${this.apiKeyLast4})`;
1897
+ return this.tx('Saved key (****{{last4}})', { last4: this.apiKeyLast4 });
1400
1898
  if (this.hasStoredApiKey)
1401
- return 'Chave salva';
1402
- return 'Sem chave salva';
1899
+ return this.tx('Saved key');
1900
+ return this.tx('No saved key');
1403
1901
  }
1404
1902
  constructor(admin, snack) {
1405
1903
  this.admin = admin;
@@ -1408,7 +1906,7 @@ class GlobalConfigEditorComponent {
1408
1906
  async ngOnInit() {
1409
1907
  const cfg = this.admin.getEffectiveConfig();
1410
1908
  const flat = this.flatten(cfg);
1411
- this.formConfig = buildGlobalConfigFormConfig();
1909
+ this.formConfig = buildGlobalConfigFormConfig(this.tx.bind(this));
1412
1910
  this.applyConfigSnapshot(flat, { resetForms: false });
1413
1911
  await this.loadProviderCatalog();
1414
1912
  this.applyProviderOptions();
@@ -1553,7 +2051,7 @@ class GlobalConfigEditorComponent {
1553
2051
  const ref = g.host.createComponent(this.dynamicFormCtor);
1554
2052
  ref.setInput('config', g.cfg);
1555
2053
  ref.setInput('mode', 'edit');
1556
- // Não habilitar o modo de edição de layout (canvas) queremos apenas edição de valores
2054
+ // Não habilitar o modo de edição de layout (canvas) - queremos apenas edição de valores
1557
2055
  ref.setInput('enableCustomization', false);
1558
2056
  const inst = ref.instance;
1559
2057
  // FORÇAR estado de sucesso para renderizar o formulário sem resourcePath
@@ -1626,7 +2124,7 @@ class GlobalConfigEditorComponent {
1626
2124
  {
1627
2125
  id: 'gemini',
1628
2126
  label: 'Google Gemini',
1629
- description: 'Modelos rápidos e multimodais do Google.',
2127
+ description: this.tx('Fast multimodal models from Google.'),
1630
2128
  defaultModel: 'gemini-2.0-flash',
1631
2129
  requiresApiKey: true,
1632
2130
  supportsModels: true,
@@ -1636,7 +2134,7 @@ class GlobalConfigEditorComponent {
1636
2134
  {
1637
2135
  id: 'openai',
1638
2136
  label: 'OpenAI',
1639
- description: 'Modelos GPT para texto e chat.',
2137
+ description: this.tx('GPT models for text and chat.'),
1640
2138
  defaultModel: 'gpt-4o-mini',
1641
2139
  requiresApiKey: true,
1642
2140
  supportsModels: true,
@@ -1646,7 +2144,7 @@ class GlobalConfigEditorComponent {
1646
2144
  {
1647
2145
  id: 'xai',
1648
2146
  label: 'xAI (Grok)',
1649
- description: 'Modelos Grok focados em raciocínio.',
2147
+ description: this.tx('Grok models focused on reasoning.'),
1650
2148
  defaultModel: 'grok-2-latest',
1651
2149
  requiresApiKey: true,
1652
2150
  supportsModels: true,
@@ -1656,7 +2154,7 @@ class GlobalConfigEditorComponent {
1656
2154
  {
1657
2155
  id: 'mock',
1658
2156
  label: 'Mock (dev)',
1659
- description: 'Modo local para testes sem chave.',
2157
+ description: this.tx('Local mode for tests without a key.'),
1660
2158
  defaultModel: 'mock-default',
1661
2159
  requiresApiKey: false,
1662
2160
  supportsModels: true,
@@ -1845,8 +2343,8 @@ class GlobalConfigEditorComponent {
1845
2343
  this.hasStoredGlobalConfig = false;
1846
2344
  }
1847
2345
  this.configSourceLabel = this.hasStoredGlobalConfig
1848
- ? 'Configuração salva (UI) sobrescreve os defaults do servidor'
1849
- : 'Padrões do servidor (env vars)';
2346
+ ? this.tx('Saved configuration (UI) - overrides server defaults')
2347
+ : this.tx('Server defaults (env vars)');
1850
2348
  }
1851
2349
  async clearStoredConfig() {
1852
2350
  if (this.isClearingGlobalConfig)
@@ -1861,13 +2359,13 @@ class GlobalConfigEditorComponent {
1861
2359
  this.refreshAiStateAfterConfig();
1862
2360
  await this.refreshStoredConfigState();
1863
2361
  try {
1864
- this.snack.open('Configuração global limpa. Usando defaults do servidor.', undefined, { duration: 2500 });
2362
+ this.snack.open(this.tx('Global config cleared. Using server defaults.'), undefined, { duration: 2500 });
1865
2363
  }
1866
2364
  catch { }
1867
2365
  }
1868
2366
  catch (err) {
1869
2367
  try {
1870
- this.snack.open('Falha ao limpar a configuração global.', undefined, { duration: 4000 });
2368
+ this.snack.open(this.tx('Failed to clear global config.'), undefined, { duration: 4000 });
1871
2369
  }
1872
2370
  catch { }
1873
2371
  }
@@ -1994,10 +2492,10 @@ class GlobalConfigEditorComponent {
1994
2492
  const model = this.availableModels.find(m => m.name.endsWith(modelName));
1995
2493
  if (model) {
1996
2494
  const formatLimit = (n) => n ? (n >= 1000 ? (n / 1000).toFixed(0) + 'k' : n) : 'N/A';
1997
- this.selectedModelDetails = `Modelo: ${model.displayName || modelName} | Tokens (in/out): ${formatLimit(model.inputTokenLimit)}/${formatLimit(model.outputTokenLimit)} | Métodos: ${model.supportedGenerationMethods?.join(', ') || 'N/A'}`;
2495
+ this.selectedModelDetails = this.tx('Model: {{model}} | Tokens (in/out): {{in}}/{{out}} | Methods: {{methods}}', { model: model.displayName || modelName, in: formatLimit(model.inputTokenLimit), out: formatLimit(model.outputTokenLimit), methods: model.supportedGenerationMethods?.join(', ') || 'N/A' });
1998
2496
  }
1999
2497
  else {
2000
- this.selectedModelDetails = 'Detalhes do modelo não disponíveis.';
2498
+ this.selectedModelDetails = this.tx('No model details available.');
2001
2499
  }
2002
2500
  }
2003
2501
  // SettingsPanel expects these methods
@@ -2033,7 +2531,7 @@ class GlobalConfigEditorComponent {
2033
2531
  this.initialValues = { ...this.currentValues };
2034
2532
  this.isDirty$.next(false);
2035
2533
  try {
2036
- this.snack.open('Configurações salvas', undefined, { duration: 2000 });
2534
+ this.snack.open(this.tx('Settings saved'), undefined, { duration: 2000 });
2037
2535
  }
2038
2536
  catch { }
2039
2537
  return partial;
@@ -2056,7 +2554,7 @@ class GlobalConfigEditorComponent {
2056
2554
  const meta = this.findProvider(provider);
2057
2555
  if (meta?.supportsModels === false) {
2058
2556
  if (!silent) {
2059
- this.aiTestResult = { success: false, message: 'Este provedor não oferece catálogo de modelos.' };
2557
+ this.aiTestResult = { success: false, message: this.tx('This provider has no model catalog.') };
2060
2558
  this.cdr.detectChanges();
2061
2559
  }
2062
2560
  return;
@@ -2064,7 +2562,7 @@ class GlobalConfigEditorComponent {
2064
2562
  const requiresKey = meta?.requiresApiKey !== false;
2065
2563
  const hasKey = !!apiKey || this.hasStoredApiKey || !requiresKey;
2066
2564
  if (requiresKey && !hasKey) {
2067
- this.aiTestResult = { success: false, message: 'Insira uma chave de API para buscar modelos.' };
2565
+ this.aiTestResult = { success: false, message: this.tx('Enter an API key to fetch models.') };
2068
2566
  this.cdr.detectChanges();
2069
2567
  return;
2070
2568
  }
@@ -2079,8 +2577,7 @@ class GlobalConfigEditorComponent {
2079
2577
  request.apiKey = apiKey;
2080
2578
  const response = await firstValueFrom(this.aiApi.listModels(request));
2081
2579
  if (!response?.success) {
2082
- const msg = response?.message || 'Erro ao buscar modelos.';
2083
- throw new Error(msg);
2580
+ throw new Error(this.tx('Error fetching models.'));
2084
2581
  }
2085
2582
  const models = response.models || [];
2086
2583
  this.availableModels = models; // Store available models
@@ -2101,9 +2598,9 @@ class GlobalConfigEditorComponent {
2101
2598
  }
2102
2599
  catch (error) {
2103
2600
  this.logger.error('[GlobalConfigEditor] Error fetching models', this.buildLogOptions({ error, provider }, { context: { actionId: 'models.fetch' } }));
2104
- this.aiTestResult = { success: false, message: error.message || 'Erro ao buscar modelos.' };
2601
+ this.aiTestResult = { success: false, message: this.tx('Error fetching models.') };
2105
2602
  if (!silent) {
2106
- this.snack.open('Erro ao buscar modelos. Verifique a chave de API.', 'Fechar', { duration: 5000 });
2603
+ this.snack.open(this.tx('Error fetching models. Check your API key.'), this.tx('Close'), { duration: 5000 });
2107
2604
  }
2108
2605
  }
2109
2606
  finally {
@@ -2133,7 +2630,7 @@ class GlobalConfigEditorComponent {
2133
2630
  this.recreateAiModelForm();
2134
2631
  if (!silent) {
2135
2632
  try {
2136
- this.snack.open(`Lista de modelos atualizada (${modelOptions.length} modelos)`, undefined, { duration: 3000 });
2633
+ this.snack.open(this.tx('Model list updated ({{count}} models)', { count: modelOptions.length }), undefined, { duration: 3000 });
2137
2634
  }
2138
2635
  catch { }
2139
2636
  }
@@ -2151,7 +2648,7 @@ class GlobalConfigEditorComponent {
2151
2648
  const requiresKey = meta?.requiresApiKey !== false;
2152
2649
  const hasKey = !!apiKey || this.hasStoredApiKey || !requiresKey;
2153
2650
  if (requiresKey && !hasKey) {
2154
- this.aiTestResult = { success: false, message: 'Insira uma chave de API para testar.' };
2651
+ this.aiTestResult = { success: false, message: this.tx('Enter an API key to test.') };
2155
2652
  this.isTestingAi = false;
2156
2653
  this.cdr.detectChanges();
2157
2654
  return;
@@ -2162,17 +2659,16 @@ class GlobalConfigEditorComponent {
2162
2659
  request.apiKey = apiKey;
2163
2660
  const response = await firstValueFrom(this.aiApi.testProvider(request));
2164
2661
  if (!response?.success) {
2165
- throw new Error(response?.message || 'Falha ao testar conexao.');
2662
+ throw new Error(this.tx('Failed to test connection.'));
2166
2663
  }
2167
- this.aiTestResult = { success: true, message: response.message || 'Conexao estabelecida com sucesso!' };
2664
+ this.aiTestResult = { success: true, message: this.tx('Connection established successfully!') };
2168
2665
  this.hasApiKey = true; // Garantir desbloqueio da seção de modelo após sucesso
2169
2666
  // Após validar a chave, já buscar a lista de modelos para preencher o select
2170
2667
  await this.refreshModels(true);
2171
2668
  }
2172
2669
  catch (err) {
2173
2670
  this.logger.error('[GlobalConfigEditor] AI Connection Test Error', this.buildLogOptions({ error: err, provider, model: selectedModel }, { context: { actionId: 'provider.test-connection' } }));
2174
- const msg = err?.message || 'Erro desconhecido';
2175
- this.aiTestResult = { success: false, message: msg };
2671
+ this.aiTestResult = { success: false, message: this.tx('Failed to test connection.') };
2176
2672
  }
2177
2673
  finally {
2178
2674
  this.isTestingAi = false;
@@ -2193,6 +2689,10 @@ class GlobalConfigEditorComponent {
2193
2689
  safeName(path) {
2194
2690
  return path.replace(/[^a-zA-Z0-9_]/g, '_');
2195
2691
  }
2692
+ tx(text, params) {
2693
+ const normalized = normalizeMojibakeText(text);
2694
+ return this.i18n.t(normalized, params, normalized, PRAXIS_SETTINGS_PANEL_I18N_NAMESPACE);
2695
+ }
2196
2696
  buildChangedValues() {
2197
2697
  const out = {};
2198
2698
  for (const [safe, value] of Object.entries(this.currentValues)) {
@@ -2217,21 +2717,7 @@ class GlobalConfigEditorComponent {
2217
2717
  return initial !== current;
2218
2718
  }
2219
2719
  resolveSaveErrorMessage(err) {
2220
- const apiMessage = typeof err?.error?.message === 'string' ? err.error.message : null;
2221
- const details = err?.error?.details;
2222
- if (apiMessage && apiMessage.trim()) {
2223
- return apiMessage;
2224
- }
2225
- if (details && typeof details === 'object') {
2226
- const first = Object.values(details).find((v) => typeof v === 'string' && v.trim());
2227
- if (typeof first === 'string') {
2228
- return first;
2229
- }
2230
- }
2231
- if (typeof err?.message === 'string' && err.message.trim()) {
2232
- return err.message;
2233
- }
2234
- return 'Falha ao salvar configurações.';
2720
+ return this.tx('Save failed.');
2235
2721
  }
2236
2722
  normalizeFieldValue(path, value) {
2237
2723
  if (typeof value !== 'string')
@@ -2278,7 +2764,7 @@ class GlobalConfigEditorComponent {
2278
2764
  if (!normalized)
2279
2765
  continue;
2280
2766
  if (!check.regex.test(normalized)) {
2281
- return `Valor inválido em ${TABLE_COMPACT_FIELD_LABELS[check.path]}. Use uma string CSS simples, como ${check.example}.`;
2767
+ return `Invalid value in ${TABLE_COMPACT_FIELD_LABELS[check.path]}. Use a simple CSS string, such as ${check.example}.`;
2282
2768
  }
2283
2769
  }
2284
2770
  return null;
@@ -2388,9 +2874,9 @@ class GlobalConfigEditorComponent {
2388
2874
  <mat-expansion-panel-header>
2389
2875
  <mat-panel-title>
2390
2876
  <mat-icon class="panel-icon">construction</mat-icon>
2391
- CRUD
2877
+ {{ tx('CRUD') }}
2392
2878
  </mat-panel-title>
2393
- <mat-panel-description>Políticas globais de abertura, back e header</mat-panel-description>
2879
+ <mat-panel-description>{{ tx('Global policies for opening, back and header') }}</mat-panel-description>
2394
2880
  </mat-expansion-panel-header>
2395
2881
  <ng-template #hostCrud></ng-template>
2396
2882
  </mat-expansion-panel>
@@ -2398,9 +2884,9 @@ class GlobalConfigEditorComponent {
2398
2884
  <mat-expansion-panel-header>
2399
2885
  <mat-panel-title>
2400
2886
  <mat-icon class="panel-icon">dynamic_form</mat-icon>
2401
- Dynamic Fields
2887
+ {{ tx('Dynamic Fields') }}
2402
2888
  </mat-panel-title>
2403
- <mat-panel-description>Async Select, cascata e paginação</mat-panel-description>
2889
+ <mat-panel-description>{{ tx('Async Select, cascade and pagination') }}</mat-panel-description>
2404
2890
  </mat-expansion-panel-header>
2405
2891
  <ng-template #hostFields></ng-template>
2406
2892
  </mat-expansion-panel>
@@ -2408,9 +2894,9 @@ class GlobalConfigEditorComponent {
2408
2894
  <mat-expansion-panel-header>
2409
2895
  <mat-panel-title>
2410
2896
  <mat-icon class="panel-icon">cached</mat-icon>
2411
- Cache & Persistência
2897
+ {{ tx('Cache & Persistence') }}
2412
2898
  </mat-panel-title>
2413
- <mat-panel-description>Estratégia de cache de schema (local vs server)</mat-panel-description>
2899
+ <mat-panel-description>{{ tx('Schema cache strategy (local vs server)') }}</mat-panel-description>
2414
2900
  </mat-expansion-panel-header>
2415
2901
  <ng-template #hostCache></ng-template>
2416
2902
  </mat-expansion-panel>
@@ -2418,9 +2904,9 @@ class GlobalConfigEditorComponent {
2418
2904
  <mat-expansion-panel-header>
2419
2905
  <mat-panel-title>
2420
2906
  <mat-icon class="panel-icon">psychology</mat-icon>
2421
- Inteligência Artificial
2907
+ {{ tx('Artificial Intelligence') }}
2422
2908
  </mat-panel-title>
2423
- <mat-panel-description>Integração com LLM</mat-panel-description>
2909
+ <mat-panel-description>{{ tx('LLM integration') }}</mat-panel-description>
2424
2910
  </mat-expansion-panel-header>
2425
2911
 
2426
2912
  <div class="ai-config-container">
@@ -2429,23 +2915,23 @@ class GlobalConfigEditorComponent {
2429
2915
  <mat-icon>settings_suggest</mat-icon>
2430
2916
  <span>{{ configSourceLabel }}</span>
2431
2917
  </div>
2432
- <button
2433
- mat-stroked-button
2434
- type="button"
2435
- class="ai-action-btn ai-action-btn--clear"
2436
- *ngIf="hasStoredGlobalConfig"
2437
- [attr.aria-busy]="isClearingGlobalConfig ? 'true' : null"
2438
- [disabled]="isClearingGlobalConfig"
2439
- (click)="clearStoredConfig()"
2440
- matTooltip="Apaga o config salvo e volta aos defaults do servidor"
2918
+ <button
2919
+ mat-stroked-button
2920
+ type="button"
2921
+ class="ai-action-btn ai-action-btn--clear"
2922
+ *ngIf="hasStoredGlobalConfig"
2923
+ [attr.aria-busy]="isClearingGlobalConfig ? 'true' : null"
2924
+ [disabled]="isClearingGlobalConfig"
2925
+ (click)="clearStoredConfig()"
2926
+ [matTooltip]="tx('Clear saved config and return to server defaults')"
2441
2927
  >
2442
2928
  <ng-container *ngIf="isClearingGlobalConfig; else clearContent">
2443
2929
  <mat-spinner diameter="16" class="btn-spinner"></mat-spinner>
2444
- <span class="ai-action-label">Limpando...</span>
2930
+ <span class="ai-action-label">{{ tx('Clearing...') }}</span>
2445
2931
  </ng-container>
2446
2932
  <ng-template #clearContent>
2447
2933
  <mat-icon>delete_sweep</mat-icon>
2448
- <span class="ai-action-label">Limpar config salvo</span>
2934
+ <span class="ai-action-label">{{ tx('Clear saved config') }}</span>
2449
2935
  </ng-template>
2450
2936
  </button>
2451
2937
  </div>
@@ -2453,7 +2939,7 @@ class GlobalConfigEditorComponent {
2453
2939
  <div class="ai-group">
2454
2940
  <div class="ai-group-header">
2455
2941
  <div class="ai-group-title">
2456
- <mat-icon>vpn_key</mat-icon> Credenciais
2942
+ <mat-icon>vpn_key</mat-icon> {{ tx('Credentials') }}
2457
2943
  </div>
2458
2944
  <button mat-stroked-button
2459
2945
  type="button"
@@ -2462,15 +2948,15 @@ class GlobalConfigEditorComponent {
2462
2948
  [attr.aria-busy]="isTestingAi ? 'true' : null"
2463
2949
  (click)="testAiConnection()"
2464
2950
  [disabled]="isTestingAi || !hasApiKey"
2465
- matTooltip="Testar conexão com a chave informada">
2951
+ [matTooltip]="tx('Test connection with the provided key')">
2466
2952
  <ng-container *ngIf="isTestingAi; else btnContent">
2467
2953
  <mat-spinner diameter="16" class="btn-spinner"></mat-spinner>
2468
- <span class="ai-action-label">Conectando...</span>
2954
+ <span class="ai-action-label">{{ tx('Connecting...') }}</span>
2469
2955
  </ng-container>
2470
2956
  <ng-template #btnContent>
2471
2957
  <mat-icon>{{ aiTestResult?.success ? 'check' : 'bolt' }}</mat-icon>
2472
2958
  <span class="ai-action-label">
2473
- {{ aiTestResult?.success ? 'Conectado' : 'Testar conexão' }}
2959
+ {{ aiTestResult?.success ? tx('Connected') : tx('Test connection') }}
2474
2960
  </span>
2475
2961
  </ng-template>
2476
2962
  </button>
@@ -2512,7 +2998,7 @@ class GlobalConfigEditorComponent {
2512
2998
  </div>
2513
2999
  <div class="ai-provider-key is-unlocked" *ngIf="selectedProvider?.requiresApiKey === false">
2514
3000
  <mat-icon>check_circle</mat-icon>
2515
- <span>Sem chave necessária</span>
3001
+ <span>{{ tx('No key required') }}</span>
2516
3002
  </div>
2517
3003
  </div>
2518
3004
  <div class="ai-credentials-row">
@@ -2532,12 +3018,12 @@ class GlobalConfigEditorComponent {
2532
3018
  <div class="ai-group" [class.disabled-group]="!hasApiKey">
2533
3019
  <div class="ai-group-header">
2534
3020
  <div class="ai-group-title">
2535
- <mat-icon>smart_toy</mat-icon> Modelo & Comportamento
3021
+ <mat-icon>smart_toy</mat-icon> {{ tx('Model & Behavior') }}
2536
3022
  </div>
2537
3023
  <div class="ai-header-actions">
2538
- <span class="ai-subtext" *ngIf="hasApiKey">Escolha o modelo após validar a chave.</span>
2539
- <mat-chip-option *ngIf="!hasApiKey" disabled>Requer chave API validada</mat-chip-option>
2540
- <button mat-icon-button (click)="refreshModels(true)" [disabled]="isTestingAi || !hasApiKey" matTooltip="Atualizar lista de modelos" aria-label="Atualizar lista de modelos">
3024
+ <span class="ai-subtext" *ngIf="hasApiKey">{{ tx('Choose the model after validating the key.') }}</span>
3025
+ <mat-chip-option *ngIf="!hasApiKey" disabled>{{ tx('API key validated required') }}</mat-chip-option>
3026
+ <button mat-icon-button (click)="refreshModels(true)" [disabled]="isTestingAi || !hasApiKey" [matTooltip]="tx('Refresh model list')" [attr.aria-label]="tx('Refresh model list')">
2541
3027
  <mat-icon [class.spin]="isRefetchingModels">sync</mat-icon>
2542
3028
  </button>
2543
3029
  </div>
@@ -2556,7 +3042,7 @@ class GlobalConfigEditorComponent {
2556
3042
 
2557
3043
  <div class="ai-placeholder" *ngIf="!hasApiKey">
2558
3044
  <mat-icon>lock</mat-icon>
2559
- <span>Configure e teste sua chave de API para desbloquear a seleção de modelos.</span>
3045
+ <span>{{ tx('Configure and test your API key to unlock model selection.') }}</span>
2560
3046
  </div>
2561
3047
  </div>
2562
3048
 
@@ -2564,7 +3050,7 @@ class GlobalConfigEditorComponent {
2564
3050
  <div class="ai-group">
2565
3051
  <div class="ai-group-header">
2566
3052
  <div class="ai-group-title">
2567
- <mat-icon>scatter_plot</mat-icon> Embeddings (RAG)
3053
+ <mat-icon>scatter_plot</mat-icon> {{ tx('Embeddings (RAG)') }}
2568
3054
  </div>
2569
3055
  <div class="ai-header-actions">
2570
3056
  <button
@@ -2573,19 +3059,19 @@ class GlobalConfigEditorComponent {
2573
3059
  class="ai-action-btn"
2574
3060
  (click)="useLlmForEmbeddings()"
2575
3061
  [disabled]="!canUseLlmForEmbeddings"
2576
- matTooltip="Aplicar provedor e chave do LLM aos embeddings"
3062
+ [matTooltip]="tx('Use the LLM provider and key for embeddings')"
2577
3063
  >
2578
3064
  <mat-icon>merge_type</mat-icon>
2579
- <span class="ai-action-label">Usar mesmo LLM</span>
3065
+ <span class="ai-action-label">{{ tx('Use the LLM provider and key for embeddings') }}</span>
2580
3066
  </button>
2581
- <mat-chip-option *ngIf="!canUseLlmForEmbeddings" disabled>Provedor sem embeddings</mat-chip-option>
3067
+ <mat-chip-option *ngIf="!canUseLlmForEmbeddings" disabled>{{ tx('Provider has no embeddings') }}</mat-chip-option>
2582
3068
  </div>
2583
3069
  </div>
2584
3070
  <div class="ai-subtext">
2585
- Configure o provedor de embeddings para buscas vetoriais (templates e schemas).
3071
+ {{ tx('Configure the embeddings provider for vector search (templates and schemas).') }}
2586
3072
  </div>
2587
3073
  <div class="ai-subtext" *ngIf="embeddingUseSameAsLlm">
2588
- Sincronizado com o LLM. Os campos abaixo acompanham a credencial principal.
3074
+ {{ tx('Synchronized with the LLM. The fields below follow the primary credential.') }}
2589
3075
  </div>
2590
3076
  <div class="ai-embedding-row">
2591
3077
  <ng-template #hostAiEmbedding></ng-template>
@@ -2593,7 +3079,7 @@ class GlobalConfigEditorComponent {
2593
3079
  <div class="ai-feedback ai-feedback--warn" *ngIf="embeddingDimensionMismatch">
2594
3080
  <mat-icon>warning</mat-icon>
2595
3081
  <span class="error-text">
2596
- Dimensão de embeddings diferente do banco (768). Ajuste para 768 ou refaça a migração.
3082
+ {{ tx('Embedding dimension mismatch with database (768). Adjust to 768 or redo the migration.') }}
2597
3083
  </span>
2598
3084
  </div>
2599
3085
  </div>
@@ -2604,9 +3090,9 @@ class GlobalConfigEditorComponent {
2604
3090
  <mat-expansion-panel-header>
2605
3091
  <mat-panel-title>
2606
3092
  <mat-icon class="panel-icon">table_chart</mat-icon>
2607
- Tabela
3093
+ {{ tx('Table') }}
2608
3094
  </mat-panel-title>
2609
- <mat-panel-description>Toolbar, aparência e filtro avançado</mat-panel-description>
3095
+ <mat-panel-description>{{ tx('Toolbar, appearance and advanced filter') }}</mat-panel-description>
2610
3096
  </mat-expansion-panel-header>
2611
3097
  <ng-template #hostTable></ng-template>
2612
3098
  </mat-expansion-panel>
@@ -2614,27 +3100,27 @@ class GlobalConfigEditorComponent {
2614
3100
  <mat-expansion-panel-header>
2615
3101
  <mat-panel-title>
2616
3102
  <mat-icon class="panel-icon">forum</mat-icon>
2617
- Dialog
3103
+ {{ tx('Dialog') }}
2618
3104
  </mat-panel-title>
2619
- <mat-panel-description>Defaults e variants (danger, info, success, question, error)</mat-panel-description>
3105
+ <mat-panel-description>{{ tx('Defaults and variants (danger, info, success, question, error)') }}</mat-panel-description>
2620
3106
  </mat-expansion-panel-header>
2621
3107
  <ng-template #hostDialog></ng-template>
2622
3108
  <!-- Icon UX helpers for Dialog variants -->
2623
3109
  <div class="dlg-icon-helpers">
2624
- <div class="dlg-icon-helpers__head">Ícones por perfil (atalhos)</div>
3110
+ <div class="dlg-icon-helpers__head">{{ tx('Icons by profile (shortcuts)') }}</div>
2625
3111
  <div class="dlg-icon-helpers__row" *ngFor="let k of dialogVariantKeys">
2626
3112
  <div class="dlg-icon-helpers__label">{{ k }}</div>
2627
3113
  <mat-icon aria-hidden="true" [praxisIcon]="getVariantIcon(k) || 'mi:help_outline'" class="dlg-icon-helpers__preview"></mat-icon>
2628
- <button mat-stroked-button color="primary" type="button" (click)="pickVariantIcon(k)" matTooltip="Escolher ícone para {{k}}">
3114
+ <button mat-stroked-button color="primary" type="button" (click)="pickVariantIcon(k)" [matTooltip]="tx('Pick icon for {{key}}', { key: k })">
2629
3115
  <mat-icon>search</mat-icon>
2630
- Escolher ícone
3116
+ {{ tx('Pick icon') }}
2631
3117
  </button>
2632
- <button mat-icon-button type="button" *ngIf="getVariantIcon(k)" (click)="clearVariantIcon(k)" matTooltip="Limpar ícone de {{k}}" aria-label="Limpar ícone">
3118
+ <button mat-icon-button type="button" *ngIf="getVariantIcon(k)" (click)="clearVariantIcon(k)" [matTooltip]="tx('Clear icon for {{key}}', { key: k })" [attr.aria-label]="tx('Clear icon')">
2633
3119
  <mat-icon>backspace</mat-icon>
2634
3120
  </button>
2635
3121
  <span class="dlg-icon-helpers__value" *ngIf="getVariantIcon(k)">{{ getVariantIcon(k) }}</span>
2636
3122
  </div>
2637
- <div class="dlg-icon-helpers__hint">Dica: O campo de texto acima permanece editável. Estes botões apenas facilitam a escolha/limpeza com preview.</div>
3123
+ <div class="dlg-icon-helpers__hint">{{ tx('The text field above remains editable. These buttons only help with selection/clear preview.') }}</div>
2638
3124
  </div>
2639
3125
  </mat-expansion-panel>
2640
3126
  </mat-accordion>
@@ -2648,9 +3134,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2648
3134
  <mat-expansion-panel-header>
2649
3135
  <mat-panel-title>
2650
3136
  <mat-icon class="panel-icon">construction</mat-icon>
2651
- CRUD
3137
+ {{ tx('CRUD') }}
2652
3138
  </mat-panel-title>
2653
- <mat-panel-description>Políticas globais de abertura, back e header</mat-panel-description>
3139
+ <mat-panel-description>{{ tx('Global policies for opening, back and header') }}</mat-panel-description>
2654
3140
  </mat-expansion-panel-header>
2655
3141
  <ng-template #hostCrud></ng-template>
2656
3142
  </mat-expansion-panel>
@@ -2658,9 +3144,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2658
3144
  <mat-expansion-panel-header>
2659
3145
  <mat-panel-title>
2660
3146
  <mat-icon class="panel-icon">dynamic_form</mat-icon>
2661
- Dynamic Fields
3147
+ {{ tx('Dynamic Fields') }}
2662
3148
  </mat-panel-title>
2663
- <mat-panel-description>Async Select, cascata e paginação</mat-panel-description>
3149
+ <mat-panel-description>{{ tx('Async Select, cascade and pagination') }}</mat-panel-description>
2664
3150
  </mat-expansion-panel-header>
2665
3151
  <ng-template #hostFields></ng-template>
2666
3152
  </mat-expansion-panel>
@@ -2668,9 +3154,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2668
3154
  <mat-expansion-panel-header>
2669
3155
  <mat-panel-title>
2670
3156
  <mat-icon class="panel-icon">cached</mat-icon>
2671
- Cache & Persistência
3157
+ {{ tx('Cache & Persistence') }}
2672
3158
  </mat-panel-title>
2673
- <mat-panel-description>Estratégia de cache de schema (local vs server)</mat-panel-description>
3159
+ <mat-panel-description>{{ tx('Schema cache strategy (local vs server)') }}</mat-panel-description>
2674
3160
  </mat-expansion-panel-header>
2675
3161
  <ng-template #hostCache></ng-template>
2676
3162
  </mat-expansion-panel>
@@ -2678,9 +3164,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2678
3164
  <mat-expansion-panel-header>
2679
3165
  <mat-panel-title>
2680
3166
  <mat-icon class="panel-icon">psychology</mat-icon>
2681
- Inteligência Artificial
3167
+ {{ tx('Artificial Intelligence') }}
2682
3168
  </mat-panel-title>
2683
- <mat-panel-description>Integração com LLM</mat-panel-description>
3169
+ <mat-panel-description>{{ tx('LLM integration') }}</mat-panel-description>
2684
3170
  </mat-expansion-panel-header>
2685
3171
 
2686
3172
  <div class="ai-config-container">
@@ -2689,23 +3175,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2689
3175
  <mat-icon>settings_suggest</mat-icon>
2690
3176
  <span>{{ configSourceLabel }}</span>
2691
3177
  </div>
2692
- <button
2693
- mat-stroked-button
2694
- type="button"
2695
- class="ai-action-btn ai-action-btn--clear"
2696
- *ngIf="hasStoredGlobalConfig"
2697
- [attr.aria-busy]="isClearingGlobalConfig ? 'true' : null"
2698
- [disabled]="isClearingGlobalConfig"
2699
- (click)="clearStoredConfig()"
2700
- matTooltip="Apaga o config salvo e volta aos defaults do servidor"
3178
+ <button
3179
+ mat-stroked-button
3180
+ type="button"
3181
+ class="ai-action-btn ai-action-btn--clear"
3182
+ *ngIf="hasStoredGlobalConfig"
3183
+ [attr.aria-busy]="isClearingGlobalConfig ? 'true' : null"
3184
+ [disabled]="isClearingGlobalConfig"
3185
+ (click)="clearStoredConfig()"
3186
+ [matTooltip]="tx('Clear saved config and return to server defaults')"
2701
3187
  >
2702
3188
  <ng-container *ngIf="isClearingGlobalConfig; else clearContent">
2703
3189
  <mat-spinner diameter="16" class="btn-spinner"></mat-spinner>
2704
- <span class="ai-action-label">Limpando...</span>
3190
+ <span class="ai-action-label">{{ tx('Clearing...') }}</span>
2705
3191
  </ng-container>
2706
3192
  <ng-template #clearContent>
2707
3193
  <mat-icon>delete_sweep</mat-icon>
2708
- <span class="ai-action-label">Limpar config salvo</span>
3194
+ <span class="ai-action-label">{{ tx('Clear saved config') }}</span>
2709
3195
  </ng-template>
2710
3196
  </button>
2711
3197
  </div>
@@ -2713,7 +3199,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2713
3199
  <div class="ai-group">
2714
3200
  <div class="ai-group-header">
2715
3201
  <div class="ai-group-title">
2716
- <mat-icon>vpn_key</mat-icon> Credenciais
3202
+ <mat-icon>vpn_key</mat-icon> {{ tx('Credentials') }}
2717
3203
  </div>
2718
3204
  <button mat-stroked-button
2719
3205
  type="button"
@@ -2722,15 +3208,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2722
3208
  [attr.aria-busy]="isTestingAi ? 'true' : null"
2723
3209
  (click)="testAiConnection()"
2724
3210
  [disabled]="isTestingAi || !hasApiKey"
2725
- matTooltip="Testar conexão com a chave informada">
3211
+ [matTooltip]="tx('Test connection with the provided key')">
2726
3212
  <ng-container *ngIf="isTestingAi; else btnContent">
2727
3213
  <mat-spinner diameter="16" class="btn-spinner"></mat-spinner>
2728
- <span class="ai-action-label">Conectando...</span>
3214
+ <span class="ai-action-label">{{ tx('Connecting...') }}</span>
2729
3215
  </ng-container>
2730
3216
  <ng-template #btnContent>
2731
3217
  <mat-icon>{{ aiTestResult?.success ? 'check' : 'bolt' }}</mat-icon>
2732
3218
  <span class="ai-action-label">
2733
- {{ aiTestResult?.success ? 'Conectado' : 'Testar conexão' }}
3219
+ {{ aiTestResult?.success ? tx('Connected') : tx('Test connection') }}
2734
3220
  </span>
2735
3221
  </ng-template>
2736
3222
  </button>
@@ -2772,7 +3258,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2772
3258
  </div>
2773
3259
  <div class="ai-provider-key is-unlocked" *ngIf="selectedProvider?.requiresApiKey === false">
2774
3260
  <mat-icon>check_circle</mat-icon>
2775
- <span>Sem chave necessária</span>
3261
+ <span>{{ tx('No key required') }}</span>
2776
3262
  </div>
2777
3263
  </div>
2778
3264
  <div class="ai-credentials-row">
@@ -2792,12 +3278,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2792
3278
  <div class="ai-group" [class.disabled-group]="!hasApiKey">
2793
3279
  <div class="ai-group-header">
2794
3280
  <div class="ai-group-title">
2795
- <mat-icon>smart_toy</mat-icon> Modelo & Comportamento
3281
+ <mat-icon>smart_toy</mat-icon> {{ tx('Model & Behavior') }}
2796
3282
  </div>
2797
3283
  <div class="ai-header-actions">
2798
- <span class="ai-subtext" *ngIf="hasApiKey">Escolha o modelo após validar a chave.</span>
2799
- <mat-chip-option *ngIf="!hasApiKey" disabled>Requer chave API validada</mat-chip-option>
2800
- <button mat-icon-button (click)="refreshModels(true)" [disabled]="isTestingAi || !hasApiKey" matTooltip="Atualizar lista de modelos" aria-label="Atualizar lista de modelos">
3284
+ <span class="ai-subtext" *ngIf="hasApiKey">{{ tx('Choose the model after validating the key.') }}</span>
3285
+ <mat-chip-option *ngIf="!hasApiKey" disabled>{{ tx('API key validated required') }}</mat-chip-option>
3286
+ <button mat-icon-button (click)="refreshModels(true)" [disabled]="isTestingAi || !hasApiKey" [matTooltip]="tx('Refresh model list')" [attr.aria-label]="tx('Refresh model list')">
2801
3287
  <mat-icon [class.spin]="isRefetchingModels">sync</mat-icon>
2802
3288
  </button>
2803
3289
  </div>
@@ -2816,7 +3302,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2816
3302
 
2817
3303
  <div class="ai-placeholder" *ngIf="!hasApiKey">
2818
3304
  <mat-icon>lock</mat-icon>
2819
- <span>Configure e teste sua chave de API para desbloquear a seleção de modelos.</span>
3305
+ <span>{{ tx('Configure and test your API key to unlock model selection.') }}</span>
2820
3306
  </div>
2821
3307
  </div>
2822
3308
 
@@ -2824,7 +3310,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2824
3310
  <div class="ai-group">
2825
3311
  <div class="ai-group-header">
2826
3312
  <div class="ai-group-title">
2827
- <mat-icon>scatter_plot</mat-icon> Embeddings (RAG)
3313
+ <mat-icon>scatter_plot</mat-icon> {{ tx('Embeddings (RAG)') }}
2828
3314
  </div>
2829
3315
  <div class="ai-header-actions">
2830
3316
  <button
@@ -2833,19 +3319,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2833
3319
  class="ai-action-btn"
2834
3320
  (click)="useLlmForEmbeddings()"
2835
3321
  [disabled]="!canUseLlmForEmbeddings"
2836
- matTooltip="Aplicar provedor e chave do LLM aos embeddings"
3322
+ [matTooltip]="tx('Use the LLM provider and key for embeddings')"
2837
3323
  >
2838
3324
  <mat-icon>merge_type</mat-icon>
2839
- <span class="ai-action-label">Usar mesmo LLM</span>
3325
+ <span class="ai-action-label">{{ tx('Use the LLM provider and key for embeddings') }}</span>
2840
3326
  </button>
2841
- <mat-chip-option *ngIf="!canUseLlmForEmbeddings" disabled>Provedor sem embeddings</mat-chip-option>
3327
+ <mat-chip-option *ngIf="!canUseLlmForEmbeddings" disabled>{{ tx('Provider has no embeddings') }}</mat-chip-option>
2842
3328
  </div>
2843
3329
  </div>
2844
3330
  <div class="ai-subtext">
2845
- Configure o provedor de embeddings para buscas vetoriais (templates e schemas).
3331
+ {{ tx('Configure the embeddings provider for vector search (templates and schemas).') }}
2846
3332
  </div>
2847
3333
  <div class="ai-subtext" *ngIf="embeddingUseSameAsLlm">
2848
- Sincronizado com o LLM. Os campos abaixo acompanham a credencial principal.
3334
+ {{ tx('Synchronized with the LLM. The fields below follow the primary credential.') }}
2849
3335
  </div>
2850
3336
  <div class="ai-embedding-row">
2851
3337
  <ng-template #hostAiEmbedding></ng-template>
@@ -2853,7 +3339,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2853
3339
  <div class="ai-feedback ai-feedback--warn" *ngIf="embeddingDimensionMismatch">
2854
3340
  <mat-icon>warning</mat-icon>
2855
3341
  <span class="error-text">
2856
- Dimensão de embeddings diferente do banco (768). Ajuste para 768 ou refaça a migração.
3342
+ {{ tx('Embedding dimension mismatch with database (768). Adjust to 768 or redo the migration.') }}
2857
3343
  </span>
2858
3344
  </div>
2859
3345
  </div>
@@ -2864,9 +3350,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2864
3350
  <mat-expansion-panel-header>
2865
3351
  <mat-panel-title>
2866
3352
  <mat-icon class="panel-icon">table_chart</mat-icon>
2867
- Tabela
3353
+ {{ tx('Table') }}
2868
3354
  </mat-panel-title>
2869
- <mat-panel-description>Toolbar, aparência e filtro avançado</mat-panel-description>
3355
+ <mat-panel-description>{{ tx('Toolbar, appearance and advanced filter') }}</mat-panel-description>
2870
3356
  </mat-expansion-panel-header>
2871
3357
  <ng-template #hostTable></ng-template>
2872
3358
  </mat-expansion-panel>
@@ -2874,27 +3360,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2874
3360
  <mat-expansion-panel-header>
2875
3361
  <mat-panel-title>
2876
3362
  <mat-icon class="panel-icon">forum</mat-icon>
2877
- Dialog
3363
+ {{ tx('Dialog') }}
2878
3364
  </mat-panel-title>
2879
- <mat-panel-description>Defaults e variants (danger, info, success, question, error)</mat-panel-description>
3365
+ <mat-panel-description>{{ tx('Defaults and variants (danger, info, success, question, error)') }}</mat-panel-description>
2880
3366
  </mat-expansion-panel-header>
2881
3367
  <ng-template #hostDialog></ng-template>
2882
3368
  <!-- Icon UX helpers for Dialog variants -->
2883
3369
  <div class="dlg-icon-helpers">
2884
- <div class="dlg-icon-helpers__head">Ícones por perfil (atalhos)</div>
3370
+ <div class="dlg-icon-helpers__head">{{ tx('Icons by profile (shortcuts)') }}</div>
2885
3371
  <div class="dlg-icon-helpers__row" *ngFor="let k of dialogVariantKeys">
2886
3372
  <div class="dlg-icon-helpers__label">{{ k }}</div>
2887
3373
  <mat-icon aria-hidden="true" [praxisIcon]="getVariantIcon(k) || 'mi:help_outline'" class="dlg-icon-helpers__preview"></mat-icon>
2888
- <button mat-stroked-button color="primary" type="button" (click)="pickVariantIcon(k)" matTooltip="Escolher ícone para {{k}}">
3374
+ <button mat-stroked-button color="primary" type="button" (click)="pickVariantIcon(k)" [matTooltip]="tx('Pick icon for {{key}}', { key: k })">
2889
3375
  <mat-icon>search</mat-icon>
2890
- Escolher ícone
3376
+ {{ tx('Pick icon') }}
2891
3377
  </button>
2892
- <button mat-icon-button type="button" *ngIf="getVariantIcon(k)" (click)="clearVariantIcon(k)" matTooltip="Limpar ícone de {{k}}" aria-label="Limpar ícone">
3378
+ <button mat-icon-button type="button" *ngIf="getVariantIcon(k)" (click)="clearVariantIcon(k)" [matTooltip]="tx('Clear icon for {{key}}', { key: k })" [attr.aria-label]="tx('Clear icon')">
2893
3379
  <mat-icon>backspace</mat-icon>
2894
3380
  </button>
2895
3381
  <span class="dlg-icon-helpers__value" *ngIf="getVariantIcon(k)">{{ getVariantIcon(k) }}</span>
2896
3382
  </div>
2897
- <div class="dlg-icon-helpers__hint">Dica: O campo de texto acima permanece editável. Estes botões apenas facilitam a escolha/limpeza com preview.</div>
3383
+ <div class="dlg-icon-helpers__hint">{{ tx('The text field above remains editable. These buttons only help with selection/clear preview.') }}</div>
2898
3384
  </div>
2899
3385
  </mat-expansion-panel>
2900
3386
  </mat-accordion>
@@ -2933,7 +3419,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2933
3419
  function openGlobalConfigEditor(settings, opts) {
2934
3420
  settings.open({
2935
3421
  id: opts?.id ?? 'global-config',
2936
- title: opts?.title ?? 'Configurações Globais',
3422
+ title: opts?.title,
2937
3423
  titleIcon: opts?.titleIcon ?? 'tune',
2938
3424
  content: { component: GlobalConfigEditorComponent, inputs: {} },
2939
3425
  });
@@ -2978,4 +3464,3 @@ const SETTINGS_PANEL_AI_CAPABILITIES = {
2978
3464
  */
2979
3465
 
2980
3466
  export { GLOBAL_CONFIG_DYNAMIC_FORM_COMPONENT, GlobalConfigAdminService, GlobalConfigEditorComponent, SETTINGS_PANEL_AI_CAPABILITIES, SETTINGS_PANEL_DATA, SETTINGS_PANEL_REF, SettingsPanelComponent, SettingsPanelRef, SettingsPanelService, buildGlobalConfigFormConfig, openGlobalConfigEditor, providePraxisSettingsPanelBridge };
2981
- //# sourceMappingURL=praxisui-settings-panel.mjs.map