How to translate Custom Labels in Salesforce

By Manuel Roldán Pérez · Updated · Salesforce steps checked against Salesforce's documentation on

On this page 8 sections
  1. 1. From the label's own page
  2. 2. In Translation Workbench, many at once
  3. 3. As metadata, in a deployment
  4. The limits — three of them
  5. How code picks the translation
  6. When a new label is created, translate it in the same change
  7. Common problems
  8. Related guides

A Custom Label is a piece of text that code and configuration refer to by name — Upload_Document_Title — instead of writing the words themselves, so the words can change and be translated without touching the code. To translate one, open it in Setup → Custom Labels and add a translation in its Translations related list, or translate many at once in Translation Workbench. At runtime Salesforce gives each user the translation for their language, and the label's own value when there is none.

1. From the label's own page

The quickest route for one label (Salesforce Help: translate custom labels):

  1. Setup → Custom Labels, and open the label by its name.
  2. In the Translations related list, click New. (For a label that comes from a managed package, this is where local translations and overrides go.)
  3. Choose the Language, enter the Translation Text, and save.

The language must be one added in Translation Language Settings. The translation replaces the label's value for users whose language it is.

2. In Translation Workbench, many at once

For more than a few labels, or for a translator who should not have access to the labels themselves:

  1. Setup → Translate.
  2. Choose the Language and the Setup Component Custom Labels.
  3. Double-click a label's translation cell, type, and save.

The grid lists every Custom Label with its current translation in that language, so gaps are visible at a glance, and its Out of Date column flags a translation whose label changed after it was translated. For a whole release, Translation Workbench's Export (choose Outdated and untranslated to get only the gaps) and Import carry Custom Labels with everything else — see where every label is translated.

3. As metadata, in a deployment

In source control a label and its translations live in two different places, and that is the first thing to get right:

  • The label itself — its name, category, and value in the default language — is a CustomLabel inside the org's CustomLabels metadata (labels/CustomLabels.labels-meta.xml in a Salesforce DX project).
  • Each translation is in the Translations file for its language (translations/es.translation-meta.xml), as a customLabels entry with the label's name and the translated label.

A minimal Spanish translation file with one label:

<?xml version="1.0" encoding="UTF-8"?>
<Translations xmlns="http://soap.sforce.com/2006/04/metadata">
    <customLabels>
        <label>Subir documento de identidad</label>
        <name>Upload_Document_Title</name>
    </customLabels>
</Translations>

Two things catch almost everyone:

  • Retrieving translations needs the labels in the same retrieve. Salesforce returns translations "only for the other metadata types referenced in package.xml". A package.xml that asks for Translations alone brings back an almost empty file; list CustomLabels (Salesforce's own example uses the wildcard *) beside it and the labels' translations come back.
  • A translation belongs with its label. Deploy the label before its translations, or in the same deployment — a translation for a label the target org does not have yet has nothing to attach to.

The limits — three of them

  • An org can have up to 5,000 Custom Labels (managed packages' labels do not count), and a label's value can be up to 1,000 characters (about custom labels).
  • In the Metadata API, a translation's label is limited to 765 characters.
  • In the Tooling API, where a translation is an ExternalStringLocalization record, its Value can be much longer.

So a translation longer than 765 characters, written through Setup or the Tooling API, will not round-trip through a Translations retrieve and deploy. Keep long texts short enough for the strictest of the three, or keep them out of labels.

How code picks the translation

Every way of reading a label returns the text in the running user's language, falling back to the label's own value:

WhereHow it is referenced
ApexSystem.Label.Upload_Document_Title
Lightning Web Componentsimport title from '@salesforce/label/c.Upload_Document_Title';
Aura$A.get("$Label.c.Upload_Document_Title") or {!$Label.c.Upload_Document_Title}
Visualforce{!$Label.Upload_Document_Title}
Flowthe $Label global variable in a formula or a text template

Because the language is the running user's, a label read in an automated context — a scheduled job, an email built by a process — is in that context user's language, not necessarily the recipient's. Apex can also ask for a specific language: System.Label has get(namespace, label, language), and translationExists(namespace, label, language) to check first.

When a new label is created, translate it in the same change

A label created without translations is invisible in the target languages' QA until someone happens to look: Salesforce shows the default value, so nothing looks broken. The dependable habit is to create a label and its translations together — in the same Setup session, the same export batch, or the same commit — and to check new labels in the Outdated and untranslated export before a release.

Sextant's New Custom Labels grid in the fictional org Northstar Subscriptions: a label named, its English value and its Spanish translation filled in, and a column for each of the org's other languages.
Creating a label and its translations in one pass, checked against the org before anything is deployed. Photographed in Sextant's demo; the org is fictional.

Common problems

  • "The translation does not show." Check the user's language (their user record), that the language is Active in Translation Language Settings, and that the component really reads the label: a string written into a component's code looks like a label but has nothing to translate.
  • "I cannot tell which label a string on the page is." Several labels can hold the same words, and a field label or a layout section can match them too. The guide to finding the metadata behind Lightning text covers searching labels by their value and the other options.
  • "The retrieve has no translations." List CustomLabels in the same package.xml (above).
  • "Someone changed a translation and nobody knows who." Salesforce records no author for a translated value; see what Salesforce does not tell you.