Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6245c2d
refactor(i18n): strip dead keys, normalize locales, fix broken refs
NewtTheWolf Jun 18, 2026
f8e2a17
refactor(i18n): drop redundant inline defaultValue fallbacks
NewtTheWolf Jun 18, 2026
98eeb4d
refactor(i18n): sparse target locales + consistent plurals for Tolgee
NewtTheWolf Jun 18, 2026
7004fdd
feat(i18n): OTA translation updates via Tolgee CDN
NewtTheWolf Jun 18, 2026
5385a37
feat(i18n): lingui spike — setup, provider, id-bridge verified
NewtTheWolf Jun 18, 2026
aa53542
chore(i18n): drop dead CJS catalog artifacts, gitignore compile .js o…
NewtTheWolf Jun 19, 2026
0c3bcb4
feat(i18n): lingui codemod tool + fixtures
NewtTheWolf Jun 19, 2026
4d3b953
refactor(i18n): structured codemod manifest for Task-4 backfill
NewtTheWolf Jun 19, 2026
36904ec
fix(i18n): codemod crash on multi-import + backtick fallback
NewtTheWolf Jun 19, 2026
af3f3b1
refactor(i18n): convert all call sites to lingui macros + registries
NewtTheWolf Jun 19, 2026
65423dc
fix(i18n): restore 4 interpolation value expressions lost in codemod
NewtTheWolf Jun 19, 2026
56dd529
feat(i18n): backfill lingui PO catalogs from existing translations
NewtTheWolf Jun 19, 2026
fbba927
refactor(i18n): remove i18next — native-only lingui
NewtTheWolf Jun 19, 2026
5dccbe8
test(i18n): migrate assertions from i18next keys to lingui source text
NewtTheWolf Jun 19, 2026
24084c5
fix(plugin-api): keep usePluginTranslation backwards-compatible
NewtTheWolf Jun 19, 2026
9c0fe06
feat(create-plugin): scaffold Lingui i18n + fix dead --with-ui manifest
NewtTheWolf Jun 19, 2026
ace3c34
fix(i18n): split 12 same-namespace duplicate-English collisions
NewtTheWolf Jun 19, 2026
6bdc013
chore(i18n): tolgee push format PO_ICU for source-text reimport
NewtTheWolf Jun 19, 2026
8d07bd1
feat(i18n): phase-2 runtime OTA — overlay Tolgee CDN PO at runtime
NewtTheWolf Jun 19, 2026
68b23ec
feat(i18n): regenerate catalogs live in dev via a Vite plugin
NewtTheWolf Jun 22, 2026
535202d
ci(i18n): refresh catalogs on PRs, push+backsync Tolgee
NewtTheWolf Jun 22, 2026
11ab32d
docs(i18n): document the Lingui authoring & translator workflow
NewtTheWolf Jun 22, 2026
99d9f12
Merge upstream/main into feat/integrate-tolgee
NewtTheWolf Jun 22, 2026
a8fc7a9
Merge upstream/main into feat/integrate-tolgee
NewtTheWolf Jun 22, 2026
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
65 changes: 65 additions & 0 deletions .github/workflows/i18n-catalogs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: i18n Catalogs

# Keeps the Lingui message catalogs in sync with the source, so a contributor
# who never ran `pnpm tauri dev` (which auto-regenerates them) doesn't leave the
# catalogs stale. On a PR it regenerates and commits the catalogs back onto the
# PR branch; on main it does the same as a safety net (e.g. for fork PRs that
# couldn't be auto-committed). This does NOT touch Tolgee — that happens only on
# release (see i18n-tolgee-sync.yml).

concurrency:
group: i18n-catalogs-${{ github.ref }}
cancel-in-progress: true

on:
push:
branches: [main]
paths:
- 'src/**'
- 'lingui.config.ts'
- '.github/workflows/i18n-catalogs.yml'
pull_request:
branches: [main]
paths:
- 'src/**'
- 'lingui.config.ts'
- '.github/workflows/i18n-catalogs.yml'

permissions:
contents: write

jobs:
catalogs:
runs-on: ubuntu-24.04
# Auto-commit can only push to branches in this repo, not forks. Fork PRs
# are covered by the main run after merge.
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ github.head_ref || github.ref_name }}
token: ${{ secrets.GITHUB_TOKEN }}

- uses: pnpm/action-setup@v5
name: Install pnpm

