title: Angular i18n to generic form from array of objects
body: <p>I have a form that is created from an object I received from the API. To create this form I created an array of objects on the TS and then I make the loop and add the inputs/selects. The form is rendered correctly, but when I translate the application, this form doesn't is translated.</p>
  
  <pre><code>import { SpecializedAreasComponents } from 'src/app/models/SpecializedAreasComponent';
  import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
  
  @Component({
   selector: 'citation-constraint-form',
   templateUrl: './citation-constraint-form.component.html',
   styleUrls: ['./citation-constraint-form.component.scss'],
  })
  export class CitationConstraintFormComponent implements SpecializedAreasComponents, OnInit {
   form: FormGroup;
   @Input() data: any;
   @Output() output: EventEmitter&lt;any&gt; = new EventEmitter();
   @Input() errors: any = {};
   @Input() allowEdit;
   constraints: any = [];
   selectOne = [
       {
           value: '',
           description: 'Select One...',
       },
   ];
   bool = [
       ...this.selectOne,
       {
           description: 'Yes',
           value: true,
       },
       {
           description: 'No',
           value: false,
       },
   ];
   activitySectors = [
       ...this.selectOne,
       {
           value: 'industry',
           description: 'Industry',
       },
       {
           value: 'wholesale',
           description: 'Wholesale',
       },
       {
           value: 'retail',
           description: 'Retail',
       },
       {
           value: 'finalConsumer',
           description: 'Final Consumer',
       },
       {
           value: 'service',
           description: 'Service',
       },
       {
           value: 'ruralProducer',
           description: 'Rural Producer',
       },
       {
           value: 'generalWarehouse',
           description: 'General Warehouse',
       },
       {
           value: 'stockWarehouse',
           description: 'Stock Warehouse',
       },
       {
           value: 'transporter',
           description: 'Transporter',
       },
       {
           value: 'publicAgency',
           description: 'Public Agency',
       },
       {
           value: 'telco',
           description: 'Communication Service',
       },
       {
           value: 'importer',
           description: 'Importer',
       },
       {
           value: 'mealSupplier',
           description: 'Meal Supplier',
       },
       {
           value: 'coops',
           description: 'Cooperative',
       },
       {
           value: 'farmCoop',
           description: 'Farms Cooperative',
       },
       {
           value: 'transporter',
           description: 'Transporter',
       },
       {
           value: 'distributionCenter',
           description: 'Distribution Center',
       },
       {
           value: 'electricityDistributor',
           description: 'Electricity Distributor',
       },
       {
           value: 'fuelDistributor',
           description: 'Fuel Distributor',
       },
       {
           value: 'pharmaDistributor',
           description: 'Medication Distributor',
       },
       {
           value: 'waterDistributor',
           description: 'Water Dispenser',
       },
       {
           value: 'publicAgency',
           description: 'Orgao Publico',
       },
       {
           value: 'religiousEstablishment',
           description: 'Temples of Any Worship',
       },
       {
           value: 'itaipubiNacional',
           description: 'Itaipu Binacional',
       },
       {
           value: 'auctioneer',
           description: 'Auctioneer',
       },
   ];
   federalTaxRegimes = [
       {
           value: 'realProfit',
           description: 'Real profit',
       },
       {
           value: 'estimatedProfit',
           description: 'Estimated profit',
       },
       {
           value: 'simplified',
           description: 'Simplified',
       },
       {
           value: 'simplifiedOverGrossthreshold',
           description: 'Simplified over grossthreshold',
       },
       {
           value: 'simplifiedEntrepreneur',
           description: 'Simplified entrepreneur',
       },
       {
           value: 'notApplicable',
           description: 'Not applicable',
       },
       {
           value: 'individual',
           description: 'Individual',
       },
   ];
   entityTypes = [
       {
           value: 'business',
           description: 'Business',
       },
       {
           value: 'individual',
           description: 'Individual',
       },
       {
           value: 'federalGovernment',
           description: 'Federal government',
       },
       {
           value: 'stateGovernment',
           description: 'State government',
       },
       {
           value: 'cityGovernment',
           description: 'City government',
       },
       {
           value: 'foreign',
           description: 'Foreign',
       },
   ];
   specialProductClasses = [
       ...this.selectOne,
       {
           value: '1',
           description: 'SUS',
       },
       {
           value: '2',
           description: 'Órgão do Poder Executivo',
       },
       {
           value: '3',
           description: 'Bancos',
       },
       {
           value: '4',
           description: 'Comércio/Indústria',
       },
       {
           value: '5',
           description: 'Poder Legislativo/Judiciário',
       },
       {
           value: '0',
           description: 'Outro',
       },
   ];
   fiscalTypes = [
       ...this.selectOne,
       {
           value: 'FOR PRODUCT',
           description: 'For product',
       },
       {
           value: 'FOR MERCHANDISE',
           description: 'For merchandise',
       },
       {
           value: 'NO RESTRICTION',
           description: 'No restriction',
       },
       {
           value: 'SERVICE',
           description: 'Service',
       },
       {
           value: 'FEEDSTOCK',
           description: 'Feedstock',
       },
       {
           value: 'FIXED ASSETS',
           description: 'Fixed assets',
       },
       {
           value: 'PACKAGING',
           description: 'Packaging',
       },
       {
           value: 'PRODUCT IN PROCESS',
           description: 'Product in process',
       },
       {
           value: 'SUBPRODUCT',
           description: 'Subproduct',
       },
       {
           value: 'INTERMEDIATE PRODUCT',
           description: 'Intermediate product',
       },
       {
           value: 'MATERIAL FOR USAGE AND CONSUMPTION',
           description: 'Material for usage and consumption',
       },
       {
           value: 'OTHER INPUTS',
           description: 'Other inputs',
       },
   ];
   constraintsTypes = [
       {
           key: 'item',
           label: 'Item',
           type: 'text',
           ignore: false,
       },
       {
           key: 'unit',
           label: 'UNIT',
           type: 'text',
           ignore: false,
       },
       {
           key: 'lowerLimitAmount',
           label: 'Lower Limit Amount',
           type: 'number',
           ignore: false,
       },
       {
           key: 'upperLimitAmout',
           label: 'Upper Limit Amount',
           type: 'number',
       },
       {
           key: 'fiscalType',
           label: 'Fiscal Type',
           type: 'select',
           options: [...this.fiscalTypes],
           ignore: false,
       },
       {
           key: 'activitySectorListEmmiter',
           label: 'Activity Sector List Emmiter',
           type: 'select',
           options: [...this.activitySectors],
           ignore: false,
       },
       {
           key: 'activitySectorListReceiver',
           label: 'Activity Sector List Receiver',
           type: 'select',
           options: [...this.activitySectors],
           ignore: false,
       },
       {
           key: 'packaging',
           label: 'Packaging',
           type: 'text',
           ignore: false,
       },
       {
           key: 'supplementaryInformation',
           label: 'Supplementary Information',
           type: 'text',
           ignore: false,
       },
       {
           key: 'specialProductClass',
           label: 'Special Product Class',
           type: 'select',
           options: [...this.specialProductClasses],
           ignore: false,
       },
       {
           key: 'ceanTax',
           label: 'CEAN Taxable',
           type: 'text',
           ignore: false,
       },
       {
           key: 'icmsTaxPayer',
           label: 'ICMS Tax Payer',
           type: 'select',
           options: [...this.bool],
           ignore: false,
       },
       {
           key: 'subjectPayrollTaxRelief',
           label: 'Subject to Payroll Tax Relief',
           type: 'select',
           options: [...this.bool],
           ignore: false,
       },
       {
           key: 'federalTaxRegimeListReceiver',
           label: 'Federal Tax Regime',
           type: 'multiple',
           options: [...this.federalTaxRegimes],
           ignore: false,
       },
       {
           key: 'entityTypeListReceiver',
           label: 'Entity Type',
           type: 'multiple',
           options: [...this.entityTypes],
           ignore: false,
       },
   ];
   rows = [];
  
   constructor(private fb: FormBuilder) {
       this.form = this.fb.group({
           constraint: new FormGroup({
               item: new FormControl(''),
               unit: new FormControl(''),
               lowerLimitAmount: new FormControl(''),
               upperLimitAmout: new FormControl(''),
               fiscalType: new FormControl(''),
               activitySectorListEmmiter: new FormControl(''),
               activitySectorListReceiver: new FormControl(''),
               packaging: new FormControl(''),
               supplementaryInformation: new FormControl(''),
               specialProductClass: new FormControl(''),
               ceanTax: new FormControl(''),
               icmsTaxPayer: new FormControl(''),
               subjectPayrollTaxRelief: new FormControl(''),
               federalTaxRegimeListReceiver: new FormControl([]),
               entityTypeListReceiver: new FormControl([]),
           }),
       });
   }
  
   getDescFromKey(key) {
       return (
           {
               unit: 'UNIT',
               lowerLimitAmount: 'Lower Limit Amount',
               upperLimitAmount: 'Upper Limit Amount',
               fiscalType: 'Fiscal Type',
               activitySectorListEmmiter: 'Activity Sector List Emmiter',
               activitySectorListReceiver: 'Activity Sector List Receiver',
               packaging: 'Packaging',
               supplementaryInformation: 'Supplementary Information',
               specialProductClass: 'Special Product Class',
               ceanTax: 'CEAN Taxable',
               icmsTaxPayer: 'ICMS Tax Player',
               subjectPayrollTaxRelief: 'Subject to Payroll Tax Relief',
               federalTaxRegimeListReceiver: 'Federal Tax Regime',
               entityTypeListReceiver: 'Entity Type',
           }[key] || key
       );
   }
  
   updateForm(value) {
       if (
           value?.constraint?.federalTaxRegimeListReceiver &amp;&amp;
           value?.constraint?.federalTaxRegimeListReceiver[0]?.value &amp;&amp;
           !value?.constraint?.federalTaxRegimeListReceiver[0]?.description
       ) {
           value.constraint.federalTaxRegimeListReceiver = value.constraint.federalTaxRegimeListReceiver.map((ftr) =&gt; {
               return {
                   value: ftr.value,
                   description: this.getDescriptionForConstraintsTypes(ftr.value, 'federalTaxRegimeListReceiver'),
               };
           });
       }
       if (
           value?.constraint?.entityTypeListReceiver &amp;&amp;
           value?.constraint?.entityTypeListReceiver[0]?.value &amp;&amp;
           !value?.constraint?.entityTypeListReceiver[0]?.description
       ) {
           value.constraint.entityTypeListReceiver = value.constraint.entityTypeListReceiver.map((ftr) =&gt; {
               return {
                   value: ftr.value,
                   description: this.getDescriptionForConstraintsTypes(ftr.value, 'entityTypeListReceiver'),
               };
           });
       }
       this.form.patchValue(this.allowEdit ? value : { constraint: value });
   }
  
   getDescriptionForConstraintsTypes(value, type) {
       const list = type === 'entityTypeListReceiver' ? this.entityTypes : this.federalTaxRegimes;
  
       const option = list.find((o) =&gt; o.value === value);
  
       return option.description || '';
   }
  
   ngOnInit() {
       if (!this.allowEdit) this.form.disable();
       this.form.valueChanges.subscribe(() =&gt; this.output.emit(this.form.value));
       this.updateForm(this.data.constraint);
       this.constraintsTypes.map((constraint, i) =&gt; {
           const constr = {
               key: constraint.key,
               label: constraint.label,
               value: constraint.type === 'multiple' ? [] : '',
               type: constraint.type,
               options: constraint?.options || [],
           };
  
           if (i === 0) {
               this.rows.push([constr]);
           } else if (i % 3 === 0) {
               this.rows.push([constr]);
           } else {
               this.rows[this.rows.length - 1].push(constr);
           }
       });
   }
  
   extractArray(item) {
       if (Array.isArray(item)) {
           return item.map((a) =&gt; (typeof a === 'string' ? a : a.code));
       }
  
       return item;
   }
  }
  </code></pre>
  
  <pre><code>&lt;form [formGroup]="form"&gt;
    &lt;s-row class="pad-all-none" *ngFor="let row of rows" formGroupName="constraint"&gt;
      &lt;s-col span="4" *ngFor="let const of row"&gt;
        &lt;fieldset&gt;
          &lt;label [for]="const.key" i18n&gt;{{ const.label }}&lt;/label&gt;
          &lt;input
            [type]="const.type"
            [placeholder]="const.label"
            [formControlName]="const.key"
            [id]="const.key"
            *ngIf="const.type === 'text' || const.type === 'number'"
            [attr.disabled]="!allowEdit ? '' : null"
          /&gt;
          &lt;select
            [id]="const.key"
            [formControlName]="const.key"
            *ngIf="const.type === 'select'"
            [attr.disabled]="!allowEdit ? '' : null"
          &gt;
            &lt;option *ngFor="let option of const.options" value="{{ option?.value }}"&gt;
              {{ option.description }}
            &lt;/option&gt;
          &lt;/select&gt;
          &lt;kendo-multiselect
            [data]="const.options"
            [textField]="'description'"
            [valueField]="'value'"
            [id]="const.key"
            [formControlName]="const.key"
            [filterable]="true"
            [placeholder]="'Select Multiple'"
            *ngIf="const.type === 'multiple'"
            [attr.disabled]="!allowEdit ? '' : null"
          &gt;
          &lt;/kendo-multiselect&gt;
        &lt;/fieldset&gt;
      &lt;/s-col&gt;
    &lt;/s-row&gt;
  &lt;/form&gt;
  </code></pre>
  
  <p>Does anyone have any idea of how I can use the i18n here? </p>
  
  <p>Thank you.
  Lucas.</p>