skill-translate

AL translation and localization for Business Central. Use when working with XLF files, NAB tools, or implementing multi-language support in extensions.

SKILL.md

GitHub

Skill: AL Translation Management

Purpose

Manage multilingual translations for AL extensions using XLF files: create and refresh language files, batch-translate with NAB AL Tools, preserve placeholders, enforce character limits, maintain terminology consistency, and implement quality review workflows.

When to Load

This skill should be loaded when:

  • A new target language needs to be added to an AL extension
  • Untranslated texts need to be translated after code changes
  • Translation quality review is needed (placeholder validation, character limits)
  • Regional language variations must be managed (es-ES vs es-MX)
  • Incremental translation is required after refreshing XLF files

Core Patterns

Pattern 1: Create Language File

Create a new XLF translation file from the generated source:

createLanguageXlf
  generatedXlfFilePath: "Translations/MyApp.g.xlf"
  targetLanguageCode: "es-ES"
  matchBaseAppTranslation: true    // pre-populate from Microsoft base translations

Rules:

  • The .g.xlf file is auto-generated by the AL compiler — never edit it manually
  • matchBaseAppTranslation: true copies existing Microsoft translations for standard terms
  • One language file per locale: MyApp.es-ES.xlf, MyApp.fr-FR.xlf, etc.

Pattern 2: Refresh and Retrieve Texts

After code changes, sync the language file and get new untranslated texts:

// Step 1: Refresh — adds new entries, preserves existing translations
refreshXlf
  generatedXlfFilePath: "Translations/MyApp.g.xlf"
  filePath: "Translations/MyApp.es-ES.xlf"

// Step 2: Get untranslated texts with context
getTextsToTranslate
  filePath: "Translations/MyApp.es-ES.xlf"
  limit: 50
  offset: 0

Each text entry includes:

  • id — unique identifier for the translation unit
  • source — original text to translate
  • type — context: Table Customer - Field Name - Property Caption
  • maxLength — character limit (if set in AL source)
  • comments — notes about placeholders (%1, %2)

Pattern 3: Batch Translation

Translate multiple texts in a single operation:

saveTranslatedTexts
  filePath: "Translations/MyApp.es-ES.xlf"
  translations: [
    {
      "id": "Table_ContosoProject_Field_Description_Caption",
      "targetText": "Descripción",
      "targetState": "translated"
    },
    {
      "id": "Page_ContosoProjectCard_Action_Release_Caption",
      "targetText": "Lanzar",
      "targetState": "translated"
    },
    {
      "id": "Codeunit_ContosoMgt_Error_CustomerNotFound",
      "targetText": "Cliente %1 no encontrado.",
      "targetState": "translated"
    }
  ]

Translation rules:

  1. Preserve placeholders — %1, %2, %3 must appear in the same order
  2. Respect maxLength — abbreviate if needed, never exceed
  3. Match context — same English word may have different translations depending on type
  4. Follow Microsoft terminology — use base app translations for standard BC terms

Pattern 4: Translation Quality Review

Use translation states to implement a review workflow:

State Meaning Who
translated Initial translation done Translator
needs-review-translation Flagged for review Translator / QA
final Reviewed and approved Reviewer
signed-off Production-ready Language lead
// Find texts needing review
getTranslatedTextsByState
  filePath: "Translations/MyApp.es-ES.xlf"
  translationStateFilter: "needs-review-translation"
  limit: 0

// After review, promote to final
saveTranslatedTexts
  filePath: "Translations/MyApp.es-ES.xlf"
  translations: [
    { "id": "...", "targetText": "...", "targetState": "final" }
  ]

Common quality issues:

// Issue 1: Missing placeholder
❌ Source: "Posted %1 of %2"
❌ Translation: "Registrado %2"         // missing %1
✅ Translation: "Registrado %1 de %2"

// Issue 2: Character limit exceeded
❌ Source: "Post" (maxLength: 10)
❌ Translation: "Registrar y contabilizar"  // 25 chars
✅ Translation: "Registrar"                 // 9 chars

// Issue 3: Context-dependent meaning
Source: "Post"
Context: Action caption → "Registrar" ✅
Context: Table name     → "Correo"    ✅  (different meaning!)

Pattern 5: Translation Memory and Glossary

Use existing translations for consistency:

// Get all translated texts as a reference map
getTranslatedTextsMap
  filePath: "Translations/MyApp.es-ES.xlf"
  limit: 0

// Search for specific terms across translations
getTextsByKeyword
  filePath: "Translations/MyApp.es-ES.xlf"
  keyword: "Customer|Vendor|Invoice"
  isRegex: true
  caseSensitive: false
  searchInTarget: true

Glossary approach:

  • Before translating a batch, retrieve existing translations with getTranslatedTextsMap
  • Search for related terms with getTextsByKeyword to ensure consistent terminology
  • Standard BC terms should match Microsoft's official base app translations

Pattern 6: Regional Variations

Manage locale-specific translations (e.g., es-ES vs es-MX):

// Step 1: Create base translation (es-ES)
createLanguageXlf
  generatedXlfFilePath: "Translations/MyApp.g.xlf"
  targetLanguageCode: "es-ES"
  matchBaseAppTranslation: true

// Step 2: Create regional variant from base
createLanguageXlf
  generatedXlfFilePath: "Translations/MyApp.g.xlf"
  targetLanguageCode: "es-MX"
  matchBaseAppTranslation: true

// Step 3: Get base translations as reference
getTranslatedTextsMap
  filePath: "Translations/MyApp.es-ES.xlf"
  limit: 0

// Step 4: Copy base, then adjust regional terms
// "Ordenador" (es-ES) → "Computadora" (es-MX)
// "Factura" stays the same in both

Workflow

Step 1: Setup

  1. Build the extension to generate the .g.xlf file: al_build
  2. Create language file for each target locale (Pattern 1)
  3. If language files already exist, refresh them (Pattern 2)

Step 2: Translate

  1. Retrieve untranslated texts with getTextsToTranslate (paginate with limit/offset)
  2. Check translation memory for consistency (Pattern 5)
  3. Translate in batches of 20-50 items (Pattern 3)
  4. Save progress frequently — use targetState: "translated"

Step 3: Review

  1. Retrieve texts by state: getTranslatedTextsByState with "translated" filter
  2. Validate:
    • All placeholders preserved (%1, %2, etc.)
    • Character limits respected
    • Context-appropriate translations
    • Consistent terminology across the extension
  3. Mark reviewed texts: targetState: "needs-review-translation" → "final"

Step 4: Finalize

  1. Verify no untranslated texts remain: getTextsToTranslate with limit: 0
  2. Promote all final texts to signed-off
  3. Build the extension to verify XLF integration: al_build
  4. Test the UI in the target language

Common Language Codes

Code Language Code Language
es-ES Spanish (Spain) fr-FR French (France)
es-MX Spanish (Mexico) fr-CA French (Canada)
de-DE German pt-BR Portuguese (Brazil)
it-IT Italian nl-NL Dutch
da-DK Danish sv-SE Swedish
nb-NO Norwegian fi-FI Finnish
pl-PL Polish cs-CZ Czech
ja-JP Japanese zh-CN Chinese (Simplified)

References

Constraints

  • This skill covers XLF translation management, batch translation, and quality review workflows
  • Do NOT edit .g.xlf files manually — they are compiler-generated
  • Do NOT remove or reorder placeholders (%1, %2) in translations
  • Do NOT exceed maxLength character limits defined in AL source
  • Do NOT translate without checking existing translation memory first (consistency)
  • Translation testing in UI → skill-testing.md | Page captions and tooltips → skill-pages.md