Translate

Saturday, August 27, 2022

🌐 Translating Text Dynamically at Runtime in Dynamics 365 F&O Using Google Translate API

In some business scenarios, you may need to display data in multiple languages dynamically on forms or reports in Microsoft Dynamics 365 Finance and Operations. While D365FO supports label-based translations, these are statically defined and managed through configurations. However, if the content is dynamic (like customer-entered data), label translations won’t suffice.

In such cases, you can use code to call external translation services—such as Google Translate API—at runtime. Below is a simple X++ example that demonstrates how to translate text between two languages (e.g., English to Hindi) using a web service.

✅ Use Case

Translate a string from English (en) to Hindi (hi) during runtime using a direct HTTP call to the Google Translate API.

💻 X++ Code Example

public static void main(Args _args)
{
    str inputStr = "Uma Mahesh";
    System.String downloadedString;
    int len, startPos, endPos;
    str translatedResult;
 
    // Construct Google Translate API URL
    str url = strFmt(
        "https://translate.googleapis.com/translate_a/single?client=gtx&sl=%1&tl=%2&dt=t&q=%3",
        "en", // Source language
        "hi", // Target language
    inputStr
    );
 
    // Use WebClient to download the JSON response from the API
    System.Net.WebClient webClient = new System.Net.WebClient();
    webClient.set_Encoding(System.Text.Encoding::get_UTF8());
    downloadedString = webClient.DownloadString(url);
 
    // Sample response: [[["उमा महेश","Uma Mahesh",null,null,3,null,null,[[]],[[["..."]]]]],null,"en",null,null,null,null,[]]
    // Parse translated text (first occurrence between double quotes)
    len = downloadedString.get_Length();
    startPos = strScan(downloadedString, '"', 1, len) + 1;
    endPos   = strScan(downloadedString, '"', startPos + 1, len) - startPos;
 
    translatedResult = subStr(downloadedString, startPos, endPos);
 
    info(strFmt("Translated Text: %1", translatedResult));
}

🧠 Key Points

  • URL Format: The URL is built using source and target language codes (sl, tl) and the text to translate (q).

  • System.Net.WebClient: We use .NET interop to make the web request and handle the UTF-8 encoded response.

  • Simple JSON Parsing: The API response is a nested JSON array. For this basic use case, we extract the first quoted string after parsing.

⚠️ Important Notes

  • This example uses the free version of the Google Translate API, which is undocumented and may be rate-limited. For production-grade applications, consider using the official Google Cloud Translation API with proper authentication.

  • For large-scale or real-time translation needs, also consider caching frequently translated values to reduce API calls.

✅ When to Use

  • You need to display dynamic content in multiple languages on a report or form.

  • Label-based translation is not feasible.

  • The translated content is runtime-dependent and needs external translation support.

Sunday, June 26, 2022

Fetching GST Amount from CustInvoiceLine in X++ Dynamics 365 FnO

 Recently, I was tasked with displaying the GST amount for a freetext invoice. In my source code at the backend, I only had access to the CustInvoiceLine Table, while the GST amounts are stored in the TaxTrans Table. Initially, I struggled to find a direct relationship between these two tables, as multiple tables are needed to establish a relation. However, after some research, I discovered that the CustInvoiceLine already has an out-of-the-box method, displayTaxAmount(), which returns the GST amount.

Please see the screenshot below for more details.






Thursday, January 27, 2022

How to Make a Specific Financial Dimension Read-Only Using X++ in D365 FnO On Form initializes

    public void init()
    {
        DimensionAttribute              dimAttr;
        DimensionAttributeSetStorage    dimStorage;
        DimensionEnumeration            editableDimensionSet;
 
        next init();
 
        dimStorage = new DimensionAttributeSetStorage();
   
        while select HashKey, RecId from dimAttr
            where dimAttr.Type != DimensionAttributeType::DynamicAccount
            &&    dimAttr.Type != DimensionAttributeType::MainAccount
            &&    dimAttr.Name != "Business Unit"
        {
            dimStorage.addItem(dimAttr.RecId, dimAttr.HashKey, NoYes::Yes);
        }
 
        editableDimensionSet = dimStorage.save();
 
        //Make Business unit readonly
        if(editableDimensionSet)
        {
            DimensionEntryControlTable.parmEditableDimensionSet(editableDimensionSet);
            DimensionEntryControlTable.allowEdit(true);
        }
    }