- uses: actions/setup-node@v6
with:
node-version: '20'
cache: 'pnpm'

- name: Install dependencies
run: pnpm install

- name: Regenerate message catalogs
run: |
pnpm run i18n:extract
pnpm run i18n:compile

- name: Commit refreshed catalogs
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add src/locales
git diff --staged --quiet || (git commit -m "chore(i18n): refresh message catalogs [skip ci]" && git push)
67 changes: 67 additions & 0 deletions .github/workflows/i18n-tolgee-backsync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: i18n Tolgee Backsync

# Pulls finished translations (human + machine translation) back from Tolgee into
# the bundled catalogs. Runs on a schedule because machine translation completes
# asynchronously — there's no event telling us when it's ready, so we poll.
#
# Only the target languages are pulled (never `en` — English/source is owned by
# the code), and only TRANSLATED/REVIEWED states, so untranslated keys keep their
# English fallback. After pulling, `lingui extract` re-normalizes the catalogs to
# the canonical Lingui format (matching by source+context, so msgstr is preserved)
# and `lingui compile` rebuilds messages.ts. Changes are committed with [skip ci].
#
# Requires the repo secret TOLGEE_API_KEY.

on:
schedule:
- cron: '0 3 * * *' # daily 03:00 UTC — tune for how fast you want MT to land
workflow_dispatch:

permissions:
contents: write

concurrency:
group: i18n-tolgee-backsync
cancel-in-progress: false

jobs:
backsync:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}

- uses: pnpm/action-setup@v5
name: Install pnpm

- uses: actions/setup-node@v6
with:
node-version: '20'
cache: 'pnpm'

- name: Install dependencies
run: pnpm install

- name: Pull translations from Tolgee
run: >
npx --yes @tolgee/cli@latest pull
--path src/locales
--file-structure-template "{languageTag}/messages.{extension}"
--languages de es fr it ja ru zh
--states TRANSLATED REVIEWED
env:
TOLGEE_API_KEY: ${{ secrets.TOLGEE_API_KEY }}

- name: Re-normalize and compile catalogs
run: |
pnpm run i18n:extract
pnpm run i18n:compile

- name: Commit synced translations
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add src/locales
git diff --staged --quiet || (git commit -m "chore(i18n): backsync translations from Tolgee [skip ci]" && git push)
52 changes: 52 additions & 0 deletions .github/workflows/i18n-tolgee-sync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: i18n Tolgee Sync

# Pushes the current source strings to Tolgee on every push to main, so the
# translation platform learns about new keys promptly and can start machine-
# translating them. Finished translations flow back via i18n-tolgee-backsync.yml.
#
# Uses forceMode KEEP (configured in .tolgeerc.json) — it only ADDS new keys and
# NEVER overwrites translations that already exist in Tolgee, so a typo fixed by a
# translator in Tolgee is never clobbered by the bundled catalogs. English/source
# text is owned by the code: fix source typos in the `t` string, not in Tolgee.
#
# Requires the repo secret TOLGEE_API_KEY (a Tolgee PAT or project API key with
# write access to project 32587).

concurrency:
group: i18n-tolgee-sync
cancel-in-progress: false

on:
push:
branches: [main]
paths:
- 'src/**'
- '.tolgeerc.json'
- '.github/workflows/i18n-tolgee-sync.yml'
workflow_dispatch:

jobs:
tolgee:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v6

- uses: pnpm/action-setup@v5
name: Install pnpm

- uses: actions/setup-node@v6
with:
node-version: '20'
cache: 'pnpm'

- name: Install dependencies
run: pnpm install

- name: Regenerate source catalog
run: pnpm run i18n:extract

