Skip to content

Dictate in the user's language, not always en-US - #35

Merged
milind-soni merged 1 commit into
milind-soni:mainfrom
guilimasp:fix/dictation-locale
Aug 14, 2026
Merged

Dictate in the user's language, not always en-US#35
milind-soni merged 1 commit into
milind-soni:mainfrom
guilimasp:fix/dictation-locale

Conversation

@guilimasp

@guilimasp guilimasp commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

speech-helper.swift pins the recognizer to en-US, so dictation only works for English speakers — everyone else gets their speech transcribed into English words that sound roughly similar.

It now walks Locale.preferredLanguages and uses the first locale with an available recognizer, falling back to en-US. A locale the system has no model for reports isAvailable == false, so this can only match today's behavior or improve on it.

One caveat: the system language is not always the language someone dictates in, so a per-user setting would cover that case properly.

pnpm typecheck && pnpm test pass, and the helper compiles with swiftc.

The speech helper builds an SFSpeechRecognizer pinned to en-US, so
dictation transcribes any other language into nonsense — a Portuguese
speaker gets English words that sound vaguely similar.

Walk the user's preferred languages and use the first one with an
available recognizer, keeping en-US as the fallback. Recognizers the
system has no model for report isAvailable == false, so this cannot end
up worse than today.

Co-Authored-By: Claude <noreply@anthropic.com>

@milind-soni milind-soni left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed against current main: locale selection preserves en-US fallback. Swift typecheck, project typecheck, and all 159 tests pass in the combined tree.

@milind-soni
milind-soni merged commit bb5ecf9 into milind-soni:main Aug 14, 2026
guilimasp added a commit to guilimasp/OpenMausBot that referenced this pull request Aug 18, 2026
Every patch had rotted across the ten-version jump the stalled sync hid,
so a build would have skipped all seven and quietly shipped an app with
none of this fork's behavior.

