Skip to content

Commit f6bcdf0

Browse files
committed
Merge remote-tracking branch 'origin/master' into rm-tracking-cookie
2 parents c9a5dfc + 7849864 commit f6bcdf0

File tree

115 files changed

+4826
-2442
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+4826
-2442
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Update i18n Translations
2+
3+
Complete workflow for updating internationalization translations in CoCalc frontend.
4+
5+
## What this command does
6+
7+
This command runs the full i18n update sequence:
8+
1. **Extract** new translation strings from source code
9+
2. **Upload** them to SimpleLocalize for automatic translation to 19+ languages
10+
3. **Download** the translated files
11+
4. **Compile** them for runtime use
12+
13+
## Usage
14+
15+
```
16+
/update-i18n
17+
```
18+
19+
## Commands executed
20+
21+
Run this in `./packages/frontend/`
22+
23+
Step 1:
24+
25+
Wait for the auto-translations to finish
26+
27+
```bash
28+
pnpm i18n:extract && pnpm i18n:upload
29+
```
30+
31+
Step 2:
32+
33+
34+
```
35+
pnpm i18n:download && pnpm i18n:compile
36+
```
37+
38+
## When to use
39+
40+
- After adding new FormattedMessage components with translation IDs
41+
- After modifying existing translation strings
42+
- When preparing translations for a new feature release
43+
- When onboarding new languages
44+
45+
## Prerequisites
46+
47+
- Must be in the `packages/frontend` directory
48+
- SIMPLELOCALIZE_KEY environment variable must be set
49+
- Changes to translation strings should already be committed to source code

src/.claude/settings.json

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
"allow": [
44
"Bash(../node_modules/.bin/tsc:*)",
55
"Bash(NODE_OPTIONS=--max-old-space-size=8192 ../node_modules/.bin/tsc --noEmit)",
6+
"Bash(bash:*)",
7+
"Bash(chmod:*)",
68
"Bash(curl:*)",
79
"Bash(docker run:*)",
810
"Bash(find:*)",
@@ -17,23 +19,34 @@
1719
"Bash(npm show:*)",
1820
"Bash(npm view:*)",
1921
"Bash(npx tsc:*)",
22+
"Bash(pnpm add:*)",
23+
"Bash(pnpm audit:*)",
2024
"Bash(pnpm build:*)",
2125
"Bash(pnpm i18n:*)",
26+
"Bash(pnpm info:*)",
27+
"Bash(pnpm list:*)",
28+
"Bash(pnpm remove:*)",
29+
"Bash(pnpm run:*)",
2230
"Bash(pnpm ts-build:*)",
2331
"Bash(pnpm tsc:*)",
32+
"Bash(pnpm view:*)",
33+
"Bash(pnpm update:*)",
34+
"Bash(pnpm why:*)",
2435
"Bash(prettier -w:*)",
2536
"Bash(psql:*)",
26-
"WebFetch(domain:cocalc.com)",
27-
"WebFetch(domain:doc.cocalc.com)",
28-
"WebFetch(domain:docs.anthropic.com)",
29-
"WebFetch(domain:github.com)",
30-
"WebFetch(domain:mistral.ai)",
31-
"WebFetch(domain:simplelocalize.io)",
32-
"Bash(pnpm list:*)",
33-
"Bash(pnpm why:*)",
37+
"Bash(python3:*)",
38+
"WebFetch",
39+
"WebSearch",
40+
"mcp__cclsp__find_definition",
41+
"mcp__cclsp__find_references",
3442
"mcp__github__get_issue",
35-
"WebFetch(domain:www.anthropic.com)",
36-
"mcp__cclsp__find_definition"
43+
"mcp__github__get_issue_comments",
44+
"mcp__github__get_pull_request",
45+
"mcp__github__get_pull_request_comments",
46+
"mcp__github__get_pull_request_comments",
47+
"mcp__github__get_pull_request_status",
48+
"mcp__github__list_workflow_runs",
49+
"mcp__github__list_workflows"
3750
],
3851
"deny": []
3952
}

