Skip to content

Commit 480cb19

Browse files
committed
Merge remote-tracking branch 'origin/master' into express-5-8529
2 parents 1cfe5e8 + 7849864 commit 480cb19

File tree

79 files changed

+2907
-1320
lines changed

Some content is hidden

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

79 files changed

+2907
-1320
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: 13 additions & 7 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,27 @@
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:*)",
2227
"Bash(pnpm list:*)",
28+
"Bash(pnpm list:*)",
29+
"Bash(pnpm remove:*)",
30+
"Bash(pnpm run:*)",
2331
"Bash(pnpm ts-build:*)",
2432
"Bash(pnpm tsc:*)",
33+
"Bash(pnpm update:*)",
2534
"Bash(pnpm view:*)",
2635
"Bash(pnpm why:*)",
2736
"Bash(prettier -w:*)",
2837
"Bash(psql:*)",
29-
"WebFetch(domain:cocalc.com)",
30-
"WebFetch(domain:doc.cocalc.com)",
31-
"WebFetch(domain:docs.anthropic.com)",
32-
"WebFetch(domain:github.com)",
33-
"WebFetch(domain:mistral.ai)",
34-
"WebFetch(domain:simplelocalize.io)",
35-
"WebFetch(domain:www.anthropic.com)",
38+
"Bash(python3:*)",
39+
"WebFetch",
40+
"WebSearch",
3641
"mcp__cclsp__find_definition",
42+
"mcp__cclsp__find_references",
3743
"mcp__github__get_issue",
3844
"mcp__github__get_issue_comments",
3945
"mcp__github__get_pull_request",

src/CLAUDE.md

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,20 @@ 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
3335
- `python3 ./scripts/check_npm_packages.py` - Check npm package consistency across packages
@@ -38,15 +40,16 @@ This file provides guidance to Claude Code (claude.ai/code) and also Gemini CLI
3840

3941
- `cd packages/[package] && pnpm build` - Build and compile a specific package
4042
- for packages/next and packages/static, run `cd packages/[package] && pnpm build-dev`
41-
- `cd packages/[package] && pnpm tsc:watch` - TypeScript compilation in watch mode for a specific package
4243
- `cd packages/[package] && pnpm test` - Run tests for a specific package
4344
- `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
4446
- **IMPORTANT**: When modifying packages like `util` that other packages depend on, you must run `pnpm build` in the modified package before typechecking dependent packages
4547

4648
### Development
4749

4850
- **IMPORTANT**: Always run `prettier -w [filename]` immediately after editing any .ts, .tsx, .md, or .json file to ensure consistent styling
4951
- 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!
5053

5154
## Architecture Overview
5255

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

167170
CoCalc uses react-intl for internationalization with SimpleLocalize as the translation platform.
168171

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+
169179
### Translation ID Naming Convention
170180

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

173183
Examples:
184+
174185
- `labels.masked_files` - for common UI labels
175186
- `account.sign-out.button.title` - for account sign-out dialog
176187
- `command.generic.force_build.label` - for command labels
177188

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+
178196
### Translation Workflow
179197

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

191210
### Translation File Structure
192211

193-
- `packages/frontend/i18n/README.md` - more information
194-
- `packages/frontend/i18n/common.ts` - shared translation definitions
195-
- `packages/frontend/i18n/extracted.json` - auto-generated, do not edit manually
196-
- `packages/frontend/i18n/[locale].json` - downloaded translations per language
197-
- `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
198218

199219
# Ignore
200220

201221
- Ignore files covered by `.gitignore`
202222
- Ignore everything in `node_modules` or `dist` directories
203223
- 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/packages/backend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
"@types/debug": "^4.1.12",
4747
"@types/jest": "^30.0.0",
4848
"awaiting": "^3.0.0",
49-
"better-sqlite3": "^11.10.0",
49+
"better-sqlite3": "^12.2.0",
5050
"chokidar": "^3.6.0",
5151
"debug": "^4.4.0",
5252
"fs-extra": "^11.2.0",

src/packages/frontend/account/i18n-selector.tsx

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,20 @@
44
*/
55

66
/*
7-
Basically a drop-down to change the langauge (i18n localization)
7+
Basically a drop-down to change the language (i18n localization)
88
*/
99

1010
import { DownOutlined } from "@ant-design/icons";
11-
import { Button, Dropdown, MenuProps, Modal, Space, Tooltip } from "antd";
11+
import {
12+
Button,
13+
Dropdown,
14+
MenuProps,
15+
Modal,
16+
Select,
17+
SelectProps,
18+
Space,
19+
Tooltip,
20+
} from "antd";
1221
import { SizeType } from "antd/es/config-provider/SizeContext";
1322
import { useState } from "react";
1423
import { defineMessage, useIntl } from "react-intl";
@@ -54,6 +63,50 @@ Thank you for your patience and understanding as we work to make our application
5463
description: "Content of translation information modal",
5564
});
5665

66+
interface LanguageSelectorProps
67+
extends Omit<SelectProps, "options" | "onChange"> {
68+
value?: string;
69+
onChange?: (language: Locale) => void;
70+
}
71+
72+
/**
73+
* A reusable language selector component for translation purposes.
74+
*/
75+
export function LanguageSelector({
76+
value,
77+
onChange,
78+
...props
79+
}: LanguageSelectorProps) {
80+
const intl = useIntl();
81+
82+
let availableLocales = Object.keys(LOCALIZATIONS) as Locale[];
83+
84+
const options = availableLocales.map((locale) => {
85+
const localization = LOCALIZATIONS[locale];
86+
const other =
87+
locale === value
88+
? localization.name
89+
: intl.formatMessage(localization.trans);
90+
return {
91+
value: locale,
92+
label: `${localization.flag} ${localization.native} (${other})`,
93+
};
94+
});
95+
96+
return (
97+
<Select
98+
value={value}
99+
onChange={onChange}
100+
options={options}
101+
placeholder="Select a language..."
102+
showSearch
103+
optionFilterProp="label"
104+
popupMatchSelectWidth={false}
105+
{...props}
106+
/>
107+
);
108+
}
109+
57110
export function I18NSelector(props: Readonly<Props>) {
58111
const { isWide = true, size, confirm = false } = props;
59112

@@ -114,7 +167,7 @@ export function I18NSelector(props: Readonly<Props>) {
114167

115168
const menu: MenuProps = {
116169
items,
117-
style: { maxHeight: "75vh", overflow: "auto" },
170+
style: { maxHeight: "50vh", overflow: "auto" },
118171
onClick: ({ key }) => {
119172
if (key in LOCALIZATIONS) {
120173
if (confirm) {

0 commit comments

Comments
 (0)