# Translation

Activity and comment text can be translated on demand using the same automated translation provider as [Stream Chat](https://getstream.io/chat/docs/react-native/translation/). Translations are stored in an `i18n` object on the activity or comment and can be projected when reading feeds, activities, and comments.

<Admonition type="info">

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.

</Admonition>

## 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`

```js label="JavaScript"
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."
```

The response includes the full activity with the updated `i18n` map. An `activity.updated` event is emitted (see [Events](#events) below).

## Translate a comment

Translates a comment's `text` field to the requested language.

`POST /api/v2/feeds/comments/{id}/translate`

```js label="JavaScript"
const response = await client.translateComment({
  id: "comment_456",
  language: "es",
});

console.log(response.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.

```js label="JavaScript"
const feed = client.feed("user", "john");
const response = await feed.getOrCreate({
  language: "es",
});

// text is still the original English
console.log(response.activities[0].text);
// "Hello world"

// projected i18n includes Spanish when translated
console.log(response.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`.

```js label="JavaScript"
const feed = client.feed("user", "john");
const response = await feed.getOrCreate({
  language: "es",
  translate_text: true,
});

console.log(response.activities[0].text);
// "Hola mundo"

console.log(response.activities[0].i18n?.language);
// "en"
```

<Admonition type="info">

If no translation exists for the requested language, `text` is returned unchanged regardless of the `translate_text` flag.

</Admonition>

## 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](https://getstream.io/chat/docs/react-native/translation/#i18n-data):

- `language` — ISO 639-1 code of the original text
- `{language}_text` — text in that language (e.g. `en_text`, `fr_text`, `es_text`)

<Tabs>

```json label="JSON"
{
  "language": "en",
  "en_text": "Hello world",
  "fr_text": "Bonjour le monde",
  "es_text": "Hola mundo"
}
```

</Tabs>

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:

1. Stored `i18n.language` (set on first translation)
2. The activity or comment author's `user.language`
3. Automatic detection by the translation provider

```js label="JavaScript"
await client.updateUsers({
  users: {
    user_123: { id: "user_123", language: "en", name: "Jane" },
  },
});
```

See [Users](https://getstream.io/docs/platform/users/) 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.

<Admonition type="warning">

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.

</Admonition>

## Limits and behavior

- **Scope** — Only the `text` field is translated. `custom` fields, 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** — `@mentioned` display 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 `i18n` JSON 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](https://getstream.io/chat/docs/react-native/translation/#available-languages).


---

This page was last updated at 2026-09-08T17:13:39.240Z.

For the most recent version of this documentation, visit [https://getstream.io/activity-feeds/docs/react-native/translation/](https://getstream.io/activity-feeds/docs/react-native/translation/).