Four are gone because upstream merged them (milind-soni#35 dictation language, milind-soni#36
the connected-apps prompt, milind-soni#37 the screen frame, milind-soni#67 composer drafts) or
shipped its own version (milind-soni#68 became upstream's paste chips and file
drop). Deleting a patch upstream now carries is the whole point of the
mechanism.

Three remain and are rewritten against the current code:

- 020 box TTL: upstream landed boxErrorMessage and noEnv since, so the
  retry moves into a createBox helper instead of an inline second call.
- 030 dictation: upstream took the language fallback but not the config
  override, so the patch is now just the {"dictation":{"locale"}} read
  in front of the preferences it already consults.
- 060 pasted images: rewritten around upstream's new composer, whose
  attachment chips fold into the prompt text and so cannot carry an
  image. Images stay a separate strip and reach the driver as their own
  blocks.

typecheck and the full suite pass with all three applied (103 files,
997 tests).
github-actions Bot pushed a commit to guilimasp/OpenMausBot that referenced this pull request Aug 19, 2026
Every patch had rotted across the ten-version jump the stalled sync hid,
so a build would have skipped all seven and quietly shipped an app with
none of this fork's behavior.

Four are gone because upstream merged them (milind-soni#35 dictation language, milind-soni#36
the connected-apps prompt, milind-soni#37 the screen frame, milind-soni#67 composer drafts) or
shipped its own version (milind-soni#68 became upstream's paste chips and file
drop). Deleting a patch upstream now carries is the whole point of the
mechanism.

Three remain and are rewritten against the current code:

- 020 box TTL: upstream landed boxErrorMessage and noEnv since, so the
  retry moves into a createBox helper instead of an inline second call.
- 030 dictation: upstream took the language fallback but not the config
  override, so the patch is now just the {"dictation":{"locale"}} read
  in front of the preferences it already consults.
- 060 pasted images: rewritten around upstream's new composer, whose
  attachment chips fold into the prompt text and so cannot carry an
  image. Images stay a separate strip and reach the driver as their own
  blocks.

typecheck and the full suite pass with all three applied (103 files,
997 tests).
github-actions Bot pushed a commit to guilimasp/OpenMausBot that referenced this pull request Aug 20, 2026
Every patch had rotted across the ten-version jump the stalled sync hid,
so a build would have skipped all seven and quietly shipped an app with
none of this fork's behavior.

Four are gone because upstream merged them (milind-soni#35 dictation language, milind-soni#36
the connected-apps prompt, milind-soni#37 the screen frame, milind-soni#67 composer drafts) or
shipped its own version (milind-soni#68 became upstream's paste chips and file
drop). Deleting a patch upstream now carries is the whole point of the
mechanism.

Three remain and are rewritten against the current code:

- 020 box TTL: upstream landed boxErrorMessage and noEnv since, so the
  retry moves into a createBox helper instead of an inline second call.
- 030 dictation: upstream took the language fallback but not the config
  override, so the patch is now just the {"dictation":{"locale"}} read
  in front of the preferences it already consults.
- 060 pasted images: rewritten around upstream's new composer, whose
  attachment chips fold into the prompt text and so cannot carry an
  image. Images stay a separate strip and reach the driver as their own
  blocks.

typecheck and the full suite pass with all three applied (103 files,
997 tests).
github-actions Bot pushed a commit to guilimasp/OpenMausBot that referenced this pull request Aug 21, 2026
Every patch had rotted across the ten-version jump the stalled sync hid,
so a build would have skipped all seven and quietly shipped an app with
none of this fork's behavior.

Four are gone because upstream merged them (milind-soni#35 dictation language, milind-soni#36
the connected-apps prompt, milind-soni#37 the screen frame, milind-soni#67 composer drafts) or
shipped its own version (milind-soni#68 became upstream's paste chips and file
drop). Deleting a patch upstream now carries is the whole point of the
mechanism.

Three remain and are rewritten against the current code:

- 020 box TTL: upstream landed boxErrorMessage and noEnv since, so the
  retry moves into a createBox helper instead of an inline second call.
- 030 dictation: upstream took the language fallback but not the config
  override, so the patch is now just the {"dictation":{"locale"}} read
  in front of the preferences it already consults.
- 060 pasted images: rewritten around upstream's new composer, whose
  attachment chips fold into the prompt text and so cannot carry an
  image. Images stay a separate strip and reach the driver as their own
  blocks.

typecheck and the full suite pass with all three applied (103 files,
997 tests).
github-actions Bot pushed a commit to guilimasp/OpenMausBot that referenced this pull request Aug 22, 2026
Every patch had rotted across the ten-version jump the stalled sync hid,
so a build would have skipped all seven and quietly shipped an app with
none of this fork's behavior.

Four are gone because upstream merged them (milind-soni#35 dictation language, milind-soni#36
the connected-apps prompt, milind-soni#37 the screen frame, milind-soni#67 composer drafts) or
shipped its own version (milind-soni#68 became upstream's paste chips and file
drop). Deleting a patch upstream now carries is the whole point of the
mechanism.

Three remain and are rewritten against the current code:

- 020 box TTL: upstream landed boxErrorMessage and noEnv since, so the
  retry moves into a createBox helper instead of an inline second call.
- 030 dictation: upstream took the language fallback but not the config
  override, so the patch is now just the {"dictation":{"locale"}} read
  in front of the preferences it already consults.
- 060 pasted images: rewritten around upstream's new composer, whose
  attachment chips fold into the prompt text and so cannot carry an
  image. Images stay a separate strip and reach the driver as their own
  blocks.

typecheck and the full suite pass with all three applied (103 files,
997 tests).
github-actions Bot pushed a commit to guilimasp/OpenMausBot that referenced this pull request Aug 23, 2026
Every patch had rotted across the ten-version jump the stalled sync hid,
so a build would have skipped all seven and quietly shipped an app with
none of this fork's behavior.

Four are gone because upstream merged them (milind-soni#35 dictation language, milind-soni#36
the connected-apps prompt, milind-soni#37 the screen frame, milind-soni#67 composer drafts) or
shipped its own version (milind-soni#68 became upstream's paste chips and file
drop). Deleting a patch upstream now carries is the whole point of the
mechanism.

Three remain and are rewritten against the current code:

- 020 box TTL: upstream landed boxErrorMessage and noEnv since, so the
  retry moves into a createBox helper instead of an inline second call.
- 030 dictation: upstream took the language fallback but not the config
  override, so the patch is now just the {"dictation":{"locale"}} read
  in front of the preferences it already consults.
- 060 pasted images: rewritten around upstream's new composer, whose
  attachment chips fold into the prompt text and so cannot carry an
  image. Images stay a separate strip and reach the driver as their own
  blocks.

typecheck and the full suite pass with all three applied (103 files,
997 tests).
github-actions Bot pushed a commit to guilimasp/OpenMausBot that referenced this pull request Aug 24, 2026
Every patch had rotted across the ten-version jump the stalled sync hid,
so a build would have skipped all seven and quietly shipped an app with
none of this fork's behavior.

Four are gone because upstream merged them (milind-soni#35 dictation language, milind-soni#36
the connected-apps prompt, milind-soni#37 the screen frame, milind-soni#67 composer drafts) or
shipped its own version (milind-soni#68 became upstream's paste chips and file
drop). Deleting a patch upstream now carries is the whole point of the
mechanism.

Three remain and are rewritten against the current code:

- 020 box TTL: upstream landed boxErrorMessage and noEnv since, so the
  retry moves into a createBox helper instead of an inline second call.
- 030 dictation: upstream took the language fallback but not the config
  override, so the patch is now just the {"dictation":{"locale"}} read
  in front of the preferences it already consults.
- 060 pasted images: rewritten around upstream's new composer, whose
  attachment chips fold into the prompt text and so cannot carry an
  image. Images stay a separate strip and reach the driver as their own
  blocks.

typecheck and the full suite pass with all three applied (103 files,
997 tests).
github-actions Bot pushed a commit to guilimasp/OpenMausBot that referenced this pull request Aug 25, 2026
Every patch had rotted across the ten-version jump the stalled sync hid,
so a build would have skipped all seven and quietly shipped an app with
none of this fork's behavior.

Four are gone because upstream merged them (milind-soni#35 dictation language, milind-soni#36
the connected-apps prompt, milind-soni#37 the screen frame, milind-soni#67 composer drafts) or
shipped its own version (milind-soni#68 became upstream's paste chips and file
drop). Deleting a patch upstream now carries is the whole point of the
mechanism.

Three remain and are rewritten against the current code:

- 020 box TTL: upstream landed boxErrorMessage and noEnv since, so the
  retry moves into a createBox helper instead of an inline second call.
- 030 dictation: upstream took the language fallback but not the config
  override, so the patch is now just the {"dictation":{"locale"}} read
  in front of the preferences it already consults.
- 060 pasted images: rewritten around upstream's new composer, whose
  attachment chips fold into the prompt text and so cannot carry an
  image. Images stay a separate strip and reach the driver as their own
  blocks.

typecheck and the full suite pass with all three applied (103 files,
997 tests).
github-actions Bot pushed a commit to guilimasp/OpenMausBot that referenced this pull request Aug 26, 2026
Every patch had rotted across the ten-version jump the stalled sync hid,
so a build would have skipped all seven and quietly shipped an app with
none of this fork's behavior.

Four are gone because upstream merged them (milind-soni#35 dictation language, milind-soni#36
the connected-apps prompt, milind-soni#37 the screen frame, milind-soni#67 composer drafts) or
shipped its own version (milind-soni#68 became upstream's paste chips and file
drop). Deleting a patch upstream now carries is the whole point of the
mechanism.

Three remain and are rewritten against the current code:

- 020 box TTL: upstream landed boxErrorMessage and noEnv since, so the
  retry moves into a createBox helper instead of an inline second call.
- 030 dictation: upstream took the language fallback but not the config
  override, so the patch is now just the {"dictation":{"locale"}} read
  in front of the preferences it already consults.
- 060 pasted images: rewritten around upstream's new composer, whose
  attachment chips fold into the prompt text and so cannot carry an
  image. Images stay a separate strip and reach the driver as their own
  blocks.

typecheck and the full suite pass with all three applied (103 files,
997 tests).
github-actions Bot pushed a commit to guilimasp/OpenMausBot that referenced this pull request Aug 27, 2026
Every patch had rotted across the ten-version jump the stalled sync hid,
so a build would have skipped all seven and quietly shipped an app with
none of this fork's behavior.

Four are gone because upstream merged them (milind-soni#35 dictation language, milind-soni#36
the connected-apps prompt, milind-soni#37 the screen frame, milind-soni#67 composer drafts) or
shipped its own version (milind-soni#68 became upstream's paste chips and file
drop). Deleting a patch upstream now carries is the whole point of the
mechanism.

Three remain and are rewritten against the current code:

- 020 box TTL: upstream landed boxErrorMessage and noEnv since, so the
  retry moves into a createBox helper instead of an inline second call.
- 030 dictation: upstream took the language fallback but not the config
  override, so the patch is now just the {"dictation":{"locale"}} read
  in front of the preferences it already consults.
- 060 pasted images: rewritten around upstream's new composer, whose
  attachment chips fold into the prompt text and so cannot carry an
  image. Images stay a separate strip and reach the driver as their own
  blocks.

typecheck and the full suite pass with all three applied (103 files,
997 tests).
github-actions Bot pushed a commit to guilimasp/OpenMausBot that referenced this pull request Aug 28, 2026
Every patch had rotted across the ten-version jump the stalled sync hid,
so a build would have skipped all seven and quietly shipped an app with
none of this fork's behavior.

Four are gone because upstream merged them (milind-soni#35 dictation language, milind-soni#36
the connected-apps prompt, milind-soni#37 the screen frame, milind-soni#67 composer drafts) or
shipped its own version (milind-soni#68 became upstream's paste chips and file
drop). Deleting a patch upstream now carries is the whole point of the
mechanism.

Three remain and are rewritten against the current code:

- 020 box TTL: upstream landed boxErrorMessage and noEnv since, so the
  retry moves into a createBox helper instead of an inline second call.
- 030 dictation: upstream took the language fallback but not the config
  override, so the patch is now just the {"dictation":{"locale"}} read
  in front of the preferences it already consults.
- 060 pasted images: rewritten around upstream's new composer, whose
  attachment chips fold into the prompt text and so cannot carry an
  image. Images stay a separate strip and reach the driver as their own
  blocks.

typecheck and the full suite pass with all three applied (103 files,
997 tests).
github-actions Bot pushed a commit to guilimasp/OpenMausBot that referenced this pull request Aug 29, 2026
Every patch had rotted across the ten-version jump the stalled sync hid,
so a build would have skipped all seven and quietly shipped an app with
none of this fork's behavior.

Four are gone because upstream merged them (milind-soni#35 dictation language, milind-soni#36
the connected-apps prompt, milind-soni#37 the screen frame, milind-soni#67 composer drafts) or
shipped its own version (milind-soni#68 became upstream's paste chips and file
drop). Deleting a patch upstream now carries is the whole point of the
mechanism.

Three remain and are rewritten against the current code:

- 020 box TTL: upstream landed boxErrorMessage and noEnv since, so the
  retry moves into a createBox helper instead of an inline second call.
- 030 dictation: upstream took the language fallback but not the config
  override, so the patch is now just the {"dictation":{"locale"}} read
  in front of the preferences it already consults.
- 060 pasted images: rewritten around upstream's new composer, whose
  attachment chips fold into the prompt text and so cannot carry an
  image. Images stay a separate strip and reach the driver as their own
  blocks.

typecheck and the full suite pass with all three applied (103 files,
997 tests).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants