diff --git a/.github/workflows/make-and-test.yml b/.github/workflows/make-and-test.yml index 088354e702f..03a3c4952fc 100644 --- a/.github/workflows/make-and-test.yml +++ b/.github/workflows/make-and-test.yml @@ -106,7 +106,6 @@ jobs: pip install ipykernel python -m ipykernel install --prefix=./jupyter-local --name python3-local --display-name "Python 3 (Local)" - - name: install pnpm uses: pnpm/action-setup@v4 with: @@ -128,6 +127,191 @@ jobs: name: "test-results-node-${{ matrix.node-version }}-pg-${{ matrix.pg-version }}" path: 'src/packages/*/junit.xml' + - name: Start CoCalc Hub + run: | + # Create conat password for hub internal authentication + mkdir -p src/data/secrets + echo "test-conat-password-$(date +%s)" > src/data/secrets/conat-password + chmod 600 src/data/secrets/conat-password + + cd src/packages/hub + pnpm run hub-project-dev-nobuild > hub.log 2>&1 & + HUB_PID=$! + echo $HUB_PID > hub.pid + echo "Hub started with PID $HUB_PID" + # Check if process is still running after a moment + sleep 2 + if ! kill -0 $HUB_PID 2>/dev/null; then + echo "Error: Hub process died immediately after starting" + echo "Hub log:" + cat hub.log + exit 1 + fi + env: + PGDATABASE: smc + PGUSER: smc + PGHOST: localhost + COCALC_MODE: single-user + COCALC_TEST_MODE: yes + DEBUG: 'cocalc:*,-cocalc:silly:*,hub:*,project:*' + + - name: Wait for hub readiness + run: | + MAX_ATTEMPTS=30 + READY=false + for i in $(seq 1 $MAX_ATTEMPTS); do + if curl -sf --max-time 3 http://localhost:5000/healthcheck > /dev/null; then + echo "Hub is ready" + READY=true + break + fi + echo "Waiting for hub... ($i/$MAX_ATTEMPTS)" + sleep 3 + done + if [ "$READY" = "false" ]; then + echo "Hub failed to become ready after $MAX_ATTEMPTS attempts" + echo "Hub log:" + cat src/packages/hub/hub.log || echo "No log file found" + exit 1 + fi + + - name: Create CI admin user and API key + run: | + cd src/packages/hub + OUTPUT=$(node dist/run/test-create-admin.js) + # Split output into account_id and API key (format: UUID;api-key) + ACCOUNT_ID=$(echo "$OUTPUT" | cut -d';' -f1) + API_KEY=$(echo "$OUTPUT" | cut -d';' -f2) + + # Store in separate files + echo "$ACCOUNT_ID" > ../../account_id.txt + echo "$API_KEY" > ../../api_key.txt + + # Validate account ID (UUID format) + if ! echo "$ACCOUNT_ID" | grep -qE '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'; then + echo "Error: Invalid account ID format: $ACCOUNT_ID" + exit 1 + fi + + # Validate API key was created + if [ ! -s ../../api_key.txt ]; then + echo "Error: API key file is empty or missing" + exit 1 + fi + if ! echo "$API_KEY" | grep -qE '^sk-[A-Za-z0-9]+$'; then + echo "Error: Invalid API key format: $API_KEY" + exit 1 + fi + + echo "Account ID: $ACCOUNT_ID" + echo "API key created successfully" + env: + PGDATABASE: smc + PGUSER: smc + PGHOST: localhost + + - name: Restart CoCalc Hub + run: | + HUB_PID=$(cat src/packages/hub/hub.pid) + echo "Stopping hub with PID $HUB_PID" + kill $HUB_PID || true + # Wait a bit for graceful shutdown + sleep 5 + # Force kill if still running + kill -9 $HUB_PID 2>/dev/null || true + + # Read the admin account ID created in the previous step + cd src/packages/hub + ADMIN_ACCOUNT_ID=$(cat ../../account_id.txt) + echo "Using admin account ID: $ADMIN_ACCOUNT_ID" + + # Export env vars for the hub process + export COCALC_SETTING_JUPYTER_API_ENABLED=yes + export COCALC_SETTING_JUPYTER_ACCOUNT_ID=$ADMIN_ACCOUNT_ID + export COCALC_SETTING_JUPYTER_PROJECT_POOL_SIZE=1 + + # Start hub with new configuration + pnpm run hub-project-dev-nobuild > hub.log 2>&1 & + HUB_PID=$! + echo $HUB_PID > hub.pid + echo "Hub restarted with PID $HUB_PID" + + # Check if process is still running after a moment + sleep 2 + if ! kill -0 $HUB_PID 2>/dev/null; then + echo "Error: Hub process died immediately after restarting" + echo "Hub log:" + cat hub.log + exit 1 + fi + + # Wait for hub to be ready + MAX_ATTEMPTS=30 + READY=false + for i in $(seq 1 $MAX_ATTEMPTS); do + if curl -sf --max-time 3 http://localhost:5000/healthcheck > /dev/null; then + echo "Hub is ready after restart" + READY=true + break + fi + echo "Waiting for hub to be ready... ($i/$MAX_ATTEMPTS)" + sleep 3 + done + if [ "$READY" = "false" ]; then + echo "Hub failed to become ready after restart" + echo "Hub log:" + cat hub.log + exit 1 + fi + env: + PGDATABASE: smc + PGUSER: smc + PGHOST: localhost + COCALC_MODE: single-user + COCALC_TEST_MODE: yes + DEBUG: 'cocalc:*,-cocalc:silly:*,hub:*,project:*' + + - name: Install uv for cocalc-api tests + run: curl -LsSf https://astral.sh/uv/install.sh | sh && echo "$HOME/.local/bin" >> $GITHUB_PATH + + - name: Run cocalc-api tests + run: | + export COCALC_API_KEY=$(cat src/api_key.txt) + export COCALC_HOST=http://localhost:5000 + export CI=true + cd src/python/cocalc-api && make ci + env: + PGDATABASE: smc + PGUSER: smc + PGHOST: localhost + + - name: Stop CoCalc Hub + if: always() + run: | + if [ -f src/packages/hub/hub.pid ]; then + HUB_PID=$(cat src/packages/hub/hub.pid) + echo "Stopping hub with PID $HUB_PID" + kill $HUB_PID || true + # Wait a bit for graceful shutdown + sleep 5 + # Force kill if still running + kill -9 $HUB_PID 2>/dev/null || true + fi + + - name: Upload hub logs + uses: actions/upload-artifact@v4 + if: always() + with: + name: "hub-logs-node-${{ matrix.node-version }}-pg-${{ matrix.pg-version }}" + path: 'src/packages/hub/hub.log' + + - name: Upload cocalc-api test results + uses: actions/upload-artifact@v4 + if: always() + with: + name: "cocalc-api-test-results-node-${{ matrix.node-version }}-pg-${{ matrix.pg-version }}" + path: 'src/python/cocalc-api/test-results.xml' + report: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index b03ea399673..2ebd082b17d 100644 --- a/.gitignore +++ b/.gitignore @@ -71,6 +71,12 @@ src/conf/tinc_hosts/ # mocha: banket coverage report src/coverage src/*/coverage + +# Python coverage files +.coverage +.coverage.* +htmlcov/ +**/htmlcov/ # comes up when testing in that directory src/rethinkdb_data/ src/dev/project/rethinkdb_data/ @@ -169,3 +175,5 @@ junit.xml # autogenerated docs **/cocalc-api/site/** + +!src/packages/next/public/documents/*.pdf diff --git a/src/.claude/settings.json b/src/.claude/settings.json index 2ba490f7fc0..ebc6cbff4b5 100644 --- a/src/.claude/settings.json +++ b/src/.claude/settings.json @@ -35,6 +35,10 @@ "Bash(pnpm exec tsc:*)", "Bash(pnpm i18n:*)", "Bash(pnpm i18n:*:*)", + "Bash(pnpm i18n:compile:*)", + "Bash(pnpm i18n:download:*)", + "Bash(pnpm i18n:extract:*)", + "Bash(pnpm i18n:upload:*)", "Bash(pnpm i18n:update:*)", "Bash(pnpm info:*)", "Bash(pnpm list:*)", @@ -49,9 +53,12 @@ "Bash(prettier -w:*)", "Bash(psql:*)", "Bash(python3:*)", + "Bash(uv:*)", + "Bash(timeout:*)", "Bash(uv sync:*)", "WebFetch", "WebSearch", + "mcp__cocalc__*", "mcp__cclsp__find_definition", "mcp__cclsp__find_references", "mcp__github__get_issue", diff --git a/src/AGENTS.md b/src/AGENTS.md index 0fa74f9444d..0aee0192de9 100644 --- a/src/AGENTS.md +++ b/src/AGENTS.md @@ -105,6 +105,22 @@ CoCalc is organized as a monorepo with key packages: 5. **Authentication**: Each conat request includes account_id and is subject to permission checks at the hub level 6. **Subjects**: Messages are routed using hierarchical subjects like `hub.account.{uuid}.{service}` or `project.{uuid}.{compute_server_id}.{service}` +#### CoCalc Conat Hub API Architecture + +**API Method Registration Pattern:** + +- **Registry**: `packages/conat/hub/api/projects.ts` contains `export const projects = { methodName: authFirstRequireAccount }` +- **Implementation**: `packages/server/conat/api/projects.ts` contains `export async function methodName() { ... }` +- **Flow**: Python client `@api_method("projects.methodName")` → POST `/api/conat/hub` → `hubBridge()` → conat subject `hub.account.{account_id}.api` → registry lookup → implementation + +**Example - projects.createProject:** + +1. **Python**: `@api_method("projects.createProject")` decorator +2. **HTTP**: `POST /api/conat/hub {"name": "projects.createProject", "args": [...]}` +3. **Bridge**: `hubBridge()` routes to conat subject +4. **Registry**: `packages/conat/hub/api/projects.ts: createProject: authFirstRequireAccount` +5. **Implementation**: `packages/server/conat/api/projects.ts: export { createProject }` → `@cocalc/server/projects/create` + ### Key Technologies - **TypeScript**: Primary language for all new code @@ -158,7 +174,6 @@ CoCalc is organized as a monorepo with key packages: - Prefix git commits with the package and general area. e.g. 'frontend/latex: ...' if it concerns latex editor changes in the packages/frontend/... code. - When pushing a new branch to Github, track it upstream. e.g. `git push --set-upstream origin feature-foo` for branch "feature-foo". - ## React-intl / Internationalization (i18n) CoCalc uses react-intl for internationalization with SimpleLocalize as the translation platform. @@ -176,7 +191,7 @@ Translation IDs follow a hierarchical pattern: `[directory].[subdir].[filename]. Examples: -- `labels.masked_files` - for common UI labels +- `labels.account` - for common UI labels - `account.sign-out.button.title` - for account sign-out dialog - `command.generic.force_build.label` - for command labels @@ -216,11 +231,42 @@ Same flow as above, but **before 3. i18n:upload**, delete the key. Only new keys - Ignore everything in `node_modules` or `dist` directories - Ignore all files not tracked by Git, unless they are newly created files -# Important Instruction Reminders +# CoCalc Python API Client Investigation + +## Overview + +The `python/cocalc-api/` directory contains a uv-based Python client library for the CoCalc API, published as the `cocalc-api` package on PyPI. + +It also contains a test framework (`python/cocalc-api/tests/README.md`) and an MCP client (`python/cocalc-api/src/cocalc_api/mcp/README.md`). +For convenience, a `python/cocalc-api/Makefile` exists. + +## Client-Server Architecture Investigation + +### API Call Flow + +1. **cocalc-api Client** (Python) → HTTP POST requests +2. **Next.js API Routes** (`/api/conat/{hub,project}`) → Bridge to conat messaging +3. **ConatClient** (server-side) → NATS-like messaging protocol +4. **Hub API Implementation** (`packages/conat/hub/api/`) → Actual business logic + +### Endpoints Discovered + +#### Hub API: `POST /api/conat/hub` + +- **Bridge**: `packages/next/pages/api/conat/hub.ts` → `hubBridge()` → conat subject `hub.account.{account_id}.api` +- **Implementation**: `packages/conat/hub/api/projects.ts` +- **Available Methods**: `createProject`, `start`, `stop`, `setQuotas`, `addCollaborator`, `removeCollaborator`, etc. + +#### Project API: `POST /api/conat/project` + +- **Bridge**: `packages/next/pages/api/conat/project.ts` → `projectBridge()` → conat project subjects +- **Implementation**: `packages/conat/project/api/` (system.ping, system.exec, system.jupyterExecute) + +# important-instruction-reminders -- Do what has been asked; nothing more, nothing less -- NEVER create files unless they're absolutely necessary for achieving your goal -- ALWAYS prefer editing an existing file to creating a new one -- REFUSE to modify files when the git repository is on the `master` or `main` branch -- NEVER proactively create documentation files (`*.md`) or README files. Only create documentation files if explicitly requested by the User -- when modifying a file with a copyright banner at the top, make sure to fix/add the current year to indicate the copyright year \ No newline at end of file +- Do what has been asked; nothing more, nothing less. +- NEVER create files unless they're absolutely necessary for achieving your goal. +- ALWAYS prefer editing an existing file to creating a new one. +- NEVER proactively create documentation files (\*.md) or README files. Only create documentation files if explicitly requested by the User. +- ALWAYS ask questions if something is unclear. Only proceed to the implementation step if you have no questions left. +- When modifying a file with a copyright banner at the top, make sure to fix/add the current year to indicate the copyright year. diff --git a/src/cocalc.code-workspace b/src/cocalc.code-workspace index 5b0008c220a..535fcc22f83 100644 --- a/src/cocalc.code-workspace +++ b/src/cocalc.code-workspace @@ -3,6 +3,9 @@ { "name": "cocalc", "path": "." + }, + { + "path": "../.github" } ], "settings": { diff --git a/src/packages/conat/core/server.ts b/src/packages/conat/core/server.ts index 4d8ce4f3d19..95cd9e111e6 100644 --- a/src/packages/conat/core/server.ts +++ b/src/packages/conat/core/server.ts @@ -28,49 +28,52 @@ cd packages/server */ import type { ConnectionStats, ServerInfo } from "./types"; + +import { delay } from "awaiting"; +import { EventEmitter } from "events"; +import { throttle } from "lodash"; +import { Server } from "socket.io"; + +import { getClientIpAddress } from "@cocalc/util/get-client-ip-address"; +import { getLogger } from "@cocalc/conat/client"; +import { UsageMonitor } from "@cocalc/conat/monitor/usage"; +import { type ConatSocketServer } from "@cocalc/conat/socket"; import { isValidSubject, isValidSubjectWithoutWildcards, } from "@cocalc/conat/util"; -import { Server } from "socket.io"; -import { delay } from "awaiting"; +import { once, until } from "@cocalc/util/async-utils"; +import { is_array } from "@cocalc/util/misc"; +import { reuseInFlight } from "@cocalc/util/reuse-in-flight"; +import { Metrics } from "../types"; import { - ConatError, - connect, Client, type ClientOptions, + ConatError, + connect, MAX_INTEREST_TIMEOUT, } from "./client"; -import { - RESOURCE, - MAX_CONNECTIONS_PER_USER, - MAX_CONNECTIONS, - MAX_PAYLOAD, - MAX_SUBSCRIPTIONS_PER_CLIENT, - MAX_SUBSCRIPTIONS_PER_HUB, -} from "./constants"; -import { Patterns } from "./patterns"; -import { is_array } from "@cocalc/util/misc"; -import { UsageMonitor } from "@cocalc/conat/monitor/usage"; -import { once, until } from "@cocalc/util/async-utils"; import { clusterLink, type ClusterLink, clusterStreams, type ClusterStreams, - trimClusterStreams, createClusterPersistServer, + trimClusterStreams, Interest, hashInterest, } from "./cluster"; -import { type ConatSocketServer } from "@cocalc/conat/socket"; -import { throttle } from "lodash"; -import { getLogger } from "@cocalc/conat/client"; -import { reuseInFlight } from "@cocalc/util/reuse-in-flight"; -import { type SysConatServer, sysApiSubject, sysApi } from "./sys"; +import { + MAX_CONNECTIONS, + MAX_CONNECTIONS_PER_USER, + MAX_PAYLOAD, + MAX_SUBSCRIPTIONS_PER_CLIENT, + MAX_SUBSCRIPTIONS_PER_HUB, + RESOURCE, +} from "./constants"; +import { Patterns } from "./patterns"; import { forkedConatServer } from "./start-server"; -import { EventEmitter } from "events"; -import { Metrics } from "../types"; +import { sysApi, sysApiSubject, type SysConatServer } from "./sys"; const logger = getLogger("conat:core:server"); @@ -1564,27 +1567,7 @@ export function randomChoice(v: Set): string { // See https://socket.io/how-to/get-the-ip-address-of-the-client function getAddress(socket) { - const header = socket.handshake.headers["forwarded"]; - if (header) { - for (const directive of header.split(",")[0].split(";")) { - if (directive.startsWith("for=")) { - return directive.substring(4); - } - } - } - - let addr = socket.handshake.headers["x-forwarded-for"]?.split(",")?.[0]; - if (addr) { - return addr; - } - for (const other of ["cf-connecting-ip", "fastly-client-ip"]) { - addr = socket.handshake.headers[other]; - if (addr) { - return addr; - } - } - - return socket.handshake.address; + return getClientIpAddress(socket.handshake) ?? socket.handshake.address; } export function updateInterest(update: InterestUpdate, interest: Interest) { diff --git a/src/packages/conat/hub/api/projects.ts b/src/packages/conat/hub/api/projects.ts index bf42fd5d36d..3414522c25b 100644 --- a/src/packages/conat/hub/api/projects.ts +++ b/src/packages/conat/hub/api/projects.ts @@ -1,6 +1,10 @@ import { authFirstRequireAccount } from "./util"; import { type CreateProjectOptions } from "@cocalc/util/db-schema/projects"; import { type UserCopyOptions } from "@cocalc/util/db-schema/projects"; +import { + type ProjectState, + type ProjectStatus, +} from "@cocalc/util/db-schema/projects"; export const projects = { createProject: authFirstRequireAccount, @@ -12,6 +16,10 @@ export const projects = { setQuotas: authFirstRequireAccount, start: authFirstRequireAccount, stop: authFirstRequireAccount, + deleteProject: authFirstRequireAccount, + touch: authFirstRequireAccount, + state: authFirstRequireAccount, + status: authFirstRequireAccount, }; export type AddCollaborator = @@ -103,4 +111,18 @@ export interface Projects { start: (opts: { account_id: string; project_id: string }) => Promise; stop: (opts: { account_id: string; project_id: string }) => Promise; + deleteProject: (opts: { + account_id: string; + project_id: string; + }) => Promise; + + touch: (opts: { account_id: string; project_id: string }) => Promise; + state: (opts: { + account_id: string; + project_id: string; + }) => Promise; + status: (opts: { + account_id: string; + project_id: string; + }) => Promise; } diff --git a/src/packages/conat/hub/api/system.ts b/src/packages/conat/hub/api/system.ts index ad8d961107d..a2f144e5661 100644 --- a/src/packages/conat/hub/api/system.ts +++ b/src/packages/conat/hub/api/system.ts @@ -9,6 +9,7 @@ import { type UserSearchResult } from "@cocalc/util/db-schema/accounts"; export const system = { getCustomize: noAuth, ping: noAuth, + test: authFirst, terminate: authFirst, userTracking: authFirst, logClientError: authFirst, @@ -31,6 +32,8 @@ export interface System { getCustomize: (fields?: string[]) => Promise; // ping server and get back the current time ping: () => { now: number }; + // test API key and return scope information (account_id) and server time + test: () => Promise<{ account_id: string; server_time: number }>; // terminate a service: // - only admin can do this. // - useful for development diff --git a/src/packages/conat/project/api/system.ts b/src/packages/conat/project/api/system.ts index 3e780381c86..c5746bd1209 100644 --- a/src/packages/conat/project/api/system.ts +++ b/src/packages/conat/project/api/system.ts @@ -28,12 +28,17 @@ export const system = { configuration: true, ping: true, + test: true, exec: true, signal: true, // jupyter stateless API jupyterExecute: true, + + // jupyter kernel management + listJupyterKernels: true, + stopJupyterKernel: true, }; export interface System { @@ -65,6 +70,8 @@ export interface System { ping: () => Promise<{ now: number }>; + test: () => Promise<{ project_id: string; server_time: number }>; + exec: (opts: ExecuteCodeOptions) => Promise; signal: (opts: { @@ -74,4 +81,9 @@ export interface System { }) => Promise; jupyterExecute: (opts: ProjectJupyterApiOptions) => Promise; + + listJupyterKernels: () => Promise< + { pid: number; connectionFile: string; kernel_name?: string }[] + >; + stopJupyterKernel: (opts: { pid: number }) => Promise<{ success: boolean }>; } diff --git a/src/packages/database/package.json b/src/packages/database/package.json index f4fbf634973..ca3537746d7 100644 --- a/src/packages/database/package.json +++ b/src/packages/database/package.json @@ -32,7 +32,7 @@ "random-key": "^0.3.2", "read": "^1.0.7", "sql-string-escape": "^1.1.6", - "validator": "^13.15.20" + "validator": "^13.15.22" }, "devDependencies": { "@types/lodash": "^4.14.202", diff --git a/src/packages/database/postgres/project-queries.ts b/src/packages/database/postgres/project-queries.ts index b408f93ce60..8b26d023740 100644 --- a/src/packages/database/postgres/project-queries.ts +++ b/src/packages/database/postgres/project-queries.ts @@ -1,20 +1,27 @@ /* - * This file is part of CoCalc: Copyright © 2020 Sagemath, Inc. + * This file is part of CoCalc: Copyright © 2020 – 2025 Sagemath, Inc. * License: MS-RSL – see LICENSE.md for details */ +import debug from "debug"; import { omit } from "lodash"; -import { PostgreSQL } from "./types"; + import { callback2 } from "@cocalc/util/async-utils"; +import { + DUMMY_SECRET, + PORT_MAX, + PORT_MIN, + validatePortNumber, +} from "@cocalc/util/consts"; +import { DatastoreConfig } from "@cocalc/util/types"; import { query } from "./query"; -import debug from "debug"; +import { PostgreSQL } from "./types"; + const L = debug("hub:project-queries"); -import { DUMMY_SECRET } from "@cocalc/util/consts"; -import { DatastoreConfig } from "@cocalc/util/types"; export async function project_has_network_access( db: PostgreSQL, - project_id: string + project_id: string, ): Promise { let x; try { @@ -52,7 +59,7 @@ interface GetDSOpts { } async function get_datastore( - opts: GetDSOpts + opts: GetDSOpts, ): Promise<{ [key: string]: DatastoreConfig }> { const { db, account_id, project_id } = opts; const q: { users: any; addons?: any } = await query({ @@ -73,19 +80,34 @@ export async function project_datastore_set( db: PostgreSQL, account_id: string, project_id: string, - config: any + config: any, ): Promise { // L("project_datastore_set", config); if (config.name == null) throw Error("configuration 'name' is not defined"); if (typeof config.type !== "string") throw Error( - "configuration 'type' is not defined (must be 'gcs', 'sshfs', ...)" + "configuration 'type' is not defined (must be 'gcs', 'sshfs', ...)", ); // check data from user for (const [key, val] of Object.entries(config)) { - if (typeof val !== "string" && typeof val !== "boolean") { + if (val == null) continue; + if (key === "port") { + const port = validatePortNumber(val); + if (port == null) { + throw new Error( + `Invalid value -- 'port' must be an integer between ${PORT_MIN} and ${PORT_MAX}`, + ); + } + config.port = port; + continue; + } + if ( + typeof val !== "string" && + typeof val !== "boolean" && + typeof val !== "number" + ) { throw new Error(`Invalid value -- '${key}' is not a valid type`); } if (typeof val === "string" && val.length > 100000) { @@ -128,7 +150,7 @@ export async function project_datastore_del( db: PostgreSQL, account_id: string, project_id: string, - name: string + name: string, ): Promise { L("project_datastore_del", name); if (typeof name !== "string" || name.length == 0) { @@ -149,7 +171,7 @@ export async function project_datastore_del( export async function project_datastore_get( db: PostgreSQL, account_id: string, - project_id: string + project_id: string, ): Promise { try { const ds = await get_datastore({ diff --git a/src/packages/frontend/account/_account.sass b/src/packages/frontend/account/_account.sass new file mode 100644 index 00000000000..1514ed0dbb0 --- /dev/null +++ b/src/packages/frontend/account/_account.sass @@ -0,0 +1,13 @@ +// Account page styles + +.account-menu-inline-collapsed + .ant-menu-item, + .ant-menu-submenu-title + padding-inline: 0px + text-align: center + + .ant-menu-submenu-title + padding-right: 20px + + .ant-menu-submenu-arrow + right: 5px diff --git a/src/packages/frontend/account/account-page.tsx b/src/packages/frontend/account/account-page.tsx index 82681a6b702..11fab5a5923 100644 --- a/src/packages/frontend/account/account-page.tsx +++ b/src/packages/frontend/account/account-page.tsx @@ -119,7 +119,7 @@ const LOAD_ACCOUNT_INFO_TIMEOUT = 15_000; export const AccountPage: React.FC = () => { const intl = useIntl(); const [hidden, setHidden] = useState(IS_MOBILE); - const [openKeys, setOpenKeys] = useState(["preferences"]); + const [openKeys, setOpenKeys] = useState([]); const { width: windowWidth } = useWindowDimensions(); const isWide = windowWidth > 800; @@ -316,85 +316,98 @@ export const AccountPage: React.FC = () => { items.push({ type: "divider" }); if (is_commercial) { - items.push({ - key: "subscriptions", - label: ( - - {intl.formatMessage(labels.subscriptions)} - - ), - children: active_page === "subscriptions" && , - }); - items.push({ - key: "licenses", - label: ( - - {intl.formatMessage(labels.licenses)} - - ), - children: active_page === "licenses" && , - }); - items.push({ - key: "payg", - label: ( - - {" "} - {intl.formatMessage(labels.pay_as_you_go)} - - ), - children: active_page === "payg" && , - }); - if (is_commercial && kucalc === KUCALC_COCALC_COM) { - // these have been deprecated for ~ 5 years, but some customers still have them. - items.push({ - key: "upgrades", + const billingChildren = [ + { + key: "subscriptions", label: ( - {" "} - {intl.formatMessage(labels.upgrades)} + {" "} + {intl.formatMessage(labels.subscriptions)} ), - children: active_page === "upgrades" && , - }); - } - items.push({ type: "divider" }); - items.push({ - key: "purchases", - label: ( - - {intl.formatMessage(labels.purchases)} - - ), - children: active_page === "purchases" && , - }); - items.push({ - key: "payments", - label: ( - - {intl.formatMessage(labels.payments)} - - ), - children: active_page === "payments" && , - }); - items.push({ - key: "payment-methods", - label: ( - - {" "} - {intl.formatMessage(labels.payment_methods)} - - ), - children: active_page === "payment-methods" && , - }); + children: active_page === "subscriptions" && , + }, + { + key: "licenses", + label: ( + + {intl.formatMessage(labels.licenses)} + + ), + children: active_page === "licenses" && , + }, + { + key: "payg", + label: ( + + {" "} + {intl.formatMessage(labels.pay_as_you_go)} + + ), + children: active_page === "payg" && , + }, + ...(kucalc === KUCALC_COCALC_COM + ? [ + { + key: "upgrades", + label: ( + + {" "} + {intl.formatMessage(labels.upgrades)} + + ), + children: active_page === "upgrades" && , + }, + ] + : []), + { + key: "purchases", + label: ( + + {intl.formatMessage(labels.purchases)} + + ), + children: active_page === "purchases" && , + }, + { + key: "payments", + label: ( + + {intl.formatMessage(labels.payments)} + + ), + children: active_page === "payments" && , + }, + { + key: "payment-methods", + label: ( + + {" "} + {intl.formatMessage(labels.payment_methods)} + + ), + children: active_page === "payment-methods" && , + }, + { + key: "statements", + label: ( + + {" "} + {intl.formatMessage(labels.statements)} + + ), + children: active_page === "statements" && , + }, + ]; + items.push({ - key: "statements", + key: "billing", label: ( - {" "} - {intl.formatMessage(labels.statements)} + {intl.formatMessage(labels.billing)} ), - children: active_page === "statements" && , + children: billingChildren, }); items.push({ type: "divider" }); } @@ -446,6 +459,40 @@ export const AccountPage: React.FC = () => { } const tabs = getTabs(); + const parentByChildKey = new Map(); + + useEffect(() => { + const parentKey = + parentByChildKey.get(active_sub_tab ?? "") ?? + parentByChildKey.get(active_page ?? ""); + setOpenKeys((prevOpenKeys) => + parentKey == null + ? [] + : prevOpenKeys.length === 1 && prevOpenKeys[0] === parentKey + ? prevOpenKeys + : [parentKey], + ); + }, [active_page, active_sub_tab]); + + useEffect(() => { + if ( + active_sub_tab && + parentByChildKey.get(active_sub_tab) !== active_page + ) { + redux.getActions("account").setState({ active_sub_tab: undefined }); + } + }, [active_page, active_sub_tab, parentByChildKey]); + + function handleOpenChange(keys: string[]) { + setOpenKeys((prevOpenKeys) => { + const newlyOpened = keys.find((key) => !prevOpenKeys.includes(key)); + return newlyOpened ? [newlyOpened] : []; + }); + } + + function visibleLabel(label) { + return hidden ? {label.props.children[0]} : label; + } // Process tabs to handle nested children for sub-tabs const children = {}; @@ -454,68 +501,35 @@ export const AccountPage: React.FC = () => { if (tab.type == "divider") { continue; } - if (tab.key === "preferences" && Array.isArray(tab.children)) { - // Handle sub-tabs for preferences + const originalLabel = tab.label; + titles[tab.key] = originalLabel; + tab.label = visibleLabel(originalLabel); + + if (Array.isArray(tab.children)) { + // Handle nested submenus generically (preferences, billing, etc.) const subTabs = tab.children; tab.children = subTabs.map((subTab) => { - // Extract just the icon (first child) from the span when hidden - const label = hidden ? ( - - {subTab.label.props.children[0]} - - ) : ( - subTab.label - ); + const label = visibleLabel(subTab.label); return { key: subTab.key, label, }; }); - // Store sub-tab children and full labels for (const subTab of subTabs) { + // Track child -> parent mapping for openKeys/title lookup. + parentByChildKey.set(subTab.key, tab.key); children[subTab.key] = subTab.children; titles[subTab.key] = subTab.label; // Always store original full label } - } else if (tab.key === "settings" || tab.key === "profile") { - // Handle settings and profile as top-level pages - // Store original full label for renderTitle() - const originalLabel = tab.label; - // Extract just the icon (first child) from the span when hidden - tab.label = hidden ? ( - - {tab.label.props.children[0]} - - ) : ( - tab.label - ); - children[tab.key] = tab.children; - titles[tab.key] = originalLabel; // Store original label - delete tab.children; } else { - // Store original full label for renderTitle() - const originalLabel = tab.label; - // Extract just the icon (first child) from the span when hidden - tab.label = hidden ? ( - - {tab.label.props.children[0]} - - ) : ( - tab.label - ); children[tab.key] = tab.children; - titles[tab.key] = originalLabel; // Store original label delete tab.children; } } + const activeChildKey = active_sub_tab ?? active_page; function renderTitle() { - return ( - - {active_page === "preferences" && active_sub_tab - ? titles[active_sub_tab] - : titles[active_page]} - - ); + return {titles[activeChildKey]}; } function renderExtraContent() { @@ -565,9 +579,9 @@ export const AccountPage: React.FC = () => { }} > { @@ -578,7 +592,7 @@ export const AccountPage: React.FC = () => { } inlineIndent={hidden ? 0 : 24} style={{ - width: hidden ? 50 : 200, + width: hidden ? 50 : 220, background: "#00000005", flex: "1 1 auto", overflowY: "auto", @@ -622,9 +636,7 @@ export const AccountPage: React.FC = () => {
{renderExtraContent()} - {active_page === "preferences" && active_sub_tab - ? children[active_sub_tab] - : children[active_page]} + {children[activeChildKey] ?? children[active_page]}
diff --git a/src/packages/frontend/account/account-preferences-appearance.tsx b/src/packages/frontend/account/account-preferences-appearance.tsx index 1794ceada22..8c22dcbd433 100644 --- a/src/packages/frontend/account/account-preferences-appearance.tsx +++ b/src/packages/frontend/account/account-preferences-appearance.tsx @@ -18,7 +18,11 @@ import { LabeledRow, } from "@cocalc/frontend/components"; import { labels } from "@cocalc/frontend/i18n"; -import { DARK_MODE_ICON } from "@cocalc/util/consts/ui"; +import { + A11Y, + ACCESSIBILITY_ICON, + DARK_MODE_ICON, +} from "@cocalc/util/consts/ui"; import { DARK_MODE_DEFAULTS } from "@cocalc/util/db-schema/accounts"; import { COLORS } from "@cocalc/util/theme"; import { @@ -62,6 +66,18 @@ const DARK_MODE_LABELS = defineMessages({ }, }); +const ACCESSIBILITY_MESSAGES = defineMessages({ + title: { + id: "account.appearance.accessibility.title", + defaultMessage: "Accessibility", + }, + enabled: { + id: "account.appearance.accessibility.enabled", + defaultMessage: + "Enable Accessibility Mode: optimize the user interface for accessibility features", + }, +}); + export function AccountPreferencesAppearance() { const intl = useIntl(); const other_settings = useTypedRedux("account", "other_settings"); @@ -107,6 +123,46 @@ export function AccountPreferencesAppearance() { ); } + function getAccessibilitySettings(): { enabled: boolean } { + const settingsStr = other_settings.get(A11Y); + if (!settingsStr) { + return { enabled: false }; + } + try { + return JSON.parse(settingsStr); + } catch { + return { enabled: false }; + } + } + + function setAccessibilitySettings(settings: { enabled: boolean }): void { + on_change(A11Y, JSON.stringify(settings)); + } + + function renderAccessibilityPanel(): ReactElement { + const settings = getAccessibilitySettings(); + return ( + + {" "} + {intl.formatMessage(ACCESSIBILITY_MESSAGES.title)} + + } + > + + setAccessibilitySettings({ ...settings, enabled: e.target.checked }) + } + > + + + + ); + } + function renderDarkModePanel(): ReactElement { const checked = !!other_settings.get("dark_mode"); const config = get_dark_mode_config(other_settings.toJS()); @@ -303,6 +359,7 @@ export function AccountPreferencesAppearance() { mode="appearance" /> {renderDarkModePanel()} + {renderAccessibilityPanel()} ): React.JSX.Element { checked={!!props.other_settings.get("dim_file_extensions")} onChange={(e) => on_change("dim_file_extensions", e.target.checked)} > - Dim file extensions: gray out file extensions so their - names stand out. + Dim file extensions: gray out file extensions so their names stand out.`} + /> ); } diff --git a/src/packages/frontend/account/settings-index.tsx b/src/packages/frontend/account/settings-index.tsx index 1ea42581ce3..93276feef2d 100644 --- a/src/packages/frontend/account/settings-index.tsx +++ b/src/packages/frontend/account/settings-index.tsx @@ -13,6 +13,7 @@ import { Icon } from "@cocalc/frontend/components"; import AIAvatar from "@cocalc/frontend/components/ai-avatar"; import { cloudFilesystemsEnabled } from "@cocalc/frontend/compute"; import { labels } from "@cocalc/frontend/i18n"; +import { KUCALC_COCALC_COM } from "@cocalc/util/db-schema/site-defaults"; import { COLORS } from "@cocalc/util/theme"; import { VALID_PREFERENCES_SUB_TYPES, @@ -83,6 +84,10 @@ const MESSAGES = defineMessages({ id: "account.settings.overview.payg", defaultMessage: "Configure pay-as-you-go usage and billing.", }, + upgrades: { + id: "account.settings.overview.upgrades", + defaultMessage: "Manage your legacy quota upgrades.", + }, purchases: { id: "account.settings.overview.purchases", defaultMessage: "View purchase history and receipts.", @@ -91,6 +96,10 @@ const MESSAGES = defineMessages({ id: "account.settings.overview.payments", defaultMessage: "Manage payment methods and transaction history.", }, + paymentMethods: { + id: "account.settings.overview.payment_methods", + defaultMessage: "Manage your saved payment methods or add new ones.", + }, statements: { id: "account.settings.overview.statements", defaultMessage: "View detailed billing statements and invoices.", @@ -133,6 +142,7 @@ const FLEX_PROPS = { export function SettingsOverview() { const intl = useIntl(); const is_commercial = useTypedRedux("customize", "is_commercial"); + const kucalc = useTypedRedux("customize", "kucalc"); function handleNavigate(path: NavigatePath) { // Use the same navigation pattern as the account page @@ -297,6 +307,18 @@ export function SettingsOverview() { description={intl.formatMessage(MESSAGES.payg)} /> + {kucalc === KUCALC_COCALC_COM && ( + handleNavigate("settings/upgrades")} + > + } + title={intl.formatMessage(labels.upgrades)} + description={intl.formatMessage(MESSAGES.upgrades)} + /> + + )} handleNavigate("settings/purchases")} @@ -317,6 +339,16 @@ export function SettingsOverview() { description={intl.formatMessage(MESSAGES.payments)} /> + handleNavigate("settings/payment-methods")} + > + } + title={intl.formatMessage(labels.payment_methods)} + description={intl.formatMessage(MESSAGES.paymentMethods)} + /> + handleNavigate("settings/statements")} diff --git a/src/packages/frontend/account/settings/email-address-setting.tsx b/src/packages/frontend/account/settings/email-address-setting.tsx index be04979725e..e8d6270e8fe 100644 --- a/src/packages/frontend/account/settings/email-address-setting.tsx +++ b/src/packages/frontend/account/settings/email-address-setting.tsx @@ -77,7 +77,7 @@ export const EmailAddressSetting = ({ return; } try { - // anonymouse users will get the "welcome" email + // anonymous users will get the "welcome" email await webapp_client.account_client.send_verification_email(!is_anonymous); } catch (error) { const err_msg = `Problem sending welcome email: ${error}`; diff --git a/src/packages/frontend/account/types.ts b/src/packages/frontend/account/types.ts index 51e2fb3618b..8ddc10f04b2 100644 --- a/src/packages/frontend/account/types.ts +++ b/src/packages/frontend/account/types.ts @@ -68,6 +68,7 @@ export interface AccountState { use_balance_toward_subscriptions?: boolean; show_symbol_bar_labels?: boolean; // whether to show labels on the menu buttons [ACTIVITY_BAR_LABELS]?: boolean; // whether to show labels on the vertical activity bar + accessibility?: string; // string is JSON: { enabled: boolean } }>; stripe_customer?: TypedMap<{ subscriptions: { data: Map }; diff --git a/src/packages/frontend/app/context.tsx b/src/packages/frontend/app/context.tsx index f60f097d8d3..44aad83b4da 100644 --- a/src/packages/frontend/app/context.tsx +++ b/src/packages/frontend/app/context.tsx @@ -11,6 +11,7 @@ import { useIntl } from "react-intl"; import { useTypedRedux } from "@cocalc/frontend/app-framework"; import { IntlMessage, isIntlMessage } from "@cocalc/frontend/i18n"; import { ACTIVITY_BAR_LABELS } from "@cocalc/frontend/project/page/activity-bar-consts"; +import { A11Y } from "@cocalc/util/consts/ui"; import { COLORS } from "@cocalc/util/theme"; import { getBaseAntdTheme } from "./antd-base-theme"; import { NARROW_THRESHOLD_PX, PageStyle } from "./top-nav-consts"; @@ -86,6 +87,18 @@ export function useAntdStyleProvider() { const branded = other_settings?.get("antd_brandcolors", false); const compact = other_settings?.get("antd_compact", false); + // Parse accessibility settings + const accessibilityStr = other_settings?.get(A11Y); + let accessibilityEnabled = false; + if (accessibilityStr) { + try { + const accessibilitySettings = JSON.parse(accessibilityStr); + accessibilityEnabled = accessibilitySettings.enabled ?? false; + } catch { + // Ignore parse errors + } + } + const borderStyle = rounded ? undefined : { borderRadius: 0, borderRadiusLG: 0, borderRadiusSM: 0 }; @@ -96,6 +109,16 @@ export function useAntdStyleProvider() { ? undefined : { colorPrimary: COLORS.ANTD_LINK_BLUE }; + // Accessibility: Set all text to pure black for maximum contrast + const accessibilityTextColor = accessibilityEnabled + ? { + colorText: "#000000", + colorTextSecondary: "#000000", + colorTextTertiary: "#000000", + colorTextQuaternary: "#000000", + } + : undefined; + const algorithm = compact ? { algorithm: theme.compactAlgorithm } : undefined; const antdTheme: ThemeConfig = { @@ -106,6 +129,7 @@ export function useAntdStyleProvider() { ...primaryColor, ...borderStyle, ...animationStyle, + ...accessibilityTextColor, }, components: { Button: { diff --git a/src/packages/frontend/app/query-params.ts b/src/packages/frontend/app/query-params.ts index 83599348e8c..11e8e5f3453 100644 --- a/src/packages/frontend/app/query-params.ts +++ b/src/packages/frontend/app/query-params.ts @@ -14,9 +14,10 @@ import { set_local_storage, } from "@cocalc/frontend/misc/local-storage"; import { QueryParams } from "@cocalc/frontend/misc/query-params"; +import { A11Y } from "@cocalc/util/consts/ui"; import { is_valid_uuid_string } from "@cocalc/util/misc"; -export function init_query_params(): void { +function init_fullscreen_mode(): void { const actions = redux.getActions("page"); // enable fullscreen mode upon loading a URL like /app?fullscreen and // additionally kiosk-mode upon /app?fullscreen=kiosk @@ -40,13 +41,19 @@ export function init_query_params(): void { } else if (COCALC_FULLSCREEN === "project") { actions.set_fullscreen("project"); } +} +function init_api_key(): void { + const actions = redux.getActions("page"); const get_api_key_query_value = QueryParams.get("get_api_key"); if (get_api_key_query_value) { actions.set_get_api_key(get_api_key_query_value); actions.set_fullscreen("project"); } +} +function init_session(): void { + const actions = redux.getActions("page"); // configure the session // This makes it so the default session is 'default' and there is no // way to NOT have a session, except via session=, which is treated @@ -79,5 +86,73 @@ export function init_query_params(): void { // not have session in the URL, so we can share url's without infected // other user's session. QueryParams.remove("session"); +} + +function parse_accessibility_param(param: string): boolean | null { + if (param === "true" || param === "on" || param === "1") { + return true; + } + if (param === "false" || param === "off" || param === "0") { + return false; + } + return null; +} + +async function init_accessibility(): Promise { + // Handle accessibility query parameter + // If ?accessibility=true or =on, enable accessibility mode permanently + // If ?accessibility=false or =off, disable it permanently + // This allows sharing URLs that automatically enable accessibility + const accessibilityParam = QueryParams.get(A11Y); + if (accessibilityParam == null) { + return; + } + + const enabled = parse_accessibility_param(accessibilityParam); + QueryParams.remove(A11Y); + if (enabled == null) { + return; + } + + try { + // Wait for account store to be ready before setting accessibility + const store = redux.getStore("account"); + if (!store || typeof store.async_wait !== "function") { + console.warn("Account store not ready"); + return; + } + + await store.async_wait({ + until: () => store.get_account_id() != null, + timeout: 0, + }); + + // Preserve existing accessibility settings + const existingSettingsStr = store.getIn(["other_settings", A11Y]); + let existingSettings = { enabled: false }; + if (existingSettingsStr) { + try { + existingSettings = JSON.parse(existingSettingsStr); + } catch { + // Ignore parse errors, use default + } + } + + // Merge with new enabled value + const settings = { ...existingSettings, enabled }; + const accountActions = redux.getActions("account"); + accountActions.set_other_settings(A11Y, JSON.stringify(settings)); + } catch (err) { + console.warn("Failed to set accessibility from query param:", err); + } +} + +export function init_query_params(): void { + init_fullscreen_mode(); + init_api_key(); + init_session(); + // Run accessibility init in background without blocking + // to avoid delaying other store initializations + init_accessibility(); } diff --git a/src/packages/frontend/course/assignments/assignment.tsx b/src/packages/frontend/course/assignments/assignment.tsx index 276aaa1364b..2d06aca7ebf 100644 --- a/src/packages/frontend/course/assignments/assignment.tsx +++ b/src/packages/frontend/course/assignments/assignment.tsx @@ -3,8 +3,19 @@ * License: MS-RSL – see LICENSE.md for details */ -import { Alert, Button, Card, Col, Input, Popconfirm, Row, Space } from "antd"; -import { ReactElement, useState } from "react"; +import { + Alert, + Button, + Card, + Col, + ConfigProvider, + Divider, + Input, + Popconfirm, + Row, + Space, +} from "antd"; +import { ReactElement, useEffect, useState } from "react"; import { DebounceInput } from "react-debounce-input"; import { FormattedMessage, useIntl } from "react-intl"; import { AppRedux, useActions } from "@cocalc/frontend/app-framework"; @@ -13,9 +24,10 @@ import { Icon, IconName, Loading, - MarkdownInput, Tip, } from "@cocalc/frontend/components"; +import MultiMarkdownInput from "@cocalc/frontend/editors/markdown-input/multimode"; +import StaticMarkdown from "@cocalc/frontend/editors/slate/static-markdown"; import { course, labels } from "@cocalc/frontend/i18n"; import { capitalize, trunc_middle } from "@cocalc/util/misc"; import { CourseActions } from "../actions"; @@ -93,6 +105,21 @@ export function Assignment({ }: AssignmentProps) { const intl = useIntl(); const size = useButtonSize(); + const assignmentId = assignment.get("assignment_id"); + const noteProp = assignment.get("note") ?? ""; + const [noteValue, setNoteValue] = useState(noteProp); + const [noteEditing, setNoteEditing] = useState(false); + + useEffect(() => { + setNoteValue(noteProp); + setNoteEditing(false); + }, [assignmentId]); + + useEffect(() => { + if (!noteEditing) { + setNoteValue(noteProp); + } + }, [noteProp, noteEditing]); const [ copy_assignment_confirm_overwrite, @@ -122,21 +149,19 @@ export function Assignment({ function render_due() { return ( - -
- - Due - -
- + +
Due:
+ + +
); } @@ -150,90 +175,82 @@ export function Assignment({ function render_note() { return ( - - - + + + +
+ {noteEditing ? ( + setNoteValue(value)} + placeholder="Private notes about this assignment (not visible to students)" + height="200px" + minimal + enableUpload={false} + /> + ) : ( + + )} +
+
); } function render_export_file_use_times() { return ( - - - - Export file use times -
- -
- - - - -
+ + + ); } function render_export_assignment() { return ( - - - - Export collected student files -
- -
- - - - -
+ + + ); } @@ -261,109 +278,106 @@ export function Assignment({ return ; } const v: ReactElement[] = []; + const stackSize = size === "small" ? "small" : "middle"; - const bottom = { - borderBottom: "1px solid grey", - paddingBottom: "15px", - marginBottom: "15px", - }; v.push( - - {render_open_button()} - - - + + + + + {render_open_button()} {render_due()} - - - - {render_peer_button()} - - + + + + + {render_export_file_use_times()} + {render_export_assignment()} + {render_delete_button()} + + + + + {expand_peer_config ? ( + + ) : null} + + {render_note()} + + + {(() => { + const peer = is_peer_graded(); + width = peer ? 4 : 6; + + if (num_files === 0) return null; + + const buttons: ReactElement[] = []; + const insert_grade_button = (key: string) => { + const b2 = render_skip_grading_button(status); + return buttons.push( + + {render_nbgrader_button(status)} + {b2} + , + ); + }; + + for (const name of STEPS(peer)) { + const b = render_button(name, status); + // squeeze in the skip grading button (don't add it to STEPS!) + if (!peer && name === "return_graded") { + insert_grade_button("skip_grading"); + } + if (b != null) { + buttons.push( + + {b} + , + ); + if (peer && name === "peer_collect") { + insert_grade_button("skip_peer_collect"); + } + } + } + + return ( + <> + + + set_student_search(e.target.value)} /> - {render_delete_button()} + + + {buttons} - - - - , - ); - - if (expand_peer_config) { - v.push( - - - {render_configure_peer()} - - , - ); - } - - const peer = is_peer_graded(); - if (peer) { - width = 4; - } else { - width = 6; - } - - if (num_files > 0) { - const buttons: ReactElement[] = []; - const insert_grade_button = (key: string) => { - const b2 = render_skip_grading_button(status); - return buttons.push( - - {render_nbgrader_button(status)} - {b2} - , - ); - }; - for (const name of STEPS(peer)) { - const b = render_button(name, status); - // squeeze in the skip grading button (don't add it to STEPS!) - if (!peer && name === "return_graded") { - insert_grade_button("skip_grading"); - } - if (b != null) { - buttons.push( - - {b} - , + + + {render_copy_confirms(status)} + + + ); - if (peer && name === "peer_collect") { - insert_grade_button("skip_peer_collect"); - } - } - } - - v.push( - - - set_student_search(e.target.value)} - /> - - - {buttons} - - , - ); - - v.push( - - - {render_copy_confirms(status)} - - , - ); - } + })()} + , + ); /* The whiteSpace:'normal' here is because we put this in an antd Card title, which has line wrapping disabled. */ return
{v}
; @@ -376,32 +390,28 @@ export function Assignment({ body = render_no_content(); } else { body = ( - <> - - {render_note()} -
-
-
- {render_export_file_use_times()} -
- {render_export_assignment()} - + ); } return ( - {body} + + + {render_more_header(num_files)} + {body} + + ); @@ -438,7 +448,7 @@ export function Assignment({ tip="Open the directory in the current project that contains the original files for this assignment. Edit files in this folder to create the content that your students will see when they receive an assignment." > ); @@ -483,7 +493,6 @@ export function Assignment({ ); @@ -1115,7 +1121,6 @@ export function Assignment({ }} disabled={copy_confirm} type={type} - size={size} > - @@ -1200,10 +1205,6 @@ export function Assignment({ } } - function render_configure_peer() { - return ; - } - function render_peer_button() { let icon; if (is_peer_graded()) { diff --git a/src/packages/frontend/cspell.json b/src/packages/frontend/cspell.json index 1fa2c0fb60c..ab68c4b2b0e 100644 --- a/src/packages/frontend/cspell.json +++ b/src/packages/frontend/cspell.json @@ -43,6 +43,7 @@ "onprem", "pdflatex", "plotly", + "pulseaudio", "pythontex", "rclass", "rereturn", @@ -81,7 +82,8 @@ "undeletes", "undeleting", "xelatex", - "xetex" + "xetex", + "xpra" ], "ignoreWords": [ "antd", @@ -110,6 +112,7 @@ "noconf", "nprocs", "pchildren", + "pgrep", "pids", "Popconfirm", "PoweroffOutlined", diff --git a/src/packages/frontend/embed/index.ts b/src/packages/frontend/embed/index.ts index 2884acae908..55f6e7f6eb2 100644 --- a/src/packages/frontend/embed/index.ts +++ b/src/packages/frontend/embed/index.ts @@ -23,7 +23,6 @@ import { init as initMarkdown } from "../markdown/markdown-input/main"; import { init as initCrashBanner } from "../crash-banner"; import { init as initCustomize } from "../customize"; - // Do not delete this without first looking at https://github.com/sagemathinc/cocalc/issues/5390 // This import of codemirror forces the initial full load of codemirror // as part of the main webpack entry point. diff --git a/src/packages/frontend/entry-point.ts b/src/packages/frontend/entry-point.ts index fe1631e5354..041a84c6b09 100644 --- a/src/packages/frontend/entry-point.ts +++ b/src/packages/frontend/entry-point.ts @@ -15,7 +15,7 @@ import { COCALC_MINIMAL } from "./fullscreen"; // Load/initialize Redux-based react functionality import { redux } from "./app-framework"; -// Systemwide notifications that are broadcast to all users (and set by admins) +// system-wide notifications that are broadcast to all users (and set by admins) import "./system-notifications"; // News about the platform, features, etc. – also shown at https://$DNS/news diff --git a/src/packages/frontend/frame-editors/x11-editor/xpra-client.ts b/src/packages/frontend/frame-editors/x11-editor/xpra-client.ts index d60e32f6e00..16676eba344 100644 --- a/src/packages/frontend/frame-editors/x11-editor/xpra-client.ts +++ b/src/packages/frontend/frame-editors/x11-editor/xpra-client.ts @@ -156,9 +156,10 @@ export class XpraClient extends EventEmitter { // Get origin, but with http[s] stripped. // Do not use window.location.hostname, since that doesn't // include the port, if there is one. - let origin = window.location.origin; + const { origin, protocol: pageProtocol } = window.location; const i = origin.indexOf(":"); - origin = origin.slice(i); + const originTail = origin.slice(i); + const wsProtocol = pageProtocol === "https:" ? "wss" : "ws"; const path = join( appBasePath, @@ -166,7 +167,7 @@ export class XpraClient extends EventEmitter { "server", `${port}`, ); - const uri = `wss${origin}${path}`; + const uri = `${wsProtocol}${originTail}${path}`; const dpi = Math.round(BASE_DPI * window.devicePixelRatio); return { uri, dpi }; } diff --git a/src/packages/frontend/i18n/bin/delete.sh b/src/packages/frontend/i18n/bin/delete.sh index f741e1ca828..f21cd1fab56 100755 --- a/src/packages/frontend/i18n/bin/delete.sh +++ b/src/packages/frontend/i18n/bin/delete.sh @@ -7,8 +7,8 @@ if [ $# -eq 0 ]; then echo "Delete one or more translation keys from SimpleLocalize" echo "" echo "Example:" - echo " $0 labels.masked_files" - echo " $0 labels.masked_files account.sign-out.button.title" + echo " $0 labels.account" + echo " $0 labels.account account.sign-out.button.title" exit 1 fi @@ -34,4 +34,4 @@ echo echo "Done! Now you should run:" echo " pnpm i18n:upload (to re-upload the key with new content)" echo " pnpm i18n:download (to fetch updated translations)" -echo " pnpm i18n:compile (to compile translation files)" \ No newline at end of file +echo " pnpm i18n:compile (to compile translation files)" diff --git a/src/packages/frontend/i18n/trans/ar_EG.json b/src/packages/frontend/i18n/trans/ar_EG.json index 969c3308ec6..73aa13b39a6 100644 --- a/src/packages/frontend/i18n/trans/ar_EG.json +++ b/src/packages/frontend/i18n/trans/ar_EG.json @@ -5,6 +5,8 @@ "account.account_page.translation.info.title": "معلومات الترجمة", "account.account-button.confirm.ok": "نعم، سجل الخروج", "account.account-button.confirm.title": "تسجيل الخروج من حسابك؟", + "account.appearance.accessibility.enabled": "تمكين وضع الوصول: تحسين واجهة المستخدم لميزات الوصول", + "account.appearance.accessibility.title": "إمكانية الوصول", "account.appearance.user_interface.title": "واجهة المستخدم", "account.delete-account.alert.description": "سوف تفقد فوراً الوصول إلى جميع مشاريعك، سيتم إلغاء أي اشتراكات، وستفقد جميع الأرصدة غير المستخدمة. {br} {hr} لحذف حسابك، أدخل أولاً \"{required_text}\" أدناه:", "account.delete-account.alert.message": "هل أنت متأكد أنك تريد حذف حسابك؟", @@ -31,13 +33,11 @@ "account.editor-setting.checkbox.strip_trailing_whitespace": "إزالة كلما تم حفظ الملف", "account.editor-settings-autosave-interval.label": "فترة الحفظ التلقائي", "account.editor-settings.basic.title": "الإعدادات الأساسية", - "account.editor-settings.color-schemes.label": "نظام ألوان المحرر", "account.editor-settings.color-schemes.panel_title": "نظام ألوان المحرر", "account.editor-settings.font-size.label": "حجم الخط العالمي الافتراضي", "account.editor-settings.indent-size.label": "حجم المسافة البادئة", "account.editor-settings.keyboard-bindings.label": "اختصارات لوحة المفاتيح للمحرر", "account.editor-settings.keyboard.title": "لوحة المفاتيح", - "account.editor-settings.title": "المحرر", "account.editor-settings.x11-keyboard-variant.label": "متغير لوحة المفاتيح (لجهاز سطح المكتب X11)", "account.editor-settings.x11-physical-keyboard.label": "تخطيط لوحة المفاتيح (لـ X11 Desktop)", "account.global-ssh-keys.help": "للدخول إلى مشروع باستخدام SSH، استخدم التالي username@host: [project-id-without-dashes]@ssh.cocalc.com يمكن العثور على معرف المشروع بدون فواصل في جزء إعدادات المشروع المتعلق بمفاتيح SSH. للدخول بين المشاريع باستخدام SSH، استخدم [project-id-without-dashes]@ssh.", @@ -66,13 +66,13 @@ "account.keyboard-shortcuts.shortcut.split-view-sagews": "عرض منقسم في ورقة عمل Sage", "account.keyboard-shortcuts.shortcut.toggle-comment": "تبديل تعليق التحديد", "account.other-settings._page_size.label": "عدد الملفات لكل صفحة", - "account.other-settings.browser_performance.title": "متصفح", + "account.other-settings.auto_focus": "إدخال نص التركيز التلقائي: التركيز تلقائيًا على حقول إدخال النص عند ظهورها (مثل مستكشف الملفات، المشاريع، ...)", "account.other-settings.button_tooltips": "إخفاء تلميحات الأزرار: يخفي بعض تلميحات الأزرار (هذا جزئي فقط)", "account.other-settings.confirm_close": "تأكيد الإغلاق: اطلب دائمًا التأكيد قبل إغلاق نافذة المتصفح", - "account.other-settings.content_display.title": "عرض المحتوى", "account.other-settings.default_file_sort.by_name": "الترتيب حسب الاسم", "account.other-settings.default_file_sort.by_time": "الترتيب حسب الوقت", "account.other-settings.default_file_sort.label": "ترتيب الملفات الافتراضي", + "account.other-settings.dim_file_extensions": "تعتيم امتدادات الملفات: تظليل امتدادات الملفات حتى تبرز أسماؤها.", "account.other-settings.file_popovers": "إخفاء النوافذ المنبثقة لعلامات تبويب الملفات: عدم عرض النوافذ المنبثقة فوق علامات تبويب الملفات", "account.other-settings.filename_generator.description": "اختر كيفية توليد أسماء الملفات التلقائية. بشكل خاص، لجعلها فريدة أو لتضمين الوقت الحالي.", "account.other-settings.filename_generator.label": "مولد اسم الملف", @@ -85,12 +85,9 @@ "account.other-settings.llm.title": "إعدادات AI", "account.other-settings.markdown_codebar": "تعطيل شريط كود العلامات في جميع مستندات العلامات. يؤدي تحديد هذا إلى إخفاء أزرار التشغيل والنسخ والشرح الإضافية في كتل الكود المسورة.", "account.other-settings.mask_files": "إخفاء الملفات: تظليل الملفات في عارض الملفات التي ربما لا تريد فتحها", - "account.other-settings.messages.title": "رسائل", "account.other-settings.project_popovers": "إخفاء النوافذ المنبثقة لعلامات التبويب في المشروع: لا تعرض النوافذ المنبثقة فوق علامات تبويب المشروع", - "account.other-settings.projects.title": "مشاريع", "account.other-settings.standby_timeout": "مهلة الانتظار", "account.other-settings.symbol_bar_labels": "إظهار تسميات شريط الرموز: إظهار التسميات في شريط رموز محرر الإطار", - "account.other-settings.theme": "السمة", "account.other-settings.theme.antd.animations": "الرسوم المتحركة: تحريك بعض العناصر بإيجاز، مثل الأزرار", "account.other-settings.theme.antd.color_scheme": "مخطط الألوان: استخدم ألوان العلامة التجارية بدلاً من الألوان الافتراضية", "account.other-settings.theme.antd.compact": "تصميم مضغوط: استخدم تصميمًا أكثر إحكامًا", @@ -128,6 +125,7 @@ "account.settings.overview.licenses": "إدارة تراخيص البرامج وأذونات الوصول.", "account.settings.overview.other": "إعدادات وخيارات متنوعة.", "account.settings.overview.payg": "قم بتكوين الاستخدام والدفع حسب الاستهلاك والفواتير.", + "account.settings.overview.payment_methods": "إدارة طرق الدفع المحفوظة أو إضافة طرق جديدة.", "account.settings.overview.payments": "إدارة طرق الدفع وسجل المعاملات.", "account.settings.overview.profile": "إدارة معلوماتك الشخصية وصورتك الرمزية وتفاصيل حسابك.", "account.settings.overview.purchases": "عرض سجل الشراء والإيصالات.", @@ -135,6 +133,7 @@ "account.settings.overview.subscriptions": "عرض وإدارة اشتراكاتك النشطة.", "account.settings.overview.support": "الوصول إلى تذاكر الدعم وموارد المساعدة.", "account.settings.overview.title": "نظرة عامة على الإعدادات", + "account.settings.overview.upgrades": "إدارة ترقيات حصة الإرث الخاصة بك.", "account.settings.sso.account_is_linked": "حسابك مرتبط مع (انقر لإلغاء الارتباط)", "account.settings.sso.link_your_account": "{is_anonymous, select, true {سجل باستخدام حسابك في} other {اضغط لربط حسابك}}", "account.settings.unlisted.label": "غير مدرج: يمكن العثور عليك فقط من خلال مطابقة عنوان البريد الإلكتروني بشكل دقيق", @@ -155,6 +154,9 @@ "ai-generate-document.modal.title": "إنشاء مستند {docName} باستخدام الذكاء الاصطناعي", "ai-generator.select_llm": "اختر نموذج اللغة", "app.fullscreen-button.tooltip": "وضع الشاشة الكاملة، يركز على المستند أو الصفحة الحالية.", + "app.hotkey.dialog.help_text": "انقر على الإطارات أعلاه • المفتاح 0 يبدل الدردشة • المفاتيح 1-9 تركز على الإطارات • اكتب للبحث • ↑↓ للتنقل • عودة لفتح • ESC للإغلاق", + "app.hotkey.dialog.search_placeholder": "البحث في الملفات والصفحات...", + "app.hotkey.dialog.title": "التنقل السريع", "app.verify-email-banner.edit": "إذا كانت عنوان البريد الإلكتروني خاطئة، يرجى تعديله في إعدادات الحساب.", "app.verify-email-banner.help.text": "من المهم أن يكون لديك عنوان بريد إلكتروني يعمل. نستخدمه لإعادة تعيين كلمة المرور، وإرسال الرسائل، وإشعارات الفوترة، والدعم. يرجى التأكد من صحة بريدك الإلكتروني للبقاء على اطلاع.", "app.verify-email-banner.text": "{sent, select, true {تم إرسال البريد الإلكتروني! يرجى التحقق من صندوق البريد الإلكتروني (وربما الرسائل غير المرغوب فيها) والنقر على رابط التأكيد.} other {يرجى التحقق من عنوان بريدك الإلكتروني وتأكيده:}}", @@ -988,6 +990,7 @@ "labels.config": "الإعدادات", "labels.configuration": "التكوين", "labels.configuration.short": "الإعدادات", + "labels.connected": "متصل", "labels.connecting": "الاتصال", "labels.connection": "الاتصال", "labels.copied": "تم النسخ", @@ -1016,6 +1019,7 @@ "labels.environment": "بيئة", "labels.explorer": "المستكشف", "labels.file_explorer": "مستكشف الملفات", + "labels.file_use_notifications": "إشعارات استخدام الملفات", "labels.files": "الملفات", "labels.folder": "مجلد", "labels.frame-editors.title-bar.save_label": "{type, select, is_public {عام} read_only {للقراءة فقط} other {حفظ}}", @@ -1095,6 +1099,7 @@ "labels.project.settings.stop-project.label": "إيقاف{short, select, true {} other { المشروع}}…", "labels.project.settings.stop-project.ok": "نعم، أوقف المشروع", "labels.projects": "المشاريع", + "labels.public_paths": "المسارات العامة", "labels.published_files": "ملفات منشورة", "labels.purchases": "المشتريات", "labels.ready": "جاهز", @@ -1423,7 +1428,6 @@ "projects.create-project.helpTxt": "اختر عنوانًا. يمكنك تغييره بسهولة لاحقًا!", "projects.create-project.requireLicense": "مطلوب ترخيص لإنشاء مشاريع إضافية.", "projects.filename-search.placeholder": "ابحث عن أسماء الملفات التي قمت بتحريرها...", - "projects.list.no_starred_found": "لم يتم العثور على مشاريع مميزة. استخدم رمز النجمة بجانب عناوين المشاريع لوضع إشارة مرجعية على مشاريعك المفضلة.", "projects.load-all.label": "عرض كل المشاريع...", "projects.operations.clear-filter": "مسح الفلتر", "projects.operations.delete.button": "{deleted, select, true {استعادة الكل} other {حذف الكل}}", @@ -1455,7 +1459,9 @@ "projects.table-controls.hashtags.placeholder": "التصفية حسب الوسوم...", "projects.table-controls.hidden.label": "مخفي", "projects.table-controls.search.placeholder": "ابحث عن المشاريع...", + "projects.table.keyboard-row-hint": "المشروع {title}. استخدم الأسهم لأعلى ولأسفل للتحرك؛ اضغط على Enter أو Space للفتح.", "projects.table.last-edited": "آخر تعديل", + "projects.table.untitled": "بدون عنوان", "purchases.automatic-payments-warning.description": "المدفوعات التلقائية هي أكثر ملاءمة بكثير، وستوفر لك الوقت، وتضمن عدم إلغاء الاشتراكات عن طريق الخطأ.", "purchases.automatic-payments-warning.title": "الدفع التلقائي ليس مطلوبًا للاشتراك", "purchases.automatic-payments.are-enabled": "المدفوعات التلقائية مفعلة", diff --git a/src/packages/frontend/i18n/trans/de_DE.json b/src/packages/frontend/i18n/trans/de_DE.json index 0933088f29f..95db74315a1 100644 --- a/src/packages/frontend/i18n/trans/de_DE.json +++ b/src/packages/frontend/i18n/trans/de_DE.json @@ -5,6 +5,8 @@ "account.account_page.translation.info.title": "Informationen zur Übersetzung", "account.account-button.confirm.ok": "Ja, ausloggen", "account.account-button.confirm.title": "Vom Konto ausloggen?", + "account.appearance.accessibility.enabled": "Barrierefreiheitsmodus aktivieren: die Benutzeroberfläche für Barrierefreiheitsfunktionen optimieren", + "account.appearance.accessibility.title": "Barrierefreiheit", "account.appearance.user_interface.title": "Benutzeroberfläche", "account.delete-account.alert.description": "Sie werden sofort den Zugriff auf alle Ihrer Projekte verlieren, alle Abonnements werden storniert, und alle nicht ausgegebenen Guthaben gehen verloren. {br} {hr} Um IHR KONTO ZU LÖSCHEN, geben Sie zuerst unten \"{required_text}\" ein:", "account.delete-account.alert.message": "Sind Sie sicher, dass Sie IHR KONTO LÖSCHEN möchten?", @@ -31,13 +33,11 @@ "account.editor-setting.checkbox.strip_trailing_whitespace": "entfernen, wenn Datei gespeichert wird", "account.editor-settings-autosave-interval.label": "Automatisches Speicherintervall", "account.editor-settings.basic.title": "Grundeinstellungen", - "account.editor-settings.color-schemes.label": "Editor-Farbschema", "account.editor-settings.color-schemes.panel_title": "Editor Farbschema", "account.editor-settings.font-size.label": "Standard globale Schriftgröße", "account.editor-settings.indent-size.label": "Einzugsgröße", "account.editor-settings.keyboard-bindings.label": "Editor-Tastenkombinationen", "account.editor-settings.keyboard.title": "Tastatur", - "account.editor-settings.title": "Editor", "account.editor-settings.x11-keyboard-variant.label": "Tastaturvariante (für X11-Desktop)", "account.editor-settings.x11-physical-keyboard.label": "Tastaturlayout (für X11-Desktop)", "account.global-ssh-keys.help": "Um über SSH in ein Projekt zu gelangen, verwenden Sie folgendes username@host: [project-id-without-dashes]@ssh.cocalc.com Die Projekt-ID ohne Bindestriche finden Sie im Teil der Projekteinstellungen über SSH-Schlüssel. Um zwischen Projekten über SSH zu wechseln, verwenden Sie [project-id-without-dashes]@ssh", @@ -66,13 +66,13 @@ "account.keyboard-shortcuts.shortcut.split-view-sagews": "Geteilte Ansicht im Sage-Arbeitsblatt", "account.keyboard-shortcuts.shortcut.toggle-comment": "Auswahl kommentieren umschalten", "account.other-settings._page_size.label": "Anzahl der Dateien pro Seite", - "account.other-settings.browser_performance.title": "Browser", + "account.other-settings.auto_focus": "Textfelder automatisch fokussieren: Textfelder automatisch fokussieren, wenn sie erscheinen (z.B. Dateiexplorer, Projekte, ...)", "account.other-settings.button_tooltips": "Schaltflächen-Tooltips ausblenden: blendet einige Schaltflächen-Tooltips aus (dies ist nur teilweise)", "account.other-settings.confirm_close": "Schließen bestätigen: immer um Bestätigung bitten, bevor das Browserfenster geschlossen wird", - "account.other-settings.content_display.title": "Inhaltsanzeige", "account.other-settings.default_file_sort.by_name": "Nach Name sortieren", "account.other-settings.default_file_sort.by_time": "Nach Zeit sortieren", "account.other-settings.default_file_sort.label": "Standarddatei sortieren", + "account.other-settings.dim_file_extensions": "Dateierweiterungen abdunkeln: Dateierweiterungen ausgrauen, damit ihre Namen hervorstechen.", "account.other-settings.file_popovers": "Datei-Tab-Popovers ausblenden: Popovers über Dateitabs nicht anzeigen", "account.other-settings.filename_generator.description": "Wählen Sie aus, wie automatisch generierte Dateinamen erstellt werden. Insbesondere, um sie einzigartig zu machen oder die aktuelle Uhrzeit einzubeziehen.", "account.other-settings.filename_generator.label": "Dateinamengenerator", @@ -85,12 +85,9 @@ "account.other-settings.llm.title": "KI-Einstellungen", "account.other-settings.markdown_codebar": "Deaktiviere die Markdown-Codeleiste in allen Markdown-Dokumenten. Wenn Sie dies aktivieren, werden die zusätzlichen Ausführen-, Kopieren- und Erklären-Buttons in umrandeten Codeblöcken ausgeblendet.", "account.other-settings.mask_files": "Dateien maskieren: Dateien im Dateibetrachter ausgrauen, die Sie wahrscheinlich nicht öffnen möchten", - "account.other-settings.messages.title": "Nachrichten", "account.other-settings.project_popovers": "Projekt-Tab-Popovers ausblenden: die Popovers über den Projekt-Tabs nicht anzeigen", - "account.other-settings.projects.title": "Projekte", "account.other-settings.standby_timeout": "Standby-Timeout", "account.other-settings.symbol_bar_labels": "Symbolleistensymbol-Beschriftungen anzeigen: Beschriftungen in der Symbolleiste des Rahmeneditors anzeigen", - "account.other-settings.theme": "Thema", "account.other-settings.theme.antd.animations": "Animationen: einige Aspekte kurz animieren, z. B. Schaltflächen", "account.other-settings.theme.antd.color_scheme": "Farbschema: Verwenden Sie Markenfarben anstelle der Standardfarben", "account.other-settings.theme.antd.compact": "Kompaktes Design: ein kompakteres Design verwenden", @@ -128,6 +125,7 @@ "account.settings.overview.licenses": "Verwalten Sie Softwarelizenzen und Zugriffsberechtigungen.", "account.settings.overview.other": "Verschiedene Einstellungen und Optionen.", "account.settings.overview.payg": "Konfigurieren Sie die Nutzung und Abrechnung nach Verbrauch.", + "account.settings.overview.payment_methods": "Verwalten Sie Ihre gespeicherten Zahlungsmethoden oder fügen Sie neue hinzu.", "account.settings.overview.payments": "Zahlungsmethoden und Transaktionsverlauf verwalten.", "account.settings.overview.profile": "Verwalten Sie Ihre persönlichen Informationen, Ihren Avatar und Ihre Kontodetails.", "account.settings.overview.purchases": "Kaufhistorie und Belege anzeigen.", @@ -135,6 +133,7 @@ "account.settings.overview.subscriptions": "Anzeigen und verwalten Sie Ihre aktiven Abonnements.", "account.settings.overview.support": "Zugriff auf Support-Tickets und Hilfsressourcen.", "account.settings.overview.title": "Einstellungen Übersicht", + "account.settings.overview.upgrades": "Verwalten Sie Ihre Legacy-Quotenerweiterungen.", "account.settings.sso.account_is_linked": "Ihr Konto ist verknüpft mit (klicken, um die Verknüpfung aufzuheben)", "account.settings.sso.link_your_account": "{is_anonymous, select, true {Registrieren Sie sich mit Ihrem Konto bei} other {Klicken Sie, um Ihr Konto zu verknüpfen}}", "account.settings.unlisted.label": "Nicht gelistet: Sie können nur durch eine genaue Übereinstimmung der E-Mail-Adresse gefunden werden", @@ -155,6 +154,9 @@ "ai-generate-document.modal.title": "Erzeuge ein {docName} Dokument mit KI", "ai-generator.select_llm": "Sprachmodell auswählen", "app.fullscreen-button.tooltip": "Vollbildmodus, fokussiert auf das aktuelle Dokument oder die aktuelle Seite", + "app.hotkey.dialog.help_text": "Klicke auf Rahmen oben • Taste 0 schaltet Chat um • Tasten 1–9 fokussieren Rahmen • Tippen, um zu suchen • ↑↓ navigieren • Eingabetaste zum Öffnen • ESC zum Schließen", + "app.hotkey.dialog.search_placeholder": "Dateien und Seiten durchsuchen...", + "app.hotkey.dialog.title": "Schnellnavigation", "app.verify-email-banner.edit": "Wenn die E-Mail-Adresse falsch ist, bitte bearbeiten Sie sie in den Kontoeinstellungen.", "app.verify-email-banner.help.text": "Es ist wichtig, eine funktionierende E-Mail-Adresse zu haben. Wir verwenden sie für das Zurücksetzen von Passwörtern, das Senden von Nachrichten, Abrechnungsbenachrichtigungen und Unterstützung. Bitte stellen Sie sicher, dass Ihre E-Mail korrekt ist, um informiert zu bleiben.", "app.verify-email-banner.text": "{sent, select, true {E-Mail gesendet! Bitte überprüfen Sie Ihren E-Mail-Posteingang (und vielleicht Spam) und klicken Sie auf den Bestätigungslink.} other {Bitte überprüfen und verifizieren Sie Ihre E-Mail-Adresse:}}", @@ -988,6 +990,7 @@ "labels.config": "Konfiguration", "labels.configuration": "Konfiguration", "labels.configuration.short": "Konfig", + "labels.connected": "Verbunden", "labels.connecting": "Verbinde", "labels.connection": "Verbindung", "labels.copied": "kopiert", @@ -1016,6 +1019,7 @@ "labels.environment": "Umgebung", "labels.explorer": "Explorer", "labels.file_explorer": "Dateimanager", + "labels.file_use_notifications": "Benachrichtigungen zur Dateiverwendung", "labels.files": "Dateien", "labels.folder": "Ordner", "labels.frame-editors.title-bar.save_label": "{type, select, is_public {Öffentlich} read_only {Schreibgeschützt} other {Speichern}}", @@ -1095,6 +1099,7 @@ "labels.project.settings.stop-project.label": "Stop{short, select, true {} other { Projekt}}…", "labels.project.settings.stop-project.ok": "Ja, stoppe Projekt", "labels.projects": "Projekte", + "labels.public_paths": "Öffentliche Pfade", "labels.published_files": "Veröffentlichte Dateien", "labels.purchases": "Einkäufe", "labels.ready": "Bereit", @@ -1423,7 +1428,6 @@ "projects.create-project.helpTxt": "Wählen Sie einen Titel. Sie können ihn später einfach ändern!", "projects.create-project.requireLicense": "Eine Lizenz ist erforderlich, um zusätzliche Projekte zu erstellen.", "projects.filename-search.placeholder": "Suche nach Dateien, die Sie bearbeitet haben...", - "projects.list.no_starred_found": "Keine mit Stern markierten Projekte gefunden. Verwenden Sie das Sternsymbol neben Projekttiteln, um Ihre Lieblingsprojekte zu speichern.", "projects.load-all.label": "Zeige alle Projekte...", "projects.operations.clear-filter": "Filter löschen", "projects.operations.delete.button": "{deleted, select, true {Alle wiederherstellen} other {Alle löschen}}", @@ -1455,7 +1459,9 @@ "projects.table-controls.hashtags.placeholder": "Nach Hashtags filtern...", "projects.table-controls.hidden.label": "Versteckt", "projects.table-controls.search.placeholder": "Projekte durchsuchen...", + "projects.table.keyboard-row-hint": "Projekt {title}. Verwenden Sie die Pfeiltasten nach oben und unten, um sich zu bewegen; drücken Sie Enter oder Leertaste, um zu öffnen.", "projects.table.last-edited": "Zuletzt bearbeitet", + "projects.table.untitled": "Unbenannt", "purchases.automatic-payments-warning.description": "Automatische Zahlungen sind viel bequemer, ersparen Ihnen Zeit und stellen sicher, dass Abonnements nicht versehentlich gekündigt werden.", "purchases.automatic-payments-warning.title": "Automatische Zahlungen sind NICHT erforderlich, um ein Abonnement zu haben", "purchases.automatic-payments.are-enabled": "Automatische Zahlungen sind aktiviert", diff --git a/src/packages/frontend/i18n/trans/es_ES.json b/src/packages/frontend/i18n/trans/es_ES.json index ff03e994cdc..8b11ef9204d 100644 --- a/src/packages/frontend/i18n/trans/es_ES.json +++ b/src/packages/frontend/i18n/trans/es_ES.json @@ -5,6 +5,8 @@ "account.account_page.translation.info.title": "Información de traducción", "account.account-button.confirm.ok": "Sí, cerrar sesión", "account.account-button.confirm.title": "¿Cerrar sesión de tu cuenta?", + "account.appearance.accessibility.enabled": "Activar el Modo de Accesibilidad: optimizar la interfaz de usuario para características de accesibilidad", + "account.appearance.accessibility.title": "Accesibilidad", "account.appearance.user_interface.title": "Interfaz de usuario", "account.delete-account.alert.description": "Perderá inmediatamente acceso a todos sus proyectos, cualquier suscripción será cancelada y todo el crédito no utilizado se perderá. {br} {hr} Para ELIMINAR SU CUENTA, primero ingrese \"{required_text}\" a continuación:", "account.delete-account.alert.message": "¿Está seguro de que desea ELIMINAR SU CUENTA?", @@ -31,13 +33,11 @@ "account.editor-setting.checkbox.strip_trailing_whitespace": "eliminar siempre que se guarde el archivo", "account.editor-settings-autosave-interval.label": "Intervalo de guardado automático", "account.editor-settings.basic.title": "Configuración básica", - "account.editor-settings.color-schemes.label": "Esquema de color del editor", "account.editor-settings.color-schemes.panel_title": "Esquema de Color del Editor", "account.editor-settings.font-size.label": "Tamaño de fuente global predeterminado", "account.editor-settings.indent-size.label": "Tamaño de sangría", "account.editor-settings.keyboard-bindings.label": "Asignaciones de teclado del editor", "account.editor-settings.keyboard.title": "Teclado", - "account.editor-settings.title": "Editor", "account.editor-settings.x11-keyboard-variant.label": "Variante de teclado (para escritorio X11)", "account.editor-settings.x11-physical-keyboard.label": "Distribución del teclado (para el escritorio X11)", "account.global-ssh-keys.help": "Para hacer SSH en un proyecto, usa el siguiente username@host: [project-id-without-dashes]@ssh.cocalc.com El ID del proyecto sin guiones se puede encontrar en la parte de configuración del proyecto sobre claves SSH. Para hacer SSH entre proyectos, usa [project-id-without-dashes]@ssh", @@ -66,13 +66,13 @@ "account.keyboard-shortcuts.shortcut.split-view-sagews": "Vista dividida en hoja de trabajo Sage", "account.keyboard-shortcuts.shortcut.toggle-comment": "Alternar selección de comentarios", "account.other-settings._page_size.label": "Número de archivos por página", - "account.other-settings.browser_performance.title": "Navegador", + "account.other-settings.auto_focus": "Enfoque Automático en la Entrada de Texto: enfocar automáticamente los campos de entrada de texto cuando aparezcan (por ejemplo, explorador de archivos, proyectos, ...)", "account.other-settings.button_tooltips": "Ocultar descripciones emergentes de botones: oculta algunas descripciones emergentes de botones (esto es solo parcial)", "account.other-settings.confirm_close": "Confirmar cierre: siempre pedir confirmación antes de cerrar la ventana del navegador", - "account.other-settings.content_display.title": "Visualización de contenido", "account.other-settings.default_file_sort.by_name": "Ordenar por nombre", "account.other-settings.default_file_sort.by_time": "Ordenar por tiempo", "account.other-settings.default_file_sort.label": "Orden predeterminado de archivos", + "account.other-settings.dim_file_extensions": "Atenuar las extensiones de archivo: atenuar las extensiones de archivo para que sus nombres destaquen.", "account.other-settings.file_popovers": "Ocultar Popovers de Pestañas de Archivos: no mostrar los popovers sobre pestañas de archivos", "account.other-settings.filename_generator.description": "Seleccione cómo se generan los nombres de archivo automáticamente. En particular, para hacerlos únicos o incluir la hora actual.", "account.other-settings.filename_generator.label": "Generador de nombres de archivo", @@ -85,12 +85,9 @@ "account.other-settings.llm.title": "Configuración de IA", "account.other-settings.markdown_codebar": "Desactivar la barra de código markdown en todos los documentos markdown. Al marcar esto, se ocultan los botones adicionales de ejecutar, copiar y explicar en los bloques de código delimitados.", "account.other-settings.mask_files": "Archivos ocultos: atenuar archivos en el visor de archivos que probablemente no desees abrir", - "account.other-settings.messages.title": "Mensajes", "account.other-settings.project_popovers": "Ocultar los Popovers de Pestañas de Proyecto: no mostrar los popovers sobre las pestañas del proyecto", - "account.other-settings.projects.title": "Proyectos", "account.other-settings.standby_timeout": "Tiempo de espera en espera", "account.other-settings.symbol_bar_labels": "Mostrar etiquetas de la barra de símbolos: mostrar etiquetas en la barra de símbolos del editor de marcos", - "account.other-settings.theme": "Tema", "account.other-settings.theme.antd.animations": "Animaciones: animar brevemente algunos aspectos, p. ej., botones", "account.other-settings.theme.antd.color_scheme": "Esquema de Color: usar colores de marca en lugar de colores predeterminados", "account.other-settings.theme.antd.compact": "Diseño Compacto: usar un diseño más compacto", @@ -128,6 +125,7 @@ "account.settings.overview.licenses": "Gestionar licencias de software y permisos de acceso.", "account.settings.overview.other": "Configuraciones y opciones misceláneas.", "account.settings.overview.payg": "Configurar el uso y la facturación de pago por uso.", + "account.settings.overview.payment_methods": "Administra tus métodos de pago guardados o añade nuevos.", "account.settings.overview.payments": "Administrar métodos de pago e historial de transacciones.", "account.settings.overview.profile": "Administra tu información personal, avatar y detalles de la cuenta.", "account.settings.overview.purchases": "Ver historial de compras y recibos.", @@ -135,6 +133,7 @@ "account.settings.overview.subscriptions": "Ver y gestionar tus suscripciones activas.", "account.settings.overview.support": "Accede a los tickets de soporte y recursos de ayuda.", "account.settings.overview.title": "Resumen de configuración", + "account.settings.overview.upgrades": "Administra tus actualizaciones de cuota heredada.", "account.settings.sso.account_is_linked": "Tu cuenta está vinculada con (haz clic para desvincular)", "account.settings.sso.link_your_account": "{is_anonymous, select, true {Regístrate usando tu cuenta en} other {Haz clic para vincular tu cuenta}}", "account.settings.unlisted.label": "No listada: solo se te puede encontrar con una coincidencia exacta de dirección de correo electrónico", @@ -155,6 +154,9 @@ "ai-generate-document.modal.title": "Generar un documento {docName} usando IA", "ai-generator.select_llm": "Seleccionar modelo de idioma", "app.fullscreen-button.tooltip": "Modo de pantalla completa, centrado en el documento o página actual.", + "app.hotkey.dialog.help_text": "Haz clic en los marcos de arriba • La tecla 0 alterna el chat • Las teclas 1–9 enfocan los marcos • Escribe para buscar • ↑↓ navega • Return para abrir • ESC para cerrar", + "app.hotkey.dialog.search_placeholder": "Buscar archivos y páginas...", + "app.hotkey.dialog.title": "Navegación Rápida", "app.verify-email-banner.edit": "Si la dirección de correo electrónico es incorrecta, por favor edítala en la configuración de la cuenta.", "app.verify-email-banner.help.text": "Es importante tener una dirección de correo electrónico funcional. La usamos para restablecer contraseñas, enviar mensajes, notificaciones de facturación y soporte. Por favor, asegúrate de que tu correo electrónico sea correcto para mantenerte informado.", "app.verify-email-banner.text": "{sent, select, true {¡Correo electrónico enviado! Por favor, revisa tu bandeja de entrada de correo (y quizá el spam) y haz clic en el enlace de confirmación.} other {Por favor, revisa y verifica tu dirección de correo electrónico:}}", @@ -988,6 +990,7 @@ "labels.config": "Configurar", "labels.configuration": "Configuración", "labels.configuration.short": "Configurar", + "labels.connected": "Conectado", "labels.connecting": "Conectando", "labels.connection": "Conexión", "labels.copied": "copiado", @@ -1016,6 +1019,7 @@ "labels.environment": "Entorno", "labels.explorer": "Explorador", "labels.file_explorer": "Explorador de Archivos", + "labels.file_use_notifications": "Notificaciones de uso de archivos", "labels.files": "Archivos", "labels.folder": "carpeta", "labels.frame-editors.title-bar.save_label": "{type, select, is_public {Público} read_only {Solo lectura} other {Guardar}}", @@ -1095,6 +1099,7 @@ "labels.project.settings.stop-project.label": "Detener{short, select, true {} other { Proyecto}}…", "labels.project.settings.stop-project.ok": "Sí, detener proyecto", "labels.projects": "Proyectos", + "labels.public_paths": "Rutas Públicas", "labels.published_files": "Archivos Publicados", "labels.purchases": "Compras", "labels.ready": "Listo", @@ -1423,7 +1428,6 @@ "projects.create-project.helpTxt": "Elige un título. ¡Puedes cambiarlo fácilmente más tarde!", "projects.create-project.requireLicense": "Se requiere una licencia para crear proyectos adicionales.", "projects.filename-search.placeholder": "Buscar nombres de archivos que editaste", - "projects.list.no_starred_found": "No se encontraron proyectos destacados. Usa el icono de estrella junto a los títulos de los proyectos para marcar tus proyectos favoritos.", "projects.load-all.label": "Mostrar todos los proyectos...", "projects.operations.clear-filter": "Borrar filtro", "projects.operations.delete.button": "{deleted, select, true {Restaurar todo} other {Eliminar todo}}", @@ -1455,7 +1459,9 @@ "projects.table-controls.hashtags.placeholder": "Filtrar por hashtags...", "projects.table-controls.hidden.label": "Oculto", "projects.table-controls.search.placeholder": "Buscar proyectos...", + "projects.table.keyboard-row-hint": "Proyecto {title}. Usa las flechas Arriba y Abajo para moverte; presiona Enter o Espacio para abrir.", "projects.table.last-edited": "Última edición", + "projects.table.untitled": "Sin título", "purchases.automatic-payments-warning.description": "Los pagos automáticos son mucho más convenientes, te ahorrarán tiempo y asegurarán que las suscripciones no se cancelen por accidente.", "purchases.automatic-payments-warning.title": "Los pagos automáticos NO son necesarios para tener una suscripción", "purchases.automatic-payments.are-enabled": "Los pagos automáticos están habilitados", diff --git a/src/packages/frontend/i18n/trans/es_PV.json b/src/packages/frontend/i18n/trans/es_PV.json index dc59eb628b5..5814b75b346 100644 --- a/src/packages/frontend/i18n/trans/es_PV.json +++ b/src/packages/frontend/i18n/trans/es_PV.json @@ -5,6 +5,8 @@ "account.account_page.translation.info.title": "Itzulpen Informazioa", "account.account-button.confirm.ok": "Bai, saioa amaitu", "account.account-button.confirm.title": "Saioa amaitu zure kontuan?", + "account.appearance.accessibility.enabled": "Gaitu Irisgarritasun Modua: optimizatu erabiltzailearen interfazea irisgarritasun ezaugarrientzat", + "account.appearance.accessibility.title": "Irisgarritasuna", "account.appearance.user_interface.title": "Erabiltzaile Interfazea", "account.delete-account.alert.description": "Berehala galduko duzu zure proiektu guztietara sartzeko aukera, harpidetzak bertan behera utziko dira, eta gastatu gabeko kreditu guztia galduko da. {br} {hr} ZURE KONTUA EZABATZEKO, lehenik sartu behean \"{required_text}\":", "account.delete-account.alert.message": "Ziur zaude ZURE KONTUA EZABATU nahi duzula?", @@ -31,13 +33,11 @@ "account.editor-setting.checkbox.strip_trailing_whitespace": "kendu, fitxategia gordetzen den bakoitzean", "account.editor-settings-autosave-interval.label": "Autogordetze tartea", "account.editor-settings.basic.title": "Oinarrizko Ezarpenak", - "account.editor-settings.color-schemes.label": "Editorearen kolore eskema", "account.editor-settings.color-schemes.panel_title": "Editorearen Kolore Eskema", "account.editor-settings.font-size.label": "Lehenetsitako letra-tamaina globala", "account.editor-settings.indent-size.label": "Indentazio tamaina", "account.editor-settings.keyboard-bindings.label": "Editorearen teklatu loturak", "account.editor-settings.keyboard.title": "Teklatua", - "account.editor-settings.title": "Editorearen Ezarpenak", "account.editor-settings.x11-keyboard-variant.label": "Teklatuaren aldaera (X11 Mahaigainarentzat)", "account.editor-settings.x11-physical-keyboard.label": "Teklatuaren diseinua (X11 Mahaigainarentzat)", "account.global-ssh-keys.help": "SSH bidez proiektu batean sartzeko, erabili honako hau username@host: [proiektuaren-id-gidoi-barik]@ssh.cocalc.com Proiektuaren IDa gidoirik gabe SSH gakoen inguruko proiektuaren ezarpenetan aurki daiteke. Proiektuen artean SSH egiteko, erabili [proiektuaren-id-gidoi-barik]@ssh", @@ -66,13 +66,13 @@ "account.keyboard-shortcuts.shortcut.split-view-sagews": "Bista zatitua Sageko kalkulu orrian", "account.keyboard-shortcuts.shortcut.toggle-comment": "Gaitu hautaketa komentatzea", "account.other-settings._page_size.label": "Fitxategi kopurua orrialde bakoitzeko", - "account.other-settings.browser_performance.title": "Nabigatzailea", + "account.other-settings.auto_focus": "Testu Sarrera Automatikoki Fokatzea: automatikoki fokatu testu sarrera eremuak agertzen direnean (adibidez, fitxategi arakatzailea, proiektuak, ...)", "account.other-settings.button_tooltips": "Ezkutatu Botoiaren Tresna-aholkuak: botoi batzuen tresna-aholkuak ezkutatzen ditu (hau partziala da)", "account.other-settings.confirm_close": "Berrestu Ixtea: beti eskatu berrespena nabigatzailearen leihoa itxi aurretik", - "account.other-settings.content_display.title": "Edukien Erakusketa", "account.other-settings.default_file_sort.by_name": "Izenez ordenatu", "account.other-settings.default_file_sort.by_time": "Ordenatu denboraren arabera", "account.other-settings.default_file_sort.label": "Fitxategi ordenazio lehenetsia", + "account.other-settings.dim_file_extensions": "Fitxategiaren luzapenak ilundu: gristatu fitxategiaren luzapenak, haien izenak nabarmentzeko.", "account.other-settings.file_popovers": "Ezkutatu Fitxategi Fitxen Popoverrak: ez erakutsi popoverrak fitxategi fitxetan", "account.other-settings.filename_generator.description": "Hautatu automatikoki sortutako fitxategi-izenak nola sortzen diren. Bereziki, bakarrak bihurtzeko edo egungo denbora sartzeko.", "account.other-settings.filename_generator.label": "Fitxategi-izenen sortzailea", @@ -85,12 +85,9 @@ "account.other-settings.llm.title": "AI Ezarpenak", "account.other-settings.markdown_codebar": "Desgaitu markdown kode barra markdown dokumentu guztietan. Hau markatzeak \"exekutatu\", \"kopiatu\" eta \"azaldu\" botoi gehigarriak ezkutatzen ditu.", "account.other-settings.mask_files": "Fitxategiak Maskaratu: ziurrenik ireki nahi ez dituzun fitxategiak esploratzailean grisez apaldu", - "account.other-settings.messages.title": "Mezuak", "account.other-settings.project_popovers": "Proiektuaren fitxa popoverrak ezkutatu: ez erakutsi popoverrak proiektuaren fitxen gainean", - "account.other-settings.projects.title": "Proiektuak", "account.other-settings.standby_timeout": "Itxaronaldi epea", "account.other-settings.symbol_bar_labels": "Ikusi Sinbolo Barra Etiketak: erakutsi etiketak marko editorearen sinbolo barran", - "account.other-settings.theme": "Gaia", "account.other-settings.theme.antd.animations": "Animazioak: gauza batzuk labur animatu, adibidez, botoiak", "account.other-settings.theme.antd.color_scheme": "Kolore Eskema: erabili marka koloreak lehenetsitako koloreen ordez", "account.other-settings.theme.antd.compact": "Diseinu Trinkoa: Diseinu trinkoagoa erabili", @@ -128,6 +125,7 @@ "account.settings.overview.licenses": "Kudeatu software lizentziak eta sarbide-baimenak.", "account.settings.overview.other": "Aukera eta ezarpen desberdinak.", "account.settings.overview.payg": "Konfiguratu ordaindu ahala erabiltzea eta fakturazioa.", + "account.settings.overview.payment_methods": "Kudeatu zure ordainketa-metodo gordeak edo gehitu berriak.", "account.settings.overview.payments": "Kudeatu ordainketa metodoak eta transakzio historia.", "account.settings.overview.profile": "Kudeatu zure informazio pertsonala, avatarra eta kontuaren xehetasunak.", "account.settings.overview.purchases": "Ikusi erosketa historia eta ordainagirienak.", @@ -135,6 +133,7 @@ "account.settings.overview.subscriptions": "Ikusi eta kudeatu zure harpidetza aktiboak.", "account.settings.overview.support": "Sarbide laguntza-txarteletara eta laguntza-baliabideetara.", "account.settings.overview.title": "Ezarpenen Ikuspegi Orokorra", + "account.settings.overview.upgrades": "Kudeatu zure kuota berritzeak.", "account.settings.sso.account_is_linked": "Zure kontua honekin dago lotuta (klikatu lotura kentzeko)", "account.settings.sso.link_your_account": "{is_anonymous, select, true {Eman izena zure kontuarekin} other {Egin klik zure kontua lotzeko}}", "account.settings.unlisted.label": "Zerrendatik kanpo: posta elektroniko zehatzarekin baino ez zaitzake aurkitu", @@ -155,6 +154,9 @@ "ai-generate-document.modal.title": "Sortu {docName} Dokumentua AI erabiliz", "ai-generator.select_llm": "Aukeratu hizkuntza eredua", "app.fullscreen-button.tooltip": "Pantaila osoa modua, uneko dokumentuan edo orrian zentratuta.", + "app.hotkey.dialog.help_text": "Egin klik goiko markoetan • Tekla 0k txata aktibatu/desaktibatzen du • Teklak 1–9 markoetan zentratzen dira • Idatzi bilatzeko • ↑↓ nabigatzeko • Return irekitzeko • ESC ixteko", + "app.hotkey.dialog.search_placeholder": "Bilatu fitxategiak eta orriak...", + "app.hotkey.dialog.title": "Nabigazio Bizkorra", "app.verify-email-banner.edit": "Email helbidea ez bada zuzena editatu egizu kontu ezarpenetan.", "app.verify-email-banner.help.text": "Garrantzitsua da funtzionatzen duen helbide elektroniko bat izatea. Pasahitzak berrezartzeko, mezuak bidaltzeko, fakturazio jakinarazpenak egiteko eta laguntza emateko bidaltzen dugu. Mesedez, ziurtatu zure helbide elektronikoa zuzena dela informazioa jasotzeko.", "app.verify-email-banner.text": "{sent, select, true {Emaila Bidalita! Mesedez, begiratu zure email sarrera-ontzia (eta agian spam karpeta) eta klik egin berrespen estekan.} other {Mesedez, egiaztatu eta baieztatu zure helbide elektronikoa:}}", @@ -988,6 +990,7 @@ "labels.config": "Konfigurazio", "labels.configuration": "Konfigurazioa", "labels.configuration.short": "Konfigurazio", + "labels.connected": "Konektatuta", "labels.connecting": "Konexioa egiten", "labels.connection": "Konexioa", "labels.copied": "kopiatuta", @@ -1016,6 +1019,7 @@ "labels.environment": "Ingurunea", "labels.explorer": "Arakatzailea", "labels.file_explorer": "Fitxategi Arakatzailea", + "labels.file_use_notifications": "Fitxategi Erabilera Jakinarazpenak", "labels.files": "Fitxategiak", "labels.folder": "karpeta", "labels.frame-editors.title-bar.save_label": "{type, select, is_public {Publikoa} read_only {Iragargaitza} other {Gorde}}", @@ -1095,6 +1099,7 @@ "labels.project.settings.stop-project.label": "Gelditu{short, select, true {} other { Proiektua}}…", "labels.project.settings.stop-project.ok": "Bai, gelditu proiektua", "labels.projects": "Proiektuak", + "labels.public_paths": "Bide Publikoak", "labels.published_files": "Argitaratua", "labels.purchases": "Erosketak", "labels.ready": "Prest", @@ -1423,7 +1428,6 @@ "projects.create-project.helpTxt": "Hautatu izenburua. Erraz alda dezakezu geroago!", "projects.create-project.requireLicense": "Proiektu gehigarriak sortzeko lizentzia behar da.", "projects.filename-search.placeholder": "Bilatu editatu dituzun fitxategi izenak...", - "projects.list.no_starred_found": "Ez da izarrez markatutako proiekturik aurkitu. Erabili izar ikonoa proiektuen izenburuen ondoan zure proiektu gogokoenak laster-markan jartzeko.", "projects.load-all.label": "Erakutsi proiektu guztiak...", "projects.operations.clear-filter": "Garbitu Iragazkia", "projects.operations.delete.button": "{deleted, select, true {Berreskuratu Guztiak} other {Ezabatu Guztiak}}", @@ -1455,7 +1459,9 @@ "projects.table-controls.hashtags.placeholder": "Iragazi etiketen arabera...", "projects.table-controls.hidden.label": "Ezkutua", "projects.table-controls.search.placeholder": "Proiektuak bilatu...", + "projects.table.keyboard-row-hint": "Proiektua {title}. Erabili gora eta behera gezien tekla mugitzeko; sakatu Enter edo Space irekitzeko.", "projects.table.last-edited": "Azken aldiz editatua", + "projects.table.untitled": "Izenbururik gabe", "purchases.automatic-payments-warning.description": "Ordainketa automatikoak askoz erosoagoak dira, denbora aurreztuko dizute eta harpidetzak ez direla istripuz bertan behera geldituko ziurtatuko dute.", "purchases.automatic-payments-warning.title": "Ez da beharrezkoa ordainketa automatikoak izatea harpidetza izateko", "purchases.automatic-payments.are-enabled": "Ordainketa Automatikoak Gaituta Daude", diff --git a/src/packages/frontend/i18n/trans/fr_FR.json b/src/packages/frontend/i18n/trans/fr_FR.json index 29624a48bb1..0ad050e6d0d 100644 --- a/src/packages/frontend/i18n/trans/fr_FR.json +++ b/src/packages/frontend/i18n/trans/fr_FR.json @@ -5,6 +5,8 @@ "account.account_page.translation.info.title": "Informations de traduction", "account.account-button.confirm.ok": "Oui, déconnexion", "account.account-button.confirm.title": "Se déconnecter de votre compte ?", + "account.appearance.accessibility.enabled": "Activer le mode Accessibilité : optimiser l'interface utilisateur pour les fonctionnalités d'accessibilité", + "account.appearance.accessibility.title": "Accessibilité", "account.appearance.user_interface.title": "Interface utilisateur", "account.delete-account.alert.description": "Vous perdrez immédiatement l'accès à tous vos projets, tous les abonnements seront annulés, et tout crédit non dépensé sera perdu. {br} {hr} Pour SUPPRIMER VOTRE COMPTE, entrez d'abord \"{required_text}\" ci-dessous :", "account.delete-account.alert.message": "Êtes-vous sûr de vouloir SUPPRIMER VOTRE COMPTE ?", @@ -31,13 +33,11 @@ "account.editor-setting.checkbox.strip_trailing_whitespace": "supprimer chaque fois que le fichier est enregistré", "account.editor-settings-autosave-interval.label": "Intervalle de sauvegarde automatique", "account.editor-settings.basic.title": "Paramètres de base", - "account.editor-settings.color-schemes.label": "Schéma de couleurs de l'éditeur", "account.editor-settings.color-schemes.panel_title": "Schéma de couleurs de l'éditeur", "account.editor-settings.font-size.label": "Taille de police globale par défaut", "account.editor-settings.indent-size.label": "Taille de l'indentation", "account.editor-settings.keyboard-bindings.label": "Raccourcis clavier de l'éditeur", "account.editor-settings.keyboard.title": "Clavier", - "account.editor-settings.title": "Éditeur", "account.editor-settings.x11-keyboard-variant.label": "Variante de clavier (pour le bureau X11)", "account.editor-settings.x11-physical-keyboard.label": "Disposition du clavier (pour le bureau X11)", "account.global-ssh-keys.help": "Pour SSH dans un projet, utilisez le format suivant username@host: [project-id-without-dashes]@ssh.cocalc.com L'identifiant du projet sans tirets se trouve dans la section des paramètres du projet concernant les clés SSH. Pour SSH entre projets, utilisez [project-id-without-dashes]@ssh", @@ -66,13 +66,13 @@ "account.keyboard-shortcuts.shortcut.split-view-sagews": "Vue partagée dans la feuille de calcul Sage", "account.keyboard-shortcuts.shortcut.toggle-comment": "Basculer le commentaire de la sélection", "account.other-settings._page_size.label": "Nombre de fichiers par page", - "account.other-settings.browser_performance.title": "Navigateur", + "account.other-settings.auto_focus": "Texte d'entrée de mise au point automatique : met automatiquement au point les champs de saisie de texte lorsqu'ils apparaissent (par exemple, explorateur de fichiers, projets, ...)", "account.other-settings.button_tooltips": "Masquer les info-bulles des boutons : masque certaines info-bulles des boutons (ceci est seulement partiel)", "account.other-settings.confirm_close": "Confirmer la fermeture : toujours demander confirmation avant de fermer la fenêtre du navigateur", - "account.other-settings.content_display.title": "Affichage du contenu", "account.other-settings.default_file_sort.by_name": "Trier par nom", "account.other-settings.default_file_sort.by_time": "Trier par temps", "account.other-settings.default_file_sort.label": "Tri par défaut des fichiers", + "account.other-settings.dim_file_extensions": "Extensions de fichier en gris : griser les extensions de fichier pour que leurs noms se démarquent.", "account.other-settings.file_popovers": "Cacher les info-bulles des onglets de fichiers : ne pas afficher les info-bulles sur les onglets de fichiers", "account.other-settings.filename_generator.description": "Sélectionnez comment les noms de fichiers générés automatiquement sont créés. En particulier, pour les rendre uniques ou inclure l'heure actuelle.", "account.other-settings.filename_generator.label": "Générateur de nom de fichier", @@ -85,12 +85,9 @@ "account.other-settings.llm.title": "Paramètres AI", "account.other-settings.markdown_codebar": "Désactiver la barre de code markdown dans tous les documents markdown. Cocher ceci masque les boutons supplémentaires d'exécution, de copie et d'explication dans les blocs de code délimités.", "account.other-settings.mask_files": "Masquer les fichiers : griser les fichiers dans le visualiseur de fichiers que vous ne souhaitez probablement pas ouvrir", - "account.other-settings.messages.title": "Messages", "account.other-settings.project_popovers": "Masquer les popovers des onglets de projet : ne pas afficher les popovers au-dessus des onglets de projet", - "account.other-settings.projects.title": "Projets", "account.other-settings.standby_timeout": "Délai d'attente en veille", "account.other-settings.symbol_bar_labels": "Afficher les étiquettes de la barre de symboles : afficher les étiquettes dans la barre de symboles de l'éditeur de cadre", - "account.other-settings.theme": "Thème", "account.other-settings.theme.antd.animations": "Animations : animer brièvement certains aspects, par exemple les boutons", "account.other-settings.theme.antd.color_scheme": "Schéma de couleurs : utiliser les couleurs de marque au lieu des couleurs par défaut", "account.other-settings.theme.antd.compact": "Conception compacte: utiliser une conception plus compacte", @@ -128,6 +125,7 @@ "account.settings.overview.licenses": "Gérer les licences logicielles et les autorisations d'accès.", "account.settings.overview.other": "Paramètres et options divers.", "account.settings.overview.payg": "Configurer l'utilisation et la facturation à la demande.", + "account.settings.overview.payment_methods": "Gérez vos méthodes de paiement enregistrées ou ajoutez-en de nouvelles.", "account.settings.overview.payments": "Gérer les méthodes de paiement et l'historique des transactions.", "account.settings.overview.profile": "Gérez vos informations personnelles, votre avatar et les détails de votre compte.", "account.settings.overview.purchases": "Afficher l'historique des achats et les reçus.", @@ -135,6 +133,7 @@ "account.settings.overview.subscriptions": "Afficher et gérer vos abonnements actifs.", "account.settings.overview.support": "Accédez aux tickets de support et aux ressources d'aide.", "account.settings.overview.title": "Aperçu des paramètres", + "account.settings.overview.upgrades": "Gérez vos mises à niveau de quota d'héritage.", "account.settings.sso.account_is_linked": "Votre compte est lié à (cliquez pour dissocier)", "account.settings.sso.link_your_account": "{is_anonymous, select, true {Inscrivez-vous en utilisant votre compte sur} other {Cliquez pour lier votre compte}}", "account.settings.unlisted.label": "Non répertorié : on ne peut vous trouver qu'avec une correspondance exacte d'adresse email", @@ -155,6 +154,9 @@ "ai-generate-document.modal.title": "Générer un document {docName} en utilisant l'IA", "ai-generator.select_llm": "Sélectionner le modèle de langue", "app.fullscreen-button.tooltip": "Mode plein écran, concentré sur le document ou la page actuelle.", + "app.hotkey.dialog.help_text": "Cliquez sur les cadres ci-dessus • Touche 0 pour basculer le chat • Touches 1–9 pour focaliser les cadres • Tapez pour rechercher • ↑↓ naviguer • Entrée pour ouvrir • Échap pour fermer", + "app.hotkey.dialog.search_placeholder": "Rechercher des fichiers et des pages...", + "app.hotkey.dialog.title": "Navigation rapide", "app.verify-email-banner.edit": "Si l'adresse e-mail est incorrecte, veuillez la modifier dans les paramètres du compte.", "app.verify-email-banner.help.text": "Il est important d'avoir une adresse e-mail fonctionnelle. Nous l'utilisons pour les réinitialisations de mot de passe, l'envoi de messages, les notifications de facturation et le support. Veuillez vous assurer que votre e-mail est correct pour rester informé.", "app.verify-email-banner.text": "{sent, select, true {Email envoyé ! Veuillez vérifier votre boîte de réception (et peut-être les spams) et cliquez sur le lien de confirmation.} other {Veuillez vérifier et confirmer votre adresse e-mail :}}", @@ -988,6 +990,7 @@ "labels.config": "Config", "labels.configuration": "Configuration", "labels.configuration.short": "Config", + "labels.connected": "Connecté", "labels.connecting": "Connexion", "labels.connection": "Connexion", "labels.copied": "copié", @@ -1016,6 +1019,7 @@ "labels.environment": "Environnement", "labels.explorer": "Explorateur", "labels.file_explorer": "Explorateur de fichiers", + "labels.file_use_notifications": "Notifications d'utilisation de fichier", "labels.files": "Fichiers", "labels.folder": "dossier", "labels.frame-editors.title-bar.save_label": "{type, select, is_public {Public} read_only {Lecture seule} other {Enregistrer}}", @@ -1095,6 +1099,7 @@ "labels.project.settings.stop-project.label": "Arrêter{short, select, true {} other { Projet}}…", "labels.project.settings.stop-project.ok": "Oui, arrêter le projet", "labels.projects": "Projets", + "labels.public_paths": "Chemins Publics", "labels.published_files": "Fichiers publiés", "labels.purchases": "Achats", "labels.ready": "Prêt", @@ -1423,7 +1428,6 @@ "projects.create-project.helpTxt": "Choisissez un titre. Vous pouvez facilement le changer plus tard !", "projects.create-project.requireLicense": "Une licence est requise pour créer des projets supplémentaires.", "projects.filename-search.placeholder": "Rechercher les noms de fichiers que vous avez modifiés...", - "projects.list.no_starred_found": "Aucun projet étoilé trouvé. Utilisez l'icône en forme d'étoile à côté des titres de projet pour ajouter vos projets favoris en signet.", "projects.load-all.label": "Afficher tous les projets...", "projects.operations.clear-filter": "Effacer le filtre", "projects.operations.delete.button": "{deleted, select, true {Restaurer tout} other {Tout supprimer}}", @@ -1455,7 +1459,9 @@ "projects.table-controls.hashtags.placeholder": "Filtrer par hashtags...", "projects.table-controls.hidden.label": "Caché", "projects.table-controls.search.placeholder": "Rechercher des projets...", + "projects.table.keyboard-row-hint": "Projet {title}. Utilisez les flèches Haut et Bas pour vous déplacer ; appuyez sur Entrée ou Espace pour ouvrir.", "projects.table.last-edited": "Dernière modification", + "projects.table.untitled": "Sans titre", "purchases.automatic-payments-warning.description": "Les paiements automatiques sont beaucoup plus pratiques, vous feront gagner du temps, et assurent que les abonnements ne soient pas annulés par accident.", "purchases.automatic-payments-warning.title": "Les paiements automatiques NE sont PAS nécessaires pour avoir un abonnement", "purchases.automatic-payments.are-enabled": "Les paiements automatiques sont activés", diff --git a/src/packages/frontend/i18n/trans/he_IL.json b/src/packages/frontend/i18n/trans/he_IL.json index fe22315927b..d31a194da5a 100644 --- a/src/packages/frontend/i18n/trans/he_IL.json +++ b/src/packages/frontend/i18n/trans/he_IL.json @@ -5,6 +5,8 @@ "account.account_page.translation.info.title": "מידע על תרגום", "account.account-button.confirm.ok": "כן, התנתק", "account.account-button.confirm.title": "לצאת מהחשבון שלך?", + "account.appearance.accessibility.enabled": "הפעל מצב נגישות: מיטוב ממשק המשתמש עבור תכונות נגישות", + "account.appearance.accessibility.title": "נגישות", "account.appearance.user_interface.title": "ממשק משתמש", "account.delete-account.alert.description": "תאבד מיד גישה לכל הפרויקטים שלך, כל המנויים יבוטלו, וכל הקרדיט שלא נוצל יאבד. {br} {hr} כדי למחוק את החשבון שלך, ראשית הכנס את \"{required_text}\" למטה:", "account.delete-account.alert.message": "האם אתה בטוח שברצונך למחוק את החשבון שלך?", @@ -31,13 +33,11 @@ "account.editor-setting.checkbox.strip_trailing_whitespace": "הסר בכל פעם שקובץ נשמר", "account.editor-settings-autosave-interval.label": "מרווח שמירה אוטומטית", "account.editor-settings.basic.title": "הגדרות בסיסיות", - "account.editor-settings.color-schemes.label": "ערכת צבעים של העורך", "account.editor-settings.color-schemes.panel_title": "ערכת צבעים לעורך", "account.editor-settings.font-size.label": "גודל גופן גלובלי ברירת מחדל", "account.editor-settings.indent-size.label": "גודל הזחה", "account.editor-settings.keyboard-bindings.label": "קיצורי מקלדת לעורך", "account.editor-settings.keyboard.title": "מקלדת", - "account.editor-settings.title": "עורך", "account.editor-settings.x11-keyboard-variant.label": "גרסת מקלדת (לשולחן עבודה X11)", "account.editor-settings.x11-physical-keyboard.label": "פריסת מקלדת (לשולחן העבודה X11)", "account.global-ssh-keys.help": "כדי להתחבר בפרוטוקול SSH לפרויקט, השתמש ב-username@host: [project-id-without-dashes]@ssh.cocalc.com ניתן למצוא את מזהה הפרויקט ללא מקפים בחלק של הגדרות הפרויקט לגבי מפתחות SSH. כדי להתחבר בפרוטוקול SSH בין פרויקטים, השתמש ב-[project-id-without-dashes]@ssh", @@ -66,13 +66,13 @@ "account.keyboard-shortcuts.shortcut.split-view-sagews": "תצוגה מפוצלת בגליון העבודה של Sage", "account.keyboard-shortcuts.shortcut.toggle-comment": "החלפת מצב הערות בחירה", "account.other-settings._page_size.label": "מספר הקבצים לכל עמוד", - "account.other-settings.browser_performance.title": "דפדפן", + "account.other-settings.auto_focus": "מיקוד אוטומטי על שדה טקסט: מיקוד אוטומטי על שדות טקסט כשאלה מופיעים (לדוגמה, סייר קבצים, פרויקטים, ...)", "account.other-settings.button_tooltips": "הסתרת תיאורי כלים של כפתורים: מסתיר חלק מתיאורי הכלים של הכפתורים (זה חלקי בלבד)", "account.other-settings.confirm_close": "אישור סגירה: תמיד לבקש אישור לפני סגירת חלון הדפדפן", - "account.other-settings.content_display.title": "תצוגת תוכן", "account.other-settings.default_file_sort.by_name": "מיין לפי שם", "account.other-settings.default_file_sort.by_time": "מיין לפי זמן", "account.other-settings.default_file_sort.label": "מיון קבצים ברירת מחדל", + "account.other-settings.dim_file_extensions": "סיומות קבצים בגוון אפור: צביעת סיומות קבצים באפור כדי ששמותיהם יבלטו.", "account.other-settings.file_popovers": "הסתרת פופאברים בכרטיסיות קבצים: אל תציג את הפופאברים מעל כרטיסיות הקבצים", "account.other-settings.filename_generator.description": "בחר כיצד שמות קבצים הנוצרים באופן אוטומטי נוצרים. במיוחד, כדי להפוך אותם לייחודיים או לכלול את הזמן הנוכחי.", "account.other-settings.filename_generator.label": "מחולל שמות קבצים", @@ -85,12 +85,9 @@ "account.other-settings.llm.title": "הגדרות AI", "account.other-settings.markdown_codebar": "השבת את סרגל הקוד של Markdown בכל מסמכי ה-Markdown. סימון זה מסתיר את כפתורי הריצה, ההעתקה וההסבר הנוספים בקטעי קוד מגודרים.", "account.other-settings.mask_files": "הסתר קבצים: האפור קבצים בצופה הקבצים שבדרך כלל לא תרצה לפתוח", - "account.other-settings.messages.title": "הודעות", "account.other-settings.project_popovers": "הסתרת פופאברים בכרטיסיות הפרויקט: אל תציג את הפופאברים מעל כרטיסיות הפרויקט", - "account.other-settings.projects.title": "פרויקטים", "account.other-settings.standby_timeout": "פסק זמן במצב המתנה", "account.other-settings.symbol_bar_labels": "הצג תוויות סרגל סמלים: הצג תוויות בסרגל הסמלים בעורך המסגרת", - "account.other-settings.theme": "ערכת נושא", "account.other-settings.theme.antd.animations": "אנימציות: הנפשה קצרה של חלקים מסוימים, למשל כפתורים", "account.other-settings.theme.antd.color_scheme": "ערכת צבעים: השתמש בצבעי המותג במקום בצבעי ברירת המחדל", "account.other-settings.theme.antd.compact": "עיצוב קומפקטי: השתמש בעיצוב יותר קומפקטי", @@ -128,6 +125,7 @@ "account.settings.overview.licenses": "נהל רישיונות תוכנה והרשאות גישה.", "account.settings.overview.other": "הגדרות ואפשרויות שונות.", "account.settings.overview.payg": "הגדר שימוש ותשלום לפי צריכה.", + "account.settings.overview.payment_methods": "נהל את אמצעי התשלום השמורים שלך או הוסף חדשים.", "account.settings.overview.payments": "נהל שיטות תשלום והיסטוריית עסקאות.", "account.settings.overview.profile": "נהל את המידע האישי שלך, את הדמות שלך ואת פרטי החשבון.", "account.settings.overview.purchases": "צפה בהיסטוריית רכישות וקבלות.", @@ -135,6 +133,7 @@ "account.settings.overview.subscriptions": "צפה ונהל את המנויים הפעילים שלך.", "account.settings.overview.support": "גישה לכרטיסי תמיכה ומשאבי עזרה.", "account.settings.overview.title": "סקירת הגדרות", + "account.settings.overview.upgrades": "נהל את שדרוגי מכסת המורשת שלך.", "account.settings.sso.account_is_linked": "החשבון שלך מקושר עם (לחץ כדי לבטל קישור)", "account.settings.sso.link_your_account": "{is_anonymous, select, true {הירשם באמצעות החשבון שלך ב} other {לחץ לקישור החשבון שלך}}", "account.settings.unlisted.label": "לא רשום: ניתן למצוא אותך רק באמצעות התאמה מדויקת של כתובת אימייל", @@ -155,6 +154,9 @@ "ai-generate-document.modal.title": "צור מסמך {docName} באמצעות AI", "ai-generator.select_llm": "בחר מודל שפה", "app.fullscreen-button.tooltip": "מצב מסך מלא, ממוקד במסמך או בעמוד הנוכחי", + "app.hotkey.dialog.help_text": "לחץ על המסגרות למעלה • מקש 0 מחליף צ'אט • מקשים 1–9 ממקדים מסגרות • הקלד לחיפוש • ↑↓ ניווט • Enter לפתיחה • ESC לסגירה", + "app.hotkey.dialog.search_placeholder": "חפש קבצים ודפים...", + "app.hotkey.dialog.title": "ניווט מהיר", "app.verify-email-banner.edit": "אם כתובת הדוא\"ל שגויה, אנא ערוך אותה בהגדרות החשבון.", "app.verify-email-banner.help.text": "חשוב שתהיה כתובת דוא\"ל פעילה. אנו משתמשים בה לאיפוס סיסמאות, שליחת הודעות, התראות חיוב ותמיכה. אנא ודא שכתובת הדוא\"ל שלך נכונה כדי להישאר מעודכן.", "app.verify-email-banner.text": "{sent, select, true {האימייל נשלח! בדוק את תיבת הדואר הנכנס שלך (ואולי דואר זבל) ולחץ על קישור האישור.} other {אנא בדוק ואמת את כתובת האימייל שלך:}}", @@ -988,6 +990,7 @@ "labels.config": "הגדרות", "labels.configuration": "תצורה", "labels.configuration.short": "הגדרות", + "labels.connected": "מחובר", "labels.connecting": "מתחבר", "labels.connection": "חיבור", "labels.copied": "הועתק", @@ -1016,6 +1019,7 @@ "labels.environment": "סביבה", "labels.explorer": "סייר", "labels.file_explorer": "סייר קבצים", + "labels.file_use_notifications": "התראות שימוש בקבצים", "labels.files": "קבצים", "labels.folder": "תיקייה", "labels.frame-editors.title-bar.save_label": "{type, select, is_public {ציבורי} read_only {לקריאה בלבד} other {שמור}}", @@ -1095,6 +1099,7 @@ "labels.project.settings.stop-project.label": "עצור{short, select, true {} other { פרויקט}}…", "labels.project.settings.stop-project.ok": "כן, עצור פרויקט", "labels.projects": "פרויקטים", + "labels.public_paths": "נתיבים ציבוריים", "labels.published_files": "קבצים פורסמו", "labels.purchases": "רכישות", "labels.ready": "מוכן", @@ -1423,7 +1428,6 @@ "projects.create-project.helpTxt": "בחר כותרת. תוכל לשנות אותה בקלות מאוחר יותר!", "projects.create-project.requireLicense": "נדרשת רישיון כדי ליצור פרויקטים נוספים.", "projects.filename-search.placeholder": "חפש קבצים שערכת...", - "projects.list.no_starred_found": "לא נמצאו פרויקטים מסומנים בכוכב. השתמש באייקון הכוכב ליד כותרות הפרויקטים כדי לסמן את הפרויקטים המועדפים עליך.", "projects.load-all.label": "הצג את כל הפרויקטים...", "projects.operations.clear-filter": "נקה מסנן", "projects.operations.delete.button": "{deleted, select, true {שחזר הכל} other {מחק הכל}}", @@ -1455,7 +1459,9 @@ "projects.table-controls.hashtags.placeholder": "סנן לפי האשטגים...", "projects.table-controls.hidden.label": "מוסתר", "projects.table-controls.search.placeholder": "חיפוש פרויקטים...", + "projects.table.keyboard-row-hint": "פרויקט {title}. השתמש בחצים למעלה ולמטה כדי לנוע; לחץ על Enter או על רווח כדי לפתוח.", "projects.table.last-edited": "נערך לאחרונה", + "projects.table.untitled": "ללא כותרת", "purchases.automatic-payments-warning.description": "תשלומים אוטומטיים הם הרבה יותר נוחים, יחסכו לך זמן, ויבטיחו שמנויים לא יבוטלו בטעות.", "purchases.automatic-payments-warning.title": "תשלומים אוטומטיים אינם נדרשים למנוי", "purchases.automatic-payments.are-enabled": "תשלומים אוטומטיים מופעלים", diff --git a/src/packages/frontend/i18n/trans/hi_IN.json b/src/packages/frontend/i18n/trans/hi_IN.json index 545a80e5d49..8ee7b765c72 100644 --- a/src/packages/frontend/i18n/trans/hi_IN.json +++ b/src/packages/frontend/i18n/trans/hi_IN.json @@ -5,6 +5,8 @@ "account.account_page.translation.info.title": "अनुवाद जानकारी", "account.account-button.confirm.ok": "हां, साइन आउट", "account.account-button.confirm.title": "अपने खाते से साइन आउट करें?", + "account.appearance.accessibility.enabled": "एक्सेसिबिलिटी मोड सक्षम करें: एक्सेसिबिलिटी सुविधाओं के लिए उपयोगकर्ता इंटरफ़ेस को अनुकूलित करें", + "account.appearance.accessibility.title": "पहुँच योग्यता", "account.appearance.user_interface.title": "उपयोगकर्ता इंटरफ़ेस", "account.delete-account.alert.description": "आप तुरंत अपने सभी प्रोजेक्ट्स की पहुंच खो देंगे, कोई भी सब्सक्रिप्शन रद्द कर दिए जाएंगे, और सभी बिना खर्च किया हुआ क्रेडिट खो जाएगा। {br} {hr} अपना खाता हटाने के लिए, पहले नीचे \"{required_text}\" दर्ज करें:", "account.delete-account.alert.message": "क्या आप वाकई अपना खाता हटाना चाहते हैं?", @@ -31,13 +33,11 @@ "account.editor-setting.checkbox.strip_trailing_whitespace": "जब भी फ़ाइल सहेजी जाती है, हटाएं", "account.editor-settings-autosave-interval.label": "ऑटोसेव अंतराल", "account.editor-settings.basic.title": "मूलभूत सेटिंग्स", - "account.editor-settings.color-schemes.label": "एडिटर रंग योजना", "account.editor-settings.color-schemes.panel_title": "संपादक रंग योजना", "account.editor-settings.font-size.label": "डिफ़ॉल्ट वैश्विक फ़ॉन्ट आकार", "account.editor-settings.indent-size.label": "इंडेंट आकार", "account.editor-settings.keyboard-bindings.label": "संपादक कीबोर्ड बाइंडिंग्स", "account.editor-settings.keyboard.title": "कीबोर्ड", - "account.editor-settings.title": "संपादक", "account.editor-settings.x11-keyboard-variant.label": "कीबोर्ड प्रकार (X11 डेस्कटॉप के लिए)", "account.editor-settings.x11-physical-keyboard.label": "कीबोर्ड लेआउट (X11 डेस्कटॉप के लिए)", "account.global-ssh-keys.help": "एक प्रोजेक्ट में SSH करने के लिए, निम्नलिखित का उपयोग करें username@host: [project-id-without-dashes]@ssh.cocalc.com SSH कुंजियों के बारे में प्रोजेक्ट सेटिंग्स के भाग में प्रोजेक्ट आईडी बिना डैश के पाई जा सकती है। प्रोजेक्ट्स के बीच SSH करने के लिए, [project-id-without-dashes]@ssh का उपयोग करें।", @@ -66,13 +66,13 @@ "account.keyboard-shortcuts.shortcut.split-view-sagews": "Sage कार्यपत्रक में दृश्य विभाजन", "account.keyboard-shortcuts.shortcut.toggle-comment": "चयन पर टिप्पणी टॉगल करें", "account.other-settings._page_size.label": "प्रति पृष्ठ फ़ाइलों की संख्या", - "account.other-settings.browser_performance.title": "ब्राउज़र", + "account.other-settings.auto_focus": "ऑटो फोकस टेक्स्ट इनपुट: जब वे प्रकट होते हैं तो टेक्स्ट इनपुट फ़ील्ड्स पर स्वचालित रूप से फोकस करें (जैसे, फाइल एक्सप्लोरर, प्रोजेक्ट्स, ...)", "account.other-settings.button_tooltips": "हाइड बटन टूलटिप्स: कुछ बटन टूलटिप्स को छुपाता है (यह केवल आंशिक है)", "account.other-settings.confirm_close": "बंद करने की पुष्टि करें: ब्राउज़र विंडो बंद करने से पहले हमेशा पुष्टि के लिए पूछें", - "account.other-settings.content_display.title": "सामग्री प्रदर्शन", "account.other-settings.default_file_sort.by_name": "नाम के अनुसार क्रमबद्ध करें", "account.other-settings.default_file_sort.by_time": "समय के अनुसार छाँटें", "account.other-settings.default_file_sort.label": "डिफ़ॉल्ट फ़ाइल क्रम", + "account.other-settings.dim_file_extensions": "फ़ाइल एक्सटेंशन को धुंधला करें: फ़ाइल एक्सटेंशन को ग्रे कर दें ताकि उनके नाम अलग दिखें।", "account.other-settings.file_popovers": "फाइल टैब पॉपओवर छुपाएं: फाइल टैब पर पॉपओवर न दिखाएं", "account.other-settings.filename_generator.description": "स्वचालित रूप से उत्पन्न फ़ाइल नाम कैसे उत्पन्न होते हैं, इसका चयन करें। विशेष रूप से, उन्हें अद्वितीय बनाने या वर्तमान समय शामिल करने के लिए।", "account.other-settings.filename_generator.label": "फाइलनाम जनरेटर", @@ -85,12 +85,9 @@ "account.other-settings.llm.title": "एआई सेटिंग्स", "account.other-settings.markdown_codebar": "सभी मार्कडाउन दस्तावेज़ों में मार्कडाउन कोड बार को अक्षम करें. इसे चेक करने से बाड़े गए कोड ब्लॉकों में अतिरिक्त चलाएं, कॉपी करें और समझाएं बटन छिप जाते हैं।", "account.other-settings.mask_files": "मास्क फाइल्स: उन फाइलों को ग्रे आउट करें जिन्हें आप शायद खोलना नहीं चाहते फाइल्स व्यूअर में", - "account.other-settings.messages.title": "संदेश", "account.other-settings.project_popovers": "प्रोजेक्ट टैब पॉपओवर छुपाएं: प्रोजेक्ट टैब पर पॉपओवर न दिखाएं", - "account.other-settings.projects.title": "प्रोजेक्ट्स", "account.other-settings.standby_timeout": "स्टैंडबाय टाइमआउट", "account.other-settings.symbol_bar_labels": "प्रतीक पट्टी लेबल दिखाएं: फ्रेम संपादक प्रतीक पट्टी में लेबल दिखाएं", - "account.other-settings.theme": "थीम", "account.other-settings.theme.antd.animations": "एनिमेशन: कुछ पहलुओं को संक्षेप में एनिमेट करें, जैसे बटन", "account.other-settings.theme.antd.color_scheme": "रंग योजना: डिफ़ॉल्ट रंगों के बजाय ब्रांड रंगों का उपयोग करें", "account.other-settings.theme.antd.compact": "कॉम्पैक्ट डिज़ाइन: अधिक कॉम्पैक्ट डिज़ाइन का उपयोग करें", @@ -128,6 +125,7 @@ "account.settings.overview.licenses": "सॉफ़्टवेयर लाइसेंस और एक्सेस अनुमतियाँ प्रबंधित करें।", "account.settings.overview.other": "विविध सेटिंग्स और विकल्प।", "account.settings.overview.payg": "पे-एज़-यू-गो उपयोग और बिलिंग को कॉन्फ़िगर करें।", + "account.settings.overview.payment_methods": "अपने सहेजे गए भुगतान विधियों का प्रबंधन करें या नई जोड़ें।", "account.settings.overview.payments": "भुगतान विधियों और लेनदेन इतिहास का प्रबंधन करें।", "account.settings.overview.profile": "अपने व्यक्तिगत जानकारी, अवतार और खाता विवरण प्रबंधित करें।", "account.settings.overview.purchases": "खरीद इतिहास और रसीदें देखें।", @@ -135,6 +133,7 @@ "account.settings.overview.subscriptions": "अपनी सक्रिय सदस्यताओं को देखें और प्रबंधित करें।", "account.settings.overview.support": "सहायता टिकट और सहायता संसाधनों तक पहुँचें।", "account.settings.overview.title": "सेटिंग्स अवलोकन", + "account.settings.overview.upgrades": "अपने पुराने कोटा उन्नयन प्रबंधित करें।", "account.settings.sso.account_is_linked": "आपका खाता जुड़ा हुआ है (अनलिंक करने के लिए क्लिक करें)", "account.settings.sso.link_your_account": "{is_anonymous, select, true {अपने खाते का उपयोग करके साइन अप करें} other {अपने खाते को लिंक करने के लिए क्लिक करें}}", "account.settings.unlisted.label": "सूचीबद्ध नहीं: आपको केवल एक सटीक ईमेल पता मिलान द्वारा पाया जा सकता है", @@ -155,6 +154,9 @@ "ai-generate-document.modal.title": "AI का उपयोग करके {docName} दस्तावेज़ उत्पन्न करें", "ai-generator.select_llm": "भाषा मॉडल चुनें", "app.fullscreen-button.tooltip": "पूर्ण स्क्रीन मोड, वर्तमान दस्तावेज़ या पृष्ठ पर केंद्रित।", + "app.hotkey.dialog.help_text": "ऊपर फ्रेम्स पर क्लिक करें • कुंजी 0 चैट टॉगल करती है • कुंजियाँ 1–9 फ्रेम्स पर फोकस करती हैं • खोजने के लिए टाइप करें • ↑↓ नेविगेट करें • खोलने के लिए रिटर्न दबाएं • बंद करने के लिए ESC दबाएं", + "app.hotkey.dialog.search_placeholder": "फ़ाइलें और पृष्ठ खोजें...", + "app.hotkey.dialog.title": "त्वरित नेविगेशन", "app.verify-email-banner.edit": "यदि ईमेल पता गलत है, कृपया इसे खाता सेटिंग्स में संपादित करें।", "app.verify-email-banner.help.text": "यह महत्वपूर्ण है कि आपके पास एक कार्यशील ईमेल पता हो। हम इसे पासवर्ड रीसेट, संदेश भेजने, बिलिंग सूचनाएं और सहायता के लिए उपयोग करते हैं। कृपया सूचित रहने के लिए सुनिश्चित करें कि आपका ईमेल सही है।", "app.verify-email-banner.text": "{sent, select, true {ईमेल भेजा गया! कृपया अपने ईमेल इनबॉक्स (और शायद स्पैम) की जाँच करें और पुष्टि लिंक पर क्लिक करें।} other {कृपया अपना ईमेल पता जाँचें और सत्यापित करें:}}", @@ -988,6 +990,7 @@ "labels.config": "कॉन्फ़िग", "labels.configuration": "कॉन्फ़िगरेशन", "labels.configuration.short": "कॉन्फ़िग", + "labels.connected": "कनेक्टेड", "labels.connecting": "कनेक्टिंग", "labels.connection": "कनेक्शन", "labels.copied": "कॉपी किया गया", @@ -1016,6 +1019,7 @@ "labels.environment": "पर्यावरण", "labels.explorer": "एक्सप्लोरर", "labels.file_explorer": "फ़ाइल एक्सप्लोरर", + "labels.file_use_notifications": "फ़ाइल उपयोग सूचनाएँ", "labels.files": "फ़ाइलें", "labels.folder": "फ़ोल्डर", "labels.frame-editors.title-bar.save_label": "{type, select, is_public {सार्वजनिक} read_only {केवल पढ़ने के लिए} other {सहेजें}}", @@ -1095,6 +1099,7 @@ "labels.project.settings.stop-project.label": "रुकें {short, select, true {} other { प्रोजेक्ट}}…", "labels.project.settings.stop-project.ok": "हाँ, प्रोजेक्ट बंद करें", "labels.projects": "प्रोजेक्ट्स", + "labels.public_paths": "सार्वजनिक पथ", "labels.published_files": "प्रकाशित फ़ाइलें", "labels.purchases": "खरीदें", "labels.ready": "तैयार", @@ -1423,7 +1428,6 @@ "projects.create-project.helpTxt": "शीर्षक चुनें। आप इसे बाद में आसानी से बदल सकते हैं!", "projects.create-project.requireLicense": "अतिरिक्त प्रोजेक्ट्स बनाने के लिए एक लाइसेंस आवश्यक है।", "projects.filename-search.placeholder": "संपादित की गई फ़ाइल नाम खोजें...", - "projects.list.no_starred_found": "कोई स्टार किए गए प्रोजेक्ट नहीं मिले। अपने पसंदीदा प्रोजेक्ट को बुकमार्क करने के लिए प्रोजेक्ट शीर्षकों के पास स्टार आइकन का उपयोग करें।", "projects.load-all.label": "सभी प्रोजेक्ट दिखाएँ...", "projects.operations.clear-filter": "फ़िल्टर साफ करें", "projects.operations.delete.button": "{deleted, select, true {सभी पुनःस्थापित करें} other {सभी हटाएं}}", @@ -1455,7 +1459,9 @@ "projects.table-controls.hashtags.placeholder": "हैशटैग द्वारा फ़िल्टर करें...", "projects.table-controls.hidden.label": "छिपा हुआ", "projects.table-controls.search.placeholder": "प्रोजेक्ट खोजें...", + "projects.table.keyboard-row-hint": "प्रोजेक्ट {title}. स्थानांतरित करने के लिए ऊपर और नीचे तीरों का उपयोग करें; खोलने के लिए Enter या Space दबाएं।", "projects.table.last-edited": "अंतिम संपादन", + "projects.table.untitled": "शीर्षकहीन", "purchases.automatic-payments-warning.description": "स्वचालित भुगतान बहुत अधिक सुविधाजनक हैं, आपका समय बचाएंगे, और सुनिश्चित करेंगे कि सदस्यताएँ गलती से रद्द न हों।", "purchases.automatic-payments-warning.title": "स्वत: भुगतान के लिए सदस्यता की आवश्यकता नहीं है", "purchases.automatic-payments.are-enabled": "स्वचालित भुगतान सक्षम हैं", diff --git a/src/packages/frontend/i18n/trans/hu_HU.json b/src/packages/frontend/i18n/trans/hu_HU.json index 196feacdd46..9fbbac33e5d 100644 --- a/src/packages/frontend/i18n/trans/hu_HU.json +++ b/src/packages/frontend/i18n/trans/hu_HU.json @@ -5,6 +5,8 @@ "account.account_page.translation.info.title": "Fordítási információk", "account.account-button.confirm.ok": "Igen, kijelentkezés", "account.account-button.confirm.title": "Kijelentkezik a fiókjából?", + "account.appearance.accessibility.enabled": "Akkorítsa el a hozzáférhetőség módot: optimalizálja a felhasználói felületet a hozzáférhetőségi funkciókhoz", + "account.appearance.accessibility.title": "Akadálymentesség", "account.appearance.user_interface.title": "Felhasználói felület", "account.delete-account.alert.description": "Azonnal elveszíti a hozzáférést az összes projektjéhez, minden előfizetés törlésre kerül, és minden el nem költött jóváírás elveszik. {br} {hr} A FIÓK TÖRLÉSÉHEZ először írja be az alábbi \"{required_text}\" szöveget:", "account.delete-account.alert.message": "Biztosan törölni akarja a FIÓKJÁT?", @@ -31,13 +33,11 @@ "account.editor-setting.checkbox.strip_trailing_whitespace": "távolítsa el, amikor a fájl mentésre kerül", "account.editor-settings-autosave-interval.label": "Automatikus mentés intervalluma", "account.editor-settings.basic.title": "Alapbeállítások", - "account.editor-settings.color-schemes.label": "Szerkesztő színséma", "account.editor-settings.color-schemes.panel_title": "Szerkesztő Színséma", "account.editor-settings.font-size.label": "Alapértelmezett globális betűméret", "account.editor-settings.indent-size.label": "Behúzás mérete", "account.editor-settings.keyboard-bindings.label": "Szerkesztő billentyűkötések", "account.editor-settings.keyboard.title": "Billentyűzet", - "account.editor-settings.title": "Szerkesztő", "account.editor-settings.x11-keyboard-variant.label": "Billentyűzet variáns (X11 asztali környezethez)", "account.editor-settings.x11-physical-keyboard.label": "Billentyűzetkiosztás (X11 asztalhoz)", "account.global-ssh-keys.help": "A projektbe való SSH belépéshez használja a következőt username@host: [project-id-without-dashes]@ssh.cocalc.com A kötőjelek nélküli projektazonosító az SSH kulcsok projektbeállításai részben található. Projektek közötti SSH-hoz használja [project-id-without-dashes]@ssh", @@ -66,13 +66,13 @@ "account.keyboard-shortcuts.shortcut.split-view-sagews": "Megosztott nézet Sage munkalapban", "account.keyboard-shortcuts.shortcut.toggle-comment": "Kommentár kijelölésének váltása", "account.other-settings._page_size.label": "Fájlok száma oldalanként", - "account.other-settings.browser_performance.title": "Böngésző", + "account.other-settings.auto_focus": "Automatikus fókusz a szövegbeviteli mezőkre: a szövegbeviteli mezők automatikus fókuszálása, amikor megjelennek (pl. fájlkezelő, projektek, ...)", "account.other-settings.button_tooltips": "Gombok tippjeinek elrejtése: elrejti néhány gomb tippjét (ez csak részleges)", "account.other-settings.confirm_close": "Zárás megerősítése: mindig kérjen megerősítést, mielőtt bezárja a böngészőablakot", - "account.other-settings.content_display.title": "Tartalom megjelenítés", "account.other-settings.default_file_sort.by_name": "Rendezés név szerint", "account.other-settings.default_file_sort.by_time": "Idő szerinti rendezés", "account.other-settings.default_file_sort.label": "Alapértelmezett fájlrendezés", + "account.other-settings.dim_file_extensions": "Fájl kiterjesztések elhalványítása: a fájl kiterjesztések szürkévé tétele, hogy a nevük kiemelkedjen.", "account.other-settings.file_popovers": "Fájltáb Popoverek Elrejtése: ne jelenítse meg a fájltábok feletti popovereket", "account.other-settings.filename_generator.description": "Válassza ki, hogyan generálódjanak automatikusan a fájlnevek. Különösen, hogy egyediek legyenek vagy tartalmazzák az aktuális időt.", "account.other-settings.filename_generator.label": "Fájlnév generátor", @@ -85,12 +85,9 @@ "account.other-settings.llm.title": "AI beállítások", "account.other-settings.markdown_codebar": "Tiltsa le a markdown kódsávot minden markdown dokumentumban. Ennek bejelölése elrejti a további futtatás, másolás és magyarázat gombokat a keretezett kódrészletekben.", "account.other-settings.mask_files": "Fájlok elrejtése: szürkítse el a fájlokat a fájlnézegetőben, amelyeket valószínűleg nem akar megnyitni", - "account.other-settings.messages.title": "Üzenetek", "account.other-settings.project_popovers": "Projektfülek felugróinak elrejtése: ne jelenítse meg a felugrókat a projektfülek felett", - "account.other-settings.projects.title": "Projektek", "account.other-settings.standby_timeout": "Készenléti időkorlát", "account.other-settings.symbol_bar_labels": "Szimbólumsáv címkéinek megjelenítése: címkék megjelenítése a keret szerkesztő szimbólumsávjában", - "account.other-settings.theme": "Téma", "account.other-settings.theme.antd.animations": "Animációk: röviden animálni néhány elemet, pl. gombokat", "account.other-settings.theme.antd.color_scheme": "Színséma: márka színek használata az alapértelmezett színek helyett", "account.other-settings.theme.antd.compact": "Kompakt Dizájn: használjon kompaktabb dizájnt", @@ -128,6 +125,7 @@ "account.settings.overview.licenses": "Kezelje a szoftverlicenceket és a hozzáférési engedélyeket.", "account.settings.overview.other": "Egyéb beállítások és opciók.", "account.settings.overview.payg": "Konfigurálja a használat és számlázás fizetés-alapú használatát.", + "account.settings.overview.payment_methods": "Kezelje a mentett fizetési módokat, vagy adjon hozzá újakat.", "account.settings.overview.payments": "Fizetési módok és tranzakciótörténet kezelése.", "account.settings.overview.profile": "Kezelje személyes adatait, avatarját és fiókadatait.", "account.settings.overview.purchases": "Tekintse meg a vásárlási előzményeket és a nyugtákat.", @@ -135,6 +133,7 @@ "account.settings.overview.subscriptions": "Tekintse meg és kezelje aktív előfizetéseit.", "account.settings.overview.support": "Hozzáférés támogatási jegyekhez és segítő forrásokhoz.", "account.settings.overview.title": "Beállítások áttekintése", + "account.settings.overview.upgrades": "Kezelje a régi kvótanöveléseit.", "account.settings.sso.account_is_linked": "Fiókja össze van kapcsolva (kattintson a szétkapcsoláshoz)", "account.settings.sso.link_your_account": "{is_anonymous, select, true {Regisztráljon fiókjával a} other {Kattintson fiókja összekapcsolásához}}", "account.settings.unlisted.label": "Nem nyilvános: csak pontos email cím egyezéssel található meg", @@ -155,6 +154,9 @@ "ai-generate-document.modal.title": "Hozzon létre egy {docName} dokumentumot mesterséges intelligencia segítségével", "ai-generator.select_llm": "Nyelvi modell kiválasztása", "app.fullscreen-button.tooltip": "Teljes képernyős mód, a jelenlegi dokumentumra vagy oldalra összpontosítva.", + "app.hotkey.dialog.help_text": "Kattintson a keretekre fent • A 0 gomb váltja a csevegést • Az 1–9 gombok a keretekre fókuszálnak • Gépeljen a kereséshez • ↑↓ navigálás • Enter a megnyitáshoz • ESC a bezáráshoz", + "app.hotkey.dialog.search_placeholder": "Fájlok és oldalak keresése...", + "app.hotkey.dialog.title": "Gyors navigáció", "app.verify-email-banner.edit": "Ha az e-mail cím helytelen, kérjük, szerkessze azt a fiókbeállításokban.", "app.verify-email-banner.help.text": "Fontos, hogy legyen működő e-mail címe. Jelszó-visszaállításhoz, üzenetek küldéséhez, számlázási értesítésekhez és támogatáshoz használjuk. Kérjük, győződjön meg róla, hogy az e-mail címe helyes, hogy tájékozott maradhasson.", "app.verify-email-banner.text": "{sent, select, true {Email elküldve! Kérjük, ellenőrizze az e-mail fiókját (és esetleg a spam mappát), és kattintson a megerősítő linkre.} other {Kérjük, ellenőrizze és igazolja az e-mail címét:}}", @@ -988,6 +990,7 @@ "labels.config": "Beállítás", "labels.configuration": "Konfiguráció", "labels.configuration.short": "Beállítás", + "labels.connected": "Csatlakoztatva", "labels.connecting": "Csatlakozás", "labels.connection": "Csatlakozás", "labels.copied": "másolva", @@ -1016,6 +1019,7 @@ "labels.environment": "Környezet", "labels.explorer": "Felfedező", "labels.file_explorer": "Fájlkezelő", + "labels.file_use_notifications": "Fájlhasználati értesítések", "labels.files": "Fájlok", "labels.folder": "mappa", "labels.frame-editors.title-bar.save_label": "{type, select, is_public {Nyilvános} read_only {Csak olvasható} other {Mentés}}", @@ -1095,6 +1099,7 @@ "labels.project.settings.stop-project.label": "Állítsa le{short, select, true {} other { Projekt}}…", "labels.project.settings.stop-project.ok": "Igen, állítsa le a projektet", "labels.projects": "Projektek", + "labels.public_paths": "Nyilvános útvonalak", "labels.published_files": "Közzétett fájlok", "labels.purchases": "Vásárlások", "labels.ready": "Kész", @@ -1423,7 +1428,6 @@ "projects.create-project.helpTxt": "Válasszon egy címet. Ezt később könnyedén megváltoztathatja!", "projects.create-project.requireLicense": "További projektek létrehozásához licenc szükséges.", "projects.filename-search.placeholder": "Keressen a szerkesztett fájlnevek között...", - "projects.list.no_starred_found": "Nincsenek csillagozott projektek. A projektcímek melletti csillag ikon használatával jelölheti meg a kedvenc projektjeit.", "projects.load-all.label": "Összes projekt megjelenítése...", "projects.operations.clear-filter": "Szűrő törlése", "projects.operations.delete.button": "{deleted, select, true {Összes visszaállítása} other {Összes törlése}}", @@ -1455,7 +1459,9 @@ "projects.table-controls.hashtags.placeholder": "Szűrés hashtagek alapján...", "projects.table-controls.hidden.label": "Rejtett", "projects.table-controls.search.placeholder": "Projektek keresése...", + "projects.table.keyboard-row-hint": "Projekt {title}. Használja a Fel és Le nyilakat a mozgatáshoz; nyomja meg az Enter vagy a Space gombot a megnyitáshoz.", "projects.table.last-edited": "Utoljára szerkesztve", + "projects.table.untitled": "Cím nélküli", "purchases.automatic-payments-warning.description": "Az automatikus fizetések sokkal kényelmesebbek, időt takarítanak meg, és biztosítják, hogy az előfizetések ne szűnjenek meg véletlenül.", "purchases.automatic-payments-warning.title": "Az automatikus fizetések NEM szükségesek előfizetéshez", "purchases.automatic-payments.are-enabled": "Az automatikus fizetések engedélyezve vannak", diff --git a/src/packages/frontend/i18n/trans/it_IT.json b/src/packages/frontend/i18n/trans/it_IT.json index 0d20a28b245..887b4059fe2 100644 --- a/src/packages/frontend/i18n/trans/it_IT.json +++ b/src/packages/frontend/i18n/trans/it_IT.json @@ -5,6 +5,8 @@ "account.account_page.translation.info.title": "Informazioni sulla traduzione", "account.account-button.confirm.ok": "Sì, esci", "account.account-button.confirm.title": "Esci dal tuo account?", + "account.appearance.accessibility.enabled": "Abilita Modalità Accessibilità: ottimizza l'interfaccia utente per le funzionalità di accessibilità", + "account.appearance.accessibility.title": "Accessibilità", "account.appearance.user_interface.title": "Interfaccia utente", "account.delete-account.alert.description": "Perderai immediatamente l'accesso a tutti i tuoi progetti, eventuali abbonamenti saranno annullati e tutto il credito non speso sarà perso. {br} {hr} Per CANCELLARE IL TUO ACCOUNT, inserisci prima \"{required_text}\" qui sotto:", "account.delete-account.alert.message": "Sei sicuro di voler ELIMINARE IL TUO ACCOUNT?", @@ -31,13 +33,11 @@ "account.editor-setting.checkbox.strip_trailing_whitespace": "rimuovi ogni volta che il file viene salvato", "account.editor-settings-autosave-interval.label": "Intervallo di salvataggio automatico", "account.editor-settings.basic.title": "Impostazioni di base", - "account.editor-settings.color-schemes.label": "Schema di colori dell'editor", "account.editor-settings.color-schemes.panel_title": "Schema di colori dell'editor", "account.editor-settings.font-size.label": "Dimensione predefinita del carattere globale", "account.editor-settings.indent-size.label": "Dimensione rientro", "account.editor-settings.keyboard-bindings.label": "Associazioni tastiera dell'editor", "account.editor-settings.keyboard.title": "Tastiera", - "account.editor-settings.title": "Editor", "account.editor-settings.x11-keyboard-variant.label": "Variante tastiera (per Desktop X11)", "account.editor-settings.x11-physical-keyboard.label": "Layout tastiera (per desktop X11)", "account.global-ssh-keys.help": "Per SSH in un progetto, usa il seguente username@host: [project-id-without-dashes]@ssh.cocalc.com L'id del progetto senza trattini può essere trovato nella parte delle impostazioni del progetto riguardante le chiavi SSH. Per SSH tra progetti, usa [project-id-without-dashes]@ssh", @@ -66,13 +66,13 @@ "account.keyboard-shortcuts.shortcut.split-view-sagews": "Visualizzazione divisa nel foglio di lavoro Sage", "account.keyboard-shortcuts.shortcut.toggle-comment": "Attiva/disattiva commento selezione", "account.other-settings._page_size.label": "Numero di file per pagina", - "account.other-settings.browser_performance.title": "Browser", + "account.other-settings.auto_focus": "Auto Focus Text Input: concentra automaticamente i campi di inserimento testo quando appaiono (ad esempio, esploratore di file, progetti, ...)", "account.other-settings.button_tooltips": "Nascondi suggerimenti dei pulsanti: nasconde alcuni suggerimenti dei pulsanti (questo è solo parziale)", "account.other-settings.confirm_close": "Conferma Chiusura: chiedi sempre conferma prima di chiudere la finestra del browser", - "account.other-settings.content_display.title": "Visualizzazione contenuti", "account.other-settings.default_file_sort.by_name": "Ordina per nome", "account.other-settings.default_file_sort.by_time": "Ordina per tempo", "account.other-settings.default_file_sort.label": "Ordinamento file predefinito", + "account.other-settings.dim_file_extensions": "Estensioni file opache: rendi opache le estensioni dei file in modo che i loro nomi risaltino.", "account.other-settings.file_popovers": "Nascondi Popup Schede File: non mostrare i popup sulle schede dei file", "account.other-settings.filename_generator.description": "Seleziona come vengono generati automaticamente i nomi dei file. In particolare, per renderli unici o includere l'ora attuale.", "account.other-settings.filename_generator.label": "Generatore di nomi file", @@ -85,12 +85,9 @@ "account.other-settings.llm.title": "Impostazioni AI", "account.other-settings.markdown_codebar": "Disabilita la barra del codice markdown in tutti i documenti markdown. Se selezionato, questo nasconde i pulsanti aggiuntivi di esecuzione, copia e spiegazione nei blocchi di codice recintati.", "account.other-settings.mask_files": "Maschera file: disattiva i file nel visualizzatore di file che probabilmente non vuoi aprire", - "account.other-settings.messages.title": "Messaggi", "account.other-settings.project_popovers": "Nascondi i Popover delle Schede del Progetto: non mostrare i popover sulle schede del progetto", - "account.other-settings.projects.title": "Progetti", "account.other-settings.standby_timeout": "Timeout di attesa", "account.other-settings.symbol_bar_labels": "Mostra etichette barra simboli: mostra etichette nella barra simboli dell'editor di frame", - "account.other-settings.theme": "Tema", "account.other-settings.theme.antd.animations": "Animazioni: animare brevemente alcuni aspetti, ad es. pulsanti", "account.other-settings.theme.antd.color_scheme": "Schema Colori: usa i colori del marchio invece dei colori predefiniti", "account.other-settings.theme.antd.compact": "Design compatto: usa un design più compatto", @@ -128,6 +125,7 @@ "account.settings.overview.licenses": "Gestisci le licenze software e i permessi di accesso.", "account.settings.overview.other": "Impostazioni e opzioni varie.", "account.settings.overview.payg": "Configura l'uso a consumo e la fatturazione.", + "account.settings.overview.payment_methods": "Gestisci i tuoi metodi di pagamento salvati o aggiungine di nuovi.", "account.settings.overview.payments": "Gestisci i metodi di pagamento e la cronologia delle transazioni.", "account.settings.overview.profile": "Gestisci le tue informazioni personali, avatar e dettagli dell'account.", "account.settings.overview.purchases": "Visualizza la cronologia degli acquisti e le ricevute.", @@ -135,6 +133,7 @@ "account.settings.overview.subscriptions": "Visualizza e gestisci i tuoi abbonamenti attivi.", "account.settings.overview.support": "Accedi ai ticket di supporto e alle risorse di aiuto.", "account.settings.overview.title": "Panoramica delle Impostazioni", + "account.settings.overview.upgrades": "Gestisci i tuoi aggiornamenti di quota legacy.", "account.settings.sso.account_is_linked": "Il tuo account è collegato con (clicca per scollegare)", "account.settings.sso.link_your_account": "{is_anonymous, select, true {Iscriviti utilizzando il tuo account su} other {Clicca per collegare il tuo account}}", "account.settings.unlisted.label": "Non in elenco: puoi essere trovato solo con una corrispondenza esatta dell'indirizzo email", @@ -155,6 +154,9 @@ "ai-generate-document.modal.title": "Genera un documento {docName} utilizzando l'IA", "ai-generator.select_llm": "Seleziona modello linguistico", "app.fullscreen-button.tooltip": "Modalità a schermo intero, focalizzata sul documento o pagina corrente", + "app.hotkey.dialog.help_text": "Clicca sui frame sopra • Tasto 0 attiva/disattiva chat • Tasti 1–9 mettono a fuoco i frame • Digita per cercare • ↑↓ naviga • Invio per aprire • ESC per chiudere", + "app.hotkey.dialog.search_placeholder": "Cerca file e pagine...", + "app.hotkey.dialog.title": "Navigazione Rapida", "app.verify-email-banner.edit": "Se l'indirizzo email è sbagliato, per favore modificalo nelle impostazioni dell'account.", "app.verify-email-banner.help.text": "È importante avere un indirizzo email funzionante. Lo utilizziamo per reimpostare le password, inviare messaggi, notifiche di fatturazione e supporto. Assicurati che la tua email sia corretta per rimanere informato.", "app.verify-email-banner.text": "{sent, select, true {Email inviata! Controlla la tua casella di posta elettronica (e magari spam) e clicca sul link di conferma.} other {Per favore controlla e verifica il tuo indirizzo email:}}", @@ -988,6 +990,7 @@ "labels.config": "Configura", "labels.configuration": "Configurazione", "labels.configuration.short": "Configura", + "labels.connected": "Connesso", "labels.connecting": "Connessione", "labels.connection": "Connessione", "labels.copied": "copiato", @@ -1016,6 +1019,7 @@ "labels.environment": "Ambiente", "labels.explorer": "Esploratore", "labels.file_explorer": "Esplora File", + "labels.file_use_notifications": "Notifiche di utilizzo file", "labels.files": "File", "labels.folder": "cartella", "labels.frame-editors.title-bar.save_label": "{type, select, is_public {Pubblico} read_only {Sola lettura} other {Salva}}", @@ -1095,6 +1099,7 @@ "labels.project.settings.stop-project.label": "Stop{short, select, true {} other { Progetto}}…", "labels.project.settings.stop-project.ok": "Sì, ferma progetto", "labels.projects": "Progetti", + "labels.public_paths": "Percorsi Pubblici", "labels.published_files": "File Pubblicati", "labels.purchases": "Acquisti", "labels.ready": "Pronto", @@ -1423,7 +1428,6 @@ "projects.create-project.helpTxt": "Scegli un titolo. Puoi cambiarlo facilmente in seguito!", "projects.create-project.requireLicense": "È necessaria una licenza per creare progetti aggiuntivi.", "projects.filename-search.placeholder": "Cerca i nomi dei file che hai modificato...", - "projects.list.no_starred_found": "Nessun progetto con stella trovato. Usa l'icona a stella accanto ai titoli dei progetti per aggiungere ai segnalibri i tuoi progetti preferiti.", "projects.load-all.label": "Mostra tutti i progetti...", "projects.operations.clear-filter": "Cancella filtro", "projects.operations.delete.button": "{deleted, select, true {Ripristina Tutto} other {Elimina Tutto}}", @@ -1455,7 +1459,9 @@ "projects.table-controls.hashtags.placeholder": "Filtra per hashtag...", "projects.table-controls.hidden.label": "Nascosto", "projects.table-controls.search.placeholder": "Cerca progetti...", + "projects.table.keyboard-row-hint": "Progetto {title}. Usa le frecce Su e Giù per spostarti; premi Invio o Spazio per aprire.", "projects.table.last-edited": "Ultima modifica", + "projects.table.untitled": "Senza titolo", "purchases.automatic-payments-warning.description": "I pagamenti automatici sono molto più convenienti, ti fanno risparmiare tempo e assicurano che gli abbonamenti non vengano annullati per errore.", "purchases.automatic-payments-warning.title": "I pagamenti automatici NON sono necessari per avere un abbonamento", "purchases.automatic-payments.are-enabled": "I pagamenti automatici sono abilitati", diff --git a/src/packages/frontend/i18n/trans/ja_JP.json b/src/packages/frontend/i18n/trans/ja_JP.json index 97112dca3e3..432dbee4339 100644 --- a/src/packages/frontend/i18n/trans/ja_JP.json +++ b/src/packages/frontend/i18n/trans/ja_JP.json @@ -5,6 +5,8 @@ "account.account_page.translation.info.title": "翻訳情報", "account.account-button.confirm.ok": "はい、サインアウト", "account.account-button.confirm.title": "アカウントからサインアウトしますか?", + "account.appearance.accessibility.enabled": "アクセシビリティモードを有効化:アクセシビリティ機能に合わせてユーザーインターフェースを最適化", + "account.appearance.accessibility.title": "アクセシビリティ", "account.appearance.user_interface.title": "ユーザーインターフェース", "account.delete-account.alert.description": "すぐにすべてのプロジェクトへのアクセスを失い、すべてのサブスクリプションがキャンセルされ、未使用のクレジットはすべて失われます。{br} {hr} アカウントを削除するには、まず下に「{required_text}」を入力してください。", "account.delete-account.alert.message": "本当にアカウントを削除しますか?", @@ -31,13 +33,11 @@ "account.editor-setting.checkbox.strip_trailing_whitespace": "ファイルが保存されるたびに削除", "account.editor-settings-autosave-interval.label": "自動保存間隔", "account.editor-settings.basic.title": "基本設定", - "account.editor-settings.color-schemes.label": "エディターのカラースキーム", "account.editor-settings.color-schemes.panel_title": "エディターのカラースキーム", "account.editor-settings.font-size.label": "デフォルトのグローバルフォントサイズ", "account.editor-settings.indent-size.label": "インデントサイズ", "account.editor-settings.keyboard-bindings.label": "エディターのキーボードバインディング", "account.editor-settings.keyboard.title": "キーボード", - "account.editor-settings.title": "エディター", "account.editor-settings.x11-keyboard-variant.label": "X11デスクトップ用のキーボードバリアント", "account.editor-settings.x11-physical-keyboard.label": "キーボードレイアウト(X11デスクトップ用)", "account.global-ssh-keys.help": "プロジェクトにSSHするには、次のusername@host: [project-id-without-dashes]@ssh.cocalc.comを使用します。ダッシュのないプロジェクトIDは、SSHキーに関するプロジェクト設定の部分で見つけることができます。プロジェクト間でSSHするには、[project-id-without-dashes]@sshを使用します。", @@ -66,13 +66,13 @@ "account.keyboard-shortcuts.shortcut.split-view-sagews": "Sageワークシートで分割表示", "account.keyboard-shortcuts.shortcut.toggle-comment": "選択範囲のコメントを切り替え", "account.other-settings._page_size.label": "1ページあたりのファイル数", - "account.other-settings.browser_performance.title": "ブラウザー", + "account.other-settings.auto_focus": "自動フォーカステキスト入力: テキスト入力フィールドが表示されたときに自動的にフォーカスする (例: ファイルエクスプローラー、プロジェクト、...)", "account.other-settings.button_tooltips": "ボタンのツールチップを非表示: 一部のボタンのツールチップを非表示にします(これは部分的です)", "account.other-settings.confirm_close": "閉じる確認: ブラウザーウィンドウを閉じる前に必ず確認を求める", - "account.other-settings.content_display.title": "コンテンツ表示", "account.other-settings.default_file_sort.by_name": "名前で並べ替え", "account.other-settings.default_file_sort.by_time": "時間順に並べ替え", "account.other-settings.default_file_sort.label": "デフォルトファイルソート", + "account.other-settings.dim_file_extensions": "ファイル拡張子を薄く表示: ファイル名が目立つようにファイル拡張子をグレーアウトします。", "account.other-settings.file_popovers": "ファイルタブポップオーバーを非表示: ファイルタブ上にポップオーバーを表示しない", "account.other-settings.filename_generator.description": "自動生成されるファイル名の生成方法を選択します。特に、それらをユニークにするか、現在の時間を含めるかを選択します。", "account.other-settings.filename_generator.label": "ファイル名ジェネレーター", @@ -85,12 +85,9 @@ "account.other-settings.llm.title": "AI設定", "account.other-settings.markdown_codebar": "すべてのMarkdown文書でMarkdownコードバーを無効化します。これをチェックすると、囲まれたコードブロック内の追加の実行、コピー、説明ボタンが非表示になります。", "account.other-settings.mask_files": "マスクファイル: 開きたくないファイルをファイルビューアでグレーアウト", - "account.other-settings.messages.title": "メッセージ", "account.other-settings.project_popovers": "プロジェクトタブのポップオーバーを非表示: プロジェクトタブ上のポップオーバーを表示しない", - "account.other-settings.projects.title": "プロジェクト", "account.other-settings.standby_timeout": "待機タイムアウト", "account.other-settings.symbol_bar_labels": "シンボルバーラベルを表示:フレームエディタのシンボルバーにラベルを表示", - "account.other-settings.theme": "テーマ", "account.other-settings.theme.antd.animations": "アニメーション: ボタンなどの要素を簡潔にアニメーション化", "account.other-settings.theme.antd.color_scheme": "カラー スキーム: デフォルトの色ではなくブランドの色を使用", "account.other-settings.theme.antd.compact": "コンパクトデザイン: よりコンパクトなデザインを使用", @@ -128,6 +125,7 @@ "account.settings.overview.licenses": "ソフトウェアライセンスとアクセス権限を管理する。", "account.settings.overview.other": "その他の設定とオプション", "account.settings.overview.payg": "従量課金の使用と請求を設定する。", + "account.settings.overview.payment_methods": "保存された支払い方法を管理するか、新しいものを追加します。", "account.settings.overview.payments": "支払い方法と取引履歴を管理します。", "account.settings.overview.profile": "個人情報、アバター、アカウント詳細を管理します。", "account.settings.overview.purchases": "購入履歴と領収書を表示。", @@ -135,6 +133,7 @@ "account.settings.overview.subscriptions": "アクティブなサブスクリプションを表示および管理します。", "account.settings.overview.support": "サポートチケットとヘルプリソースにアクセスする。", "account.settings.overview.title": "設定概要", + "account.settings.overview.upgrades": "レガシークォータのアップグレードを管理します。", "account.settings.sso.account_is_linked": "あなたのアカウントはリンクされています(クリックしてリンクを解除)", "account.settings.sso.link_your_account": "{is_anonymous, select, true {アカウントでサインアップ} other {アカウントをリンクするにはクリック}}", "account.settings.unlisted.label": "非公開:正確なメールアドレスの一致でのみ見つけられます", @@ -155,6 +154,9 @@ "ai-generate-document.modal.title": "AIを使用して{docName}ドキュメントを生成", "ai-generator.select_llm": "言語モデルを選択", "app.fullscreen-button.tooltip": "全画面モード、現在のドキュメントまたはページに集中。", + "app.hotkey.dialog.help_text": "上のフレームをクリック • キー0でチャットを切り替え • キー1–9でフレームにフォーカス • 検索するには入力 • ↑↓でナビゲート • Enterで開く • ESCで閉じる", + "app.hotkey.dialog.search_placeholder": "ファイルとページを検索...", + "app.hotkey.dialog.title": "クイックナビゲーション", "app.verify-email-banner.edit": "メールアドレスが間違っている場合は、アカウント設定で編集してください。", "app.verify-email-banner.help.text": "作業可能なメールアドレスを持つことが重要です。パスワードのリセット、メッセージの送信、請求通知、サポートのために使用します。情報を受け取るために、メールアドレスが正しいことを確認してください。", "app.verify-email-banner.text": "{sent, select, true {メールが送信されました!メールの受信トレイ(場合によってはスパムフォルダ)を確認し、確認リンクをクリックしてください。} other {メールアドレスを確認してください:}}", @@ -988,6 +990,7 @@ "labels.config": "設定", "labels.configuration": "設定", "labels.configuration.short": "設定", + "labels.connected": "接続済み", "labels.connecting": "接続中", "labels.connection": "接続", "labels.copied": "コピー済み", @@ -1016,6 +1019,7 @@ "labels.environment": "環境", "labels.explorer": "書類", "labels.file_explorer": "ファイルエクスプローラー", + "labels.file_use_notifications": "ファイル使用通知", "labels.files": "ファイル", "labels.folder": "フォルダー", "labels.frame-editors.title-bar.save_label": "{type, select, is_public {公開} read_only {読み取り専用} other {保存}}", @@ -1095,6 +1099,7 @@ "labels.project.settings.stop-project.label": "停止{short, select, true {} other {プロジェクト}}…", "labels.project.settings.stop-project.ok": "はい、プロジェクトを停止", "labels.projects": "プロジェクト", + "labels.public_paths": "公開パス", "labels.published_files": "公開されたファイル", "labels.purchases": "購入", "labels.ready": "準備完了", @@ -1423,7 +1428,6 @@ "projects.create-project.helpTxt": "タイトルを選んでください。後で簡単に変更できます!", "projects.create-project.requireLicense": "追加のプロジェクトを作成するにはライセンスが必要です。", "projects.filename-search.placeholder": "編集したファイル名を検索...", - "projects.list.no_starred_found": "スター付きのプロジェクトが見つかりませんでした。お気に入りのプロジェクトをブックマークするには、プロジェクトタイトルの横にある星アイコンを使用してください。", "projects.load-all.label": "すべてのプロジェクトを表示...", "projects.operations.clear-filter": "フィルターをクリア", "projects.operations.delete.button": "{deleted, select, true {すべてを復元} other {すべてを削除}}", @@ -1455,7 +1459,9 @@ "projects.table-controls.hashtags.placeholder": "ハッシュタグでフィルター...", "projects.table-controls.hidden.label": "非表示", "projects.table-controls.search.placeholder": "プロジェクトを検索...", + "projects.table.keyboard-row-hint": "プロジェクト {title}。上下矢印キーで移動し、EnterキーまたはSpaceキーで開く。", "projects.table.last-edited": "最終編集", + "projects.table.untitled": "無題", "purchases.automatic-payments-warning.description": "自動支払いはずっと便利で、時間を節約し、サブスクリプションが誤ってキャンセルされないようにします。", "purchases.automatic-payments-warning.title": "自動支払いはサブスクリプションに必要ありません", "purchases.automatic-payments.are-enabled": "自動支払いが有効です", diff --git a/src/packages/frontend/i18n/trans/ko_KR.json b/src/packages/frontend/i18n/trans/ko_KR.json index 1234fd4c23d..8af44511097 100644 --- a/src/packages/frontend/i18n/trans/ko_KR.json +++ b/src/packages/frontend/i18n/trans/ko_KR.json @@ -5,6 +5,8 @@ "account.account_page.translation.info.title": "번역 정보", "account.account-button.confirm.ok": "예, 로그아웃", "account.account-button.confirm.title": "계정에서 로그아웃하시겠습니까?", + "account.appearance.accessibility.enabled": "접근성 모드 활성화: 접근성 기능에 맞춰 사용자 인터페이스 최적화", + "account.appearance.accessibility.title": "접근성", "account.appearance.user_interface.title": "사용자 인터페이스", "account.delete-account.alert.description": "즉시 모든 프로젝트에 대한 접근 권한을 잃게 되며, 모든 구독이 취소되고 사용하지 않은 크레딧이 모두 소멸됩니다. {br} {hr} 계정을 삭제하려면 먼저 아래에 \"{required_text}\"를 입력하십시오:", "account.delete-account.alert.message": "계정을 삭제하시겠습니까?", @@ -31,13 +33,11 @@ "account.editor-setting.checkbox.strip_trailing_whitespace": "파일이 저장될 때마다 제거", "account.editor-settings-autosave-interval.label": "자동 저장 간격", "account.editor-settings.basic.title": "기본 설정", - "account.editor-settings.color-schemes.label": "편집기 색상 테마", "account.editor-settings.color-schemes.panel_title": "편집기 색상 테마", "account.editor-settings.font-size.label": "기본 전역 글꼴 크기", "account.editor-settings.indent-size.label": "들여쓰기 크기", "account.editor-settings.keyboard-bindings.label": "편집기 키보드 바인딩", "account.editor-settings.keyboard.title": "키보드", - "account.editor-settings.title": "에디터", "account.editor-settings.x11-keyboard-variant.label": "키보드 변형 (X11 데스크탑용)", "account.editor-settings.x11-physical-keyboard.label": "키보드 레이아웃 (X11 데스크탑용)", "account.global-ssh-keys.help": "프로젝트에 SSH 접속을 하려면 다음을 사용하세요 username@host: [project-id-without-dashes]@ssh.cocalc.com 대시 없이 프로젝트 ID는 SSH 키와 관련된 프로젝트 설정 부분에서 찾을 수 있습니다. 프로젝트 간에 SSH 접속을 하려면 [project-id-without-dashes]@ssh를 사용하세요.", @@ -66,13 +66,13 @@ "account.keyboard-shortcuts.shortcut.split-view-sagews": "Sage 워크시트에서 분할 보기", "account.keyboard-shortcuts.shortcut.toggle-comment": "선택 주석 전환", "account.other-settings._page_size.label": "페이지당 파일 수", - "account.other-settings.browser_performance.title": "브라우저", + "account.other-settings.auto_focus": "자동 포커스 텍스트 입력: 텍스트 입력 필드가 나타날 때 자동으로 포커스 (예: 파일 탐색기, 프로젝트, ...)", "account.other-settings.button_tooltips": "버튼 툴팁 숨기기: 일부 버튼 툴팁 숨기기 (부분적으로만 적용됨)", "account.other-settings.confirm_close": "종료 확인: 브라우저 창을 닫기 전에 항상 확인 요청", - "account.other-settings.content_display.title": "콘텐츠 표시", "account.other-settings.default_file_sort.by_name": "이름으로 정렬", "account.other-settings.default_file_sort.by_time": "시간순 정렬", "account.other-settings.default_file_sort.label": "기본 파일 정렬", + "account.other-settings.dim_file_extensions": "파일 확장자 흐리게: 파일 이름이 돋보이도록 확장자를 회색으로 표시합니다.", "account.other-settings.file_popovers": "파일 탭 팝오버 숨기기: 파일 탭 위에 팝오버를 표시하지 않음", "account.other-settings.filename_generator.description": "자동 생성된 파일 이름이 생성되는 방식을 선택하십시오. 특히, 고유하게 만들거나 현재 시간을 포함하도록 선택하십시오.", "account.other-settings.filename_generator.label": "파일명 생성기", @@ -85,12 +85,9 @@ "account.other-settings.llm.title": "AI 설정", "account.other-settings.markdown_codebar": "모든 마크다운 문서에서 마크다운 코드 바 비활성화. 이 옵션을 선택하면 코드 블록의 실행, 복사 및 설명 버튼이 숨겨집니다.", "account.other-settings.mask_files": "파일 숨기기: 파일 뷰어에서 열고 싶지 않은 파일을 회색으로 표시", - "account.other-settings.messages.title": "메시지", "account.other-settings.project_popovers": "프로젝트 탭 팝오버 숨기기: 프로젝트 탭 위에 팝오버를 표시하지 않음", - "account.other-settings.projects.title": "프로젝트", "account.other-settings.standby_timeout": "대기 시간 초과", "account.other-settings.symbol_bar_labels": "기호 막대 레이블 표시: 프레임 편집기 기호 막대에 레이블 표시", - "account.other-settings.theme": "테마", "account.other-settings.theme.antd.animations": "애니메이션: 버튼과 같은 일부 측면을 간단히 애니메이션화합니다", "account.other-settings.theme.antd.color_scheme": "색상 테마: 기본 색상 대신 브랜드 색상 사용", "account.other-settings.theme.antd.compact": "간결한 디자인: 더 간결한 디자인 사용", @@ -128,6 +125,7 @@ "account.settings.overview.licenses": "소프트웨어 라이선스 및 접근 권한 관리.", "account.settings.overview.other": "기타 설정 및 옵션.", "account.settings.overview.payg": "사용량 기반 결제 및 청구 설정.", + "account.settings.overview.payment_methods": "저장된 결제 수단을 관리하거나 새 결제 수단을 추가하세요.", "account.settings.overview.payments": "결제 방법 및 거래 내역 관리.", "account.settings.overview.profile": "개인 정보, 아바타 및 계정 세부 정보를 관리하세요.", "account.settings.overview.purchases": "구매 내역 및 영수증 보기.", @@ -135,6 +133,7 @@ "account.settings.overview.subscriptions": "활성 구독을 보고 관리하세요.", "account.settings.overview.support": "지원 티켓 및 도움말 리소스에 액세스하십시오.", "account.settings.overview.title": "설정 개요", + "account.settings.overview.upgrades": "레거시 할당량 업그레이드를 관리하세요.", "account.settings.sso.account_is_linked": "귀하의 계정이 연결되었습니다 (클릭하여 연결 해제)", "account.settings.sso.link_your_account": "{is_anonymous, select, true {계정으로 가입하기} other {계정을 연결하려면 클릭하세요}}", "account.settings.unlisted.label": "비공개: 정확한 이메일 주소로만 찾을 수 있습니다", @@ -155,6 +154,9 @@ "ai-generate-document.modal.title": "AI를 사용하여 {docName} 문서 생성", "ai-generator.select_llm": "언어 모델 선택", "app.fullscreen-button.tooltip": "풀스크린 모드, 현재 문서나 페이지에 집중.", + "app.hotkey.dialog.help_text": "위의 프레임을 클릭 • 0 키로 채팅 전환 • 1–9 키로 프레임 선택 • 검색하려면 입력 • ↑↓ 탐색 • Return으로 열기 • ESC로 닫기", + "app.hotkey.dialog.search_placeholder": "파일 및 페이지 검색...", + "app.hotkey.dialog.title": "빠른 탐색", "app.verify-email-banner.edit": "이메일 주소가 잘못된 경우 계정 설정에서 편집하십시오.", "app.verify-email-banner.help.text": "작동하는 이메일 주소를 가지고 있는 것이 중요합니다. 우리는 비밀번호 재설정, 메시지 전송, 청구 알림 및 지원을 위해 이메일을 사용합니다. 정보를 받으려면 이메일이 올바른지 확인하세요.", "app.verify-email-banner.text": "{sent, select, true {이메일이 전송되었습니다! 이메일 받은 편지함(그리고 스팸 폴더도)에서 확인하고 확인 링크를 클릭하세요.} other {이메일 주소를 확인하고 인증해 주세요:}}", @@ -988,6 +990,7 @@ "labels.config": "구성", "labels.configuration": "구성", "labels.configuration.short": "구성", + "labels.connected": "연결됨", "labels.connecting": "연결 중", "labels.connection": "연결", "labels.copied": "복사됨", @@ -1016,6 +1019,7 @@ "labels.environment": "환경", "labels.explorer": "탐색기", "labels.file_explorer": "파일 탐색기", + "labels.file_use_notifications": "파일 사용 알림", "labels.files": "파일", "labels.folder": "폴더", "labels.frame-editors.title-bar.save_label": "{type, select, is_public {공개} read_only {읽기 전용} other {저장}}", @@ -1095,6 +1099,7 @@ "labels.project.settings.stop-project.label": "중지{short, select, true {} other { 프로젝트}}…", "labels.project.settings.stop-project.ok": "예, 프로젝트 중지", "labels.projects": "프로젝트", + "labels.public_paths": "공개 경로", "labels.published_files": "게시된 파일", "labels.purchases": "구매", "labels.ready": "준비됨", @@ -1423,7 +1428,6 @@ "projects.create-project.helpTxt": "제목을 선택하세요. 나중에 쉽게 변경할 수 있습니다!", "projects.create-project.requireLicense": "추가 프로젝트를 만들려면 라이선스가 필요합니다.", "projects.filename-search.placeholder": "편집한 파일 이름 검색...", - "projects.list.no_starred_found": "별표가 있는 프로젝트를 찾을 수 없습니다. 프로젝트 제목 옆의 별 아이콘을 사용하여 즐겨찾는 프로젝트를 북마크하세요.", "projects.load-all.label": "모든 프로젝트 보기...", "projects.operations.clear-filter": "필터 지우기", "projects.operations.delete.button": "{deleted, select, true {모두 복구} other {모두 삭제}}", @@ -1455,7 +1459,9 @@ "projects.table-controls.hashtags.placeholder": "해시태그로 필터링...", "projects.table-controls.hidden.label": "숨김", "projects.table-controls.search.placeholder": "프로젝트 검색...", + "projects.table.keyboard-row-hint": "프로젝트 {title}. 이동하려면 위아래 화살표를 사용하고, 열려면 Enter 또는 Space 키를 누르세요.", "projects.table.last-edited": "마지막 편집", + "projects.table.untitled": "제목 없음", "purchases.automatic-payments-warning.description": "자동 결제는 훨씬 더 편리하고, 시간을 절약하며, 구독이 실수로 취소되지 않도록 보장합니다.", "purchases.automatic-payments-warning.title": "자동 결제는 구독에 필수적이지 않습니다", "purchases.automatic-payments.are-enabled": "자동 결제가 활성화되었습니다", diff --git a/src/packages/frontend/i18n/trans/nl_NL.json b/src/packages/frontend/i18n/trans/nl_NL.json index 8ddfd4b7b54..d9f0c91992c 100644 --- a/src/packages/frontend/i18n/trans/nl_NL.json +++ b/src/packages/frontend/i18n/trans/nl_NL.json @@ -5,6 +5,8 @@ "account.account_page.translation.info.title": "Vertaalinformatie", "account.account-button.confirm.ok": "Ja, afmelden", "account.account-button.confirm.title": "Afmelden van uw account?", + "account.appearance.accessibility.enabled": "Toegankelijkheidsmodus inschakelen: optimaliseer de gebruikersinterface voor toegankelijkheidsfuncties", + "account.appearance.accessibility.title": "Toegankelijkheid", "account.appearance.user_interface.title": "Gebruikersinterface", "account.delete-account.alert.description": "U verliest onmiddellijk toegang tot al uw projecten, eventuele abonnementen worden geannuleerd en al het ongebruikte tegoed gaat verloren. {br} {hr} Om UW ACCOUNT TE VERWIJDEREN, voert u eerst hieronder \"{required_text}\" in:", "account.delete-account.alert.message": "Weet u zeker dat u UW ACCOUNT WILT VERWIJDEREN?", @@ -31,13 +33,11 @@ "account.editor-setting.checkbox.strip_trailing_whitespace": "verwijderen wanneer bestand wordt opgeslagen", "account.editor-settings-autosave-interval.label": "Automatisch opslaan interval", "account.editor-settings.basic.title": "Basisinstellingen", - "account.editor-settings.color-schemes.label": "Editor kleurenschema", "account.editor-settings.color-schemes.panel_title": "Editor Kleurschema", "account.editor-settings.font-size.label": "Standaard globale lettergrootte", "account.editor-settings.indent-size.label": "Inspringingsgrootte", "account.editor-settings.keyboard-bindings.label": "Editor-toetsenbordkoppelingen", "account.editor-settings.keyboard.title": "Toetsenbord", - "account.editor-settings.title": "Editorinstellingen", "account.editor-settings.x11-keyboard-variant.label": "Toetsenbordvariant (voor X11 Desktop)", "account.editor-settings.x11-physical-keyboard.label": "Toetsenbordindeling (voor X11 Desktop)", "account.global-ssh-keys.help": "Om SSH in een project te gebruiken, gebruik de volgende gebruikersnaam@host: [project-id-zonder-streepjes]@ssh.cocalc.com De project-id zonder streepjes is te vinden in het gedeelte van de projectinstellingen over SSH-sleutels. Om SSH tussen projecten te gebruiken, gebruik [project-id-zonder-streepjes]@ssh", @@ -66,13 +66,13 @@ "account.keyboard-shortcuts.shortcut.split-view-sagews": "Gesplitste weergave in Sage-werkblad", "account.keyboard-shortcuts.shortcut.toggle-comment": "Selectie van commentaar voorzien/ongedaan maken", "account.other-settings._page_size.label": "Aantal bestanden per pagina", - "account.other-settings.browser_performance.title": "Browser", + "account.other-settings.auto_focus": "Auto Focus Tekstinvoer: tekstinvoervelden automatisch focussen wanneer ze verschijnen (bijv. bestandsverkenner, projecten, ...)", "account.other-settings.button_tooltips": "Verberg knopinfo: verbergt enkele knopinfo (dit is slechts gedeeltelijk)", "account.other-settings.confirm_close": "Bevestig Sluiten: altijd om bevestiging vragen voordat het browservenster wordt gesloten", - "account.other-settings.content_display.title": "Inhoudweergave", "account.other-settings.default_file_sort.by_name": "Sorteren op naam", "account.other-settings.default_file_sort.by_time": "Sorteren op tijd", "account.other-settings.default_file_sort.label": "Standaard bestandssortering", + "account.other-settings.dim_file_extensions": "Bestandsextensies dempen: bestandsextensies grijs maken zodat hun namen opvallen.", "account.other-settings.file_popovers": "Bestandstab-Popovers verbergen: toon de popovers over bestandstabs niet", "account.other-settings.filename_generator.description": "Selecteer hoe automatisch gegenereerde bestandsnamen worden gegenereerd. Met name om ze uniek te maken of de huidige tijd op te nemen.", "account.other-settings.filename_generator.label": "Bestandsnaam generator", @@ -85,12 +85,9 @@ "account.other-settings.llm.title": "AI-instellingen", "account.other-settings.markdown_codebar": "Deactiveer de markdown codebalk in alle markdown-documenten. Als u dit aanvinkt, worden de extra uitvoer-, kopieer- en uitlegknoppen in omkaderde codeblokken verborgen.", "account.other-settings.mask_files": "Masker bestanden: grijs bestanden uit in de bestandsweergave die je waarschijnlijk niet wilt openen", - "account.other-settings.messages.title": "Berichten", "account.other-settings.project_popovers": "Verberg Projecttabblad Popovers: toon de popovers niet boven de projecttabbladen", - "account.other-settings.projects.title": "Projecten", "account.other-settings.standby_timeout": "Standby-timeout", "account.other-settings.symbol_bar_labels": "Toon Symbolenbalk Labels: toon labels in de frame-editor symbolenbalk", - "account.other-settings.theme": "Thema", "account.other-settings.theme.antd.animations": "Animaties: kort sommige aspecten animeren, bijv. knoppen", "account.other-settings.theme.antd.color_scheme": "Kleurschema: gebruik merkkleuren in plaats van standaardkleuren", "account.other-settings.theme.antd.compact": "Compact Design: gebruik een compacter ontwerp", @@ -128,6 +125,7 @@ "account.settings.overview.licenses": "Beheer softwarelicenties en toegangsrechten.", "account.settings.overview.other": "Diverse instellingen en opties.", "account.settings.overview.payg": "Configureer gebruik en facturering op basis van verbruik.", + "account.settings.overview.payment_methods": "Beheer uw opgeslagen betaalmethoden of voeg nieuwe toe.", "account.settings.overview.payments": "Beheer betaalmethoden en transactiegeschiedenis.", "account.settings.overview.profile": "Beheer uw persoonlijke informatie, avatar en accountgegevens.", "account.settings.overview.purchases": "Bekijk aankoopgeschiedenis en bonnen.", @@ -135,6 +133,7 @@ "account.settings.overview.subscriptions": "Bekijk en beheer uw actieve abonnementen.", "account.settings.overview.support": "Toegangs ondersteuningsverzoeken en hulpbronnen.", "account.settings.overview.title": "Instellingenoverzicht", + "account.settings.overview.upgrades": "Beheer uw verouderde quotum-upgrades.", "account.settings.sso.account_is_linked": "Je account is gekoppeld met (klik om te ontkoppelen)", "account.settings.sso.link_your_account": "{is_anonymous, select, true {Meld je aan met je account bij} other {Klik om je account te koppelen}}", "account.settings.unlisted.label": "Niet vermeld: je kan alleen gevonden worden met een exacte e-mailadressmatch", @@ -155,6 +154,9 @@ "ai-generate-document.modal.title": "Genereer een {docName} Document met AI", "ai-generator.select_llm": "Selecteer taalmodel", "app.fullscreen-button.tooltip": "Volledig schermmodus, gericht op het huidige document of de pagina.", + "app.hotkey.dialog.help_text": "Klik op frames hierboven • Toets 0 schakelt chat in/uit • Toetsen 1–9 focussen frames • Typ om te zoeken • ↑↓ navigeer • Return om te openen • ESC om te sluiten", + "app.hotkey.dialog.search_placeholder": "Bestanden en pagina's zoeken...", + "app.hotkey.dialog.title": "Snelle Navigatie", "app.verify-email-banner.edit": "Als het e-mailadres verkeerd is, pas het dan aan in de accountinstellingen.", "app.verify-email-banner.help.text": "Het is belangrijk om een werkend e-mailadres te hebben. We gebruiken het voor het opnieuw instellen van wachtwoorden, het verzenden van berichten, factureringsmeldingen en ondersteuning. Zorg ervoor dat uw e-mailadres correct is om op de hoogte te blijven.", "app.verify-email-banner.text": "{sent, select, true {E-mail verzonden! Controleer je e-mailinbox (en misschien spam) en klik op de bevestigingslink.} other {Controleer en verifieer je e-mailadres:}}", @@ -988,6 +990,7 @@ "labels.config": "Config", "labels.configuration": "Configuratie", "labels.configuration.short": "Config", + "labels.connected": "Verbonden", "labels.connecting": "Verbinden", "labels.connection": "Verbinding", "labels.copied": "gekopieerd", @@ -1016,6 +1019,7 @@ "labels.environment": "Omgeving", "labels.explorer": "Verkenner", "labels.file_explorer": "Bestandsverkenner", + "labels.file_use_notifications": "Meldingen Bestandsgebruik", "labels.files": "Bestanden", "labels.folder": "map", "labels.frame-editors.title-bar.save_label": "{type, select, is_public {Openbaar} read_only {Alleen lezen} other {Opslaan}}", @@ -1095,6 +1099,7 @@ "labels.project.settings.stop-project.label": "Stop{short, select, true {} other { Project}}…", "labels.project.settings.stop-project.ok": "Ja, stop project", "labels.projects": "Projecten", + "labels.public_paths": "Openbare Paden", "labels.published_files": "Gepubliceerde bestanden", "labels.purchases": "Aankopen", "labels.ready": "Klaar", @@ -1423,7 +1428,6 @@ "projects.create-project.helpTxt": "Kies een titel. Je kunt het later eenvoudig wijzigen!", "projects.create-project.requireLicense": "Er is een licentie vereist om extra projecten te maken.", "projects.filename-search.placeholder": "Zoek naar bestandsnamen die je hebt bewerkt...", - "projects.list.no_starred_found": "Geen gemarkeerde projecten gevonden. Gebruik het sterpictogram naast projecttitels om je favoriete projecten te markeren.", "projects.load-all.label": "Toon alle projecten...", "projects.operations.clear-filter": "Filter wissen", "projects.operations.delete.button": "{deleted, select, true {Alles Herstellen} other {Alles Verwijderen}}", @@ -1455,7 +1459,9 @@ "projects.table-controls.hashtags.placeholder": "Filteren op hashtags...", "projects.table-controls.hidden.label": "Verborgen", "projects.table-controls.search.placeholder": "Zoek projecten...", + "projects.table.keyboard-row-hint": "Project {title}. Gebruik de pijltjestoetsen omhoog en omlaag om te bewegen; druk op Enter of Spatiebalk om te openen.", "projects.table.last-edited": "Laatst bewerkt", + "projects.table.untitled": "Naamloos", "purchases.automatic-payments-warning.description": "Automatische betalingen zijn veel handiger, zullen je tijd besparen, en ervoor zorgen dat abonnementen niet per ongeluk worden opgezegd.", "purchases.automatic-payments-warning.title": "Automatische betalingen zijn NIET vereist om een abonnement te hebben", "purchases.automatic-payments.are-enabled": "Automatische Betalingen zijn Ingeschakeld", diff --git a/src/packages/frontend/i18n/trans/pl_PL.json b/src/packages/frontend/i18n/trans/pl_PL.json index 3ce0be42a5a..bce3c5556b3 100644 --- a/src/packages/frontend/i18n/trans/pl_PL.json +++ b/src/packages/frontend/i18n/trans/pl_PL.json @@ -5,6 +5,8 @@ "account.account_page.translation.info.title": "Informacje o tłumaczeniu", "account.account-button.confirm.ok": "Tak, wyloguj się", "account.account-button.confirm.title": "Wylogować się z konta?", + "account.appearance.accessibility.enabled": "Włącz tryb dostępności: optymalizuj interfejs użytkownika pod kątem funkcji dostępności", + "account.appearance.accessibility.title": "Dostępność", "account.appearance.user_interface.title": "Interfejs użytkownika", "account.delete-account.alert.description": "Natychmiast utracisz dostęp do wszystkich swoich projektów, wszelkie subskrypcje zostaną anulowane, a cały niewykorzystany kredyt zostanie utracony. {br} {hr} Aby USUNĄĆ SWOJE KONTO, najpierw wpisz poniżej \"{required_text}\":", "account.delete-account.alert.message": "Czy na pewno chcesz USUNĄĆ SWOJE KONTO?", @@ -31,13 +33,11 @@ "account.editor-setting.checkbox.strip_trailing_whitespace": "usuń za każdym razem, gdy plik jest zapisywany", "account.editor-settings-autosave-interval.label": "Interwał automatycznego zapisu", "account.editor-settings.basic.title": "Podstawowe ustawienia", - "account.editor-settings.color-schemes.label": "Schemat kolorów edytora", "account.editor-settings.color-schemes.panel_title": "Schemat kolorów edytora", "account.editor-settings.font-size.label": "Domyślny globalny rozmiar czcionki", "account.editor-settings.indent-size.label": "Rozmiar wcięcia", "account.editor-settings.keyboard-bindings.label": "Powiązania klawiatury edytora", "account.editor-settings.keyboard.title": "Klawiatura", - "account.editor-settings.title": "Edytor", "account.editor-settings.x11-keyboard-variant.label": "Odmiana klawiatury (dla pulpitu X11)", "account.editor-settings.x11-physical-keyboard.label": "Układ klawiatury (dla pulpitu X11)", "account.global-ssh-keys.help": "Aby zalogować się do projektu przez SSH, użyj następującego username@host: [project-id-without-dashes]@ssh.cocalc.com Identyfikator projektu bez myślników można znaleźć w części ustawień projektu dotyczącej kluczy SSH. Aby zalogować się przez SSH między projektami, użyj [project-id-without-dashes]@ssh", @@ -66,13 +66,13 @@ "account.keyboard-shortcuts.shortcut.split-view-sagews": "Podziel widok w arkuszu Sage", "account.keyboard-shortcuts.shortcut.toggle-comment": "Przełącz komentarzowanie zaznaczenia", "account.other-settings._page_size.label": "Liczba plików na stronę", - "account.other-settings.browser_performance.title": "Przeglądarka", + "account.other-settings.auto_focus": "Automatyczne ustawianie fokusu na polach tekstowych: automatycznie ustawiaj fokus na polach tekstowych, gdy się pojawiają (np. eksplorator plików, projekty, ...)", "account.other-settings.button_tooltips": "Ukryj podpowiedzi przycisków: ukrywa niektóre podpowiedzi przycisków (to jest tylko częściowe)", "account.other-settings.confirm_close": "Potwierdź zamknięcie: zawsze pytaj o potwierdzenie przed zamknięciem okna przeglądarki", - "account.other-settings.content_display.title": "Wyświetlanie treści", "account.other-settings.default_file_sort.by_name": "Sortuj według nazwy", "account.other-settings.default_file_sort.by_time": "Sortuj według czasu", "account.other-settings.default_file_sort.label": "Domyślne sortowanie plików", + "account.other-settings.dim_file_extensions": "Przyciemnij rozszerzenia plików: wyszarz rozszerzenia plików, aby ich nazwy się wyróżniały.", "account.other-settings.file_popovers": "Ukryj dymki zakładek plików: nie pokazuj dymków nad zakładkami plików", "account.other-settings.filename_generator.description": "Wybierz, jak automatycznie generowane nazwy plików są tworzone. W szczególności, aby były unikalne lub zawierały bieżący czas.", "account.other-settings.filename_generator.label": "Generator nazw plików", @@ -85,12 +85,9 @@ "account.other-settings.llm.title": "Ustawienia AI", "account.other-settings.markdown_codebar": "Wyłącz pasek kodu markdown we wszystkich dokumentach markdown. Zaznaczenie tego ukrywa dodatkowe przyciski uruchamiania, kopiowania i wyjaśniania w blokach kodu.", "account.other-settings.mask_files": "Maskuj pliki: wyszarz pliki w przeglądarce plików, których prawdopodobnie nie chcesz otworzyć", - "account.other-settings.messages.title": "Wiadomości", "account.other-settings.project_popovers": "Ukryj dymki kart projektu: nie pokazuj dymków nad kartami projektu", - "account.other-settings.projects.title": "Projekty", "account.other-settings.standby_timeout": "Limit czasu w trybie gotowości", "account.other-settings.symbol_bar_labels": "Pokaż etykiety paska symboli: pokaż etykiety na pasku symboli edytora ramki", - "account.other-settings.theme": "Motyw", "account.other-settings.theme.antd.animations": "Animacje: krótko animuj niektóre aspekty, np. przyciski", "account.other-settings.theme.antd.color_scheme": "Schemat kolorów: użyj kolorów marki zamiast domyślnych kolorów", "account.other-settings.theme.antd.compact": "Kompaktowy układ: użyj bardziej zwartego układu", @@ -128,6 +125,7 @@ "account.settings.overview.licenses": "Zarządzaj licencjami oprogramowania i uprawnieniami dostępu.", "account.settings.overview.other": "Ustawienia i opcje różne.", "account.settings.overview.payg": "Skonfiguruj rozliczanie i użytkowanie pay-as-you-go.", + "account.settings.overview.payment_methods": "Zarządzaj zapisanymi metodami płatności lub dodaj nowe.", "account.settings.overview.payments": "Zarządzaj metodami płatności i historią transakcji.", "account.settings.overview.profile": "Zarządzaj swoimi danymi osobowymi, awatarem i szczegółami konta.", "account.settings.overview.purchases": "Wyświetl historię zakupów i paragony.", @@ -135,6 +133,7 @@ "account.settings.overview.subscriptions": "Wyświetlaj i zarządzaj swoimi aktywnymi subskrypcjami.", "account.settings.overview.support": "Uzyskaj dostęp do zgłoszeń pomocy i zasobów pomocniczych.", "account.settings.overview.title": "Przegląd ustawień", + "account.settings.overview.upgrades": "Zarządzaj swoimi starszymi ulepszeniami limitu.", "account.settings.sso.account_is_linked": "Twoje konto jest połączone z (kliknij, aby odłączyć)", "account.settings.sso.link_your_account": "{is_anonymous, select, true {Zarejestruj się, używając swojego konta w} other {Kliknij, aby połączyć swoje konto}}", "account.settings.unlisted.label": "Niewymieniony: można cię znaleźć tylko poprzez dokładne dopasowanie adresu e-mail", @@ -155,6 +154,9 @@ "ai-generate-document.modal.title": "Wygeneruj dokument {docName} za pomocą AI", "ai-generator.select_llm": "Wybierz model językowy", "app.fullscreen-button.tooltip": "Tryb pełnoekranowy, skupiony na bieżącym dokumencie lub stronie.", + "app.hotkey.dialog.help_text": "Kliknij ramki powyżej • Klawisz 0 przełącza czat • Klawisze 1–9 skupiają ramki • Wpisz, aby wyszukać • ↑↓ nawigacja • Return, aby otworzyć • ESC, aby zamknąć", + "app.hotkey.dialog.search_placeholder": "Szukaj plików i stron...", + "app.hotkey.dialog.title": "Szybka nawigacja", "app.verify-email-banner.edit": "Jeśli adres e-mail jest niepoprawny, proszę edytować go w ustawieniach konta.", "app.verify-email-banner.help.text": "Ważne jest posiadanie działającego adresu e-mail. Używamy go do resetowania haseł, wysyłania wiadomości, powiadomień o rozliczeniach i wsparcia. Upewnij się, że Twój e-mail jest poprawny, aby być na bieżąco.", "app.verify-email-banner.text": "{sent, select, true {Email wysłany! Sprawdź swoją skrzynkę odbiorczą (a może spam) i kliknij link potwierdzający.} other {Proszę sprawdzić i zweryfikować swój adres e-mail:}}", @@ -988,6 +990,7 @@ "labels.config": "Konfiguracja", "labels.configuration": "Konfiguracja", "labels.configuration.short": "Konfiguracja", + "labels.connected": "Połączono", "labels.connecting": "Łączenie", "labels.connection": "Połączenie", "labels.copied": "skopiowano", @@ -1016,6 +1019,7 @@ "labels.environment": "Środowisko", "labels.explorer": "Eksplorator", "labels.file_explorer": "Eksplorator plików", + "labels.file_use_notifications": "Powiadomienia o użyciu plików", "labels.files": "Pliki", "labels.folder": "folder", "labels.frame-editors.title-bar.save_label": "{type, select, is_public {Publiczny} read_only {Tylko do odczytu} other {Zapisz}}", @@ -1095,6 +1099,7 @@ "labels.project.settings.stop-project.label": "Zatrzymaj{short, select, true {} other { Projekt}}…", "labels.project.settings.stop-project.ok": "Tak, zatrzymaj projekt", "labels.projects": "Projekty", + "labels.public_paths": "Ścieżki publiczne", "labels.published_files": "Opublikowane Pliki", "labels.purchases": "Zakupy", "labels.ready": "Gotowe", @@ -1423,7 +1428,6 @@ "projects.create-project.helpTxt": "Wybierz tytuł. Możesz łatwo zmienić go później!", "projects.create-project.requireLicense": "Do utworzenia dodatkowych projektów wymagana jest licencja.", "projects.filename-search.placeholder": "Szukaj nazw plików, które edytowałeś...", - "projects.list.no_starred_found": "Nie znaleziono oznaczonych projektów. Użyj ikony gwiazdki obok tytułów projektów, aby dodać do zakładek swoje ulubione projekty.", "projects.load-all.label": "Pokaż wszystkie projekty...", "projects.operations.clear-filter": "Wyczyść filtr", "projects.operations.delete.button": "{deleted, select, true {Przywróć wszystko} other {Usuń wszystko}}", @@ -1455,7 +1459,9 @@ "projects.table-controls.hashtags.placeholder": "Filtruj według hashtagów...", "projects.table-controls.hidden.label": "Ukryty", "projects.table-controls.search.placeholder": "Szukaj projektów...", + "projects.table.keyboard-row-hint": "Projekt {title}. Użyj strzałek w górę i w dół, aby się poruszać; naciśnij Enter lub Spację, aby otworzyć.", "projects.table.last-edited": "Ostatnia edycja", + "projects.table.untitled": "Bez tytułu", "purchases.automatic-payments-warning.description": "Automatyczne płatności są znacznie wygodniejsze, zaoszczędzą Twój czas i zapewnią, że subskrypcje nie zostaną anulowane przez przypadek.", "purchases.automatic-payments-warning.title": "Automatyczne płatności NIE są wymagane do posiadania subskrypcji", "purchases.automatic-payments.are-enabled": "Automatyczne Płatności są Włączone", diff --git a/src/packages/frontend/i18n/trans/pt_BR.json b/src/packages/frontend/i18n/trans/pt_BR.json index ae7b547ba09..7db1bf11a76 100644 --- a/src/packages/frontend/i18n/trans/pt_BR.json +++ b/src/packages/frontend/i18n/trans/pt_BR.json @@ -5,6 +5,8 @@ "account.account_page.translation.info.title": "Informações de Tradução", "account.account-button.confirm.ok": "Sim, sair", "account.account-button.confirm.title": "Sair da sua conta?", + "account.appearance.accessibility.enabled": "Ativar o Modo de Acessibilidade: otimizar a interface do usuário para recursos de acessibilidade", + "account.appearance.accessibility.title": "Acessibilidade", "account.appearance.user_interface.title": "Interface do Usuário", "account.delete-account.alert.description": "Você imediatamente perderá acesso a todos os seus projetos, quaisquer assinaturas serão canceladas e todo crédito não utilizado será perdido. {br} {hr} Para DELETAR SUA CONTA, primeiro digite \"{required_text}\" abaixo:", "account.delete-account.alert.message": "Tem certeza de que deseja EXCLUIR SUA CONTA?", @@ -31,13 +33,11 @@ "account.editor-setting.checkbox.strip_trailing_whitespace": "remover sempre que o arquivo for salvo", "account.editor-settings-autosave-interval.label": "Intervalo de salvamento automático", "account.editor-settings.basic.title": "Configurações Básicas", - "account.editor-settings.color-schemes.label": "Esquema de cores do editor", "account.editor-settings.color-schemes.panel_title": "Esquema de Cores do Editor", "account.editor-settings.font-size.label": "Tamanho padrão da fonte global", "account.editor-settings.indent-size.label": "Tamanho da indentação", "account.editor-settings.keyboard-bindings.label": "Atalhos de teclado do editor", "account.editor-settings.keyboard.title": "Teclado", - "account.editor-settings.title": "Configurações do Editor", "account.editor-settings.x11-keyboard-variant.label": "Variante do teclado (para X11 Desktop)", "account.editor-settings.x11-physical-keyboard.label": "Layout de teclado (para X11 Desktop)", "account.global-ssh-keys.help": "Para acessar um projeto via SSH, use o seguinte username@host: [project-id-without-dashes]@ssh.cocalc.com O ID do projeto sem traços pode ser encontrado na parte das configurações do projeto sobre chaves SSH. Para acessar entre projetos via SSH, use [project-id-without-dashes]@ssh", @@ -66,13 +66,13 @@ "account.keyboard-shortcuts.shortcut.split-view-sagews": "Divisão de visualização na planilha Sage", "account.keyboard-shortcuts.shortcut.toggle-comment": "Alternar comentário da seleção", "account.other-settings._page_size.label": "Número de arquivos por página", - "account.other-settings.browser_performance.title": "Navegador", + "account.other-settings.auto_focus": "Focar Automaticamente no Campo de Texto: focar automaticamente nos campos de entrada de texto quando eles aparecem (por exemplo, explorador de arquivos, projetos, ...)", "account.other-settings.button_tooltips": "Ocultar Dicas de Botões: oculta algumas dicas de botões (isso é apenas parcial)", "account.other-settings.confirm_close": "Confirmar Fechamento: sempre pedir confirmação antes de fechar a janela do navegador", - "account.other-settings.content_display.title": "Exibição de Conteúdo", "account.other-settings.default_file_sort.by_name": "Ordenar por nome", "account.other-settings.default_file_sort.by_time": "Ordenar por tempo", "account.other-settings.default_file_sort.label": "Ordenação padrão de arquivos", + "account.other-settings.dim_file_extensions": "Extensões de arquivo em cinza: desbotar extensões de arquivo para que seus nomes se destaquem.", "account.other-settings.file_popovers": "Ocultar Popovers de Abas de Arquivos: não mostrar os popovers sobre as abas de arquivos", "account.other-settings.filename_generator.description": "Selecione como os nomes de arquivos gerados automaticamente são criados. Em particular, para torná-los únicos ou incluir a hora atual.", "account.other-settings.filename_generator.label": "Gerador de nomes de arquivo", @@ -85,12 +85,9 @@ "account.other-settings.llm.title": "Configurações de IA", "account.other-settings.markdown_codebar": "Desativar a barra de código markdown em todos os documentos markdown. Marcar isso oculta os botões extras de executar, copiar e explicar em blocos de código delimitados.", "account.other-settings.mask_files": "Mascarar Arquivos: escurecer arquivos no visualizador de arquivos que você provavelmente não deseja abrir", - "account.other-settings.messages.title": "Mensagens", "account.other-settings.project_popovers": "Ocultar Pop-ups das Abas do Projeto: não mostrar os pop-ups sobre as abas do projeto", - "account.other-settings.projects.title": "Projetos", "account.other-settings.standby_timeout": "Tempo de espera em espera", "account.other-settings.symbol_bar_labels": "Mostrar Rótulos da Barra de Símbolos: mostrar rótulos na barra de símbolos do editor de quadros", - "account.other-settings.theme": "Tema", "account.other-settings.theme.antd.animations": "Animações: animar brevemente alguns aspectos, por exemplo, botões", "account.other-settings.theme.antd.color_scheme": "Esquema de Cores: use cores da marca em vez de cores padrão", "account.other-settings.theme.antd.compact": "Design Compacto: use um design mais compacto", @@ -128,6 +125,7 @@ "account.settings.overview.licenses": "Gerenciar licenças de software e permissões de acesso.", "account.settings.overview.other": "Configurações e opções diversas.", "account.settings.overview.payg": "Configure o uso e cobrança conforme o consumo.", + "account.settings.overview.payment_methods": "Gerencie seus métodos de pagamento salvos ou adicione novos.", "account.settings.overview.payments": "Gerenciar métodos de pagamento e histórico de transações.", "account.settings.overview.profile": "Gerencie suas informações pessoais, avatar e detalhes da conta.", "account.settings.overview.purchases": "Ver histórico de compras e recibos.", @@ -135,6 +133,7 @@ "account.settings.overview.subscriptions": "Visualize e gerencie suas assinaturas ativas.", "account.settings.overview.support": "Acesse os tickets de suporte e recursos de ajuda.", "account.settings.overview.title": "Visão Geral das Configurações", + "account.settings.overview.upgrades": "Gerencie suas atualizações de cota legadas.", "account.settings.sso.account_is_linked": "Sua conta está vinculada a (clique para desvincular)", "account.settings.sso.link_your_account": "{is_anonymous, select, true {Cadastre-se usando sua conta em} other {Clique para vincular sua conta}}", "account.settings.unlisted.label": "Não listado: só pode ser encontrado por uma correspondência exata de endereço de email", @@ -155,6 +154,9 @@ "ai-generate-document.modal.title": "Gerar um Documento {docName} usando IA", "ai-generator.select_llm": "Selecionar modelo de linguagem", "app.fullscreen-button.tooltip": "Modo de tela cheia, focado no documento ou página atual.", + "app.hotkey.dialog.help_text": "Clique nos quadros acima • Tecla 0 alterna chat • Teclas 1–9 focam quadros • Digite para pesquisar • ↑↓ navegar • Enter para abrir • ESC para fechar", + "app.hotkey.dialog.search_placeholder": "Pesquisar arquivos e páginas...", + "app.hotkey.dialog.title": "Navegação Rápida", "app.verify-email-banner.edit": "Se o endereço de e-mail estiver errado, por favor edite nas configurações da conta.", "app.verify-email-banner.help.text": "É importante ter um endereço de e-mail funcional. Nós o usamos para redefinir senhas, enviar mensagens, notificações de cobrança e suporte. Por favor, certifique-se de que seu e-mail está correto para se manter informado.", "app.verify-email-banner.text": "{sent, select, true {Email enviado! Por favor, verifique a caixa de entrada do seu email (e talvez o spam) e clique no link de confirmação.} other {Por favor, verifique e confirme seu endereço de email:}}", @@ -988,6 +990,7 @@ "labels.config": "Configuração", "labels.configuration": "Configuração", "labels.configuration.short": "Configuração", + "labels.connected": "Conectado", "labels.connecting": "Conectando", "labels.connection": "Conexão", "labels.copied": "copiado", @@ -1016,6 +1019,7 @@ "labels.environment": "Ambiente", "labels.explorer": "Explorador", "labels.file_explorer": "Explorador de Arquivos", + "labels.file_use_notifications": "Notificações de Uso de Arquivo", "labels.files": "Arquivos", "labels.folder": "pasta", "labels.frame-editors.title-bar.save_label": "{type, select, is_public {Público} read_only {Somente leitura} other {Salvar}}", @@ -1095,6 +1099,7 @@ "labels.project.settings.stop-project.label": "Parar{short, select, true {} other { Projeto}}…", "labels.project.settings.stop-project.ok": "Sim, parar projeto", "labels.projects": "Projetos", + "labels.public_paths": "Caminhos Públicos", "labels.published_files": "Publicado", "labels.purchases": "Compras", "labels.ready": "Pronto", @@ -1423,7 +1428,6 @@ "projects.create-project.helpTxt": "Escolha um título. Você pode alterá-lo facilmente depois!", "projects.create-project.requireLicense": "É necessária uma licença para criar projetos adicionais.", "projects.filename-search.placeholder": "Pesquisar por nomes de arquivos que você editou...", - "projects.list.no_starred_found": "Nenhum projeto marcado com estrela encontrado. Use o ícone de estrela ao lado dos títulos dos projetos para marcar seus projetos favoritos.", "projects.load-all.label": "Mostrar todos os projetos...", "projects.operations.clear-filter": "Limpar Filtro", "projects.operations.delete.button": "{deleted, select, true {Restaurar Tudo} other {Excluir Tudo}}", @@ -1455,7 +1459,9 @@ "projects.table-controls.hashtags.placeholder": "Filtrar por hashtags...", "projects.table-controls.hidden.label": "Oculto", "projects.table-controls.search.placeholder": "Buscar projetos...", + "projects.table.keyboard-row-hint": "Projeto {title}. Use as setas para cima e para baixo para mover; pressione Enter ou Espaço para abrir.", "projects.table.last-edited": "Última Edição", + "projects.table.untitled": "Sem título", "purchases.automatic-payments-warning.description": "Pagamentos automáticos são muito mais convenientes, vão economizar seu tempo e garantir que assinaturas não sejam canceladas por acidente.", "purchases.automatic-payments-warning.title": "Pagamentos automáticos NÃO são necessários para ter uma assinatura", "purchases.automatic-payments.are-enabled": "Pagamentos Automáticos estão Ativados", diff --git a/src/packages/frontend/i18n/trans/pt_PT.json b/src/packages/frontend/i18n/trans/pt_PT.json index e5c65f6b920..714b91d09e4 100644 --- a/src/packages/frontend/i18n/trans/pt_PT.json +++ b/src/packages/frontend/i18n/trans/pt_PT.json @@ -5,6 +5,8 @@ "account.account_page.translation.info.title": "Informação sobre a Tradução", "account.account-button.confirm.ok": "Sim, terminar sessão", "account.account-button.confirm.title": "Sair da sua conta?", + "account.appearance.accessibility.enabled": "Ativar Modo de Acessibilidade: otimizar a interface do utilizador para funcionalidades de acessibilidade", + "account.appearance.accessibility.title": "Acessibilidade", "account.appearance.user_interface.title": "Interface do Utilizador", "account.delete-account.alert.description": "Perderá imediatamente o acesso a todos os seus projetos, quaisquer subscrições serão canceladas e todo o crédito não utilizado será perdido. {br} {hr} Para ELIMINAR A SUA CONTA, primeiro introduza \"{required_text}\" abaixo:", "account.delete-account.alert.message": "Tem a certeza de que quer ELIMINAR A SUA CONTA?", @@ -31,13 +33,11 @@ "account.editor-setting.checkbox.strip_trailing_whitespace": "remover sempre que o ficheiro for guardado", "account.editor-settings-autosave-interval.label": "Intervalo de Autossalvamento", "account.editor-settings.basic.title": "Configurações Básicas", - "account.editor-settings.color-schemes.label": "Esquema de cores do editor", "account.editor-settings.color-schemes.panel_title": "Esquema de Cores do Editor", "account.editor-settings.font-size.label": "Tamanho de fonte global padrão", "account.editor-settings.indent-size.label": "Tamanho da indentação", "account.editor-settings.keyboard-bindings.label": "Ligações de teclado do editor", "account.editor-settings.keyboard.title": "Teclado", - "account.editor-settings.title": "Editor", "account.editor-settings.x11-keyboard-variant.label": "Variante de teclado (para Desktop X11)", "account.editor-settings.x11-physical-keyboard.label": "Distribuição do teclado (para X11 Desktop)", "account.global-ssh-keys.help": "Para SSH em um projeto, use o seguinte username@host: [project-id-without-dashes]@ssh.cocalc.com O ID do projeto sem traços pode ser encontrado na parte das configurações do projeto sobre chaves SSH. Para SSH entre projetos, use [project-id-without-dashes]@ssh", @@ -66,13 +66,13 @@ "account.keyboard-shortcuts.shortcut.split-view-sagews": "Vista dividida na folha de cálculo Sage", "account.keyboard-shortcuts.shortcut.toggle-comment": "Alternar comentário da seleção", "account.other-settings._page_size.label": "Número de ficheiros por página", - "account.other-settings.browser_performance.title": "Navegador", + "account.other-settings.auto_focus": "Focar Automaticamente no Campo de Texto: focar automaticamente nos campos de texto quando eles aparecem (por exemplo, explorador de ficheiros, projetos, ...)", "account.other-settings.button_tooltips": "Ocultar Dicas de Botão: oculta algumas dicas de botão (isto é apenas parcial)", "account.other-settings.confirm_close": "Confirmar Fecho: pedir sempre confirmação antes de fechar a janela do navegador", - "account.other-settings.content_display.title": "Exibição de Conteúdo", "account.other-settings.default_file_sort.by_name": "Ordenar por nome", "account.other-settings.default_file_sort.by_time": "Ordenar por tempo", "account.other-settings.default_file_sort.label": "Ordenação padrão de ficheiros", + "account.other-settings.dim_file_extensions": "Extensões de ficheiros em cinzento: atenuar as extensões de ficheiros para que os seus nomes se destaquem.", "account.other-settings.file_popovers": "Ocultar Popovers das Abas de Ficheiro: não mostrar os popovers sobre as abas de ficheiro", "account.other-settings.filename_generator.description": "Selecione como os nomes de ficheiros gerados automaticamente são criados. Em particular, para torná-los únicos ou incluir a hora atual.", "account.other-settings.filename_generator.label": "Gerador de nomes de ficheiros", @@ -85,12 +85,9 @@ "account.other-settings.llm.title": "Configurações de IA", "account.other-settings.markdown_codebar": "Desativar a barra de código markdown em todos os documentos markdown. Marcar esta opção oculta os botões extra de execução, cópia e explicação em blocos de código delimitados.", "account.other-settings.mask_files": "Mascarar ficheiros: esbater ficheiros no visualizador de ficheiros que provavelmente não quer abrir", - "account.other-settings.messages.title": "Mensagens", "account.other-settings.project_popovers": "Ocultar Pop-ups das Abas do Projeto: não mostrar os pop-ups sobre as abas do projeto", - "account.other-settings.projects.title": "Projetos", "account.other-settings.standby_timeout": "Tempo limite de espera", "account.other-settings.symbol_bar_labels": "Mostrar Etiquetas da Barra de Símbolos: mostrar etiquetas na barra de símbolos do editor de frames", - "account.other-settings.theme": "Tema", "account.other-settings.theme.antd.animations": "Animações: animar brevemente alguns aspetos, por exemplo, botões", "account.other-settings.theme.antd.color_scheme": "Esquema de Cores: usar cores da marca em vez de cores padrão", "account.other-settings.theme.antd.compact": "Design Compacto: usar um design mais compacto", @@ -128,6 +125,7 @@ "account.settings.overview.licenses": "Gerir licenças de software e permissões de acesso.", "account.settings.overview.other": "Configurações e opções diversas.", "account.settings.overview.payg": "Configurar utilização e faturação pay-as-you-go.", + "account.settings.overview.payment_methods": "Gerir os seus métodos de pagamento guardados ou adicionar novos.", "account.settings.overview.payments": "Gerir métodos de pagamento e histórico de transações.", "account.settings.overview.profile": "Gerir as suas informações pessoais, avatar e detalhes da conta.", "account.settings.overview.purchases": "Ver histórico de compras e recibos.", @@ -135,6 +133,7 @@ "account.settings.overview.subscriptions": "Veja e gere as suas assinaturas ativas.", "account.settings.overview.support": "Aceda aos tickets de suporte e recursos de ajuda.", "account.settings.overview.title": "Visão Geral das Definições", + "account.settings.overview.upgrades": "Gerir as suas atualizações de quota legadas.", "account.settings.sso.account_is_linked": "A sua conta está ligada a (clique para desvincular)", "account.settings.sso.link_your_account": "{is_anonymous, select, true {Registe-se usando a sua conta em} other {Clique para ligar a sua conta}}", "account.settings.unlisted.label": "Não listado: só pode ser encontrado por correspondência exata do endereço de email", @@ -155,6 +154,9 @@ "ai-generate-document.modal.title": "Gerar um Documento {docName} usando IA", "ai-generator.select_llm": "Selecionar modelo de linguagem", "app.fullscreen-button.tooltip": "Modo de ecrã completo, focado no documento ou página atual", + "app.hotkey.dialog.help_text": "Clique nas molduras acima • A tecla 0 alterna o chat • As teclas 1–9 focam nas molduras • Digite para pesquisar • ↑↓ navegue • Enter para abrir • ESC para fechar", + "app.hotkey.dialog.search_placeholder": "Procurar ficheiros e páginas...", + "app.hotkey.dialog.title": "Navegação Rápida", "app.verify-email-banner.edit": "Se o endereço de email estiver errado, por favor edite nas configurações da conta.", "app.verify-email-banner.help.text": "É importante ter um endereço de email funcional. Usamo-lo para redefinições de senha, envio de mensagens, notificações de faturação e suporte. Por favor, certifique-se de que o seu email está correto para se manter informado.", "app.verify-email-banner.text": "{sent, select, true {Email Enviado! Por favor, verifique a sua caixa de entrada de email (e talvez o spam) e clique no link de confirmação.} other {Por favor, verifique e confirme o seu endereço de email:}}", @@ -988,6 +990,7 @@ "labels.config": "Configuração", "labels.configuration": "Configuração", "labels.configuration.short": "Configurar", + "labels.connected": "Ligado", "labels.connecting": "A ligar", "labels.connection": "Ligação", "labels.copied": "copiado", @@ -1016,6 +1019,7 @@ "labels.environment": "Ambiente", "labels.explorer": "Explorador", "labels.file_explorer": "Explorador de Ficheiros", + "labels.file_use_notifications": "Notificações de Uso de Ficheiro", "labels.files": "Ficheiros", "labels.folder": "pasta", "labels.frame-editors.title-bar.save_label": "{type, select, is_public {Público} read_only {Só de leitura} other {Guardar}}", @@ -1095,6 +1099,7 @@ "labels.project.settings.stop-project.label": "Parar{short, select, true {} other { Projeto}}…", "labels.project.settings.stop-project.ok": "Sim, parar projeto", "labels.projects": "Projetos", + "labels.public_paths": "Caminhos Públicos", "labels.published_files": "Ficheiros Publicados", "labels.purchases": "Compras", "labels.ready": "Pronto", @@ -1423,7 +1428,6 @@ "projects.create-project.helpTxt": "Escolha um título. Pode alterá-lo facilmente mais tarde!", "projects.create-project.requireLicense": "É necessária uma licença para criar projetos adicionais.", "projects.filename-search.placeholder": "Procurar por nomes de ficheiros que editou...", - "projects.list.no_starred_found": "Nenhum projeto com estrela encontrado. Use o ícone de estrela ao lado dos títulos dos projetos para marcar os seus projetos favoritos.", "projects.load-all.label": "Mostrar todos os projetos...", "projects.operations.clear-filter": "Limpar Filtro", "projects.operations.delete.button": "{deleted, select, true {Recuperar Tudo} other {Eliminar Tudo}}", @@ -1455,7 +1459,9 @@ "projects.table-controls.hashtags.placeholder": "Filtrar por hashtags...", "projects.table-controls.hidden.label": "Oculto", "projects.table-controls.search.placeholder": "Procurar projetos...", + "projects.table.keyboard-row-hint": "Projeto {title}. Use as setas para cima e para baixo para mover; pressione Enter ou Espaço para abrir.", "projects.table.last-edited": "Última Edição", + "projects.table.untitled": "Sem título", "purchases.automatic-payments-warning.description": "Os pagamentos automáticos são muito mais convenientes, irão poupar-lhe tempo e garantir que as subscrições não sejam canceladas por acidente.", "purchases.automatic-payments-warning.title": "Não são necessários pagamentos automáticos para ter uma subscrição", "purchases.automatic-payments.are-enabled": "Pagamentos Automáticos estão Ativados", diff --git a/src/packages/frontend/i18n/trans/ru_RU.json b/src/packages/frontend/i18n/trans/ru_RU.json index 74e072a11cd..57217b0ad71 100644 --- a/src/packages/frontend/i18n/trans/ru_RU.json +++ b/src/packages/frontend/i18n/trans/ru_RU.json @@ -5,6 +5,8 @@ "account.account_page.translation.info.title": "Информация о переводе", "account.account-button.confirm.ok": "Да, выйти", "account.account-button.confirm.title": "Выйти из вашего аккаунта?", + "account.appearance.accessibility.enabled": "Включить режим доступности: оптимизировать пользовательский интерфейс для функций доступности", + "account.appearance.accessibility.title": "Доступность", "account.appearance.user_interface.title": "Пользовательский интерфейс", "account.delete-account.alert.description": "Вы немедленно потеряете доступ ко всем вашим проектам, все подписки будут отменены, а все неиспользованные средства будут утрачены. {br} {hr} Чтобы УДАЛИТЬ ВАШ АККАУНТ, сначала введите \"{required_text}\" ниже:", "account.delete-account.alert.message": "Вы уверены, что хотите УДАЛИТЬ ВАШ АККАУНТ?", @@ -31,13 +33,11 @@ "account.editor-setting.checkbox.strip_trailing_whitespace": "удалить при каждом сохранении файла", "account.editor-settings-autosave-interval.label": "Интервал автосохранения", "account.editor-settings.basic.title": "Основные настройки", - "account.editor-settings.color-schemes.label": "Цветовая схема редактора", "account.editor-settings.color-schemes.panel_title": "Цветовая схема редактора", "account.editor-settings.font-size.label": "Размер шрифта по умолчанию", "account.editor-settings.indent-size.label": "Размер отступа", "account.editor-settings.keyboard-bindings.label": "Клавиатурные привязки редактора", "account.editor-settings.keyboard.title": "Клавиатура", - "account.editor-settings.title": "Редактор", "account.editor-settings.x11-keyboard-variant.label": "Вариант клавиатуры (для X11 Desktop)", "account.editor-settings.x11-physical-keyboard.label": "Раскладка клавиатуры (для X11 Desktop)", "account.global-ssh-keys.help": "Для SSH в проект используйте следующий username@host: [project-id-without-dashes]@ssh.cocalc.com Идентификатор проекта без тире можно найти в разделе настроек проекта о SSH-ключах. Для SSH между проектами используйте [project-id-without-dashes]@ssh", @@ -66,13 +66,13 @@ "account.keyboard-shortcuts.shortcut.split-view-sagews": "Разделить вид в рабочем листе Sage", "account.keyboard-shortcuts.shortcut.toggle-comment": "Переключить комментирование выделения", "account.other-settings._page_size.label": "Количество файлов на странице", - "account.other-settings.browser_performance.title": "Браузер", + "account.other-settings.auto_focus": "Автоматическая фокусировка текстового ввода: автоматически фокусировать поля ввода текста, когда они появляются (например, проводник файлов, проекты, ...)", "account.other-settings.button_tooltips": "Скрыть подсказки кнопок: скрывает некоторые подсказки кнопок (это только частично)", "account.other-settings.confirm_close": "Подтвердите закрытие: всегда запрашивать подтверждение перед закрытием окна браузера", - "account.other-settings.content_display.title": "Отображение контента", "account.other-settings.default_file_sort.by_name": "Сортировать по имени", "account.other-settings.default_file_sort.by_time": "Сортировать по времени", "account.other-settings.default_file_sort.label": "Сортировка файлов по умолчанию", + "account.other-settings.dim_file_extensions": "Затемнить расширения файлов: сделать расширения файлов серыми, чтобы их названия выделялись.", "account.other-settings.file_popovers": "Скрыть всплывающие подсказки вкладок файлов: не показывать всплывающие подсказки над вкладками файлов", "account.other-settings.filename_generator.description": "Выберите способ автоматической генерации имен файлов. В частности, чтобы сделать их уникальными или включить текущее время.", "account.other-settings.filename_generator.label": "Генератор имен файлов", @@ -85,12 +85,9 @@ "account.other-settings.llm.title": "Настройки AI", "account.other-settings.markdown_codebar": "Отключить панель кода markdown во всех markdown документах. Если установить этот флажок, будут скрыты дополнительные кнопки запуска, копирования и объяснения в блоках кода.", "account.other-settings.mask_files": "Маскировать файлы: затенить файлы в просмотрщике файлов, которые вы, вероятно, не захотите открывать", - "account.other-settings.messages.title": "Сообщения", "account.other-settings.project_popovers": "Скрыть всплывающие подсказки вкладок проекта: не показывать всплывающие подсказки над вкладками проекта", - "account.other-settings.projects.title": "Проекты", "account.other-settings.standby_timeout": "Таймаут ожидания", "account.other-settings.symbol_bar_labels": "Показать метки панели символов: показывать метки на панели символов в редакторе фреймов", - "account.other-settings.theme": "Тема", "account.other-settings.theme.antd.animations": "Анимации: кратко анимировать некоторые аспекты, например, кнопки", "account.other-settings.theme.antd.color_scheme": "Цветовая схема: использовать фирменные цвета вместо стандартных цветов", "account.other-settings.theme.antd.compact": "Компактный дизайн: использовать более компактный дизайн", @@ -128,6 +125,7 @@ "account.settings.overview.licenses": "Управление лицензиями на программное обеспечение и разрешениями на доступ.", "account.settings.overview.other": "Разные настройки и параметры.", "account.settings.overview.payg": "Настроить использование и оплату по мере использования.", + "account.settings.overview.payment_methods": "Управляйте сохраненными способами оплаты или добавляйте новые.", "account.settings.overview.payments": "Управление способами оплаты и историей транзакций.", "account.settings.overview.profile": "Управляйте вашей личной информацией, аватаром и данными учетной записи.", "account.settings.overview.purchases": "Просмотреть историю покупок и квитанции.", @@ -135,6 +133,7 @@ "account.settings.overview.subscriptions": "Просмотр и управление вашими активными подписками.", "account.settings.overview.support": "Доступ к заявкам в поддержку и ресурсам помощи.", "account.settings.overview.title": "Обзор настроек", + "account.settings.overview.upgrades": "Управляйте своими устаревшими квотами обновлений.", "account.settings.sso.account_is_linked": "Ваша учетная запись связана с (нажмите, чтобы отвязать)", "account.settings.sso.link_your_account": "{is_anonymous, select, true {Зарегистрируйтесь, используя ваш аккаунт в} other {Нажмите, чтобы привязать ваш аккаунт}}", "account.settings.unlisted.label": "Скрыто: вас можно найти только по точному совпадению адреса электронной почты", @@ -155,6 +154,9 @@ "ai-generate-document.modal.title": "Сгенерировать документ {docName} с помощью ИИ", "ai-generator.select_llm": "Выберите языковую модель", "app.fullscreen-button.tooltip": "Полноэкранный режим, сосредоточенный на текущем документе или странице", + "app.hotkey.dialog.help_text": "Щелкните по кадрам сверху • Клавиша 0 переключает чат • Клавиши 1–9 фокусируются на кадрах • Введите для поиска • ↑↓ навигация • Return для открытия • ESC для закрытия", + "app.hotkey.dialog.search_placeholder": "Искать файлы и страницы...", + "app.hotkey.dialog.title": "Быстрая навигация", "app.verify-email-banner.edit": "Если адрес электронной почты неверен, пожалуйста, отредактируйте его в настройках аккаунта.", "app.verify-email-banner.help.text": "Важно иметь работающий адрес электронной почты. Мы используем его для сброса пароля, отправки сообщений, уведомлений о выставлении счетов и поддержки. Пожалуйста, убедитесь, что ваш адрес электронной почты правильный, чтобы оставаться в курсе событий.", "app.verify-email-banner.text": "{sent, select, true {Электронное письмо отправлено! Пожалуйста, проверьте ваш почтовый ящик (и, возможно, спам) и нажмите на ссылку для подтверждения.} other {Пожалуйста, проверьте и подтвердите ваш адрес электронной почты:}}", @@ -988,6 +990,7 @@ "labels.config": "Конфигурация", "labels.configuration": "Конфигурация", "labels.configuration.short": "Конфиг", + "labels.connected": "Подключено", "labels.connecting": "Соединение", "labels.connection": "Соединение", "labels.copied": "скопировано", @@ -1016,6 +1019,7 @@ "labels.environment": "Окружение", "labels.explorer": "Проводник", "labels.file_explorer": "Проводник файлов", + "labels.file_use_notifications": "Уведомления об использовании файлов", "labels.files": "Файлы", "labels.folder": "папка", "labels.frame-editors.title-bar.save_label": "{type, select, is_public {Публичный} read_only {Только чтение} other {Сохранить}}", @@ -1095,6 +1099,7 @@ "labels.project.settings.stop-project.label": "Остановить{short, select, true {} other { Проект}}…", "labels.project.settings.stop-project.ok": "Да, остановить проект", "labels.projects": "Проекты", + "labels.public_paths": "Публичные пути", "labels.published_files": "Опубликованные файлы", "labels.purchases": "Покупки", "labels.ready": "Готово", @@ -1423,7 +1428,6 @@ "projects.create-project.helpTxt": "Выберите название. Вы всегда можете изменить его позже!", "projects.create-project.requireLicense": "Для создания дополнительных проектов требуется лицензия.", "projects.filename-search.placeholder": "Искать измененные вами файлы...", - "projects.list.no_starred_found": "Не найдено избранных проектов. Используйте значок звезды рядом с названиями проектов, чтобы добавить в закладки ваши любимые проекты.", "projects.load-all.label": "Показать все проекты...", "projects.operations.clear-filter": "Очистить фильтр", "projects.operations.delete.button": "{deleted, select, true {Восстановить все} other {Удалить все}}", @@ -1455,7 +1459,9 @@ "projects.table-controls.hashtags.placeholder": "Фильтр по хэштегам...", "projects.table-controls.hidden.label": "Скрыто", "projects.table-controls.search.placeholder": "Поиск проектов...", + "projects.table.keyboard-row-hint": "Проект {title}. Используйте стрелки вверх и вниз для перемещения; нажмите Enter или пробел для открытия.", "projects.table.last-edited": "Последнее изменение", + "projects.table.untitled": "Без названия", "purchases.automatic-payments-warning.description": "Автоматические платежи гораздо удобнее, сэкономят вам время и гарантируют, что подписки не будут случайно отменены.", "purchases.automatic-payments-warning.title": "Автоматические платежи НЕ требуются для подписки", "purchases.automatic-payments.are-enabled": "Автоматические платежи включены", diff --git a/src/packages/frontend/i18n/trans/tr_TR.json b/src/packages/frontend/i18n/trans/tr_TR.json index 60add4cbb48..b006a48dfd2 100644 --- a/src/packages/frontend/i18n/trans/tr_TR.json +++ b/src/packages/frontend/i18n/trans/tr_TR.json @@ -5,6 +5,8 @@ "account.account_page.translation.info.title": "Çeviri Bilgisi", "account.account-button.confirm.ok": "Evet, çıkış yap", "account.account-button.confirm.title": "Hesabınızdan çıkış yapmak mı?", + "account.appearance.accessibility.enabled": "Erişilebilirlik Modunu Etkinleştir: kullanıcı arayüzünü erişilebilirlik özelliklerine göre optimize et", + "account.appearance.accessibility.title": "Erişilebilirlik", "account.appearance.user_interface.title": "Kullanıcı Arayüzü", "account.delete-account.alert.description": "Derhal tüm projelerinize erişimi kaybedeceksiniz, abonelikler iptal edilecek ve kullanılmamış tüm krediler kaybolacak. {br} {hr} HESABINIZI SİLMEK için önce aşağıya \"{required_text}\" yazın:", "account.delete-account.alert.message": "HESABINIZI SİLMEK istediğinizden emin misiniz?", @@ -31,13 +33,11 @@ "account.editor-setting.checkbox.strip_trailing_whitespace": "dosya her kaydedildiğinde kaldır", "account.editor-settings-autosave-interval.label": "Otomatik kaydetme aralığı", "account.editor-settings.basic.title": "Temel Ayarlar", - "account.editor-settings.color-schemes.label": "Editör renk şeması", "account.editor-settings.color-schemes.panel_title": "Editör Renk Şeması", "account.editor-settings.font-size.label": "Varsayılan genel yazı tipi boyutu", "account.editor-settings.indent-size.label": "Girinti boyutu", "account.editor-settings.keyboard-bindings.label": "Editör klavye bağlamaları", "account.editor-settings.keyboard.title": "Klavye", - "account.editor-settings.title": "Editör", "account.editor-settings.x11-keyboard-variant.label": "Klavye çeşidi (X11 Masaüstü için)", "account.editor-settings.x11-physical-keyboard.label": "Klavye düzeni (X11 Masaüstü için)", "account.global-ssh-keys.help": "Bir projeye SSH ile bağlanmak için şu adresi kullanın username@host: [project-id-without-dashes]@ssh.cocalc.com Proje id'si tireler olmadan, SSH anahtarlarıyla ilgili proje ayarları bölümünde bulunabilir. Projeler arasında SSH yapmak için [project-id-without-dashes]@ssh kullanın", @@ -66,13 +66,13 @@ "account.keyboard-shortcuts.shortcut.split-view-sagews": "Sage çalışma sayfasında bölünmüş görünüm", "account.keyboard-shortcuts.shortcut.toggle-comment": "Yorum satırını değiştir", "account.other-settings._page_size.label": "Sayfa başına dosya sayısı", - "account.other-settings.browser_performance.title": "Tarayıcı", + "account.other-settings.auto_focus": "Otomatik Odak Metin Girişi: metin giriş alanlarını göründüklerinde otomatik olarak odakla (ör. dosya gezgini, projeler, ...)", "account.other-settings.button_tooltips": "Düğme İpuçlarını Gizle: bazı düğme ipuçlarını gizler (bu sadece kısmi)", "account.other-settings.confirm_close": "Kapatmayı Onayla: tarayıcı penceresini kapatmadan önce her zaman onay iste", - "account.other-settings.content_display.title": "İçerik Görüntüleme", "account.other-settings.default_file_sort.by_name": "Ada göre sırala", "account.other-settings.default_file_sort.by_time": "Zamana göre sırala", "account.other-settings.default_file_sort.label": "Varsayılan dosya sıralaması", + "account.other-settings.dim_file_extensions": "Dosya uzantılarını soluklaştır: dosya uzantılarını gri yaparak adlarının öne çıkmasını sağla.", "account.other-settings.file_popovers": "Dosya Sekmesi Açılır Pencerelerini Gizle: dosya sekmelerinin üzerindeki açılır pencereleri gösterme", "account.other-settings.filename_generator.description": "Otomatik olarak oluşturulan dosya adlarının nasıl oluşturulacağını seçin. Özellikle, onları benzersiz yapmak veya mevcut zamanı eklemek için.", "account.other-settings.filename_generator.label": "Dosya adı oluşturucu", @@ -85,12 +85,9 @@ "account.other-settings.llm.title": "AI Ayarları", "account.other-settings.markdown_codebar": "Tüm markdown belgelerinde markdown kod çubuğunu devre dışı bırak. Bunu işaretlemek, çitlenmiş kod bloklarındaki ekstra çalıştır, kopyala ve açıkla düğmelerini gizler.", "account.other-settings.mask_files": "Dosya maskesi: Dosya görüntüleyicide muhtemelen açmak istemediğiniz dosyaları gri renkte göster", - "account.other-settings.messages.title": "Mesajlar", "account.other-settings.project_popovers": "Proje Sekmesi Açılır Pencerelerini Gizle: proje sekmelerinin üzerindeki açılır pencereleri gösterme", - "account.other-settings.projects.title": "Projeler", "account.other-settings.standby_timeout": "Bekleme zaman aşımı", "account.other-settings.symbol_bar_labels": "Sembol Çubuğu Etiketlerini Göster: çerçeve düzenleyici sembol çubuğunda etiketleri göster", - "account.other-settings.theme": "Tema", "account.other-settings.theme.antd.animations": "Animasyonlar: bazı unsurları, örneğin düğmeleri kısaca canlandır", "account.other-settings.theme.antd.color_scheme": "Renk Şeması: varsayılan renkler yerine marka renklerini kullan", "account.other-settings.theme.antd.compact": "Kompakt Tasarım: daha kompakt bir tasarım kullan", @@ -128,6 +125,7 @@ "account.settings.overview.licenses": "Yazılım lisanslarını ve erişim izinlerini yönetin.", "account.settings.overview.other": "Çeşitli ayarlar ve seçenekler.", "account.settings.overview.payg": "Kullandıkça öde kullanımını ve faturalandırmayı yapılandır.", + "account.settings.overview.payment_methods": "Kayıtlı ödeme yöntemlerinizi yönetin veya yenilerini ekleyin.", "account.settings.overview.payments": "Ödeme yöntemlerini ve işlem geçmişini yönet.", "account.settings.overview.profile": "Kişisel bilgilerinizi, avatarınızı ve hesap ayrıntılarınızı yönetin.", "account.settings.overview.purchases": "Satın alma geçmişini ve makbuzları görüntüle.", @@ -135,6 +133,7 @@ "account.settings.overview.subscriptions": "Aktif aboneliklerinizi görüntüleyin ve yönetin.", "account.settings.overview.support": "Destek taleplerine ve yardım kaynaklarına erişin.", "account.settings.overview.title": "Ayarlar Genel Bakış", + "account.settings.overview.upgrades": "Eski kota yükseltmelerinizi yönetin.", "account.settings.sso.account_is_linked": "Hesabınız bağlantılı (bağlantıyı kaldırmak için tıklayın)", "account.settings.sso.link_your_account": "{is_anonymous, select, true {Hesabınızı kullanarak kaydolun} other {Hesabınızı bağlamak için tıklayın}}", "account.settings.unlisted.label": "Liste Dışı: yalnızca tam bir e-posta adresi eşleşmesiyle bulunabilirsiniz", @@ -155,6 +154,9 @@ "ai-generate-document.modal.title": "Yapay Zeka kullanarak bir {docName} Belgesi oluştur", "ai-generator.select_llm": "Dil modelini seç", "app.fullscreen-button.tooltip": "Tam ekran modu, mevcut belge veya sayfaya odaklanılmış.", + "app.hotkey.dialog.help_text": "Yukarıdaki çerçevelere tıklayın • 0 tuşu sohbeti açar/kapatır • 1–9 tuşları çerçevelere odaklanır • Aramak için yazın • ↑↓ gezin • Açmak için Enter • Kapatmak için ESC", + "app.hotkey.dialog.search_placeholder": "Dosyaları ve sayfaları ara...", + "app.hotkey.dialog.title": "Hızlı Gezinme", "app.verify-email-banner.edit": "E-posta adresi yanlışsa, lütfen hesap ayarlarında düzenleyin.", "app.verify-email-banner.help.text": "Çalışan bir e-posta adresine sahip olmak önemlidir. Şifre sıfırlama, mesaj gönderme, fatura bildirimleri ve destek için kullanıyoruz. Bilgilendirilmek için e-postanızın doğru olduğundan emin olun.", "app.verify-email-banner.text": "{sent, select, true {E-posta Gönderildi! Lütfen e-posta gelen kutunuzu (ve belki spam klasörünü) kontrol edin ve onay bağlantısına tıklayın.} other {Lütfen e-posta adresinizi kontrol edin ve doğrulayın:}}", @@ -988,6 +990,7 @@ "labels.config": "Yapılandırma", "labels.configuration": "Yapılandırma", "labels.configuration.short": "Yapılandırma", + "labels.connected": "Bağlandı", "labels.connecting": "Bağlanıyor", "labels.connection": "Bağlantı", "labels.copied": "kopyalandı", @@ -1016,6 +1019,7 @@ "labels.environment": "Ortam", "labels.explorer": "Gezer", "labels.file_explorer": "Dosya Gezgini", + "labels.file_use_notifications": "Dosya Kullanım Bildirimleri", "labels.files": "Dosyalar", "labels.folder": "klasör", "labels.frame-editors.title-bar.save_label": "{type, select, is_public {Herkese Açık} read_only {Salt Okunur} other {Kaydet}}", @@ -1095,6 +1099,7 @@ "labels.project.settings.stop-project.label": "Durdur{short, select, true {} other { Proje}}…", "labels.project.settings.stop-project.ok": "Evet, projeyi durdur", "labels.projects": "Projeler", + "labels.public_paths": "Genel Yollar", "labels.published_files": "Yayınlanan Dosyalar", "labels.purchases": "Satın Alımlar", "labels.ready": "Hazır", @@ -1423,7 +1428,6 @@ "projects.create-project.helpTxt": "Bir başlık seçin. Daha sonra kolayca değiştirebilirsiniz!", "projects.create-project.requireLicense": "Ek projeler oluşturmak için bir lisans gereklidir.", "projects.filename-search.placeholder": "Düzenlediğiniz dosya adlarını arayın...", - "projects.list.no_starred_found": "Yıldızlı proje bulunamadı. Favori projelerinizi işaretlemek için proje başlıklarının yanındaki yıldız simgesini kullanın.", "projects.load-all.label": "Tüm projeleri göster...", "projects.operations.clear-filter": "Filtreyi Temizle", "projects.operations.delete.button": "{deleted, select, true {Tümünü Geri Al} other {Tümünü Sil}}", @@ -1455,7 +1459,9 @@ "projects.table-controls.hashtags.placeholder": "Etiketlere göre filtrele...", "projects.table-controls.hidden.label": "Gizli", "projects.table-controls.search.placeholder": "Projeleri ara...", + "projects.table.keyboard-row-hint": "Proje {title}. Hareket etmek için Yukarı ve Aşağı oklarını kullanın; açmak için Enter veya Boşluk tuşuna basın.", "projects.table.last-edited": "Son Düzenleme", + "projects.table.untitled": "Adsız", "purchases.automatic-payments-warning.description": "Otomatik ödemeler çok daha uygun, zaman kazandırır ve aboneliklerin kazara iptal edilmesini önler.", "purchases.automatic-payments-warning.title": "Otomatik ödemeler bir abonelik için GEREKLİ DEĞİLDİR", "purchases.automatic-payments.are-enabled": "Otomatik Ödemeler Etkinleştirildi", diff --git a/src/packages/frontend/i18n/trans/zh_CN.json b/src/packages/frontend/i18n/trans/zh_CN.json index 66264c8a02d..e0498d5ad55 100644 --- a/src/packages/frontend/i18n/trans/zh_CN.json +++ b/src/packages/frontend/i18n/trans/zh_CN.json @@ -5,6 +5,8 @@ "account.account_page.translation.info.title": "翻译信息", "account.account-button.confirm.ok": "是,退出", "account.account-button.confirm.title": "要退出您的账户吗", + "account.appearance.accessibility.enabled": "启用辅助功能模式:优化用户界面以支持辅助功能", + "account.appearance.accessibility.title": "无障碍", "account.appearance.user_interface.title": "用户界面", "account.delete-account.alert.description": "您将立即失去对所有项目的访问权限,所有订阅将被取消,所有未用完的积分将丢失。{br} {hr} 要删除您的账户,请首先在下方输入“{required_text}”:", "account.delete-account.alert.message": "您确定要删除您的账户吗?", @@ -31,13 +33,11 @@ "account.editor-setting.checkbox.strip_trailing_whitespace": "每次保存文件时删除", "account.editor-settings-autosave-interval.label": "自动保存间隔", "account.editor-settings.basic.title": "基本设置", - "account.editor-settings.color-schemes.label": "编辑器配色方案", "account.editor-settings.color-schemes.panel_title": "编辑器配色方案", "account.editor-settings.font-size.label": "默认全局字体大小", "account.editor-settings.indent-size.label": "缩进大小", "account.editor-settings.keyboard-bindings.label": "编辑器键盘绑定", "account.editor-settings.keyboard.title": "键盘", - "account.editor-settings.title": "编辑器", "account.editor-settings.x11-keyboard-variant.label": "键盘变体(用于X11桌面)", "account.editor-settings.x11-physical-keyboard.label": "键盘布局(用于X11桌面)", "account.global-ssh-keys.help": "要 SSH 进入一个项目,请使用以下 username@host: [project-id-without-dashes]@ssh.cocalc.com 无破折号的项目 ID 可以在项目设置中关于 SSH 密钥的部分找到。要在项目之间 SSH,请使用 [project-id-without-dashes]@ssh", @@ -66,13 +66,13 @@ "account.keyboard-shortcuts.shortcut.split-view-sagews": "在 Sage 工作表中分割视图", "account.keyboard-shortcuts.shortcut.toggle-comment": "切换注释选择", "account.other-settings._page_size.label": "每页文件数量", - "account.other-settings.browser_performance.title": "浏览器", + "account.other-settings.auto_focus": "自动聚焦文本输入:文本输入字段出现时自动聚焦(例如,文件浏览器,项目,...)", "account.other-settings.button_tooltips": "隐藏按钮提示:隐藏部分按钮提示(这只是部分隐藏)", "account.other-settings.confirm_close": "确认关闭:在关闭浏览器窗口前始终要求确认", - "account.other-settings.content_display.title": "内容显示", "account.other-settings.default_file_sort.by_name": "按名称排序", "account.other-settings.default_file_sort.by_time": "按时间排序", "account.other-settings.default_file_sort.label": "默认文件排序", + "account.other-settings.dim_file_extensions": "文件扩展名变暗:将文件扩展名变灰,以突出其名称。", "account.other-settings.file_popovers": "隐藏文件标签弹出窗口:不在文件标签上显示弹出窗口", "account.other-settings.filename_generator.description": "选择如何生成自动生成的文件名。特别是,使它们唯一或包含当前时间。", "account.other-settings.filename_generator.label": "文件名生成器", @@ -85,12 +85,9 @@ "account.other-settings.llm.title": "AI设置", "account.other-settings.markdown_codebar": "禁用markdown代码栏 在所有markdown文档中。选中此项会隐藏围栏代码块中的额外运行、复制和解释按钮。", "account.other-settings.mask_files": "屏蔽文件:在文件查看器中将您可能不想打开的文件置灰", - "account.other-settings.messages.title": "消息", "account.other-settings.project_popovers": "隐藏项目标签弹出框:不在项目标签上显示弹出框", - "account.other-settings.projects.title": "项目", "account.other-settings.standby_timeout": "待机超时", "account.other-settings.symbol_bar_labels": "显示符号栏标签:在框架编辑器符号栏中显示标签", - "account.other-settings.theme": "主题", "account.other-settings.theme.antd.animations": "动画:简要动画某些方面,例如按钮", "account.other-settings.theme.antd.color_scheme": "配色方案: 使用品牌颜色而非默认颜色", "account.other-settings.theme.antd.compact": "紧凑设计:使用更紧凑的设计", @@ -128,6 +125,7 @@ "account.settings.overview.licenses": "管理软件许可证和访问权限。", "account.settings.overview.other": "杂项设置和选项。", "account.settings.overview.payg": "配置按需付费使用和账单。", + "account.settings.overview.payment_methods": "管理您已保存的支付方式或添加新的支付方式。", "account.settings.overview.payments": "管理支付方式和交易历史。", "account.settings.overview.profile": "管理您的个人信息、头像和账户详情。", "account.settings.overview.purchases": "查看购买历史和收据。", @@ -135,6 +133,7 @@ "account.settings.overview.subscriptions": "查看和管理您的有效订阅。", "account.settings.overview.support": "访问支持票据和帮助资源。", "account.settings.overview.title": "设置概览", + "account.settings.overview.upgrades": "管理您的旧版配额升级。", "account.settings.sso.account_is_linked": "您的账户已关联(点击以取消关联)", "account.settings.sso.link_your_account": "{is_anonymous, select, true {使用您的账户注册} other {点击链接您的账户}}", "account.settings.unlisted.label": "未列出:只有通过精确的电子邮件地址匹配才能找到您", @@ -155,6 +154,9 @@ "ai-generate-document.modal.title": "使用AI生成{docName}文档", "ai-generator.select_llm": "选择语言模型", "app.fullscreen-button.tooltip": "全屏模式,专注于当前文档或页面", + "app.hotkey.dialog.help_text": "单击上方的框架 • 按键 0 切换聊天 • 按键 1–9 聚焦框架 • 输入以搜索 • ↑↓ 导航 • 回车以打开 • ESC 关闭", + "app.hotkey.dialog.search_placeholder": "搜索文件和页面...", + "app.hotkey.dialog.title": "快速导航", "app.verify-email-banner.edit": "如果电子邮件地址错误,请在账户设置中编辑。", "app.verify-email-banner.help.text": "拥有一个有效的电子邮件地址非常重要。我们用它来重置密码、发送消息、账单通知和支持。请确保您的电子邮件正确以保持信息畅通。", "app.verify-email-banner.text": "{sent, select, true {邮件已发送!请检查您的电子邮箱收件箱(可能还有垃圾邮件)并点击确认链接。} other {请检查并验证您的电子邮箱地址:}}", @@ -988,6 +990,7 @@ "labels.config": "配置", "labels.configuration": "配置", "labels.configuration.short": "配置", + "labels.connected": "已连接", "labels.connecting": "连接中", "labels.connection": "连接", "labels.copied": "已复制", @@ -1016,6 +1019,7 @@ "labels.environment": "环境", "labels.explorer": "文件", "labels.file_explorer": "文件资源管理器", + "labels.file_use_notifications": "文件使用通知", "labels.files": "文件", "labels.folder": "文件夹", "labels.frame-editors.title-bar.save_label": "{type, select, is_public {公开} read_only {只读} other {保存}}", @@ -1095,6 +1099,7 @@ "labels.project.settings.stop-project.label": "停止{short, select, true {} other {项目}}…", "labels.project.settings.stop-project.ok": "是,停止项目", "labels.projects": "项目", + "labels.public_paths": "公共路径", "labels.published_files": "已发布文件", "labels.purchases": "购买", "labels.ready": "准备好", @@ -1423,7 +1428,6 @@ "projects.create-project.helpTxt": "选择一个标题。您可以稍后轻松更改!", "projects.create-project.requireLicense": "创建额外的项目需要许可证。", "projects.filename-search.placeholder": "搜索你编辑过的文件名", - "projects.list.no_starred_found": "未找到加星标的项目。使用项目标题旁边的星标图标来收藏您喜欢的项目。", "projects.load-all.label": "显示所有项目...", "projects.operations.clear-filter": "清除筛选器", "projects.operations.delete.button": "{deleted, select, true {全部取消删除} other {全部删除}}", @@ -1455,7 +1459,9 @@ "projects.table-controls.hashtags.placeholder": "按标签过滤...", "projects.table-controls.hidden.label": "隐藏", "projects.table-controls.search.placeholder": "搜索项目...", + "projects.table.keyboard-row-hint": "项目 {title}。使用向上和向下箭头移动;按 Enter 或空格键打开。", "projects.table.last-edited": "上次编辑", + "projects.table.untitled": "无标题", "purchases.automatic-payments-warning.description": "自动支付更加方便,可以节省时间,并且确保订阅不会意外取消。", "purchases.automatic-payments-warning.title": "自动付款不需要订阅", "purchases.automatic-payments.are-enabled": "自动付款已启用", diff --git a/src/packages/frontend/index.sass b/src/packages/frontend/index.sass index 2392abe4442..4338d7f430c 100644 --- a/src/packages/frontend/index.sass +++ b/src/packages/frontend/index.sass @@ -26,6 +26,7 @@ @use 'frame-editors/_style' as frame-editors-style @use 'notifications/_style' as notifications-style @use 'account-button' +@use 'account/_account' as account-account @use 'admin/_style' as admin-style @use 'antd_fix' diff --git a/src/packages/frontend/package.json b/src/packages/frontend/package.json index 56f237e6522..63d7f8b3b06 100644 --- a/src/packages/frontend/package.json +++ b/src/packages/frontend/package.json @@ -116,7 +116,7 @@ "md5": "^2", "memoize-one": "^5.1.1", "mermaid": "^11.10.0", - "node-forge": "^1.0.0", + "node-forge": "^1.3.2", "onecolor": "^3.1.0", "pdfjs-dist": "^4.6.82", "plotly.js": "^2.29.1", diff --git a/src/packages/frontend/project/settings/datastore.tsx b/src/packages/frontend/project/settings/datastore.tsx index 7140e1d6a6e..277da6f2db1 100644 --- a/src/packages/frontend/project/settings/datastore.tsx +++ b/src/packages/frontend/project/settings/datastore.tsx @@ -1,5 +1,5 @@ /* - * This file is part of CoCalc: Copyright © 2021 – 2023 Sagemath, Inc. + * This file is part of CoCalc: Copyright © 2021 – 2025 Sagemath, Inc. * License: MS-RSL – see LICENSE.md for details */ @@ -21,6 +21,7 @@ import { Checkbox, Form, Input, + InputNumber, Modal, Popconfirm, Space, @@ -50,6 +51,7 @@ import Password, { } from "@cocalc/frontend/components/password"; import { labels } from "@cocalc/frontend/i18n"; import { webapp_client } from "@cocalc/frontend/webapp-client"; +import { PORT_MAX, PORT_MIN, validatePortNumber } from "@cocalc/util/consts"; import { DOC_CLOUD_STORAGE_URL } from "@cocalc/util/consts/project"; import { DATASTORE_TITLE } from "@cocalc/util/db-schema/site-defaults"; import { unreachable } from "@cocalc/util/misc"; @@ -78,6 +80,21 @@ const RULE_ALPHANUM = [ }, ]; +const RULE_PORT = [ + { + validator: (_: any, value: number | null) => { + if (value == null) return Promise.resolve(); + const port = validatePortNumber(value); + if (port == null) { + return Promise.reject( + `Port must be an integer between ${PORT_MIN} and ${PORT_MAX}.`, + ); + } + return Promise.resolve(); + }, + }, +]; + // convert the configuration from the DB to fields for the table function raw2configs(raw: { [name: string]: Config }): Config[] { const ret: Config[] = []; @@ -96,11 +113,15 @@ function raw2configs(raw: { [name: string]: Config }): Config[] { v.about = `Bucket: ${v.bucket}`; break; case "sshfs": - v.about = [ + const about_sshfs = [ `User: ${v.user}`, `Host: ${v.host}`, `Path: ${v.path ?? `/user/${v.user}`}`, - ].join("\n"); + ]; + if (v.port != null && v.port !== 22) { + about_sshfs.push(`Port: ${v.port}`); + } + v.about = about_sshfs.join("\n"); break; default: unreachable(v); @@ -175,6 +196,7 @@ export const Datastore: React.FC = React.memo((props: Props) => { user: "", host: "", path: "", + port: 22, }); break; default: @@ -308,6 +330,9 @@ export const Datastore: React.FC = React.memo((props: Props) => { const conf: Config = { ...record }; conf.secret = ""; delete conf.about; + if (conf.type === "sshfs" && conf.port == null) { + conf.port = 22; + } set_new_config(conf); set_form_readonly(conf.readonly ?? READONLY_DEFAULT); setEditMode(true); @@ -424,7 +449,7 @@ export const Datastore: React.FC = React.memo((props: Props) => { >
{" "} {record.readonly ? "Read-only" : "Read/write"}
@@ -588,9 +613,13 @@ export const Datastore: React.FC = React.memo((props: Props) => { } async function save_config(values: any): Promise { - values.readonly = form_readonly; + const config = { ...values, readonly: form_readonly }; + if ("port" in config) { + const port = validatePortNumber(config.port); + config.port = port ?? 22; + } try { - await set(values); + await set(config); } catch (err) { if (err) set_error(err); } @@ -774,6 +803,15 @@ function NewSSHFS({ > + + + = ({ @@ -40,7 +40,7 @@ export const DiskSpaceWarning: React.FC<{ project_id: string }> = ({ return null; } - // the disk_usage comes from the project.status datatbase entry – not the "project-status" synctable + // the disk_usage comes from the project.status database entry – not the "project-status" synctable const project_status = project.get("status"); const disk_usage = project_status?.get("disk_MB"); if (disk_usage == null) return null; @@ -57,7 +57,7 @@ export const DiskSpaceWarning: React.FC<{ project_id: string }> = ({ WARNING: This project is running out of disk space: only {disk_free} MB out of {quotas.disk_quota} MB available.{" "} - actions?.set_active_tab("settings")}> + actions?.set_active_tab("upgrades")}> Increase the "Disk Space" quota {" or "} diff --git a/src/packages/frontend/projects/projects-starred.tsx b/src/packages/frontend/projects/projects-starred.tsx index 3eba337478f..9d406c9b67b 100644 --- a/src/packages/frontend/projects/projects-starred.tsx +++ b/src/packages/frontend/projects/projects-starred.tsx @@ -21,7 +21,7 @@ import { import { CSS, useActions, useTypedRedux } from "@cocalc/frontend/app-framework"; import { Icon, TimeAgo } from "@cocalc/frontend/components"; -import { trunc } from "@cocalc/util/misc"; +import { sha1, trunc } from "@cocalc/util/misc"; import { COLORS } from "@cocalc/util/theme"; import { useBookmarkedProjects } from "./use-bookmarked-projects"; @@ -131,9 +131,7 @@ export function StarredProjectsBar() { title: project.get("title") ?? "Untitled", description: project.get("description") ?? "", last_edited: project.get("last_edited"), - state: project.get("state"), avatar_image_tiny: project.get("avatar_image_tiny"), - users: project.get("users"), color: project.get("color"), }; }) @@ -143,6 +141,24 @@ export function StarredProjectsBar() { return projects; }, [bookmarkedProjects, project_map]); + // Hash only the fields that impact layout so we can avoid unnecessary re-measurements. + const layoutKey = useMemo(() => { + if (starredProjects.length === 0) { + return ""; + } + const signature = starredProjects + .map((project) => + [ + project.project_id, + project.title, + project.color ?? "", + project.avatar_image_tiny ?? "", + ].join("|"), + ) + .join("::"); + return sha1(signature); + }, [starredProjects]); + // Drag and drop sensors const mouseSensor = useSensor(MouseSensor, { activationConstraint: { distance: 5 }, // 5px to activate drag @@ -215,7 +231,7 @@ export function StarredProjectsBar() { useLayoutEffect(() => { setMeasurementPhase(true); setVisibleCount(0); - }, [starredProjects]); + }, [layoutKey]); // Measure button widths from hidden container and calculate visible count useLayoutEffect(() => { diff --git a/src/packages/frontend/projects/util.tsx b/src/packages/frontend/projects/util.tsx index 8abdbb4360c..6971ad7fd52 100644 --- a/src/packages/frontend/projects/util.tsx +++ b/src/packages/frontend/projects/util.tsx @@ -348,8 +348,10 @@ export function useFilesMenuItems( return files.map((file) => { const filename = typeof file === "string" ? file : file.filename; - const info = file_options(filename); - const icon: IconName = info?.icon ?? "file"; + const isDirectory = filename.endsWith("/"); + const icon: IconName = isDirectory + ? "folder-open" + : (file_options(filename)?.icon ?? "file"); const label = labelStyle ? ( {trunc_middle(filename, truncLength)} diff --git a/src/packages/frontend/user-tracking.ts b/src/packages/frontend/user-tracking.ts index b95e8db6d4d..7b7e913c0fe 100644 --- a/src/packages/frontend/user-tracking.ts +++ b/src/packages/frontend/user-tracking.ts @@ -7,12 +7,17 @@ // client code doesn't have to import webapp_client everywhere, and we can // completely change this if we want. -import { query, server_time } from "./frame-editors/generic/client"; -import { analytics_cookie_name as analytics, uuid } from "@cocalc/util/misc"; -import { redux } from "./app-framework"; +import { redux } from "@cocalc/frontend/app-framework"; +import { + query, + server_time, +} from "@cocalc/frontend/frame-editors/generic/client"; +import { get_cookie } from "@cocalc/frontend/misc"; +import { webapp_client } from "@cocalc/frontend/webapp-client"; +import { uuid } from "@cocalc/util/misc"; import { version } from "@cocalc/util/smc-version"; -import { get_cookie } from "./misc"; -import { webapp_client } from "./webapp-client"; + +import { ANALYTICS_COOKIE_NAME } from "@cocalc/util/consts"; export async function log(eventName: string, payload: any): Promise { const central_log = { @@ -20,18 +25,15 @@ export async function log(eventName: string, payload: any): Promise { event: `webapp-${eventName}`, value: { account_id: redux.getStore("account")?.get("account_id"), - analytics_cookie: get_cookie(analytics), + analytics_cookie: get_cookie(ANALYTICS_COOKIE_NAME), cocalc_version: version, ...payload, }, time: server_time(), }; + try { - await query({ - query: { - central_log, - }, - }); + await query({ query: { central_log } }); } catch (err) { console.warn("WARNING: Failed to write log event -- ", central_log); } diff --git a/src/packages/hub/analytics-script.ts b/src/packages/hub/analytics-script.ts index 01bddbca96c..ffaf21b61d9 100644 --- a/src/packages/hub/analytics-script.ts +++ b/src/packages/hub/analytics-script.ts @@ -15,13 +15,16 @@ * e.g. this filters the SSO auth pages, which are uninteresting referrals */ -// variable PREFIX, NAME, DOMAIN and ID are injected in the hub's http server -declare var NAME, ID, DOMAIN, PREFIX, window, document; +// variable PREFIX, NAME, DOMAIN, ID, and ANALYTICS_ENABLED are injected in the hub's http server +declare var NAME, ID, DOMAIN, PREFIX, ANALYTICS_ENABLED, window, document; -// write cookie. it would be cool to set this via the http request itself, -// but for reasons I don't know it doesn't work across subdomains. -const maxage = 7 * 24 * 60 * 60; // 7 days -document.cookie = `${NAME}=${ID}; path=/; domain=${DOMAIN}; max-age=${maxage}`; +// write cookie only if analytics is enabled (for privacy in cookieless mode) +if (ANALYTICS_ENABLED) { + // it would be cool to set this via the http request itself, + // but for reasons I don't know it doesn't work across subdomains. + const maxage = 7 * 24 * 60 * 60; // 7 days + document.cookie = `${NAME}=${ID}; path=/; domain=${DOMAIN}; max-age=${maxage}`; +} const { href, protocol, host, pathname } = window.location; diff --git a/src/packages/hub/analytics.ts b/src/packages/hub/analytics.ts index 936710c669b..ea4f664bcb2 100644 --- a/src/packages/hub/analytics.ts +++ b/src/packages/hub/analytics.ts @@ -3,36 +3,41 @@ * License: MS-RSL – see LICENSE.md for details */ -import { join } from "path"; -import ms from "ms"; -import { isEqual } from "lodash"; -import { Router, json } from "express"; -import { - analytics_cookie_name, - is_valid_uuid_string, - uuid, -} from "@cocalc/util/misc"; -import type { PostgreSQL } from "@cocalc/database/postgres/types"; -import { get_server_settings } from "@cocalc/database/postgres/server-settings"; -import { pii_retention_to_future } from "@cocalc/database/postgres/pii"; +import cors from "cors"; // express-js cors plugin +import { json, Router } from "express"; import * as fs from "fs"; -const UglifyJS = require("uglify-js"); -// express-js cors plugin: -import cors from "cors"; +import { isEqual } from "lodash"; +import ms from "ms"; import { - parseDomain, fromUrl, - ParseResultType, + parseDomain, ParseResult, + ParseResultType, } from "parse-domain"; +import { join } from "path"; +const UglifyJS = require("uglify-js"); + +import { is_valid_uuid_string, uuid } from "@cocalc/util/misc"; + +import { pii_retention_to_future } from "@cocalc/database/postgres/pii"; +import { get_server_settings } from "@cocalc/database/postgres/server-settings"; +import type { PostgreSQL } from "@cocalc/database/postgres/types"; +import { ANALYTICS_COOKIE_NAME } from "@cocalc/util/consts"; + import { getLogger } from "./logger"; +// Rate limiting for analytics data - 10 entries per second +const RATE_LIMIT_ENTRIES_PER_SECOND = 10; +const RATE_LIMIT_WINDOW_MS = 1000; +let rateLimitCounter = 0; +let rateLimitWindowStart = Date.now(); + // Minifying analytics-script.js. Note // that this file analytics.ts gets compiled to // dist/analytics.js and also analytics-script.ts // gets compiled to dist/analytics-script.js. const result = UglifyJS.minify( - fs.readFileSync(join(__dirname, "analytics-script.js")).toString() + fs.readFileSync(join(__dirname, "analytics-script.js")).toString(), ); if (result.error) { throw Error(`Error minifying analytics-script.js -- ${result.error}`); @@ -44,6 +49,25 @@ function create_log(name) { return getLogger(`analytics.${name}`).debug; } +// Rate limiting check - returns true if request should be allowed +function checkRateLimit(): boolean { + const now = Date.now(); + + // Reset counter if window has passed + if (now - rateLimitWindowStart >= RATE_LIMIT_WINDOW_MS) { + rateLimitCounter = 0; + rateLimitWindowStart = now; + } + + // Check if we're under the limit + if (rateLimitCounter < RATE_LIMIT_ENTRIES_PER_SECOND) { + rateLimitCounter++; + return true; + } + + return false; +} + /* // base64 encoded PNG (white), 1x1 pixels const _PNG_DATA = @@ -76,39 +100,65 @@ function sanitize(obj: object, recursive = 0): any { // record analytics data // case 1: store "token" with associated "data", referrer, utm, etc. // case 2: update entry with a known "token" with the account_id + 2nd timestamp +// case 3: cookieless tracking - store data without user association function recordAnalyticsData( db: any, - token: string, + token: string | null, payload: object | undefined, - pii_retention: number | false + pii_retention: number | false, ): void { if (payload == null) return; - if (!is_valid_uuid_string(token)) return; + + // Rate limiting check - applies to all analytics data recording + if (!checkRateLimit()) { + const dbg = create_log("record"); + dbg("Rate limit exceeded, dropping analytics data"); + return; + } + const dbg = create_log("record"); dbg({ token, payload }); + // sanitize data (limits size and number of characters) const rec_data = sanitize(payload); dbg("sanitized data", rec_data); const expire = pii_retention_to_future(pii_retention); - if (rec_data.account_id != null) { - // dbg("update analytics", rec_data.account_id); - // only update if account id isn't already set! - db._query({ - query: "UPDATE analytics", - where: [{ "token = $::UUID": token }, "account_id IS NULL"], - set: { - "account_id :: UUID": rec_data.account_id, - "account_id_time :: TIMESTAMP": new Date(), - "expire :: TIMESTAMP": expire, - }, - }); + // Cookie-based tracking (with user association) + if (token != null && is_valid_uuid_string(token)) { + if (rec_data.account_id != null) { + // dbg("update analytics", rec_data.account_id); + // only update if account id isn't already set! + db._query({ + query: "UPDATE analytics", + where: [{ "token = $::UUID": token }, "account_id IS NULL"], + set: { + "account_id :: UUID": rec_data.account_id, + "account_id_time :: TIMESTAMP": new Date(), + "expire :: TIMESTAMP": expire, + }, + }); + } else { + db._query({ + query: "INSERT INTO analytics", + values: { + "token :: UUID": token, + "data :: JSONB": rec_data, + "data_time :: TIMESTAMP": new Date(), + "expire :: TIMESTAMP": expire, + }, + conflict: "token", + }); + } } else { + // Cookieless tracking (no user association, privacy-focused) + // Generate a random token for this single entry + const anonymousToken = uuid(); db._query({ query: "INSERT INTO analytics", values: { - "token :: UUID": token, - "data :: JSONB": rec_data, + "token :: UUID": anonymousToken, + "data :: JSONB": { ...rec_data, cookieless: true }, "data_time :: TIMESTAMP": new Date(), "expire :: TIMESTAMP": expire, }, @@ -118,10 +168,10 @@ function recordAnalyticsData( } // could throw an error -function check_cors( +function checkCORS( origin: string | undefined, dns_parsed: ParseResult, - dbg: Function + dbg: Function, ): boolean { // no origin, e.g. when loaded as usual in a script tag if (origin == null) return true; @@ -184,7 +234,7 @@ import base_path from "@cocalc/backend/base-path"; export async function initAnalytics( router: Router, - database: PostgreSQL + database: PostgreSQL, ): Promise { const dbg = create_log("analytics_js/cors"); @@ -193,6 +243,7 @@ export async function initAnalytics( const DNS = settings.dns; const dns_parsed = parseDomain(DNS); const pii_retention = settings.pii_retention; + const analytics_enabled = settings.analytics_cookie; if ( dns_parsed.type !== ParseResultType.Listed && @@ -201,7 +252,7 @@ export async function initAnalytics( dbg( `WARNING: the configured domain name ${DNS} cannot be parsed properly. ` + `Please fix it in Admin → Site Settings!\n` + - `dns_parsed="${JSON.stringify(dns_parsed)}}"` + `dns_parsed="${JSON.stringify(dns_parsed)}}"`, ); } @@ -213,7 +264,7 @@ export async function initAnalytics( origin: function (origin, cb) { dbg(`check origin='${origin}'`); try { - if (check_cors(origin, dns_parsed, dbg)) { + if (checkCORS(origin, dns_parsed, dbg)) { cb(null, true); } else { cb(`origin="${origin}" is not allowed`, false); @@ -235,27 +286,25 @@ export async function initAnalytics( // in case user was already here, do not send it again. // only the first hit is interesting. dbg( - `/analytics.js GET analytics_cookie='${req.cookies[analytics_cookie_name]}'` + `/analytics.js GET analytics_cookie='${req.cookies[ANALYTICS_COOKIE_NAME]}'`, ); - if (!req.cookies[analytics_cookie_name]) { - // No analytics cookie is set, so we set one. - // We always set this despite any issues with parsing or - // or whether or not we are actually using the analytics.js - // script, since it's *also* useful to have this cookie set - // for other purposes, e.g., logging. + if (!req.cookies[ANALYTICS_COOKIE_NAME] && analytics_enabled) { + // No analytics cookie is set and cookies are enabled, so we set one. + // When analytics_enabled is false, we skip setting cookies to enable + // cookieless tracking for better privacy. setAnalyticsCookie(res /* DNS */); } - // also, don't write a script if the DNS is not valid + // Return NOOP if DNS is invalid, or if cookies are enabled and already exist if ( - req.cookies[analytics_cookie_name] || - dns_parsed.type !== ParseResultType.Listed + dns_parsed.type !== ParseResultType.Listed || + (analytics_enabled && req.cookies[ANALYTICS_COOKIE_NAME]) ) { // cache for 6 hours -- max-age has unit seconds res.header( "Cache-Control", - `private, max-age=${6 * 60 * 60}, must-revalidate` + `private, max-age=${6 * 60 * 60}, must-revalidate`, ); res.write("// NOOP"); res.end(); @@ -267,11 +316,12 @@ export async function initAnalytics( res.header("Cache-Control", "no-cache, no-store"); const DOMAIN = `${dns_parsed.domain}.${dns_parsed.topLevelDomains.join( - "." + ".", )}`; - res.write(`var NAME = '${analytics_cookie_name}';\n`); + res.write(`var NAME = '${ANALYTICS_COOKIE_NAME}';\n`); res.write(`var ID = '${uuid()}';\n`); res.write(`var DOMAIN = '${DOMAIN}';\n`); + res.write(`var ANALYTICS_ENABLED = ${analytics_enabled};\n`); // BASE_PATH if (req.query.fqd === "false") { res.write(`var PREFIX = '${base_path}';\n`); @@ -301,17 +351,17 @@ export async function initAnalytics( */ router.post("/analytics.js", cors(analytics_cors), function (req, res): void { - // check if token is in the cookie (see above) - // if not, ignore it - const token = req.cookies[analytics_cookie_name]; + const token = req.cookies[ANALYTICS_COOKIE_NAME]; dbg(`/analytics.js POST token='${token}'`); - if (token) { - // req.body is an object (json middlewhere somewhere?) - // e.g. {"utm":{"source":"asdfasdf"},"landing":"https://cocalc.com/..."} - // ATTN key/values could be malicious - // record it, there is no need for a callback - recordAnalyticsData(database, token, req.body, pii_retention); - } + + // req.body is an object (json middleware somewhere?) + // e.g. {"utm":{"source":"asdfasdf"},"landing":"https://cocalc.com/..."} + // ATTN key/values could be malicious + + // Always record analytics data - either with token (cookie-based) or without (cookieless) + // The recordAnalyticsData function handles both cases + recordAnalyticsData(database, token || null, req.body, pii_retention); + res.end(); }); @@ -324,7 +374,7 @@ function setAnalyticsCookie(res /* DNS: string */): void { // set the cookie (TODO sign it? that would be good so that // users can fake a cookie.) const analytics_token = uuid(); - res.cookie(analytics_cookie_name, analytics_token, { + res.cookie(ANALYTICS_COOKIE_NAME, analytics_token, { path: "/", maxAge: ms("7 days"), // httpOnly: true, diff --git a/src/packages/hub/package.json b/src/packages/hub/package.json index 52ff57d4259..f7171bf6184 100644 --- a/src/packages/hub/package.json +++ b/src/packages/hub/package.json @@ -41,7 +41,7 @@ "uglify-js": "^3.14.1", "underscore": "^1.12.1", "uuid": "^8.3.2", - "validator": "^13.15.20", + "validator": "^13.15.22", "webpack-dev-middleware": "^7.4.2", "webpack-hot-middleware": "^2.26.1" }, diff --git a/src/packages/hub/run/test-create-admin.ts b/src/packages/hub/run/test-create-admin.ts new file mode 100644 index 00000000000..a84db7b7c83 --- /dev/null +++ b/src/packages/hub/run/test-create-admin.ts @@ -0,0 +1,69 @@ +#!/usr/bin/env node + +/* + * Script to create a test admin account and API key for CI testing. + * This is used in GitHub Actions to set up cocalc-api tests. + */ + +import { v4 as uuidv4 } from "uuid"; + +import createAccount from "@cocalc/server/accounts/create-account"; +import manageApiKeys from "@cocalc/server/api/manage"; +import getPool from "@cocalc/database/pool"; + +async function main() { + const account_id = uuidv4(); + const email = "ci-admin@cocalc.test"; + const password = "testpassword"; // dummy password + const firstName = "CI"; + const lastName = "Admin"; + + console.error(`Creating admin account ${account_id}...`); + + // Create the account + await createAccount({ + email, + password, + firstName, + lastName, + account_id, + tags: [], + signupReason: "CI testing", + noFirstProject: true, + }); + + // Set as admin + const pool = getPool(); + await pool.query("UPDATE accounts SET groups=$1 WHERE account_id=$2", [ + ["admin"], + account_id, + ]); + + console.error("Creating API key..."); + + // Create API key + const keys = await manageApiKeys({ + account_id, + action: "create", + name: "ci-testing", + }); + + if (!keys || keys.length === 0) { + throw new Error("Failed to create API key"); + } + + const apiKey = keys[0]; + if (!apiKey.secret) { + throw new Error("API key secret is missing"); + } + console.error(`API key created with id=${apiKey.id}: ${apiKey.secret}`); + console.error(`Last 6 chars: ${apiKey.secret.slice(-6)}`); + + // Output the account_id and API key for CI in format: UUID;api-key + process.stdout.write(`${account_id};${apiKey.secret}`); +} + +main().catch((err) => { + console.error("Error:", err); + process.exit(1); +}); diff --git a/src/packages/jupyter/kernel/launch-kernel.ts b/src/packages/jupyter/kernel/launch-kernel.ts index e4e179610d9..21b39e599b5 100644 --- a/src/packages/jupyter/kernel/launch-kernel.ts +++ b/src/packages/jupyter/kernel/launch-kernel.ts @@ -168,6 +168,11 @@ async function launchKernelSpec( } else { running_kernel = spawn(argv[0], argv.slice(1), full_spawn_options); } + + // Store kernel info for tracking + running_kernel.connectionFile = connectionFile; + running_kernel.kernel_spec = kernel_spec; + spawned.push(running_kernel); running_kernel.on("error", (code, signal) => { @@ -221,6 +226,48 @@ async function ensureDirectoryExists(path: string) { // Clean up after any children created here const spawned: any[] = []; + +export interface RunningKernel { + pid: number; + connectionFile: string; + kernel_name?: string; +} + +export function listRunningKernels(): RunningKernel[] { + return spawned + .filter((child) => child.pid) + .map((child) => ({ + pid: child.pid, + connectionFile: child.connectionFile || "unknown", + kernel_name: child.kernel_spec?.name, + })); +} + +export function stopKernel(pid: number): boolean { + const index = spawned.findIndex((child) => child.pid === pid); + if (index === -1) { + return false; + } + + const child = spawned[index]; + try { + // Try to kill the process group first (negative PID) + process.kill(-child.pid, "SIGKILL"); + } catch (err) { + // If that fails, try killing the process directly + try { + child.kill("SIGKILL"); + } catch (err2) { + logger.debug(`stopKernel: failed to kill ${child.pid}: ${err2}`); + return false; + } + } + + // Remove from spawned array + spawned.splice(index, 1); + return true; +} + export function closeAll() { for (const child of spawned) { if (child.pid) { diff --git a/src/packages/next/components/landing/accessibility.tsx b/src/packages/next/components/landing/accessibility.tsx deleted file mode 100644 index 9fe7a4a1af9..00000000000 --- a/src/packages/next/components/landing/accessibility.tsx +++ /dev/null @@ -1,161 +0,0 @@ -import Markdown from "@cocalc/frontend/editors/slate/static-markdown"; - -export default function Accessibility() { - return ; -} - -const value = ` - -## Table of Contents - -| Criteria | Supporting features | Remarks and explanations | -| -------- | ------------------- | ------------------------ | -| [Section 1194.21 Software Applications and Operating Systems](#section-119421-software-applications-and-operating-systems) | Not applicable | | -| [Section 1194.22 Web-based Internet information and applications](#section-119422-web-based-internet-information-and-applications) | Supports with exceptions | We are always improving our website. We aim to meet or exceed universal design best practices and web accessibility standards. -| [Section 1194.23 Telecommunications Products](#section-119423-telecommunications-products)| Not applicable | | -| [Section 1194.24 Video and Multi-media Products](#section-119424-video-and-multi-media-products)| Not applicable | | -| [Section 1194.25 Self-Contained, Closed Products](#section-119425-self-contained-closed-products)| Not applicable | | -| [Section 1194.26 Desktop and Portable Computers](#section-119426-desktop-and-portable-computers)| Not applicable | | -| [Section 1194.31 Functional Performance Criteria](#section-119431-functional-performance-criteria) | Supports with exceptions | Most content is marked up for Assistive Technology. | -| [Section 1194.41 Information, Documentation and Support](#section-119441-information-documentation-and-support) | Supports | Documentation is freely available to all users via our online user manual and support is available through the CoCalc UI and via email. | - - -  -## Section 1194.21 Software Applications and Operating Systems - -| Criteria | Supporting features | Remarks and explanations | -| -------- | ------------------- | ------------------------ | -| (a) When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. | Not applicable | | -| (b) Applications shall not disrupt or disable activated features of other products that are identified as accessibility features, where those features are developed and documented according to industry standards. Applications also shall not disrupt or disable activated features of any operating system that are identified as accessibility features where the application programming interface for those accessibility features has been documented by the manufacturer of the operating system and is available to the product developer. | Not applicable | | -| (c) A well-defined on-screen indication of the current focus shall be provided that moves among interactive interface elements as the input focus changes. The focus shall be programmatically exposed so that Assistive Technology can track focus and focus changes. | Not applicable | | -| (d) Sufficient information about a user interface element including the identity, operation and state of the element shall be available to Assistive Technology. When an image represents a program element, the information conveyed by the image must also be available in text. | Not applicable | | -| (e) When bitmap images are used to identify controls, status indicators, or other programmatic elements, the meaning assigned to those images shall be consistent throughout an application's performance. | Not applicable | | -| (f) Textual information shall be provided through operating system functions for displaying text. The minimum information that shall be made available is text content, text input caret location, and text attributes. | Not applicable | | -| (g) Applications shall not override user selected contrast and color selections and other individual display attributes. | Not applicable | | -| (h) When animation is displayed, the information shall be displayable in at least one non-animated presentation mode at the option of the user. | Not applicable | | -| (i) Color coding shall not be used as the only means of conveying information, indicating an action, prompting a response, or distinguishing a visual element. | Not applicable | | -| (j) When a product permits a user to adjust color and contrast settings, a variety of color selections capable of producing a range of contrast levels shall be provided. | Not applicable | | -| (k) Software shall not use flashing or blinking text, objects, or other elements having a flash or blink frequency greater than 2 Hz and lower than 55 Hz. | Not applicable | | -| (l) When electronic forms are used, the form shall allow people using Assistive Technology to access the information, field elements, and functionality required for completion and submission of the form, including all directions and cues. | Not applicable | | - - - -  -## Section 1194.22 Web-based Internet information and applications - -| Criteria | Supporting features | Remarks and explanations | -| -------- | ------------------- | ------------------------ | -| (a) A text equivalent for every non-text element shall be provided (e.g., via “alt”, “longdesc”, or in element content). | Supports with exception | Most controls provide meaningful alternate text or descriptions.
Working towards supporting fully. | -| (b) Equivalent alternatives for any multimedia presentation shall be synchronized with the presentation. | Not applicable | | -| (c) Web pages shall be designed so that all information conveyed with color is also available without color, for example from context or markup. | Supports | The CoCalc user interface does not use color to distinguish essential controls. A multiplicity of editor color schemes are available to suit color vision restrictions of users. | -| (d) Documents shall be organized so they are readable without requiring an associated style sheet. | Not applicable | | -| (e) Redundant text links shall be provided for each active region of a server-side image map. | Not applicable | No server-side image maps are used. | -| (f) Client-side image maps shall be provided instead of server-side image maps except where the regions cannot be defined with an available geometric shape. | Not applicable | No client-side image maps are used. | -| (g) Row and column headers shall be identified for data tables. | Not applicable | There are no data tables in the control UI. | -| (h) Markup shall be used to associate data cells and header cells for data tables that have two or more logical levels of row or column headers. | Not applicable | There are no data tables in the control UI. | -| (i) Frames shall be titled with text that facilitates frame identification and navigation | Not applicable | Website does not contain Frames.
Some editor views include multiple panes, but these are not web Frames and their type is clearly identified at the top of the pane. | -| (j) Pages shall be designed to avoid causing the screen to flicker with a frequency greater than 2 Hz and lower than 55 Hz. | Supports | There is no blinking or flickering content in CoCalc, other than the text cursor, which blinks at approximately 1 Hz. | -| (k) A text-only page, with equivalent information or functionality, shall be provided to make a web site comply with the provisions of this part, when compliance cannot be accomplished in any other way. The content of the text-only page shall be updated whenever the primary page changes. | Not applicable | We do not provide alternative presentations or alternate pages - instead we ensure that the original page is accessible, i.e. we never have to create a text-only page. | -| (l) When pages utilize scripting languages to display content, or to create interface elements, the information provided by the script shall be identified with functional text that can be read by Assistive Technology. | Supports with exceptions | Some summary information is only available via mouse click / hover.| -| (m) When a web page requires that an applet, plug-in or other application be present on the client system to interpret page content, the page must provide a link to a plug-in or applet that complies with §1194.21(a) through (l). | Not applicable | Website does not contain applets or plug-ins. | -| (n) When electronic forms are designed to be completed on-line, the form shall allow people using Assistive Technology to access the information, field elements, and functionality required for completion and submission of the form, including all directions and cues. | Supports | All form fields are labeled and grouped logically. All form elements can be reached with keyboard. | -| (o) A method shall be provided that permits users to skip repetitive navigation links. | Supports | UI components that have repetitive navigation links, such as the Files list, have a search option allowing the user to skip to a desired link.| -| (p) When a timed response is required, the user shall be alerted and given sufficient time to indicate more time is required. | Not applicable | We do not require timed responses. | - - - -  -## Section 1194.23 Telecommunications Products - -| Criteria | Supporting features | Remarks and explanations | -| -------- | ------------------- | ------------------------ | -| (a) Telecommunications products or systems which provide a function allowing voice communication and which do not themselves provide a TTY functionality shall provide a standard non-acoustic connection point for TTYs. Microphones shall be capable of being turned on and off to allow the user to intermix speech with TTY use. | Not applicable | | -|(b) Telecommunications products which include voice communication functionality shall support all commonly used cross-manufacturer non-proprietary standard TTY signal protocols. | Not applicable | | -| (c) Voice mail, auto-attendant, and interactive voice response telecommunications systems shall be usable by TTY users with their TTYs. | Not applicable | | -| (d) Voice mail, messaging, auto-attendant, and interactive voice response telecommunications systems that require a response from a user within a time interval, shall give an alert when the time interval is about to run out, and shall provide sufficient time for the user to indicate more time is required. |Not applicable | | -| (e) Where provided, caller identification and similar telecommunications functions shall also be available for users of TTYs, and for users who cannot see displays. | Not applicable | | -| (f) For transmitted voice signals, telecommunications products shall provide a gain adjustable up to a minimum of 20 dB. For incremental volume control, at least one intermediate step of 12 dB of gain shall be provided. | Not applicable | | -| (g) If the telecommunications product allows a user to adjust the receive volume, a function shall be provided to automatically reset the volume to the default level after every use. | Not applicable | | -| (h) Where a telecommunications product delivers output by an audio transducer which is normally held up to the ear, a means for effective magnetic wireless coupling to hearing technologies shall be provided. | Not applicable | | -| (i) Interference to hearing technologies (including hearing aids, cochlear implants, and assistive listening devices) shall be reduced to the lowest possible level that allows a user of hearing technologies to utilize the telecommunications product. | Not applicable | | -| (j) Products that transmit or conduct information or communication, shall pass through cross-manufacturer, non-proprietary, industry-standard codes, translation protocols, formats or other information necessary to provide the information or communication in a usable format. Technologies which use encoding, signal compression, format transformation, or similar techniques shall not remove information needed for access or shall restore it upon delivery. | Not applicable | | -| (k)(1) Products which have mechanically operated controls or keys shall comply with the following: Controls and Keys shall be tactilely discernible without activating the controls or keys. | Not applicable | | -| (k)(2) Products which have mechanically operated controls or keys shall comply with the following: Controls and Keys shall be operable with one hand and shall not require tight grasping, pinching, twisting of the wrist. The force required to activate controls and keys shall be 5 lbs. (22.2N) maximum. | Not applicable | | -| (k)(3) Products which have mechanically operated controls or keys shall comply with the following: If key repeat is supported, the delay before repeat shall be adjustable to at least 2 seconds. Key repeat rate shall be adjustable to 2 seconds per character. | Not applicable | | -| (k)(4) Products which have mechanically operated controls or keys shall comply with the following: The status of all locking or toggle controls or keys shall be visually discernible, and discernible either through touch or sound. | Not applicable | | - - - -  -## Section 1194.24 Video and Multi-media Products - -| Criteria | Supporting features | Remarks and explanations | -| -------- | ------------------- | ------------------------ | -| a) All analog television displays 13 inches and larger, and computer equipment that includes analog television receiver or display circuitry, shall be equipped with caption decoder circuitry which appropriately receives, decodes, and displays closed captions from broadcast, cable, videotape, and DVD signals. As soon as practicable, but not later than July 1, 2002, widescreen digital television (DTV) displays measuring at least 7.8 inches vertically, DTV sets with conventional displays measuring at least 13 inches vertically, and stand-alone DTV tuners, whether or not they are marketed with display screens, and computer equipment that includes DTV receiver or display circuitry, shall be equipped with caption decoder circuitry which appropriately receives, decodes, and displays closed captions from broadcast, cable, videotape, and DVD signals. | Not applicable | | -| (b) Television tuners, including tuner cards for use in computers, shall be equipped with secondary audio program playback circuitry. | Not applicable | | -| (c) All training and informational video and multimedia productions which support the agency's mission, regardless of format, that contain speech or other audio information necessary for the comprehension of the content, shall be open or closed captioned. | Not applicable | | -| (d) All training and informational video and multimedia productions which support the agency's mission, regardless of format, that contain visual information necessary for the comprehension of the content, shall be audio described. | Not applicable | | -| (e) Display or presentation of alternate text presentation or audio descriptions shall be user-selectable unless permanent. | Not applicable | | - - - -  -## Section 1194.25 Self-Contained, Closed Products - -| Criteria | Supporting features | Remarks and explanations | -| -------- | ------------------- | ------------------------ | -| (a) Self contained products shall be usable by people with disabilities without requiring an end-user to attach Assistive Technology to the product. Personal headsets for private listening are not Assistive Technology. | Not applicable | | -| (b) When a timed response is required, the user shall be alerted and given sufficient time to indicate more time is required. | Not applicable | | -| (c) Where a product utilizes touchscreens or contact-sensitive controls, an input method shall be provided that complies with §1194.23 (k) (1) through (4). | Not applicable | | -| (d) When biometric forms of user identification or control are used, an alternative form of identification or activation, which does not require the user to possess particular biological characteristics, shall also be provided. | Not applicable | | -| (e) When products provide auditory output, the audio signal shall be provided at a standard signal level through an industry standard connector that will allow for private listening. The product must provide the ability to interrupt, pause, and restart the audio at anytime. | Not applicable | | -| (f) When products deliver voice output in a public area, incremental volume control shall be provided with output amplification up to a level of at least 65 dB. Where the ambient noise level of the environment is above 45 dB, a volume gain of at least 20 dB above the ambient level shall be user selectable. A function shall be provided to automatically reset the volume to the default level after every use. | Not applicable | | -| (g) Color coding shall not be used as the only means of conveying information, indicating an action, prompting a response, or distinguishing a visual element. | Not applicable | | -| (h) When a product permits a user to adjust color and contrast settings, a range of color selections capable of producing a variety of contrast levels shall be provided. | Not applicable | | -| (i) Products shall be designed to avoid causing the screen to flicker with a frequency greater than 2 Hz and lower than 55 Hz. | Not applicable | | -| (j) (1) Products which are freestanding, non-portable, and intended to be used in one location and which have operable controls shall comply with the following: The position of any operable control shall be determined with respect to a vertical plane, which is 48 inches in length, centered on the operable control, and at the maximum protrusion of the product within the 48 inch length on products which are freestanding, non-portable, and intended to be used in one location and which have operable controls. | Not applicable | | -| (j)(2) Products which are freestanding, non-portable, and intended to be used in one location and which have operable controls shall comply with the following: Where any operable control is 10 inches or less behind the reference plane, the height shall be 54 inches maximum and 15 inches minimum above the floor. | Not applicable | | -| (j)(3) Products which are freestanding, non-portable, and intended to be used in one location and which have operable controls shall comply with the following: Where any operable control is more than 10 inches and not more than 24 inches behind the reference plane, the height shall be 46 inches maximum and 15 inches minimum above the floor. | Not applicable | | -| (j)(4) Products which are freestanding, non-portable, and intended to be used in one location and which have operable controls shall comply with the following: Operable controls shall not be more than 24 inches behind the reference plane. | Not applicable | | - - - -  -## Section 1194.26 Desktop and Portable Computers - -| Criteria | Supporting features | Remarks and explanations | -| -------- | ------------------- | ------------------------ | -| (a) All mechanically operated controls and keys shall comply with §1194.23 (k) (1) through (4). | Not applicable | | -| (b) If a product utilizes touchscreens or touch-operated controls, an input method shall be provided that complies with §1194.23 (k) (1) through (4). | Not applicable | | -| (c) When biometric forms of user identification or control are used, an alternative form of identification or activation, which does not require the user to possess particular biological characteristics, shall also be provided. | Not applicable | | -| (d) Where provided, at least one of each type of expansion slots, ports and connectors shall comply with publicly available industry standards | Not applicable | | - - - -  -## Section 1194.31 Functional Performance Criteria -| Criteria | Supporting features | Remarks and explanations | -| -------- | ------------------- | ------------------------ | -| (a) At least one mode of operation and information retrieval that does not require user vision shall be provided, or support for Assistive Technology used by people who are blind or visually impaired shall be provided. | Supports with exceptions | Some top-level controls in the CoCalc UI have focus order, name, role, value, accessible name, and info and relationship issues that may prevent some scenarios from being completed. | -| (b) At least one mode of operation and information retrieval that does not require visual acuity greater than 20/70 shall be provided in audio and enlarged print output working together or independently, or support for Assistive Technology used by people who are visually impaired shall be provided. | Supports | The CoCalc UI does not impede user from zooming into page, or from increasing the font size via their browser settings. As the site is zoomed, the layout will respond to become more readable. | -| (c) At least one mode of operation and information retrieval that does not require user hearing shall be provided, or support for Assistive Technology used by people who are deaf or hard of hearing shall be provided | Not applicable | CoCalc does not require auditory feedback.| -| (d) Where audio information is important for the use of a product, at least one mode of operation and information retrieval shall be provided in an enhanced auditory fashion, or support for assistive hearing devices shall be provided. | Not applicable | CoCalc does not require auditory feedback. | -| (e) At least one mode of operation and information retrieval that does not require user speech shall be provided, or support for Assistive Technology used by people with disabilities shall be provided. | Not applicable | CoCalc does not require speech input. | -| (f) At least one mode of operation and information retrieval that does not require fine motor control or simultaneous actions and that is operable with limited reach and strength shall be provided. | Supports with exceptions | The majority of content is accessible via keyboard. Mouse interactions necessary for some features. | - - - -  -## Section 1194.41 Information, Documentation and Support -| Criteria | Supporting features | Remarks and explanations | -| -------- | ------------------- | ------------------------ | -| (a) Product support documentation provided to end-users shall be made available in alternate formats upon request, at no additional charge | Supports | Information available on the CoCalc wiki and online user manual website can be requested for free by contacting support. | -| (b) End-users shall have access to a description of the accessibility and compatibility features of products in alternate formats or alternate methods upon request, at no additional charge. | Supports | See the CoCalc Accessibility Statement [https://github.com/sagemathinc/cocalc/wiki/AccessibilityStatement](https://github.com/sagemathinc/cocalc/wiki/AccessibilityStatement), which is linked from our online user manual. | -| (c) Support services for products shall accommodate the communication needs of end-users with disabilities. | Supports | The page outlining our approach to accessibility can be read by assistive technologies. Additional information can be requested via email to help@cocalc.com. - - -  -## Legal Disclaimer (Sagemath, Inc.) - -This document is provided for information purposes only and the contents hereof are subject to change without notice. Sagemath, Inc. does not warrant that this document is error free, nor does it provide any other warranties or conditions, whether expressed orally or implied in law, including implied warranties and conditions of merchantability or fitness for a particular purpose. Sagemath, Inc. specifically disclaims any liability with respect to this document and no contractual obligations are formed either directly or indirectly by this document. Sagemath, Inc. further makes no representation concerning the ability of assistive technologies or other products to interoperate with Sagemath, Inc. products. This document addresses the named product(s) or platforms only. -`; \ No newline at end of file diff --git a/src/packages/next/lib/user-id.ts b/src/packages/next/lib/user-id.ts new file mode 100644 index 00000000000..136855b053c --- /dev/null +++ b/src/packages/next/lib/user-id.ts @@ -0,0 +1,34 @@ +/* + * This file is part of CoCalc: Copyright © 2021 Sagemath, Inc. + * License: MS-RSL – see LICENSE.md for details + */ + +import type { Request } from "express"; + +import { getServerSettings } from "@cocalc/database/settings/server-settings"; +import { ANALYTICS_COOKIE_NAME } from "@cocalc/util/consts"; +import { getClientIpAddress } from "@cocalc/util/get-client-ip-address"; +import { isValidAnonymousID } from "@cocalc/util/misc"; + +// Get anonymous user ID from cookie or IP address +export async function getAnonymousID( + req: Request, +): Promise { + const { analytics_cookie: analytics_enabled } = await getServerSettings(); + + if (analytics_enabled) { + const cookie = req.cookies[ANALYTICS_COOKIE_NAME]; + if (isValidAnonymousID(cookie)) { + return cookie; + } + } + + // Fall back to IP address + const connectingIp = getClientIpAddress(req); + + if (isValidAnonymousID(connectingIp)) { + return connectingIp; + } + + return undefined; +} diff --git a/src/packages/next/package.json b/src/packages/next/package.json index 4e4fce6e846..4f565201452 100644 --- a/src/packages/next/package.json +++ b/src/packages/next/package.json @@ -78,7 +78,7 @@ "lodash": "^4.17.21", "lru-cache": "^7.18.3", "ms": "2.1.2", - "next": "15.5.0", + "next": "15.5.7", "next-rest-framework": "6.0.0-beta.4", "next-translate": "^2.6.2", "password-hash": "^1.2.2", @@ -91,7 +91,7 @@ "timeago-react": "^3.0.4", "use-async-effect": "^2.2.7", "uuid": "^8.3.2", - "xmlbuilder2": "^3.0.2", + "xmlbuilder2": "^4.0.1", "zod": "^3.23.5" }, "devDependencies": { diff --git a/src/packages/next/pages/api/conat/project.ts b/src/packages/next/pages/api/conat/project.ts index 64445ec5a52..80597933210 100644 --- a/src/packages/next/pages/api/conat/project.ts +++ b/src/packages/next/pages/api/conat/project.ts @@ -40,7 +40,7 @@ export default async function handle(req, res) { throw Error("must specify project_id or use project-specific api key"); } if (project_id0) { - // auth via project_id + // auth via project-specific API key if (project_id0 != project_id) { throw Error("project specific api key must match requested project"); } @@ -57,6 +57,7 @@ export default async function handle(req, res) { name, args, timeout, + account_id, }); res.json(resp); } catch (err) { diff --git a/src/packages/next/pages/api/v2/jupyter/execute.ts b/src/packages/next/pages/api/v2/jupyter/execute.ts index 674a21f4e8c..73c1b1af9d6 100644 --- a/src/packages/next/pages/api/v2/jupyter/execute.ts +++ b/src/packages/next/pages/api/v2/jupyter/execute.ts @@ -20,12 +20,15 @@ The OUTPUT is: - a list of messages that describe the output of the last code execution. */ + +import type { Request, Response } from "express"; + import { execute } from "@cocalc/server/jupyter/execute"; import getAccountId from "lib/account/get-account"; import getParams from "lib/api/get-params"; -import { analytics_cookie_name } from "@cocalc/util/misc"; +import { getAnonymousID } from "lib/user-id"; -export default async function handle(req, res) { +export default async function handle(req: Request, res: Response) { try { const result = await doIt(req); res.json({ ...result, success: true }); @@ -35,16 +38,16 @@ export default async function handle(req, res) { } } -async function doIt(req) { +async function doIt(req: Request) { const { input, kernel, history, tag, noCache, hash, project_id, path } = getParams(req); const account_id = await getAccountId(req); - const analytics_cookie = req.cookies[analytics_cookie_name]; + const anonymous_id = await getAnonymousID(req); return await execute({ account_id, project_id, path, - analytics_cookie, + anonymous_id, input, hash, history, diff --git a/src/packages/next/pages/api/v2/llm/evaluate.ts b/src/packages/next/pages/api/v2/llm/evaluate.ts index 2304b453a89..a7384457f22 100644 --- a/src/packages/next/pages/api/v2/llm/evaluate.ts +++ b/src/packages/next/pages/api/v2/llm/evaluate.ts @@ -1,12 +1,14 @@ // This is the new endpoint for querying any LLM // Previously, this has been in openai/chatgpt +import type { Request, Response } from "express"; + import { evaluate } from "@cocalc/server/llm/index"; -import { analytics_cookie_name } from "@cocalc/util/misc"; import getAccountId from "lib/account/get-account"; import getParams from "lib/api/get-params"; +import { getAnonymousID } from "lib/user-id"; -export default async function handle(req, res) { +export default async function handle(req: Request, res: Response) { try { const result = await doIt(req); res.json({ ...result, success: true }); @@ -16,14 +18,14 @@ export default async function handle(req, res) { } } -async function doIt(req) { +async function doIt(req: Request) { const { input, system, history, model, tag } = getParams(req); const account_id = await getAccountId(req); - const analytics_cookie = req.cookies[analytics_cookie_name]; + const anonymous_id = await getAnonymousID(req); return { output: await evaluate({ account_id, - analytics_cookie, + anonymous_id, input, system, history, diff --git a/src/packages/next/pages/api/v2/projects/delete.test.ts b/src/packages/next/pages/api/v2/projects/delete.test.ts new file mode 100644 index 00000000000..660f9db8f72 --- /dev/null +++ b/src/packages/next/pages/api/v2/projects/delete.test.ts @@ -0,0 +1,70 @@ +/** @jest-environment node */ + +import { createMocks } from "lib/api/test-framework"; +import handler from "./delete"; + +// Mock the dependencies +jest.mock("@cocalc/server/projects/delete", () => jest.fn()); +jest.mock("lib/account/get-account", () => jest.fn()); + +describe("/api/v2/projects/delete", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + test("unauthenticated request should return JSON error, not throw", async () => { + // Mock getAccountId to return undefined (not authenticated) + const getAccountId = require("lib/account/get-account"); + getAccountId.mockResolvedValue(undefined); + + const { req, res } = createMocks({ + method: "POST", + url: "/api/v2/projects/delete", + body: { + project_id: "00000000-0000-0000-0000-000000000000", + }, + }); + + // This should NOT throw - it should handle the error gracefully + await expect(handler(req, res)).resolves.not.toThrow(); + + // Should return JSON error response + const data = res._getJSONData(); + expect(data).toHaveProperty("error"); + expect(data.error).toContain("must be signed in"); + }); + + test("authenticated request calls deleteProject", async () => { + const mockAccountId = "11111111-1111-1111-1111-111111111111"; + const mockProjectId = "00000000-0000-0000-0000-000000000000"; + + // Mock getAccountId to return a valid account_id + const getAccountId = require("lib/account/get-account"); + getAccountId.mockResolvedValue(mockAccountId); + + // Mock deleteProject + const deleteProject = require("@cocalc/server/projects/delete"); + deleteProject.mockResolvedValue(undefined); + + const { req, res } = createMocks({ + method: "POST", + url: "/api/v2/projects/delete", + body: { + project_id: mockProjectId, + }, + }); + + await handler(req, res); + + // Should call deleteProject with correct params + expect(deleteProject).toHaveBeenCalledWith({ + account_id: mockAccountId, + project_id: mockProjectId, + }); + + // Should return OK status + const data = res._getJSONData(); + expect(data).toHaveProperty("status"); + expect(data.status).toBe("ok"); + }); +}); diff --git a/src/packages/next/pages/api/v2/projects/delete.ts b/src/packages/next/pages/api/v2/projects/delete.ts index 34d622711bf..d26677c45f2 100644 --- a/src/packages/next/pages/api/v2/projects/delete.ts +++ b/src/packages/next/pages/api/v2/projects/delete.ts @@ -20,8 +20,7 @@ async function handle(req, res) { throw Error("must be signed in"); } - await deleteProject({ project_id, account_id }); - + await deleteProject({ account_id, project_id }); res.json(OkStatus); } catch (err) { res.json({ error: err.message }); diff --git a/src/packages/next/pages/policies/accessibility.tsx b/src/packages/next/pages/policies/accessibility.tsx index 11b93c5d38f..57b435aed4c 100644 --- a/src/packages/next/pages/policies/accessibility.tsx +++ b/src/packages/next/pages/policies/accessibility.tsx @@ -4,7 +4,6 @@ import Head from "components/landing/head"; import { Layout } from "antd"; import withCustomize from "lib/with-customize"; import { Customize } from "lib/customize"; -import Accessibility from "components/landing/accessibility"; import { MAX_WIDTH } from "lib/config"; export default function AccessibilityPage({ customize }) { @@ -28,12 +27,37 @@ export default function AccessibilityPage({ customize }) { >

- CoCalc Voluntary Product Accessibility Template (VPAT) + CoCalc - Accessibility Statement

-

Last Updated: July 3, 2019

- +

+ Given the scope of what is possible in CoCalc, such as using + arbitrary Jupyter notebooks with custom styling and a broad + collection of software including user installed packages, it is + infeasible to expect that everything will be fully accessible + and aligned with any standards, such as WCAG. However, we are + committed to do our best to resolve any concrete issues that our + customers face. We have a long history of successfully + facilitating courses for thousands of students (i.e. for users + who cannot easily switch to an alternative platform) as evidence + of success of this approach. +

+

+ If your use case is primarily to interact with Jupyter + notebooks, keep in mind that CoCalc makes it easy to launch + industry standard Jupyter Classic (and Jupyter Lab). These + projects have put substantial deliberate efforts into making + their products accessible, although they still do not claim to + have AA compliance with WCAG. +

+

+ For more specific details, please consult our{" "} + + Voluntary Product Accessibility Template, VPAT® + {" "} + (Last Update: December 2025) +