- name: Push source strings to Tolgee
run: npx --yes @tolgee/cli@latest push
env:
TOLGEE_API_KEY: ${{ secrets.TOLGEE_API_KEY }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,6 @@ plugins/**/target
.gitnexus
.pi/
.atl/

# Lingui: never commit CJS compile output (we ship the --typescript ES catalogs)
src/locales/**/*.js
2 changes: 1 addition & 1 deletion .rules/general.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# General Rules
1. **Language:** Use **English** for all code comments, documentation, and commit messages. Translate other languages in @src/i18n/locales .
1. **Language:** Use **English** for all code comments, documentation, and commit messages. User-facing UI strings are authored in English via Lingui macros — see [i18n Rules](./i18n.md); you do not write translations by hand.
2. **Package Manager:** Always use **pnpm** instead of npm or yarn.
6 changes: 6 additions & 0 deletions .rules/i18n.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# i18n Rules

1. **Author in English only.** Wrap every user-facing string in a Lingui macro — `` t`...` `` / `t({ message })` from `@lingui/core/macro`, or `<Trans>` / `useLingui().t` from `@lingui/react/macro`. Never ship a bare UI string literal.
2. **Do not write translations by hand.** Contributors are **not** required to translate. `pnpm tauri dev` (and `pnpm i18n:extract`) regenerates the catalogs from your source strings; missing translations fall back to English and are filled later via Tolgee + over-the-air delivery. After extracting you _may_ fill other locales' `.po` files, but it is optional.
3. **Catalogs are generated artifacts.** `src/locales/<lng>/messages.po` (source) and `messages.ts` (compiled) are produced by `lingui extract` / `lingui compile`. The dev server regenerates them on save — never edit them by hand. Commit the regenerated catalogs alongside the code that introduced the strings.
4. **Plugin UI strings are separate.** A plugin's strings live in its own `locales/<lang>.json` (ICU `{var}` placeholders), read via `usePluginTranslation(pluginId)` — they are not part of the app catalogs.
46 changes: 46 additions & 0 deletions .tolgeerc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"$schema": "https://docs.tolgee.io/cli-schema.json",
"apiUrl": "https://app.tolgee.io",
"projectId": 32587,
"format": "PO_ICU",
"patterns": [
"./src/**/*.ts?(x)"
],
"push": {
"files": [
{
"path": "src/locales/en/messages.po",
"language": "en"
},
{
"path": "src/locales/de/messages.po",
"language": "de"
},
{
"path": "src/locales/es/messages.po",
"language": "es"
},
{
"path": "src/locales/fr/messages.po",
"language": "fr"
},
{
"path": "src/locales/it/messages.po",
"language": "it"
},
{
"path": "src/locales/ja/messages.po",
"language": "ja"
},
{
"path": "src/locales/ru/messages.po",
"language": "ru"
},
{
"path": "src/locales/zh/messages.po",
"language": "zh"
}
],
"forceMode": "KEEP"
}
}
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Adhere to the rules defined in the [rules directory](./.rules/):
- [Rust Rules](./.rules/rust.md) (Backend module structure and Rust testing)
- [TypeScript Rules](./.rules/typescript.md)
- [React Rules](./.rules/react.md)
- [Frontend Rules](./.rules/frontend.md) (Driver-agnostic frontend)
- [i18n Rules](./.rules/i18n.md) (Lingui authoring & translation workflow)
- [Modal Styling Rules](./.rules/modals.md) (Modal component structure and styling)
- [Testing Conventions](./.rules/testing.md) (Test file organization and structure)

