@praxisui/stepper 3.0.0-beta.7 → 3.0.0-beta.8

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.
@@ -9,7 +9,7 @@ import * as i6 from '@angular/material/button';
9
9
  import { MatButtonModule } from '@angular/material/button';
10
10
  import * as i5$1 from '@angular/material/icon';
11
11
  import { MatIconModule } from '@angular/material/icon';
12
- import { IconPickerService, PraxisIconDirective, deepMerge, ASYNC_CONFIG_STORAGE, ComponentKeyService, LoggerService, DynamicWidgetLoaderDirective, EmptyStateCardComponent, EDITORIAL_WIDGET_TAG, ComponentMetadataRegistry, createCorporateLoggerConfig, ConsoleLoggerSink, CONFIG_STORAGE } from '@praxisui/core';
12
+ import { providePraxisI18n, PraxisI18nService, IconPickerService, PraxisIconDirective, deepMerge, ASYNC_CONFIG_STORAGE, ComponentKeyService, LoggerService, DynamicWidgetLoaderDirective, EmptyStateCardComponent, EDITORIAL_WIDGET_TAG, ComponentMetadataRegistry, createCorporateLoggerConfig, ConsoleLoggerSink, CONFIG_STORAGE } from '@praxisui/core';
13
13
  import * as i2 from '@angular/forms';
14
14
  import { FormsModule, ReactiveFormsModule } from '@angular/forms';
15
15
  import { PraxisDynamicFormConfigEditor, PraxisDynamicForm } from '@praxisui/dynamic-form';
@@ -508,7 +508,462 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
508
508
  args: [MAT_DIALOG_DATA]
509
509
  }] }] });
510
510
 
511
+ const PRAXIS_STEPPER_EN_US = {
512
+ 'praxis.stepper.editor.tabs.general': 'General',
513
+ 'praxis.stepper.editor.tabs.steps': 'Steps',
514
+ 'praxis.stepper.editor.general.eyebrow': 'Foundations',
515
+ 'praxis.stepper.editor.general.title': 'Define the base stepper behavior',
516
+ 'praxis.stepper.editor.general.subtitle': 'Adjust orientation, density, animation and utility classes without mixing structural decisions with advanced customization.',
517
+ 'praxis.stepper.editor.general.layoutTitle': 'Layout and navigation',
518
+ 'praxis.stepper.editor.general.layoutSubtitle': 'Controls how steps appear and how the user moves through the flow.',
519
+ 'praxis.stepper.editor.general.orientation': 'Orientation',
520
+ 'praxis.stepper.editor.general.orientation.horizontal': 'Horizontal',
521
+ 'praxis.stepper.editor.general.orientation.vertical': 'Vertical',
522
+ 'praxis.stepper.editor.general.headerPosition': 'Title position',
523
+ 'praxis.stepper.editor.general.headerPosition.top': 'Above',
524
+ 'praxis.stepper.editor.general.headerPosition.bottom': 'Below',
525
+ 'praxis.stepper.editor.general.labelPosition': 'Label position',
526
+ 'praxis.stepper.editor.general.labelPosition.end': 'Beside',
527
+ 'praxis.stepper.editor.general.labelPosition.bottom': 'Below',
528
+ 'praxis.stepper.editor.general.density': 'Density',
529
+ 'praxis.stepper.editor.general.density.default': 'Default',
530
+ 'praxis.stepper.editor.general.density.comfortable': 'Comfortable',
531
+ 'praxis.stepper.editor.general.density.compact': 'Compact',
532
+ 'praxis.stepper.editor.general.animationDuration': 'Animation duration',
533
+ 'praxis.stepper.editor.general.animationPlaceholder': 'e.g.: 300ms',
534
+ 'praxis.stepper.editor.general.initialStep': 'Initial step',
535
+ 'praxis.stepper.editor.general.linear': 'Respect order (linear)',
536
+ 'praxis.stepper.editor.general.disableRipple': 'Disable click effects',
537
+ 'praxis.stepper.editor.general.visualTitle': 'Classes and visual integration',
538
+ 'praxis.stepper.editor.general.visualSubtitle': 'Use only when you need to apply scoped CSS on the host.',
539
+ 'praxis.stepper.editor.general.stepperClass': 'Stepper class',
540
+ 'praxis.stepper.editor.general.stepperClassPlaceholder': 'e.g.: my-stepper',
541
+ 'praxis.stepper.editor.general.headerClass': 'Header class',
542
+ 'praxis.stepper.editor.general.headerClassPlaceholder': 'e.g.: stepper-header',
543
+ 'praxis.stepper.editor.general.contentClass': 'Content class',
544
+ 'praxis.stepper.editor.general.contentClassPlaceholder': 'e.g.: stepper-content',
545
+ 'praxis.stepper.editor.steps.eyebrow': 'Flow structure',
546
+ 'praxis.stepper.editor.steps.title': 'Define the narrative of each step',
547
+ 'praxis.stepper.editor.steps.subtitle': 'Organize titles, states and step content without mixing technical configuration with assembly actions.',
548
+ 'praxis.stepper.editor.steps.count': 'Steps',
549
+ 'praxis.stepper.editor.steps.mapTitle': 'Step map',
550
+ 'praxis.stepper.editor.steps.mapSubtitle': 'Drag to reorder and select a step to edit its content.',
551
+ 'praxis.stepper.editor.steps.add': 'Add step',
552
+ 'praxis.stepper.editor.steps.listAria': 'Step list',
553
+ 'praxis.stepper.editor.steps.stepN': 'Step {{index}}',
554
+ 'praxis.stepper.editor.steps.untitled': 'Untitled',
555
+ 'praxis.stepper.editor.steps.noId': 'No identifier',
556
+ 'praxis.stepper.editor.steps.optional': 'Optional',
557
+ 'praxis.stepper.editor.steps.completed': 'Completed',
558
+ 'praxis.stepper.editor.steps.error': 'Error',
559
+ 'praxis.stepper.editor.steps.form': 'Form',
560
+ 'praxis.stepper.editor.steps.remove': 'Remove',
561
+ 'praxis.stepper.editor.steps.removeAria': 'Remove step {{label}}',
562
+ 'praxis.stepper.editor.steps.selectedEyebrow': 'Selected step',
563
+ 'praxis.stepper.editor.steps.editing': 'Editing: {{label}}',
564
+ 'praxis.stepper.editor.steps.selectedSubtitle': 'Adjust the main content first. Secondary settings stay collapsed to reduce noise.',
565
+ 'praxis.stepper.editor.steps.mainData': 'Main data',
566
+ 'praxis.stepper.editor.steps.stepTitle': 'Step title',
567
+ 'praxis.stepper.editor.steps.identifier': 'Identifier',
568
+ 'praxis.stepper.editor.steps.iconOrState': 'Icon or state',
569
+ 'praxis.stepper.editor.steps.iconOrStatePlaceholder': 'e.g.: number, done, edit',
570
+ 'praxis.stepper.editor.steps.errorMessage': 'Error message',
571
+ 'praxis.stepper.editor.steps.optionalToggle': 'Optional step',
572
+ 'praxis.stepper.editor.steps.editableToggle': 'Allow going back and editing',
573
+ 'praxis.stepper.editor.steps.completedToggle': 'Mark as completed',
574
+ 'praxis.stepper.editor.steps.errorToggle': 'Mark as error',
575
+ 'praxis.stepper.editor.steps.accessibilityTitle': 'Accessibility and technical details',
576
+ 'praxis.stepper.editor.steps.accessibilitySubtitle': 'Auxiliary labels and less-used metadata.',
577
+ 'praxis.stepper.editor.steps.altText': 'Alternative text',
578
+ 'praxis.stepper.editor.steps.describedBy': 'Described-by ID',
579
+ 'praxis.stepper.editor.steps.editorialTitle': 'Editorial content',
580
+ 'praxis.stepper.editor.steps.editorialSubtitle': 'Use supporting blocks to contextualize the step before or after the form.',
581
+ 'praxis.stepper.editor.steps.zoneBefore': 'Before form',
582
+ 'praxis.stepper.editor.steps.zoneAfter': 'After form',
583
+ 'praxis.stepper.editor.steps.addBlock': 'Add',
584
+ 'praxis.stepper.editor.steps.widgetBenefits': 'Benefits grid',
585
+ 'praxis.stepper.editor.steps.widgetContent': 'Content block',
586
+ 'praxis.stepper.editor.steps.widgetNotice': 'Inline notice',
587
+ 'praxis.stepper.editor.steps.widgetDivider': 'Divider',
588
+ 'praxis.stepper.editor.steps.editBlock': 'Edit block',
589
+ 'praxis.stepper.editor.steps.moveAfter': 'Move after the form',
590
+ 'praxis.stepper.editor.steps.moveBefore': 'Move before the form',
591
+ 'praxis.stepper.editor.steps.duplicateBlock': 'Duplicate block',
592
+ 'praxis.stepper.editor.steps.removeBlock': 'Remove block',
593
+ 'praxis.stepper.editor.steps.emptyZone': 'No blocks in this zone.',
594
+ 'praxis.stepper.editor.steps.formSectionTitle': 'Step form',
595
+ 'praxis.stepper.editor.steps.mainFormTitle': 'Main form',
596
+ 'praxis.stepper.editor.steps.edit': 'Edit',
597
+ 'praxis.stepper.editor.steps.addForm': 'Add form',
598
+ 'praxis.stepper.editor.steps.advancedTitle': 'Advanced components',
599
+ 'praxis.stepper.editor.steps.advancedSubtitle': 'Shortcuts to assemble richer experiences without losing clarity in the flow.',
600
+ 'praxis.stepper.editor.steps.moreComponents': 'More components',
601
+ 'praxis.stepper.editor.steps.treeListTitle': 'Tree list',
602
+ 'praxis.stepper.editor.steps.treeListDesc': 'Hierarchical data with simple selection.',
603
+ 'praxis.stepper.editor.steps.insertTree': 'Insert tree',
604
+ 'praxis.stepper.editor.steps.transferTitle': 'Item transfer',
605
+ 'praxis.stepper.editor.steps.transferDesc': 'Move items between lists for multi-selection.',
606
+ 'praxis.stepper.editor.steps.insertTransfer': 'Insert transfer',
607
+ 'praxis.stepper.editor.steps.searchTitle': 'Searchable selection',
608
+ 'praxis.stepper.editor.steps.searchDesc': 'Selection with local or remote search.',
609
+ 'praxis.stepper.editor.steps.insertSelector': 'Insert selector',
610
+ 'praxis.stepper.editor.steps.uploadTitle': 'File upload',
611
+ 'praxis.stepper.editor.steps.uploadDesc': 'Attachments with validation and upload flow.',
612
+ 'praxis.stepper.editor.steps.insertUpload': 'Insert upload',
613
+ 'praxis.stepper.editor.steps.editComponent': 'Edit component',
614
+ 'praxis.stepper.editor.steps.removeComponent': 'Remove component',
615
+ 'praxis.stepper.editor.steps.emptyAdvanced': 'No advanced components added.',
616
+ 'praxis.stepper.editor.steps.noSteps': 'No steps defined.',
617
+ 'praxis.stepper.editor.navigation.tab': 'Navigation',
618
+ 'praxis.stepper.editor.navigation.eyebrow': 'Default actions',
619
+ 'praxis.stepper.editor.navigation.title': 'Configure navigation between steps',
620
+ 'praxis.stepper.editor.navigation.subtitle': 'Define when default buttons appear and how they present visually in the flow.',
621
+ 'praxis.stepper.editor.navigation.behaviorTitle': 'Button behavior',
622
+ 'praxis.stepper.editor.navigation.behaviorSubtitle': 'Appearance and alignment of the default stepper navigation.',
623
+ 'praxis.stepper.editor.navigation.visible': 'Show default navigation',
624
+ 'praxis.stepper.editor.navigation.variant': 'Button style',
625
+ 'praxis.stepper.editor.navigation.variant.default': 'Default (raised)',
626
+ 'praxis.stepper.editor.navigation.variant.basic': 'Text',
627
+ 'praxis.stepper.editor.navigation.variant.flat': 'Flat',
628
+ 'praxis.stepper.editor.navigation.variant.stroked': 'Stroked',
629
+ 'praxis.stepper.editor.navigation.variant.raised': 'Raised',
630
+ 'praxis.stepper.editor.navigation.color': 'Color',
631
+ 'praxis.stepper.editor.navigation.color.default': 'Default',
632
+ 'praxis.stepper.editor.navigation.color.primary': 'Primary',
633
+ 'praxis.stepper.editor.navigation.color.accent': 'Accent',
634
+ 'praxis.stepper.editor.navigation.color.warn': 'Warn',
635
+ 'praxis.stepper.editor.navigation.align': 'Alignment',
636
+ 'praxis.stepper.editor.navigation.align.default': 'Right',
637
+ 'praxis.stepper.editor.navigation.align.start': 'Left',
638
+ 'praxis.stepper.editor.navigation.align.center': 'Center',
639
+ 'praxis.stepper.editor.navigation.align.spaceBetween': 'Spaced',
640
+ 'praxis.stepper.editor.navigation.align.end': 'Right',
641
+ 'praxis.stepper.editor.navigation.labelsTitle': 'Labels and icons',
642
+ 'praxis.stepper.editor.navigation.labelsSubtitle': 'Adjust the copy and icons used in back and next actions.',
643
+ 'praxis.stepper.editor.navigation.prevLabel': 'Back button text',
644
+ 'praxis.stepper.editor.navigation.prevPlaceholder': 'e.g.: Back',
645
+ 'praxis.stepper.editor.navigation.nextLabel': 'Next button text',
646
+ 'praxis.stepper.editor.navigation.nextPlaceholder': 'e.g.: Next',
647
+ 'praxis.stepper.editor.navigation.prevIcon': 'Back icon',
648
+ 'praxis.stepper.editor.navigation.nextIcon': 'Next icon',
649
+ 'praxis.stepper.editor.navigation.pickPrevIcon': 'Choose the Back button icon',
650
+ 'praxis.stepper.editor.navigation.pickNextIcon': 'Choose the Next button icon',
651
+ 'praxis.stepper.editor.shared.pick': 'Choose',
652
+ 'praxis.stepper.editor.appearance.tab': 'Appearance',
653
+ 'praxis.stepper.editor.appearance.eyebrow': 'Visual theme',
654
+ 'praxis.stepper.editor.appearance.title': 'Customize appearance without losing consistency',
655
+ 'praxis.stepper.editor.appearance.subtitle': 'Start with the quick adjustments. Tokens and the SCSS snippet stay collapsed for advanced scenarios.',
656
+ 'praxis.stepper.editor.appearance.quickTitle': 'Quick adjustments',
657
+ 'praxis.stepper.editor.appearance.quickSubtitle': 'Most common controls for sizing, typography weight and theme.',
658
+ 'praxis.stepper.editor.appearance.headerHeight': 'Header height (px)',
659
+ 'praxis.stepper.editor.appearance.headerHeightPlaceholder': 'e.g.: 48',
660
+ 'praxis.stepper.editor.appearance.textSize': 'Text size (px)',
661
+ 'praxis.stepper.editor.appearance.textSizePlaceholder': 'e.g.: 14',
662
+ 'praxis.stepper.editor.appearance.textWeight': 'Text weight',
663
+ 'praxis.stepper.editor.appearance.textWeight.default': 'Default',
664
+ 'praxis.stepper.editor.appearance.textWeight.400': 'Normal',
665
+ 'praxis.stepper.editor.appearance.textWeight.500': 'Medium',
666
+ 'praxis.stepper.editor.appearance.textWeight.600': 'Semibold',
667
+ 'praxis.stepper.editor.appearance.textWeight.700': 'Bold',
668
+ 'praxis.stepper.editor.appearance.themeClass': 'Theme class',
669
+ 'praxis.stepper.editor.appearance.themeClassPlaceholder': 'e.g.: theme-stepper-custom',
670
+ 'praxis.stepper.editor.appearance.iconSet': 'Icon set',
671
+ 'praxis.stepper.editor.appearance.iconSet.default': 'Material Icons (default)',
672
+ 'praxis.stepper.editor.appearance.iconNumber': 'Number icon',
673
+ 'praxis.stepper.editor.appearance.pickIconNumber': 'Choose the number icon',
674
+ 'praxis.stepper.editor.appearance.iconDone': 'Completed icon',
675
+ 'praxis.stepper.editor.appearance.pickIconDone': 'Choose the completed icon',
676
+ 'praxis.stepper.editor.appearance.iconEdit': 'Edit icon',
677
+ 'praxis.stepper.editor.appearance.pickIconEdit': 'Choose the edit icon',
678
+ 'praxis.stepper.editor.appearance.iconError': 'Error icon',
679
+ 'praxis.stepper.editor.appearance.pickIconError': 'Choose the error icon',
680
+ 'praxis.stepper.editor.appearance.symbolsHint': 'Hint: {{icons}} are Material Symbols icons. Select a Symbols set below or click',
681
+ 'praxis.stepper.editor.appearance.useSymbols': 'Use Material Symbols (Outlined)',
682
+ 'praxis.stepper.editor.appearance.presetNeutral': 'Preset: neutral',
683
+ 'praxis.stepper.editor.appearance.presetPrimary': 'Preset: primary',
684
+ 'praxis.stepper.editor.appearance.presetHighContrast': 'Preset: high contrast',
685
+ 'praxis.stepper.editor.appearance.clearTokens': 'Clear tokens',
686
+ 'praxis.stepper.editor.appearance.advancedTitle': 'Advanced tokens and SCSS snippet',
687
+ 'praxis.stepper.editor.appearance.advancedSubtitle': 'Use when you need to go beyond quick adjustments and control the theme with more granularity.',
688
+ 'praxis.stepper.editor.appearance.tokenPlaceholder': 'CSS value or var(--token)',
689
+ 'praxis.stepper.editor.appearance.scssSnippet': 'SCSS snippet',
690
+ 'praxis.stepper.editor.dialog.configureStepForm': 'Configure Step Form',
691
+ 'praxis.stepper.editor.dialog.configureListSelection': 'Configure List (selection)',
692
+ 'praxis.stepper.editor.dialog.configureFilesUpload': 'Configure File Upload',
693
+ 'praxis.stepper.editor.dialog.addComponentToStep': 'Add component to step',
694
+ 'praxis.stepper.editor.dialog.configureTransfer': 'Configure Item Transfer',
695
+ 'praxis.stepper.editor.defaults.newStep': 'New step',
696
+ 'praxis.stepper.editor.defaults.selection': 'Selection',
697
+ 'praxis.stepper.editor.defaults.items': 'Items',
698
+ 'praxis.stepper.editor.defaults.newBenefit': 'New benefit',
699
+ 'praxis.stepper.editor.widgets.listSelection': 'List (selection)',
700
+ 'praxis.stepper.editor.widgets.searchableSelection': 'Searchable selection',
701
+ 'praxis.stepper.editor.widgets.fileUpload': 'File upload',
702
+ 'praxis.stepper.editor.widgets.form': 'Form',
703
+ 'praxis.stepper.editor.widgets.benefits': 'Benefits grid',
704
+ 'praxis.stepper.editor.widgets.content': 'Content block',
705
+ 'praxis.stepper.editor.widgets.notice': 'Inline notice',
706
+ 'praxis.stepper.editor.widgets.divider': 'Divider',
707
+ 'praxis.stepper.editor.widgets.default': 'Widget',
708
+ 'praxis.stepper.editor.summary.itemsColumns': '{{count}} item(s) • {{cols}} column(s)',
709
+ 'praxis.stepper.editor.summary.noContent': 'No content',
710
+ 'praxis.stepper.editor.summary.labelPrefix': 'Label: {{label}}',
711
+ 'praxis.stepper.editor.summary.dividerNoLabel': 'Divider without label',
712
+ 'praxis.stepper.editor.status.contentLegacy': 'Deprecated legacy: new authoring should prefer widget:rich-text-block. This block remains supported for compatibility in this cycle.',
713
+ 'praxis.stepper.editor.status.noticeCurrent': 'Kept in the current cycle: final semantics are still being defined between legal-notice and info-callout.',
714
+ 'praxis.stepper.editor.status.benefitsTemporary': 'Temporarily kept: still no canonical equivalent in the editorial backlog.',
715
+ 'praxis.stepper.editor.status.dividerTemporary': 'Temporarily kept: legacy separator without a prioritized shared equivalent.',
716
+ 'praxis.stepper.editor.status.editorialWidget': 'Wizard editorial widget.',
717
+ 'praxis.stepper.editor.tone.info': 'Informational',
718
+ 'praxis.stepper.editor.tone.warning': 'Warning',
719
+ 'praxis.stepper.editor.tone.neutral': 'Neutral',
720
+ };
721
+
722
+ const PRAXIS_STEPPER_PT_BR = {
723
+ 'praxis.stepper.editor.tabs.general': 'Geral',
724
+ 'praxis.stepper.editor.tabs.steps': 'Etapas',
725
+ 'praxis.stepper.editor.general.eyebrow': 'Fundamentos',
726
+ 'praxis.stepper.editor.general.title': 'Defina o comportamento base do stepper',
727
+ 'praxis.stepper.editor.general.subtitle': 'Ajuste orientacao, densidade, animacao e classes utilitarias sem misturar decisoes estruturais com customizacao avancada.',
728
+ 'praxis.stepper.editor.general.layoutTitle': 'Layout e navegacao',
729
+ 'praxis.stepper.editor.general.layoutSubtitle': 'Controla como as etapas aparecem e como o usuario percorre o fluxo.',
730
+ 'praxis.stepper.editor.general.orientation': 'Orientacao',
731
+ 'praxis.stepper.editor.general.orientation.horizontal': 'Horizontal',
732
+ 'praxis.stepper.editor.general.orientation.vertical': 'Vertical',
733
+ 'praxis.stepper.editor.general.headerPosition': 'Posicao dos titulos',
734
+ 'praxis.stepper.editor.general.headerPosition.top': 'Acima',
735
+ 'praxis.stepper.editor.general.headerPosition.bottom': 'Abaixo',
736
+ 'praxis.stepper.editor.general.labelPosition': 'Posicao do rotulo',
737
+ 'praxis.stepper.editor.general.labelPosition.end': 'Ao lado',
738
+ 'praxis.stepper.editor.general.labelPosition.bottom': 'Abaixo',
739
+ 'praxis.stepper.editor.general.density': 'Densidade',
740
+ 'praxis.stepper.editor.general.density.default': 'Padrao',
741
+ 'praxis.stepper.editor.general.density.comfortable': 'Confortavel',
742
+ 'praxis.stepper.editor.general.density.compact': 'Compacta',
743
+ 'praxis.stepper.editor.general.animationDuration': 'Duracao da animacao',
744
+ 'praxis.stepper.editor.general.animationPlaceholder': 'Ex.: 300ms',
745
+ 'praxis.stepper.editor.general.initialStep': 'Etapa inicial',
746
+ 'praxis.stepper.editor.general.linear': 'Respeitar ordem (linear)',
747
+ 'praxis.stepper.editor.general.disableRipple': 'Desativar efeitos de clique',
748
+ 'praxis.stepper.editor.general.visualTitle': 'Classes e integracao visual',
749
+ 'praxis.stepper.editor.general.visualSubtitle': 'Use apenas quando precisar aplicar CSS escopado no host.',
750
+ 'praxis.stepper.editor.general.stepperClass': 'Classe do stepper',
751
+ 'praxis.stepper.editor.general.stepperClassPlaceholder': 'Ex.: meu-stepper',
752
+ 'praxis.stepper.editor.general.headerClass': 'Classe do cabecalho',
753
+ 'praxis.stepper.editor.general.headerClassPlaceholder': 'Ex.: stepper-header',
754
+ 'praxis.stepper.editor.general.contentClass': 'Classe do conteudo',
755
+ 'praxis.stepper.editor.general.contentClassPlaceholder': 'Ex.: stepper-content',
756
+ 'praxis.stepper.editor.steps.eyebrow': 'Estrutura do fluxo',
757
+ 'praxis.stepper.editor.steps.title': 'Defina a narrativa de cada etapa',
758
+ 'praxis.stepper.editor.steps.subtitle': 'Organize titulos, estados e conteudo da etapa sem misturar configuracao tecnica com acoes de montagem.',
759
+ 'praxis.stepper.editor.steps.count': 'Etapas',
760
+ 'praxis.stepper.editor.steps.mapTitle': 'Mapa de etapas',
761
+ 'praxis.stepper.editor.steps.mapSubtitle': 'Arraste para reordenar e selecione uma etapa para editar o conteudo.',
762
+ 'praxis.stepper.editor.steps.add': 'Adicionar etapa',
763
+ 'praxis.stepper.editor.steps.listAria': 'Lista de etapas',
764
+ 'praxis.stepper.editor.steps.stepN': 'Etapa {{index}}',
765
+ 'praxis.stepper.editor.steps.untitled': 'Sem titulo',
766
+ 'praxis.stepper.editor.steps.noId': 'Sem identificador',
767
+ 'praxis.stepper.editor.steps.optional': 'Opcional',
768
+ 'praxis.stepper.editor.steps.completed': 'Concluida',
769
+ 'praxis.stepper.editor.steps.error': 'Erro',
770
+ 'praxis.stepper.editor.steps.form': 'Formulario',
771
+ 'praxis.stepper.editor.steps.remove': 'Remover',
772
+ 'praxis.stepper.editor.steps.removeAria': 'Remover etapa {{label}}',
773
+ 'praxis.stepper.editor.steps.selectedEyebrow': 'Etapa selecionada',
774
+ 'praxis.stepper.editor.steps.editing': 'Editando: {{label}}',
775
+ 'praxis.stepper.editor.steps.selectedSubtitle': 'Ajuste conteudo principal primeiro. Configuracoes secundarias ficam recolhidas para reduzir ruido.',
776
+ 'praxis.stepper.editor.steps.mainData': 'Dados principais',
777
+ 'praxis.stepper.editor.steps.stepTitle': 'Titulo da etapa',
778
+ 'praxis.stepper.editor.steps.identifier': 'Identificador',
779
+ 'praxis.stepper.editor.steps.iconOrState': 'Icone ou estado',
780
+ 'praxis.stepper.editor.steps.iconOrStatePlaceholder': 'Ex.: number, done, edit',
781
+ 'praxis.stepper.editor.steps.errorMessage': 'Mensagem de erro',
782
+ 'praxis.stepper.editor.steps.optionalToggle': 'Etapa opcional',
783
+ 'praxis.stepper.editor.steps.editableToggle': 'Permitir voltar e editar',
784
+ 'praxis.stepper.editor.steps.completedToggle': 'Marcar como concluida',
785
+ 'praxis.stepper.editor.steps.errorToggle': 'Marcar como com erro',
786
+ 'praxis.stepper.editor.steps.accessibilityTitle': 'Acessibilidade e detalhes tecnicos',
787
+ 'praxis.stepper.editor.steps.accessibilitySubtitle': 'Rotulos auxiliares e metadados menos usados.',
788
+ 'praxis.stepper.editor.steps.altText': 'Texto alternativo',
789
+ 'praxis.stepper.editor.steps.describedBy': 'ID que descreve',
790
+ 'praxis.stepper.editor.steps.editorialTitle': 'Conteudo editorial',
791
+ 'praxis.stepper.editor.steps.editorialSubtitle': 'Use blocos de apoio para contextualizar a etapa antes ou depois do formulario.',
792
+ 'praxis.stepper.editor.steps.zoneBefore': 'Antes do formulario',
793
+ 'praxis.stepper.editor.steps.zoneAfter': 'Depois do formulario',
794
+ 'praxis.stepper.editor.steps.addBlock': 'Adicionar',
795
+ 'praxis.stepper.editor.steps.widgetBenefits': 'Grade de beneficios',
796
+ 'praxis.stepper.editor.steps.widgetContent': 'Bloco de conteudo',
797
+ 'praxis.stepper.editor.steps.widgetNotice': 'Aviso inline',
798
+ 'praxis.stepper.editor.steps.widgetDivider': 'Divisor',
799
+ 'praxis.stepper.editor.steps.editBlock': 'Editar bloco',
800
+ 'praxis.stepper.editor.steps.moveAfter': 'Mover para depois do formulario',
801
+ 'praxis.stepper.editor.steps.moveBefore': 'Mover para antes do formulario',
802
+ 'praxis.stepper.editor.steps.duplicateBlock': 'Duplicar bloco',
803
+ 'praxis.stepper.editor.steps.removeBlock': 'Remover bloco',
804
+ 'praxis.stepper.editor.steps.emptyZone': 'Nenhum bloco nesta zona.',
805
+ 'praxis.stepper.editor.steps.formSectionTitle': 'Formulario da etapa',
806
+ 'praxis.stepper.editor.steps.mainFormTitle': 'Formulario principal',
807
+ 'praxis.stepper.editor.steps.edit': 'Editar',
808
+ 'praxis.stepper.editor.steps.addForm': 'Adicionar formulario',
809
+ 'praxis.stepper.editor.steps.advancedTitle': 'Componentes avancados',
810
+ 'praxis.stepper.editor.steps.advancedSubtitle': 'Atalhos para montar experiencias mais ricas sem perder clareza no fluxo.',
811
+ 'praxis.stepper.editor.steps.moreComponents': 'Mais componentes',
812
+ 'praxis.stepper.editor.steps.treeListTitle': 'Lista em arvore',
813
+ 'praxis.stepper.editor.steps.treeListDesc': 'Dados hierarquicos com selecao simples.',
814
+ 'praxis.stepper.editor.steps.insertTree': 'Inserir arvore',
815
+ 'praxis.stepper.editor.steps.transferTitle': 'Transferencia de itens',
816
+ 'praxis.stepper.editor.steps.transferDesc': 'Mover itens entre listas para selecao multipla.',
817
+ 'praxis.stepper.editor.steps.insertTransfer': 'Inserir transferencia',
818
+ 'praxis.stepper.editor.steps.searchTitle': 'Selecao com busca',
819
+ 'praxis.stepper.editor.steps.searchDesc': 'Selecao com busca local ou remota.',
820
+ 'praxis.stepper.editor.steps.insertSelector': 'Inserir seletor',
821
+ 'praxis.stepper.editor.steps.uploadTitle': 'Upload de arquivos',
822
+ 'praxis.stepper.editor.steps.uploadDesc': 'Anexos com validacao e fluxo de upload.',
823
+ 'praxis.stepper.editor.steps.insertUpload': 'Inserir upload',
824
+ 'praxis.stepper.editor.steps.editComponent': 'Editar componente',
825
+ 'praxis.stepper.editor.steps.removeComponent': 'Remover componente',
826
+ 'praxis.stepper.editor.steps.emptyAdvanced': 'Nenhum componente avancado adicionado.',
827
+ 'praxis.stepper.editor.steps.noSteps': 'Nenhuma etapa definida.',
828
+ 'praxis.stepper.editor.navigation.tab': 'Navegacao',
829
+ 'praxis.stepper.editor.navigation.eyebrow': 'Acoes padrao',
830
+ 'praxis.stepper.editor.navigation.title': 'Configure a navegacao entre etapas',
831
+ 'praxis.stepper.editor.navigation.subtitle': 'Defina quando os botoes padrao aparecem e como eles se apresentam visualmente no fluxo.',
832
+ 'praxis.stepper.editor.navigation.behaviorTitle': 'Comportamento dos botoes',
833
+ 'praxis.stepper.editor.navigation.behaviorSubtitle': 'Aparencia e alinhamento da navegacao padrao do stepper.',
834
+ 'praxis.stepper.editor.navigation.visible': 'Mostrar navegacao padrao',
835
+ 'praxis.stepper.editor.navigation.variant': 'Estilo dos botoes',
836
+ 'praxis.stepper.editor.navigation.variant.default': 'Padrao (elevado)',
837
+ 'praxis.stepper.editor.navigation.variant.basic': 'Texto',
838
+ 'praxis.stepper.editor.navigation.variant.flat': 'Plano',
839
+ 'praxis.stepper.editor.navigation.variant.stroked': 'Contornado',
840
+ 'praxis.stepper.editor.navigation.variant.raised': 'Elevado',
841
+ 'praxis.stepper.editor.navigation.color': 'Cor',
842
+ 'praxis.stepper.editor.navigation.color.default': 'Padrao',
843
+ 'praxis.stepper.editor.navigation.color.primary': 'Primaria',
844
+ 'praxis.stepper.editor.navigation.color.accent': 'Acento',
845
+ 'praxis.stepper.editor.navigation.color.warn': 'Alerta',
846
+ 'praxis.stepper.editor.navigation.align': 'Alinhamento',
847
+ 'praxis.stepper.editor.navigation.align.default': 'Direita',
848
+ 'praxis.stepper.editor.navigation.align.start': 'Esquerda',
849
+ 'praxis.stepper.editor.navigation.align.center': 'Centro',
850
+ 'praxis.stepper.editor.navigation.align.spaceBetween': 'Espacado',
851
+ 'praxis.stepper.editor.navigation.align.end': 'Direita',
852
+ 'praxis.stepper.editor.navigation.labelsTitle': 'Rotulos e icones',
853
+ 'praxis.stepper.editor.navigation.labelsSubtitle': 'Ajuste a copia e os icones usados nas acoes de voltar e avancar.',
854
+ 'praxis.stepper.editor.navigation.prevLabel': 'Texto do botao Voltar',
855
+ 'praxis.stepper.editor.navigation.prevPlaceholder': 'Ex.: Voltar',
856
+ 'praxis.stepper.editor.navigation.nextLabel': 'Texto do botao Proximo',
857
+ 'praxis.stepper.editor.navigation.nextPlaceholder': 'Ex.: Proximo',
858
+ 'praxis.stepper.editor.navigation.prevIcon': 'Icone de Voltar',
859
+ 'praxis.stepper.editor.navigation.nextIcon': 'Icone de Proximo',
860
+ 'praxis.stepper.editor.navigation.pickPrevIcon': 'Escolher icone do botao Voltar',
861
+ 'praxis.stepper.editor.navigation.pickNextIcon': 'Escolher icone do botao Proximo',
862
+ 'praxis.stepper.editor.shared.pick': 'Escolher',
863
+ 'praxis.stepper.editor.appearance.tab': 'Aparencia',
864
+ 'praxis.stepper.editor.appearance.eyebrow': 'Tema visual',
865
+ 'praxis.stepper.editor.appearance.title': 'Personalize a aparencia sem perder consistencia',
866
+ 'praxis.stepper.editor.appearance.subtitle': 'Comece pelos ajustes rapidos. Tokens e snippet SCSS ficam recolhidos para cenarios avancados.',
867
+ 'praxis.stepper.editor.appearance.quickTitle': 'Ajustes rapidos',
868
+ 'praxis.stepper.editor.appearance.quickSubtitle': 'Controles mais comuns para tamanho, peso tipografico e tema.',
869
+ 'praxis.stepper.editor.appearance.headerHeight': 'Altura do cabecalho (px)',
870
+ 'praxis.stepper.editor.appearance.headerHeightPlaceholder': 'Ex.: 48',
871
+ 'praxis.stepper.editor.appearance.textSize': 'Tamanho do texto (px)',
872
+ 'praxis.stepper.editor.appearance.textSizePlaceholder': 'Ex.: 14',
873
+ 'praxis.stepper.editor.appearance.textWeight': 'Peso do texto',
874
+ 'praxis.stepper.editor.appearance.textWeight.default': 'Padrao',
875
+ 'praxis.stepper.editor.appearance.textWeight.400': 'Normal',
876
+ 'praxis.stepper.editor.appearance.textWeight.500': 'Medio',
877
+ 'praxis.stepper.editor.appearance.textWeight.600': 'Seminegrito',
878
+ 'praxis.stepper.editor.appearance.textWeight.700': 'Negrito',
879
+ 'praxis.stepper.editor.appearance.themeClass': 'Classe de tema',
880
+ 'praxis.stepper.editor.appearance.themeClassPlaceholder': 'Ex.: theme-stepper-custom',
881
+ 'praxis.stepper.editor.appearance.iconSet': 'Conjunto de icones',
882
+ 'praxis.stepper.editor.appearance.iconSet.default': 'Material Icons (padrao)',
883
+ 'praxis.stepper.editor.appearance.iconNumber': 'Icone do numero',
884
+ 'praxis.stepper.editor.appearance.pickIconNumber': 'Escolher icone do numero',
885
+ 'praxis.stepper.editor.appearance.iconDone': 'Icone concluido',
886
+ 'praxis.stepper.editor.appearance.pickIconDone': 'Escolher icone de concluido',
887
+ 'praxis.stepper.editor.appearance.iconEdit': 'Icone de edicao',
888
+ 'praxis.stepper.editor.appearance.pickIconEdit': 'Escolher icone de edicao',
889
+ 'praxis.stepper.editor.appearance.iconError': 'Icone de erro',
890
+ 'praxis.stepper.editor.appearance.pickIconError': 'Escolher icone de erro',
891
+ 'praxis.stepper.editor.appearance.symbolsHint': 'Dica: {{icons}} sao icones do Material Symbols. Selecione um conjunto Symbols abaixo ou clique em',
892
+ 'praxis.stepper.editor.appearance.useSymbols': 'Usar Material Symbols (Outlined)',
893
+ 'praxis.stepper.editor.appearance.presetNeutral': 'Preset: neutro',
894
+ 'praxis.stepper.editor.appearance.presetPrimary': 'Preset: primario',
895
+ 'praxis.stepper.editor.appearance.presetHighContrast': 'Preset: alto contraste',
896
+ 'praxis.stepper.editor.appearance.clearTokens': 'Limpar tokens',
897
+ 'praxis.stepper.editor.appearance.advancedTitle': 'Tokens avancados e snippet SCSS',
898
+ 'praxis.stepper.editor.appearance.advancedSubtitle': 'Use quando precisar sair do ajuste rapido e controlar o tema com granularidade.',
899
+ 'praxis.stepper.editor.appearance.tokenPlaceholder': 'valor CSS ou var(--token)',
900
+ 'praxis.stepper.editor.appearance.scssSnippet': 'Snippet SCSS',
901
+ 'praxis.stepper.editor.dialog.configureStepForm': 'Configurar Formulario da Etapa',
902
+ 'praxis.stepper.editor.dialog.configureListSelection': 'Configurar Lista (selecao)',
903
+ 'praxis.stepper.editor.dialog.configureFilesUpload': 'Configurar Upload de Arquivos',
904
+ 'praxis.stepper.editor.dialog.addComponentToStep': 'Adicionar componente a etapa',
905
+ 'praxis.stepper.editor.dialog.configureTransfer': 'Configurar Transferencia de Itens',
906
+ 'praxis.stepper.editor.defaults.newStep': 'Novo passo',
907
+ 'praxis.stepper.editor.defaults.selection': 'Selecao',
908
+ 'praxis.stepper.editor.defaults.items': 'Itens',
909
+ 'praxis.stepper.editor.defaults.newBenefit': 'Novo beneficio',
910
+ 'praxis.stepper.editor.widgets.listSelection': 'Lista (selecao)',
911
+ 'praxis.stepper.editor.widgets.searchableSelection': 'Selecao com busca',
912
+ 'praxis.stepper.editor.widgets.fileUpload': 'Upload de arquivos',
913
+ 'praxis.stepper.editor.widgets.form': 'Formulario',
914
+ 'praxis.stepper.editor.widgets.benefits': 'Grade de beneficios',
915
+ 'praxis.stepper.editor.widgets.content': 'Bloco de conteudo',
916
+ 'praxis.stepper.editor.widgets.notice': 'Aviso inline',
917
+ 'praxis.stepper.editor.widgets.divider': 'Divisor',
918
+ 'praxis.stepper.editor.widgets.default': 'Widget',
919
+ 'praxis.stepper.editor.summary.itemsColumns': '{{count}} item(ns) • {{cols}} coluna(s)',
920
+ 'praxis.stepper.editor.summary.noContent': 'Sem conteudo',
921
+ 'praxis.stepper.editor.summary.labelPrefix': 'Rotulo: {{label}}',
922
+ 'praxis.stepper.editor.summary.dividerNoLabel': 'Divisor sem rotulo',
923
+ 'praxis.stepper.editor.status.contentLegacy': 'Legado em deprecacao: novo authoring deve preferir widget:rich-text-block. O bloco continua suportado por compatibilidade neste ciclo.',
924
+ 'praxis.stepper.editor.status.noticeCurrent': 'Mantido no ciclo atual: semantica final ainda em definicao entre legal-notice e info-callout.',
925
+ 'praxis.stepper.editor.status.benefitsTemporary': 'Mantido temporariamente: ainda sem equivalente canonico no backlog editorial.',
926
+ 'praxis.stepper.editor.status.dividerTemporary': 'Mantido temporariamente: separador legado sem equivalente compartilhado priorizado.',
927
+ 'praxis.stepper.editor.status.editorialWidget': 'Widget editorial do wizard.',
928
+ 'praxis.stepper.editor.tone.info': 'Informativo',
929
+ 'praxis.stepper.editor.tone.warning': 'Atencao',
930
+ 'praxis.stepper.editor.tone.neutral': 'Neutro',
931
+ };
932
+
933
+ function createPraxisStepperI18nConfig(options = {}) {
934
+ const dictionaries = {
935
+ 'pt-BR': {
936
+ ...PRAXIS_STEPPER_PT_BR,
937
+ ...(options.dictionaries?.['pt-BR'] ?? {}),
938
+ },
939
+ 'en-US': {
940
+ ...PRAXIS_STEPPER_EN_US,
941
+ ...(options.dictionaries?.['en-US'] ?? {}),
942
+ },
943
+ };
944
+ for (const [locale, dictionary] of Object.entries(options.dictionaries ?? {})) {
945
+ if (locale === 'pt-BR' || locale === 'en-US')
946
+ continue;
947
+ dictionaries[locale] = { ...(dictionaries[locale] ?? {}), ...dictionary };
948
+ }
949
+ return {
950
+ locale: options.locale,
951
+ fallbackLocale: options.fallbackLocale ?? 'pt-BR',
952
+ dictionaries,
953
+ };
954
+ }
955
+ function providePraxisStepperI18n(options = {}) {
956
+ return providePraxisI18n(createPraxisStepperI18nConfig(options));
957
+ }
958
+ function resolvePraxisStepperText(i18n, key, fallback) {
959
+ const namespacedKey = key.startsWith('praxis.stepper.')
960
+ ? key
961
+ : `praxis.stepper.${key}`;
962
+ return i18n.t(namespacedKey, undefined, fallback) || fallback;
963
+ }
964
+
511
965
  class PraxisStepperConfigEditor {
966
+ i18n = inject(PraxisI18nService);
512
967
  config = { steps: [], orientation: 'horizontal', headerPosition: 'top', linear: false };
513
968
  activeStepRef = null;
514
969
  // SettingsValueProvider observables
@@ -538,11 +993,23 @@ class PraxisStepperConfigEditor {
538
993
  }
539
994
  }
