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:
- AiContextLanguageService -- detects the current content language and
applies entity translations via
translateItem()/translateItems() - AiContextSelector -- uses the language service before filtering and scoring
- 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:
- Request path -- checks for a language prefix (for example
/fr/) - Referer header -- checks a same-site HTTP Referer for a language prefix, which covers AJAX calls from language-prefixed pages
- 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
- Enable the Language and Content Translation modules
- Add additional languages at
/admin/config/regional/language - Enable translation for AI Context Items at
/admin/config/regional/content-language - Check "AI Context Item" and select which fields should be translatable
- Save the configuration
Adding translations
- Go to
/admin/config/ai/context/items - Click Edit on a context item
- Click the Translate tab
- Click Add for the language you want to translate to
- Enter the translated content
- 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_languagecache context, which includes Referer-based detection for unprefixed AJAX requests
Migration notes
No migration is required. Translation support is automatically available once you:
- Update the module code
- Clear caches (
drush cr) - Enable content translation for
ai_context_itementities (optional) - Add translations to your context items (optional)
Troubleshooting
Context not translating
- Verify content translation is enabled for
ai_context_itemat/admin/config/regional/content-language - Check that the context item has a translation in the target language
- Verify the language is properly configured in Drupal at
/admin/config/regional/language - Clear all caches (
drush cr)
Wrong language returned
- Enable debug logging and check the
ai_contextlog messages for the detected language - Verify the AJAX caller is sending a Referer header (browsers do this by default)
- Verify that
language.negotiationconfig has the correcturl.prefixesmapping - If the language prefix is missing from both the request path and Referer,
the system falls back to
getCurrentLanguage(TYPE_CONTENT)
Translation not saving
- Verify the user has permission to translate content
- Check that all required fields are filled in the translation
- Verify the translation is marked as published
- Clear all caches after saving