{"id":49427542,"url":"https://github.com/ysm-dev/opencode-translate","last_synced_at":"2026-05-10T06:04:26.738Z","repository":{"id":353282239,"uuid":"1217810194","full_name":"ysm-dev/opencode-translate","owner":"ysm-dev","description":"OpenCode plugin that auto-translates user prompts to English before LLM calls, and translates LLM responses back to the user's language. Lets you converse in any language while the LLM always receives English.","archived":false,"fork":false,"pushed_at":"2026-04-23T07:21:03.000Z","size":126,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-23T09:15:20.622Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ysm-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-22T08:37:20.000Z","updated_at":"2026-04-23T07:20:45.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ysm-dev/opencode-translate","commit_stats":null,"previous_names":["ysm-dev/opencode-translate"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/ysm-dev/opencode-translate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ysm-dev%2Fopencode-translate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ysm-dev%2Fopencode-translate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ysm-dev%2Fopencode-translate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ysm-dev%2Fopencode-translate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ysm-dev","download_url":"https://codeload.github.com/ysm-dev/opencode-translate/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ysm-dev%2Fopencode-translate/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32414506,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-29T06:29:02.080Z","status":"ssl_error","status_checked_at":"2026-04-29T06:29:00.631Z","response_time":110,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-29T10:07:11.535Z","updated_at":"2026-04-29T10:07:12.196Z","avatar_url":"https://github.com/ysm-dev.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# opencode-translate\n\n`opencode-translate` is an OpenCode plugin that lets the user chat in a configured `sourceLanguage` while the main chat loop and compaction summariser only see English.\n\n## What It Does\n\n- Activates once per root session when the first user message contains a trigger keyword such as `$en`.\n- Translates user-authored text parts from `sourceLanguage` to English before the main LLM sees them.\n- Stores the original user text, plus a cached English translation in part metadata.\n- Shows a visible `→ EN: ...` preview under each translated user text part.\n- Translates assistant text parts from English into `displayLanguage` when each text part completes.\n- Translates the built-in `question` tool's question text, header, and every option's label and description into `displayLanguage` so the TUI confirmation dialog is in the user's language. The tool output string returned to the LLM is restored to English, keeping the chat history English-only.\n- Stores assistant text as:\n\n```md\n\u003cenglish\u003e\n\n\u003c!-- oc-translate:{nonce}:start --\u003e\n---\n\n**{displayLanguageLabel}:**\n\n\u003ctranslated\u003e\n\u003c!-- oc-translate:{nonce}:end --\u003e\n```\n\n- Strips that trailer back out before later LLM turns, so the model history stays English-only.\n\n## v1 Limits\n\n- No mid-session toggle off.\n- No auto-detection of source or display language.\n- No title translation or title-path English enforcement.\n- No subagent translation.\n- No translation of tool inputs, tool outputs, or reasoning parts.\n- Edited historical translated user messages are passed through as-is instead of being re-translated (the original edited text is what the LLM sees).\n\n## Hook Failure Handling\n\nHooks never throw. If the translator fails (network error, auth failure, provider 4xx/5xx), the plugin:\n\n1. Logs the error via `client.app.log` (visible with `verbose: true`).\n2. Emits a `⚠️ Translation failed: …` synthetic part.\n3. Falls back to sending the original (untranslated) user text to the model.\n4. On first-turn activation failure, it also rolls back activation so the next turn retries cleanly.\n\nA stalled provider request is additionally bounded by a 60s hard timeout per translation call, so a hung upstream cannot block the OpenCode session.\n\n## Install\n\n```bash\nnpm install -g opencode-translate\n```\n\nAdd it to `~/.config/opencode/opencode.json`:\n\n```json\n{\n  \"plugin\": [\n    [\"opencode-translate\", {\n      \"translatorModel\": \"anthropic/claude-haiku-4-5\",\n      \"triggerKeywords\": [\"$en\"],\n      \"sourceLanguage\": \"ko\",\n      \"displayLanguage\": \"ko\",\n      \"verbose\": false\n    }]\n  ]\n}\n```\n\nThen make sure the translator provider has credentials. Any of these work:\n\n```bash\nopencode auth login anthropic\nexport ANTHROPIC_API_KEY=...\n```\n\nStart a brand-new session and put the trigger in the first message:\n\n```text\n$en 프로젝트 루트의 package.json을 읽고 요약해줘\n```\n\n## Options\n\n| Option | Type | Default |\n| --- | --- | --- |\n| `translatorModel` | string | `anthropic/claude-haiku-4-5` |\n| `triggerKeywords` | string[] | `[$en]` |\n| `sourceLanguage` | string | `en` |\n| `displayLanguage` | string | `en` |\n| `apiKey` | string | `undefined` |\n| `verbose` | boolean | `false` |\n\n## Privacy\n\nUsing this plugin means text goes to two model providers per turn:\n\n- the normal OpenCode chat provider\n- the configured `translatorModel` provider\n\nIf you need strict single-provider or self-hosted-only behavior, do not enable this plugin.\n\n## Anthropic OAuth Support\n\nIf `translatorModel` uses Anthropic and OpenCode auth is backed by Anthropic OAuth (Claude Pro/Max), the plugin reuses those OAuth credentials for translation requests.\n\nAnthropic's `/v1/messages` endpoint rejects OAuth-authenticated requests that do not match the Claude Code CLI fingerprint (response: `429 rate_limit_error` with an empty `\"Error\"` message). To pass, the plugin applies the same transformation that `@ex-machina/opencode-anthropic-auth` uses for OpenCode's main chat, but only for its own translator requests:\n\n- `user-agent: claude-cli/2.1.87 (external, cli)`\n- Required `anthropic-beta` headers (`oauth-2025-04-20`, `interleaved-thinking-2025-05-14`)\n- `?beta=true` appended to the `/v1/messages` URL\n- `x-anthropic-billing-header` block prepended to `system[]` (deterministic CCH of the first user message)\n- `\"You are a Claude agent, built on Anthropic's Claude Agent SDK.\"` injected as the next `system[]` block\n\nThe technique and constants are documented in https://github.com/ex-machina-co/opencode-anthropic-auth. See `src/anthropic-oauth.ts`.\n\nTradeoffs:\n\n- Relies on an undocumented Anthropic OAuth request shape. Anthropic can change this at any time and force the plugin to stop using OAuth.\n- OpenCode upstream removed Anthropic OAuth support for legal / policy reasons. Installing this plugin reintroduces an equivalent code path in your environment.\n- Translator requests contribute to your Claude Pro/Max rate limit alongside OpenCode's main chat.\n\nIf you prefer a plain API key, set `ANTHROPIC_API_KEY` in the environment or pass `apiKey` in plugin options. The plugin prefers explicit `apiKey`, then `ANTHROPIC_API_KEY`, then OAuth.\n\n## Manual Smoke Test\n\n1. Install the plugin and configure `sourceLanguage: \"ko\"`, `displayLanguage: \"ko\"`.\n2. Start a new session and send `$en 프로젝트 루트의 package.json을 읽고 요약해줘`.\n3. Confirm the activation banner appears.\n4. Confirm the `→ EN: ...` preview appears under the user message.\n5. Confirm assistant text streams in English, then gains a translated trailer when the text part finishes.\n6. Confirm later messages in the same session translate without repeating `$en`.\n7. Confirm editing a historical translated user message falls back to the edited text being sent as-is (with a log entry visible under `verbose: true`).\n8. Confirm task-tool child sessions are not translated.\n9. Confirm the title remains in the source language in v1.\n\n## Development\n\n```bash\nbun install\nbun run check      # biome format + lint + organize imports (write)\nbun run typecheck  # tsgo (@typescript/native-preview, TS v7 beta)\nbun test\n```\n\nTo only verify without writing:\n\n```bash\nbun run check:ci\n```\n\n### Release\n\n`main` 브랜치에 푸시될 때 `package.json`의 `version`이 npm에 아직 없는 값이면, `.github/workflows/publish.yml`이 자동으로:\n\n1. `biome check`, `tsgo`, `bun test` 실행\n2. `npm publish --provenance --access public`\n3. `vX.Y.Z` git 태그와 GitHub Release 생성\n\n버전을 올리려면 `package.json`의 `version`만 수정해 main에 merge 하세요. 이미 publish된 버전이면 workflow는 publish를 건너뜁니다.\n\n`docs/spec.en.md` is the source of truth for behavior.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fysm-dev%2Fopencode-translate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fysm-dev%2Fopencode-translate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fysm-dev%2Fopencode-translate/lists"}