540
995
  else {
541
- this.config.steps = [{ id: 'step1', label: 'Novo passo' }];
996
+ this.config.steps = [{ id: 'step1', label: this.tx('editor.defaults.newStep', 'New step') }];
542
997
  this.isDirty$.next(true);
543
998
  }
544
999
  this.ensureActiveStep();
545
1000
  }
1001
+ tx(key, fallback) {
1002
+ return resolvePraxisStepperText(this.i18n, key, fallback);
1003
+ }
1004
+ stepIndexLabel(index) {
1005
+ return this.tx('editor.steps.stepN', 'Step {{index}}').replace('{{index}}', `${index + 1}`);
1006
+ }
1007
+ stepRemoveAria(step, index) {
1008
+ return this.tx('editor.steps.removeAria', 'Remove step {{label}}').replace('{{label}}', `${step.label || index + 1}`);
1009
+ }
1010
+ editingStepTitle(step) {
1011
+ return this.tx('editor.steps.editing', 'Editing: {{label}}').replace('{{label}}', `${step.label || ''}`);
1012
+ }
546
1013
  markDirty() { this.isDirty$.next(true); this.validate(); }
547
1014
  validate() {
548
1015
  const valid = Array.isArray(this.config.steps) && this.config.steps.every(s => !!s.label);
@@ -805,15 +1272,15 @@ class PraxisStepperConfigEditor {
805
1272
  s.widgetsBeforeForm = []; return s.widgetsBeforeForm; }
806
1273
  displayWidgetName(w) {
807
1274
  switch (w.id) {
808
- case 'praxis-list': return 'Lista (seleção)';
809
- case 'pdx-material-searchable-select': return 'Seleção com busca';
810
- case 'praxis-files-upload': return 'Upload de arquivos';
811
- case 'praxis-dynamic-form': return 'Formulário';
812
- case 'praxis-wizard-benefits': return 'Grade de benefícios';
813
- case 'praxis-wizard-content': return 'Bloco de conteúdo';
814
- case 'praxis-wizard-inline-notice': return 'Aviso inline';
815
- case 'praxis-wizard-divider': return 'Divisor';
816
- default: return w.inputs?.title || w.inputs?.label || 'Widget';
1275
+ case 'praxis-list': return this.tx('editor.widgets.listSelection', 'List (selection)');
1276
+ case 'pdx-material-searchable-select': return this.tx('editor.widgets.searchableSelection', 'Searchable selection');
1277
+ case 'praxis-files-upload': return this.tx('editor.widgets.fileUpload', 'File upload');
1278
+ case 'praxis-dynamic-form': return this.tx('editor.widgets.form', 'Form');
1279
+ case 'praxis-wizard-benefits': return this.tx('editor.widgets.benefits', 'Benefits grid');
1280
+ case 'praxis-wizard-content': return this.tx('editor.widgets.content', 'Content block');
1281
+ case 'praxis-wizard-inline-notice': return this.tx('editor.widgets.notice', 'Inline notice');
1282
+ case 'praxis-wizard-divider': return this.tx('editor.widgets.divider', 'Divider');
1283
+ default: return w.inputs?.title || w.inputs?.label || this.tx('editor.widgets.default', 'Widget');
817
1284
  }
818
1285
  }
819
1286
  editorialBeforeWidgets(step) {
@@ -835,17 +1302,19 @@ class PraxisStepperConfigEditor {
835
1302
  const text = (value || '').trim();
836
1303
  if (!text)
837
1304
  return '';
838
- return text.length > max ? `${text.slice(0, max - 1)}…` : text;
1305
+ return text.length > max ? `${text.slice(0, max - 3)}...` : text;
839
1306
  };
840
1307
  switch (w.id) {
841
1308
  case 'praxis-wizard-benefits': {
842
1309
  const count = Array.isArray(inputs.items) ? inputs.items.length : 0;
843
1310
  const cols = Number.isFinite(Number(inputs.columns)) ? Number(inputs.columns) : 4;
844
- return `${count} item(ns) • ${cols} coluna(s)`;
1311
+ return this.tx('editor.summary.itemsColumns', '{{count}} item(s) • {{cols}} column(s)')
1312
+ .replace('{{count}}', `${count}`)
1313
+ .replace('{{cols}}', `${cols}`);
845
1314
  }
846
1315
  case 'praxis-wizard-content': {
847
1316
  const text = shorten(inputs.title || inputs.subtitle || inputs.text || inputs.caption, 90);
848
- return text || 'Sem conteúdo';
1317
+ return text || this.tx('editor.summary.noContent', 'No content');
849
1318
  }
850
1319
  case 'praxis-wizard-inline-notice': {
851
1320
  const tone = this.toneLabel(inputs.tone);
@@ -853,7 +1322,9 @@ class PraxisStepperConfigEditor {
853
1322
  return text ? `${tone} • ${text}` : tone;
854
1323
  }
855
1324
  case 'praxis-wizard-divider':
856
- return inputs.label ? `Rótulo: ${inputs.label}` : 'Divisor sem rótulo';
1325
+ return inputs.label
1326
+ ? this.tx('editor.summary.labelPrefix', 'Label: {{label}}').replace('{{label}}', inputs.label)
1327
+ : this.tx('editor.summary.dividerNoLabel', 'Divider without label');
857
1328
  default:
858
1329
  return '';
859
1330
  }
@@ -861,15 +1332,15 @@ class PraxisStepperConfigEditor {
861
1332
  editorialWidgetStatus(w) {
862
1333
  switch (w.id) {
863
1334
  case 'praxis-wizard-content':
864
- return 'Legado em deprecação: novo authoring deve preferir widget:rich-text-block. O bloco continua suportado por compatibilidade neste ciclo.';
1335
+ return this.tx('editor.status.contentLegacy', 'Deprecated legacy: new authoring should prefer widget:rich-text-block. This block remains supported for compatibility in this cycle.');
865
1336
  case 'praxis-wizard-inline-notice':
866
- return 'Mantido no ciclo atual: semântica final ainda em definição entre legal-notice e info-callout.';
1337
+ return this.tx('editor.status.noticeCurrent', 'Kept in the current cycle: final semantics are still being defined between legal-notice and info-callout.');
867
1338
  case 'praxis-wizard-benefits':
868
- return 'Mantido temporariamente: ainda sem equivalente canônico no backlog editorial.';
1339
+ return this.tx('editor.status.benefitsTemporary', 'Temporarily kept: still no canonical equivalent in the editorial backlog.');
869
1340
  case 'praxis-wizard-divider':
870
- return 'Mantido temporariamente: separador legado sem equivalente compartilhado priorizado.';
1341
+ return this.tx('editor.status.dividerTemporary', 'Temporarily kept: legacy separator without a prioritized shared equivalent.');
871
1342
  default:
872
- return 'Widget editorial do wizard.';
1343
+ return this.tx('editor.status.editorialWidget', 'Wizard editorial widget.');
873
1344
  }
874
1345
  }
875
1346
  addEditorialWidget(id, zone = 'before') {
@@ -976,7 +1447,7 @@ class PraxisStepperConfigEditor {
976
1447
  title: '',
977
1448
  columns: 4,
978
1449
  boxed: true,
979
- items: [{ icon: '', title: 'Novo benefício', text: '' }],
1450
+ items: [{ icon: '', title: this.tx('editor.defaults.newBenefit', 'New benefit'), text: '' }],
980
1451
  };
981
1452
  case 'praxis-wizard-content':
982
1453
  return {
@@ -1036,9 +1507,9 @@ class PraxisStepperConfigEditor {
1036
1507
  }
1037
1508
  toneLabel(value) {
1038
1509
  switch (value) {
1039
- case 'info': return 'Informativo';
1040
- case 'warning': return 'Atenção';
1041
- default: return 'Neutro';
1510
+ case 'info': return this.tx('editor.tone.info', 'Informational');
1511
+ case 'warning': return this.tx('editor.tone.warning', 'Warning');
1512
+ default: return this.tx('editor.tone.neutral', 'Neutral');
1042
1513
  }
1043
1514
  }
1044
1515
  reorderSubset(list, pick, fromSubsetIndex, toSubsetIndex) {
@@ -1062,7 +1533,7 @@ class PraxisStepperConfigEditor {
1062
1533
  const step = this.activeStep;
1063
1534
  if (!step)
1064
1535
  return;
1065
- const ref = this.settings.open({ id: `stepper:form:${step.id || this.activeIndex}`, title: 'Configurar Formulário da Etapa', content: { component: PraxisDynamicFormConfigEditor, inputs: { formConfig: step.form?.config || { sections: [] }, formId: step.form?.formId || step.id, mode: step.form?.mode || 'create' } } });
1536
+ const ref = this.settings.open({ id: `stepper:form:${step.id || this.activeIndex}`, title: this.tx('editor.dialog.configureStepForm', 'Configure Step Form'), content: { component: PraxisDynamicFormConfigEditor, inputs: { formConfig: step.form?.config || { sections: [] }, formId: step.form?.formId || step.id, mode: step.form?.mode || 'create' } } });
1066
1537
  const apply = (val) => {
1067
1538
  const v = val || {};
1068
1539
  step.form = {
@@ -1086,7 +1557,7 @@ class PraxisStepperConfigEditor {
1086
1557
  const current = { ...(this.ensureWidgets().find(w => w.id === 'praxis-list')?.inputs?.config || {}) };
1087
1558
  // Ensure minimal selection setup
1088
1559
  current.selection = current.selection || { mode: 'single', return: 'value' };
1089
- const ref = this.settings.open({ id: `stepper:list:${step.id || this.activeIndex}`, title: 'Configurar Lista (seleção)', content: { component: PraxisListConfigEditor, inputs: { config: current, listId: step.id || 'list' } } });
1560
+ const ref = this.settings.open({ id: `stepper:list:${step.id || this.activeIndex}`, title: this.tx('editor.dialog.configureListSelection', 'Configure List (selection)'), content: { component: PraxisListConfigEditor, inputs: { config: current, listId: step.id || 'list' } } });
1090
1561
  const apply = (val) => {
1091
1562
  const cfg = (val && (val.config || val)) || current;
1092
1563
  const wd = { id: 'praxis-list', inputs: { config: cfg, listId: `${step.id || 'step'}-list-${Date.now()}` } };
@@ -1107,7 +1578,7 @@ class PraxisStepperConfigEditor {
1107
1578
  return;
1108
1579
  const meta = {
1109
1580
  name: res.name || 'selection',
1110
- label: res.label || 'Seleção',
1581
+ label: res.label || this.tx('editor.defaults.selection', 'Selection'),
1111
1582
  required: !!res.required,
1112
1583
  searchable: true,
1113
1584
  multiple: !!res.multiple,
@@ -1125,7 +1596,7 @@ class PraxisStepperConfigEditor {
1125
1596
  const step = this.activeStep;
1126
1597
  if (!step)
1127
1598
  return;
1128
- const ref = this.settings.open({ id: `stepper:upload:${step.id || this.activeIndex}`, title: 'Configurar Upload de Arquivos', content: { component: PraxisFilesUploadConfigEditor, inputs: {} } });
1599
+ const ref = this.settings.open({ id: `stepper:upload:${step.id || this.activeIndex}`, title: this.tx('editor.dialog.configureFilesUpload', 'Configure File Upload'), content: { component: PraxisFilesUploadConfigEditor, inputs: {} } });
1129
1600
  const apply = (cfg) => {
1130
1601
  const wd = { id: 'praxis-files-upload', inputs: { config: cfg, filesUploadId: `${step.id || 'step'}-upload-${Date.now()}` } };
1131
1602
  this.ensureWidgets().push(wd);
@@ -1135,7 +1606,7 @@ class PraxisStepperConfigEditor {
1135
1606
  ref.saved$.subscribe(apply);
1136
1607
  }
1137
1608
  openMoreComponents() {
1138
- const dlg = this.dialog.open(ComponentPaletteDialogComponent, { width: '560px', data: { title: 'Adicionar componente à etapa', allowedWidgetIds: ['praxis-dynamic-form', 'praxis-list', 'pdx-material-searchable-select', 'praxis-files-upload'] } });
1609
+ const dlg = this.dialog.open(ComponentPaletteDialogComponent, { width: '560px', data: { title: this.tx('editor.dialog.addComponentToStep', 'Add component to step'), allowedWidgetIds: ['praxis-dynamic-form', 'praxis-list', 'pdx-material-searchable-select', 'praxis-files-upload'] } });
1139
1610
  dlg.afterClosed().subscribe((id) => {
1140
1611
  if (!id)
1141
1612
  return;
@@ -1176,10 +1647,10 @@ class PraxisStepperConfigEditor {
1176
1647
  // Seed a simple form with a transfer list field
1177
1648
  const formConfig = {
1178
1649
  sections: [
1179
- { rows: [[{ name: 'items', label: 'Itens', controlType: 'TRANSFER_LIST', transferOptions: { source: [], target: [] } }]] }
1650
+ { rows: [[{ name: 'items', label: this.tx('editor.defaults.items', 'Items'), controlType: 'TRANSFER_LIST', transferOptions: { source: [], target: [] } }]] }
1180
1651
  ]
1181
1652
  };
1182
- const ref = this.settings.open({ id: `stepper:transfer:${step.id || this.activeIndex}`, title: 'Configurar Transferência de Itens', content: { component: PraxisDynamicFormConfigEditor, inputs: { formConfig, formId: step.id || 'transfer' } } });
1653
+ const ref = this.settings.open({ id: `stepper:transfer:${step.id || this.activeIndex}`, title: this.tx('editor.dialog.configureTransfer', 'Configure Item Transfer'), content: { component: PraxisDynamicFormConfigEditor, inputs: { formConfig, formId: step.id || 'transfer' } } });
1183
1654
  const apply = (val) => {
1184
1655
  const v = val || {};
1185
1656
  step.form = { config: v.formConfig || formConfig, formId: v?.formId || step.id, mode: v?.inputsPatch?.mode || 'create' };
@@ -1199,7 +1670,7 @@ class PraxisStepperConfigEditor {
1199
1670
  const step = this.activeStep;
1200
1671
  if (!step)
1201
1672
  return;
1202
- const ref = this.settings.open({ id: `stepper:list:${step.id || this.activeIndex}`, title: 'Configurar Lista (seleção)', content: { component: PraxisListConfigEditor, inputs: { config: cfg, listId: step.id || 'list' } } });
1673
+ const ref = this.settings.open({ id: `stepper:list:${step.id || this.activeIndex}`, title: this.tx('editor.dialog.configureListSelection', 'Configure List (selection)'), content: { component: PraxisListConfigEditor, inputs: { config: cfg, listId: step.id || 'list' } } });
1203
1674
  const apply = (val) => {
1204
1675
  const next = (val && (val.config || val)) || cfg;
1205
1676
  w.inputs = { ...(w.inputs || {}), config: next };
@@ -1223,7 +1694,7 @@ class PraxisStepperConfigEditor {
1223
1694
  }
1224
1695
  case 'praxis-files-upload': {
1225
1696
  const cfg = w.inputs?.config || {};
1226
- const ref = this.settings.open({ id: `stepper:upload:edit`, title: 'Configurar Upload de Arquivos', content: { component: PraxisFilesUploadConfigEditor, inputs: { ...cfg } } });
1697
+ const ref = this.settings.open({ id: `stepper:upload:edit`, title: this.tx('editor.dialog.configureFilesUpload', 'Configure File Upload'), content: { component: PraxisFilesUploadConfigEditor, inputs: { ...cfg } } });
1227
1698
  const apply = (val) => { w.inputs = { ...(w.inputs || {}), config: val }; this.markDirty(); };
1228
1699
  ref.applied$.subscribe(apply);
1229
1700
  ref.saved$.subscribe(apply);
@@ -1282,101 +1753,101 @@ class PraxisStepperConfigEditor {
1282
1753
  }
1283
1754
  }
1284
1755
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisStepperConfigEditor, deps: [{ token: SETTINGS_PANEL_DATA }], target: i0.ɵɵFactoryTarget.Component });
1285
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: PraxisStepperConfigEditor, isStandalone: true, selector: "praxis-stepper-config-editor", ngImport: i0, template: `
1756
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: PraxisStepperConfigEditor, isStandalone: true, selector: "praxis-stepper-config-editor", providers: [providePraxisStepperI18n()], ngImport: i0, template: `
1286
1757
  <div class="pdx-editor">
1287
1758
  <mat-tab-group>
1288
- <mat-tab label="Geral">
1759
+ <mat-tab [label]="tx('editor.tabs.general', 'General')">
1289
1760
  <div class="tab-pad">
1290
1761
  <div class="editor-intro">
1291
1762
  <div class="editor-intro-copy">
1292
- <div class="eyebrow">Fundamentos</div>
1293
- <div class="editor-title">Defina o comportamento base do stepper</div>
1294
- <div class="editor-subtitle">Ajuste orientação, densidade, animação e classes utilitárias sem misturar decisões estruturais com customização avançada.</div>
1763
+ <div class="eyebrow">{{ tx('editor.general.eyebrow', 'Foundations') }}</div>
1764
+ <div class="editor-title">{{ tx('editor.general.title', 'Define the base stepper behavior') }}</div>
1765
+ <div class="editor-subtitle">{{ tx('editor.general.subtitle', 'Adjust orientation, density, animation and utility classes without mixing structural decisions with advanced customization.') }}</div>
1295
1766
  </div>
1296
1767
  </div>
1297
1768
  <div class="settings-group">
1298
1769
  <div class="group-head">
1299
- <div class="section-title">Layout e navegação</div>
1300
- <div class="section-subtitle">Controla como as etapas aparecem e como o usuário percorre o fluxo.</div>
1770
+ <div class="section-title">{{ tx('editor.general.layoutTitle', 'Layout and navigation') }}</div>
1771
+ <div class="section-subtitle">{{ tx('editor.general.layoutSubtitle', 'Controls how steps appear and how the user moves through the flow.') }}</div>
1301
1772
  </div>
1302
1773
  <div class="pdx-grid">
1303
1774
  <mat-form-field appearance="outline">
1304
- <mat-label>Orientação</mat-label>
1775
+ <mat-label>{{ tx('editor.general.orientation', 'Orientation') }}</mat-label>
1305
1776
  <select matNativeControl [(ngModel)]="config.orientation" (ngModelChange)="markDirty()">
1306
- <option value="horizontal">Horizontal</option>
1307
- <option value="vertical">Vertical</option>
1777
+ <option value="horizontal">{{ tx('editor.general.orientation.horizontal', 'Horizontal') }}</option>
1778
+ <option value="vertical">{{ tx('editor.general.orientation.vertical', 'Vertical') }}</option>
1308
1779
  </select>
1309
1780
  </mat-form-field>
1310
1781
  <mat-form-field appearance="outline">
1311
- <mat-label>Posição dos títulos</mat-label>
1782
+ <mat-label>{{ tx('editor.general.headerPosition', 'Title position') }}</mat-label>
1312
1783
  <select matNativeControl [(ngModel)]="config.headerPosition" (ngModelChange)="markDirty()">
1313
- <option value="top">Acima</option>
1314
- <option value="bottom">Abaixo</option>
1784
+ <option value="top">{{ tx('editor.general.headerPosition.top', 'Above') }}</option>
1785
+ <option value="bottom">{{ tx('editor.general.headerPosition.bottom', 'Below') }}</option>
1315
1786
  </select>
1316
1787
  </mat-form-field>
1317
1788
  <mat-form-field appearance="outline">
1318
- <mat-label>Posição do rótulo</mat-label>
1789
+ <mat-label>{{ tx('editor.general.labelPosition', 'Label position') }}</mat-label>
1319
1790
  <select matNativeControl [(ngModel)]="config.labelPosition" (ngModelChange)="markDirty()" [disabled]="config.orientation !== 'horizontal'">
1320
- <option value="end">Ao lado</option>
1321
- <option value="bottom">Abaixo</option>
1791
+ <option value="end">{{ tx('editor.general.labelPosition.end', 'Beside') }}</option>
1792
+ <option value="bottom">{{ tx('editor.general.labelPosition.bottom', 'Below') }}</option>
1322
1793
  </select>
1323
1794
  </mat-form-field>
1324
1795
  <mat-form-field appearance="outline">
1325
- <mat-label>Densidade</mat-label>
1796
+ <mat-label>{{ tx('editor.general.density', 'Density') }}</mat-label>
1326
1797
  <select matNativeControl [(ngModel)]="config.density" (ngModelChange)="markDirty()">
1327
- <option [ngValue]="undefined">Padrão</option>
1328
- <option value="comfortable">Confortável</option>
1329
- <option value="compact">Compacta</option>
1798
+ <option [ngValue]="undefined">{{ tx('editor.general.density.default', 'Default') }}</option>
1799
+ <option value="comfortable">{{ tx('editor.general.density.comfortable', 'Comfortable') }}</option>
1800
+ <option value="compact">{{ tx('editor.general.density.compact', 'Compact') }}</option>
1330
1801
  </select>
1331
1802
  </mat-form-field>
1332
1803
  <mat-form-field appearance="outline">
1333
- <mat-label>Duração da animação</mat-label>
1334
- <input matInput [(ngModel)]="config.animationDuration" (ngModelChange)="markDirty()" placeholder="Ex.: 300ms" />
1804
+ <mat-label>{{ tx('editor.general.animationDuration', 'Animation duration') }}</mat-label>
1805
+ <input matInput [(ngModel)]="config.animationDuration" (ngModelChange)="markDirty()" [placeholder]="tx('editor.general.animationPlaceholder', 'e.g.: 300ms')" />
1335
1806
  </mat-form-field>
1336
1807
  <mat-form-field appearance="outline">
1337
- <mat-label>Etapa inicial</mat-label>
1808
+ <mat-label>{{ tx('editor.general.initialStep', 'Initial step') }}</mat-label>
1338
1809
  <input matInput type="number" [(ngModel)]="config.selectedIndex" (ngModelChange)="markDirty()" />
1339
1810
  </mat-form-field>
1340
1811
  </div>
1341
1812
  <div class="toggle-group">
1342
- <mat-slide-toggle [(ngModel)]="config.linear" (ngModelChange)="markDirty()">Respeitar ordem (linear)</mat-slide-toggle>
1343
- <mat-slide-toggle [(ngModel)]="config.disableRipple" (ngModelChange)="markDirty()">Desativar efeitos de clique</mat-slide-toggle>
1813
+ <mat-slide-toggle [(ngModel)]="config.linear" (ngModelChange)="markDirty()">{{ tx('editor.general.linear', 'Respect order (linear)') }}</mat-slide-toggle>
1814
+ <mat-slide-toggle [(ngModel)]="config.disableRipple" (ngModelChange)="markDirty()">{{ tx('editor.general.disableRipple', 'Disable click effects') }}</mat-slide-toggle>
1344
1815
  </div>
1345
1816
  </div>
1346
1817
  <details class="disclosure">
1347
1818
  <summary>
1348
- <span class="section-title">Classes e integração visual</span>
1349
- <span class="section-subtitle">Use apenas quando precisar aplicar CSS escopado no host.</span>
1819
+ <span class="section-title">{{ tx('editor.general.visualTitle', 'Classes and visual integration') }}</span>
1820
+ <span class="section-subtitle">{{ tx('editor.general.visualSubtitle', 'Use only when you need to apply scoped CSS on the host.') }}</span>
1350
1821
  </summary>
1351
1822
  <div class="detail-grid disclosure-body">
1352
1823
  <mat-form-field appearance="outline" class="field-span-2">
1353
- <mat-label>Classe do stepper</mat-label>
1354
- <input matInput [(ngModel)]="config.stepperClass" (ngModelChange)="markDirty()" placeholder="Ex.: meu-stepper" />
1824
+ <mat-label>{{ tx('editor.general.stepperClass', 'Stepper class') }}</mat-label>
1825
+ <input matInput [(ngModel)]="config.stepperClass" (ngModelChange)="markDirty()" [placeholder]="tx('editor.general.stepperClassPlaceholder', 'e.g.: my-stepper')" />
1355
1826
  </mat-form-field>
1356
1827
  <mat-form-field appearance="outline">
1357
- <mat-label>Classe do cabeçalho</mat-label>
1358
- <input matInput [(ngModel)]="config.headerClass" (ngModelChange)="markDirty()" placeholder="Ex.: stepper-header" />
1828
+ <mat-label>{{ tx('editor.general.headerClass', 'Header class') }}</mat-label>
1829
+ <input matInput [(ngModel)]="config.headerClass" (ngModelChange)="markDirty()" [placeholder]="tx('editor.general.headerClassPlaceholder', 'e.g.: stepper-header')" />
1359
1830
  </mat-form-field>
1360
1831
  <mat-form-field appearance="outline">
1361
- <mat-label>Classe do conteúdo</mat-label>
1362
- <input matInput [(ngModel)]="config.contentClass" (ngModelChange)="markDirty()" placeholder="Ex.: stepper-content" />
1832
+ <mat-label>{{ tx('editor.general.contentClass', 'Content class') }}</mat-label>
1833
+ <input matInput [(ngModel)]="config.contentClass" (ngModelChange)="markDirty()" [placeholder]="tx('editor.general.contentClassPlaceholder', 'e.g.: stepper-content')" />
1363
1834
  </mat-form-field>
1364
1835
  </div>
1365
1836
  </details>
1366
1837
  </div>
1367
1838
  </mat-tab>
1368
1839
 
1369
- <mat-tab label="Etapas">
1840
+ <mat-tab [label]="tx('editor.tabs.steps', 'Steps')">
1370
1841
  <div class="tab-pad">
1371
1842
  <div class="editor-intro">
1372
1843
  <div class="editor-intro-copy">
1373
- <div class="eyebrow">Estrutura do fluxo</div>
1374
- <div class="editor-title">Defina a narrativa de cada etapa</div>
1375
- <div class="editor-subtitle">Organize títulos, estados e conteúdo da etapa sem misturar configuração técnica com ações de montagem.</div>
1844
+ <div class="eyebrow">{{ tx('editor.steps.eyebrow', 'Flow structure') }}</div>
1845
+ <div class="editor-title">{{ tx('editor.steps.title', 'Define the narrative of each step') }}</div>
1846
+ <div class="editor-subtitle">{{ tx('editor.steps.subtitle', 'Organize titles, states and step content without mixing technical configuration with assembly actions.') }}</div>
1376
1847
  </div>
1377
1848
  <div class="editor-intro-meta">
1378
1849
  <div class="meta-pill">
1379
- <span class="meta-label">Etapas</span>
1850
+ <span class="meta-label">{{ tx('editor.steps.count', 'Steps') }}</span>
1380
1851
  <strong>{{ config.steps.length }}</strong>
1381
1852
  </div>
1382
1853
  </div>
@@ -1384,16 +1855,16 @@ class PraxisStepperConfigEditor {
1384
1855
  <div class="pdx-steps">
1385
1856
  <div class="pdx-steps-header">
1386
1857
  <div>
1387
- <div class="section-title">Mapa de etapas</div>
1388
- <div class="section-subtitle">Arraste para reordenar e selecione uma etapa para editar o conteúdo.</div>
1858
+ <div class="section-title">{{ tx('editor.steps.mapTitle', 'Step map') }}</div>
1859
+ <div class="section-subtitle">{{ tx('editor.steps.mapSubtitle', 'Drag to reorder and select a step to edit its content.') }}</div>
1389
1860
  </div>
1390
- <button mat-flat-button color="primary" (click)="addStep()"><mat-icon [praxisIcon]="'add'"></mat-icon>Adicionar etapa</button>
1861
+ <button mat-flat-button color="primary" (click)="addStep()"><mat-icon [praxisIcon]="'add'"></mat-icon>{{ tx('editor.steps.add', 'Add step') }}</button>
1391
1862
  </div>
1392
1863
  <div class="steps-workspace" *ngIf="activeStep as step; else noSteps">
1393
1864
  <div
1394
1865
  cdkDropList
1395
1866
  role="listbox"
1396
- aria-label="Lista de etapas"
1867
+ [attr.aria-label]="tx('editor.steps.listAria', 'Step list')"
1397
1868
  (cdkDropListDropped)="drop($event)"
1398
1869
  class="pdx-step-list">
1399
1870
  <div
@@ -1412,19 +1883,19 @@ class PraxisStepperConfigEditor {
1412
1883
  <div class="drag-handle" cdkDragHandle><mat-icon [praxisIcon]="'drag_indicator'"></mat-icon></div>
1413
1884
  <div class="step-summary">
1414
1885
  <div class="step-summary-head">
1415
- <div class="step-summary-index">Etapa {{ i + 1 }}</div>
1416
- <div class="step-summary-title">{{ s.label || 'Sem título' }}</div>
1886
+ <div class="step-summary-index">{{ stepIndexLabel(i) }}</div>
1887
+ <div class="step-summary-title">{{ s.label || tx('editor.steps.untitled', 'Untitled') }}</div>
1417
1888
  </div>
1418
- <div class="step-summary-sub">{{ s.id || 'Sem identificador' }}</div>
1889
+ <div class="step-summary-sub">{{ s.id || tx('editor.steps.noId', 'No identifier') }}</div>
1419
1890
  <div class="step-summary-flags">
1420
- <span class="summary-chip" *ngIf="s.optional">Opcional</span>
1421
- <span class="summary-chip" *ngIf="s.completed">Concluída</span>
1422
- <span class="summary-chip summary-chip-warn" *ngIf="s.hasError">Erro</span>
1423
- <span class="summary-chip" *ngIf="s.form">Formulário</span>
1891
+ <span class="summary-chip" *ngIf="s.optional">{{ tx('editor.steps.optional', 'Optional') }}</span>
1892
+ <span class="summary-chip" *ngIf="s.completed">{{ tx('editor.steps.completed', 'Completed') }}</span>
1893
+ <span class="summary-chip summary-chip-warn" *ngIf="s.hasError">{{ tx('editor.steps.error', 'Error') }}</span>
1894
+ <span class="summary-chip" *ngIf="s.form">{{ tx('editor.steps.form', 'Form') }}</span>
1424
1895
  </div>
1425
1896
  </div>
1426
1897
  <div class="pdx-actions">
1427
- <button mat-icon-button color="warn" (click)="removeStep(i); $event.stopPropagation()" matTooltip="Remover" [attr.aria-label]="'Remover etapa ' + (s.label || (i + 1))">
1898
+ <button mat-icon-button color="warn" (click)="removeStep(i); $event.stopPropagation()" [matTooltip]="tx('editor.steps.remove', 'Remove')" [attr.aria-label]="stepRemoveAria(s, i)">
1428
1899
  <mat-icon [praxisIcon]="'delete'"></mat-icon>
1429
1900
  </button>
1430
1901
  </div>
@@ -1434,52 +1905,52 @@ class PraxisStepperConfigEditor {
1434
1905
  <div class="pdx-active-step">
1435
1906
  <div class="hdr">
1436
1907
  <div class="active-step-head">
1437
- <div class="eyebrow">Etapa selecionada</div>
1438
- <div class="title">Editando: {{ step.label }}</div>
1439
- <div class="section-subtitle">Ajuste conteúdo principal primeiro. Configurações secundárias ficam recolhidas para reduzir ruído.</div>
1908
+ <div class="eyebrow">{{ tx('editor.steps.selectedEyebrow', 'Selected step') }}</div>
1909
+ <div class="title">{{ editingStepTitle(step) }}</div>
1910
+ <div class="section-subtitle">{{ tx('editor.steps.selectedSubtitle', 'Adjust the main content first. Secondary settings stay collapsed to reduce noise.') }}</div>
1440
1911
  </div>
1441
1912
  </div>
1442
1913
 
1443
1914
  <div class="section">
1444
- <div class="section-title">Dados principais</div>
1915
+ <div class="section-title">{{ tx('editor.steps.mainData', 'Main data') }}</div>
1445
1916
  <div class="detail-grid">
1446
1917
  <mat-form-field appearance="outline" class="field-span-2">
1447
- <mat-label>Título da etapa</mat-label>
1918
+ <mat-label>{{ tx('editor.steps.stepTitle', 'Step title') }}</mat-label>
1448
1919
  <input matInput [(ngModel)]="step.label" (ngModelChange)="markDirty()" />
1449
1920
  </mat-form-field>
1450
1921
  <mat-form-field appearance="outline">
1451
- <mat-label>Identificador</mat-label>
1922
+ <mat-label>{{ tx('editor.steps.identifier', 'Identifier') }}</mat-label>
1452
1923
  <input matInput [(ngModel)]="step.id" (ngModelChange)="markDirty()" />
1453
1924
  </mat-form-field>
1454
1925
  <mat-form-field appearance="outline">
1455
- <mat-label>Ícone ou estado</mat-label>
1456
- <input matInput [(ngModel)]="step.state" (ngModelChange)="markDirty()" placeholder="Ex.: number, done, edit" />
1926
+ <mat-label>{{ tx('editor.steps.iconOrState', 'Icon or state') }}</mat-label>
1927
+ <input matInput [(ngModel)]="step.state" (ngModelChange)="markDirty()" [placeholder]="tx('editor.steps.iconOrStatePlaceholder', 'e.g.: number, done, edit')" />
1457
1928
  </mat-form-field>
1458
1929
  <mat-form-field appearance="outline" class="field-span-2">
1459
- <mat-label>Mensagem de erro</mat-label>
1930
+ <mat-label>{{ tx('editor.steps.errorMessage', 'Error message') }}</mat-label>
1460
1931
  <input matInput [(ngModel)]="step.errorMessage" (ngModelChange)="markDirty()" />
1461
1932
  </mat-form-field>
1462
1933
  </div>
1463
1934
  <div class="toggle-group">
1464
- <mat-slide-toggle [(ngModel)]="step.optional" (ngModelChange)="markDirty()">Etapa opcional</mat-slide-toggle>
1465
- <mat-slide-toggle [(ngModel)]="step.editable" (ngModelChange)="markDirty()">Permitir voltar e editar</mat-slide-toggle>
1466
- <mat-slide-toggle [(ngModel)]="step.completed" (ngModelChange)="markDirty()">Marcar como concluída</mat-slide-toggle>
1467
- <mat-slide-toggle [(ngModel)]="step.hasError" (ngModelChange)="markDirty()">Marcar como com erro</mat-slide-toggle>
1935
+ <mat-slide-toggle [(ngModel)]="step.optional" (ngModelChange)="markDirty()">{{ tx('editor.steps.optionalToggle', 'Optional step') }}</mat-slide-toggle>
1936
+ <mat-slide-toggle [(ngModel)]="step.editable" (ngModelChange)="markDirty()">{{ tx('editor.steps.editableToggle', 'Allow going back and editing') }}</mat-slide-toggle>
1937
+ <mat-slide-toggle [(ngModel)]="step.completed" (ngModelChange)="markDirty()">{{ tx('editor.steps.completedToggle', 'Mark as completed') }}</mat-slide-toggle>
1938
+ <mat-slide-toggle [(ngModel)]="step.hasError" (ngModelChange)="markDirty()">{{ tx('editor.steps.errorToggle', 'Mark as error') }}</mat-slide-toggle>
1468
1939
  </div>
1469
1940
  </div>
1470
1941
 
1471
1942
  <details class="disclosure">
1472
1943
  <summary>
1473
- <span class="section-title">Acessibilidade e detalhes técnicos</span>
1474
- <span class="section-subtitle">Rótulos auxiliares e metadados menos usados.</span>
1944
+ <span class="section-title">{{ tx('editor.steps.accessibilityTitle', 'Accessibility and technical details') }}</span>
1945
+ <span class="section-subtitle">{{ tx('editor.steps.accessibilitySubtitle', 'Auxiliary labels and less-used metadata.') }}</span>
1475
1946
  </summary>
1476
1947
  <div class="detail-grid disclosure-body">
1477
1948
  <mat-form-field appearance="outline">
1478
- <mat-label>Texto alternativo</mat-label>
1949
+ <mat-label>{{ tx('editor.steps.altText', 'Alternative text') }}</mat-label>
1479
1950
  <input matInput [(ngModel)]="step.ariaLabel" (ngModelChange)="markDirty()" />
1480
1951
  </mat-form-field>
1481
1952
  <mat-form-field appearance="outline">
1482
- <mat-label>ID que descreve</mat-label>
1953
+ <mat-label>{{ tx('editor.steps.describedBy', 'Described-by ID') }}</mat-label>
1483
1954
  <input matInput [(ngModel)]="step.ariaLabelledby" (ngModelChange)="markDirty()" />
1484
1955
  </mat-form-field>
1485
1956
  </div>
@@ -1489,37 +1960,37 @@ class PraxisStepperConfigEditor {
1489
1960
  <div class="section editorial-section">
1490
1961
  <div class="section-head">
1491
1962
  <div>
1492
- <div class="section-title">Conteúdo editorial</div>
1493
- <div class="section-subtitle">Use blocos de apoio para contextualizar a etapa antes ou depois do formulário.</div>
1963
+ <div class="section-title">{{ tx('editor.steps.editorialTitle', 'Editorial content') }}</div>
1964
+ <div class="section-subtitle">{{ tx('editor.steps.editorialSubtitle', 'Use supporting blocks to contextualize the step before or after the form.') }}</div>
1494
1965
  </div>
1495
1966
  </div>
1496
1967
 
1497
1968
  <div class="zone-grid">
1498
1969
  <div class="zone-column">
1499
1970
  <div class="zone-head">
1500
- <div class="zone-title">Antes do formulário</div>
1971
+ <div class="zone-title">{{ tx('editor.steps.zoneBefore', 'Before form') }}</div>
1501
1972
  <div class="zone-actions">
1502
1973
  <span class="zone-count">{{ editorialBeforeWidgets(step).length }}</span>
1503
1974
  <button mat-stroked-button [matMenuTriggerFor]="beforeEditorialMenu">
1504
1975
  <mat-icon [praxisIcon]="'add'"></mat-icon>
1505
- Adicionar
1976
+ {{ tx('editor.steps.addBlock', 'Add') }}
1506
1977
  </button>
1507
1978
  <mat-menu #beforeEditorialMenu="matMenu">
1508
1979
  <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-benefits', 'before')">
1509
1980
  <mat-icon [praxisIcon]="'view_module'"></mat-icon>
1510
- Grade de benefícios
1981
+ {{ tx('editor.steps.widgetBenefits', 'Benefits grid') }}
1511
1982
  </button>
1512
1983
  <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-content', 'before')">
1513
1984
  <mat-icon [praxisIcon]="'article'"></mat-icon>
1514
- Bloco de conteúdo
1985
+ {{ tx('editor.steps.widgetContent', 'Content block') }}
1515
1986
  </button>
1516
1987
  <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-inline-notice', 'before')">
1517
1988
  <mat-icon [praxisIcon]="'info'"></mat-icon>
1518
- Aviso inline
1989
+ {{ tx('editor.steps.widgetNotice', 'Inline notice') }}
1519
1990
  </button>
1520
1991
  <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-divider', 'before')">
1521
1992
  <mat-icon [praxisIcon]="'horizontal_rule'"></mat-icon>
1522
- Divisor
1993
+ {{ tx('editor.steps.widgetDivider', 'Divider') }}
1523
1994
  </button>
1524
1995
  </mat-menu>
1525
1996
  </div>
@@ -1534,49 +2005,49 @@ class PraxisStepperConfigEditor {
1534
2005
  <div class="meta" *ngIf="widgetBlockId(w) as blockId">ID: {{ blockId }}</div>
1535
2006
  </div>
1536
2007
  <div class="actions">
1537
- <button mat-icon-button (click)="editWidget(w)" matTooltip="Editar bloco">
2008
+ <button mat-icon-button (click)="editWidget(w)" [matTooltip]="tx('editor.steps.editBlock', 'Edit block')">
1538
2009
  <mat-icon [praxisIcon]="'tune'"></mat-icon>
1539
2010
  </button>
1540
- <button mat-icon-button (click)="moveEditorialWidget(w, 'before', 'after')" matTooltip="Mover para depois do formulário">
2011
+ <button mat-icon-button (click)="moveEditorialWidget(w, 'before', 'after')" [matTooltip]="tx('editor.steps.moveAfter', 'Move after the form')">
1541
2012
  <mat-icon [praxisIcon]="'south'"></mat-icon>
1542
2013
  </button>
1543
- <button mat-icon-button (click)="duplicateEditorialWidget(w, 'before')" matTooltip="Duplicar bloco">
2014
+ <button mat-icon-button (click)="duplicateEditorialWidget(w, 'before')" [matTooltip]="tx('editor.steps.duplicateBlock', 'Duplicate block')">
1544
2015
  <mat-icon [praxisIcon]="'content_copy'"></mat-icon>
1545
2016
  </button>
1546
- <button mat-icon-button color="warn" (click)="removeEditorialWidget(w, 'before')" matTooltip="Remover bloco">
2017
+ <button mat-icon-button color="warn" (click)="removeEditorialWidget(w, 'before')" [matTooltip]="tx('editor.steps.removeBlock', 'Remove block')">
1547
2018
  <mat-icon [praxisIcon]="'delete'"></mat-icon>
1548
2019
  </button>
1549
2020
  </div>
1550
2021
  </div>
1551
- <div class="empty" *ngIf="!editorialBeforeWidgets(step).length">Nenhum bloco nesta zona.</div>
2022
+ <div class="empty" *ngIf="!editorialBeforeWidgets(step).length">{{ tx('editor.steps.emptyZone', 'No blocks in this zone.') }}</div>
1552
2023
  </div>
1553
2024
  </div>
1554
2025
 
1555
2026
  <div class="zone-column">
1556
2027
  <div class="zone-head">
1557
- <div class="zone-title">Depois do formulário</div>
2028
+ <div class="zone-title">{{ tx('editor.steps.zoneAfter', 'After form') }}</div>
1558
2029
  <div class="zone-actions">
1559
2030
  <span class="zone-count">{{ editorialAfterWidgets(step).length }}</span>
1560
2031
  <button mat-stroked-button [matMenuTriggerFor]="afterEditorialMenu">
1561
2032
  <mat-icon [praxisIcon]="'add'"></mat-icon>
1562
- Adicionar
2033
+ {{ tx('editor.steps.addBlock', 'Add') }}
1563
2034
  </button>
1564
2035
  <mat-menu #afterEditorialMenu="matMenu">
1565
2036
  <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-benefits', 'after')">
1566
2037
  <mat-icon [praxisIcon]="'view_module'"></mat-icon>
1567
- Grade de benefícios
2038
+ {{ tx('editor.steps.widgetBenefits', 'Benefits grid') }}
1568
2039
  </button>
1569
2040
  <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-content', 'after')">
1570
2041
  <mat-icon [praxisIcon]="'article'"></mat-icon>
1571
- Bloco de conteúdo
2042
+ {{ tx('editor.steps.widgetContent', 'Content block') }}
1572
2043
  </button>
1573
2044
  <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-inline-notice', 'after')">
1574
2045
  <mat-icon [praxisIcon]="'info'"></mat-icon>
1575
- Aviso inline
2046
+ {{ tx('editor.steps.widgetNotice', 'Inline notice') }}
1576
2047
  </button>
1577
2048
  <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-divider', 'after')">
1578
2049
  <mat-icon [praxisIcon]="'horizontal_rule'"></mat-icon>
1579
- Divisor
2050
+ {{ tx('editor.steps.widgetDivider', 'Divider') }}
1580
2051
  </button>
1581
2052
  </mat-menu>
1582
2053
  </div>
@@ -1591,46 +2062,46 @@ class PraxisStepperConfigEditor {
1591
2062
  <div class="meta" *ngIf="widgetBlockId(w) as blockId">ID: {{ blockId }}</div>
1592
2063
  </div>
1593
2064
  <div class="actions">
1594
- <button mat-icon-button (click)="editWidget(w)" matTooltip="Editar bloco">
2065
+ <button mat-icon-button (click)="editWidget(w)" [matTooltip]="tx('editor.steps.editBlock', 'Edit block')">
1595
2066
  <mat-icon [praxisIcon]="'tune'"></mat-icon>
1596
2067
  </button>
1597
- <button mat-icon-button (click)="moveEditorialWidget(w, 'after', 'before')" matTooltip="Mover para antes do formulário">
2068
+ <button mat-icon-button (click)="moveEditorialWidget(w, 'after', 'before')" [matTooltip]="tx('editor.steps.moveBefore', 'Move before the form')">
1598
2069
  <mat-icon [praxisIcon]="'north'"></mat-icon>
1599
2070
  </button>
1600
- <button mat-icon-button (click)="duplicateEditorialWidget(w, 'after')" matTooltip="Duplicar bloco">
2071
+ <button mat-icon-button (click)="duplicateEditorialWidget(w, 'after')" [matTooltip]="tx('editor.steps.duplicateBlock', 'Duplicate block')">
1601
2072
  <mat-icon [praxisIcon]="'content_copy'"></mat-icon>
1602
2073
  </button>
1603
- <button mat-icon-button color="warn" (click)="removeEditorialWidget(w, 'after')" matTooltip="Remover bloco">
2074
+ <button mat-icon-button color="warn" (click)="removeEditorialWidget(w, 'after')" [matTooltip]="tx('editor.steps.removeBlock', 'Remove block')">
1604
2075
  <mat-icon [praxisIcon]="'delete'"></mat-icon>
1605
2076
  </button>
1606
2077
  </div>
1607
2078
  </div>
1608
- <div class="empty" *ngIf="!editorialAfterWidgets(step).length">Nenhum bloco nesta zona.</div>
2079
+ <div class="empty" *ngIf="!editorialAfterWidgets(step).length">{{ tx('editor.steps.emptyZone', 'No blocks in this zone.') }}</div>
1609
2080
  </div>
1610
2081
  </div>
1611
2082
  </div>
1612
2083
  </div>
1613
2084
 
1614
2085
  <div class="section">
1615
- <div class="section-title">Formulário da etapa</div>
2086
+ <div class="section-title">{{ tx('editor.steps.formSectionTitle', 'Step form') }}</div>
1616
2087
  <div class="section-body">
1617
2088
  <ng-container *ngIf="step.form; else addFormBtn">
1618
2089
  <div class="form-row-card">
1619
2090
  <div class="form-row-main">
1620
2091
  <mat-icon [praxisIcon]="'dynamic_form'"></mat-icon>
1621
2092
  <div>
1622
- <div class="name">Formulário principal</div>
2093
+ <div class="name">{{ tx('editor.steps.mainFormTitle', 'Main form') }}</div>
1623
2094
  <div class="sub">{{ step.form.formId || step.id || '—' }}</div>
1624
2095
  </div>
1625
2096
  </div>
1626
2097
  <div class="form-row-actions">
1627
- <button mat-button (click)="editMainForm()"><mat-icon [praxisIcon]="'tune'"></mat-icon> Editar</button>
1628
- <button mat-button color="warn" (click)="removeMainForm()"><mat-icon [praxisIcon]="'delete'"></mat-icon> Remover</button>
2098
+ <button mat-button (click)="editMainForm()"><mat-icon [praxisIcon]="'tune'"></mat-icon>{{ tx('editor.steps.edit', 'Edit') }}</button>
2099
+ <button mat-button color="warn" (click)="removeMainForm()"><mat-icon [praxisIcon]="'delete'"></mat-icon>{{ tx('editor.steps.remove', 'Remove') }}</button>
1629
2100
  </div>
1630
2101
  </div>
1631
2102
  </ng-container>
1632
2103
  <ng-template #addFormBtn>
1633
- <button mat-stroked-button color="primary" (click)="addMainForm()"><mat-icon [praxisIcon]="'add'"></mat-icon> Adicionar formulário</button>
2104
+ <button mat-stroked-button color="primary" (click)="addMainForm()"><mat-icon [praxisIcon]="'add'"></mat-icon>{{ tx('editor.steps.addForm', 'Add form') }}</button>
1634
2105
  </ng-template>
1635
2106
  </div>
1636
2107
  </div>
@@ -1638,12 +2109,12 @@ class PraxisStepperConfigEditor {
1638
2109
  <div class="section">
1639
2110
  <div class="section-head">
1640
2111
  <div>
1641
- <div class="section-title">Componentes avançados</div>
1642
- <div class="section-subtitle">Atalhos para montar experiências mais ricas sem perder clareza no fluxo.</div>
2112
+ <div class="section-title">{{ tx('editor.steps.advancedTitle', 'Advanced components') }}</div>
2113
+ <div class="section-subtitle">{{ tx('editor.steps.advancedSubtitle', 'Shortcuts to assemble richer experiences without losing clarity in the flow.') }}</div>
1643
2114
  </div>
1644
2115
  <button mat-stroked-button (click)="openMoreComponents()">
1645
2116
  <mat-icon [praxisIcon]="'add'"></mat-icon>
1646
- Mais componentes
2117
+ {{ tx('editor.steps.moreComponents', 'More components') }}
1647
2118
  </button>
1648
2119
  </div>
1649
2120
  <div class="section-body">
@@ -1652,14 +2123,14 @@ class PraxisStepperConfigEditor {
1652
2123
  <div class="cta-head">
1653
2124
  <mat-icon [praxisIcon]="'account_tree'"></mat-icon>
1654
2125
  <div>
1655
- <div class="cta-title">Lista em árvore</div>
1656
- <div class="cta-desc">Dados hierárquicos com seleção simples.</div>
2126
+ <div class="cta-title">{{ tx('editor.steps.treeListTitle', 'Tree list') }}</div>
2127
+ <div class="cta-desc">{{ tx('editor.steps.treeListDesc', 'Hierarchical data with simple selection.') }}</div>
1657
2128
  </div>
1658
2129
  </div>
1659
2130
  <div class="cta-actions">
1660
2131
  <button mat-stroked-button (click)="addTreeList()">
1661
2132
  <mat-icon [praxisIcon]="'add'"></mat-icon>
1662
- Inserir árvore
2133
+ {{ tx('editor.steps.insertTree', 'Insert tree') }}
1663
2134
  </button>
1664
2135
  </div>
1665
2136
  </div>
@@ -1667,14 +2138,14 @@ class PraxisStepperConfigEditor {
1667
2138
  <div class="cta-head">
1668
2139
  <mat-icon [praxisIcon]="'swap_horiz'"></mat-icon>
1669
2140
  <div>
1670
- <div class="cta-title">Transferência de itens</div>
1671
- <div class="cta-desc">Mover itens entre listas para seleção múltipla.</div>
2141
+ <div class="cta-title">{{ tx('editor.steps.transferTitle', 'Item transfer') }}</div>
2142
+ <div class="cta-desc">{{ tx('editor.steps.transferDesc', 'Move items between lists for multi-selection.') }}</div>
1672
2143
  </div>
1673
2144
  </div>
1674
2145
  <div class="cta-actions">
1675
2146
  <button mat-stroked-button (click)="addTransferListQuick()">
1676
2147
  <mat-icon [praxisIcon]="'add'"></mat-icon>
1677
- Inserir transferência
2148
+ {{ tx('editor.steps.insertTransfer', 'Insert transfer') }}
1678
2149
  </button>
1679
2150
  </div>
1680
2151
  </div>
@@ -1682,14 +2153,14 @@ class PraxisStepperConfigEditor {
1682
2153
  <div class="cta-head">
1683
2154
  <mat-icon [praxisIcon]="'search'"></mat-icon>
1684
2155
  <div>
1685
- <div class="cta-title">Seleção com busca</div>
1686
- <div class="cta-desc">Seleção com busca local ou remota.</div>
2156
+ <div class="cta-title">{{ tx('editor.steps.searchTitle', 'Searchable selection') }}</div>
2157
+ <div class="cta-desc">{{ tx('editor.steps.searchDesc', 'Selection with local or remote search.') }}</div>
1687
2158
  </div>
1688
2159
  </div>
1689
2160
  <div class="cta-actions">
1690
2161
  <button mat-stroked-button (click)="addSearchableSelect()">
1691
2162
  <mat-icon [praxisIcon]="'add'"></mat-icon>
1692
- Inserir seletor
2163
+ {{ tx('editor.steps.insertSelector', 'Insert selector') }}
1693
2164
  </button>
1694
2165
  </div>
1695
2166
  </div>
@@ -1697,14 +2168,14 @@ class PraxisStepperConfigEditor {
1697
2168
  <div class="cta-head">
1698
2169
  <mat-icon [praxisIcon]="'upload_file'"></mat-icon>
1699
2170
  <div>
1700
- <div class="cta-title">Upload de arquivos</div>
1701
- <div class="cta-desc">Anexos com validação e fluxo de upload.</div>
2171
+ <div class="cta-title">{{ tx('editor.steps.uploadTitle', 'File upload') }}</div>
2172
+ <div class="cta-desc">{{ tx('editor.steps.uploadDesc', 'Attachments with validation and upload flow.') }}</div>
1702
2173
  </div>
1703
2174
  </div>
1704
2175
  <div class="cta-actions">
1705
2176
  <button mat-stroked-button (click)="addFilesUpload()">
1706
2177
  <mat-icon [praxisIcon]="'add'"></mat-icon>
1707
- Inserir upload
2178
+ {{ tx('editor.steps.insertUpload', 'Insert upload') }}
1708
2179
  </button>
1709
2180
  </div>
1710
2181
  </div>
@@ -1718,15 +2189,15 @@ class PraxisStepperConfigEditor {
1718
2189
  <div class="sub">{{ w.id }}</div>
1719
2190
  </div>
1720
2191
  <div class="actions">
1721
- <button mat-icon-button (click)="editWidget(w)" [disabled]="!canEditWidget(w)" matTooltip="Editar componente">
2192
+ <button mat-icon-button (click)="editWidget(w)" [disabled]="!canEditWidget(w)" [matTooltip]="tx('editor.steps.editComponent', 'Edit component')">
1722
2193
  <mat-icon [praxisIcon]="'tune'"></mat-icon>
1723
2194
  </button>
1724
- <button mat-icon-button color="warn" (click)="removeAdvancedWidget(w)" matTooltip="Remover componente">
2195
+ <button mat-icon-button color="warn" (click)="removeAdvancedWidget(w)" [matTooltip]="tx('editor.steps.removeComponent', 'Remove component')">
1725
2196
  <mat-icon [praxisIcon]="'delete'"></mat-icon>
1726
2197
  </button>
1727
2198
  </div>
1728
2199
  </div>
1729
- <div class="empty" *ngIf="!advancedWidgets(step).length">Nenhum componente avançado adicionado.</div>
2200
+ <div class="empty" *ngIf="!advancedWidgets(step).length">{{ tx('editor.steps.emptyAdvanced', 'No advanced components added.') }}</div>
1730
2201
  </div>
1731
2202
  </div>
1732
2203
  </div>
@@ -1735,88 +2206,88 @@ class PraxisStepperConfigEditor {
1735
2206
  </div>
1736
2207
  </div>
1737
2208
  <ng-template #noSteps>
1738
- <div class="muted">Nenhuma etapa definida.</div>
2209
+ <div class="muted">{{ tx('editor.steps.noSteps', 'No steps defined.') }}</div>
1739
2210
  </ng-template>
1740
2211
  </div>
1741
2212
  </mat-tab>
1742
2213
 
1743
- <mat-tab label="Navegação">
2214
+ <mat-tab [label]="tx('editor.navigation.tab', 'Navigation')">
1744
2215
  <div class="tab-pad">
1745
2216
  <div class="editor-intro">
1746
2217
  <div class="editor-intro-copy">
1747
- <div class="eyebrow">Ações padrão</div>
1748
- <div class="editor-title">Configure a navegação entre etapas</div>
1749
- <div class="editor-subtitle">Defina quando os botões padrão aparecem e como eles se apresentam visualmente no fluxo.</div>
2218
+ <div class="eyebrow">{{ tx('editor.navigation.eyebrow', 'Default actions') }}</div>
2219
+ <div class="editor-title">{{ tx('editor.navigation.title', 'Configure navigation between steps') }}</div>
2220
+ <div class="editor-subtitle">{{ tx('editor.navigation.subtitle', 'Define when default buttons appear and how they present visually in the flow.') }}</div>
1750
2221
  </div>
1751
2222
  </div>
1752
2223
  <div class="settings-group">
1753
2224
  <div class="group-head">
1754
- <div class="section-title">Comportamento dos botões</div>
1755
- <div class="section-subtitle">Aparência e alinhamento da navegação padrão do stepper.</div>
2225
+ <div class="section-title">{{ tx('editor.navigation.behaviorTitle', 'Button behavior') }}</div>
2226
+ <div class="section-subtitle">{{ tx('editor.navigation.behaviorSubtitle', 'Appearance and alignment of the default stepper navigation.') }}</div>
1756
2227
  </div>
1757
2228
  <div class="toggle-group">
1758
- <mat-slide-toggle [(ngModel)]="navigationCfg.visible" (ngModelChange)="markDirty()">Mostrar navegação padrão</mat-slide-toggle>
2229
+ <mat-slide-toggle [(ngModel)]="navigationCfg.visible" (ngModelChange)="markDirty()">{{ tx('editor.navigation.visible', 'Show default navigation') }}</mat-slide-toggle>
1759
2230
  </div>
1760
2231
  <div class="pdx-grid">
1761
2232
  <mat-form-field appearance="outline">
1762
- <mat-label>Estilo dos botões</mat-label>
2233
+ <mat-label>{{ tx('editor.navigation.variant', 'Button style') }}</mat-label>
1763
2234
  <select matNativeControl [(ngModel)]="navigationCfg.variant" (ngModelChange)="markDirty()" [disabled]="!navigationCfg.visible">
1764
- <option [ngValue]="undefined">Padrão (elevado)</option>
1765
- <option value="basic">Texto</option>
1766
- <option value="flat">Plano</option>
1767
- <option value="stroked">Contornado</option>
1768
- <option value="raised">Elevado</option>
2235
+ <option [ngValue]="undefined">{{ tx('editor.navigation.variant.default', 'Default (raised)') }}</option>
2236
+ <option value="basic">{{ tx('editor.navigation.variant.basic', 'Text') }}</option>
2237
+ <option value="flat">{{ tx('editor.navigation.variant.flat', 'Flat') }}</option>
2238
+ <option value="stroked">{{ tx('editor.navigation.variant.stroked', 'Stroked') }}</option>
2239
+ <option value="raised">{{ tx('editor.navigation.variant.raised', 'Raised') }}</option>
1769
2240
  </select>
1770
2241
  </mat-form-field>
1771
2242
  <mat-form-field appearance="outline">
1772
- <mat-label>Cor</mat-label>
2243
+ <mat-label>{{ tx('editor.navigation.color', 'Color') }}</mat-label>
1773
2244
  <select matNativeControl [(ngModel)]="navigationCfg.color" (ngModelChange)="markDirty()" [disabled]="!navigationCfg.visible">
1774
- <option [ngValue]="undefined">Padrão</option>
1775
- <option value="primary">Primária</option>
1776
- <option value="accent">Acento</option>
1777
- <option value="warn">Alerta</option>
2245
+ <option [ngValue]="undefined">{{ tx('editor.navigation.color.default', 'Default') }}</option>
2246
+ <option value="primary">{{ tx('editor.navigation.color.primary', 'Primary') }}</option>
2247
+ <option value="accent">{{ tx('editor.navigation.color.accent', 'Accent') }}</option>
2248
+ <option value="warn">{{ tx('editor.navigation.color.warn', 'Warn') }}</option>
1778
2249
  </select>
1779
2250
  </mat-form-field>
1780
2251
  <mat-form-field appearance="outline">
1781
- <mat-label>Alinhamento</mat-label>
2252
+ <mat-label>{{ tx('editor.navigation.align', 'Alignment') }}</mat-label>
1782
2253
  <select matNativeControl [(ngModel)]="navigationCfg.align" (ngModelChange)="markDirty()" [disabled]="!navigationCfg.visible">
1783
- <option [ngValue]="undefined">Direita</option>
1784
- <option value="start">Esquerda</option>
1785
- <option value="center">Centro</option>
1786
- <option value="space-between">Espaçado</option>
1787
- <option value="end">Direita</option>
2254
+ <option [ngValue]="undefined">{{ tx('editor.navigation.align.default', 'Right') }}</option>
2255
+ <option value="start">{{ tx('editor.navigation.align.start', 'Left') }}</option>
2256
+ <option value="center">{{ tx('editor.navigation.align.center', 'Center') }}</option>
2257
+ <option value="space-between">{{ tx('editor.navigation.align.spaceBetween', 'Spaced') }}</option>
2258
+ <option value="end">{{ tx('editor.navigation.align.end', 'Right') }}</option>
1788
2259
  </select>
1789
2260
  </mat-form-field>
1790
2261
  </div>
1791
2262
  </div>
1792
2263
  <div class="settings-group">
1793
2264
  <div class="group-head">
1794
- <div class="section-title">Rótulos e ícones</div>
1795
- <div class="section-subtitle">Ajuste a cópia e os ícones usados nas ações de voltar e avançar.</div>
2265
+ <div class="section-title">{{ tx('editor.navigation.labelsTitle', 'Labels and icons') }}</div>
2266
+ <div class="section-subtitle">{{ tx('editor.navigation.labelsSubtitle', 'Adjust the copy and icons used in back and next actions.') }}</div>
1796
2267
  </div>
1797
2268
  <div class="pdx-grid">
1798
2269
  <mat-form-field appearance="outline">
1799
- <mat-label>Texto do botão Voltar</mat-label>
1800
- <input matInput [(ngModel)]="navigationCfg.prevLabel" (ngModelChange)="markDirty()" placeholder="Ex.: Voltar" [disabled]="!navigationCfg.visible" />
2270
+ <mat-label>{{ tx('editor.navigation.prevLabel', 'Back button text') }}</mat-label>
2271
+ <input matInput [(ngModel)]="navigationCfg.prevLabel" (ngModelChange)="markDirty()" [placeholder]="tx('editor.navigation.prevPlaceholder', 'e.g.: Back')" [disabled]="!navigationCfg.visible" />
1801
2272
  </mat-form-field>
1802
2273
  <mat-form-field appearance="outline">
1803
- <mat-label>Texto do botão Próximo</mat-label>
1804
- <input matInput [(ngModel)]="navigationCfg.nextLabel" (ngModelChange)="markDirty()" placeholder="Ex.: Próximo" [disabled]="!navigationCfg.visible" />
2274
+ <mat-label>{{ tx('editor.navigation.nextLabel', 'Next button text') }}</mat-label>
2275
+ <input matInput [(ngModel)]="navigationCfg.nextLabel" (ngModelChange)="markDirty()" [placeholder]="tx('editor.navigation.nextPlaceholder', 'e.g.: Next')" [disabled]="!navigationCfg.visible" />
1805
2276
  </mat-form-field>
1806
2277
  </div>
1807
2278
  <div class="inline-actions-grid">
1808
2279
  <div class="inline-action-item">
1809
- <div class="section-title">Ícone de Voltar</div>
1810
- <button mat-stroked-button type="button" (click)="pickNavIcon('prevIcon')" [disabled]="!navigationCfg.visible" aria-label="Escolher ícone do botão Voltar">
2280
+ <div class="section-title">{{ tx('editor.navigation.prevIcon', 'Back icon') }}</div>
2281
+ <button mat-stroked-button type="button" (click)="pickNavIcon('prevIcon')" [disabled]="!navigationCfg.visible" [attr.aria-label]="tx('editor.navigation.pickPrevIcon', 'Choose the Back button icon')">
1811
2282
  <mat-icon *ngIf="navigationCfg.prevIcon" [fontIcon]="navigationCfg.prevIcon"></mat-icon>
1812
- <ng-container *ngIf="!navigationCfg.prevIcon">Escolher</ng-container>
2283
+ <ng-container *ngIf="!navigationCfg.prevIcon">{{ tx('editor.shared.pick', 'Choose') }}</ng-container>
1813
2284
  </button>
1814
2285
  </div>
1815
2286
  <div class="inline-action-item">
1816
- <div class="section-title">Ícone de Próximo</div>
1817
- <button mat-stroked-button type="button" (click)="pickNavIcon('nextIcon')" [disabled]="!navigationCfg.visible" aria-label="Escolher ícone do botão Próximo">
2287
+ <div class="section-title">{{ tx('editor.navigation.nextIcon', 'Next icon') }}</div>
2288
+ <button mat-stroked-button type="button" (click)="pickNavIcon('nextIcon')" [disabled]="!navigationCfg.visible" [attr.aria-label]="tx('editor.navigation.pickNextIcon', 'Choose the Next button icon')">
1818
2289
  <mat-icon *ngIf="navigationCfg.nextIcon" [fontIcon]="navigationCfg.nextIcon"></mat-icon>
1819
- <ng-container *ngIf="!navigationCfg.nextIcon">Escolher</ng-container>
2290
+ <ng-container *ngIf="!navigationCfg.nextIcon">{{ tx('editor.shared.pick', 'Choose') }}</ng-container>
1820
2291
  </button>
1821
2292
  </div>
1822
2293
  </div>
@@ -1824,47 +2295,47 @@ class PraxisStepperConfigEditor {
1824
2295
  </div>
1825
2296
  </mat-tab>
1826
2297
 
1827
- <mat-tab label="Aparência">
2298
+ <mat-tab [label]="tx('editor.appearance.tab', 'Appearance')">
1828
2299
  <div class="tab-pad">
1829
2300
  <div class="editor-intro">
1830
2301
  <div class="editor-intro-copy">
1831
- <div class="eyebrow">Tema visual</div>
1832
- <div class="editor-title">Personalize aparência sem perder consistência</div>
1833
- <div class="editor-subtitle">Comece pelos ajustes rápidos. Tokens e snippet SCSS ficam recolhidos para cenários avançados.</div>
2302
+ <div class="eyebrow">{{ tx('editor.appearance.eyebrow', 'Visual theme') }}</div>
2303
+ <div class="editor-title">{{ tx('editor.appearance.title', 'Customize appearance without losing consistency') }}</div>
2304
+ <div class="editor-subtitle">{{ tx('editor.appearance.subtitle', 'Start with the quick adjustments. Tokens and the SCSS snippet stay collapsed for advanced scenarios.') }}</div>
1834
2305
  </div>
1835
2306
  </div>
1836
2307
  <div class="settings-group">
1837
2308
  <div class="group-head">
1838
- <div class="section-title">Ajustes rápidos</div>
1839
- <div class="section-subtitle">Controles mais comuns para tamanho, peso tipográfico e tema.</div>
2309
+ <div class="section-title">{{ tx('editor.appearance.quickTitle', 'Quick adjustments') }}</div>
2310
+ <div class="section-subtitle">{{ tx('editor.appearance.quickSubtitle', 'Most common controls for sizing, typography weight and theme.') }}</div>
1840
2311
  </div>
1841
2312
  <div class="quick-grid">
1842
2313
  <mat-form-field appearance="outline">
1843
- <mat-label>Altura do cabeçalho (px)</mat-label>
1844
- <input matInput type="number" [ngModel]="headerHeightPx" (ngModelChange)="setHeaderHeightPx($event)" placeholder="Ex.: 48" />
2314
+ <mat-label>{{ tx('editor.appearance.headerHeight', 'Header height (px)') }}</mat-label>
2315
+ <input matInput type="number" [ngModel]="headerHeightPx" (ngModelChange)="setHeaderHeightPx($event)" [placeholder]="tx('editor.appearance.headerHeightPlaceholder', 'e.g.: 48')" />
1845
2316
  </mat-form-field>
1846
2317
  <mat-form-field appearance="outline">
1847
- <mat-label>Tamanho do texto (px)</mat-label>
1848
- <input matInput type="number" [ngModel]="headerLabelTextSizePx" (ngModelChange)="setHeaderLabelTextSizePx($event)" placeholder="Ex.: 14" />
2318
+ <mat-label>{{ tx('editor.appearance.textSize', 'Text size (px)') }}</mat-label>
2319
+ <input matInput type="number" [ngModel]="headerLabelTextSizePx" (ngModelChange)="setHeaderLabelTextSizePx($event)" [placeholder]="tx('editor.appearance.textSizePlaceholder', 'e.g.: 14')" />
1849
2320
  </mat-form-field>
1850
2321
  <mat-form-field appearance="outline">
1851
- <mat-label>Peso do texto</mat-label>
2322
+ <mat-label>{{ tx('editor.appearance.textWeight', 'Text weight') }}</mat-label>
1852
2323
  <select matNativeControl [ngModel]="headerLabelTextWeight" (ngModelChange)="setHeaderLabelTextWeight($event)">
1853
- <option [ngValue]="undefined">Padrão</option>
1854
- <option value="400">Normal</option>
1855
- <option value="500">Médio</option>
1856
- <option value="600">Seminegrito</option>
1857
- <option value="700">Negrito</option>
2324
+ <option [ngValue]="undefined">{{ tx('editor.appearance.textWeight.default', 'Default') }}</option>
2325
+ <option value="400">{{ tx('editor.appearance.textWeight.400', 'Normal') }}</option>
2326
+ <option value="500">{{ tx('editor.appearance.textWeight.500', 'Medium') }}</option>
2327
+ <option value="600">{{ tx('editor.appearance.textWeight.600', 'Semibold') }}</option>
2328
+ <option value="700">{{ tx('editor.appearance.textWeight.700', 'Bold') }}</option>
1858
2329
  </select>
1859
2330
  </mat-form-field>
1860
2331
  <mat-form-field appearance="outline" class="field-span-2">
1861
- <mat-label>Classe de tema</mat-label>
1862
- <input matInput [(ngModel)]="appearance.themeClass" (ngModelChange)="onAppearanceChange()" placeholder="Ex.: theme-stepper-custom" />
2332
+ <mat-label>{{ tx('editor.appearance.themeClass', 'Theme class') }}</mat-label>
2333
+ <input matInput [(ngModel)]="appearance.themeClass" (ngModelChange)="onAppearanceChange()" [placeholder]="tx('editor.appearance.themeClassPlaceholder', 'e.g.: theme-stepper-custom')" />
1863
2334
  </mat-form-field>
1864
2335
  <mat-form-field appearance="outline">
1865
- <mat-label>Conjunto de ícones</mat-label>
2336
+ <mat-label>{{ tx('editor.appearance.iconSet', 'Icon set') }}</mat-label>
1866
2337
  <select matNativeControl [(ngModel)]="appearance.iconsSet" (ngModelChange)="onAppearanceChange()">
1867
- <option [ngValue]="undefined">Material Icons (padrão)</option>
2338
+ <option [ngValue]="undefined">{{ tx('editor.appearance.iconSet.default', 'Material Icons (default)') }}</option>
1868
2339
  <option value="material-symbols-outlined">Material Symbols (Outlined)</option>
1869
2340
  <option value="material-symbols-rounded">Material Symbols (Rounded)</option>
1870
2341
  <option value="material-symbols-sharp">Material Symbols (Sharp)</option>
@@ -1873,63 +2344,63 @@ class PraxisStepperConfigEditor {
1873
2344
  </div>
1874
2345
  <div class="inline-actions-grid icon-picker-grid">
1875
2346
  <div class="inline-action-item">
1876
- <div class="section-title">Ícone do número</div>
1877
- <button mat-stroked-button type="button" (click)="pickIcon('number')" aria-label="Escolher ícone do número">
2347
+ <div class="section-title">{{ tx('editor.appearance.iconNumber', 'Number icon') }}</div>
2348
+ <button mat-stroked-button type="button" (click)="pickIcon('number')" [attr.aria-label]="tx('editor.appearance.pickIconNumber', 'Choose the number icon')">
1878
2349
  <mat-icon *ngIf="icons.number; else pick" [fontIcon]="icons.number"></mat-icon>
1879
- <ng-template #pick>Escolher</ng-template>
2350
+ <ng-template #pick>{{ tx('editor.shared.pick', 'Choose') }}</ng-template>
1880
2351
  </button>
1881
2352
  </div>
1882
2353
  <div class="inline-action-item">
1883
- <div class="section-title">Ícone concluído</div>
1884
- <button mat-stroked-button type="button" (click)="pickIcon('done')" aria-label="Escolher ícone de concluído">
2354
+ <div class="section-title">{{ tx('editor.appearance.iconDone', 'Completed icon') }}</div>
2355
+ <button mat-stroked-button type="button" (click)="pickIcon('done')" [attr.aria-label]="tx('editor.appearance.pickIconDone', 'Choose the completed icon')">
1885
2356
  <mat-icon *ngIf="icons.done; else pick2" [fontIcon]="icons.done"></mat-icon>
1886
- <ng-template #pick2>Escolher</ng-template>
2357
+ <ng-template #pick2>{{ tx('editor.shared.pick', 'Choose') }}</ng-template>
1887
2358
  </button>
1888
2359
  </div>
1889
2360
  <div class="inline-action-item">
1890
- <div class="section-title">Ícone edição</div>
1891
- <button mat-stroked-button type="button" (click)="pickIcon('edit')" aria-label="Escolher ícone de edição">
2361
+ <div class="section-title">{{ tx('editor.appearance.iconEdit', 'Edit icon') }}</div>
2362
+ <button mat-stroked-button type="button" (click)="pickIcon('edit')" [attr.aria-label]="tx('editor.appearance.pickIconEdit', 'Choose the edit icon')">
1892
2363
  <mat-icon *ngIf="icons.edit; else pick3" [fontIcon]="icons.edit"></mat-icon>
1893
- <ng-template #pick3>Escolher</ng-template>
2364
+ <ng-template #pick3>{{ tx('editor.shared.pick', 'Choose') }}</ng-template>
1894
2365
  </button>
1895
2366
  </div>
1896
2367
  <div class="inline-action-item">
1897
- <div class="section-title">Ícone de erro</div>
1898
- <button mat-stroked-button type="button" (click)="pickIcon('error')" aria-label="Escolher ícone de erro">
2368
+ <div class="section-title">{{ tx('editor.appearance.iconError', 'Error icon') }}</div>
2369
+ <button mat-stroked-button type="button" (click)="pickIcon('error')" [attr.aria-label]="tx('editor.appearance.pickIconError', 'Choose the error icon')">
1899
2370
  <mat-icon *ngIf="icons.error; else pick4" [fontIcon]="icons.error"></mat-icon>
1900
- <ng-template #pick4>Escolher</ng-template>
2371
+ <ng-template #pick4>{{ tx('editor.shared.pick', 'Choose') }}</ng-template>
1901
2372
  </button>
1902
2373
  </div>
1903
2374
  </div>
1904
2375
  <div class="icons-hint" *ngIf="symbolsLikelySelected.length && !appearance.iconsSet">
1905
2376
  <div class="muted">
1906
- Dica: {{ symbolsLikelySelected.join(', ') }} são ícones do Material Symbols. Selecione um conjunto Symbols abaixo ou clique em
1907
- <button mat-button color="primary" type="button" (click)="setIconsSetToSymbols()">Usar Material Symbols (Outlined)</button>.
2377
+ {{ tx('editor.appearance.symbolsHint', 'Hint: {{icons}} are Material Symbols icons. Select a Symbols set below or click').replace('{{icons}}', symbolsLikelySelected.join(', ')) }}
2378
+ <button mat-button color="primary" type="button" (click)="setIconsSetToSymbols()">{{ tx('editor.appearance.useSymbols', 'Use Material Symbols (Outlined)') }}</button>.
1908
2379
  </div>
1909
2380
  </div>
1910
2381
  <div class="pdx-appearance-actions">
1911
- <button mat-stroked-button color="primary" type="button" (click)="applyPreset('neutral')">Preset: neutro</button>
1912
- <button mat-stroked-button color="primary" type="button" (click)="applyPreset('primary')">Preset: primário</button>
1913
- <button mat-stroked-button color="primary" type="button" (click)="applyPreset('high-contrast')">Preset: alto contraste</button>
1914
- <button mat-button type="button" (click)="clearTokens()">Limpar tokens</button>
2382
+ <button mat-stroked-button color="primary" type="button" (click)="applyPreset('neutral')">{{ tx('editor.appearance.presetNeutral', 'Preset: neutral') }}</button>
2383
+ <button mat-stroked-button color="primary" type="button" (click)="applyPreset('primary')">{{ tx('editor.appearance.presetPrimary', 'Preset: primary') }}</button>
2384
+ <button mat-stroked-button color="primary" type="button" (click)="applyPreset('high-contrast')">{{ tx('editor.appearance.presetHighContrast', 'Preset: high contrast') }}</button>
2385
+ <button mat-button type="button" (click)="clearTokens()">{{ tx('editor.appearance.clearTokens', 'Clear tokens') }}</button>
1915
2386
  </div>
1916
2387
  </div>
1917
2388
  <details class="disclosure">
1918
2389
  <summary>
1919
- <span class="section-title">Tokens avançados e snippet SCSS</span>
1920
- <span class="section-subtitle">Use quando precisar sair do ajuste rápido e controlar o tema com granularidade.</span>
2390
+ <span class="section-title">{{ tx('editor.appearance.advancedTitle', 'Advanced tokens and SCSS snippet') }}</span>
2391
+ <span class="section-subtitle">{{ tx('editor.appearance.advancedSubtitle', 'Use when you need to go beyond quick adjustments and control the theme with more granularity.') }}</span>
1921
2392
  </summary>
1922
2393
  <div class="disclosure-body">
1923
2394
  <div class="tokens-grid">
1924
2395
  <div class="token-item" *ngFor="let key of stepperTokenKeys">
1925
2396
  <mat-form-field appearance="outline" class="w-full">
1926
2397
  <mat-label>{{ key }}</mat-label>
1927
- <input matInput [ngModel]="appearance.tokens?.[key]" (ngModelChange)="onTokenChange(key, $event)" placeholder="valor CSS ou var(--token)" />
2398
+ <input matInput [ngModel]="appearance.tokens?.[key]" (ngModelChange)="onTokenChange(key, $event)" [placeholder]="tx('editor.appearance.tokenPlaceholder', 'CSS value or var(--token)')" />
1928
2399
  </mat-form-field>
1929
2400
  </div>
1930
2401
  </div>
1931
2402
  <div class="code-card">
1932
- <div class="code-head">Snippet SCSS</div>
2403
+ <div class="code-head">{{ tx('editor.appearance.scssSnippet', 'SCSS snippet') }}</div>
1933
2404
  <pre class="code"><code>{{ scssSnippet() }}</code></pre>
1934
2405
  </div>
1935
2406
  </div>
@@ -1956,101 +2427,101 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
1956
2427
  MatDialogModule,
1957
2428
  MatMenuModule,
1958
2429
  MatTabsModule,
1959
- ], template: `
2430
+ ], providers: [providePraxisStepperI18n()], template: `
1960
2431
  <div class="pdx-editor">
1961
2432
  <mat-tab-group>
1962
- <mat-tab label="Geral">
2433
+ <mat-tab [label]="tx('editor.tabs.general', 'General')">
1963
2434
  <div class="tab-pad">
1964
2435
  <div class="editor-intro">
1965
2436
  <div class="editor-intro-copy">
1966
- <div class="eyebrow">Fundamentos</div>
1967
- <div class="editor-title">Defina o comportamento base do stepper</div>
1968
- <div class="editor-subtitle">Ajuste orientação, densidade, animação e classes utilitárias sem misturar decisões estruturais com customização avançada.</div>
2437
+ <div class="eyebrow">{{ tx('editor.general.eyebrow', 'Foundations') }}</div>
2438
+ <div class="editor-title">{{ tx('editor.general.title', 'Define the base stepper behavior') }}</div>
2439
+ <div class="editor-subtitle">{{ tx('editor.general.subtitle', 'Adjust orientation, density, animation and utility classes without mixing structural decisions with advanced customization.') }}</div>
1969
2440
  </div>
1970
2441
  </div>
1971
2442
  <div class="settings-group">
1972
2443
  <div class="group-head">
1973
- <div class="section-title">Layout e navegação</div>
1974
- <div class="section-subtitle">Controla como as etapas aparecem e como o usuário percorre o fluxo.</div>
2444
+ <div class="section-title">{{ tx('editor.general.layoutTitle', 'Layout and navigation') }}</div>
2445
+ <div class="section-subtitle">{{ tx('editor.general.layoutSubtitle', 'Controls how steps appear and how the user moves through the flow.') }}</div>
1975
2446
  </div>
1976
2447
  <div class="pdx-grid">
1977
2448
  <mat-form-field appearance="outline">
1978
- <mat-label>Orientação</mat-label>
2449
+ <mat-label>{{ tx('editor.general.orientation', 'Orientation') }}</mat-label>
1979
2450
  <select matNativeControl [(ngModel)]="config.orientation" (ngModelChange)="markDirty()">
1980
- <option value="horizontal">Horizontal</option>
1981
- <option value="vertical">Vertical</option>
2451
+ <option value="horizontal">{{ tx('editor.general.orientation.horizontal', 'Horizontal') }}</option>
2452
+ <option value="vertical">{{ tx('editor.general.orientation.vertical', 'Vertical') }}</option>
1982
2453
  </select>
1983
2454
  </mat-form-field>
1984
2455
  <mat-form-field appearance="outline">
1985
- <mat-label>Posição dos títulos</mat-label>
2456
+ <mat-label>{{ tx('editor.general.headerPosition', 'Title position') }}</mat-label>
1986
2457
  <select matNativeControl [(ngModel)]="config.headerPosition" (ngModelChange)="markDirty()">
1987
- <option value="top">Acima</option>
1988
- <option value="bottom">Abaixo</option>
2458
+ <option value="top">{{ tx('editor.general.headerPosition.top', 'Above') }}</option>
2459
+ <option value="bottom">{{ tx('editor.general.headerPosition.bottom', 'Below') }}</option>
1989
2460
  </select>
1990
2461
  </mat-form-field>
1991
2462
  <mat-form-field appearance="outline">
1992
- <mat-label>Posição do rótulo</mat-label>
2463
+ <mat-label>{{ tx('editor.general.labelPosition', 'Label position') }}</mat-label>
1993
2464
  <select matNativeControl [(ngModel)]="config.labelPosition" (ngModelChange)="markDirty()" [disabled]="config.orientation !== 'horizontal'">
1994
- <option value="end">Ao lado</option>
1995
- <option value="bottom">Abaixo</option>
2465
+ <option value="end">{{ tx('editor.general.labelPosition.end', 'Beside') }}</option>
2466
+ <option value="bottom">{{ tx('editor.general.labelPosition.bottom', 'Below') }}</option>
1996
2467
  </select>
1997
2468
  </mat-form-field>
1998
2469
  <mat-form-field appearance="outline">
1999
- <mat-label>Densidade</mat-label>
2470
+ <mat-label>{{ tx('editor.general.density', 'Density') }}</mat-label>
2000
2471
  <select matNativeControl [(ngModel)]="config.density" (ngModelChange)="markDirty()">
2001
- <option [ngValue]="undefined">Padrão</option>
2002
- <option value="comfortable">Confortável</option>
2003
- <option value="compact">Compacta</option>
2472
+ <option [ngValue]="undefined">{{ tx('editor.general.density.default', 'Default') }}</option>
2473
+ <option value="comfortable">{{ tx('editor.general.density.comfortable', 'Comfortable') }}</option>
2474
+ <option value="compact">{{ tx('editor.general.density.compact', 'Compact') }}</option>
2004
2475
  </select>
2005
2476
  </mat-form-field>
2006
2477
  <mat-form-field appearance="outline">
2007
- <mat-label>Duração da animação</mat-label>
2008
- <input matInput [(ngModel)]="config.animationDuration" (ngModelChange)="markDirty()" placeholder="Ex.: 300ms" />
2478
+ <mat-label>{{ tx('editor.general.animationDuration', 'Animation duration') }}</mat-label>
2479
+ <input matInput [(ngModel)]="config.animationDuration" (ngModelChange)="markDirty()" [placeholder]="tx('editor.general.animationPlaceholder', 'e.g.: 300ms')" />
2009
2480
  </mat-form-field>
2010
2481
  <mat-form-field appearance="outline">
2011
- <mat-label>Etapa inicial</mat-label>
2482
+ <mat-label>{{ tx('editor.general.initialStep', 'Initial step') }}</mat-label>
2012
2483
  <input matInput type="number" [(ngModel)]="config.selectedIndex" (ngModelChange)="markDirty()" />
2013
2484
  </mat-form-field>
2014
2485
  </div>
2015
2486
  <div class="toggle-group">
2016
- <mat-slide-toggle [(ngModel)]="config.linear" (ngModelChange)="markDirty()">Respeitar ordem (linear)</mat-slide-toggle>
2017
- <mat-slide-toggle [(ngModel)]="config.disableRipple" (ngModelChange)="markDirty()">Desativar efeitos de clique</mat-slide-toggle>
2487
+ <mat-slide-toggle [(ngModel)]="config.linear" (ngModelChange)="markDirty()">{{ tx('editor.general.linear', 'Respect order (linear)') }}</mat-slide-toggle>
2488
+ <mat-slide-toggle [(ngModel)]="config.disableRipple" (ngModelChange)="markDirty()">{{ tx('editor.general.disableRipple', 'Disable click effects') }}</mat-slide-toggle>
2018
2489
  </div>
2019
2490
  </div>
2020
2491
  <details class="disclosure">
2021
2492
  <summary>
2022
- <span class="section-title">Classes e integração visual</span>
2023
- <span class="section-subtitle">Use apenas quando precisar aplicar CSS escopado no host.</span>
2493
+ <span class="section-title">{{ tx('editor.general.visualTitle', 'Classes and visual integration') }}</span>
2494
+ <span class="section-subtitle">{{ tx('editor.general.visualSubtitle', 'Use only when you need to apply scoped CSS on the host.') }}</span>
2024
2495
  </summary>
2025
2496
  <div class="detail-grid disclosure-body">
2026
2497
  <mat-form-field appearance="outline" class="field-span-2">
2027
- <mat-label>Classe do stepper</mat-label>
2028
- <input matInput [(ngModel)]="config.stepperClass" (ngModelChange)="markDirty()" placeholder="Ex.: meu-stepper" />
2498
+ <mat-label>{{ tx('editor.general.stepperClass', 'Stepper class') }}</mat-label>
2499
+ <input matInput [(ngModel)]="config.stepperClass" (ngModelChange)="markDirty()" [placeholder]="tx('editor.general.stepperClassPlaceholder', 'e.g.: my-stepper')" />
2029
2500
  </mat-form-field>
2030
2501
  <mat-form-field appearance="outline">
2031
- <mat-label>Classe do cabeçalho</mat-label>
2032
- <input matInput [(ngModel)]="config.headerClass" (ngModelChange)="markDirty()" placeholder="Ex.: stepper-header" />
2502
+ <mat-label>{{ tx('editor.general.headerClass', 'Header class') }}</mat-label>
2503
+ <input matInput [(ngModel)]="config.headerClass" (ngModelChange)="markDirty()" [placeholder]="tx('editor.general.headerClassPlaceholder', 'e.g.: stepper-header')" />
2033
2504
  </mat-form-field>
2034
2505
  <mat-form-field appearance="outline">
2035
- <mat-label>Classe do conteúdo</mat-label>
2036
- <input matInput [(ngModel)]="config.contentClass" (ngModelChange)="markDirty()" placeholder="Ex.: stepper-content" />
2506
+ <mat-label>{{ tx('editor.general.contentClass', 'Content class') }}</mat-label>
2507
+ <input matInput [(ngModel)]="config.contentClass" (ngModelChange)="markDirty()" [placeholder]="tx('editor.general.contentClassPlaceholder', 'e.g.: stepper-content')" />
2037
2508
  </mat-form-field>
2038
2509
  </div>
2039
2510
  </details>
2040
2511
  </div>
2041
2512
  </mat-tab>
2042
2513
 
2043
- <mat-tab label="Etapas">
2514
+ <mat-tab [label]="tx('editor.tabs.steps', 'Steps')">
2044
2515
  <div class="tab-pad">
2045
2516
  <div class="editor-intro">
2046
2517
  <div class="editor-intro-copy">
2047
- <div class="eyebrow">Estrutura do fluxo</div>
2048
- <div class="editor-title">Defina a narrativa de cada etapa</div>
2049
- <div class="editor-subtitle">Organize títulos, estados e conteúdo da etapa sem misturar configuração técnica com ações de montagem.</div>
2518
+ <div class="eyebrow">{{ tx('editor.steps.eyebrow', 'Flow structure') }}</div>
2519
+ <div class="editor-title">{{ tx('editor.steps.title', 'Define the narrative of each step') }}</div>
2520
+ <div class="editor-subtitle">{{ tx('editor.steps.subtitle', 'Organize titles, states and step content without mixing technical configuration with assembly actions.') }}</div>
2050
2521
  </div>
2051
2522
  <div class="editor-intro-meta">
2052
2523
  <div class="meta-pill">
2053
- <span class="meta-label">Etapas</span>
2524
+ <span class="meta-label">{{ tx('editor.steps.count', 'Steps') }}</span>
2054
2525
  <strong>{{ config.steps.length }}</strong>
2055
2526
  </div>
2056
2527
  </div>
@@ -2058,16 +2529,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2058
2529
  <div class="pdx-steps">
2059
2530
  <div class="pdx-steps-header">
2060
2531
  <div>
2061
- <div class="section-title">Mapa de etapas</div>
2062
- <div class="section-subtitle">Arraste para reordenar e selecione uma etapa para editar o conteúdo.</div>
2532
+ <div class="section-title">{{ tx('editor.steps.mapTitle', 'Step map') }}</div>
2533
+ <div class="section-subtitle">{{ tx('editor.steps.mapSubtitle', 'Drag to reorder and select a step to edit its content.') }}</div>
2063
2534
  </div>
2064
- <button mat-flat-button color="primary" (click)="addStep()"><mat-icon [praxisIcon]="'add'"></mat-icon>Adicionar etapa</button>
2535
+ <button mat-flat-button color="primary" (click)="addStep()"><mat-icon [praxisIcon]="'add'"></mat-icon>{{ tx('editor.steps.add', 'Add step') }}</button>
2065
2536
  </div>
2066
2537
  <div class="steps-workspace" *ngIf="activeStep as step; else noSteps">
2067
2538
  <div
2068
2539
  cdkDropList
2069
2540
  role="listbox"
2070
- aria-label="Lista de etapas"
2541
+ [attr.aria-label]="tx('editor.steps.listAria', 'Step list')"
2071
2542
  (cdkDropListDropped)="drop($event)"
2072
2543
  class="pdx-step-list">
2073
2544
  <div
@@ -2086,19 +2557,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2086
2557
  <div class="drag-handle" cdkDragHandle><mat-icon [praxisIcon]="'drag_indicator'"></mat-icon></div>
2087
2558
  <div class="step-summary">
2088
2559
  <div class="step-summary-head">
2089
- <div class="step-summary-index">Etapa {{ i + 1 }}</div>
2090
- <div class="step-summary-title">{{ s.label || 'Sem título' }}</div>
2560
+ <div class="step-summary-index">{{ stepIndexLabel(i) }}</div>
2561
+ <div class="step-summary-title">{{ s.label || tx('editor.steps.untitled', 'Untitled') }}</div>
2091
2562
  </div>
2092
- <div class="step-summary-sub">{{ s.id || 'Sem identificador' }}</div>
2563
+ <div class="step-summary-sub">{{ s.id || tx('editor.steps.noId', 'No identifier') }}</div>
2093
2564
  <div class="step-summary-flags">
2094
- <span class="summary-chip" *ngIf="s.optional">Opcional</span>
2095
- <span class="summary-chip" *ngIf="s.completed">Concluída</span>
2096
- <span class="summary-chip summary-chip-warn" *ngIf="s.hasError">Erro</span>
2097
- <span class="summary-chip" *ngIf="s.form">Formulário</span>
2565
+ <span class="summary-chip" *ngIf="s.optional">{{ tx('editor.steps.optional', 'Optional') }}</span>
2566
+ <span class="summary-chip" *ngIf="s.completed">{{ tx('editor.steps.completed', 'Completed') }}</span>
2567
+ <span class="summary-chip summary-chip-warn" *ngIf="s.hasError">{{ tx('editor.steps.error', 'Error') }}</span>
2568
+ <span class="summary-chip" *ngIf="s.form">{{ tx('editor.steps.form', 'Form') }}</span>
2098
2569
  </div>
2099
2570
  </div>
2100
2571
  <div class="pdx-actions">
2101
- <button mat-icon-button color="warn" (click)="removeStep(i); $event.stopPropagation()" matTooltip="Remover" [attr.aria-label]="'Remover etapa ' + (s.label || (i + 1))">
2572
+ <button mat-icon-button color="warn" (click)="removeStep(i); $event.stopPropagation()" [matTooltip]="tx('editor.steps.remove', 'Remove')" [attr.aria-label]="stepRemoveAria(s, i)">
2102
2573
  <mat-icon [praxisIcon]="'delete'"></mat-icon>
2103
2574
  </button>
2104
2575
  </div>
@@ -2108,52 +2579,52 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2108
2579
  <div class="pdx-active-step">
2109
2580
  <div class="hdr">
2110
2581
  <div class="active-step-head">
2111
- <div class="eyebrow">Etapa selecionada</div>
2112
- <div class="title">Editando: {{ step.label }}</div>
2113
- <div class="section-subtitle">Ajuste conteúdo principal primeiro. Configurações secundárias ficam recolhidas para reduzir ruído.</div>
2582
+ <div class="eyebrow">{{ tx('editor.steps.selectedEyebrow', 'Selected step') }}</div>
2583
+ <div class="title">{{ editingStepTitle(step) }}</div>
2584
+ <div class="section-subtitle">{{ tx('editor.steps.selectedSubtitle', 'Adjust the main content first. Secondary settings stay collapsed to reduce noise.') }}</div>
2114
2585
  </div>
2115
2586
  </div>
2116
2587
 
2117
2588
  <div class="section">
2118
- <div class="section-title">Dados principais</div>
2589
+ <div class="section-title">{{ tx('editor.steps.mainData', 'Main data') }}</div>
2119
2590
  <div class="detail-grid">
2120
2591
  <mat-form-field appearance="outline" class="field-span-2">
2121
- <mat-label>Título da etapa</mat-label>
2592
+ <mat-label>{{ tx('editor.steps.stepTitle', 'Step title') }}</mat-label>
2122
2593
  <input matInput [(ngModel)]="step.label" (ngModelChange)="markDirty()" />
2123
2594
  </mat-form-field>
2124
2595
  <mat-form-field appearance="outline">
2125
- <mat-label>Identificador</mat-label>
2596
+ <mat-label>{{ tx('editor.steps.identifier', 'Identifier') }}</mat-label>
2126
2597
  <input matInput [(ngModel)]="step.id" (ngModelChange)="markDirty()" />
2127
2598
  </mat-form-field>
2128
2599
  <mat-form-field appearance="outline">
2129
- <mat-label>Ícone ou estado</mat-label>
2130
- <input matInput [(ngModel)]="step.state" (ngModelChange)="markDirty()" placeholder="Ex.: number, done, edit" />
2600
+ <mat-label>{{ tx('editor.steps.iconOrState', 'Icon or state') }}</mat-label>
2601
+ <input matInput [(ngModel)]="step.state" (ngModelChange)="markDirty()" [placeholder]="tx('editor.steps.iconOrStatePlaceholder', 'e.g.: number, done, edit')" />
2131
2602
  </mat-form-field>
2132
2603
  <mat-form-field appearance="outline" class="field-span-2">
2133
- <mat-label>Mensagem de erro</mat-label>
2604
+ <mat-label>{{ tx('editor.steps.errorMessage', 'Error message') }}</mat-label>
2134
2605
  <input matInput [(ngModel)]="step.errorMessage" (ngModelChange)="markDirty()" />
2135
2606
  </mat-form-field>
2136
2607
  </div>
2137
2608
  <div class="toggle-group">
2138
- <mat-slide-toggle [(ngModel)]="step.optional" (ngModelChange)="markDirty()">Etapa opcional</mat-slide-toggle>
2139
- <mat-slide-toggle [(ngModel)]="step.editable" (ngModelChange)="markDirty()">Permitir voltar e editar</mat-slide-toggle>
2140
- <mat-slide-toggle [(ngModel)]="step.completed" (ngModelChange)="markDirty()">Marcar como concluída</mat-slide-toggle>
2141
- <mat-slide-toggle [(ngModel)]="step.hasError" (ngModelChange)="markDirty()">Marcar como com erro</mat-slide-toggle>
2609
+ <mat-slide-toggle [(ngModel)]="step.optional" (ngModelChange)="markDirty()">{{ tx('editor.steps.optionalToggle', 'Optional step') }}</mat-slide-toggle>
2610
+ <mat-slide-toggle [(ngModel)]="step.editable" (ngModelChange)="markDirty()">{{ tx('editor.steps.editableToggle', 'Allow going back and editing') }}</mat-slide-toggle>
2611
+ <mat-slide-toggle [(ngModel)]="step.completed" (ngModelChange)="markDirty()">{{ tx('editor.steps.completedToggle', 'Mark as completed') }}</mat-slide-toggle>
2612
+ <mat-slide-toggle [(ngModel)]="step.hasError" (ngModelChange)="markDirty()">{{ tx('editor.steps.errorToggle', 'Mark as error') }}</mat-slide-toggle>
2142
2613
  </div>
2143
2614
  </div>
2144
2615
 
2145
2616
  <details class="disclosure">
2146
2617
  <summary>
2147
- <span class="section-title">Acessibilidade e detalhes técnicos</span>
2148
- <span class="section-subtitle">Rótulos auxiliares e metadados menos usados.</span>
2618
+ <span class="section-title">{{ tx('editor.steps.accessibilityTitle', 'Accessibility and technical details') }}</span>
2619
+ <span class="section-subtitle">{{ tx('editor.steps.accessibilitySubtitle', 'Auxiliary labels and less-used metadata.') }}</span>
2149
2620
  </summary>
2150
2621
  <div class="detail-grid disclosure-body">
2151
2622
  <mat-form-field appearance="outline">
2152
- <mat-label>Texto alternativo</mat-label>
2623
+ <mat-label>{{ tx('editor.steps.altText', 'Alternative text') }}</mat-label>
2153
2624
  <input matInput [(ngModel)]="step.ariaLabel" (ngModelChange)="markDirty()" />
2154
2625
  </mat-form-field>
2155
2626
  <mat-form-field appearance="outline">
2156
- <mat-label>ID que descreve</mat-label>
2627
+ <mat-label>{{ tx('editor.steps.describedBy', 'Described-by ID') }}</mat-label>
2157
2628
  <input matInput [(ngModel)]="step.ariaLabelledby" (ngModelChange)="markDirty()" />
2158
2629
  </mat-form-field>
2159
2630
  </div>
@@ -2163,37 +2634,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2163
2634
  <div class="section editorial-section">
2164
2635
  <div class="section-head">
2165
2636
  <div>
2166
- <div class="section-title">Conteúdo editorial</div>
2167
- <div class="section-subtitle">Use blocos de apoio para contextualizar a etapa antes ou depois do formulário.</div>
2637
+ <div class="section-title">{{ tx('editor.steps.editorialTitle', 'Editorial content') }}</div>
2638
+ <div class="section-subtitle">{{ tx('editor.steps.editorialSubtitle', 'Use supporting blocks to contextualize the step before or after the form.') }}</div>
2168
2639
  </div>
2169
2640
  </div>
2170
2641
 
2171
2642
  <div class="zone-grid">
2172
2643
  <div class="zone-column">
2173
2644
  <div class="zone-head">
2174
- <div class="zone-title">Antes do formulário</div>
2645
+ <div class="zone-title">{{ tx('editor.steps.zoneBefore', 'Before form') }}</div>
2175
2646
  <div class="zone-actions">
2176
2647
  <span class="zone-count">{{ editorialBeforeWidgets(step).length }}</span>
2177
2648
  <button mat-stroked-button [matMenuTriggerFor]="beforeEditorialMenu">
2178
2649
  <mat-icon [praxisIcon]="'add'"></mat-icon>
2179
- Adicionar
2650
+ {{ tx('editor.steps.addBlock', 'Add') }}
2180
2651
  </button>
2181
2652
  <mat-menu #beforeEditorialMenu="matMenu">
2182
2653
  <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-benefits', 'before')">
2183
2654
  <mat-icon [praxisIcon]="'view_module'"></mat-icon>
2184
- Grade de benefícios
2655
+ {{ tx('editor.steps.widgetBenefits', 'Benefits grid') }}
2185
2656
  </button>
2186
2657
  <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-content', 'before')">
2187
2658
  <mat-icon [praxisIcon]="'article'"></mat-icon>
2188
- Bloco de conteúdo
2659
+ {{ tx('editor.steps.widgetContent', 'Content block') }}
2189
2660
  </button>
2190
2661
  <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-inline-notice', 'before')">
2191
2662
  <mat-icon [praxisIcon]="'info'"></mat-icon>
2192
- Aviso inline
2663
+ {{ tx('editor.steps.widgetNotice', 'Inline notice') }}
2193
2664
  </button>
2194
2665
  <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-divider', 'before')">
2195
2666
  <mat-icon [praxisIcon]="'horizontal_rule'"></mat-icon>
2196
- Divisor
2667
+ {{ tx('editor.steps.widgetDivider', 'Divider') }}
2197
2668
  </button>
2198
2669
  </mat-menu>
2199
2670
  </div>
@@ -2208,49 +2679,49 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2208
2679
  <div class="meta" *ngIf="widgetBlockId(w) as blockId">ID: {{ blockId }}</div>
2209
2680
  </div>
2210
2681
  <div class="actions">
2211
- <button mat-icon-button (click)="editWidget(w)" matTooltip="Editar bloco">
2682
+ <button mat-icon-button (click)="editWidget(w)" [matTooltip]="tx('editor.steps.editBlock', 'Edit block')">
2212
2683
  <mat-icon [praxisIcon]="'tune'"></mat-icon>
2213
2684
  </button>
2214
- <button mat-icon-button (click)="moveEditorialWidget(w, 'before', 'after')" matTooltip="Mover para depois do formulário">
2685
+ <button mat-icon-button (click)="moveEditorialWidget(w, 'before', 'after')" [matTooltip]="tx('editor.steps.moveAfter', 'Move after the form')">
2215
2686
  <mat-icon [praxisIcon]="'south'"></mat-icon>
2216
2687
  </button>
2217
- <button mat-icon-button (click)="duplicateEditorialWidget(w, 'before')" matTooltip="Duplicar bloco">
2688
+ <button mat-icon-button (click)="duplicateEditorialWidget(w, 'before')" [matTooltip]="tx('editor.steps.duplicateBlock', 'Duplicate block')">
2218
2689
  <mat-icon [praxisIcon]="'content_copy'"></mat-icon>
2219
2690
  </button>
2220
- <button mat-icon-button color="warn" (click)="removeEditorialWidget(w, 'before')" matTooltip="Remover bloco">
2691
+ <button mat-icon-button color="warn" (click)="removeEditorialWidget(w, 'before')" [matTooltip]="tx('editor.steps.removeBlock', 'Remove block')">
2221
2692
  <mat-icon [praxisIcon]="'delete'"></mat-icon>
2222
2693
  </button>
2223
2694
  </div>
2224
2695
  </div>
2225
- <div class="empty" *ngIf="!editorialBeforeWidgets(step).length">Nenhum bloco nesta zona.</div>
2696
+ <div class="empty" *ngIf="!editorialBeforeWidgets(step).length">{{ tx('editor.steps.emptyZone', 'No blocks in this zone.') }}</div>
2226
2697
  </div>
2227
2698
  </div>
2228
2699
 
2229
2700
  <div class="zone-column">
2230
2701
  <div class="zone-head">
2231
- <div class="zone-title">Depois do formulário</div>
2702
+ <div class="zone-title">{{ tx('editor.steps.zoneAfter', 'After form') }}</div>
2232
2703
  <div class="zone-actions">
2233
2704
  <span class="zone-count">{{ editorialAfterWidgets(step).length }}</span>
2234
2705
  <button mat-stroked-button [matMenuTriggerFor]="afterEditorialMenu">
2235
2706
  <mat-icon [praxisIcon]="'add'"></mat-icon>
2236
- Adicionar
2707
+ {{ tx('editor.steps.addBlock', 'Add') }}
2237
2708
  </button>
2238
2709
  <mat-menu #afterEditorialMenu="matMenu">
2239
2710
  <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-benefits', 'after')">
2240
2711
  <mat-icon [praxisIcon]="'view_module'"></mat-icon>
2241
- Grade de benefícios
2712
+ {{ tx('editor.steps.widgetBenefits', 'Benefits grid') }}
2242
2713
  </button>
2243
2714
  <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-content', 'after')">
2244
2715
  <mat-icon [praxisIcon]="'article'"></mat-icon>
2245
- Bloco de conteúdo
2716
+ {{ tx('editor.steps.widgetContent', 'Content block') }}
2246
2717
  </button>
2247
2718
  <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-inline-notice', 'after')">
2248
2719
  <mat-icon [praxisIcon]="'info'"></mat-icon>
2249
- Aviso inline
2720
+ {{ tx('editor.steps.widgetNotice', 'Inline notice') }}
2250
2721
  </button>
2251
2722
  <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-divider', 'after')">
2252
2723
  <mat-icon [praxisIcon]="'horizontal_rule'"></mat-icon>
2253
- Divisor
2724
+ {{ tx('editor.steps.widgetDivider', 'Divider') }}
2254
2725
  </button>
2255
2726
  </mat-menu>
2256
2727
  </div>
@@ -2265,46 +2736,46 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2265
2736
  <div class="meta" *ngIf="widgetBlockId(w) as blockId">ID: {{ blockId }}</div>
2266
2737
  </div>
2267
2738
  <div class="actions">
2268
- <button mat-icon-button (click)="editWidget(w)" matTooltip="Editar bloco">
2739
+ <button mat-icon-button (click)="editWidget(w)" [matTooltip]="tx('editor.steps.editBlock', 'Edit block')">
2269
2740
  <mat-icon [praxisIcon]="'tune'"></mat-icon>
2270
2741
  </button>
2271
- <button mat-icon-button (click)="moveEditorialWidget(w, 'after', 'before')" matTooltip="Mover para antes do formulário">
2742
+ <button mat-icon-button (click)="moveEditorialWidget(w, 'after', 'before')" [matTooltip]="tx('editor.steps.moveBefore', 'Move before the form')">
2272
2743
  <mat-icon [praxisIcon]="'north'"></mat-icon>
2273
2744
  </button>
2274
- <button mat-icon-button (click)="duplicateEditorialWidget(w, 'after')" matTooltip="Duplicar bloco">
2745
+ <button mat-icon-button (click)="duplicateEditorialWidget(w, 'after')" [matTooltip]="tx('editor.steps.duplicateBlock', 'Duplicate block')">
2275
2746
  <mat-icon [praxisIcon]="'content_copy'"></mat-icon>
2276
2747
  </button>
2277
- <button mat-icon-button color="warn" (click)="removeEditorialWidget(w, 'after')" matTooltip="Remover bloco">
2748
+ <button mat-icon-button color="warn" (click)="removeEditorialWidget(w, 'after')" [matTooltip]="tx('editor.steps.removeBlock', 'Remove block')">
2278
2749
  <mat-icon [praxisIcon]="'delete'"></mat-icon>
2279
2750
  </button>
2280
2751
  </div>
2281
2752
  </div>
2282
- <div class="empty" *ngIf="!editorialAfterWidgets(step).length">Nenhum bloco nesta zona.</div>
2753
+ <div class="empty" *ngIf="!editorialAfterWidgets(step).length">{{ tx('editor.steps.emptyZone', 'No blocks in this zone.') }}</div>
2283
2754
  </div>
2284
2755
  </div>
2285
2756
  </div>
2286
2757
  </div>
2287
2758
 
2288
2759
  <div class="section">
2289
- <div class="section-title">Formulário da etapa</div>
2760
+ <div class="section-title">{{ tx('editor.steps.formSectionTitle', 'Step form') }}</div>
2290
2761
  <div class="section-body">
2291
2762
  <ng-container *ngIf="step.form; else addFormBtn">
2292
2763
  <div class="form-row-card">
2293
2764
  <div class="form-row-main">
2294
2765
  <mat-icon [praxisIcon]="'dynamic_form'"></mat-icon>
2295
2766
  <div>
2296
- <div class="name">Formulário principal</div>
2767
+ <div class="name">{{ tx('editor.steps.mainFormTitle', 'Main form') }}</div>
2297
2768
  <div class="sub">{{ step.form.formId || step.id || '—' }}</div>
2298
2769
  </div>
2299
2770
  </div>
2300
2771
  <div class="form-row-actions">
2301
- <button mat-button (click)="editMainForm()"><mat-icon [praxisIcon]="'tune'"></mat-icon> Editar</button>
2302
- <button mat-button color="warn" (click)="removeMainForm()"><mat-icon [praxisIcon]="'delete'"></mat-icon> Remover</button>
2772
+ <button mat-button (click)="editMainForm()"><mat-icon [praxisIcon]="'tune'"></mat-icon>{{ tx('editor.steps.edit', 'Edit') }}</button>
2773
+ <button mat-button color="warn" (click)="removeMainForm()"><mat-icon [praxisIcon]="'delete'"></mat-icon>{{ tx('editor.steps.remove', 'Remove') }}</button>
2303
2774
  </div>
2304
2775
  </div>
2305
2776
  </ng-container>
2306
2777
  <ng-template #addFormBtn>
2307
- <button mat-stroked-button color="primary" (click)="addMainForm()"><mat-icon [praxisIcon]="'add'"></mat-icon> Adicionar formulário</button>
2778
+ <button mat-stroked-button color="primary" (click)="addMainForm()"><mat-icon [praxisIcon]="'add'"></mat-icon>{{ tx('editor.steps.addForm', 'Add form') }}</button>
2308
2779
  </ng-template>
2309
2780
  </div>
2310
2781
  </div>
@@ -2312,12 +2783,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2312
2783
  <div class="section">
2313
2784
  <div class="section-head">
2314
2785
  <div>
2315
- <div class="section-title">Componentes avançados</div>
2316
- <div class="section-subtitle">Atalhos para montar experiências mais ricas sem perder clareza no fluxo.</div>
2786
+ <div class="section-title">{{ tx('editor.steps.advancedTitle', 'Advanced components') }}</div>
2787
+ <div class="section-subtitle">{{ tx('editor.steps.advancedSubtitle', 'Shortcuts to assemble richer experiences without losing clarity in the flow.') }}</div>
2317
2788
  </div>
2318
2789
  <button mat-stroked-button (click)="openMoreComponents()">
2319
2790
  <mat-icon [praxisIcon]="'add'"></mat-icon>
2320
- Mais componentes
2791
+ {{ tx('editor.steps.moreComponents', 'More components') }}
2321
2792
  </button>
2322
2793
  </div>
2323
2794
  <div class="section-body">
@@ -2326,14 +2797,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2326
2797
  <div class="cta-head">
2327
2798
  <mat-icon [praxisIcon]="'account_tree'"></mat-icon>
2328
2799
  <div>
2329
- <div class="cta-title">Lista em árvore</div>
2330
- <div class="cta-desc">Dados hierárquicos com seleção simples.</div>
2800
+ <div class="cta-title">{{ tx('editor.steps.treeListTitle', 'Tree list') }}</div>
2801
+ <div class="cta-desc">{{ tx('editor.steps.treeListDesc', 'Hierarchical data with simple selection.') }}</div>
2331
2802
  </div>
2332
2803
  </div>
2333
2804
  <div class="cta-actions">
2334
2805
  <button mat-stroked-button (click)="addTreeList()">
2335
2806
  <mat-icon [praxisIcon]="'add'"></mat-icon>
2336
- Inserir árvore
2807
+ {{ tx('editor.steps.insertTree', 'Insert tree') }}
2337
2808
  </button>
2338
2809
  </div>
2339
2810
  </div>
@@ -2341,14 +2812,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2341
2812
  <div class="cta-head">
2342
2813
  <mat-icon [praxisIcon]="'swap_horiz'"></mat-icon>
2343
2814
  <div>
2344
- <div class="cta-title">Transferência de itens</div>
2345
- <div class="cta-desc">Mover itens entre listas para seleção múltipla.</div>
2815
+ <div class="cta-title">{{ tx('editor.steps.transferTitle', 'Item transfer') }}</div>
2816
+ <div class="cta-desc">{{ tx('editor.steps.transferDesc', 'Move items between lists for multi-selection.') }}</div>
2346
2817
  </div>
2347
2818
  </div>
2348
2819
  <div class="cta-actions">
2349
2820
  <button mat-stroked-button (click)="addTransferListQuick()">
2350
2821
  <mat-icon [praxisIcon]="'add'"></mat-icon>
2351
- Inserir transferência
2822
+ {{ tx('editor.steps.insertTransfer', 'Insert transfer') }}
2352
2823
  </button>
2353
2824
  </div>
2354
2825
  </div>
@@ -2356,14 +2827,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2356
2827
  <div class="cta-head">
2357
2828
  <mat-icon [praxisIcon]="'search'"></mat-icon>
2358
2829
  <div>
2359
- <div class="cta-title">Seleção com busca</div>
2360
- <div class="cta-desc">Seleção com busca local ou remota.</div>
2830
+ <div class="cta-title">{{ tx('editor.steps.searchTitle', 'Searchable selection') }}</div>
2831
+ <div class="cta-desc">{{ tx('editor.steps.searchDesc', 'Selection with local or remote search.') }}</div>
2361
2832
  </div>
2362
2833
  </div>
2363
2834
  <div class="cta-actions">
2364
2835
  <button mat-stroked-button (click)="addSearchableSelect()">
2365
2836
  <mat-icon [praxisIcon]="'add'"></mat-icon>
2366
- Inserir seletor
2837
+ {{ tx('editor.steps.insertSelector', 'Insert selector') }}
2367
2838
  </button>
2368
2839
  </div>
2369
2840
  </div>
@@ -2371,14 +2842,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2371
2842
  <div class="cta-head">
2372
2843
  <mat-icon [praxisIcon]="'upload_file'"></mat-icon>
2373
2844
  <div>
2374
- <div class="cta-title">Upload de arquivos</div>
2375
- <div class="cta-desc">Anexos com validação e fluxo de upload.</div>
2845
+ <div class="cta-title">{{ tx('editor.steps.uploadTitle', 'File upload') }}</div>
2846
+ <div class="cta-desc">{{ tx('editor.steps.uploadDesc', 'Attachments with validation and upload flow.') }}</div>
2376
2847
  </div>
2377
2848
  </div>
2378
2849
  <div class="cta-actions">
2379
2850
  <button mat-stroked-button (click)="addFilesUpload()">
2380
2851
  <mat-icon [praxisIcon]="'add'"></mat-icon>
2381
- Inserir upload
2852
+ {{ tx('editor.steps.insertUpload', 'Insert upload') }}
2382
2853
  </button>
2383
2854
  </div>
2384
2855
  </div>
@@ -2392,15 +2863,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2392
2863
  <div class="sub">{{ w.id }}</div>
2393
2864
  </div>
2394
2865
  <div class="actions">
2395
- <button mat-icon-button (click)="editWidget(w)" [disabled]="!canEditWidget(w)" matTooltip="Editar componente">
2866
+ <button mat-icon-button (click)="editWidget(w)" [disabled]="!canEditWidget(w)" [matTooltip]="tx('editor.steps.editComponent', 'Edit component')">
2396
2867
  <mat-icon [praxisIcon]="'tune'"></mat-icon>
2397
2868
  </button>
2398
- <button mat-icon-button color="warn" (click)="removeAdvancedWidget(w)" matTooltip="Remover componente">
2869
+ <button mat-icon-button color="warn" (click)="removeAdvancedWidget(w)" [matTooltip]="tx('editor.steps.removeComponent', 'Remove component')">
2399
2870
  <mat-icon [praxisIcon]="'delete'"></mat-icon>
2400
2871
  </button>
2401
2872
  </div>
2402
2873
  </div>
2403
- <div class="empty" *ngIf="!advancedWidgets(step).length">Nenhum componente avançado adicionado.</div>
2874
+ <div class="empty" *ngIf="!advancedWidgets(step).length">{{ tx('editor.steps.emptyAdvanced', 'No advanced components added.') }}</div>
2404
2875
  </div>
2405
2876
  </div>
2406
2877
  </div>
@@ -2409,88 +2880,88 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2409
2880
  </div>
2410
2881
  </div>
2411
2882
  <ng-template #noSteps>
2412
- <div class="muted">Nenhuma etapa definida.</div>
2883
+ <div class="muted">{{ tx('editor.steps.noSteps', 'No steps defined.') }}</div>
2413
2884
  </ng-template>
2414
2885
  </div>
2415
2886
  </mat-tab>
2416
2887
 
2417
- <mat-tab label="Navegação">
2888
+ <mat-tab [label]="tx('editor.navigation.tab', 'Navigation')">
2418
2889
  <div class="tab-pad">
2419
2890
  <div class="editor-intro">
2420
2891
  <div class="editor-intro-copy">
2421
- <div class="eyebrow">Ações padrão</div>
2422
- <div class="editor-title">Configure a navegação entre etapas</div>
2423
- <div class="editor-subtitle">Defina quando os botões padrão aparecem e como eles se apresentam visualmente no fluxo.</div>
2892
+ <div class="eyebrow">{{ tx('editor.navigation.eyebrow', 'Default actions') }}</div>
2893
+ <div class="editor-title">{{ tx('editor.navigation.title', 'Configure navigation between steps') }}</div>
2894
+ <div class="editor-subtitle">{{ tx('editor.navigation.subtitle', 'Define when default buttons appear and how they present visually in the flow.') }}</div>
2424
2895
  </div>
2425
2896
  </div>
2426
2897
  <div class="settings-group">
2427
2898
  <div class="group-head">
2428
- <div class="section-title">Comportamento dos botões</div>
2429
- <div class="section-subtitle">Aparência e alinhamento da navegação padrão do stepper.</div>
2899
+ <div class="section-title">{{ tx('editor.navigation.behaviorTitle', 'Button behavior') }}</div>
2900
+ <div class="section-subtitle">{{ tx('editor.navigation.behaviorSubtitle', 'Appearance and alignment of the default stepper navigation.') }}</div>
2430
2901
  </div>
2431
2902
  <div class="toggle-group">
2432
- <mat-slide-toggle [(ngModel)]="navigationCfg.visible" (ngModelChange)="markDirty()">Mostrar navegação padrão</mat-slide-toggle>
2903
+ <mat-slide-toggle [(ngModel)]="navigationCfg.visible" (ngModelChange)="markDirty()">{{ tx('editor.navigation.visible', 'Show default navigation') }}</mat-slide-toggle>
2433
2904
  </div>
2434
2905
  <div class="pdx-grid">
2435
2906
  <mat-form-field appearance="outline">
2436
- <mat-label>Estilo dos botões</mat-label>
2907
+ <mat-label>{{ tx('editor.navigation.variant', 'Button style') }}</mat-label>
2437
2908
  <select matNativeControl [(ngModel)]="navigationCfg.variant" (ngModelChange)="markDirty()" [disabled]="!navigationCfg.visible">
2438
- <option [ngValue]="undefined">Padrão (elevado)</option>
2439
- <option value="basic">Texto</option>
2440
- <option value="flat">Plano</option>
2441
- <option value="stroked">Contornado</option>
2442
- <option value="raised">Elevado</option>
2909
+ <option [ngValue]="undefined">{{ tx('editor.navigation.variant.default', 'Default (raised)') }}</option>
2910
+ <option value="basic">{{ tx('editor.navigation.variant.basic', 'Text') }}</option>
2911
+ <option value="flat">{{ tx('editor.navigation.variant.flat', 'Flat') }}</option>
2912
+ <option value="stroked">{{ tx('editor.navigation.variant.stroked', 'Stroked') }}</option>
2913
+ <option value="raised">{{ tx('editor.navigation.variant.raised', 'Raised') }}</option>
2443
2914
  </select>
2444
2915
  </mat-form-field>
2445
2916
  <mat-form-field appearance="outline">
2446
- <mat-label>Cor</mat-label>
2917
+ <mat-label>{{ tx('editor.navigation.color', 'Color') }}</mat-label>
2447
2918
  <select matNativeControl [(ngModel)]="navigationCfg.color" (ngModelChange)="markDirty()" [disabled]="!navigationCfg.visible">
2448
- <option [ngValue]="undefined">Padrão</option>
2449
- <option value="primary">Primária</option>
2450
- <option value="accent">Acento</option>
2451
- <option value="warn">Alerta</option>
2919
+ <option [ngValue]="undefined">{{ tx('editor.navigation.color.default', 'Default') }}</option>
2920
+ <option value="primary">{{ tx('editor.navigation.color.primary', 'Primary') }}</option>
2921
+ <option value="accent">{{ tx('editor.navigation.color.accent', 'Accent') }}</option>
2922
+ <option value="warn">{{ tx('editor.navigation.color.warn', 'Warn') }}</option>
2452
2923
  </select>
2453
2924
  </mat-form-field>
2454
2925
  <mat-form-field appearance="outline">
2455
- <mat-label>Alinhamento</mat-label>
2926
+ <mat-label>{{ tx('editor.navigation.align', 'Alignment') }}</mat-label>
2456
2927
  <select matNativeControl [(ngModel)]="navigationCfg.align" (ngModelChange)="markDirty()" [disabled]="!navigationCfg.visible">
2457
- <option [ngValue]="undefined">Direita</option>
2458
- <option value="start">Esquerda</option>
2459
- <option value="center">Centro</option>
2460
- <option value="space-between">Espaçado</option>
2461
- <option value="end">Direita</option>
2928
+ <option [ngValue]="undefined">{{ tx('editor.navigation.align.default', 'Right') }}</option>
2929
+ <option value="start">{{ tx('editor.navigation.align.start', 'Left') }}</option>
2930
+ <option value="center">{{ tx('editor.navigation.align.center', 'Center') }}</option>
2931
+ <option value="space-between">{{ tx('editor.navigation.align.spaceBetween', 'Spaced') }}</option>
2932
+ <option value="end">{{ tx('editor.navigation.align.end', 'Right') }}</option>
2462
2933
  </select>
2463
2934
  </mat-form-field>
2464
2935
  </div>
2465
2936
  </div>
2466
2937
  <div class="settings-group">
2467
2938
  <div class="group-head">
2468
- <div class="section-title">Rótulos e ícones</div>
2469
- <div class="section-subtitle">Ajuste a cópia e os ícones usados nas ações de voltar e avançar.</div>
2939
+ <div class="section-title">{{ tx('editor.navigation.labelsTitle', 'Labels and icons') }}</div>
2940
+ <div class="section-subtitle">{{ tx('editor.navigation.labelsSubtitle', 'Adjust the copy and icons used in back and next actions.') }}</div>
2470
2941
  </div>
2471
2942
  <div class="pdx-grid">
2472
2943
  <mat-form-field appearance="outline">
2473
- <mat-label>Texto do botão Voltar</mat-label>
2474
- <input matInput [(ngModel)]="navigationCfg.prevLabel" (ngModelChange)="markDirty()" placeholder="Ex.: Voltar" [disabled]="!navigationCfg.visible" />
2944
+ <mat-label>{{ tx('editor.navigation.prevLabel', 'Back button text') }}</mat-label>
2945
+ <input matInput [(ngModel)]="navigationCfg.prevLabel" (ngModelChange)="markDirty()" [placeholder]="tx('editor.navigation.prevPlaceholder', 'e.g.: Back')" [disabled]="!navigationCfg.visible" />
2475
2946
  </mat-form-field>
2476
2947
  <mat-form-field appearance="outline">
2477
- <mat-label>Texto do botão Próximo</mat-label>
2478
- <input matInput [(ngModel)]="navigationCfg.nextLabel" (ngModelChange)="markDirty()" placeholder="Ex.: Próximo" [disabled]="!navigationCfg.visible" />
2948
+ <mat-label>{{ tx('editor.navigation.nextLabel', 'Next button text') }}</mat-label>
2949
+ <input matInput [(ngModel)]="navigationCfg.nextLabel" (ngModelChange)="markDirty()" [placeholder]="tx('editor.navigation.nextPlaceholder', 'e.g.: Next')" [disabled]="!navigationCfg.visible" />
2479
2950
  </mat-form-field>
2480
2951
  </div>
2481
2952
  <div class="inline-actions-grid">
2482
2953
  <div class="inline-action-item">
2483
- <div class="section-title">Ícone de Voltar</div>
2484
- <button mat-stroked-button type="button" (click)="pickNavIcon('prevIcon')" [disabled]="!navigationCfg.visible" aria-label="Escolher ícone do botão Voltar">
2954
+ <div class="section-title">{{ tx('editor.navigation.prevIcon', 'Back icon') }}</div>
2955
+ <button mat-stroked-button type="button" (click)="pickNavIcon('prevIcon')" [disabled]="!navigationCfg.visible" [attr.aria-label]="tx('editor.navigation.pickPrevIcon', 'Choose the Back button icon')">
2485
2956
  <mat-icon *ngIf="navigationCfg.prevIcon" [fontIcon]="navigationCfg.prevIcon"></mat-icon>
2486
- <ng-container *ngIf="!navigationCfg.prevIcon">Escolher</ng-container>
2957
+ <ng-container *ngIf="!navigationCfg.prevIcon">{{ tx('editor.shared.pick', 'Choose') }}</ng-container>
2487
2958
  </button>
2488
2959
  </div>
2489
2960
  <div class="inline-action-item">
2490
- <div class="section-title">Ícone de Próximo</div>
2491
- <button mat-stroked-button type="button" (click)="pickNavIcon('nextIcon')" [disabled]="!navigationCfg.visible" aria-label="Escolher ícone do botão Próximo">
2961
+ <div class="section-title">{{ tx('editor.navigation.nextIcon', 'Next icon') }}</div>
2962
+ <button mat-stroked-button type="button" (click)="pickNavIcon('nextIcon')" [disabled]="!navigationCfg.visible" [attr.aria-label]="tx('editor.navigation.pickNextIcon', 'Choose the Next button icon')">
2492
2963
  <mat-icon *ngIf="navigationCfg.nextIcon" [fontIcon]="navigationCfg.nextIcon"></mat-icon>
2493
- <ng-container *ngIf="!navigationCfg.nextIcon">Escolher</ng-container>
2964
+ <ng-container *ngIf="!navigationCfg.nextIcon">{{ tx('editor.shared.pick', 'Choose') }}</ng-container>
2494
2965
  </button>
2495
2966
  </div>
2496
2967
  </div>
@@ -2498,47 +2969,47 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2498
2969
  </div>
2499
2970
  </mat-tab>
2500
2971
 
2501
- <mat-tab label="Aparência">
2972
+ <mat-tab [label]="tx('editor.appearance.tab', 'Appearance')">
2502
2973
  <div class="tab-pad">
2503
2974
  <div class="editor-intro">
2504
2975
  <div class="editor-intro-copy">
2505
- <div class="eyebrow">Tema visual</div>
2506
- <div class="editor-title">Personalize aparência sem perder consistência</div>
2507
- <div class="editor-subtitle">Comece pelos ajustes rápidos. Tokens e snippet SCSS ficam recolhidos para cenários avançados.</div>
2976
+ <div class="eyebrow">{{ tx('editor.appearance.eyebrow', 'Visual theme') }}</div>
2977
+ <div class="editor-title">{{ tx('editor.appearance.title', 'Customize appearance without losing consistency') }}</div>
2978
+ <div class="editor-subtitle">{{ tx('editor.appearance.subtitle', 'Start with the quick adjustments. Tokens and the SCSS snippet stay collapsed for advanced scenarios.') }}</div>
2508
2979
  </div>
2509
2980
  </div>
2510
2981
  <div class="settings-group">
2511
2982
  <div class="group-head">
2512
- <div class="section-title">Ajustes rápidos</div>
2513
- <div class="section-subtitle">Controles mais comuns para tamanho, peso tipográfico e tema.</div>
2983
+ <div class="section-title">{{ tx('editor.appearance.quickTitle', 'Quick adjustments') }}</div>
2984
+ <div class="section-subtitle">{{ tx('editor.appearance.quickSubtitle', 'Most common controls for sizing, typography weight and theme.') }}</div>
2514
2985
  </div>
2515
2986
  <div class="quick-grid">
2516
2987
  <mat-form-field appearance="outline">
2517
- <mat-label>Altura do cabeçalho (px)</mat-label>
2518
- <input matInput type="number" [ngModel]="headerHeightPx" (ngModelChange)="setHeaderHeightPx($event)" placeholder="Ex.: 48" />
2988
+ <mat-label>{{ tx('editor.appearance.headerHeight', 'Header height (px)') }}</mat-label>
2989
+ <input matInput type="number" [ngModel]="headerHeightPx" (ngModelChange)="setHeaderHeightPx($event)" [placeholder]="tx('editor.appearance.headerHeightPlaceholder', 'e.g.: 48')" />
2519
2990
  </mat-form-field>
2520
2991
  <mat-form-field appearance="outline">
2521
- <mat-label>Tamanho do texto (px)</mat-label>
2522
- <input matInput type="number" [ngModel]="headerLabelTextSizePx" (ngModelChange)="setHeaderLabelTextSizePx($event)" placeholder="Ex.: 14" />
2992
+ <mat-label>{{ tx('editor.appearance.textSize', 'Text size (px)') }}</mat-label>
2993
+ <input matInput type="number" [ngModel]="headerLabelTextSizePx" (ngModelChange)="setHeaderLabelTextSizePx($event)" [placeholder]="tx('editor.appearance.textSizePlaceholder', 'e.g.: 14')" />
2523
2994
  </mat-form-field>
2524
2995
  <mat-form-field appearance="outline">
2525
- <mat-label>Peso do texto</mat-label>
2996
+ <mat-label>{{ tx('editor.appearance.textWeight', 'Text weight') }}</mat-label>
2526
2997
  <select matNativeControl [ngModel]="headerLabelTextWeight" (ngModelChange)="setHeaderLabelTextWeight($event)">
2527
- <option [ngValue]="undefined">Padrão</option>
2528
- <option value="400">Normal</option>
2529
- <option value="500">Médio</option>
2530
- <option value="600">Seminegrito</option>
2531
- <option value="700">Negrito</option>
2998
+ <option [ngValue]="undefined">{{ tx('editor.appearance.textWeight.default', 'Default') }}</option>
2999
+ <option value="400">{{ tx('editor.appearance.textWeight.400', 'Normal') }}</option>
3000
+ <option value="500">{{ tx('editor.appearance.textWeight.500', 'Medium') }}</option>
3001
+ <option value="600">{{ tx('editor.appearance.textWeight.600', 'Semibold') }}</option>
3002
+ <option value="700">{{ tx('editor.appearance.textWeight.700', 'Bold') }}</option>
2532
3003
  </select>
2533
3004
  </mat-form-field>
2534
3005
  <mat-form-field appearance="outline" class="field-span-2">
2535
- <mat-label>Classe de tema</mat-label>
2536
- <input matInput [(ngModel)]="appearance.themeClass" (ngModelChange)="onAppearanceChange()" placeholder="Ex.: theme-stepper-custom" />
3006
+ <mat-label>{{ tx('editor.appearance.themeClass', 'Theme class') }}</mat-label>
3007
+ <input matInput [(ngModel)]="appearance.themeClass" (ngModelChange)="onAppearanceChange()" [placeholder]="tx('editor.appearance.themeClassPlaceholder', 'e.g.: theme-stepper-custom')" />
2537
3008
  </mat-form-field>
2538
3009
  <mat-form-field appearance="outline">
2539
- <mat-label>Conjunto de ícones</mat-label>
3010
+ <mat-label>{{ tx('editor.appearance.iconSet', 'Icon set') }}</mat-label>
2540
3011
  <select matNativeControl [(ngModel)]="appearance.iconsSet" (ngModelChange)="onAppearanceChange()">
2541
- <option [ngValue]="undefined">Material Icons (padrão)</option>
3012
+ <option [ngValue]="undefined">{{ tx('editor.appearance.iconSet.default', 'Material Icons (default)') }}</option>
2542
3013
  <option value="material-symbols-outlined">Material Symbols (Outlined)</option>
2543
3014
  <option value="material-symbols-rounded">Material Symbols (Rounded)</option>
2544
3015
  <option value="material-symbols-sharp">Material Symbols (Sharp)</option>
@@ -2547,63 +3018,63 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2547
3018
  </div>
2548
3019
  <div class="inline-actions-grid icon-picker-grid">
2549
3020
  <div class="inline-action-item">
2550
- <div class="section-title">Ícone do número</div>
2551
- <button mat-stroked-button type="button" (click)="pickIcon('number')" aria-label="Escolher ícone do número">
3021
+ <div class="section-title">{{ tx('editor.appearance.iconNumber', 'Number icon') }}</div>
3022
+ <button mat-stroked-button type="button" (click)="pickIcon('number')" [attr.aria-label]="tx('editor.appearance.pickIconNumber', 'Choose the number icon')">
2552
3023
  <mat-icon *ngIf="icons.number; else pick" [fontIcon]="icons.number"></mat-icon>
2553
- <ng-template #pick>Escolher</ng-template>
3024
+ <ng-template #pick>{{ tx('editor.shared.pick', 'Choose') }}</ng-template>
2554
3025
  </button>
2555
3026
  </div>
2556
3027
  <div class="inline-action-item">
2557
- <div class="section-title">Ícone concluído</div>
2558
- <button mat-stroked-button type="button" (click)="pickIcon('done')" aria-label="Escolher ícone de concluído">
3028
+ <div class="section-title">{{ tx('editor.appearance.iconDone', 'Completed icon') }}</div>
3029
+ <button mat-stroked-button type="button" (click)="pickIcon('done')" [attr.aria-label]="tx('editor.appearance.pickIconDone', 'Choose the completed icon')">
2559
3030
  <mat-icon *ngIf="icons.done; else pick2" [fontIcon]="icons.done"></mat-icon>
2560
- <ng-template #pick2>Escolher</ng-template>
3031
+ <ng-template #pick2>{{ tx('editor.shared.pick', 'Choose') }}</ng-template>
2561
3032
  </button>
2562
3033
  </div>
2563
3034
  <div class="inline-action-item">
2564
- <div class="section-title">Ícone edição</div>
2565
- <button mat-stroked-button type="button" (click)="pickIcon('edit')" aria-label="Escolher ícone de edição">
3035
+ <div class="section-title">{{ tx('editor.appearance.iconEdit', 'Edit icon') }}</div>
3036
+ <button mat-stroked-button type="button" (click)="pickIcon('edit')" [attr.aria-label]="tx('editor.appearance.pickIconEdit', 'Choose the edit icon')">
2566
3037
  <mat-icon *ngIf="icons.edit; else pick3" [fontIcon]="icons.edit"></mat-icon>
2567
- <ng-template #pick3>Escolher</ng-template>
3038
+ <ng-template #pick3>{{ tx('editor.shared.pick', 'Choose') }}</ng-template>
2568
3039
  </button>
2569
3040
  </div>
2570
3041
  <div class="inline-action-item">
2571
- <div class="section-title">Ícone de erro</div>
2572
- <button mat-stroked-button type="button" (click)="pickIcon('error')" aria-label="Escolher ícone de erro">
3042
+ <div class="section-title">{{ tx('editor.appearance.iconError', 'Error icon') }}</div>
3043
+ <button mat-stroked-button type="button" (click)="pickIcon('error')" [attr.aria-label]="tx('editor.appearance.pickIconError', 'Choose the error icon')">
2573
3044
  <mat-icon *ngIf="icons.error; else pick4" [fontIcon]="icons.error"></mat-icon>
2574
- <ng-template #pick4>Escolher</ng-template>
3045
+ <ng-template #pick4>{{ tx('editor.shared.pick', 'Choose') }}</ng-template>
2575
3046
  </button>
2576
3047
  </div>
2577
3048
  </div>
2578
3049
  <div class="icons-hint" *ngIf="symbolsLikelySelected.length && !appearance.iconsSet">
2579
3050
  <div class="muted">
2580
- Dica: {{ symbolsLikelySelected.join(', ') }} são ícones do Material Symbols. Selecione um conjunto Symbols abaixo ou clique em
2581
- <button mat-button color="primary" type="button" (click)="setIconsSetToSymbols()">Usar Material Symbols (Outlined)</button>.
3051
+ {{ tx('editor.appearance.symbolsHint', 'Hint: {{icons}} are Material Symbols icons. Select a Symbols set below or click').replace('{{icons}}', symbolsLikelySelected.join(', ')) }}
3052
+ <button mat-button color="primary" type="button" (click)="setIconsSetToSymbols()">{{ tx('editor.appearance.useSymbols', 'Use Material Symbols (Outlined)') }}</button>.
2582
3053
  </div>
2583
3054
  </div>
2584
3055
  <div class="pdx-appearance-actions">
2585
- <button mat-stroked-button color="primary" type="button" (click)="applyPreset('neutral')">Preset: neutro</button>
2586
- <button mat-stroked-button color="primary" type="button" (click)="applyPreset('primary')">Preset: primário</button>
2587
- <button mat-stroked-button color="primary" type="button" (click)="applyPreset('high-contrast')">Preset: alto contraste</button>
2588
- <button mat-button type="button" (click)="clearTokens()">Limpar tokens</button>
3056
+ <button mat-stroked-button color="primary" type="button" (click)="applyPreset('neutral')">{{ tx('editor.appearance.presetNeutral', 'Preset: neutral') }}</button>
3057
+ <button mat-stroked-button color="primary" type="button" (click)="applyPreset('primary')">{{ tx('editor.appearance.presetPrimary', 'Preset: primary') }}</button>
3058
+ <button mat-stroked-button color="primary" type="button" (click)="applyPreset('high-contrast')">{{ tx('editor.appearance.presetHighContrast', 'Preset: high contrast') }}</button>
3059
+ <button mat-button type="button" (click)="clearTokens()">{{ tx('editor.appearance.clearTokens', 'Clear tokens') }}</button>
2589
3060
  </div>
2590
3061
  </div>
2591
3062
  <details class="disclosure">
2592
3063
  <summary>
2593
- <span class="section-title">Tokens avançados e snippet SCSS</span>
2594
- <span class="section-subtitle">Use quando precisar sair do ajuste rápido e controlar o tema com granularidade.</span>
3064
+ <span class="section-title">{{ tx('editor.appearance.advancedTitle', 'Advanced tokens and SCSS snippet') }}</span>
3065
+ <span class="section-subtitle">{{ tx('editor.appearance.advancedSubtitle', 'Use when you need to go beyond quick adjustments and control the theme with more granularity.') }}</span>
2595
3066
  </summary>
2596
3067
  <div class="disclosure-body">
2597
3068
  <div class="tokens-grid">
2598
3069
  <div class="token-item" *ngFor="let key of stepperTokenKeys">
2599
3070
  <mat-form-field appearance="outline" class="w-full">
2600
3071
  <mat-label>{{ key }}</mat-label>
2601
- <input matInput [ngModel]="appearance.tokens?.[key]" (ngModelChange)="onTokenChange(key, $event)" placeholder="valor CSS ou var(--token)" />
3072
+ <input matInput [ngModel]="appearance.tokens?.[key]" (ngModelChange)="onTokenChange(key, $event)" [placeholder]="tx('editor.appearance.tokenPlaceholder', 'CSS value or var(--token)')" />
2602
3073
  </mat-form-field>
2603
3074
  </div>
2604
3075
  </div>
2605
3076
  <div class="code-card">
2606
- <div class="code-head">Snippet SCSS</div>
3077
+ <div class="code-head">{{ tx('editor.appearance.scssSnippet', 'SCSS snippet') }}</div>
2607
3078
  <pre class="code"><code>{{ scssSnippet() }}</code></pre>
2608
3079
  </div>
2609
3080
  </div>
@@ -3037,7 +3508,14 @@ class PraxisStepper {
3037
3508
  return v === false;
3038
3509
  }
3039
3510
  onChildWidgetEvent(stepIndex, wd, e) {
3040
- this.widgetEvent.emit({ stepIndex, stepId: this.steps()[stepIndex]?.id, sourceId: e.sourceId, output: e.output, payload: e.payload });
3511
+ this.widgetEvent.emit({
3512
+ ...e,
3513
+ path: [
3514
+ { kind: 'stepper', id: this.stepperId },
3515
+ { kind: 'step', id: this.steps()[stepIndex]?.id, index: stepIndex },
3516
+ ...(e.path || []),
3517
+ ],
3518
+ });
3041
3519
  }
3042
3520
  isStepEmpty(step) {
3043
3521
  const hasForm = !!step.form;
@@ -3403,7 +3881,7 @@ class PraxisStepper {
3403
3881
  >
3404
3882
  <mat-icon fontIcon="edit"></mat-icon>
3405
3883
  </button>
3406
- `, isInline: true, styles: [":host{display:block;position:relative}.praxis-stepper{width:100%;background:var(--md-sys-color-surface);border:1px solid var(--md-sys-color-outline-variant);border-radius:16px;padding:12px;box-shadow:var(--mat-elevation-level1)}.praxis-stepper.pdx-stepper-ft-light{background:transparent;border:none;border-radius:0;padding:0;box-shadow:none}:host(.density-compact) ::ng-deep .mat-step-header{min-height:36px}:host(.density-compact) .pdx-step-actions{padding-top:4px;gap:6px}:host(.density-comfortable) ::ng-deep .mat-step-header{min-height:44px}.pdx-step-content{padding:12px 4px 8px;color:var(--md-sys-color-on-surface)}.pdx-step-actions{display:flex;gap:8px;padding-top:8px}::ng-deep .praxis-stepper .mat-step-header{border-radius:999px;margin:4px 0;color:var(--md-sys-color-on-surface)}::ng-deep .praxis-stepper .mat-step-label{color:var(--md-sys-color-on-surface)}::ng-deep .praxis-stepper .mat-step-label.mat-step-label-selected{color:var(--md-sys-color-on-surface);font-weight:600}::ng-deep .praxis-stepper .mat-step-header.cdk-keyboard-focused,::ng-deep .praxis-stepper .mat-step-header.cdk-program-focused{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}::ng-deep .praxis-stepper .mat-step-icon{background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface)}::ng-deep .praxis-stepper .mat-step-icon-selected{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}::ng-deep .praxis-stepper .mat-step-icon-state-done{background:var(--md-sys-color-tertiary);color:var(--md-sys-color-on-tertiary)}::ng-deep .praxis-stepper .mat-step-icon-state-error{background:var(--md-sys-color-error);color:var(--md-sys-color-on-error)}::ng-deep .praxis-stepper .mat-stepper-horizontal-line{border-top-color:var(--md-sys-color-outline-variant)}::ng-deep .praxis-stepper .mat-stepper-vertical-line:before{border-left-color:var(--md-sys-color-outline-variant)}::ng-deep .pdx-stepper-ft-light .mat-stepper-horizontal{background:transparent;--mat-stepper-header-hover-state-layer-color: color-mix( in srgb, var(--md-sys-color-on-surface) 8%, transparent );--mat-stepper-header-focus-state-layer-color: transparent;--mat-stepper-header-hover-state-layer-shape: 14px;--mat-stepper-header-focus-state-layer-shape: 14px}::ng-deep .pdx-stepper-ft-light .mat-step-header{margin:0}::ng-deep .pdx-stepper-ft-light .mat-step-header .mat-step-header-ripple{display:none}::ng-deep .ft-stepper{background:transparent}.ft-stepper-content{padding:0}.ft-stepper-content .form-section{border:none;padding:0;background:transparent}.nav-align-start{justify-content:flex-start}.nav-align-center{justify-content:center}.nav-align-end{justify-content:flex-end}.nav-align-space-between{justify-content:space-between}.edit-fab{position:absolute;right:12px;bottom:12px;z-index:2}.stepper-ai-assistant{position:absolute;right:12px;bottom:72px;z-index:3}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: MatStepperModule }, { kind: "component", type: i2$1.MatStep, selector: "mat-step", inputs: ["color"], exportAs: ["matStep"] }, { kind: "directive", type: i2$1.MatStepLabel, selector: "[matStepLabel]" }, { kind: "component", type: i2$1.MatStepper, selector: "mat-stepper, mat-vertical-stepper, mat-horizontal-stepper, [matStepper]", inputs: ["disableRipple", "color", "labelPosition", "headerPosition", "animationDuration"], outputs: ["animationDone"], exportAs: ["matStepper", "matVerticalStepper", "matHorizontalStepper"] }, { kind: "directive", type: i2$1.MatStepperIcon, selector: "ng-template[matStepperIcon]", inputs: ["matStepperIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i6.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: i6.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisDynamicForm, selector: "praxis-dynamic-form", inputs: ["resourcePath", "resourceId", "editorialContext", "mode", "config", "schemaSource", "enableCustomization", "formId", "componentInstanceId", "layout", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "visibleGlobal", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "formReady", "valueChange", "syncCompleted", "initializationError", "loadingStateChange", "enableCustomizationChange", "customAction", "actionConfirmation", "schemaStatusChange", "fieldRenderError", "widgetEvent"] }, { kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent"], exportAs: ["dynamicWidgetLoader"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline", "tone"] }, { kind: "component", type: PraxisAiAssistantComponent, selector: "praxis-ai-assistant", inputs: ["adapter", "riskPolicy", "allowManualPatchEdit"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3884
+ `, isInline: true, styles: [":host{display:block;position:relative}.praxis-stepper{width:100%;background:var(--md-sys-color-surface);border:1px solid var(--md-sys-color-outline-variant);border-radius:16px;padding:12px;box-shadow:var(--mat-elevation-level1)}.praxis-stepper.pdx-stepper-ft-light{background:transparent;border:none;border-radius:0;padding:0;box-shadow:none}:host(.density-compact) ::ng-deep .mat-step-header{min-height:36px}:host(.density-compact) .pdx-step-actions{padding-top:4px;gap:6px}:host(.density-comfortable) ::ng-deep .mat-step-header{min-height:44px}.pdx-step-content{padding:12px 4px 8px;color:var(--md-sys-color-on-surface)}.pdx-step-actions{display:flex;gap:8px;padding-top:8px}::ng-deep .praxis-stepper .mat-step-header{border-radius:999px;margin:4px 0;color:var(--md-sys-color-on-surface)}::ng-deep .praxis-stepper .mat-step-label{color:var(--md-sys-color-on-surface)}::ng-deep .praxis-stepper .mat-step-label.mat-step-label-selected{color:var(--md-sys-color-on-surface);font-weight:600}::ng-deep .praxis-stepper .mat-step-header.cdk-keyboard-focused,::ng-deep .praxis-stepper .mat-step-header.cdk-program-focused{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}::ng-deep .praxis-stepper .mat-step-icon{background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface)}::ng-deep .praxis-stepper .mat-step-icon-selected{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}::ng-deep .praxis-stepper .mat-step-icon-state-done{background:var(--md-sys-color-tertiary);color:var(--md-sys-color-on-tertiary)}::ng-deep .praxis-stepper .mat-step-icon-state-error{background:var(--md-sys-color-error);color:var(--md-sys-color-on-error)}::ng-deep .praxis-stepper .mat-stepper-horizontal-line{border-top-color:var(--md-sys-color-outline-variant)}::ng-deep .praxis-stepper .mat-stepper-vertical-line:before{border-left-color:var(--md-sys-color-outline-variant)}::ng-deep .pdx-stepper-ft-light .mat-stepper-horizontal{background:transparent;--mat-stepper-header-hover-state-layer-color: color-mix( in srgb, var(--md-sys-color-on-surface) 8%, transparent );--mat-stepper-header-focus-state-layer-color: transparent;--mat-stepper-header-hover-state-layer-shape: 14px;--mat-stepper-header-focus-state-layer-shape: 14px}::ng-deep .pdx-stepper-ft-light .mat-step-header{margin:0}::ng-deep .pdx-stepper-ft-light .mat-step-header .mat-step-header-ripple{display:none}::ng-deep .ft-stepper{background:transparent}.ft-stepper-content{padding:0}.ft-stepper-content .form-section{border:none;padding:0;background:transparent}.nav-align-start{justify-content:flex-start}.nav-align-center{justify-content:center}.nav-align-end{justify-content:flex-end}.nav-align-space-between{justify-content:space-between}.edit-fab{position:absolute;right:12px;bottom:12px;z-index:2}.stepper-ai-assistant{position:absolute;right:12px;bottom:72px;z-index:3}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: MatStepperModule }, { kind: "component", type: i2$1.MatStep, selector: "mat-step", inputs: ["color"], exportAs: ["matStep"] }, { kind: "directive", type: i2$1.MatStepLabel, selector: "[matStepLabel]" }, { kind: "component", type: i2$1.MatStepper, selector: "mat-stepper, mat-vertical-stepper, mat-horizontal-stepper, [matStepper]", inputs: ["disableRipple", "color", "labelPosition", "headerPosition", "animationDuration"], outputs: ["animationDone"], exportAs: ["matStepper", "matVerticalStepper", "matHorizontalStepper"] }, { kind: "directive", type: i2$1.MatStepperIcon, selector: "ng-template[matStepperIcon]", inputs: ["matStepperIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i6.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: i6.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisDynamicForm, selector: "praxis-dynamic-form", inputs: ["resourcePath", "resourceId", "editorialContext", "mode", "config", "schemaSource", "enableCustomization", "formId", "componentInstanceId", "layout", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "visibleGlobal", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "formReady", "valueChange", "syncCompleted", "initializationError", "loadingStateChange", "enableCustomizationChange", "customAction", "actionConfirmation", "schemaStatusChange", "fieldRenderError", "widgetEvent"] }, { kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "ownerWidgetKey", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent", "widgetDiagnostic"], exportAs: ["dynamicWidgetLoader"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline", "tone"] }, { kind: "component", type: PraxisAiAssistantComponent, selector: "praxis-ai-assistant", inputs: ["adapter", "riskPolicy", "allowManualPatchEdit"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3407
3885
  }
3408
3886
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisStepper, decorators: [{
3409
3887
  type: Component,
@@ -3803,7 +4281,7 @@ const PRAXIS_STEPPER_COMPONENT_METADATA = {
3803
4281
  { name: 'selectionChange', type: 'any', label: 'Troca de seleção' },
3804
4282
  { name: 'selectedIndexChange', type: 'number', label: 'Índice selecionado (change)' },
3805
4283
  { name: 'animationDone', type: 'void', label: 'Animação concluída' },
3806
- { name: 'widgetEvent', type: '{ stepId?: string; stepIndex?: number; sourceId: string; output?: string; payload?: any }', label: 'Evento interno' },
4284
+ { name: 'widgetEvent', type: 'WidgetEventEnvelope', label: 'Evento interno' },
3807
4285
  { name: 'stepFormReady', type: '{ stepId?: string; stepIndex: number; event: FormReadyEvent }', label: 'Form ready (por etapa)' },
3808
4286
  { name: 'stepFormValueChange', type: '{ stepId?: string; stepIndex: number; event: FormValueChangeEvent }', label: 'Form value change (por etapa)' },
3809
4287
  ],