SfSkills Domains Docs GitHub

Home / admin / custom-label-management

custom-label-management

Custom Labels for i18n, configuration strings, and UI text: translation workbench, Apex System.Label, LWC @salesforce/label imports, 1,000-char limit. NOT for translating picklist values, field labels or layouts — use admin/multi-language-and-translation. NOT for config values in custom metadata or custom settings — use admin/custom-metadata-types.

Open the skill folder on GitHub


Custom Label Management

Activate when hard-coded strings appear in Apex, LWC, validation rules, or email templates that will need to be translated, reviewed for tone, or changed without code. Custom Labels are the canonical Salesforce mechanism for externalizing text and pushing it through the Translation Workbench.

Before Starting

Questions to Ask Before Configuring

Ask these before the first <labels> element is written. Every row maps to a CustomLabel field that Metadata API marks Required or to a documented platform behaviour — skip a row and the file still deploys, then misbehaves.

AskWhy it mattersWhat a good answer adds
"Is this string shown to a user verbatim, or is it a value code branches on?"Only the first kind belongs in a label; endpoints, toggles and thresholds belong in a Custom Metadata TypeA per-string disposition: label, CMDT, or stays inline
"What is the org's default language, and which locales are already enabled?"language is a Required field on every CustomLabel, and translations are separate metadata under translations/The <language> value for the source file plus the list of <locale>.translation files to author
"Will these labels ship inside a managed package, and may the installing org reference them?"protected is Required; protected components can't be linked to or referenced by components created in the installing orgAn explicit true/false per label instead of a copy-pasted false
"How does the pipeline retrieve labels — wildcard CustomLabels or named CustomLabel members?"CustomLabels doesn't support retrieving labels by name; the singular CustomLabel type doesA manifest that touches only the labels this change owns
"How long is the longest value, and will it be translated?"Source value caps at 1,000 characters but a CustomLabelTranslation.label caps at 765Either a split-label plan or a decision to move the long text to a CMDT LongTextArea
"Which categories already exist, and who filters on them?"categories is a comma-separated string, max 255 characters, used as list-view filter criteriaA category vocabulary reused rather than reinvented per feature
"Which surfaces consume each label — Apex, LWC, Flow, validation rule?"Apex resolves System.Label.X at compile time, so the label must be in the same deployment payload as the classThe deployment artifact contents and the order of any destructive change

What a proper configuration adds over just creating the labels: the file deploys alongside the code that references it, every label carries the translator context and packaging flag the platform requires, and the translation files exist per locale instead of silently falling back to the source language.


Core Concepts

Label vs Name vs Value

Every custom label has a Name (API, immutable once referenced), Short Description (required, hint for translators), Categories (a comma-separated grouping string — see the field table below), Value (the default-language string), and per-language translations. Never rename Name — Apex references break.

The CustomLabel fields Metadata API actually defines

FieldTypeRequired?Constraint the guide states
fullNamestringRequiredThe name of the custom label; must be specified when creating, updating, or deleting
valuestringRequiredThe translated custom label. Maximum of 1000 characters
languagestringRequiredThe language of the translated custom label
protectedbooleanRequiredProtected components can't be linked to or referenced by components created in the installing organization
shortDescriptionstringRequiredAn easily recognizable term to identify this label; used in merge fields
categoriesstringOptionalA comma-separated list; usable as list-view filter criteria. Maximum of 255 characters

Source: Metadata API Developer Guide, CustomLabels → CustomLabel field table (api_meta.txt:41187-41221). Note categories is comma-separated per the guide, not semicolon-separated.

Where the metadata lives

Reference patterns

UNVERIFIED (2026-09-04): only the Apex forms above are grounded in the sources used for this revision (apexdev.txt:7246-7250, apexrefguide.txt:220031-220037). The LWC @salesforce/label/c.<Name> import specifier is not re-grounded because the LWC Developer Guide is not in the extracted corpus, and the corpus shows the $Label merge field only in its namespaced form inside a Gift Entry template (api_meta.txt:78590) — never in a validation-rule or formula context. Confirm both against their own guides before shipping; the full markers and what they rest on are in references/metadata-examples.md.

Translation Workbench

Admin enables target languages; translators (or a translator profile) fill values per language. Export/import CSV/STF files for external translation services. The Workbench side — enabling locales, the picklist and field-label surfaces, and toLabel() in SOQL — belongs to admin/multi-language-and-translation; this skill owns the label's own lifecycle and the Translations metadata that carries its translated value.

Packaging impact

