Skip to content

String

Gitlab Pipeline Status Gitlab Code Coverage GitLab Tag GitLab Contributors

The String module provides a developer-friendly way for managing strings in your Drupal project using "Keyword" philosophy. Instead of hard-coding strings throughout your codebase, this module enables you to use unique string identifiers, making your code more maintainable and translation-friendly.

Key Features

  • 🔑 Unique string identifiers for better code organization
  • 🌐 Translation workflow independence
  • 📝 No codebase updates needed for string changes
  • 🔄 Stable translation keys
  • 🎯 Improved context handling
  • 🚀 Consistent internationalization across PHP and JavaScript
  • 📦 Easy integration with existing Drupal projects

Quick Example

<?php
// Before (Traditional Drupal)
t('Welcome to your dashboard, @name!', ['@name' => $name]);

// After (Using String Module)
t('dashboard.welcome_message', ['@name' => $name]);

Documentation Sections

Requirements

  • Drupal 10.3 or 11.x
  • PHP 8.1 or higher
  • Drupal core Locale module

Installation

composer require drupal/string
drush en string

Support

Sample usage

Current (Core) String
t('Dashboard') t('dashboard.title')
t('My Dashboard') t('user_dashboard.title')
t('Welcome @name!', ['@name' => $name]) t('dashboard.welcome_message.title', ['@name' => $name])
format_plural($count, '1 item', '@count items') format_plural($count, 'search_result.item_count', 'search_result.item_count')

Advantages

  • Makes your codebase independent of translation workflow.
  • No need to update your codebase to edit strings.
  • Editing a text in original language won't invalidate the translation in other language.
  • More intuitive use of translation context.
  • Instead of reference to codebase and source files, strings are managed via unique human friendly string "ids".
  • Cleaner code syntax. t('dashboard.welcome_message') is more readable than verbose markup like t('Welcome to your dashboard').
  • Separates content from presentation, allowing developers to focus on UI/UX without being copywriters.
  • Stable translation keys that remain unchanged even when fixing typos or updating text in the primary language.
  • Improved context handling for ambiguous terms (no need for artificial descriptions when the context is clear).
  • Better handling of context-dependent translations (e.g., "Get started" can have different translations based on its usage as a button, page title, or document name).
  • Provides a more maintainable approach to internationalization that works consistently across both PHP and JavaScript contexts.

Defining strings

Before you can start using "identifiers", we need to tell Drupal about it. For this, after enabling the module, define your strings in a custom module via string yaml plugin. This is similar to creating routes via routing.yml plugin.

Let say you have a module named foo, then create a file in the root of your module folder called foo.string.yml. Each entry would represent a unique string. Please refer to sample configuration file with ample comment.

Strings are logically grouped using . (a period) in their identifier.

Example dashboard.welcome_message.short would be part of following groups, - dashboard - dashboard.welcome_message

The top level group is called namespace. Usually this would be the module's machine name, but not necessarily. The identifier thus follows a format namespace.key. Where key can also have its own grouping.

Note

String IDs MUST have a namespace and a key.

# Demo: String with a placeholder.
dashboard.welcome_message.short:
  default: "Hello @name!"

# Demo: Another string with placeholder.
dashboard.welcome_message.long:
  default: "Hello @name! Welcome back, good to see you again."

# Demo: Plural strings.
search.result.items_count:
  default: "@count item found"
  default_plural: "@count items found"

# Demo: Expose strings from contrib module.
# Following is a string which is actually used in a contrib module "Group".
drupal.contrib.groups.label:
  default: "Groups"
  msgid: "Groups"

# Demo: Expose strings from core.
# Following is a string from core.
drupal.core.module.extend.label:
  default: "Extend"
  msgid: "Extend"

# Demo: String Override.
# Following is a way you could override an existing string.
# Much like string overrides. This allows us to not add
# another English language to replace existing string.
drupal.core.node.content.label:
  default: "Pages"
  msgid: "Content"
# A string with context.
# However it really doesn't make any sense.
dashboard.greetings.short:
  default: 'Sup @name!'
  msgid: 'Hi @name!'
  msgctxt: 'short_greeting'
# A string with context.
# However it really doesn't make any sense.
drupal.core.node.search_result_summary:
  default: 'One item found.'
  default_plural: '@count items found.'
  msgid: '@count item found'
  msgid_plural: '@count items found'
  # You may also add some comments for each string.
  comments:
    - 'Comment line 1'
    - 'Comment line 2'

After clearing the cache, you can start using the identifier in your translation function calls. E.g. t('dashboard.welcome_message.short').

Admin interface

Exporting translation source file (POT files)

Export form is located at /admin/config/regional/translate/string-export.

It can also be accessed through,

Configuration → Regional and language → User interface translation → String Export.

You may have to provide manage string export permission to the users for doing this.

Importing translation file (PO files)

You can use the interface provided by locale module to import custom translation files. This is located at /admin/config/regional/translate/import It can also be accessed through,

Configuration → Regional and language → User interface translation → Import.

Compatible with

  • Strings exposed are available to be translated via Interface translation
  • Translation strings can be imported using pot files via core interface.

References