Working with Translation Files

Dynamics 365 Business Central is multi-language enabled, which means that you can display the user interface (UI) in different languages. In Dynamics 365 Business Central this is done using XLIFF files, which is a standardized format used for computer-based translations.

For an overview of how translations are applied, see Translations Overview.

Generating the XLIFF file

To add a new language to the extension that you have built, you must first enable the generation of XLIFF files. The XLIFF file extension is .xlf. The generated XLIFF file contains the strings that are specified in properties such as Caption, CaptionML, and Tooltip.

Note

To submit an app to AppSource, you must use XLIFF translation files.

In the app.json file of your extension, add the following line:

  "features": [ "TranslationFile" ]

Note

If the Incremental Build setting is enabled in the AL Language extension configuration then all translations will be ignored, even though the "features": [ "TranslationFile" ] setting is specified in the app.json file. For more information, see AL Language Extension Configuration. The same is true when using RAD publishing, then all translations will also be ignored. For more information, see Working with Rapid Application Development.

Now, when you run the build command (Ctrl+Shift+B) in Visual Studio Code, a \Translations folder will be generated and populated with the .xlf file that contains all the labels, label properties, and report labels that you are using in the extension. The generated .xlf file can now be translated.

Important

The ML versions of properties are not included in the .xlf file:

The TextConst Data Type is not included in the .xlf file either.

Important

Make sure to rename the translation file to avoid the file being overwritten the next time the extension is built.

By setting the GenerateCaptions flag in the app.json file, you specify that you want to generate captions based on the object name for pages, tables, reports, XMLports, request pages, and table fields. If the object already has a Caption property set, that value will be used, for table fields the OptionCaption is used. The syntax is the following:

  "features": [ "TranslationFile", "GenerateCaptions" ]

GenerateLockedTranslations

APPLIES TO: Business Central 2020 release wave 2 and later

By setting the GenerateLockedTranslations flag in the app.json file, you specify that you want to generate <trans-unit> elements for locked labels in the XLIFF file. The default behavior is that these elements are not generated. For more information, see JSON Files.

  "features": [ "GenerateLockedTranslations" ]

Label syntax

The label syntax is shown in the example below for the Caption property:

Caption = 'Developer translation for %1',  Comment = '%1 is extension name', locked = false, MaxLength=999; 

Note

The comment, locked, and maxLength attributes are optional and the order is not enforced. For more information, see Label Data Type.

Use the same syntax for report labels:

labels
{
  LabelName = 'Label Text', Comment='Foo', MaxLength=999, Locked=true;
} 

And the following is the syntax for Label data types:

var
    a : Label 'Label Text', Comment='Foo', MaxLength=999, Locked=true;

The XLIFF file

In the generated .xlf file, you can see a <source> element for each label. For the translation, you will now have to add the target-language and a <target> element per label. The target-language must be specified in the format "<language code>-<country code>", for example "da-DK", "es-ES", or "de-DE". The <trans-unit id> attribute corresponds to the object ID in the extension. This is illustrated in the example below.

<?xml version="1.0" encoding="utf-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
  <file datatype="xml" source-language="en-US" target-language="da-DK" original="ALProject16">
    <body>
      <group id="body">
        <trans-unit id="PageExtension 50110" maxWidth="999" size-unit="char" translate="yes" xml:space="preserve">
          <source>Developer translation for %1</source>
          <target>Udvikleroversættelse for %1</target>
          <note from="Developer" annotates="general" priority="2">%1 is extension name</note>
          <note from="Xliff Generator" annotates="general" priority="3">PageExtension - PageExtension</note>
        </trans-unit>
      </group>
    </body>
  </file>
</xliff>

Note

You can have only one .xlf file per language. If you translate your extension to multiple languages, you must have a translation file per language. There is no enforced naming on the file, but a suggested good practice is to name it <extensionname>.<language>.xlf.

When the extension is built and published, you change the language of Dynamics 365 Business Central to view the UI in the translated language.

Translating other extensions

To translate other extensions, for example, when adding translations to the Base Application, you must reference the project to be translated using the dependencies section in the app.json file. For more information, see JSON Files. When the dependencies are set, you can add xliff files in your current project that translates the object captions of the referenced extension. Create a directory named Translations in the root of the extension, and place the translated xliff file there. When your extension is then built and published, change the language of Dynamics 365 Business Central to view the UI in the translated language.

Note

When translating other extensions make sure that the attribute original in the <file> element in the xliff file is not set to the name of the current app, otherwise translations are only used to translate labels in the same app.

For apps where translations are meant to translate the current app, the generated xliff file will have the correct value of the app name.

Use the <trans-unit id> of the label where it was defined

In order to translate other apps, you must use the <trans-unit id> of the original property, not the one of an extension object, because that might have been modified.

If MyPage defined as:

page 50000 MyPage {
  Caption = 'Base Page'
}

has <trans-unit id> for the page corresponding to Page 2931038265 - Property 2879900210.

And the following page extension of MyPage called MyPageExtension:

pageextension 50000 MyPageExtension extends MyPage
{
    Caption = 'Extension Page';
}

has <trans-unit id> for the page extension corresponding to PageExtension 1716690578 - Property 2879900210, then if you want to change the caption on the page, you must use the ID Page 2931038265 - Property 2879900210, which is the <trans-unit id> of the original property.

See Also

Working with labels
Working with multiple AL project folders within one workspace
JSON Files