Labels travel with metadata. Managed-package labels are namespaced (ns.My_Label); unlocked packages and org-level labels are not. The protected flag is the packaging contract: protected labels "can't be linked to or referenced by components created in the installing organization" (api_meta.txt:41203-41206), and Apex "can't access labels that are protected in a different namespace" (apexrefguide.txt:220008-220009). It is inert in an unpackaged org, which is why it gets set wrong — see references/gotchas.md Gotcha 10.

Common Patterns

Pattern: Category-based organization

Use categories like Errors, UIButtons, Toast, EmailBody. Filter the setup list during audits; Apex tools can scan by category prefix.

Pattern: LWC label import with local labels object

import greeting from '@salesforce/label/c.Greeting';
import farewell from '@salesforce/label/c.Farewell';
export default class Hello extends LightningElement {
    labels = { greeting, farewell };
}

Template: {labels.greeting}. Clean and renameable.

Pattern: Long-text overflow

For strings over 1,000 chars (complex email body), split into My_Long_Text_Part1, My_Long_Text_Part2 and concatenate. Alternatively, store in a Custom Metadata Type Rich Text field.

Decision Guidance

NeedMechanism
User-facing UI string, translatableCustom Label
Configuration value (URL, toggle)Custom Metadata Type
Long dynamic email bodyEmail Template or CMDT rich text
Runtime mutable string by adminCustom Setting or CMDT
Label over 1,000 charsSplit or use CMDT
  1. Inventory and disposition. Fill

    templates/custom-label-management-template.md with the answers to Questions to Ask Before Configuring and one row per hard-coded string found in .cls, .trigger, LWC .html/.js, .flow-meta.xml and validation rules. Anything code branches on leaves for admin/custom-metadata-types.

  2. Retrieve the current label set before editing. CustomLabels is one

    file for the whole org, so every deploy is a whole-set write and a stale copy silently reverts other people's values. Use the retrieve command and manifest in references/metadata-examples.md ("Retrieve, lint, deploy"), and note the categories already in use.

  3. Author the <labels> entries. Copy the shape from

    references/metadata-examples.md — fullName, value, language, protected, shortDescription, categories on every label, not just the Required minimum.

  4. Wire the consumers in the same change. Apex System.Label.X, LWC

    @salesforce/label/c.X, Flow and formula $Label.X. Read references/gotchas.md Gotchas 2 and 6 first — the compile-time binding and the whole-file replacement rule decide the deployment shape.

  5. Lint before deploying. Run

    python3 scripts/check_custom_label_management.py --manifest-dir force-app/main/default. Clear every ERROR (duplicate fullName, over-length value); triage WARN (missing shortDescription, undefined label reference) and INFO (uncategorised label, label referenced nowhere).

  6. Deploy labels and consumers as one payload, then author

    translations/<locale>.translation-meta.xml per enabled locale — see references/metadata-examples.md and admin/multi-language-and-translation for the Translation Workbench side.

  7. Verify per locale. Follow the verification step in

    references/metadata-examples.md: log in as a user whose LanguageLocaleKey is the target locale and confirm each consumer surface, because a missing translation renders the source value with no error.

Review Checklist

Salesforce-Specific Gotchas

  1. Renaming the label Name breaks Apex. References compile-fail. Always add a new label and deprecate.
  2. Labels are cached per session. Changing a value may not reflect until session reload; bust cache or test with a new session.
  3. STF export can omit new labels if not saved first. Save the label list before exporting.

Output Artifacts

ArtifactDescription
Label catalogName, value, category, languages, owner
Reference auditFiles referencing each label
Translation planLanguages, translators, turnaround

Reference Files

FileRead it when
references/metadata-examples.mdWriting CustomLabels.labels-meta.xml, the <locale>.translation-meta.xml companion, the consumer snippets (Apex / LWC / Flow / validation rule), package.xml, the retrieve-deploy commands, or the post-deploy verification
references/gotchas.mdThe labels deployed cleanly and something is still wrong — labels vanished, a class won't compile, a translation is blank, an LWC shows stale text, or a namespaced retrieve returns nothing
references/examples.mdTwo end-to-end walkthroughs — one label consumed by both Apex and LWC, and a vendor translation round-trip — plus the i18n-debt anti-pattern
references/llm-anti-patterns.mdReviewing label guidance or label-bearing code an AI assistant produced
references/well-architected.mdChoosing between Custom Label, CMDT, Custom Setting and Static Resource, or chasing the official source behind a claim here
templates/custom-label-management-template.mdWorkflow step 1 — the string inventory and per-string disposition, before any XML exists
scripts/check_custom_label_management.pyWorkflow step 5, before every deploy that touches labels/

Package files