src/CLAUDE.md

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,36 +16,40 @@ This file provides guidance to Claude Code (claude.ai/code) and also Gemini CLI
1616
- Run `pretter -w [filename]` after modifying a file (ts, tsx, md, json, ...) to format it correctly.
1717
- All .js and .ts files are formatted by the tool prettier
1818
- Add suitable types when you write code
19-
- Variable name styles are "camelCase" for local and "FOO_BAR" for global variables. If you edit older code not following these guidlines, adjust this rule to fit the files style.
19+
- Follow DRY principles!
20+
- Variable name styles are `camelCase` for local and `FOO_BAR` for global variables. React Components and Classes are `FooBar`. If you edit older code not following these guidlines, adjust this rule to fit the files style.
2021
- Some older code is JavaScript or CoffeeScript, which will be translated to TypeScript
2122
- Use ES modules (import/export) syntax, not CommonJS (require)
2223
- Organize the list of imports in such a way: installed npm packages are on top, newline, then are imports from @cocalc's code base. Sorted alphabetically.
24+
- **Colors**: Always use the `COLORS` dictionary from `@cocalc/util/theme` for all color values. Never hardcode colors like `#f0f0f0` or `rgb(...)`. Import with `import { COLORS } from "@cocalc/util/theme";` and use predefined constants like `COLORS.GRAY_M`, `COLORS.GRAY_L`, `COLORS.GRAY_LL`, etc.
2325
- **Backend Logging**: Use `getLogger` from `@cocalc/project/logger` for logging in backend code. Do NOT use `console.log`. Example: `const L = getLogger("module:name").debug;`
2426

2527
## Development Commands
2628

2729
### Essential Commands
2830

2931
- `pnpm build-dev` - Build all packages for development
30-
- `pnpm clean` - Clean all node_modules and dist directories
32+
- `pnpm clean` - Clean all `node_modules` and `dist` directories
3133
- `pnpm test` - Run full test suite
3234
- `pnpm depcheck` - Check for dependency issues
35+
- `python3 ./scripts/check_npm_packages.py` - Check npm package consistency across packages
3336
- `prettier -w [filename]` to format the style of a file after editing it
3437
- after creating a file, run `git add [filename]` to start tracking it
3538

3639
### Package-Specific Commands
3740

3841
- `cd packages/[package] && pnpm build` - Build and compile a specific package
3942
- for packages/next and packages/static, run `cd packages/[package] && pnpm build-dev`
40-
- `cd packages/[package] && pnpm tsc:watch` - TypeScript compilation in watch mode for a specific package
4143
- `cd packages/[package] && pnpm test` - Run tests for a specific package
4244
- `cd packages/[package] && pnpm build` - Build a specific package
45+
- To typecheck the frontend, it is best to run `cd packages/static && pnpm build` - this implicitly compiles the frontend and reports typescript errors
4346
- **IMPORTANT**: When modifying packages like `util` that other packages depend on, you must run `pnpm build` in the modified package before typechecking dependent packages
4447

4548
### Development
4649

4750
- **IMPORTANT**: Always run `prettier -w [filename]` immediately after editing any .ts, .tsx, .md, or .json file to ensure consistent styling
4851
- After TypeScript or `*.tsx` changes, run `pnpm build` in the relevant package directory
52+
- When editing the frontend, run `pnpm build-dev` in `packages/static`. This implicitly builds the frontend!
4953

5054
## Architecture Overview
5155

@@ -165,18 +169,34 @@ CoCalc is organized as a monorepo with key packages:
165169

166170
CoCalc uses react-intl for internationalization with SimpleLocalize as the translation platform.
167171

172+
### Architecture Overview
173+
174+
- **Library**: Uses `react-intl` library with `defineMessages()` and `defineMessage()`
175+
- **Default Language**: English uses `defaultMessage` directly - no separate English translation files
176+
- **Supported Languages**: 19+ languages including German, Chinese, Spanish, French, Italian, Dutch, Russian, Japanese, Portuguese, Korean, Polish, Turkish, Hebrew, Hindi, Hungarian, Arabic, and Basque
177+
- **Translation Platform**: SimpleLocalize with OpenAI GPT-4o for automatic translations
178+
168179
### Translation ID Naming Convention
169180

