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
1 change: 1 addition & 0 deletions crates/services/src/services/config/versions/v6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub enum UiLanguage {
#[default]
Browser, // Detect from browser
En, // Force English
Ru, // Force Russian
Fr, // Force French
Ja, // Force Japanese
Es, // Force Spanish
Expand Down
56 changes: 56 additions & 0 deletions docs/designs/russian-localization-upstream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Russian Localization Upstream Plan

Status: active
Date: 2026-03-29
Branch: feat/i18n-foundation-ru

## Goal

Add Russian as a first-class Vibe Kanban locale and upstream it in a way that maintainers can review and extend easily.

## Why This Is Split Into Two PRs

One large "add Russian + invent the locale workflow" PR is harder to review and easier to reject on process grounds.

Two smaller PRs keep the review clean:

1. PR 1 adds localization infrastructure for future contributors.
2. PR 2 adds the Russian locale using that infrastructure.

## PR 1: Localization Infrastructure

Scope:

- Add a documented workflow for introducing a new locale.
- Add a locale scaffold script that copies the English namespace files into a new locale directory.
- Add a QA helper that reports untranslated or unchanged strings compared to English.
- Keep the change small. No new runtime abstractions. No CI policy changes.

Out of scope:

- Adding Russian translations.
- Refactoring the existing i18n system.
- Translating docs or README.

## PR 2: Add Russian Locale

Scope:

- Add `RU` to the config enum and generated shared types.
- Register `ru` in the frontend language map and i18n resources.
- Add `packages/web-core/src/i18n/locales/ru/*.json`.
- Verify language selection, browser detection, and key consistency.

Out of scope:

- Rewriting existing copy.
- Bulk cleanup of unrelated hardcoded strings.
- Translating the marketing site or documentation.

## Acceptance Bar

Both PRs should be independently reviewable and green on existing checks.

PR 1 should make the next locale cheaper to add.

PR 2 should feel like a complete product locale, not a partial translation dump.
82 changes: 82 additions & 0 deletions docs/i18n.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Internationalization Workflow

Vibe Kanban already ships multiple first-class locales. This document describes the lowest-friction way to add another one without missing type, config, or QA steps.

## Locale layout

Frontend locale files live in:

`packages/web-core/src/i18n/locales/<i18n-code>/`

Each locale currently mirrors the English namespaces:

- `common.json`
- `settings.json`
- `projects.json`
- `tasks.json`
- `organization.json`

English is the source locale:

`packages/web-core/src/i18n/locales/en/`

## Add a new locale

1. Scaffold the locale files from English:

```bash
node scripts/create-locale.mjs --ui RU --code ru --name "Русский"
```

2. Register the language in the config enum:

`crates/services/src/services/config/versions/v6.rs`

3. Regenerate shared types:

```bash
pnpm run generate-types
```

4. Register the language mapping and endonym:

`packages/web-core/src/i18n/languages.ts`

5. Register the locale resources:

`packages/web-core/src/i18n/config.ts`

6. Translate the new locale JSON files.

## QA checklist

Run the existing i18n checks:

```bash
./scripts/check-i18n.sh
node scripts/check-unused-i18n-keys.mjs
```

Run the unchanged-string helper for the new locale:

```bash
node scripts/check-locale-translation.mjs ru
```

Use `--fail-on-identical` if you want the command to exit non-zero when the locale still contains English strings:

```bash
node scripts/check-locale-translation.mjs ru --fail-on-identical
```

## Review expectations

For upstream locale PRs, aim for:

- full namespace coverage
- no missing keys
- no accidental English leftovers in user-facing strings
- working language selection in Settings
- sensible browser-language detection

Keep locale workflow changes separate from large translation changes when possible. It makes review much easier.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
"remote:generate-types:check": "cargo run --manifest-path crates/remote/Cargo.toml --bin remote-generate-types -- --check",
"prepare-db": "node scripts/prepare-db.js",
"prepare-db:check": "node scripts/prepare-db.js --check",
"locale:new": "node scripts/create-locale.mjs",
"locale:check": "node scripts/check-locale-translation.mjs",
"build:bippy-bundle": "node scripts/build-bippy-bundle.mjs",
"build:npx": "bash ./local-build.sh",
"build:npx-cli": "cd npx-cli && npm ci && npm run build",
Expand Down
12 changes: 12 additions & 0 deletions packages/web-core/src/i18n/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import enSettings from './locales/en/settings.json';
import enProjects from './locales/en/projects.json';
import enTasks from './locales/en/tasks.json';
import enOrganization from './locales/en/organization.json';
import ruCommon from './locales/ru/common.json';
import ruSettings from './locales/ru/settings.json';
import ruProjects from './locales/ru/projects.json';
import ruTasks from './locales/ru/tasks.json';
import ruOrganization from './locales/ru/organization.json';
import frCommon from './locales/fr/common.json';
import frSettings from './locales/fr/settings.json';
import frProjects from './locales/fr/projects.json';
Expand Down Expand Up @@ -48,6 +53,13 @@ const resources = {
tasks: enTasks,
organization: enOrganization,
},
ru: {
common: ruCommon,
settings: ruSettings,
projects: ruProjects,
tasks: ruTasks,
organization: ruOrganization,
},
fr: {
common: frCommon,
settings: frSettings,
Expand Down
3 changes: 3 additions & 0 deletions packages/web-core/src/i18n/languages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

export const UI_TO_I18N = {
EN: 'en',
RU: 'ru',
FR: 'fr',
JA: 'ja',
ES: 'es',
Expand All @@ -17,6 +18,7 @@ export const UI_TO_I18N = {
const SUPPORTED_UI_LANGUAGES = [
'BROWSER',
'EN',
'RU',
'FR',
'JA',
'ES',
Expand All @@ -28,6 +30,7 @@ export const SUPPORTED_I18N_CODES = Object.values(UI_TO_I18N);

const FALLBACK_ENDONYMS = {
en: 'English',
ru: 'Русский',
fr: 'Français',
ja: '日本語',
es: 'Español',
Expand Down
Loading