You've now made your module's interface strings translatable — but what about content that lives in configuration, not code? A block's custom text, a config entity's label, a settings-form description an administrator typed in — none of that gets scanned by the string-translation system, because it's not a literal argument to t() anywhere. Config translation solves this: it lets a site administrator provide a per-language override for specific configuration values, through the normal Configuration Translation UI.
What you'll learn in this lesson
- Why configuration values need a completely different translation mechanism than interface strings
- How to mark a schema property as translatable using
type: label - How the Configuration Translation module discovers what's translatable on your config entity
- Where translated config actually gets stored
Marking a schema property translatable
my_module.robot.*:
type: config_entity
label: 'Robot'
mapping:
id:
type: string
label: 'Robot id'
label:
type: label
label: 'Label'
description:
type: label
label: 'Description'
The key detail is type: label instead of plain type: string. Both store a text value identically — the difference is purely about intent. label tells Drupal's Configuration Translation system "this specific property is human-facing display text, eligible for translation." string is for identifiers and machine values that should never be translated, like the id field above.
Enabling translation for a config entity type
/**
* @ConfigEntityType(
* id = "robot",
* label = @Translation("Robot"),
* ...
* links = {
* "config-translation-overview" = "/admin/structure/robot/manage/{robot}/translate"
* }
* )
*/
class Robot extends ConfigEntityBase {
Adding a config-translation-overview link template to your entity's annotation, plus a dependency on the core config_translation module, is what makes a "Translate" operation appear next to each robot in the admin listing. Once that's wired up, an administrator can click through and provide a French, German, or Arabic version of any label-typed property — no code changes required for each new language.
Quick check: your robot config entity has a
neural_systemboolean property. Should you mark ittype: labelso administrators can "translate" it per language? (Answer: no —labelis specifically for translatable human-facing text. A boolean has no meaningful translation; it should staytype: boolean, exactly as it would outside any translation context.)
Key takeaways
- Configuration values need
config_translation, nott()— they're never scanned for literal translation calls. - Use
type: labelin a config entity's schema for any property that's genuinely human-facing display text eligible for translation; keep identifiers and non-text values as their real type. - A
config-translation-overviewlink template in your entity's annotation is what surfaces the "Translate" operation in the admin UI. - Translations are stored as per-language overrides on top of the base configuration — the original values are never overwritten.
Coming up next
Between interface strings and config translation, your module is now genuinely ready for a multilingual audience. Next, we shift from making things work correctly to making them easy to debug when they don't — starting with how to add useful debug logging to your own module code.