170181
Translation IDs follow a hierarchical pattern: `[directory].[subdir].[filename].[aspect].[label|title|tooltip|...]`
171182

172183
Examples:
184+
173185
- `labels.masked_files` - for common UI labels
174186
- `account.sign-out.button.title` - for account sign-out dialog
175187
- `command.generic.force_build.label` - for command labels
176188

189+
### Usage Patterns
190+
191+
- **TSX Components**: `<FormattedMessage id="..." defaultMessage="..." />`
192+
- **Data Structures**: `defineMessage({id: "...", defaultMessage: "..."})`
193+
- **Programmatic Use**: `useIntl()` hook + `intl.formatMessage()`
194+
- **Non-React Contexts**: `getIntl()` function
195+
177196
### Translation Workflow
178197

179198
**For new translation keys:**
199+
180200
1. Add the translation to source code (e.g., `packages/frontend/i18n/common.ts`)
181201
2. Run `pnpm i18n:extract` - updates `extracted.json` from source code
182202
3. Run `pnpm i18n:upload` - sends new strings to SimpleLocalize
@@ -189,14 +209,22 @@ Same flow as above, but **before 3. i18n:upload**, delete the key. Only new keys
189209

190210
### Translation File Structure
191211

192-
- `packages/frontend/i18n/README.md` - more information
193-
- `packages/frontend/i18n/common.ts` - shared translation definitions
194-
- `packages/frontend/i18n/extracted.json` - auto-generated, do not edit manually
195-
- `packages/frontend/i18n/[locale].json` - downloaded translations per language
196-
- `packages/frontend/i18n/[locale].compiled.json` - compiled for runtime use
212+
- `packages/frontend/i18n/README.md` - detailed documentation
213+
- `packages/frontend/i18n/common.ts` - shared translation definitions (labels, menus, editor, jupyter, etc.)
214+
- `packages/frontend/i18n/extracted.json` - auto-extracted messages from source code
215+
- `packages/frontend/i18n/trans/[locale].json` - downloaded translations from SimpleLocalize
216+
- `packages/frontend/i18n/trans/[locale].compiled.json` - compiled translation files for runtime
217+
- `packages/frontend/i18n/index.ts` - exports and locale loading logic
197218

198219
# Ignore
199220

200221
- Ignore files covered by `.gitignore`
201222
- Ignore everything in `node_modules` or `dist` directories
202223
- Ignore all files not tracked by Git, unless they are newly created files
224+
225+
# important-instruction-reminders
226+
227+
Do what has been asked; nothing more, nothing less.
228+
NEVER create files unless they're absolutely necessary for achieving your goal.
229+
ALWAYS prefer editing an existing file to creating a new one.
230+
NEVER proactively create documentation files (\*.md) or README files. Only create documentation files if explicitly requested by the User.

src/compute/compute/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
"devDependencies": {
5454
"@types/cookie": "^0.6.0",
5555
"@types/node": "^18.16.14",
56-
"typescript": "^5.7.3"
56+
"typescript": "^5.9.2"
5757
},
5858
"pnpm-comment": "There is a WRONG warning during install saying this onlyBuiltDependencies won't be used because it is in this file, but this is the ONLY place that works. We do also put it there.",
5959
"pnpm": {

src/packages/backend/conat/test/core/basic.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ describe("basic test of publish and subscribe", () => {
101101
const sub1 = await cn.subscribe(subject);
102102
await expect(async () => {
103103
await cn.subscribe(subject, { queue: "xxx" });
104-
}).rejects.toThrowError("one queue group");
104+
}).rejects.toThrow("one queue group");
105105

106106
sub1.stop();
107107
// now this works
@@ -259,7 +259,7 @@ describe("basic tests of request/respond", () => {
259259
it("call the iter server -- test that throws an error", async () => {
260260
await expect(async () => {
261261
await callIter(c1, null);
262-
}).rejects.toThrowError("is not iterable");
262+
}).rejects.toThrow("is not iterable");
263263
});
264264
});
265265

src/packages/backend/conat/test/core/core-stream-break.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ describe("stop persist server, create a client, create an ephemeral core-stream,
6565

6666
await expect(async () => {
6767
await stream.publish("y", { timeout: 100 });
68-
}).rejects.toThrowError();
68+
}).rejects.toThrow();
6969

