Skip to content

feat(i18n): add Turkish (tr) translation - #815

Merged
devswha merged 8 commits into
devswha:mainfrom
fitzgpt:feat/i18n-turkish-v2
Oct 11, 2026
Merged

devswha merged 8 commits into
devswha:mainfrom
fitzgpt:feat/i18n-turkish-v2

Conversation

@fitzgpt

@fitzgpt fitzgpt commented Oct 11, 2026

Copy link
Copy Markdown
Contributor

Change

Adds Turkish (Türkçe) as a UI language, following the existing Korean/Japanese/Chinese pattern, in a single clean commit:

  • src/lib/i18n.tr.ts — a full dictionary of all 910 strings the code asks for, in the same grouped order as the other dictionaries. Labels and buttons are nouns, sentences are plain written Turkish; panel, çalışma alanı, ajan, sohbet, eşleştirme are the fixed terms, product names (herdr, Tailscale, Claude Code, Codex) stay as they are, placeholders keep their English names. Git worktree checkouts are rendered as "çalışma kopyası".
  • src/lib/i18n.ts — tr in LANGUAGE_SETTINGS/LANGUAGE_NAMES (Türkçe)/LOCALE_TAGS (tr-TR)/DICTIONARIES and the browser-detection regex.
  • release-summaries.json — Turkish highlights for every release since 0.3.52, the same lists as the English ones (same line counts, each line within the 90-character limit), so the repo's own summaries checks stay green.
  • shared/update.ts — tr joins SUMMARY_LANGUAGES, which the test asserts equals the app's languages.
  • README.tr.md — a full Turkish README, linked from the language line of README.md.
  • CONTRIBUTING.md, CHANGELOG.md, and the two release-notes test fixtures updated to include the new language; one test description renamed to "every language the app has".

