const response = await client.translateActivity({
id: "activity_123",
language: "fr",
});
console.log(response.activity.i18n?.fr_text);
// "Bonjour, j'aimerais en savoir plus sur votre produit."Translation
Activity and comment text can be translated on demand using the same automated translation provider as Stream Chat. Translations are stored in an i18n object on the activity or comment and can be projected when reading feeds, activities, and comments.
Feeds v3 does not automatically translate content when you create an activity or comment. Automatic translation on write is planned for a later release. Until then, call the translate endpoints explicitly — either on demand from your app, or from your backend when you receive an activity/comment create webhook — and read stored translations with the language query parameter.
Translate an activity
Translates an activity's text field to the requested language. Requires the same permission as reading the activity (ReadActivities).
POST /api/v2/feeds/activities/{id}/translate
$response = $feedsClient->translateActivity(
'activity_123',
new GeneratedModels\TranslateActivityRequest(language: 'fr'),
);
echo $response->getData()->activity->i18n['fr_text'];The response includes the full activity with the updated i18n map. An activity.updated event is emitted (see Events below).
Translate a comment
Translates a comment's text field to the requested language.
POST /api/v2/feeds/comments/{id}/translate
$response = $feedsClient->translateComment(
'comment_456',
new GeneratedModels\TranslateCommentRequest(language: 'es'),
);
echo $response->getData()->comment->i18n['es_text'];Reading translated content
After a translation is stored, you can project it when reading feeds, activities, and comments using two optional query parameters:
| Parameter | Type | Description |
|---|---|---|
language | string | ISO 639-1 language code. Returns a slim i18n map with the original language and the requested translation when available. |
translate_text | boolean | When true, substitutes the top-level text field with the requested translation when one exists. Default is false. |
These parameters are supported on:
- Feed reads (
getOrCreateFeed) getActivity,queryActivities- Comment reads (
getComments,getComment,getCommentReplies,queryComments) queryPinnedActivities,queryBookmarks
Default projection (translate_text=false)
The text field stays in the original language. The response includes a projected i18n object with the original language key and the requested translation when stored.
// Request body first; optional language / translate_text follow (PHP SDK v9+)
$response = $feedsClient->feed('user', 'john')->getOrCreateFeed(
new GeneratedModels\GetOrCreateFeedRequest(userID: 'john'),
language: 'es',
);
// text is still the original English
echo $response->getData()->activities[0]->text;
// "Hello world"
// projected i18n includes Spanish when translated
echo $response->getData()->activities[0]->i18n['es_text'];
// "Hola mundo"Substitute text (translate_text=true)
When a translation exists for the requested language, the text field is replaced with the translated version. The original is always recoverable from i18n.
$response = $feedsClient->feed('user', 'john')->getOrCreateFeed(
new GeneratedModels\GetOrCreateFeedRequest(userID: 'john'),
language: 'es',
translateText: true,
);
echo $response->getData()->activities[0]->text;
// "Hola mundo"
echo $response->getData()->activities[0]->i18n['language'];
// "en"If no translation exists for the requested language, text is returned unchanged regardless of the translate_text flag.
The i18n object
When content is translated, an i18n object is added to the activity or comment. It uses the same format as Chat message translations:
language— ISO 639-1 code of the original text{language}_text— text in that language (e.g.en_text,fr_text,es_text)
{
"language": "en",
"en_text": "Hello world",
"fr_text": "Bonjour le monde",
"es_text": "Hola mundo"
}The explicit translate endpoints return the full i18n map. Read endpoints with language return a projected subset: the original language metadata plus the requested translation when available.
Set user language
Setting a user's language improves source-language detection when translating. The source language priority is:
- Stored
i18n.language(set on first translation) - The activity or comment author's
user.language - Automatic detection by the translation provider
$client->updateUsers(new GeneratedModels\UpdateUsersRequest(
users: [
'user_123' => [
'id' => 'user_123',
'name' => 'Jane',
'language' => 'en',
],
],
));See User management for full user create/update examples. The language field is shared across Chat, Feeds, and Video products.
Events
Translating an activity or comment emits an activity.updated or comment.updated event.
To pre-translate content when it is created, listen for activity/comment create webhooks (or WebSocket events) and call the translate endpoints from your backend for the languages you need. Create events do not include translations — you add them with an explicit translate call.
WebSocket and webhook event payloads do not include i18n. Use the HTTP translate response, or re-fetch the object with language projection, to read stored translations after an event.
Limits and behavior
- Scope — Only the
textfield is translated.customfields, attachments, and other metadata are not included. - Idempotency — Translating into a language that is already stored is a no-op (no additional billing for that language).
- Text edits — Updating an activity or comment's text clears all stored translations for that object.
- Mentions —
@mentioneddisplay names in text are protected during translation (same behavior as Chat). - Search — Translated text is not indexed for activity search.
- Size limits — Up to 10 languages per object. Maximum
i18nJSON size: 32 KB for activities, 16 KB for comments (separate from user text size limits). - Permissions — Translate endpoints require the same read permission as the underlying object (
ReadActivities).
Billing
Each new destination language translated for an activity or comment counts toward your app's translation usage (translations_daily). Re-requesting a language that is already stored does not increment usage.
Available languages
Feeds uses the same supported language codes as Chat. See the Chat translation languages table.