7070
try {
7171
await stream.publish("y", { timeout: 100 });

src/packages/backend/conat/test/core/core-stream.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ describe("create a client, create an ephemeral core-stream, and do basic tests",
6060
it("publishing undefined is not allowed", async () => {
6161
await expect(
6262
async () => await stream.publish(undefined),
63-
).rejects.toThrowError("must not be 'undefined'");
63+
).rejects.toThrow("must not be 'undefined'");
6464
});
6565

6666
it("a second client has the same messages", async () => {
@@ -307,7 +307,7 @@ describe("test previousSeq when setting keys, which can be used to ensure consis
307307
it("tries to change the value using the wrong previousSeq", async () => {
308308
await expect(async () => {
309309
await stream.setKv("my", "newval", { previousSeq: 0 });
310-
}).rejects.toThrowError("wrong last sequence");
310+
}).rejects.toThrow("wrong last sequence");
311311
});
312312

313313
it("changes the value using the correct previousSeq", async () => {
@@ -398,7 +398,7 @@ describe("test permissions", () => {
398398
// they give the project_id, not their id.
399399
await expect(async () => {
400400
await stream.init();
401-
}).rejects.toThrowError("permission denied");
401+
}).rejects.toThrow("permission denied");
402402

403403
stream.close();
404404
});
@@ -415,7 +415,7 @@ describe("test permissions", () => {
415415
stream.storage.path = "hub/conat2.ipynb";
416416
await expect(async () => {
417417
await stream.init();
418-
}).rejects.toThrowError("permission denied");
418+
}).rejects.toThrow("permission denied");
419419
stream.close();
420420

421421
stream = new CoreStream({
@@ -429,7 +429,7 @@ describe("test permissions", () => {
429429
stream.user = { project_id: "00000000-0000-4000-8000-000000000004" };
430430
await expect(async () => {
431431
await stream.init();
432-
}).rejects.toThrowError("permission denied");
432+
}).rejects.toThrow("permission denied");
433433
stream.close();
434434

435435
stream = new CoreStream({
@@ -442,7 +442,7 @@ describe("test permissions", () => {
442442
stream.user = { account_id: "00000000-0000-4000-8000-000000000000" };
443443
await expect(async () => {
444444
await stream.init();
445-
}).rejects.toThrowError("permission denied");
445+
}).rejects.toThrow("permission denied");
446446

447447
stream.close();
448448
});

src/packages/backend/conat/test/core/services.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ describe("more service tests", () => {
100100
});
101101
await expect(async () => {
102102
await arith.mul(2, 3);
103-
}).rejects.toThrowError("no subscribers");
103+
}).rejects.toThrow("no subscribers");
104104
});
105105

106106
it("cleans up", () => {

src/packages/backend/conat/test/core/wait-for-interest.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ describe("test waitForInterest with request", () => {
3535
it("request throws an error by default if there is no listener", async () => {
3636
expect(async () => {
3737
await client.request("eval.server.com", "2+3");
38-
}).rejects.toThrowError("no subscribers");
38+
}).rejects.toThrow("no subscribers");
3939
});
4040

4141
it("requests with waitForInterest set and sees it work", async () => {
@@ -54,7 +54,7 @@ describe("test waitForInterest with requestMany", () => {
5454
it("request throws an error by default if there is no listener", async () => {
5555
expect(async () => {
5656
await client.requestMany("arith.server.com", [2, 3]);
57-
}).rejects.toThrowError("no subscribers");
57+
}).rejects.toThrow("no subscribers");
5858
});
5959

6060
it("requestMany with waitForInterest set and sees it work", async () => {

src/packages/backend/conat/test/server/limits.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ describe("test the per user subscription limit", () => {
2727
it("creates another subscription and gets an error", async () => {
2828
await expect(async () => {
2929
await client.sub("sub3");
30-
}).rejects.toThrowError("limit");
30+
}).rejects.toThrow("limit");
3131
});
3232

3333
it("cleans up", () => {

0 commit comments

Comments
 (0)