venerdì 15 aprile 2022

D365FFO - Gestione traduzioni

Gestire le traduzione di un testo in AX è un'operazione molto comune. Abbiamo a disposizione due framework. Il primo è quello che si appoggia sulla tabella LanguageTxt, già presente fin dalle primissime versioni; il secondo è quello che è stato introdotto sulla 2012 e si basa sulla classe SysTranslationHelper. In questo post vediamo come utilizzarli entrambe.

Allo scopo definiamo una tabella  codice,descrizione che chiameremo "LILtestTable" con la relativa form omonima.

1)LanguageTxt framework

Per prima cosa dobbiamo creare l'estensione della tabella LanguageTxt ed aggiungere la relation con la nostra tabella (possiamo copiare tutte le proprietà dalle relation già esistenti, si veda l'estensione  standard LanguageTxt.Extension) così:



A questo punto nella nostra form basta trascinare nel design il menù item display "LanguageTxt" ed impostare "LILTestTable"  nella proprietà "datasource".



Con questo metodo possiamo recuperare la traduzione:

 public static FreeTxt txt(  
     Voucher  _code,  
     LanguageId _languageId = CompanyInfo::languageId())  
 {  
      LILTestTable testTable = LILTestTable::find(_code);  
   
      LanguageTxt languageTxt = LanguageTxt::find(  
           testTable.TableId,  
           testTable.RecId,  
           _languageId);  
   
      return languageTxt.Txt ? languageTxt.Txt : testTable.Description;  
 }  

2)SysTranslationHelper framework

Dobbiamo creare una nuova tabella che chiameremo LILTestTableTranslation fatta così:


Questa nuova tabella và aggiunta come datasource alla form e messa in join deleayed con il datasource principale LILtestTable. Dobbiamo poi scrivere una classe fatta così:

 class LILTestTableTranslationHelper extends LedgerDimensionTranslationHelper  
 {  
   protected TableId getBackingEntityTranslationTableId()  
   {  
     return tableNum(LILTestTableTranslation);  
   }  
   
   protected Array getGetBackingEntityTranslatedFieldIds()  
   {  
     Array backingEntityTranslatedFieldIds;  
   
     backingEntityTranslatedFieldIds = new Array(Types::Integer);  
     backingEntityTranslatedFieldIds.value(1, fieldNum(LILTestTable, Description));  
   
     return backingEntityTranslatedFieldIds;  
   }  
   
   public static client void main(Args _args)  
   {  
     LILTestTableTranslationHelper TranslationHelper;  
   
     TranslationHelper = LILTestTableTranslationHelper::newFromArgs(_args);  
   
     TranslationHelper.launchTranslationDetailForm();  
   }  
   
   public static client LILTestTableTranslationHelper newFromArgs(Args _args)  
   {  
     LILTestTableTranslationHelper       TranslationHelper;  
     LILTestTable               LILTestTable;  
   
     if ( !(_args && _args.record() is LILTestTable))  
     {  
       throw error(strFmt("@SYS134996", tableStr(LILTestTable)));  
     }  
   
     LILTestTable = _args.record() as LILTestTable;  
   
     TranslationHelper = new LILTestTableTranslationHelper();  
     TranslationHelper.parmBackingEntity(LILTestTable);  
   
     return TranslationHelper;  
   }  
   
 }  

Ho preso la classe STD LedgerDimensionTranslationHelper perchè è una buona base generica che si presta molto all'estensione

Dobbiamo poi creare un menù item action che punta a questa classe ed inserirlo nel design della form:


Con questo metodo possiamo recuperare la traduzione:
 public Description localizedDescription(LanguageId _languageId = new xInfo().language())  
 {  
      Description       description;  
      LILTestTableTranslation translation;  
   
      if(this.RecId)  
      {  
           select firstonly translation  
           where translation.LILTestTable == this.RecId  
                && translation.Language == _languageId;  
             
           description = translation.Description;  
      }  
   
      if(!description)  
      {  
           description = this.Description;  
      }  
   
      return description;  
 }  

Conlusioni:
Come abbiamo visto il primo framework è molto più semplice del primo e di fatto non richiede codice.Lo svantaggio è che richiede di aggiungere ogni volta una nuova relation alla tabella languageTxt. 

Un vantaggio che ho riscontrato utilizzando il secondo framework (oltre ad essere più "user friendly")è che avendo una tabella dedicata risulta più semplice creare la relativa entity delle traduzioni