Expand Down
18 changes: 18 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ All types of contributions are encouraged and valued. See the [Table of Contents
- [Suggesting Enhancements](#suggesting-enhancements)
- [Your First Code Contribution](#your-first-code-contribution)
- [Improving The Documentation](#improving-the-documentation)
- [Translations](#translations)
- [Styleguides](#styleguides)
- [Commit Messages](#commit-messages)
- [Join The Project Team](#join-the-project-team)
Expand Down Expand Up @@ -154,6 +155,23 @@ Updating, improving and correcting the documentation

-->

### Translations

Tabularis is localized with [Lingui](https://lingui.dev), and the source language is English.

**For code contributors — you don't have to translate anything.** Just wrap every user-facing string in a Lingui macro and write it in English:

```tsx
import { useLingui } from "@lingui/react/macro";

const { t } = useLingui();
return <button>{t`Add Connection`}</button>;
```

`pnpm tauri dev` regenerates the catalogs (`src/locales/<lng>/messages.po` and the compiled `messages.ts`) automatically on save, so you never edit them by hand — commit the regenerated catalogs alongside your change. If you forget, CI regenerates and commits them on your PR. Strings without a translation fall back to English. After extracting you _may_ fill in other locales' `.po` files, but it is entirely optional; leave them and a translator (or the maintainers) will.

**For translators.** Translations live in [Tolgee](https://tolgee.io), not in the repository: source strings are pushed there, translated, reviewed, and delivered to the app over the air — so a corrected translation reaches users without waiting for a release. You never need to touch `.po` files or open a PR to translate. If you'd like to help translate Tabularis, or want a new language added, open an [issue](https://github.com/TabularisDB/tabularis/issues) or ping us on [Discord](https://discord.com/invite/K2hmhfHRSt) and we'll get you set up.

## Styleguides

### Commit Messages
Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,19 @@ pnpm tauri dev
pnpm tauri build
```

### Translations

The UI is localized with [Lingui](https://lingui.dev), and **you don't need to translate anything to contribute** — just wrap user-facing strings in a Lingui macro and write them in English:

```tsx
import { useLingui } from "@lingui/react/macro";

const { t } = useLingui();
<button>{t`Add Connection`}</button>;
```

`pnpm tauri dev` regenerates the message catalogs (`src/locales/<lng>/messages.po`) on save, so new strings appear immediately via HMR. Untranslated strings fall back to English; the actual translations are managed in [Tolgee](https://tolgee.io) and delivered over the air, so they reach users without an app release. See [CONTRIBUTING.md](./CONTRIBUTING.md#translations) for the translator workflow.

## Roadmap

- [x] [[Feat]: Allow loading of multiple Databases per connection](https://github.com/TabularisDB/tabularis/issues/47)
Expand Down
14 changes: 14 additions & 0 deletions lingui.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { defineConfig } from "@lingui/cli";
import { formatter } from "@lingui/format-po";

export default defineConfig({
sourceLocale: "en",
locales: ["en", "it", "es", "zh", "fr", "de", "ja", "ru"],
catalogs: [
{
path: "src/locales/{locale}/messages",
include: ["src"],
},
],
format: formatter({ lineNumbers: false }),
});
15 changes: 12 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,19 @@
"check:plugin-api": "pnpm --filter @tabularis/plugin-api check:sync",
"build:create-plugin": "pnpm --filter @tabularis/create-plugin build",
"smoke:create-plugin": "pnpm --filter @tabularis/create-plugin smoke",
"i18n:extract": "lingui extract",
"i18n:compile": "lingui compile --typescript --namespace es",
"i18n:backfill": "node scripts/i18n/backfill.mjs",
"roadmap": "node scripts/update-roadmap.js",
"sync-links": "node scripts/sync-links.js",
"sync-sponsors": "node scripts/sync-sponsors.js",
"version": "node scripts/sync-version.js && conventional-changelog -p angular -i CHANGELOG.md -s && git add README.md CHANGELOG.md src-tauri/tauri.conf.json src-tauri/Cargo.toml src-tauri/Cargo.lock src/version.ts"
},
"dependencies": {
"@lingui/core": "^6.4.0",
"@lingui/format-po": "^6.4.0",
"@lingui/message-utils": "^6.4.0",
"@lingui/react": "^6.4.0",
"@monaco-editor/react": "^4.7.0",
"@tailwindcss/postcss": "^4.2.2",
"@tanstack/react-table": "^8.21.3",
Expand All @@ -48,16 +55,14 @@
"clsx": "^2.1.1",
"dagre": "^0.8.5",
"emoji-picker-react": "^4.19.1",
"i18next": "^25.10.10",
"i18next-browser-languagedetector": "^8.2.1",
"json-edit-react": "^1.29.1",
"lucide-react": "^0.563.0",
"monaco-editor": "^0.55.1",
"pofile": "^1.1.4",
"process": "^0.11.10",
"react": "^19.2.4",
"react-colorful": "^5.7.0",
"react-dom": "^19.2.4",
"react-i18next": "^16.6.6",
"react-markdown": "^10.1.0",
"react-router-dom": "^7.13.2",
"recharts": "^3.8.1",
Expand All @@ -66,6 +71,9 @@
},
"devDependencies": {
"@eslint/js": "^9.39.4",
"@lingui/babel-plugin-lingui-macro": "^6.4.0",
"@lingui/cli": "^6.4.0",
"@lingui/vite-plugin": "^6.4.0",
"@tauri-apps/cli": "^2.10.1",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
Expand All @@ -85,6 +93,7 @@
"jsdom": "^28.1.0",
"postcss": "^8.5.8",
"tailwindcss": "^4.2.2",
"ts-morph": "^28.0.0",
"typescript": "~5.9.3",
"typescript-eslint": "^8.58.0",
"vite": "^7.3.1",
Expand Down
Loading
Loading