Skip to content

fix(poll): keep translations from poll.updated in the poll state - #1937

Merged
NikolaGoranNaumovski merged 1 commit into
release-v10from
fix/poll-updated-translations
Oct 22, 2026
Merged

NikolaGoranNaumovski merged 1 commit into
release-v10from
fix/poll-updated-translations

Conversation

@NikolaGoranNaumovski

@NikolaGoranNaumovski NikolaGoranNaumovski commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Description of the changes, What, Why and How?

What. Poll.handlePollUpdated now keeps the server's question and description translations (name_i18n, description_i18n) from a poll.updated event.

Why. The backend translates polls automatically
(CHA-5308), and
#1878 added the response fields. But handlePollUpda through extractPollData, which builds an UpdatePollRequestand lists its fields one by one. The translations aren't in that lpoll.state. Checked against the live API with 10.0.0-rc.22: the server sends the new name_i18ninpoll.updated`, and the cache
are affected:

  • Edited question: readers in other languages see the old translation, or the
    new question untranslated, until they reload.
  • Language added on demand: client.translateMessage({ id }, { language })
    on a poll message translates the poll on the server
    question's new language never reaches open clients.

Option translations were not affected, because options is copied whole. I also
checked the other paths that write poll state: mess(answer_text_i18narrives withpoll_vote), query()andreinitializeState`. None of them lose translations.

How. handlePollUpdated copies both fields from event.poll explicitly, also when they are absent. poll.updated carries the whole poll (confirmed live, including after an option is added), and a change made under channel-only translation removes the old translations, so an absent field clears the stale ones. extractPollData is public and returns a request type, so it is lefis. There are no public API or type changes: PollState already has both fields. Tests - test/unit/poll.test.js: an edited question's translations are stored, a language added later is stored, the description's translations are stored,translations the event no longer carries are cleared. - test/unit/poll_manager.test.ts: poll.updated sent through the clientlanguage added later is stored, the description's translations are stored, and
translations the event no longer carries are cleared.

  • test/unit/poll_manager.test.ts: poll.updated sent through the client updates the cached poll's name_i18n. yarn types, yarn lint and yarn test pass (4513 tests). The run reports 2
    unhandled errors. Both also happen on an unmodified release-v10, in
    poll.test.js (slowRequest.reject) and messageOperations/optimisticRouting.test.ts, and are unrelated.
    Verified live: with this build, a translateMessage to a new language shows up
    in an open client's cached poll (it_text added). Before the fix, the cache wasunchanged.

Consumer: GetStream/stream-chat-react React PR link, poll translations in the
React v15 UI.

Changelog

  • Fix: poll.updated now keeps the poll's question and description translations (name_i18n, description_i18n), so edited questions and languages added with translateMessage show without a reload.

Video of Fix

Screen.Recording.2026-10-21.at.16.50.38.mov

handlePollUpdated copied the event through extractPollData, which builds an
UpdatePollRequest and lists its fields one by one. It leaves out the
server-owned name_i18n and description_i18n, so a poll.updated stored the new
question but dropped its translations.

Readers in other languages kept the stale translation after a question was
edited, and a language added on demand with translateMessage never reached
the cached poll. Option translations were not affected, because options are
copied whole.

Copy both fields from the event, also when they are absent. The event carries
the whole poll, and a change made under channel-only translation removes the
old translations, so an absent field clears the stale ones. extractPollData is
public and keeps its request shape.
@NikolaGoranNaumovski
NikolaGoranNaumovski merged commit e47b75a into release-v10 Oct 22, 2026
8 checks passed
@NikolaGoranNaumovski
NikolaGoranNaumovski deleted the fix/poll-updated-translations branch October 22, 2026 13:00
github-actions Bot pushed a commit that referenced this pull request Oct 26, 2026
## [10.0.0-rc.25](v10.0.0-rc.24...v10.0.0-rc.25) (2026-10-26)

### ⚠ BREAKING CHANGES

* Channel.watch() resolves with the channel instance to use (the channel, or the instance that superseded it) instead of the server response.
- watch() sends no query for a channel that is already watched and loaded (watchStatus Watching, initialized, and messagePaginator.hasResults) when it passes no options or the same options as the last successful watch() during the current watch; other options send a query. It no longer refreshes a watched channel: use channel.reload(), and load other messages through channel.messagePaginator (jumpToMessage(), toTail(), toHead()).
- A watch() while another with the same options is in flight joins it instead of sending a request.
- Aborting requestOptions.signal ends only that caller's wait; the request is cancelled once every caller waiting for it has aborted.
- Channel.ensureWatched() is removed (v10 release candidates only); call watch().
```

## Changelog

- `Channel.watch()` resolves with the channel and sends no query for a
channel already watched and loaded, unless it asks for options the
current watch was not sent with. `Channel.ensureWatched()` is removed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

### Bug Fixes

* channel list reconciliation ([#1942](#1942)) ([f7f9ec8](f7f9ec8))
* count hidden messages on each side of a jump page ([#1940](#1940)) ([487ac3d](487ac3d))
* **poll:** keep translations from poll.updated in the poll state ([#1937](#1937)) ([e47b75a](e47b75a)), closes [#1878](#1878)

### Refactors

* call the paginator intervals intervals, not windows ([#1939](#1939)) ([69aa18a](69aa18a))
* **channel:** remove no-op overrides, dead branch and redundant id guards ([#1936](#1936)) ([050953e](050953e)), closes [#1870](#1870)
* make Channel.watch() watch a channel only when it is not watched and loaded ([#1943](#1943)) ([3c363cb](3c363cb))
@stream-ci-bot

Copy link
Copy Markdown

🎉 This PR is included in version 10.0.0-rc.25 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants