A VSCode extension to keep XLIFF translation files in sync with an automatically generated base-XLIFF file.
Note that there is also an "XLIFF Sync" PowerShell module!
The "XLIFF Sync" extension for Visual Studio Code can help you work more efficiently with XLIFF translation files in various ways.
It is specifically targeted at easing translation of extensions for Microsoft Dynamics 365 Business Central, by allowing you to more easily keep .xlf
translation files of your extensions in sync with the .g.xlf
files that are automatically generated by the AL Language extension.
However, it can also be used in combination with other software projects that use XLIFF translation files for translation, supporting both XLIFF 1.2 and XLIFF 2.0.
Apart from synchronizing trans-units from a base-XLIFF file, this extension contributes various other features, including commands to check for missing translations, detect problems in translations and import translations from external XLIFF files.
View the demo in the Areopa webinar recording: VS Code AL Extensions - XLIFF Sync (starts at 6:16)
More information: XLIFF Sync: Time for a complete overview
- XLIFF Sync
- Summary
- Features
- Contributions
- Usage
- Known Issues
- Contributors
- Merge new translations from a generated, base-XLIFF file into existing XLIFF files.
- Merge from the base-XLIFF file into a manually specified target XLIFF file.
- Merge from the base-XLIFF file into all XLIFF files in the open workspace.
- Search and highlight missing translations in an open XLIFF file.
- Run technical validations to check for problems in the translations of target XLIFF files.
- Import/Copy translations for matching sources from external XLIFF files to target XLIFF files.
- Support for XLIFF 1.2 and 2.0
- Convert between XLIFF 1.2 and 2.0 format.
Command | Explanation |
---|---|
XLIFF: Create New Target File(s) | Create one or more new target XLIFF files from the base-XLIFF file. |
XLIFF: Synchronize to Single File | Merge new trans-units from base-XLIFF file into a manually specified target XLIFF file. |
XLIFF: Synchronize Translation Units | Merge new trans-units from base-XLIFF file into all other XLIFF files in the open project folder. |
XLIFF: Check for Missing Translations | Checks if there are any missing translations in the target XLIFF files in the open project folder. For each file with missing translations, an informational message will be shown (with a button to open the file externally). |
XLIFF: Check for Need Work Translations | Checks if there are translations that need work in the target XLIFF files in the open project folder. For example, the source text contains placeholders (e.g., "%1" or "{0}") while the translation does not. Translations with problems will be tagged with needs-adaptation and an "XLIFF Sync" note will be added to the trans-unit node. For each file with translations that need work, an informational message will be shown (with a button to open the file externally). |
XLIFF: Next Missing Translation | In an XLIFF file that is currently opened in the active editor, search for the next missing translation. |
XLIFF: Next Needs Work Translation | In an XLIFF file that is currently opened in the active editor, search for the next translation tagged as needs-adaptation . |
XLIFF: Import Translations from File(s) | Import/Copy translations from external XLIFF files to trans-units with matching sources of target XLIFF files with the same target-language. |
XLIFF: Build with Translations | Builds the project in the currently open workspace/project folder (Ctrl + Shift + B) and afterwards synchronizes all translation units from base-XLIFF file into all other XLIFF files in the open workspace/project folder. |
Setting | Default | Explanation |
---|---|---|
xliffSync.baseFile | .g.xlf |
Specifies which XLIFF file to use as the base (e.g., the generated XLIFF). If the file does not exist, you will be prompted to specify the file to use as base-XLIFF file the first time you use the Synchronize command. |
xliffSync.fileType | xlf |
The file type (xlf or xlf2 ). |
xliffSync.syncCrossWorkspaceFolders | false |
Specifies whether the extension will sync from a base file to the translation files in all workspace folders. By default, the extension will always sync. per workspace folder. If you enable this setting, then you can have the base file in one workspace folder and target translation files in other workspace folders. |
xliffSync.matchingOriginalOnly | true |
Specifies whether the extension will sync only to files where the original-attribute is matching. |
xliffSync.unitMaps | All |
Specifies for which search purposes this command should create in-memory maps in preparation of syncing. |
xliffSync.missingTranslation | %EMPTY% |
The placeholder for missing translations for trans-units that were synced/merged into target XLIFF files. You can use %EMPTY% if you want to use an empty string for missing translations. |
xliffSync.needsWorkTranslationSubstate | xliffSync:needsWork |
Specifies the substate to use for translations that need work in XLIFF 2.0 files. Tip: If you use Poedit, then you could also set this to poedit:fuzzy . |
xliffSync.findByXliffGeneratorNoteAndSource | true |
Specifies whether or not the extension will try to find trans-units by XLIFF generator note and source. |
xliffSync.findByXliffGeneratorAndDeveloperNote | true |
Specifies whether or not the extension will try to find trans-units by XLIFF generator note and developer note. |
xliffSync.findByXliffGeneratorNote | true |
Specifies whether or not the extension will try to find trans-units by XLIFF generator note. |
xliffSync.findBySourceAndDeveloperNote | false |
Specifies whether or not the extension will try to find translations by the combination of source and developer note. |
xliffSync.findBySource | false |
Specifies whether or not the extension will try to find translations by source. If there are multiple trans-units with the same source, then the translation of the first translation unit is used for all units. |
xliffSync.parseFromDeveloperNote | false |
Specifies whether translations should be parsed from the developer note. Translations can be retrieved from a Developer note in the following format: en-US=My translation|nl-NL=Mijn vertaling . |
xliffSync.parseFromDeveloperNoteOverwrite | false |
Specifies whether translations parsed from the developer note should always overwrite existing translations. |
xliffSync.parseFromDeveloperNoteSeparator | | |
Specifies the separator that is used when translations are parsed from the developer note. |
xliffSync.parseFromDeveloperNoteTrimCharacters | `` | Specifies the characters that will be trimmed from the translation. |
xliffSync.equivalentLanguages | { "de-DE": "de-.*", "en-US": "en-.*", "es-ES": "es-.*", "fr-FR": "fr-.*", "nl-NL": "nl-.*" } |
Specifies master and slave languages that should be treated as equivalent, i.e., translations are copied from the master language. |
xliffSync.equivalentLanguagesEnabled | false |
Specifies whether languages should be treated as equivalent as specified in the xliffSync.equivalentLanguages setting. |
xliffSync.copyFromSourceForLanguages | [] |
Specifies the languages for which translations should be copied from the source text of trans-units. |
xliffSync.copyFromSourceForSameLanguage | false |
Specifies whether translations should be copied from the source text if source-language = target-language. This will not overwrite existing translations of trans-units in target files. |
xliffSync.copyFromSourceOverwrite | false |
Specifies whether translations copied from the source text should overwrite existing translations. |
xliffSync.detectSourceTextChanges | true |
Specifies whether changes in the source text of a trans-unit should be detected. If a change is detected, the target state is changed to needs-adaptation and a note is added to indicate the translation should be reviewed. |
xliffSync.ignoreLineEndingTypeChanges | false |
Specifies whether changes in line ending type (CRLF vs. LF) should not be considered as changes to the source text of a trans-unit. |
xliffSync.clearTranslationAfterSourceTextChange | false |
Specifies whether translations should be cleared when the source text of a trans-unit changed. |
xliffSync.addNeedsWorkTranslationNote | true |
Specifies whether an XLIFF Sync note should be added to explain why a trans-unit was marked as needs-work. |
xliffSync.useSelfClosingTags | true |
Specifies whether the XML tags in the XLIFF target files should be self-closing tags. (i.e., <note></note> vs. <note/> ). |
xliffSync.keepEditorOpenAfterSync | true |
Specifies whether XLIFF files should be opened in the editor after syncing. |
xliffSync.openExternallyAfterEvent | [] |
Specifies after which event translation files should be opened automatically with the default XLIFF editor. Options: "Check", "ProblemDetected", "Sync" |
xliffSync.developerNoteDesignation | Developer |
Specifies the name that is used to designate a developer note. |
xliffSync.xliffGeneratorNoteDesignation | Xliff Generator |
Specifies the name that is used to designate a XLIFF generator note. |
xliffSync.autoCheckMissingTranslations | false |
Specifies whether or not the extension should automatically check for missing translations after syncing. |
xliffSync.autoCheckNeedWorkTranslations | false |
Specifies whether or not the extension should automatically run a technical validation on translations after syncing |
xliffSync.needWorkTranslationRules | ["OptionMemberCount", "OptionLeadingSpaces", "Placeholders"] |
Specifies which technical validation rules should be used. |
xliffSync.needWorkTranslationRulesEnableAll | false |
Specifies whether or not all available technical validation rules should be used. Enabling this setting makes xliffSync.needWorkTranslationRules redundant. |
xliffSync.preserveTargetAttributes | false |
Specifies whether or not syncing should use the attributes from the target files for the trans-unit nodes while syncing. |
xliffSync.preserveTargetAttributesOrder | false |
Specifies whether the attributes of trans-unit nodes should use the order found in the target files while syncing. |
xliffSync.preserveTargetChildNodes | false |
Specifies whether child nodes of trans-unit nodes specific to the target files should be preserved. This will preserve alt-trans nodes and custom nodes in XLIFF 1.2 target files. |
xliffSync.replaceTranslationsDuringImport | false |
Specifies whether existing translations will be replaced when the XLIFF: Import Translations from File(s) command is run. |
xliffSync.decoration | {"backgroundColor": "rgba(240, 210, 105, 0.35)", "overviewRulerColor": "rgba(240, 210, 105, 0.35)", "border": "1px solid white", "borderRadius": "4px"} |
Specifies how to highlight missing translations or translations that need work in an XLIFF file opened in the editor. |
xliffSync.decorationEnabled | true |
Specifies whether decorations for missing translations and translations that need work should be applied. |
xliffSync.decorationTargetTextOnly | false |
Specifies whether decorations for missing translations and translations that need work should only be applied to the target text. |
xliffSync.enableSnippetsForLanguages | [] |
Specifies the programming languages for which the XLIFF Sync snippets should be enabled. Currently supported: al . |
xliffSync.snippetTargetLanguage | TargetLanguageCode |
Specifies which target language to use by default in the XLIFF Sync snippets (e.g., nl-NL ). |
xliffSync.defaultLanguages | [] |
Specifies the languages that should automatically be used for the translation file generation. If empty, you will be prompted to select the languages to create translation files for. |
xliffSync.buildCommandToExecute | al.package |
Specifies the build command to execute when building with translations. |
The extension will try to find corresponding trans-units and translations within an existing file as follows:
-
Finding trans-units:
1. By Id
2. By XLIFF Generator Note & Source (enabled by default, configurable with
xliffSync.findByXliffGeneratorNoteAndSource
)3. By XLIFF Generator Note & Developer Note (enabled by default, configurable with
xliffSync.findByXliffGeneratorAndDeveloperNote
)4. By XLIFF Generator Note (enabled by default, configurable with
xliffSync.findByXliffGeneratorNote
) -
Finding translations:
5. By Source & Developer Note (disabled by default, configurable with
xliffSync.findBySourceAndDeveloperNote
)6. By Source (disabled by default, configurable with
xliffSync.findBySource
) -
Initial translation:
7. Parse from Developer Note (disabled by default, configurable with
xliffSync.parseFromDeveloperNote
)8. Copy from Source, if applicable/configured for target language (disabled by default, configurable with
xliffSync.copyFromSourceFor...
)
If no trans-unit or translation is found, the unit is added and its target node is tagged with state="needs-translation"
.
- F1 or Ctrl/Cmd + Shift + P to open the command palette
- XLIFF: Create New Target File(s)
This command will let you create one or more new target files, using the languages specified in the xliffSync.defaultLanguages
setting or when empty letting you choose from a set of RFC 4646 or RFC 5646 language tags depending on the XLIFF file type (i.e., xlf
or xlf2
).
The new file is automatically synced with the base file; if it is not known you will be prompted to specify the file to use as the base file first.
More detailed instruction: Create New Target Files
- F1 or Ctrl/Cmd + Shift + P to open the command palette
- XLIFF: Synchronize to Single File
- Alt + X, S (default shortcut)
By default, the extension expects the base-XLIFF file to end with .g.xlf
.
If no matching file is found, you are prompted to identify the base file.
This setting will be saved for future use.
If the extension is invoked from a localization file, that file will be updated, otherwise the extension will prompt you for the file to update.
You can also use this command to create a new XLIFF file for a language. For this, choose the "New File..." option and choose the language tag for the new target language.
- F1 or Ctrl/Cmd + Shift + P to open the command palette
- XLIFF: Synchronize Translation Units
NOTE: This command will merge new translations into all XLIFF files in your workspace folder (with, obviously, excluding the base-XLIFF file itself).
- Alt + X, M (default shortcut)
- Right-click on a file with the .xlf extension.
- Select: Synchronize Translation Units
If you select the base-XLIFF file, then translation units will be synced to all other XLIFF files in the workspace. If you select any other XLIFF file, then translation units will be synced from the base-XLIFF file to the selected file.
Here's a small demo:
More detailed instruction: Synchronize Translation Files
- F1 or Ctrl/Cmd + Shift + P to open the command palette
- XLIFF: Check for Missing Translations
This will check all XLIFF files in the workspace and notify about any missing translations in the files. You also have the option to open files with missing translations with your default XLIFF editor using the Open Externally button from the informational message.
More detailed instruction: Check Translation Files
- F1 or Ctrl/Cmd + Shift + P to open the command palette
- XLIFF: Check for Need Work Translations
This will run technical validation/checks for all XLIFF files in the workspace and notify about any translations that need work in the files. You also have the option to open files containing problems with your default XLIFF editor using the Open Externally button from the informational message.
The target node of the trans-units containing problems will be tagged with state="needs-adaptation"
.
Additionally, a note
will be added to the trans-unit to explain which problem was detected.
When you run the command again after resolving the issue, then this note will be automatically removed.
You can configure the checks that need to be run with the xliffSync.needWorkTranslationRules
setting.
The currently implemented checks are the following:
Rule ID | Check | Trigger | Example |
---|---|---|---|
ConsecutiveSpacesConsistent |
'Consecutive space'-occurrences are not matching. | N.A. | The source text includes 3 consecutive spaces, the translation text includes 2 consecutive spaces. |
ConsecutiveSpacesExist |
Source or translation text contain consecutive spaces. | N.A. | The source text includes 2 consecutive spaces, e.g., Hello World |
OptionMemberCount |
Number of options in caption are not matching. | Xliff Generator note with Property OptionCaption or Property PromotedActionCategories . |
The source text includes 3 options, A,B,C , but the translation text includes 4 options, A,B,C,D . |
OptionLeadingSpaces |
Number of leading spaces in options are not matching. | Xliff Generator note with Property OptionCaption or Property PromotedActionCategories . |
The source text includes a space, A, B , but the translation text does not, A,B . |
Placeholders |
Placeholders of source and translation are not matching. | Source/Translation text includes placeholders of the form {0} or %1 or #1 . |
The source text includes placeholders %1 %2 , but the translation text only includes %1 . |
PlaceholdersDevNote |
Placeholders are not explained in the Developer note. | Source text includes placeholders of the form {0} or %1 or #1 . |
The source text includes placeholders %1 %2 , but the Developer note is empty and so does not contain the placeholders. |
SourceEqualsTarget |
Source and translation are not the same, even though source-language = target-language for the .xlf file. | The source-language is the same as the target-language for the .xlf file. | The source text is 'A', but the translation text is 'B'. The source-language and target-language are both 'en-US'. |
Note: You may want to use rule SourceEqualsTarget
in combination with setting xliffSync.copyFromSourceForSameLanguage
set to true
.
More detailed instruction: Check Translation Files
- F1 or CMD + Shift + P to open the command palette
- XLIFF: Next Missing Translation
- Alt + X, N (default shortcut)
Missing translations are tagged and highlighted. You can use the extension to navigate between missing translations. On a Macbook Pro, this command appears on the touchbar within XLIFF files.
- F1 or CMD + Shift + P to open the command palette
- XLIFF: Next Needs Work Translation
- Alt + X, W (default shortcut)
Translations that need work are tagged and highlighted. You can use this command to navigate between translations that need work. On a Macbook Pro, this command appears on the touchbar within XLIFF files.
- F1 or Ctrl/Cmd + Shift + P to open the command palette
- XLIFF: Import Translations from File(s)
This will open a file dialog in which you can select one or more XLIFF files (.xlf). The command will copy translations from the selected files to trans-units in the XLIFF files in your project folder with the same target-language for matching sources. It will try first to merge translations for trans-units with a matching combination of source-text and Developer note, and only after that try to merge translations to trans-units with matching source-text. That way you could utilize the Developer note to have the import perform a more precise merge of the translations (e.g., based on tags in the Developer notes).
More detailed instruction: Import Translations from Files
- F1 or Ctrl/Cmd + Shift + P to open the command palette
- XLIFF: Build with Translations
- Ctrl + Shift + T (default shortcut)
This command combines multiple actions into one command:
- Build the project of the currently open project folder using the build command defined in the
xliffSync.buildCommandToExecute
setting. - If no .xlf translation files exists, then create new translation files (for the languages specified in the
xliffSync.defaultLanguages
setting). - Merge new translations into all XLIFF files in your workspace folder
If you would like to make XLIFF: Build with Translations your default build task, then this is one of the ways you can do that:
-
Run the command Tasks: Open Workspace/User Tasks via the command palette, or add/edit a
tasks.json
file at workspace/project folder level. -
Add the following task as default build task:
{ "version": "2.0.0", "tasks": [ { "label": "XLIFF: Build with Translations", "command": "${command:xliffSync.buildWithTranslations}", "problemMatcher": [], "group": { "kind": "build", "isDefault": true } } ] }
An approach that is taken by some app developers is to have the initial translation provided by the developers themselves (that is, for languages that they are proficient in, typically their mother tongue). This can be done by adding translations as a developer note/comment in the source code:
procedure MyProcedure()
var
DissapointDaveErr: Label 'I am afraid I can not do that, Dave', Comment = 'en-US=I am trepidacious I can not do that, Dave|nl-NL=Ik ben bang dat ik dat niet kan doen, Dave';
ExtremeMathMsg: Label 'One plus one = two', Comment = 'en-US=One plus one = TWO|nl-NL=Een plus een is twee|nl-BE=Een plus een is twee';
SatisfySamMsg: Label 'I hope you are satisfied, Sam', Comment = 'This is just a regular comment';
TerminateTimErr: Label 'Hasta la vista, Tim', Comment = 'nl-BE=Salut, Tim';
WorshipWillemMsg: Label 'Thank you Willem';
begin
Error(DissapointDaveErr);
end;
If you want to utilize this, the "XLIFF Sync" extension for Visual Studio code can help you to automatically get the translations provided by the developer in the comments to your target XLIFF translation files.
To let "XLIFF Sync" extract/parse translations from the Developer notes, you will need to set the xliffSync.parseFromDeveloperNote
setting to true
.
If you synchronize with this setting enabled, then the translations will be parsed from the Developer notes and added to the translation units in your target translation files.
If you would like the translations from the Developer notes to always overwrite the existing translations in the target translation files, then you can additionally set the xliffSync.parseFromDeveloperNoteOverwrite
setting to true
.
This is typically used in combination with xliffSync.detectSourceTextChanges
set to false
, if you wish that the translation states do not change to needs-adaptation
when the source text of translation units change.
On top of that, you can also enable snippets that help you adding captions, labels and tooltips with translation comments in your AL source code.
For this, you can set the xliffSync.enableSnippetsForLanguages
setting to ["al"]
and set xliffSync.snippetTargetLanguage
to your preferred language, e.g.:
{
"xliffSync.enableSnippetsForLanguages": ["al"],
"xliffSync.snippetTargetLanguage": "nl-NL"
}
You can then use snippets tcaptionwithtranslation
, tcommentwithtranslation
, toptioncaptionwithtranslation
, tpromotedactioncategorieswithtranslation
, tlabelwithtranslation
and ttooltipwithtranslation
to add translations in comments in your AL source code as follows:
For an extensive example, you can also check GitHub issue #37 "[Feature Request] Parsing Target from Comment".
- Automatically inserting new groups into target files is not implemented.
- The NAV2018 XLIFF generator creates Xliff Generator Notes without any identifiers, therefore it is recommended to change the
xliffSync.findBy...
settings to not synchronize trans-units based on Xliff Generator notes. - Files larger than 50 MB cannot be processed at the moment. For now, please use the "XLIFF Sync" PowerShell module instead.
You can find the contributions in the Changelog. Thank you all! 🤍