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

# 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

- [Working with Translation Files](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-work-with-translation-files)
- [NAB AL Tools Extension](https://marketplace.visualstudio.com/items?itemName=nabsolutions.nab-al-tools)
- [XLIFF 1.2 Standard](http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html)
- [MaxLength Property](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/properties/devenv-maxlength-property)

## 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`
