Skip to content

Multilingual Support

The AI Context module supports content translation for ai_context_item entities. When AI consumers select context items, they receive content in the current content language when a translation exists.

How it works

Translation detection

Translation support is primarily handled in these services:

  1. AiContextLanguageService -- detects the current content language and applies entity translations via translateItem() / translateItems()
  2. AiContextSelector -- uses the language service before filtering and scoring
  3. AiContextRenderer -- renders the already-translated entities

AiContextSelector, the Language scope plugin, and function call plugins use the shared AiContextLanguageService. This keeps translation selection and Language scope hard filtering on the same content language. Detection order is:

  1. Request path -- checks for a language prefix (for example /fr/)
  2. Referer header -- checks a same-site HTTP Referer for a language prefix, which covers AJAX calls from language-prefixed pages
  3. Drupal language negotiation -- falls back to getCurrentLanguage(TYPE_CONTENT)

Language scope and entity translation

Language scope and entity translation answer different questions:

  • Language scope determines whether a Context Item is eligible for the current request and contributes to subscription scoring.
  • Entity translation determines which version of a selected Context Item is rendered.

Leaving Language scope blank makes an item language-neutral for matching. It does not make the item language-neutral content: Drupal still stores an original entity language, and the selector uses that original when a requested translation does not exist.

Language scope hard filtering uses the same content-language detection order as translation selection, so AJAX requests from a language-prefixed page filter and render with that language.

See Language scope for selection examples and Context Selection for where translation occurs in the pipeline.

Why not just getCurrentLanguage()?

Drupal's language negotiation relies on the request URL. AJAX-based tools can POST to an unprefixed path even when the page the user is viewing is language-prefixed. In that case, getCurrentLanguage() can return the default language unless the Referer is also checked.

Fallback behavior

When a translation is not available for the current language, the system falls back to the default language version of the content. This ensures that context remains available even when translations are incomplete.

Compatibility

The behavior works in all of these cases:

  • content translation is enabled and translations exist
  • content translation is enabled but translations do not exist
  • content translation is not enabled
  • the language module is not enabled

Setting up translations

Enabling translation

  1. Enable the Language and Content Translation modules
  2. Add additional languages at /admin/config/regional/language
  3. Enable translation for AI Context Items at /admin/config/regional/content-language
  4. Check "AI Context Item" and select which fields should be translatable
  5. Save the configuration

Adding translations

  1. Go to /admin/config/ai/context/items
  2. Click Edit on a context item
  3. Click the Translate tab
  4. Click Add for the language you want to translate to
  5. Enter the translated content
  6. Save the translation

Usage example

/** @var \Drupal\ai_context\Service\AiContextRequestFactory $factory */
$factory = \Drupal::service('ai_context.request_factory');

$result = $factory->getResult(
  scopes: ['use_case' => ['working_with_text']],
  consumerId: 'my_module',
);
$context_text = $result->getRenderedText();

Selection detects the content language from the current request or Referer; callers do not need to pass a Language scope solely to select a translation. If a translation is missing, the default-language entity is used instead.

Technical details

Safe translation checks

The implementation uses safe translation checks that work even when translation is not enabled:

if ($item->hasTranslation($currentLanguage)) {
  $item = $item->getTranslation($currentLanguage);
}

Performance

  • translation loading happens in the same entity-loading pass
  • no extra translation work happens in the renderer
  • language detection happens once per request
  • selection results vary by the ai_context.detected_language cache context, which includes Referer-based detection for unprefixed AJAX requests

Migration notes

No migration is required. Translation support is automatically available once you:

  1. Update the module code
  2. Clear caches (drush cr)
  3. Enable content translation for ai_context_item entities (optional)
  4. Add translations to your context items (optional)

Troubleshooting

Context not translating

  1. Verify content translation is enabled for ai_context_item at /admin/config/regional/content-language
  2. Check that the context item has a translation in the target language
  3. Verify the language is properly configured in Drupal at /admin/config/regional/language
  4. Clear all caches (drush cr)

Wrong language returned

  1. Enable debug logging and check the ai_context log messages for the detected language
  2. Verify the AJAX caller is sending a Referer header (browsers do this by default)
  3. Verify that language.negotiation config has the correct url.prefixes mapping
  4. If the language prefix is missing from both the request path and Referer, the system falls back to getCurrentLanguage(TYPE_CONTENT)

Translation not saving

  1. Verify the user has permission to translate content
  2. Check that all required fields are filled in the translation
  3. Verify the translation is marked as published
  4. Clear all caches after saving