Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ First contribution checklist:

Translated READMEs: [`translated_readmes/`](./translated_readmes/README.md), available in English, 简体中文, 繁體中文, 日本語.

The App is available in the following languages: English (`en`), Japanese (`ja`), Simplified Chinese (`zh`), Vietnamese (`vi`), Brazilian Portuguese (`pt-BR`).
The App is available in the following languages: English (`en`), Japanese (`ja`), Simplified Chinese (`zh`), Vietnamese (`vi`), Brazilian Portuguese (`pt-BR`), Russian (`ru`).

## For Teams & Businesses

Expand Down
6 changes: 3 additions & 3 deletions TRANSLATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ If you want to add a new README language:

You can also help translate the app UI via:

- `packages/app/src/i18n/`
- `apps/app/src/i18n/`

Currently available app UI locales: English (`en`), Japanese (`ja`), Simplified Chinese (`zh`), Vietnamese (`vi`), Brazilian Portuguese (`pt-BR`).
Currently available app UI locales: English (`en`), Japanese (`ja`), Simplified Chinese (`zh`), Vietnamese (`vi`), Brazilian Portuguese (`pt-BR`), Russian (`ru`).

Locale files live in `packages/app/src/i18n/locales/`.
Locale files live in `apps/app/src/i18n/locales/`.

If you are unsure where to start, open an issue and mention the language you want to contribute.
22 changes: 20 additions & 2 deletions apps/app/src/i18n/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@ import th from "./locales/th";
import fr from "./locales/fr";
import ca from "./locales/ca";
import es from "./locales/es";
import ru from "./locales/ru";
import { LANGUAGE_PREF_KEY } from "../app/constants";

/**
* Supported languages
*/
export type Language = "en" | "ja" | "zh" | "vi" | "pt-BR" | "th" | "fr" | "ca" | "es";
export type Language = "en" | "ja" | "zh" | "vi" | "pt-BR" | "th" | "fr" | "ca" | "es" | "ru";
export type Locale = Language;

/**
* All supported languages - single source of truth
*/
export const LANGUAGES: Language[] = ["en", "ja", "zh", "vi", "pt-BR", "th", "fr", "ca", "es"];
export const LANGUAGES: Language[] = ["en", "ja", "zh", "vi", "pt-BR", "th", "fr", "ca", "es", "ru"];

/**
* Language options for UI - single source of truth
Expand All @@ -33,8 +34,24 @@ export const LANGUAGE_OPTIONS = [
{ value: "fr" as Language, label: "French", nativeName: "Français" },
{ value: "ca" as Language, label: "Català", nativeName: "Català" },
{ value: "es" as Language, label: "Español", nativeName: "Español" },
{ value: "ru" as Language, label: "Русский", nativeName: "Русский" },
] as const;

const PLURAL_SUFFIX_EMPTY_LANGUAGES = new Set<Language>(["ja", "zh", "th"]);

/**
* Current translation strings use an English-style plural suffix placeholder.
* Some locales render the noun without a visible plural marker, so we keep
* that suffix empty for them.
*/
export const pluralSuffix = (locale: Language, count: number): string => {
if (PLURAL_SUFFIX_EMPTY_LANGUAGES.has(locale)) {
return "";
}

return count === 1 ? "" : "s";
};

/**
* Translation maps
*/
Expand All @@ -48,6 +65,7 @@ const TRANSLATIONS: Record<Language, Record<string, string>> = {
fr,
ca,
es,
ru,
};

/**
Expand Down
1 change: 1 addition & 0 deletions apps/app/src/i18n/locales/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export { default as ptBR } from "./pt-BR";
export { default as fr } from "./fr";
export { default as ca } from "./ca";
export { default as es } from "./es";
export { default as ru } from "./ru";
12 changes: 6 additions & 6 deletions apps/app/src/i18n/locales/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -443,8 +443,8 @@ export default {
"den.status_browser_signup": "ブラウザでアカウント作成を完了してOpenWorkに接続してください。",
"den.status_cloud_signed_in_as": "OpenWork Cloudに{email}として接続しました。",
"den.status_cloud_signin_done": "OpenWork Cloudに接続しました。",
"den.status_loaded_orgs": "{count}件の組織を読み込みました。",
"den.status_loaded_workers": "{name}の{count}件のワーカーを読み込みました。",
"den.status_loaded_orgs": "{count}件の組織{plural}を読み込みました。",
"den.status_loaded_workers": "{name}の{count}件のワーカー{plural}を読み込みました。",
"den.status_no_workers": "{name}にワーカーが見つかりません。",
"den.status_opened_worker": "OpenWorkで{name}を開きました。",
"den.status_signed_in_as": "{email}としてサインインしました。",
Expand Down Expand Up @@ -810,7 +810,7 @@ export default {
"message_list.open_session": "セッションを開く",
"message_list.step_updates_progress": "進捗を更新",
"message_list.subagent_loading_transcript": "トランスクリプトを読み込み中",
"message_list.subagent_message_count": "{count}件のメッセージ",
"message_list.subagent_message_count": "{count}件のメッセージ{plural}",
"message_list.subagent_running": "実行中",
"message_list.subagent_session_fallback": "サブエージェントセッション",
"message_list.subagent_type_task": "{agentType}タスク",
Expand Down Expand Up @@ -895,7 +895,7 @@ export default {
"onboarding.create_first_workspace": "最初のワークスペースを作成",
"onboarding.create_workspace": "ワークスペースを作成",
"onboarding.engine_running": "エンジンは既に実行中です",
"onboarding.folders_allowed": "{count}個のフォルダが許可済み",
"onboarding.folders_allowed": "{count}個のフォルダ{plural}が許可済み",
"onboarding.getting_ready": "準備しています",
"onboarding.install": "OpenCodeをインストール",
"onboarding.install_instruction": "ローカルサーバーを有効にするにはOpenCodeをインストールしてください(ターミナル不要)。",
Expand Down Expand Up @@ -1197,7 +1197,7 @@ export default {
"session.share_worker_url_phones_hint": "このワーカーに接続するスマートフォンやノートPCで使用します。",
"session.share_worker_url_resolving_hint": "ワーカーURLを解決中。フォールバックとしてホストURLを表示しています。",
"session.shared_folder_upload_failed": "共有フォルダへのアップロードに失敗しました",
"session.show_earlier": "以前の{count}件のメッセージを表示",
"session.show_earlier": "以前の{count}件のメッセージ{plural}を表示",
"session.status_active": "セッション稼働中",
"session.status_compacting": "コンテキストを圧縮中",
"session.status_delegating": "委任中",
Expand Down Expand Up @@ -1910,7 +1910,7 @@ export default {
"status.mcp_connected": "{count}件のMCP接続済み",
"status.open_docs": "ドキュメントを開く",
"status.openwork_ready": "OpenWork準備完了",
"status.providers_connected": "{count}件のプロバイダーが接続済み",
"status.providers_connected": "{count}件のプロバイダー{plural}が接続済み",
"status.ready_for_tasks": "新しいタスクの準備完了",
"status.reloading_engine": "エンジンをリロード中",
"status.restarting_engine": "エンジンを再起動中",
Expand Down
Loading