Validation

  • bun run generate:types --check — generated types are up to date.
  • bun run typecheck — clean.
  • bun run build — builds.
  • bun run test:unit — 2691 tests, 0 fail; the i18n suite now covers the Turkish dictionary (every string present, no stale entries, placeholders intact, not just English repeated) and resolveLanguage picks tr from tr-TR.
  • A second full self-review pass over the dictionary fixed percent formatting (Bağlamın %{percent}'i kaldı), checkout terminology, and several awkward sentences before opening this PR.

@coderabbitai

coderabbitai Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 31 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: devswha/herdr-web-ui/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a9b94d29-47fa-45c5-b867-9c3987f3cf98

📥 Commits

Reviewing files that changed from the base of the PR and between 01aba43 and 25cbea6.


📒 Files selected for processing (61)
  • CHANGELOG.md
  • CONTRIBUTING.md
  • DESIGN.md
  • docs/guide.md
  • scripts/file-viewer-mobile-regression.ts
  • scripts/file-viewer-regression.ts
  • scripts/mobile-tabs-regression.ts
  • scripts/mobile-viewport-regression.ts
  • scripts/pane-find-regression.ts
  • scripts/sheets-settled.ts
  • scripts/sidebar-activity-demo-regression.ts
  • scripts/tab-menu-regression.ts
  • scripts/ui-regression.ts
  • server/AGENTS.md
  • server/telemetry.test.ts
  • server/telemetry.ts
  • shared/protocol.ts
  • shared/telemetry.ts
  • src/AGENTS.md
  • src/App.tsx
  • src/components/AgentSidebar.css
  • src/components/AgentSidebar.tsx
  • src/components/ChatView.css
  • src/components/CommandPalette.tsx
  • src/components/Composer.css
  • src/components/ConfirmDialog.tsx
  • src/components/FileViewer.tsx
  • src/components/FilesDialog.tsx
  • src/components/KeyBar.css
  • src/components/NewSessionDialog.tsx
  • src/components/PaneCanvas.tsx
  • src/components/PaneTerminal.css
  • src/components/PlanDialog.tsx
  • src/components/RowMenu.css
  • src/components/RowMenu.tsx
  • src/components/SettingsDialog.css
  • src/components/SettingsDialog.tsx
  • src/components/Sidebar.css
  • src/components/TabStrip.tsx
  • src/components/TelemetryControls.tsx
  • src/components/WorktreeDialog.tsx
  • src/lib/api.ts
  • src/lib/edgeSwipe.test.ts
  • src/lib/edgeSwipe.ts
  • src/lib/i18n.ja.ts
  • src/lib/i18n.ko.ts
  • src/lib/i18n.test.ts
  • src/lib/i18n.tr.ts
  • src/lib/i18n.zh.ts
  • src/lib/paneCanvas.test.ts
  • src/lib/paneCanvas.ts
  • src/lib/settings.test.ts
  • src/lib/settings.ts
  • src/lib/sheets.test.ts
  • src/lib/sheets.ts
  • src/main.tsx
  • src/styles.css
  • telemetry/README.md
  • telemetry/schema.sql
  • telemetry/worker.test.ts
  • telemetry/worker.ts

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: devswha/herdr-web-ui/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2a6b5e35-17ef-4f85-8c3a-9f8503dcd803


📥 Commits

Reviewing files that changed from the base of the PR and between 5280dbe and 01aba43.



📒 Files selected for processing (11)
  • CHANGELOG.md
  • CONTRIBUTING.md
  • README.md
  • README.tr.md
  • release-summaries.json
  • scripts/release-notes.test.ts
  • server/release-notes.test.ts
  • shared/update.ts
  • src/lib/i18n.test.ts
  • src/lib/i18n.tr.ts
  • src/lib/i18n.ts


Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 1 remain after this review.




📝 Summary

Summary by CodeRabbit

  • New Features
    • Added Turkish as a display language, including automatic selection when Turkish is preferred in the browser.
    • Added a Turkish version of the README and Turkish translations for release notes.
📝 Summary

Walkthrough

The application adds Turkish as a supported UI language, with a translation dictionary and browser-language selection. Turkish release summaries and project documentation are also added.

Changes

Turkish language support

Layer / File(s) Summary
UI localization and language selection
src/lib/i18n.tr.ts, src/lib/i18n.ts, src/lib/i18n.test.ts
Adds the Turkish dictionary, registers Turkish in language settings, and recognizes Turkish browser-language tags. Tests include Turkish dictionary and language-resolution checks.
Turkish release summaries
shared/update.ts, release-summaries.json, scripts/release-notes.test.ts, server/release-notes.test.ts
Adds Turkish to supported summary languages and provides Turkish release notes for versions 0.4.0 through 0.4.6. Release-note test data includes Turkish.
Turkish project documentation
README.tr.md, README.md, CONTRIBUTING.md, CHANGELOG.md
Adds a Turkish README and links it from the language selector. The contribution rule and changelog now include Turkish.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Suggested reviewers: devswha



Merge Risk: ⚪ Minimal · up to 01aba

This adds Turkish as a UI language with matching release notes and documentation. No concrete merge-blocking risk was found in the supplied changes.

Pre-merge checks | Passed 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check Passed The title clearly and concisely identifies the main change: adding the Turkish translation.
Description check Passed The description includes the required Change and Validation sections. It explains the Turkish localization scope and lists relevant typecheck, build, and test results. It does not include the template…
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 6 files. (5 skipped: 5 …
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.



✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR



  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

jiunshinn and others added 6 commits October 11, 2026 08:51
devswha#683)

> This changes DESIGN.md's "dialogs and their scrims snap open and
closed" rule for phones (≤640px), so it is a design call as much as
code. DESIGN.md, the changelog and `src/AGENTS.md` say what changes.
Desktop keeps the snap.

## Change

On a phone, the app looked and felt like a web page. Dialogs and menus
appeared with no motion and could not be swiped away. The drawer slid on
its own instead of following the finger. A tapped header button drew an
amber box, a long press selected a button's label, and a pinch zoomed
the whole interface. This makes it move and respond like an iPhone app,
with the same screens and layout.

- **Sheets** (dialogs, the ⋯ menu, the palette, Settings) rise from the
bottom, follow a finger dragged down from their head or from a list at
its top, and drop however they close. A short drag springs back. Past
30% of the height, or with a flick, the sheet closes through the same
close as the scrim. A stroke on a sheet scrolls nothing behind it
(`touch-action: none`), but the sheet's own lists still scroll. In
`lib/sheets.ts`, each sheet calls `useSheetSwipe`. `watchSheetExits`
(started in `main.tsx`) puts a closed scrim's last frame back as an
inert `.is-leaving` copy inside a closed shadow root until it has slid
out, so no query of the page finds two copies of a sheet.
- **Drawer** stays under the finger (`lib/edgeSwipe.ts`) and settles by
how much of it shows and how fast it was let go. The scrim stays mounted
while the drawer is closed (`opacity: 0`, no pointer events) and fades.
Otherwise, a swipe begun on the scrim would unmount it mid-stroke, and
the stroke's `touchend` would go with it, leaving the drawer stuck
partway. A stroke that still holds the drawer when the next touch begins
lets it go first.
- **Chat**: the header is glass (`--bar-bg` + `--glass-blur`) and the
transcript scrolls under it. Only the transcript reaches under the
header, so a prompt card, held messages and the composer stay below it.
While nothing stands between them, the input card floats over the end of
the transcript on `--card-glass`. The xterm mount is not fitted under
the chat, so this resizes no pty.
- **Touch** (`hover: none` and `pointer: coarse`): a press dims a button
instead of drawing the amber `:active` box, and a list row fills. The
app's chrome is not selectable and opens no callout, while the
transcript, code, files and fields still are. Pinch and double-tap do
not zoom, and landscape does not inflate text.
- Reduced motion drops the rise and drop. A drag still follows the
finger.

Desktop is unchanged: sheets move only at ≤640px, the glass only at
≤768px, and the touch rules apply only on touch screens.

| Chat: glass header, floating input card | Drawer under the finger |
Settings sheet dragged down |
|---|---|---|
| <img
src="https://raw.githubusercontent.com/jiunshinn/herdr-web-ui/67a11d82d843f3370d27bd9cae43f919386edbdd/ios-feel-chat.png"
width="260"> | <img
src="https://raw.githubusercontent.com/jiunshinn/herdr-web-ui/67a11d82d843f3370d27bd9cae43f919386edbdd/ios-feel-drawer.png"
width="260"> | <img
src="https://raw.githubusercontent.com/jiunshinn/herdr-web-ui/67a11d82d843f3370d27bd9cae43f919386edbdd/ios-feel-sheet.png"
width="260"> |

Screenshots are from the demo build (fixture transport) at 390×844 in
headless Chrome, not a live session. The drawer and sheet shots are
taken mid-stroke, with the finger still down.

## Validation

- `bun run typecheck`, `bun run build`, and `HERDR_TEST_MODE=unit bun
test ./src`: 854 pass. New tests: `src/lib/sheets.test.ts`, drawer
tracking in `src/lib/edgeSwipe.test.ts`, and a stroke whose `touchend`
never arrives.
- Phone demo scripts on this branch:
- Pass: settings-pages, keyboard-viewport, droplet, chat-greeting,
composer-fit, held-rows, prompt-dock, key-bar-customization and
sidebar-activity (`*-demo-regression.ts`), plus
`mobile-viewport-regression.ts`, `file-viewer-regression.ts` and
`file-viewer-mobile-regression.ts`.
- Fails: `font-swap-demo-regression.ts`, with the same assertion on an
unchanged `main` on my Mac ("the faces redrew the conversation at
another height (455 -> 455)").
- Two scripts measured a sheet mid-rise or found a closing copy.
`scripts/sheets-settled.ts` waits for sheets to settle, and
`openSettingsPage` targets the open dialog.
- iOS Simulator Safari (iPhone 17 Pro): the glass header, sheets and
drawer render as intended.
- I have been running this since today in the iPhone home-screen app
from my fork (jiunshinn#7). The scrim fix came from that
use (jiunshinn#11). Headless Chrome at 393×852 with CDP
touch events: before the fix, a swipe from the scrim left the drawer at
`translateX(-60px)`. After it, the drawer closes fully with no inline
styles left.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Hako <devswha@gmail.com>
Co-authored-by: devswha <devswha@users.noreply.github.com>
)

## Change

Fixes devswha#809.

Since 0.4.6 (devswha#747) a phone draws every pane of a split tab in herdr's
grid. At 390px two panes are 195px each: chat wraps after three or four
words, the composer covers the transcript, and each pane's key bar is
cut off.

Up to 768px the canvas now shows the selected pane alone at full size,
the way a zoomed pane is shown, and the tab's menu (the `⋯` beside the
open tab) lists the tab's panes first, the open one marked. Wider
screens keep the split.

- This is only what the browser draws: herdr's layout and zoom are not
changed, so a desktop or the TUI on the same session is unaffected. No
`pane.zoom` call was added.
- The other panes stay mounted and hidden, so drafts and attachments are
kept. They take the whole canvas too, so each keeps the grid it is shown
with.
- The decision is one pure function, `soloPane`
(`src/lib/paneCanvas.ts`); `SOLO_PANE_QUERY` is shared by `PaneCanvas`
and `TabStrip`.
- No layout toggle: nothing on a phone wants 195px panes.

Two existing checks asserted the behavior the issue reports ("the
terminal lens retains both panes on a phone", "the phone retains the
same split layout"). They now assert one visible pane, the picker, and
that herdr's layout is not zoomed.

Known limit: while herdr itself is zoomed, the selection follows herdr's
zoomed pane (existing rule), so the picker cannot leave it.

## Validation

- `bun run typecheck`: pass
- `HERDR_TEST_MODE=unit bun test ./src/lib/paneCanvas.test.ts`: 7 pass
(3 new cases for `soloPane`)
- `bun run check run --build bun scripts/mobile-tabs-regression.ts`:
pass (isolated herdr)
- `bun run check run --build bun scripts/tab-menu-regression.ts`: pass
(isolated herdr; 390x844 and 320x640: one visible frame, the menu
switches the pane, `layout.zoomed === false`; a 1280px window narrowed
to 700px shows one pane and lists the panes in its tab menu)
- Demo client in Chrome at 390x844 and 1440x900 with a tab split three
ways: one full-width pane and a three-pane menu on the phone, three
panes and their dividers on the desktop, and the same page follows the
viewport when resized.

Not run to the end locally: `scripts/ui-regression.ts` stops on this Mac
at "explicit Send now delivered one item" on unmodified `main` as well,
so its later sections were run as the standalone scripts above.
…uest (devswha#821)

## Change

`CONTRIBUTING.md` said "One change per PR" with no room for changes that
cannot be split. It now also says that changes which cannot stand apart,
because one needs another's code, may share a PR: each as its own
commit, in dependency order, with the description saying what needs
what.

Independent changes still go in independent PRs, and a stack is still a
maintainer's call; this only covers the case where a second PR could not
typecheck or pass its tests without the first (for example devswha#820, where
the telemetry change counts settings that the two commits before it
add).

## Validation

Prose only; no test.
…changed appearance settings (devswha#820)

## Change

Three commits, in order; the third depends on the first two (it counts
their settings).

**1. Sidebar: workspace cards and pin stars are settings, off by
default.** devswha#673 and devswha#778 turned both on for everyone. The Agents list is
flat again and its rows carry no star unless **Settings → Appearance →
Workspace cards** / **Pin agents** is on. Saved pins stay stored while
the setting is off.

**2. Plan: the flow and the header's count are settings, on by
default.** **Plan flow** off opens a pane's plan as the list alone, with
no switch; **Plan count in the header** off takes the plan button out of
the header on that device. Defaults keep devswha#531 as it is.

**3. Anonymous counts name the appearance settings changed from their
defaults.** The install/update event gets `changed_settings`: names from
a fixed list (theme, density, palette, sidebar rows, Agents order,
workspace cards, pin agents, plan flow, plan count). Names only, never a
value, never a setting the user types.

- The browser tells its server the list on opening and on a change
(`POST /api/telemetry { changed_settings }`; anything outside the list
is a 400). The server keeps it for its next event and sends nothing by
itself.
- The notice says so and is shown once more (`NOTICE_VERSION = 2`). An
install that saw the older notice sends nothing, its update count
included, until it has seen this one.
- The same switch, `HERDR_WEB_TELEMETRY=0` and `DO_NOT_TRACK` turn it
off.
- Receiver: a `changed_settings` column (sorted, comma-joined, `''` for
none, `NULL` when not told). The Worker drops a name it does not know
instead of refusing the event, so a newer app is still counted.
`telemetry/README.md` has the `ALTER` and a query for "installs that
changed each setting".

The receiver is already deployed: the column was added to the D1 table
and the Worker deployed from this branch's `telemetry/` (it accepts
events from released versions unchanged).

## Validation

- `bun run typecheck`: pass
- `HERDR_TEST_MODE=unit bun test` on `server/telemetry.test.ts`,
`telemetry/worker.test.ts`, `src/lib/settings.test.ts`, `i18n.test.ts`,
`plan.test.ts`, `sidebarOrder.test.ts`, `sidebarAgents.test.ts`: 141
pass
- `bun scripts/sidebar-activity-demo-regression.ts`: pass (new: the list
is flat and starless by default; the plan's flow and header count stand
by default on a desktop and a phone, and each goes with its setting)
- End to end with the real `createServer` + `Telemetry`, the Worker's
`handle` over an in-memory table from `schema.sql`, and Chrome: with
theme, workspace cards and plan flow changed (and a typed terminal
font), the stored row holds `agentCards,planFlow,theme`; neither the
font nor any value leaves the PC; a later change is kept for the next
event and sends nothing; with the switch off a new version sends
nothing.
- Deployed receiver: a test event stored `agentCards,theme` (an unknown
name dropped); the test rows were deleted.

`scripts/ui-regression.ts` was not run to the end locally (it stops on
this Mac at "explicit Send now delivered one item" on unmodified `main`
as well).
@devswha
devswha merged commit 6e6eaaf into devswha:main Oct 11, 2026
29 of 33 checks passed
devswha added a commit that referenced this pull request Oct 11, 2026
… back lands (#825)

## Change

`scripts/settings-pages-demo-regression.ts` has timed out in CI on
unrelated PRs (#819, #820, #815 twice, `feat/plan-step-detail`), always
in a wait on `history.state` that said nothing when it ran out.

**Cause, from CI's own trace** (first commit: the waits on the history
say which step it was, what the history holds, and every `go` /
`pushState` / `replaceState` / `popstate` up to then):

```
the reload: the history never held it.
138ms loaded      {settings: {page: "alerts", depth: 2}}  ?…&settings=alerts
298ms go(-2)
330ms popstate    {}                                      ?…
546ms pushState   {settings: {page: null, depth: 1}}
549ms pushState   {settings: {page: "alerts", depth: 2}}
736ms replaceState                                        ?…&settings=alerts
```

A reload on a Settings entry steps out of it (`lib/settingsHistory.ts`),
but that step lands when the browser gets to it. `App` reads the address
once at load, and when it did so before the step landed, the address
still named Settings: the dialog opened again and pushed its entries
back. So this is a bug in the app that the test caught only on a slow
runner, not a fault of the test: a reload with Settings open closed it
on a fast device and kept it on a slow one.

**Fix:** `lib/settingsHistory.ts` remembers at load whether the load
began on an entry Settings left (`loadedOnSettingsEntry()`), and such a
load does not open Settings from its address (`src/App.tsx`, the one
read of the address at load). Asked of the module rather than read from
the history when the app first draws: a review pointed out that the step
back can also land *before* that, on an entry whose address names
Settings too (the one a link to Settings opened), and the dialog would
come back in that order instead. A link to Settings opened fresh begins
on no such entry and opens as before.

**Test:** the reload step now makes the slow order on purpose: it waits
until the address names Settings, holds the load's steps back until the
app has drawn itself, then lets them go, and asserts the dialog was
never shown. Without the fix this fails every time locally with the same
trace as CI; with it, it passes.

A second case covers a link to Settings: it opens the dialog, and a
reload there closes it.

Not in this PR (older, another cause): a link naming both a file and
Settings pushes the file preview's entry with a copy of the Settings
entry, and a reload from the preview steps back onto a Settings entry,
which opens Settings.

## Validation

- `bun scripts/settings-pages-demo-regression.ts` without the fix: fails
at "the reload", trace identical to CI's.
- With the fix: 13 PASS, repeated runs.
- CI on the first version of the fix: both browser lanes green on a full
re-run (one earlier run failed in
`terminal-command-backspace-regression.ts`, "readline fixture did not
start", which this does not touch).
- `bun run typecheck`: pass. `settingsHistory.test.ts`,
`deepLink.test.ts`: 40 pass.

Not reproduced by CPU load, CPU throttling or delaying `history.go`
alone; a `replaceState`/`pushState` right after `history.go` does not
cancel the traversal in Chrome (360/360 landed), so that was not it.

## Release

Client-side only.
devswha added a commit to sobir-git/herdr-web-ui that referenced this pull request Oct 11, 2026
main gained a Turkish dictionary (devswha#815) after this branch was synced. The
strings this change adds and renames get their Turkish entries here, so the
dictionary check passes on the merged tree.
devswha added a commit that referenced this pull request Oct 11, 2026
## Change

Closes #640. Supersedes #652: @od-studio-webagency's commit is carried
over onto current `main` with its authorship, and one commit on top
changes two things.

**New workspace** shows the PC's recent folders as chips under
Directory, so a project whose panes were closed can be picked again
without typing its path or browsing to it.

- History is per PC, kept in this browser (`localStorage`). It is seeded
from the folders of the panes a connected PC has open, and survives
closing them and reloading.
- Only a successful start moves a folder to the front; a failed or
partly failed start changes no order. A folder merely seen in a pane
goes behind what is kept: a pane's folder follows every `cd` of its
shell (checked on an isolated herdr), so in front it would fill the
three chips with wherever a shell has been.
- New tab keeps its workspace's folder and shows no chips.

Changed from #652:

1. **A chip fills Directory and starts nothing.** In #652 a click
created the workspace at once, with no chance to change the agent or the
name, or to take back a wrong click.
2. **Three chips, on one row.** #652 wrapped every stored folder into a
scroll area of up to four rows. The dialog now shows the three most
recent; a short name is shown whole and a long one gives way to an
ellipsis. The stored history is not capped: capping it at three would
reorder the list on every snapshot once a PC has four folders open.

3. **No hint under the chips.** The line explaining a click is gone; the
chips and their tooltips say it.

No server change.

## Validation

- `bun run typecheck`: pass
- `bun test src/lib/recent-directories.test.ts src/lib/i18n.test.ts
scripts/ci-browser.test.ts`: 32 pass (the Turkish dictionary added in
#815 has the three strings)
- `bun run check run --build bun scripts/recent-folders-regression.ts`
(Chrome, the test herdr session): pass at 1440, 1920 and 390 px in dark
and light. It checks that four stored folders show three chips on one
row without overflow, that a chip sets Directory and sends no request,
then Start, pending, a failed start and a partly failed start. The
script is added to `scripts/ci-browser.sh`.

Not run locally: the whole unit and browser lanes.

---------

Co-authored-by: studiood <253281802+od-studio-webagency@users.noreply.github.com>
@devswha

devswha commented Oct 14, 2026 •

Copy link
Copy Markdown
Owner

@fitzgpt thank you again for the Turkish translation, it was thorough and careful work.

A heads-up so it doesn't come as a surprise: we are removing the Turkish UI language in #1081. This is not about the translation's quality. Every UI language has to translate each new string and every release summary from then on, and the anonymous usage counts show very few installs that would see it (about 0.5% of installs are in Turkey). To keep that cost down, the app now keeps English, Korean, Japanese and Simplified Chinese, and CONTRIBUTING says new UI languages are not taken.

A browser set to Turkish will show English, and a device that picked Turkish goes back to following the browser. Sorry to undo your work, and thanks for contributing.

devswha added a commit that referenced this pull request Oct 14, 2026
## Change

The UI languages are English, Korean, Japanese and Simplified Chinese.
Turkish (added in #815 three days ago) is removed with its README.

- Telemetry: the language setting itself was never reported (the
deployed counts name only seven appearance settings), so usage is read
from the country: 5 of 1091 installs (0.5%) were last seen in Turkey.
For comparison, KR 204, JP 40, and TW/HK/SG about 63.
- Every UI language has to translate each new `t("…")` string
(`i18n.test.ts` fails otherwise) and every release summary
(`release-summaries.json`), so each one is a recurring cost.
CONTRIBUTING now says new UI language PRs are not taken.
- A browser set to Turkish now resolves to English. A device that chose
`tr` in Settings loads as `system` (`sanitizeSettings` already falls
back for an unknown value; a new test pins it).
- `SUMMARY_LANGUAGES` drops `tr`, and the `tr` entries are removed from
`release-summaries.json` (other languages unchanged, same JSON
formatting).
- Unchanged on purpose: `shared/telemetry.ts` keeps `tr` in its language
enum (narrowing it would need a Worker redeploy); dictation's `tr-TR`
speech language stays, since that is the browser's speech recognition,
not UI text; the Turkish keyboard-layout notes in `shortcuts.ts` stay.

## Validation

- `bun run check fast`: generated types, typecheck, build, unit tests
all pass.
- Demo app in Chromium: the Language select lists System, English, 简体中文,
日本語, 한국어; a `tr-TR` browser with `language: "tr"` stored renders `<html
lang="en-US">` with the select on System; a `tr-TR` browser on System
renders English; a `ko-KR` browser still renders Korean; no page errors.
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.

3 participants