From 2552dd77a1dff4c9a07b030db77a90779dc5af35 Mon Sep 17 00:00:00 2001 From: Harald Schilly Date: Wed, 3 Dec 2025 13:08:27 +0100 Subject: [PATCH] project/collaborators: implement ownership management -- #7718 --- src/.claude/settings.json | 1 + src/packages/conat/hub/api/projects.ts | 14 + .../database/postgres-user-queries.coffee | 14 + .../postgres/manage-users-owner-only.test.ts | 85 +++ .../project/manage-users-owner-only.ts | 31 + src/packages/database/postgres/types.ts | 15 +- src/packages/frontend/antd-bootstrap.tsx | 2 +- .../frontend/client/project-collaborators.ts | 12 +- .../collaborators/add-collaborators.tsx | 55 +- .../collaborators/collaborators-setting.tsx | 133 ++++ .../collaborators/current-collabs.tsx | 387 ++++++++++-- src/packages/frontend/customize.tsx | 3 +- src/packages/frontend/i18n/common.ts | 44 ++ src/packages/frontend/i18n/trans/ar_EG.json | 46 +- src/packages/frontend/i18n/trans/de_DE.json | 46 +- src/packages/frontend/i18n/trans/es_ES.json | 46 +- src/packages/frontend/i18n/trans/es_PV.json | 46 +- src/packages/frontend/i18n/trans/fr_FR.json | 46 +- src/packages/frontend/i18n/trans/he_IL.json | 46 +- src/packages/frontend/i18n/trans/hi_IN.json | 46 +- src/packages/frontend/i18n/trans/hu_HU.json | 46 +- src/packages/frontend/i18n/trans/it_IT.json | 46 +- src/packages/frontend/i18n/trans/ja_JP.json | 46 +- src/packages/frontend/i18n/trans/ko_KR.json | 46 +- src/packages/frontend/i18n/trans/nl_NL.json | 46 +- src/packages/frontend/i18n/trans/pl_PL.json | 46 +- src/packages/frontend/i18n/trans/pt_BR.json | 46 +- src/packages/frontend/i18n/trans/pt_PT.json | 46 +- src/packages/frontend/i18n/trans/ru_RU.json | 46 +- src/packages/frontend/i18n/trans/tr_TR.json | 46 +- src/packages/frontend/i18n/trans/zh_CN.json | 46 +- .../frontend/project/history/log-entry.tsx | 69 ++- .../frontend/project/history/types.ts | 20 +- src/packages/frontend/projects/actions.ts | 36 +- src/packages/next/lib/project/get-owner.ts | 40 +- .../projects/collaborators-ownership.test.ts | 320 ++++++++++ src/packages/server/projects/collaborators.ts | 213 ++++++- .../projects/manage-users-owner-only.test.ts | 197 ++++++ src/packages/util/db-schema/client-db.ts | 6 + src/packages/util/db-schema/projects.ts | 55 ++ src/packages/util/db-schema/site-defaults.ts | 9 + src/packages/util/project-ownership.test.ts | 576 ++++++++++++++++++ src/packages/util/project-ownership.ts | 354 +++++++++++ 43 files changed, 3263 insertions(+), 256 deletions(-) create mode 100644 src/packages/database/postgres/manage-users-owner-only.test.ts create mode 100644 src/packages/database/postgres/project/manage-users-owner-only.ts create mode 100644 src/packages/frontend/collaborators/collaborators-setting.tsx create mode 100644 src/packages/server/projects/collaborators-ownership.test.ts create mode 100644 src/packages/server/projects/manage-users-owner-only.test.ts create mode 100644 src/packages/util/project-ownership.test.ts create mode 100644 src/packages/util/project-ownership.ts diff --git a/src/.claude/settings.json b/src/.claude/settings.json index 2ba490f7fc0..628d1ee3d24 100644 --- a/src/.claude/settings.json +++ b/src/.claude/settings.json @@ -13,6 +13,7 @@ "Bash(gh pr view:*)", "Bash(gh:*)", "Bash(git add:*)", + "Bash(git grep:*)", "Bash(git branch:*)", "Bash(git checkout:*)", "Bash(git commit:*)", diff --git a/src/packages/conat/hub/api/projects.ts b/src/packages/conat/hub/api/projects.ts index bf42fd5d36d..ea606e478fa 100644 --- a/src/packages/conat/hub/api/projects.ts +++ b/src/packages/conat/hub/api/projects.ts @@ -1,6 +1,7 @@ import { authFirstRequireAccount } from "./util"; import { type CreateProjectOptions } from "@cocalc/util/db-schema/projects"; import { type UserCopyOptions } from "@cocalc/util/db-schema/projects"; +import { type UserGroup } from "@cocalc/util/project-ownership"; export const projects = { createProject: authFirstRequireAccount, @@ -9,6 +10,7 @@ export const projects = { addCollaborator: authFirstRequireAccount, inviteCollaborator: authFirstRequireAccount, inviteCollaboratorWithoutAccount: authFirstRequireAccount, + changeUserType: authFirstRequireAccount, setQuotas: authFirstRequireAccount, start: authFirstRequireAccount, stop: authFirstRequireAccount, @@ -87,6 +89,18 @@ export interface Projects { }; }) => Promise; + changeUserType: ({ + account_id, + opts, + }: { + account_id?: string; + opts: { + project_id: string; + target_account_id: string; + new_group: UserGroup; + }; + }) => Promise; + setQuotas: (opts: { account_id?: string; project_id: string; diff --git a/src/packages/database/postgres-user-queries.coffee b/src/packages/database/postgres-user-queries.coffee index 2cb8f7754d7..075aa9df616 100644 --- a/src/packages/database/postgres-user-queries.coffee +++ b/src/packages/database/postgres-user-queries.coffee @@ -30,6 +30,7 @@ required = defaults.required {queryIsCmp, userGetQueryFilter} = require("./user-query/user-get-query") {updateRetentionData} = require('./postgres/retention') +{sanitizeManageUsersOwnerOnly} = require('./postgres/project/manage-users-owner-only') { checkProjectName } = require("@cocalc/util/db-schema/name-rules"); {callback2} = require('@cocalc/util/async-utils') @@ -839,6 +840,13 @@ exports.extend_PostgreSQL = (ext) -> class PostgreSQL extends ext users[id] = x return users + _user_set_query_project_manage_users_owner_only: (obj, account_id) => + # This hook is called from the schema functional substitution to validate + # the manage_users_owner_only flag. This must be synchronous - async validation + # (permission checks) is done in the check_hook instead. + # Just do basic type validation and sanitization here + return sanitizeManageUsersOwnerOnly(obj.manage_users_owner_only) + project_action: (opts) => opts = defaults opts, project_id : required @@ -933,6 +941,12 @@ exports.extend_PostgreSQL = (ext) -> class PostgreSQL extends ext cb("Only the owner of the project can currently change the project name.") return + if new_val?.manage_users_owner_only? and new_val.manage_users_owner_only != old_val?.manage_users_owner_only + # Permission is enforced in the set-field interceptor; nothing to do here. + # Leaving this block for clarity and to avoid silent bypass if future callers + # modify manage_users_owner_only via another path. + dbg("manage_users_owner_only change requested") + if new_val?.action_request? and JSON.stringify(new_val.action_request.time) != JSON.stringify(old_val?.action_request?.time) # Requesting an action, e.g., save, restart, etc. dbg("action_request -- #{misc.to_json(new_val.action_request)}") diff --git a/src/packages/database/postgres/manage-users-owner-only.test.ts b/src/packages/database/postgres/manage-users-owner-only.test.ts new file mode 100644 index 00000000000..6f8d24533f8 --- /dev/null +++ b/src/packages/database/postgres/manage-users-owner-only.test.ts @@ -0,0 +1,85 @@ +/* + * This file is part of CoCalc: Copyright © 2025 Sagemath, Inc. + * License: MS-RSL – see LICENSE.md for details + */ + +import getPool, { initEphemeralDatabase } from "@cocalc/database/pool"; +import { db } from "@cocalc/database"; +import { uuid } from "@cocalc/util/misc"; + +let pool: ReturnType | undefined; +let dbAvailable = true; + +beforeAll(async () => { + try { + await initEphemeralDatabase(); + pool = getPool(); + } catch (err) { + // Skip locally if postgres is unavailable. + dbAvailable = false; + console.warn("Skipping manage_users_owner_only tests: " + err); + } +}, 15000); + +afterAll(async () => { + if (pool) { + await pool.end(); + } +}); + +async function insertProject(opts: { + projectId: string; + ownerId: string; + collaboratorId: string; +}) { + const { projectId, ownerId, collaboratorId } = opts; + if (!pool) { + throw Error("Pool not initialized"); + } + await pool.query("INSERT INTO projects(project_id, users) VALUES ($1, $2)", [ + projectId, + { + [ownerId]: { group: "owner" }, + [collaboratorId]: { group: "collaborator" }, + }, + ]); +} + +describe("manage_users_owner_only set hook", () => { + const projectId = uuid(); + const ownerId = uuid(); + const collaboratorId = uuid(); + + beforeAll(async () => { + if (!dbAvailable) return; + await insertProject({ projectId, ownerId, collaboratorId }); + }); + + test("owner can set manage_users_owner_only", async () => { + if (!dbAvailable) return; + const value = await db()._user_set_query_project_manage_users_owner_only( + { project_id: projectId, manage_users_owner_only: true }, + ownerId, + ); + expect(value).toBe(true); + }); + + test("collaborator call returns sanitized value (permission enforced elsewhere)", async () => { + if (!dbAvailable) return; + const value = await db()._user_set_query_project_manage_users_owner_only( + { project_id: projectId, manage_users_owner_only: true }, + collaboratorId, + ); + expect(value).toBe(true); + }); + + test("invalid type is rejected", async () => { + if (!dbAvailable) return; + expect(() => + db()._user_set_query_project_manage_users_owner_only( + { project_id: projectId, manage_users_owner_only: "yes" as any }, + ownerId, + ), + ).toThrow("manage_users_owner_only must be a boolean"); + }); +}); diff --git a/src/packages/database/postgres/project/manage-users-owner-only.ts b/src/packages/database/postgres/project/manage-users-owner-only.ts new file mode 100644 index 00000000000..858b65c1b0b --- /dev/null +++ b/src/packages/database/postgres/project/manage-users-owner-only.ts @@ -0,0 +1,31 @@ +/* + * This file is part of CoCalc: Copyright © 2025 Sagemath, Inc. + * License: MS-RSL – see LICENSE.md for details + */ + +export function sanitizeManageUsersOwnerOnly( + value: unknown, +): boolean | undefined { + if (value === undefined || value === null) { + return undefined; + } + if (typeof value === "object") { + // Allow nested shape { manage_users_owner_only: boolean } from callers that wrap input. + const candidate = (value as any).manage_users_owner_only; + if (candidate !== undefined) { + return sanitizeManageUsersOwnerOnly(candidate); + } + // Allow Immutable.js style get("manage_users_owner_only") + const getter = (value as any).get; + if (typeof getter === "function") { + const maybe = getter.call(value, "manage_users_owner_only"); + if (maybe !== undefined) { + return sanitizeManageUsersOwnerOnly(maybe); + } + } + } + if (typeof value !== "boolean") { + throw Error("manage_users_owner_only must be a boolean"); + } + return value; +} diff --git a/src/packages/database/postgres/types.ts b/src/packages/database/postgres/types.ts index 939a4b81cff..657260935be 100644 --- a/src/packages/database/postgres/types.ts +++ b/src/packages/database/postgres/types.ts @@ -48,8 +48,10 @@ export interface QueryOptions { cb?: CB>; } -export interface AsyncQueryOptions - extends Omit, "cb"> {} +export interface AsyncQueryOptions extends Omit< + QueryOptions, + "cb" +> {} export interface UserQueryOptions { client_id?: string; // if given, uses to control number of queries at once by one client. @@ -406,8 +408,13 @@ export interface PostgreSQL extends EventEmitter { webapp_error(opts: object); set_project_settings(opts: { project_id: string; settings: object; cb?: CB }); - - uncaught_exception: (err:any) => void; + + _user_set_query_project_manage_users_owner_only( + obj: any, + account_id: string, + ): string | undefined; + + uncaught_exception: (err: any) => void; } // This is an extension of BaseProject in projects/control/base.ts diff --git a/src/packages/frontend/antd-bootstrap.tsx b/src/packages/frontend/antd-bootstrap.tsx index 1bf7e016748..94ecc4a9cb6 100644 --- a/src/packages/frontend/antd-bootstrap.tsx +++ b/src/packages/frontend/antd-bootstrap.tsx @@ -86,7 +86,7 @@ function parse_bsStyle(props: { let type = props.bsStyle == null ? "default" - : BS_STYLE_TO_TYPE[props.bsStyle] ?? "default"; + : (BS_STYLE_TO_TYPE[props.bsStyle] ?? "default"); let style: React.CSSProperties | undefined = undefined; // antd has no analogue of "success" & "warning", it's not clear to me what diff --git a/src/packages/frontend/client/project-collaborators.ts b/src/packages/frontend/client/project-collaborators.ts index ee2af1ff072..7ee6f904c3b 100644 --- a/src/packages/frontend/client/project-collaborators.ts +++ b/src/packages/frontend/client/project-collaborators.ts @@ -3,6 +3,8 @@ * License: MS-RSL – see LICENSE.md for details */ +// cSpell:ignore replyto collabs noncloud + import type { ConatClient } from "@cocalc/frontend/conat/client"; import type { AddCollaborator } from "@cocalc/conat/hub/api/projects"; @@ -57,10 +59,18 @@ export class ProjectCollaborators { public async add_collaborator( opts: AddCollaborator, ): Promise<{ project_id?: string | string[] }> { - // project_id is a single string or possibly an array of project_id's + // project_id is a single string or possibly an array of project_id's // in case of a token. return await this.conat.hub.projects.addCollaborator({ opts, }); } + + public async change_user_type(opts: { + project_id: string; + target_account_id: string; + new_group: "owner" | "collaborator"; + }): Promise { + return await this.conat.hub.projects.changeUserType({ opts }); + } } diff --git a/src/packages/frontend/collaborators/add-collaborators.tsx b/src/packages/frontend/collaborators/add-collaborators.tsx index 1ba217d9612..b52c63b6c93 100644 --- a/src/packages/frontend/collaborators/add-collaborators.tsx +++ b/src/packages/frontend/collaborators/add-collaborators.tsx @@ -7,8 +7,11 @@ Add collaborators to a project */ +// cSpell:ignore replyto noncloud collabs + import { Alert, Button, Input, Select } from "antd"; -import { useIntl } from "react-intl"; +import { FormattedMessage, useIntl } from "react-intl"; + import { labels } from "@cocalc/frontend/i18n"; import { React, @@ -17,12 +20,19 @@ import { useIsMountedRef, useMemo, useRef, + useRedux, useTypedRedux, useState, } from "../app-framework"; -import { Well } from "../antd-bootstrap"; -import { A, Icon, Loading, ErrorDisplay, Gap } from "../components"; -import { webapp_client } from "../webapp-client"; +import { Well } from "@cocalc/frontend/antd-bootstrap"; +import { + A, + Icon, + Loading, + ErrorDisplay, + Gap, +} from "@cocalc/frontend/components"; +import { webapp_client } from "@cocalc/frontend/webapp-client"; import { SITE_NAME } from "@cocalc/util/theme"; import { contains_url, @@ -34,10 +44,10 @@ import { search_match, search_split, } from "@cocalc/util/misc"; -import { Project } from "../projects/store"; -import { Avatar } from "../account/avatar/avatar"; +import { Project } from "@cocalc/frontend/projects/store"; +import { Avatar } from "@cocalc/frontend/account/avatar/avatar"; import { ProjectInviteTokens } from "./project-invite-tokens"; -import { alert_message } from "../alerts"; +import { alert_message } from "@cocalc/frontend/alerts"; import { useStudentProjectFunctionality } from "@cocalc/frontend/course"; import Sandbox from "./sandbox"; import track from "@cocalc/frontend/user-tracking"; @@ -104,6 +114,20 @@ export const AddCollaborators: React.FC = ({ () => project_map?.get(project_id), [project_id, project_map], ); + const get_account_id = useRedux("account", "get_account_id"); + const current_account_id = get_account_id(); + const strict_collaborator_management = + useTypedRedux("customize", "strict_collaborator_management") ?? false; + const manage_users_owner_only = + strict_collaborator_management || + (project?.get("manage_users_owner_only") ?? false); + const current_user_group = project?.getIn([ + "users", + current_account_id, + "group", + ]); + const isOwner = current_user_group === "owner"; + const collaboratorManagementRestricted = manage_users_owner_only && !isOwner; // search that user has typed in so far const [search, set_search] = useState(""); @@ -257,7 +281,7 @@ export const AddCollaborators: React.FC = ({ // react rendered version of this that is much nicer (with pictures!) someday. const extra: string[] = []; if (r.account_id != null && user_map.get(r.account_id)) { - extra.push("Collaborator"); + extra.push(intl.formatMessage(labels.collaborator)); } if (r.last_active) { extra.push(`Active ${new Date(r.last_active).toLocaleDateString()}`); @@ -691,6 +715,21 @@ export const AddCollaborators: React.FC = ({ return
; } + if (collaboratorManagementRestricted) { + return ( + + } + /> + ); + } + return (
) { + const intl = useIntl(); + const [error, setError] = useState(""); + const [saving, setSaving] = useState(false); + + const project_id = project.get("project_id"); + const siteEnforced = + useTypedRedux("customize", "strict_collaborator_management") ?? false; + const manage_users_owner_only = + siteEnforced || project.get("manage_users_owner_only") || false; + + // Check if current user is an owner + const account_id = webapp_client.account_id; + const userGroup = project.getIn(["users", account_id, "group"]); + const isOwner = userGroup === "owner"; + + async function handleChange(checked: boolean): Promise { + if (siteEnforced) return; + if (!isOwner) return; + + setError(""); + setSaving(true); + + try { + await webapp_client.async_query({ + query: { + projects: { + project_id, + manage_users_owner_only: checked, + }, + }, + }); + } catch (err) { + setError(`Error updating setting: ${err}`); + } finally { + setSaving(false); + } + } + + const switchComponent = ( + handleChange(e.target.checked)} + disabled={siteEnforced || !isOwner || saving} + > + + + ); + + const content = ( + <> + {!isOwner ? ( + + {switchComponent} + + ) : ( + switchComponent + )} + + {siteEnforced && ( + + } + /> + )} + + {error && ( + setError("")} + message={error} + /> + )} + + ); + + if (!withSettingBox) { + return content; + } + + return ( + + {content} + + ); +} diff --git a/src/packages/frontend/collaborators/current-collabs.tsx b/src/packages/frontend/collaborators/current-collabs.tsx index 767c381c9de..214b2d74916 100644 --- a/src/packages/frontend/collaborators/current-collabs.tsx +++ b/src/packages/frontend/collaborators/current-collabs.tsx @@ -3,15 +3,24 @@ * License: MS-RSL – see LICENSE.md for details */ -import { Button, Card, Popconfirm } from "antd"; -import React from "react"; +// cSpell:ignore replyto collabs noncloud + +import { Alert, Button, Card, Dropdown, Popconfirm } from "antd"; +import React, { useState } from "react"; import { FormattedMessage, useIntl } from "react-intl"; -import { CSS, redux, useRedux } from "@cocalc/frontend/app-framework"; + +import { + CSS, + redux, + useRedux, + useTypedRedux, +} from "@cocalc/frontend/app-framework"; import { - Gap, Icon, Paragraph, SettingBox, + Text, + Tip, Title, } from "@cocalc/frontend/components"; import { useStudentProjectFunctionality } from "@cocalc/frontend/course"; @@ -19,9 +28,20 @@ import { labels } from "@cocalc/frontend/i18n"; import { CancelText } from "@cocalc/frontend/i18n/components"; import { Project } from "@cocalc/frontend/project/settings/types"; import { COLORS } from "@cocalc/util/theme"; +import { CollaboratorsSetting } from "./collaborators-setting"; import { FIX_BORDER } from "../project/page/common"; import { User } from "../users"; +const LIST_STYLE: CSS = { + maxHeight: "20em", + overflowY: "auto", + overflowX: "hidden", + marginBottom: "0", + display: "flex", + flexDirection: "column", + gap: "12px", +} as const; + interface Props { project: Project; user_map?: any; @@ -35,16 +55,46 @@ export const CurrentCollaboratorsPanel: React.FC = (props: Props) => { const get_account_id = useRedux("account", "get_account_id"); const sort_by_activity = useRedux("projects", "sort_by_activity"); const student = useStudentProjectFunctionality(project.get("project_id")); + const [error, setError] = useState(""); + + const project_id = project.get("project_id"); + const current_account_id = get_account_id(); + const users = project.get("users"); + const current_user_group = users?.getIn([current_account_id, "group"]); + const is_requester_owner = current_user_group === "owner"; + const strict_collaborator_management = + useTypedRedux("customize", "strict_collaborator_management") ?? false; + const manage_users_owner_only = + strict_collaborator_management || + (project.get("manage_users_owner_only") ?? false); + + // Count owners to check if this is the last owner + const owner_count = users + ? users.valueSeq().count((u: any) => u?.get?.("group") === "owner") + : 0; function remove_collaborator(account_id: string) { - const project_id = project.get("project_id"); redux.getActions("projects").remove_collaborator(project_id, account_id); - if (account_id === get_account_id()) { - (redux.getActions("page") as any).close_project_tab(project_id); + if (account_id === current_account_id) { + (redux.getActions("page") as any).close_project_tab(project_id); // TODO: better types } } + async function change_user_type( + account_id: string, + new_group: "owner" | "collaborator", + ) { + try { + setError(""); + await redux + .getActions("projects") + .change_user_type(project_id, account_id, new_group); + } catch (err) { + setError(`Error: ${err}`); + } + } + function user_remove_confirm_text(account_id: string) { const style: CSS = { maxWidth: "300px" }; if (account_id === get_account_id()) { @@ -73,51 +123,217 @@ export const CurrentCollaboratorsPanel: React.FC = (props: Props) => { } } - function user_remove_button(account_id: string, group?: string) { + function renderRoleSetting(account_id: string, group?: string) { + const isOwner = group === "owner"; + const isLastOwner = isOwner && owner_count === 1; + const can_promote = !isOwner && is_requester_owner; + const can_demote = isOwner && is_requester_owner && !isLastOwner; + + const buttonSize = isFlyout ? "small" : "middle"; + const roleLabel = intl.formatMessage( + isOwner ? labels.owner : labels.collaborator, + ); + + // If not allowed to change owner/collab status, simply report the role of the given user + if (student.disableCollaborators || !is_requester_owner) { + const label = ( + + {`(${roleLabel})`} + + ); + return isFlyout ? ( +
+ {label} +
+ ) : ( + label + ); + } + + const menuItems = [ + { + key: "promote", + label: ( + + + + ), + disabled: !can_promote, + onClick: () => change_user_type(account_id, "owner"), + }, + { + key: "demote", + label: ( + + + + ), + disabled: !can_demote, + onClick: () => change_user_type(account_id, "collaborator"), + }, + ]; + + const dropdown = ( + + + + ); + + if (isFlyout) { + return ( +
+ {dropdown} +
+ ); + } else { + return dropdown; + } + } + + function renderRemoveButton(account_id: string, group?: string) { if (student.disableCollaborators) return; const text = user_remove_confirm_text(account_id); const isOwner = group === "owner"; + const isSelf = account_id === current_account_id; + const disabledBySetting = + manage_users_owner_only && !is_requester_owner && !isSelf; + const disabled = isOwner || disabledBySetting; + + const disabledReason = (() => { + if (isOwner) { + return intl.formatMessage({ + id: "collaborators.current-collabs.remove.owner_disabled", + defaultMessage: "Owners must be demoted before they can be removed.", + }); + } + if (disabledBySetting) { + return intl.formatMessage({ + id: "collaborators.current-collabs.remove.setting_disabled", + defaultMessage: + "Only owners can remove collaborators when this setting is enabled.", + }); + } + return undefined; + })(); + + const buttonType = isFlyout ? "link" : "default"; + const buttonSize = isFlyout ? "small" : "middle"; + return ( - remove_collaborator(account_id)} - okText={"Yes, remove collaborator"} - cancelText={} - disabled={isOwner} - > - - + + + ); } function render_user(user: any, is_last?: boolean) { - const style = { + const baseStyle: CSS = { width: "100%", flex: "1 1 auto", ...(!is_last ? { marginBottom: "20px" } : {}), }; + + if (isFlyout) { + return ( +
+
+ +
+
+ {renderRoleSetting(user.account_id, user.group)} + {renderRemoveButton(user.account_id, user.group)} +
+
+ ); + } + return ( -
- - - ({user.group}) - - {user_remove_button(user.account_id, user.group)} +
+
+ +
+
+ {renderRoleSetting(user.account_id, user.group)} + {renderRemoveButton(user.account_id, user.group)} +
); } @@ -131,70 +347,111 @@ export const CurrentCollaboratorsPanel: React.FC = (props: Props) => { .map((v, k) => ({ account_id: k, group: v.get("group") })) .toList() .toJS(); - return sort_by_activity(users, project.get("project_id")).map((u, i) => - render_user(u, i === users.length - 1), + return sort_by_activity(users, project.get("project_id")).map( + (u: any, i: number) => render_user(u, i === users.length - 1), + ); + } + + function render_setting() { + return ( +
+ +
); } function render_collaborators_list() { - const style: CSS = { - maxHeight: "20em", - overflowY: "auto", - overflowX: "hidden", - marginBottom: "0", - display: "flex", - flexDirection: "column", - }; + const header = ( + <> + {error && ( + setError("")} + style={{ marginBottom: "10px" }} + /> + )} + + ); + + const list =
{render_users()}
; + if (isFlyout) { return ( -
- {render_users()} +
+ {header} + {list}
); } else { return ( - - {render_users()} + + {header} + {list} ); } } - const introText = intl.formatMessage({ - id: "collaborators.current-collabs.intro", - defaultMessage: - "Everybody listed below can collaboratively work with you on any Jupyter Notebook, Linux Terminal or file in this project, and add or remove other collaborators.", + const introText = intl.formatMessage( + { + id: "collaborators.current-collabs.intro2", + defaultMessage: `Everybody listed below can collaboratively work with you on any Jupyter Notebook, Linux Terminal or file in this project. + {manageUsersOnly, select, + true { Only project owners can add or remove collaborators.} + other { Collaborators can also add or remove other collaborators.}}`, + }, + { manageUsersOnly: manage_users_owner_only ? "true" : "false" }, + ); + + const nonOwnerNote = !is_requester_owner + ? intl.formatMessage({ + id: "project.collaborators.non_owner_note", + defaultMessage: "Only project owners can manage user roles.", + }) + : null; + + const titleText = intl.formatMessage({ + id: "collaborators.current-collabs.title", + defaultMessage: "Current Collaborators", + description: "Title of a table listing users collaborating on that project", }); switch (mode) { case "project": return ( - {introText} +
+ {introText} + {nonOwnerNote && ( + <> + {" "} + {nonOwnerNote} + + )} +

{render_collaborators_list()} +
+ {render_setting()}
); case "flyout": return (
- <Icon name="user" />{" "} - <FormattedMessage - id="collaborators.current-collabs.title" - defaultMessage={"Current Collaborators"} - description={ - "Title of a table listing users collaborating on that project" - } - /> + <Icon name="user" /> {titleText} {introText} + {nonOwnerNote && <> {nonOwnerNote}} {render_collaborators_list()} + {render_setting()}
); } diff --git a/src/packages/frontend/customize.tsx b/src/packages/frontend/customize.tsx index decc79733f4..7b82449dddf 100644 --- a/src/packages/frontend/customize.tsx +++ b/src/packages/frontend/customize.tsx @@ -146,6 +146,7 @@ export interface CustomizeState { organization_name: string; organization_url: string; share_server: boolean; + strict_collaborator_management: boolean; site_description: string; site_name: string; splash_image: string; @@ -261,7 +262,7 @@ export class CustomizeActions extends Actions { unlicensed_project_timetravel_limit: undefined, }); }; - + reload = async () => { await loadCustomizeState(); }; diff --git a/src/packages/frontend/i18n/common.ts b/src/packages/frontend/i18n/common.ts index 654ebdd2d57..6c518b88ec1 100644 --- a/src/packages/frontend/i18n/common.ts +++ b/src/packages/frontend/i18n/common.ts @@ -544,6 +544,18 @@ export const labels = defineMessages({ description: "Short label of a table, which shows the list of users having access", }, + owner: { + id: "labels.owner", + defaultMessage: "Owner", + description: + "Label for a project owner role - a user with full administrative rights", + }, + collaborator: { + id: "labels.collaborator", + defaultMessage: "Collaborator", + description: + "Label for a project collaborator role - a user with access to work on the project", + }, project_info_title: { id: "labels.project_info_title", defaultMessage: "Processes", @@ -1941,3 +1953,35 @@ export const course = defineMessages({ defaultMessage: "Restrict Student Projects", }, }); + +export const ownershipErrors = defineMessages({ + LAST_OWNER: { + id: "errors.ownership.last_owner", + defaultMessage: + "Cannot remove owner, because at least one owner is required.", + }, + NOT_OWNER: { + id: "errors.ownership.not_owner", + defaultMessage: "Only project owners can change user types.", + }, + CANNOT_REMOVE_OWNER: { + id: "errors.ownership.cannot_remove_owner", + defaultMessage: "Cannot remove an owner. Demote to collaborator first.", + }, + INVALID_TARGET: { + id: "errors.ownership.invalid_target", + defaultMessage: "Target user is not a member of this project.", + }, + INVALID_USER: { + id: "errors.ownership.invalid_user", + defaultMessage: "User not found or invalid.", + }, + INVALID_REQUESTING_USER: { + id: "errors.ownership.invalid_requesting_user", + defaultMessage: "You are not a project member.", + }, + INVALID_PROJECT_STATE: { + id: "errors.ownership.invalid_project_state", + defaultMessage: "Project data is missing or invalid.", + }, +}); diff --git a/src/packages/frontend/i18n/trans/ar_EG.json b/src/packages/frontend/i18n/trans/ar_EG.json index 969c3308ec6..d66ce4b3027 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 {يرجى التحقق من عنوان بريدك الإلكتروني وتأكيده:}}", @@ -177,8 +179,12 @@ "codemirror.extensions.ai_formula.insert_full_reply_button": "إدراج الرد الكامل", "codemirror.extensions.ai_formula.title": "توليد صيغة LaTeX", "collaborators.current-collabs.intro": "كل شخص مدرج أدناه يمكنه العمل معك بشكل تعاوني على أي دفتر Jupyter، أو Terminal Linux، أو ملف في هذا المشروع، وإضافة أو إزالة متعاونين آخرين.", + "collaborators.current-collabs.intro2": "يمكن للجميع المذكورين أدناه العمل معك بشكل تعاوني على أي دفتر Jupyter أو محطة Linux أو ملف في هذا المشروع. {manageUsersOnly, select, true { يمكن لمالكي المشروع فقط إضافة أو إزالة المتعاونين.} other { يمكن للمتعاونين أيضًا إضافة أو إزالة متعاونين آخرين.}}", "collaborators.current-collabs.remove_other": "هل أنت متأكد أنك تريد إزالة {user} من هذا المشروع؟ لن يكون لديهم وصول إلى هذا المشروع بعد الآن.", "collaborators.current-collabs.remove_self": "هل أنت متأكد أنك تريد إزالة نفسك من هذا المشروع؟ لن يكون لديك حق الوصول إلى هذا المشروع بعد الآن ولا يمكنك إضافة نفسك مرة أخرى.", + "collaborators.current-collabs.remove.ok_button": "نعم، إزالة {role}", + "collaborators.current-collabs.remove.owner_disabled": "يجب خفض رتبة المالكين قبل أن يتم إزالتهم.", + "collaborators.current-collabs.remove.setting_disabled": "يمكن للمالكين فقط إزالة المتعاونين عند تمكين هذا الإعداد.", "collaborators.current-collabs.title": "المتعاونون الحاليون", "command.format.ai_formula.button": "الصيغة", "command.format.ai_formula.label": "صيغة مولدة بواسطة AI", @@ -634,6 +640,13 @@ "editor.terminal.cmd.help.title": "عرض الوثائق لاستخدام محطة لينكس في CoCalc", "editor.toggle_pdf_dark_mode.label": "تبديل وضع PDF الداكن", "editor.toggle_pdf_dark_mode.title": "إيقاف الوضع الداكن لملف PDF لرؤية الملف الأصلي", + "errors.ownership.cannot_remove_owner": "لا يمكن إزالة المالك. قم بتخفيضه إلى متعاون أولاً.", + "errors.ownership.invalid_project_state": "بيانات المشروع مفقودة أو غير صالحة.", + "errors.ownership.invalid_requesting_user": "أنت لست عضوًا في المشروع.", + "errors.ownership.invalid_target": "المستخدم المستهدف ليس عضوًا في هذا المشروع.", + "errors.ownership.invalid_user": "المستخدم غير موجود أو غير صالح.", + "errors.ownership.last_owner": "لا يمكن إزالة المالك، لأن وجود مالك واحد على الأقل مطلوب.", + "errors.ownership.not_owner": "فقط مالكو المشروع يمكنهم تغيير أنواع المستخدمين.", "file_actions.compress.name": "ضغط", "file_actions.copy.name": "نسخ", "file_actions.create.name": "إنشاء", @@ -982,12 +995,14 @@ "labels.cloud_file_system": "أنظمة ملفات السحابة", "labels.cloud_storage_remote_filesystems": "التخزين السحابي وأنظمة الملفات البعيدة", "labels.code_folding": "طي الكود", + "labels.collaborator": "متعاون", "labels.collaborators": "المتعاونون", "labels.color": "لون", "labels.communication": "الاتصال", "labels.config": "الإعدادات", "labels.configuration": "التكوين", "labels.configuration.short": "الإعدادات", + "labels.connected": "متصل", "labels.connecting": "الاتصال", "labels.connection": "الاتصال", "labels.copied": "تم النسخ", @@ -1016,6 +1031,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 {حفظ}}", @@ -1077,6 +1093,7 @@ "labels.open": "افتح", "labels.other": "أخرى", "labels.overview": "نظرة عامة", + "labels.owner": "المالك", "labels.pages": "الصفحات", "labels.paste": "لصق", "labels.pay_as_you_go": "الدفع حسب الاستخدام", @@ -1095,6 +1112,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": "جاهز", @@ -1283,6 +1301,12 @@ "project_actions.rename_file.what": "إعادة تسمية {src}", "project-start-warning.content": "يجب أن تبدأ المشروع \"{project_title}\" قبل أن تتمكن من {what}. {title}", "project-start-warning.title": "بدء هذا المشروع؟", + "project.collaborators.add.owner_only_setting": "فقط مالكو المشروع يمكنهم إضافة المتعاونين عندما يكون تمكين الإدارة لمالكي المشروع فقط.", + "project.collaborators.demote.label": "خفض إلى متعاون", + "project.collaborators.demote.tooltip": "{isLastOwner, select, true {لا يمكن تخفيض مالك الحساب الأخير} other {تخفيض هذا المالك إلى متعاون}}", + "project.collaborators.non_owner_note": "يمكن لمالكي المشاريع فقط إدارة أدوار المستخدمين.", + "project.collaborators.promote.label": "ترقية إلى مالك", + "project.collaborators.promote.tooltip": "ترقية هذا المتعاون إلى مالك، مما يمنحهم التحكم الكامل في المشروع", "project.explorer.action-bar.check_all.button": "{checked, select, true {إلغاء تحديد الكل} other {تحديد الكل}}", "project.explorer.action-bar.currently_selected.info": "اضغط على مربع الاختيار إلى يسار الملف لنسخ أو تنزيل أو غير ذلك", "project.explorer.action-bar.currently_selected.items": "{checked} من {total} {items} محدد", @@ -1293,6 +1317,7 @@ "project.explorer.misc-side-buttons.open_dir.tooltip": "يفتح الدليل الحالي في مثيل خادم {name}، الذي يعمل داخل هذا المشروع", "project.explorer.search-bar.placeholder": "تصفية الملفات أو \"/\" للمحطة...", "project.explorer.start_project.warning": "لمشاهدة الملفات في هذا الدليل، عليك بدء هذا المشروع", + "project.history.log-entry.change_collaborator_type": "غيّر {target} من {old_group} إلى {new_group}", "project.history.log-entry.invited_user": "المستخدم المدعو", "project.history.log-entry.invited_user_via": "دعا مستخدم جديد عبر", "project.history.log-entry.miniterm": "تم تنفيذ أمر المحطة المصغرة {cmd}", @@ -1385,6 +1410,7 @@ "project.settings.about-box.name.label": "الاسم (اختياري)", "project.settings.about-box.starred.help": "يمكن تصفية المشاريع المميزة بالضغط على زر التصفية المميزة في قائمة مشاريعك.", "project.settings.about-box.title.label": "العنوان", + "project.settings.collaborators.title": "إدارة المتعاونين", "project.settings.compute-image-selector.button.save-restart": "حفظ وإعادة التشغيل", "project.settings.compute-image-selector.doubt": "{default, select, true {هذا هو الاختيار الافتراضي} other {ملاحظة: في حالة الشك، اختر \"{default_title}\"}}", "project.settings.compute-image-selector.software-env-info": "يوفر بيئة البرمجيات جميع البرامج التي يمكن لهذا المشروع الاستفادة منها. إذا كنت بحاجة إلى برامج إضافية، يمكنك إما تثبيتها في المشروع أو الاتصال بالدعم. تعلم عن تثبيت حزم Python، نواة Jupyter لـ Python، حزم R وحزم Julia.", @@ -1408,6 +1434,9 @@ "project.settings.hide-delete-box.hide.label": "{hidden, select, true {إظهار المشروع} other {إخفاء المشروع}}", "project.settings.hide-delete-box.hide.switch": "{hidden, select, true {مخفي} other {مرئي}}", "project.settings.hide-delete-box.title": "إخفاء أو حذف المشروع", + "project.settings.manage_users_owner_only": "السماح فقط للمالكين بإدارة المتعاونين.", + "project.settings.manage_users_owner_only.note": "لا يمكن تغيير هذا الإعداد إلا من قبل مالكي المشروع.", + "project.settings.manage_users_owner_only.site_enforced": "هذا الإعداد مفروض من قبل مدير الموقع لجميع المشاريع.", "project.settings.restart-project.button.label": "{is_running, select, true {إعادة التشغيل} other {بدء}}", "project.settings.site-license.body.info": "معلومات حول التراخيص المرفقة. انقر على صف لعرض التفاصيل.", "project.settings.site-license.button.label": "الترقية باستخدام مفتاح الترخيص...", @@ -1423,7 +1452,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 +1483,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..8fe2cedfcaf 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:}}", @@ -177,8 +179,12 @@ "codemirror.extensions.ai_formula.insert_full_reply_button": "Antwort einfügen", "codemirror.extensions.ai_formula.title": "LaTeX-Formel generieren", "collaborators.current-collabs.intro": "Jeder, der unten aufgeführt ist, kann mit Ihnen an jedem Jupyter-Notebook, Linux-Terminal oder jeder Datei in diesem Projekt zusammenarbeiten und andere Mitwirkende hinzufügen oder entfernen.", + "collaborators.current-collabs.intro2": "Jeder, der unten aufgeführt ist, kann mit Ihnen an jedem Jupyter Notebook, Linux-Terminal oder jeder Datei in diesem Projekt zusammenarbeiten. {manageUsersOnly, select, true { Nur Projekteigentümer können Mitarbeiter hinzufügen oder entfernen.} other { Mitarbeiter können auch andere Mitarbeiter hinzufügen oder entfernen.}}", "collaborators.current-collabs.remove_other": "Sind Sie sicher, dass Sie {user} aus diesem Projekt entfernen möchten? Sie werden keinen Zugriff mehr auf dieses Projekt haben.", "collaborators.current-collabs.remove_self": "Sind Sie sicher, dass Sie sich selbst aus diesem Projekt entfernen möchten? Sie werden keinen Zugriff mehr auf dieses Projekt haben und können sich nicht wieder hinzufügen.", + "collaborators.current-collabs.remove.ok_button": "Ja, {role} entfernen", + "collaborators.current-collabs.remove.owner_disabled": "Eigentümer müssen herabgestuft werden, bevor sie entfernt werden können.", + "collaborators.current-collabs.remove.setting_disabled": "Nur Eigentümer können Mitarbeiter entfernen, wenn diese Einstellung aktiviert ist.", "collaborators.current-collabs.title": "Aktuelle Mitarbeiter", "command.format.ai_formula.button": "KI-Formel", "command.format.ai_formula.label": "KI-generierte Formel", @@ -634,6 +640,13 @@ "editor.terminal.cmd.help.title": "Öffne die Dokumentation für die Nutzung des Linux-Terminals in CoCalc.", "editor.toggle_pdf_dark_mode.label": "PDF-Dunkelmodus umschalten", "editor.toggle_pdf_dark_mode.title": "Schalten Sie den Dunkelmodus der PDF aus, um die Originaldatei zu sehen", + "errors.ownership.cannot_remove_owner": "Kann einen Eigentümer nicht entfernen. Zuerst zum Mitarbeiter herabstufen.", + "errors.ownership.invalid_project_state": "Projektdaten fehlen oder sind ungültig.", + "errors.ownership.invalid_requesting_user": "Sie sind kein Projektmitglied.", + "errors.ownership.invalid_target": "Zielbenutzer ist kein Mitglied dieses Projekts.", + "errors.ownership.invalid_user": "Benutzer nicht gefunden oder ungültig.", + "errors.ownership.last_owner": "Eigentümer kann nicht entfernt werden, da mindestens ein Eigentümer erforderlich ist.", + "errors.ownership.not_owner": "Nur Projekteigentümer können Benutzertypen ändern.", "file_actions.compress.name": "Komprimieren", "file_actions.copy.name": "Kopieren", "file_actions.create.name": "Erstellen", @@ -982,12 +995,14 @@ "labels.cloud_file_system": "Cloud Dateisystem", "labels.cloud_storage_remote_filesystems": "Cloud-Speicher & entfernte Dateisysteme", "labels.code_folding": "Code-Faltung", + "labels.collaborator": "Mitarbeiter", "labels.collaborators": "Mitarbeiter", "labels.color": "Farbe", "labels.communication": "Kommunikation", "labels.config": "Konfiguration", "labels.configuration": "Konfiguration", "labels.configuration.short": "Konfig", + "labels.connected": "Verbunden", "labels.connecting": "Verbinde", "labels.connection": "Verbindung", "labels.copied": "kopiert", @@ -1016,6 +1031,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}}", @@ -1077,6 +1093,7 @@ "labels.open": "Öffnen", "labels.other": "Andere", "labels.overview": "Übersicht", + "labels.owner": "Eigentümer", "labels.pages": "Seiten", "labels.paste": "Einfügen", "labels.pay_as_you_go": "Bezahlen nach Verbrauch", @@ -1095,6 +1112,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", @@ -1283,6 +1301,12 @@ "project_actions.rename_file.what": "umbenennen {src}", "project-start-warning.content": "Sie müssen das Projekt \"{project_title}\" starten, bevor Sie {what}. {title}", "project-start-warning.title": "Dieses Projekt starten?", + "project.collaborators.add.owner_only_setting": "Nur Projekteigentümer können Mitarbeiter hinzufügen, wenn die Verwaltung nur durch den Eigentümer aktiviert ist.", + "project.collaborators.demote.label": "Herabstufen zum Mitarbeiter", + "project.collaborators.demote.tooltip": "{isLastOwner, select, true {Kann den letzten Besitzer nicht degradieren} other {Diesen Besitzer zum Mitarbeiter degradieren}}", + "project.collaborators.non_owner_note": "Nur Projekteigentümer können Benutzerrollen verwalten.", + "project.collaborators.promote.label": "Zum Besitzer befördern", + "project.collaborators.promote.tooltip": "Befördern Sie diesen Mitarbeiter zum Eigentümer und geben Sie ihm die volle Projektkontrolle.", "project.explorer.action-bar.check_all.button": "{checked, select, true {Keine auswählen} other {Alle auswählen}}", "project.explorer.action-bar.currently_selected.info": "Klicke links neben einer Datei auf die Checkbox, um sie zu kopieren, herunterzuladen usw.", "project.explorer.action-bar.currently_selected.items": "{checked} von {total} {items} ausgewählt", @@ -1293,6 +1317,7 @@ "project.explorer.misc-side-buttons.open_dir.tooltip": "Öffnet das aktuelle Verzeichnis in einer {name}-Serverinstanz, die innerhalb dieses Projekts läuft.", "project.explorer.search-bar.placeholder": "Dateien filtern oder \"/\" für Terminal...", "project.explorer.start_project.warning": "Um die Dateien in diesem Verzeichnis zu sehen, müssen Sie dieses Projekt starten.", + "project.history.log-entry.change_collaborator_type": "änderte {target} von {old_group} zu {new_group}", "project.history.log-entry.invited_user": "eingeladener Benutzer", "project.history.log-entry.invited_user_via": "neuen Benutzer eingeladen über", "project.history.log-entry.miniterm": "ausgeführter Mini-Terminal-Befehl {cmd}", @@ -1385,6 +1410,7 @@ "project.settings.about-box.name.label": "Name (optional)", "project.settings.about-box.starred.help": "Markierte Projekte können gefiltert werden, indem Sie in Ihrer Projektliste auf die Schaltfläche mit dem Sternfilter klicken.", "project.settings.about-box.title.label": "Titel", + "project.settings.collaborators.title": "Kollaborationsverwaltung", "project.settings.compute-image-selector.button.save-restart": "Speichern und neu starten", "project.settings.compute-image-selector.doubt": "{default, select, true {Dies ist die Standardauswahl} other {Hinweis: im Zweifelsfall wählen Sie \"{default_title}\"}}", "project.settings.compute-image-selector.software-env-info": "Eine Softwareumgebung stellt die gesamte Software bereit, die dieses Projekt nutzen kann. Wenn Sie zusätzliche Software benötigen, können Sie sie entweder im Projekt installieren oder den Support kontaktieren. Erfahren Sie mehr über Installation von Python-Paketen, Python Jupyter Kernel, R-Pakete und Julia-Pakete.", @@ -1408,6 +1434,9 @@ "project.settings.hide-delete-box.hide.label": "{hidden, select, true {Projekt einblenden} other {Projekt ausblenden}}", "project.settings.hide-delete-box.hide.switch": "{hidden, select, true {Ausgeblendet} other {Sichtbar}}", "project.settings.hide-delete-box.title": "Projekt ausblenden oder löschen", + "project.settings.manage_users_owner_only": "Nur Eigentümern erlauben, Mitarbeiter zu verwalten.", + "project.settings.manage_users_owner_only.note": "Diese Einstellung kann nur von Projekteigentümern geändert werden.", + "project.settings.manage_users_owner_only.site_enforced": "Diese Einstellung wird vom Site-Administrator für alle Projekte erzwungen.", "project.settings.restart-project.button.label": "{is_running, select, true {Neustarten} other {Starten}}", "project.settings.site-license.body.info": "Informationen über angehängte Lizenzen. Klicken Sie auf eine Zeile, um Details anzuzeigen.", "project.settings.site-license.button.label": "Upgrade mit einem Lizenzschlüssel...", @@ -1423,7 +1452,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 +1483,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..ab9772c9cf5 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:}}", @@ -177,8 +179,12 @@ "codemirror.extensions.ai_formula.insert_full_reply_button": "Insertar respuesta completa", "codemirror.extensions.ai_formula.title": "Generar fórmula LaTeX", "collaborators.current-collabs.intro": "Todos los enumerados a continuación pueden trabajar colaborativamente contigo en cualquier Jupyter Notebook, Terminal de Linux o archivo en este proyecto, y agregar o eliminar otros colaboradores.", + "collaborators.current-collabs.intro2": "Todos los enumerados a continuación pueden trabajar de manera colaborativa contigo en cualquier Jupyter Notebook, Terminal de Linux o archivo de este proyecto. {manageUsersOnly, select, true { Solo los propietarios del proyecto pueden añadir o eliminar colaboradores.} other { Los colaboradores también pueden añadir o eliminar a otros colaboradores.}}", "collaborators.current-collabs.remove_other": "¿Estás seguro de que quieres eliminar a {user} de este proyecto? Ya no tendrá acceso a este proyecto.", "collaborators.current-collabs.remove_self": "¿Está seguro de que quiere eliminar su cuenta de este proyecto? Ya no tendrá acceso a este proyecto y no podrá añadirse de nuevo.", + "collaborators.current-collabs.remove.ok_button": "Sí, eliminar {role}", + "collaborators.current-collabs.remove.owner_disabled": "Los propietarios deben ser degradados antes de que puedan ser eliminados.", + "collaborators.current-collabs.remove.setting_disabled": "Solo los propietarios pueden eliminar colaboradores cuando esta configuración está habilitada.", "collaborators.current-collabs.title": "Colaboradores Actuales", "command.format.ai_formula.button": "Fórmula", "command.format.ai_formula.label": "Fórmula Generada por IA", @@ -634,6 +640,13 @@ "editor.terminal.cmd.help.title": "Mostrar documentación para usar el Terminal de Linux en CoCalc", "editor.toggle_pdf_dark_mode.label": "Alternar modo oscuro de PDF", "editor.toggle_pdf_dark_mode.title": "Desactivar el modo oscuro del PDF para ver el archivo original", + "errors.ownership.cannot_remove_owner": "No se puede eliminar a un propietario. Degradar a colaborador primero.", + "errors.ownership.invalid_project_state": "Los datos del proyecto están faltando o son inválidos.", + "errors.ownership.invalid_requesting_user": "No eres miembro del proyecto.", + "errors.ownership.invalid_target": "El usuario objetivo no es miembro de este proyecto.", + "errors.ownership.invalid_user": "Usuario no encontrado o no válido.", + "errors.ownership.last_owner": "No se puede eliminar al propietario, porque se requiere al menos un propietario.", + "errors.ownership.not_owner": "Solo los propietarios del proyecto pueden cambiar los tipos de usuario.", "file_actions.compress.name": "Comprimir", "file_actions.copy.name": "Copiar", "file_actions.create.name": "Crear", @@ -982,12 +995,14 @@ "labels.cloud_file_system": "Sistemas de Archivos en la Nube", "labels.cloud_storage_remote_filesystems": "Almacenamiento en la Nube y Sistemas de Archivos Remotos", "labels.code_folding": "Plegado de Código", + "labels.collaborator": "Colaborador", "labels.collaborators": "Colaboradores", "labels.color": "Color", "labels.communication": "Comunicación", "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 +1031,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}}", @@ -1077,6 +1093,7 @@ "labels.open": "Abrir", "labels.other": "Otro", "labels.overview": "Visión general", + "labels.owner": "Propietario", "labels.pages": "Páginas", "labels.paste": "Pegar", "labels.pay_as_you_go": "Pago por Uso", @@ -1095,6 +1112,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", @@ -1283,6 +1301,12 @@ "project_actions.rename_file.what": "renombrar {src}", "project-start-warning.content": "Debes iniciar el proyecto \"{project_title}\" antes de que puedas {what}. {title}", "project-start-warning.title": "¿Iniciar este proyecto?", + "project.collaborators.add.owner_only_setting": "Solo los propietarios del proyecto pueden añadir colaboradores cuando la gestión de solo propietarios está habilitada.", + "project.collaborators.demote.label": "Degradar a Colaborador", + "project.collaborators.demote.tooltip": "{isLastOwner, select, true {No se puede degradar al último propietario} other {Degradar este propietario a colaborador}}", + "project.collaborators.non_owner_note": "Solo los propietarios del proyecto pueden gestionar los roles de usuario.", + "project.collaborators.promote.label": "Promover a propietario", + "project.collaborators.promote.tooltip": "Promocionar a este colaborador a propietario, dándole control total del proyecto", "project.explorer.action-bar.check_all.button": "{checked, select, true {Desmarcar todo} other {Marcar todo}}", "project.explorer.action-bar.currently_selected.info": "Haga clic en la casilla a la izquierda de un archivo para copiar, descargar, etc.", "project.explorer.action-bar.currently_selected.items": "{checked} de {total} {items} seleccionados", @@ -1293,6 +1317,7 @@ "project.explorer.misc-side-buttons.open_dir.tooltip": "Abre el directorio actual en una instancia del servidor {name}, que se ejecuta dentro de este proyecto.", "project.explorer.search-bar.placeholder": "Filtrar archivos o \"/\" para terminal...", "project.explorer.start_project.warning": "Para ver los archivos en este directorio, tienes que iniciar este proyecto.", + "project.history.log-entry.change_collaborator_type": "cambió {target} de {old_group} a {new_group}", "project.history.log-entry.invited_user": "usuario invitado", "project.history.log-entry.invited_user_via": "invitó a un nuevo usuario a través de", "project.history.log-entry.miniterm": "ejecutó el comando del mini terminal {cmd}", @@ -1385,6 +1410,7 @@ "project.settings.about-box.name.label": "Nombre (opcional)", "project.settings.about-box.starred.help": "Los proyectos destacados se pueden filtrar haciendo clic en el botón de filtro destacado en tu lista de proyectos.", "project.settings.about-box.title.label": "Título", + "project.settings.collaborators.title": "Gestión de colaboradores", "project.settings.compute-image-selector.button.save-restart": "Guardar y Reiniciar", "project.settings.compute-image-selector.doubt": "{default, select, true {Esta es la selección predeterminada} other {Nota: en caso de duda, seleccione \"{default_title}\"}}", "project.settings.compute-image-selector.software-env-info": "Un entorno de software proporciona todo el software que este proyecto puede utilizar. Si necesitas software adicional, puedes instalarlo en el proyecto o contactar con soporte. Aprende sobre instalar paquetes de Python, Kernel de Jupyter de Python, Paquetes de R y paquetes de Julia.", @@ -1408,6 +1434,9 @@ "project.settings.hide-delete-box.hide.label": "{hidden, select, true {Mostrar proyecto} other {Ocultar proyecto}}", "project.settings.hide-delete-box.hide.switch": "{hidden, select, true {Oculto} other {Visible}}", "project.settings.hide-delete-box.title": "Ocultar o Eliminar Proyecto", + "project.settings.manage_users_owner_only": "Permitir solo a los propietarios gestionar colaboradores.", + "project.settings.manage_users_owner_only.note": "Este ajuste solo puede ser cambiado por los propietarios del proyecto.", + "project.settings.manage_users_owner_only.site_enforced": "Esta configuración está impuesta por el administrador del sitio para todos los proyectos.", "project.settings.restart-project.button.label": "{is_running, select, true {Reiniciar} other {Iniciar}}", "project.settings.site-license.body.info": "Información sobre las licencias adjuntas. Haz clic en una fila para expandir detalles.", "project.settings.site-license.button.label": "Actualizar con una clave de licencia...", @@ -1423,7 +1452,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 +1483,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..f5f1fe6ae34 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:}}", @@ -177,8 +179,12 @@ "codemirror.extensions.ai_formula.insert_full_reply_button": "Txertatu erantzun osoa", "codemirror.extensions.ai_formula.title": "Sortu LaTeX Formula", "collaborators.current-collabs.intro": "Jarraian zerrendatutako guztiek zurekin lankidetzan aritu daitezke proiektu honetako edozein Jupyter Notebook, Linux Terminal edo fitxategitan, eta beste kolaboratzaile batzuk gehitu edo kendu ditzakete.", + "collaborators.current-collabs.intro2": "Jarraian zerrendatutako pertsona guztiek zurekin elkarlanean aritu daitezke proiektu honetako edozein Jupyter Notebok, Linux Terminal edo fitxategitan. {manageUsersOnly, select, true { Proiektuaren jabeek bakarrik gehi ditzakete edo kendu lankideak.} other { Lankideek ere gehi edo kendu ditzakete beste lankide batzuk.}}", "collaborators.current-collabs.remove_other": "Ziur zaude {user} proiektu honetatik kendu nahi duzula? Ez dute proiektu honetara sarbiderik izango.", "collaborators.current-collabs.remove_self": "Ziur zaude proiektu honetatik zeure burua kendu nahi duzula? Ez duzu proiektu honetara sarbiderik izango eta ezin izango duzu zeure buru barriro gehitu.", + "collaborators.current-collabs.remove.ok_button": "Bai, kendu {role}", + "collaborators.current-collabs.remove.owner_disabled": "Jabeak kendu aurretik jaitsi behar dira.", + "collaborators.current-collabs.remove.setting_disabled": "Ezarpen hau gaituta dagoenean, jabeek bakarrik ken ditzakete lankideak.", "collaborators.current-collabs.title": "Uneko lankideak", "command.format.ai_formula.button": "Formula", "command.format.ai_formula.label": "AI-k Sortutako Formula", @@ -634,6 +640,13 @@ "editor.terminal.cmd.help.title": "Erakutsi dokumentazioa Linux Terminala CoCalc-en erabiltzeko.", "editor.toggle_pdf_dark_mode.label": "Aldatu PDF Modu Ilunera", "editor.toggle_pdf_dark_mode.title": "PDFaren ilunpeko modua desaktibatu, jatorrizko fitxategia ikusteko", + "errors.ownership.cannot_remove_owner": "Ezin da jabe bat kendu. Lehenik lankide izatera jaitsi.", + "errors.ownership.invalid_project_state": "Proiektuaren datuak falta dira edo baliogabeak dira.", + "errors.ownership.invalid_requesting_user": "Ez zara proiektuaren kide.", + "errors.ownership.invalid_target": "Helburu-erabiltzailea ez da proiektu honetako kidea.", + "errors.ownership.invalid_user": "Erabiltzailea ez da aurkitu edo baliogabea da.", + "errors.ownership.last_owner": "Ezin da jabea kendu, gutxienez jabe bat beharrezkoa baita.", + "errors.ownership.not_owner": "Proiektuaren jabeek bakarrik alda dezakete erabiltzaileen motak.", "file_actions.compress.name": "Konprimitu", "file_actions.copy.name": "Kopiatu", "file_actions.create.name": "Sortu", @@ -982,12 +995,14 @@ "labels.cloud_file_system": "Hodeiko Fitxategi Sistemak", "labels.cloud_storage_remote_filesystems": "Hodeiko Biltegiratzea eta Urruneko Fitxategi Sistemak", "labels.code_folding": "Kode Tolestea", + "labels.collaborator": "Lankide", "labels.collaborators": "Lankideak", "labels.color": "Kolore", "labels.communication": "Komunikazioa", "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 +1031,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}}", @@ -1077,6 +1093,7 @@ "labels.open": "Ireki", "labels.other": "Beste", "labels.overview": "Orokorra", + "labels.owner": "Jabea", "labels.pages": "Orriak", "labels.paste": "Itsatsi", "labels.pay_as_you_go": "Ordaindu Erabiltzen Duzun Neurrira", @@ -1095,6 +1112,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", @@ -1283,6 +1301,12 @@ "project_actions.rename_file.what": "berrizendatu {src}", "project-start-warning.content": "Proiektua hasi behar duzu \"{project_title}\" {what} baino lehen. {title}", "project-start-warning.title": "Hasi proiektu hau?", + "project.collaborators.add.owner_only_setting": "Jabe bakarrak proiektuaren lankideak gehi ditzake jabearen kudeaketa bakarrik gaituta dagoenean.", + "project.collaborators.demote.label": "Jaitsi Kolaboratzailera", + "project.collaborators.demote.tooltip": "{isLastOwner, select, true {Ezin da azken jabea jaitsi} other {Jabe hau kolaboratzaile bihurtu}}", + "project.collaborators.non_owner_note": "Proiektuaren jabeek bakarrik kudeatu ditzakete erabiltzaileen rolak.", + "project.collaborators.promote.label": "Jabe bihurtu", + "project.collaborators.promote.tooltip": "Kolaboratzaile hau jabe bihurtu, proiektuaren kontrol osoa emanez", "project.explorer.action-bar.check_all.button": "{checked, select, true {Desmarkatu denak} other {Markatu denak}}", "project.explorer.action-bar.currently_selected.info": "Egin klik fitxategi baten ezkerrean dagoen kontrol-laukian kopiatzeko, deskargatzeko, etab.", "project.explorer.action-bar.currently_selected.items": "{checked} {total} {items} hautatuta", @@ -1293,6 +1317,7 @@ "project.explorer.misc-side-buttons.open_dir.tooltip": "Irekitzen du uneko direktorioa {name} zerbitzari instantzia batean, proiektu honen barruan exekutatzen.", "project.explorer.search-bar.placeholder": "Fitxategiak iragazi edo \"/\" terminalerako...", "project.explorer.start_project.warning": "Direktorio honetako fitxategiak ikusteko, proiektu hau hasi behar duzu.", + "project.history.log-entry.change_collaborator_type": "aldatu {target} {old_group} tik {new_group} ra", "project.history.log-entry.invited_user": "gonbidatutako erabiltzailea", "project.history.log-entry.invited_user_via": "gonbidatu berri bat bidali bidez", "project.history.log-entry.miniterm": "exekutatu mini terminaleko komandoa {cmd}", @@ -1385,6 +1410,7 @@ "project.settings.about-box.name.label": "Izena (aukerakoa)", "project.settings.about-box.starred.help": "Izar-markatutako proiektuak iragazi daitezke izar-markatutako iragazkiaren botoian klik eginez zure proiektuen zerrendan.", "project.settings.about-box.title.label": "Izenburua", + "project.settings.collaborators.title": "Kolaboratzaileen Kudeaketa", "project.settings.compute-image-selector.button.save-restart": "Gorde eta Berrabiarazi", "project.settings.compute-image-selector.doubt": "{default, select, true {Hau da lehenetsitako hautapena} other {Oharra: zalantzan, hautatu \"{default_title}\"}}", "project.settings.compute-image-selector.software-env-info": "Software ingurune batek proiektu honek erabil dezakeen software guztia eskaintzen du. Software gehigarria behar baduzu, proiektuan instalatu dezakezu edo laguntzarekin harremanetan jarri. Python paketeak instalatzea, Python Jupyter Kernel, R paketeak eta Julia paketeak ikasi.", @@ -1408,6 +1434,9 @@ "project.settings.hide-delete-box.hide.label": "{hidden, select, true {Proiektua Bistaratu} other {Proiektua Ezkutatu}}", "project.settings.hide-delete-box.hide.switch": "{hidden, select, true {Ezkutua} other {Ikusgai}}", "project.settings.hide-delete-box.title": "Ezkutatu edo Ezabatu Proiektua", + "project.settings.manage_users_owner_only": "Jabeei bakarrik utzi lankideak kudeatzen.", + "project.settings.manage_users_owner_only.note": "Ezarpen hau proiektuaren jabeek soilik alda dezakete.", + "project.settings.manage_users_owner_only.site_enforced": "Ezarpen hau gune-administratzaileak proiektu guztientzat ezartzen du.", "project.settings.restart-project.button.label": "{is_running, select, true {Berrabiarazi} other {Hasi}}", "project.settings.site-license.body.info": "Informazioa erantsitako lizentziei buruz. Xehetasunak zabaltzeko, klik egin errenkadan.", "project.settings.site-license.button.label": "Eguneratu lizentzia-gako bat erabiliz...", @@ -1423,7 +1452,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 +1483,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..fd3d5ea54e3 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 :}}", @@ -177,8 +179,12 @@ "codemirror.extensions.ai_formula.insert_full_reply_button": "Insérer la réponse complète", "codemirror.extensions.ai_formula.title": "Générer une formule LaTeX", "collaborators.current-collabs.intro": "Toutes les personnes listées ci-dessous peuvent collaborer avec vous sur n'importe quel Jupyter Notebook, Terminal Linux ou fichier dans ce projet, et ajouter ou supprimer d'autres collaborateurs.", + "collaborators.current-collabs.intro2": "Tout le monde listé ci-dessous peut collaborer avec vous sur n'importe quel Jupyter Notebook, Terminal Linux ou fichier dans ce projet. {manageUsersOnly, select, true { Seuls les propriétaires du projet peuvent ajouter ou supprimer des collaborateurs.} other { Les collaborateurs peuvent également ajouter ou supprimer d'autres collaborateurs.}}", "collaborators.current-collabs.remove_other": "Êtes-vous sûr de vouloir retirer {user} de ce projet ? Ils n'auront plus accès à ce projet.", "collaborators.current-collabs.remove_self": "Êtes-vous sûr de vouloir vous retirer de ce projet ? Vous n'aurez plus accès à ce projet et ne pourrez pas vous y ajouter de nouveau.", + "collaborators.current-collabs.remove.ok_button": "Oui, supprimer {role}", + "collaborators.current-collabs.remove.owner_disabled": "Les propriétaires doivent être rétrogradés avant de pouvoir être supprimés.", + "collaborators.current-collabs.remove.setting_disabled": "Seuls les propriétaires peuvent supprimer des collaborateurs lorsque ce paramètre est activé.", "collaborators.current-collabs.title": "Collaborateurs actuels", "command.format.ai_formula.button": "Formule", "command.format.ai_formula.label": "Formule Générée par AI", @@ -634,6 +640,13 @@ "editor.terminal.cmd.help.title": "Afficher la documentation pour utiliser le terminal Linux dans CoCalc.", "editor.toggle_pdf_dark_mode.label": "Basculer le mode sombre PDF", "editor.toggle_pdf_dark_mode.title": "Désactiver le mode sombre du PDF pour voir le fichier original", + "errors.ownership.cannot_remove_owner": "Impossible de supprimer un propriétaire. Rétrogradez-le d'abord en collaborateur.", + "errors.ownership.invalid_project_state": "Les données du projet sont manquantes ou invalides.", + "errors.ownership.invalid_requesting_user": "Vous n'êtes pas membre du projet.", + "errors.ownership.invalid_target": "L'utilisateur cible n'est pas membre de ce projet.", + "errors.ownership.invalid_user": "Utilisateur non trouvé ou invalide.", + "errors.ownership.last_owner": "Impossible de supprimer le propriétaire, car au moins un propriétaire est requis.", + "errors.ownership.not_owner": "Seuls les propriétaires de projet peuvent modifier les types d'utilisateur.", "file_actions.compress.name": "Compresser", "file_actions.copy.name": "Copier", "file_actions.create.name": "Créer", @@ -982,12 +995,14 @@ "labels.cloud_file_system": "Systèmes de fichiers en cloud", "labels.cloud_storage_remote_filesystems": "Stockage Cloud & Systèmes de Fichiers à Distance", "labels.code_folding": "Repliage de code", + "labels.collaborator": "Collaborateur", "labels.collaborators": "Collaborateurs", "labels.color": "Couleur", "labels.communication": "Communication", "labels.config": "Config", "labels.configuration": "Configuration", "labels.configuration.short": "Config", + "labels.connected": "Connecté", "labels.connecting": "Connexion", "labels.connection": "Connexion", "labels.copied": "copié", @@ -1016,6 +1031,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}}", @@ -1077,6 +1093,7 @@ "labels.open": "Ouvrir", "labels.other": "Autre", "labels.overview": "Aperçu", + "labels.owner": "Propriétaire", "labels.pages": "Pages", "labels.paste": "Coller", "labels.pay_as_you_go": "Paiement à l'utilisation", @@ -1095,6 +1112,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", @@ -1283,6 +1301,12 @@ "project_actions.rename_file.what": "renommer {src}", "project-start-warning.content": "Vous devez démarrer le projet \"{project_title}\" avant de pouvoir {what}. {title}", "project-start-warning.title": "Démarrer ce projet ?", + "project.collaborators.add.owner_only_setting": "Seuls les propriétaires de projet peuvent ajouter des collaborateurs lorsque la gestion réservée aux propriétaires est activée.", + "project.collaborators.demote.label": "Rétrograder en Collaborateur", + "project.collaborators.demote.tooltip": "{isLastOwner, select, true {Impossible de rétrograder le dernier propriétaire} other {Rétrograder ce propriétaire à collaborateur}}", + "project.collaborators.non_owner_note": "Seuls les propriétaires de projet peuvent gérer les rôles des utilisateurs.", + "project.collaborators.promote.label": "Promouvoir au propriétaire", + "project.collaborators.promote.tooltip": "Promouvoir ce collaborateur au statut de propriétaire, en lui donnant le contrôle total du projet", "project.explorer.action-bar.check_all.button": "{checked, select, true {Tout décocher} other {Tout cocher}}", "project.explorer.action-bar.currently_selected.info": "Cliquez sur la case à cocher à gauche d'un fichier pour copier, télécharger, etc.", "project.explorer.action-bar.currently_selected.items": "{checked} sur {total} {items} sélectionnés", @@ -1293,6 +1317,7 @@ "project.explorer.misc-side-buttons.open_dir.tooltip": "Ouvre le répertoire actuel dans une instance de serveur {name}, exécutée à l'intérieur de ce projet", "project.explorer.search-bar.placeholder": "Filtrer les fichiers ou \"/\" pour le terminal...", "project.explorer.start_project.warning": "Pour voir les fichiers dans ce répertoire, vous devez démarrer ce projet.", + "project.history.log-entry.change_collaborator_type": "a changé {target} de {old_group} à {new_group}", "project.history.log-entry.invited_user": "utilisateur invité", "project.history.log-entry.invited_user_via": "invité un nouvel utilisateur via", "project.history.log-entry.miniterm": "commande mini terminal exécutée {cmd}", @@ -1385,6 +1410,7 @@ "project.settings.about-box.name.label": "Nom (facultatif)", "project.settings.about-box.starred.help": "Les projets étoilés peuvent être filtrés en cliquant sur le bouton de filtre étoilé dans votre liste de projets.", "project.settings.about-box.title.label": "Titre", + "project.settings.collaborators.title": "Gestion des collaborateurs", "project.settings.compute-image-selector.button.save-restart": "Enregistrer et Redémarrer", "project.settings.compute-image-selector.doubt": "{default, select, true {Ceci est la sélection par défaut} other {Remarque : en cas de doute, sélectionnez \"{default_title}\"}}", "project.settings.compute-image-selector.software-env-info": "Un environnement logiciel fournit tous les logiciels dont ce projet peut bénéficier. Si vous avez besoin de logiciels supplémentaires, vous pouvez soit les installer dans le projet, soit contacter le support. Apprenez-en plus sur l'installation de packages Python, le noyau Jupyter Python, les packages R et les packages Julia.", @@ -1408,6 +1434,9 @@ "project.settings.hide-delete-box.hide.label": "{hidden, select, true {Afficher le projet} other {Masquer le projet}}", "project.settings.hide-delete-box.hide.switch": "{hidden, select, true {Caché} other {Visible}}", "project.settings.hide-delete-box.title": "Masquer ou Supprimer le Projet", + "project.settings.manage_users_owner_only": "Autoriser uniquement les propriétaires à gérer les collaborateurs.", + "project.settings.manage_users_owner_only.note": "Cette option ne peut être modifiée que par les propriétaires du projet.", + "project.settings.manage_users_owner_only.site_enforced": "Ce paramètre est imposé par l'administrateur du site pour tous les projets.", "project.settings.restart-project.button.label": "{is_running, select, true {Redémarrer} other {Démarrer}}", "project.settings.site-license.body.info": "Informations sur les licences attachées. Cliquez sur une ligne pour afficher les détails.", "project.settings.site-license.button.label": "Mettre à niveau avec une clé de licence...", @@ -1423,7 +1452,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 +1483,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..8efe806ffa8 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 {אנא בדוק ואמת את כתובת האימייל שלך:}}", @@ -177,8 +179,12 @@ "codemirror.extensions.ai_formula.insert_full_reply_button": "הכנס תגובה מלאה", "codemirror.extensions.ai_formula.title": "צור נוסחת LaTeX", "collaborators.current-collabs.intro": "כל מי שמופיע ברשימה למטה יכול לעבוד בשיתוף פעולה איתך על כל Jupyter Notebook, טרמינל לינוקס או קובץ בפרויקט הזה, ולהוסיף או להסיר משתפי פעולה נוספים.", + "collaborators.current-collabs.intro2": "כולם המפורטים למטה יכולים לעבוד איתך בשיתוף פעולה על כל Jupyter Notebook, טרמינל לינוקס או קובץ בפרויקט זה. {manageUsersOnly, select, true {רק בעלי הפרויקט יכולים להוסיף או להסיר משתפי פעולה.} other {משתפי פעולה יכולים גם להוסיף או להסיר משתפי פעולה אחרים.}}", "collaborators.current-collabs.remove_other": "האם אתה בטוח שברצונך להסיר את {user} מפרויקט זה? לא תהיה להם יותר גישה לפרויקט זה.", "collaborators.current-collabs.remove_self": "האם אתה בטוח שברצונך להסיר את עצמך מפרויקט זה? לא תהיה לך גישה לפרויקט זה ולא תוכל להוסיף את עצמך מחדש.", + "collaborators.current-collabs.remove.ok_button": "כן, הסר {role}", + "collaborators.current-collabs.remove.owner_disabled": "יש להוריד דרגה של בעלי המניות לפני שניתן להסיר אותם.", + "collaborators.current-collabs.remove.setting_disabled": "רק בעלי החשבון יכולים להסיר משתפי פעולה כאשר הגדרה זו מופעלת.", "collaborators.current-collabs.title": "משתפי פעולה נוכחיים", "command.format.ai_formula.button": "נוסחה", "command.format.ai_formula.label": "נוסחה שנוצרה על ידי AI", @@ -634,6 +640,13 @@ "editor.terminal.cmd.help.title": "הצג תיעוד לשימוש בטרמינל לינוקס ב-CoCalc", "editor.toggle_pdf_dark_mode.label": "החלף מצב כהה עבור PDF", "editor.toggle_pdf_dark_mode.title": "כבה את מצב החושך של ה-PDF, כדי לראות את הקובץ המקורי", + "errors.ownership.cannot_remove_owner": "לא ניתן להסיר בעלים. יש להוריד תחילה לשתף פעולה.", + "errors.ownership.invalid_project_state": "נתוני הפרויקט חסרים או לא תקינים.", + "errors.ownership.invalid_requesting_user": "אינך חבר בפרויקט.", + "errors.ownership.invalid_target": "המשתמש המיועד אינו חבר בפרויקט זה.", + "errors.ownership.invalid_user": "משתמש לא נמצא או לא חוקי.", + "errors.ownership.last_owner": "לא ניתן להסיר את הבעלים, מכיוון שנדרש לפחות בעלים אחד.", + "errors.ownership.not_owner": "רק בעלי הפרויקט יכולים לשנות סוגי משתמשים.", "file_actions.compress.name": "דחוס", "file_actions.copy.name": "העתק", "file_actions.create.name": "צור", @@ -982,12 +995,14 @@ "labels.cloud_file_system": "מערכות קבצים בענן", "labels.cloud_storage_remote_filesystems": "אחסון ענן ומערכות קבצים מרוחקות", "labels.code_folding": "קיפול קוד", + "labels.collaborator": "שותף פעולה", "labels.collaborators": "משתפי פעולה", "labels.color": "צבע", "labels.communication": "תקשורת", "labels.config": "הגדרות", "labels.configuration": "תצורה", "labels.configuration.short": "הגדרות", + "labels.connected": "מחובר", "labels.connecting": "מתחבר", "labels.connection": "חיבור", "labels.copied": "הועתק", @@ -1016,6 +1031,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 {שמור}}", @@ -1077,6 +1093,7 @@ "labels.open": "פתח", "labels.other": "אחר", "labels.overview": "סקירה", + "labels.owner": "בעלים", "labels.pages": "דפים", "labels.paste": "הדבק", "labels.pay_as_you_go": "שלם לפי שימוש", @@ -1095,6 +1112,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": "מוכן", @@ -1283,6 +1301,12 @@ "project_actions.rename_file.what": "שנה שם {src}", "project-start-warning.content": "עליך להתחיל את הפרויקט \"{project_title}\" לפני שתוכל {what}. {title}", "project-start-warning.title": "להתחיל את הפרויקט הזה?", + "project.collaborators.add.owner_only_setting": "רק בעלי פרויקט יכולים להוסיף משתפי פעולה כאשר ניהול לבעלים בלבד מופעל.", + "project.collaborators.demote.label": "להוריד מעמד לשותף", + "project.collaborators.demote.tooltip": "{isLastOwner, select, true {לא ניתן להוריד את הדרגה של הבעלים האחרון} other {להוריד את הבעלים הזה לדרגת משתף פעולה}}", + "project.collaborators.non_owner_note": "רק בעלי הפרויקט יכולים לנהל תפקידי משתמשים.", + "project.collaborators.promote.label": "קדם לבעלים", + "project.collaborators.promote.tooltip": "קדם את שותף הפעולה הזה לבעלים, ותן לו שליטה מלאה על הפרויקט", "project.explorer.action-bar.check_all.button": "{checked, select, true {בטל סימון הכל} other {סמן הכל}}", "project.explorer.action-bar.currently_selected.info": "לחץ על תיבת הסימון משמאל לקובץ כדי להעתיק, להוריד, וכו'.", "project.explorer.action-bar.currently_selected.items": "{checked} מתוך {total} {items} נבחרו", @@ -1293,6 +1317,7 @@ "project.explorer.misc-side-buttons.open_dir.tooltip": "פותח את הספרייה הנוכחית במופע שרת {name}, הפועל בתוך פרויקט זה", "project.explorer.search-bar.placeholder": "סנן קבצים או \"/\" למסוף...", "project.explorer.start_project.warning": "על מנת לראות את הקבצים בתיקייה זו, עליך להתחיל את הפרויקט הזה", + "project.history.log-entry.change_collaborator_type": "שינה {target} מ-{old_group} ל-{new_group}", "project.history.log-entry.invited_user": "משתמש מוזמן", "project.history.log-entry.invited_user_via": "הזמין משתמש חדש באמצעות", "project.history.log-entry.miniterm": "בוצעה פקודת מסוף מיני {cmd}", @@ -1385,6 +1410,7 @@ "project.settings.about-box.name.label": "שם (לא חובה)", "project.settings.about-box.starred.help": "פרויקטים עם כוכבית ניתן לסנן על ידי לחיצה על כפתור המסנן עם כוכבית ברשימת הפרויקטים שלך.", "project.settings.about-box.title.label": "כותרת", + "project.settings.collaborators.title": "ניהול משתפי פעולה", "project.settings.compute-image-selector.button.save-restart": "שמור והפעל מחדש", "project.settings.compute-image-selector.doubt": "{default, select, true {זוהי הבחירה המוגדרת כברירת מחדל} other {הערה: אם יש ספק, בחר \"{default_title}\"}}", "project.settings.compute-image-selector.software-env-info": "סביבת תוכנה מספקת את כל התוכנה שהפרויקט הזה יכול להשתמש בה. אם אתה צריך תוכנה נוספת, אתה יכול להתקין אותה בפרויקט או לפנות לתמיכה. למד על התקנת חבילות Python, ליבת Jupyter של Python, חבילות R ו-חבילות Julia.", @@ -1408,6 +1434,9 @@ "project.settings.hide-delete-box.hide.label": "{hidden, select, true {הצג פרויקט} other {הסתר פרויקט}}", "project.settings.hide-delete-box.hide.switch": "{hidden, select, true {מוסתר} other {גלוי}}", "project.settings.hide-delete-box.title": "הסתר או מחק פרויקט", + "project.settings.manage_users_owner_only": "לאפשר רק לבעלים לנהל משתפי פעולה.", + "project.settings.manage_users_owner_only.note": "ניתן לשנות הגדרה זו רק על ידי בעלי הפרויקט.", + "project.settings.manage_users_owner_only.site_enforced": "הגדרה זו נאכפת על ידי מנהל האתר עבור כל הפרויקטים.", "project.settings.restart-project.button.label": "{is_running, select, true {הפעל מחדש} other {הפעל}}", "project.settings.site-license.body.info": "מידע על רישיונות מצורפים. לחץ על שורה כדי להרחיב פרטים.", "project.settings.site-license.button.label": "שדרג באמצעות מפתח רישיון...", @@ -1423,7 +1452,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 +1483,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..a62e3f99056 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 {कृपया अपना ईमेल पता जाँचें और सत्यापित करें:}}", @@ -177,8 +179,12 @@ "codemirror.extensions.ai_formula.insert_full_reply_button": "पूरा उत्तर डालें", "codemirror.extensions.ai_formula.title": "LaTeX सूत्र उत्पन्न करें", "collaborators.current-collabs.intro": "सभी नीचे सूचीबद्ध लोग आपके साथ इस परियोजना में किसी भी Jupyter Notebook, Linux Terminal या फ़ाइल पर सहयोगात्मक रूप से काम कर सकते हैं, और अन्य सहयोगियों को जोड़ या हटा सकते हैं।", + "collaborators.current-collabs.intro2": "नीचे सूचीबद्ध सभी लोग इस परियोजना में किसी भी Jupyter Notebook, Linux Terminal या फ़ाइल पर आपके साथ सहयोगी रूप से काम कर सकते हैं। {manageUsersOnly, select, true { केवल परियोजना के मालिक सहयोगियों को जोड़ या हटा सकते हैं।} other { सहयोगी भी अन्य सहयोगियों को जोड़ या हटा सकते हैं।}}", "collaborators.current-collabs.remove_other": "क्या आप निश्चित हैं कि आप {user} को इस परियोजना से हटाना चाहते हैं? उन्हें अब इस परियोजना तक पहुंच नहीं होगी।", "collaborators.current-collabs.remove_self": "क्या आप सुनिश्चित हैं कि आप स्वयं को इस प्रोजेक्ट से हटाना चाहते हैं? आपके पास अब इस प्रोजेक्ट तक पहुंच नहीं होगी और आप स्वयं को वापस नहीं जोड़ सकते।", + "collaborators.current-collabs.remove.ok_button": "हां, {role} हटाएं", + "collaborators.current-collabs.remove.owner_disabled": "स्वामियों को हटाने से पहले उन्हें पदावनत किया जाना चाहिए।", + "collaborators.current-collabs.remove.setting_disabled": "केवल मालिक इस सेटिंग के सक्षम होने पर सहयोगियों को हटा सकते हैं।", "collaborators.current-collabs.title": "वर्तमान सहयोगी", "command.format.ai_formula.button": "फॉर्मूला", "command.format.ai_formula.label": "एआई जनरेटेड फॉर्मूला", @@ -634,6 +640,13 @@ "editor.terminal.cmd.help.title": "CoCalc में Linux टर्मिनल का उपयोग करने के लिए दस्तावेज़ दिखाएं.", "editor.toggle_pdf_dark_mode.label": "पीडीएफ डार्क मोड टॉगल करें", "editor.toggle_pdf_dark_mode.title": "पीडीएफ के डार्क मोड को बंद करें, मूल फ़ाइल देखने के लिए", + "errors.ownership.cannot_remove_owner": "स्वामी को नहीं हटा सकते। पहले सहयोगी के रूप में पदावनत करें।", + "errors.ownership.invalid_project_state": "प्रोजेक्ट डेटा गायब है या अमान्य है।", + "errors.ownership.invalid_requesting_user": "आप परियोजना सदस्य नहीं हैं।", + "errors.ownership.invalid_target": "लक्षित उपयोगकर्ता इस परियोजना का सदस्य नहीं है।", + "errors.ownership.invalid_user": "उपयोगकर्ता नहीं मिला या अमान्य है।", + "errors.ownership.last_owner": "स्वामी को नहीं हटा सकते, क्योंकि कम से कम एक स्वामी आवश्यक है।", + "errors.ownership.not_owner": "केवल परियोजना के मालिक ही उपयोगकर्ता प्रकार बदल सकते हैं।", "file_actions.compress.name": "संपीड़ित करें", "file_actions.copy.name": "कॉपी", "file_actions.create.name": "बनाएँ", @@ -982,12 +995,14 @@ "labels.cloud_file_system": "क्लाउड फाइल सिस्टम्स", "labels.cloud_storage_remote_filesystems": "क्लाउड स्टोरेज और रिमोट फ़ाइल सिस्टम", "labels.code_folding": "कोड फोल्डिंग", + "labels.collaborator": "सहयोगी", "labels.collaborators": "सहयोगी", "labels.color": "रंग", "labels.communication": "संचार", "labels.config": "कॉन्फ़िग", "labels.configuration": "कॉन्फ़िगरेशन", "labels.configuration.short": "कॉन्फ़िग", + "labels.connected": "कनेक्टेड", "labels.connecting": "कनेक्टिंग", "labels.connection": "कनेक्शन", "labels.copied": "कॉपी किया गया", @@ -1016,6 +1031,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 {सहेजें}}", @@ -1077,6 +1093,7 @@ "labels.open": "खोलें", "labels.other": "अन्य", "labels.overview": "सारांश", + "labels.owner": "मालिक", "labels.pages": "पृष्ठों", "labels.paste": "पेस्ट", "labels.pay_as_you_go": "पे ऐज़ यू गो", @@ -1095,6 +1112,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": "तैयार", @@ -1283,6 +1301,12 @@ "project_actions.rename_file.what": "{src} का नाम बदलें", "project-start-warning.content": "आपको {what} से पहले \"{project_title}\" प्रोजेक्ट शुरू करना होगा। {title}", "project-start-warning.title": "इस परियोजना को शुरू करें?", + "project.collaborators.add.owner_only_setting": "केवल प्रोजेक्ट मालिक ही सहयोगियों को जोड़ सकते हैं जब केवल मालिक प्रबंधन सक्षम होता है।", + "project.collaborators.demote.label": "सहयोगी के रूप में अवनत करें", + "project.collaborators.demote.tooltip": "{isLastOwner, select, true {अंतिम मालिक को पदावनत नहीं किया जा सकता} other {इस मालिक को सहयोगी के रूप में पदावनत करें}}", + "project.collaborators.non_owner_note": "केवल परियोजना के मालिक उपयोगकर्ता भूमिकाओं का प्रबंधन कर सकते हैं।", + "project.collaborators.promote.label": "स्वामी के रूप में पदोन्नत करें", + "project.collaborators.promote.tooltip": "इस सहयोगी को स्वामी बनाएं, उन्हें पूर्ण परियोजना नियंत्रण दें", "project.explorer.action-bar.check_all.button": "{checked, select, true {सभी अनचेक करें} other {सभी चेक करें}}", "project.explorer.action-bar.currently_selected.info": "फ़ाइल की प्रतिलिपि बनाने, डाउनलोड करने आदि के लिए बाईं ओर स्थित चेकबॉक्स पर क्लिक करें।", "project.explorer.action-bar.currently_selected.items": "{checked} में से {total} {items} चुने गए", @@ -1293,6 +1317,7 @@ "project.explorer.misc-side-buttons.open_dir.tooltip": "वर्तमान निर्देशिका को इस प्रोजेक्ट के अंदर चल रहे एक {name} सर्वर उदाहरण में खोलता है", "project.explorer.search-bar.placeholder": "फ़ाइलों को फ़िल्टर करें या टर्मिनल के लिए \"/\"...", "project.explorer.start_project.warning": "इस निर्देशिका में फाइलें देखने के लिए, आपको इस प्रोजेक्ट को शुरू करना होगा।", + "project.history.log-entry.change_collaborator_type": "{target} को {old_group} से {new_group} में बदला गया", "project.history.log-entry.invited_user": "आमंत्रित उपयोगकर्ता", "project.history.log-entry.invited_user_via": "नए उपयोगकर्ता को आमंत्रित किया गया द्वारा", "project.history.log-entry.miniterm": "{cmd} मिनी टर्मिनल कमांड निष्पादित", @@ -1385,6 +1410,7 @@ "project.settings.about-box.name.label": "नाम (वैकल्पिक)", "project.settings.about-box.starred.help": "आपके प्रोजेक्ट सूची में स्टार फ़िल्टर बटन पर क्लिक करके स्टार किए गए प्रोजेक्ट को फ़िल्टर किया जा सकता है।", "project.settings.about-box.title.label": "शीर्षक", + "project.settings.collaborators.title": "सहयोगी प्रबंधन", "project.settings.compute-image-selector.button.save-restart": "सहेजें और पुनः आरंभ करें", "project.settings.compute-image-selector.doubt": "{default, select, true {यह डिफ़ॉल्ट चयन है} other {नोट: संदेह में, \"{default_title}\" चुनें}}", "project.settings.compute-image-selector.software-env-info": "एक सॉफ़्टवेयर वातावरण वह सारी सॉफ़्टवेयर प्रदान करता है, जिसका यह प्रोजेक्ट उपयोग कर सकता है। यदि आपको अतिरिक्त सॉफ़्टवेयर की आवश्यकता है, तो आप इसे प्रोजेक्ट में स्थापित कर सकते हैं या समर्थन से संपर्क कर सकते हैं। Python पैकेज स्थापित करने, Python Jupyter Kernel, R पैकेज और Julia पैकेज के बारे में जानें।", @@ -1408,6 +1434,9 @@ "project.settings.hide-delete-box.hide.label": "{hidden, select, true {प्रोजेक्ट छिपाएं} other {प्रोजेक्ट छिपाएं}}", "project.settings.hide-delete-box.hide.switch": "{hidden, select, true {छिपा हुआ} other {दृश्यमान}}", "project.settings.hide-delete-box.title": "प्रोजेक्ट छिपाएँ या हटाएँ", + "project.settings.manage_users_owner_only": "केवल मालिकों को सहयोगियों का प्रबंधन करने की अनुमति दें।", + "project.settings.manage_users_owner_only.note": "यह सेटिंग केवल प्रोजेक्ट मालिकों द्वारा बदली जा सकती है।", + "project.settings.manage_users_owner_only.site_enforced": "यह सेटिंग साइट व्यवस्थापक द्वारा सभी परियोजनाओं के लिए लागू की गई है।", "project.settings.restart-project.button.label": "{is_running, select, true {पुनः आरंभ करें} other {शुरू करें}}", "project.settings.site-license.body.info": "संलग्न लाइसेंसों की जानकारी। विवरण देखने के लिए एक पंक्ति पर क्लिक करें।", "project.settings.site-license.button.label": "लाइसेंस कुंजी का उपयोग करके अपग्रेड करें...", @@ -1423,7 +1452,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 +1483,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..d24d04b96c4 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:}}", @@ -177,8 +179,12 @@ "codemirror.extensions.ai_formula.insert_full_reply_button": "Helyezze be a teljes választ", "codemirror.extensions.ai_formula.title": "Generálj LaTeX képletet", "collaborators.current-collabs.intro": "Az alábbi személyek mindegyike együtt dolgozhat Önnel bármely Jupyter Notebookon, Linux Terminálon vagy fájlon ebben a projektben, és más együttműködőket is hozzáadhat vagy eltávolíthat.", + "collaborators.current-collabs.intro2": "Mindenki, aki az alábbi listában szerepel, együttműködhet veled bármely Jupyter Notebookon, Linux Terminálon vagy fájlon ebben a projektben. {manageUsersOnly, select, true { Csak a projekt tulajdonosai adhatnak hozzá vagy távolíthatnak el együttműködőket.} other { Az együttműködők is hozzáadhatnak vagy eltávolíthatnak más együttműködőket.}}", "collaborators.current-collabs.remove_other": "Biztosan el akarja távolítani {user} ezt a projektből? Többé nem fognak hozzáférni ehhez a projekthez.", "collaborators.current-collabs.remove_self": "Biztosan eltávolítja magát ebből a projektből? Többé nem fog hozzáférni ehhez a projekthez, és nem tudja újra hozzáadni magát.", + "collaborators.current-collabs.remove.ok_button": "Igen, távolítsa el a {role}", + "collaborators.current-collabs.remove.owner_disabled": "A tulajdonosokat lefokozni szükséges, mielőtt eltávolíthatók.", + "collaborators.current-collabs.remove.setting_disabled": "Csak a tulajdonosok távolíthatnak el közreműködőket, ha ez a beállítás engedélyezve van.", "collaborators.current-collabs.title": "Jelenlegi Munkatársak", "command.format.ai_formula.button": "Képlet", "command.format.ai_formula.label": "AI által Generált Képlet", @@ -634,6 +640,13 @@ "editor.terminal.cmd.help.title": "Dokumentáció megjelenítése a Linux terminál használatához a CoCalc-ban.", "editor.toggle_pdf_dark_mode.label": "PDF sötét mód váltása", "editor.toggle_pdf_dark_mode.title": "Kapcsolja ki a PDF sötét módját, hogy lássa az eredeti fájlt", + "errors.ownership.cannot_remove_owner": "Nem lehet eltávolítani egy tulajdonost. Először fokozza le munkatárssá.", + "errors.ownership.invalid_project_state": "A projekt adatai hiányoznak vagy érvénytelenek.", + "errors.ownership.invalid_requesting_user": "Ön nem tagja a projektnek.", + "errors.ownership.invalid_target": "A célfelhasználó nem tagja ennek a projektnek.", + "errors.ownership.invalid_user": "Felhasználó nem található vagy érvénytelen.", + "errors.ownership.last_owner": "Nem lehet eltávolítani a tulajdonost, mert legalább egy tulajdonos szükséges.", + "errors.ownership.not_owner": "Csak a projekt tulajdonosai módosíthatják a felhasználói típusokat.", "file_actions.compress.name": "Tömörít", "file_actions.copy.name": "Másolás", "file_actions.create.name": "Létrehozás", @@ -982,12 +995,14 @@ "labels.cloud_file_system": "Felhő fájlrendszerek", "labels.cloud_storage_remote_filesystems": "Felhőtárhely és távoli fájlrendszerek", "labels.code_folding": "Kódrendszer összecsukása", + "labels.collaborator": "Közreműködő", "labels.collaborators": "Munkatársak", "labels.color": "Szín", "labels.communication": "Kommunikáció", "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 +1031,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}}", @@ -1077,6 +1093,7 @@ "labels.open": "Megnyitás", "labels.other": "Egyéb", "labels.overview": "Áttekintés", + "labels.owner": "Tulajdonos", "labels.pages": "Oldalak", "labels.paste": "Beillesztés", "labels.pay_as_you_go": "Fizess, ahogy használod", @@ -1095,6 +1112,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", @@ -1283,6 +1301,12 @@ "project_actions.rename_file.what": "átnevezés {src}", "project-start-warning.content": "El kell indítania a(z) \"{project_title}\" projektet, mielőtt {what}. {title}", "project-start-warning.title": "Elindítja ezt a projektet?", + "project.collaborators.add.owner_only_setting": "Csak a projekt tulajdonosai adhatnak hozzá munkatársakat, ha be van kapcsolva a csak tulajdonos általi kezelés.", + "project.collaborators.demote.label": "Lefokozás munkatárssá", + "project.collaborators.demote.tooltip": "{isLastOwner, select, true {Nem lehet lefokozni az utolsó tulajdonost} other {Fokozza le ezt a tulajdonost közreműködővé}}", + "project.collaborators.non_owner_note": "Csak a projekt tulajdonosai kezelhetik a felhasználói szerepeket.", + "project.collaborators.promote.label": "Előléptetés tulajdonossá", + "project.collaborators.promote.tooltip": "Emelje fel ezt a közreműködőt tulajdonossá, hogy teljes projektkontrollt biztosítson neki", "project.explorer.action-bar.check_all.button": "{checked, select, true {Mindet kivenni} other {Mindet bejelölni}}", "project.explorer.action-bar.currently_selected.info": "Kattintson a fájl melletti jelölőnégyzetre a másoláshoz, letöltéshez, stb.", "project.explorer.action-bar.currently_selected.items": "{checked} a {total} {items} közül kiválasztva", @@ -1293,6 +1317,7 @@ "project.explorer.misc-side-buttons.open_dir.tooltip": "Megnyitja az aktuális könyvtárat egy {name} szerver példányban, amely ebben a projektben fut.", "project.explorer.search-bar.placeholder": "Szűrje a fájlokat vagy \"/\" a terminálhoz...", "project.explorer.start_project.warning": "A fájlok megtekintéséhez ebben a könyvtárban, indítsd el ezt a projektet.", + "project.history.log-entry.change_collaborator_type": "megváltoztatta {target} {old_group}-ról {new_group}-ra", "project.history.log-entry.invited_user": "meghívott felhasználó", "project.history.log-entry.invited_user_via": "új felhasználó meghívása μέσω", "project.history.log-entry.miniterm": "végrehajtott mini terminál parancs {cmd}", @@ -1385,6 +1410,7 @@ "project.settings.about-box.name.label": "Név (opcionális)", "project.settings.about-box.starred.help": "A csillagozott projektek szűrhetők a csillagozott szűrő gombra kattintva a projektlistádban.", "project.settings.about-box.title.label": "Cím", + "project.settings.collaborators.title": "Együttműködő kezelése", "project.settings.compute-image-selector.button.save-restart": "Mentés és újraindítás", "project.settings.compute-image-selector.doubt": "{default, select, true {Ez az alapértelmezett kiválasztás} other {Megjegyzés: ha kétségei vannak, válassza a(z) \"{default_title}\" lehetőséget}}", "project.settings.compute-image-selector.software-env-info": "Egy szoftverkörnyezet biztosítja az összes szoftvert, amelyet ez a projekt használhat. Ha további szoftverre van szüksége, telepítheti a projektben, vagy kapcsolatba léphet a támogatással. Tudjon meg többet a Python csomagok telepítése, Python Jupyter Kernel, R csomagok és Julia csomagok témakörben.", @@ -1408,6 +1434,9 @@ "project.settings.hide-delete-box.hide.label": "{hidden, select, true {Projekt felfedése} other {Projekt elrejtése}}", "project.settings.hide-delete-box.hide.switch": "{hidden, select, true {Rejtett} other {Látható}}", "project.settings.hide-delete-box.title": "Rejtés vagy Törlés Projekt", + "project.settings.manage_users_owner_only": "Csak a tulajdonosok kezelhetik a közreműködőket.", + "project.settings.manage_users_owner_only.note": "Ezt a beállítást csak a projekt tulajdonosai módosíthatják.", + "project.settings.manage_users_owner_only.site_enforced": "Ezt a beállítást a webhely rendszergazdája érvényesíti minden projektre.", "project.settings.restart-project.button.label": "{is_running, select, true {Újraindítás} other {Indítás}}", "project.settings.site-license.body.info": "Információ a csatolt licencekről. Kattintson egy sorra a részletek kibontásához.", "project.settings.site-license.button.label": "Frissítés licenckulccsal...", @@ -1423,7 +1452,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 +1483,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..f55dba9306a 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:}}", @@ -177,8 +179,12 @@ "codemirror.extensions.ai_formula.insert_full_reply_button": "Inserisci risposta completa", "codemirror.extensions.ai_formula.title": "Genera Formula LaTeX", "collaborators.current-collabs.intro": "Tutti quelli elencati di seguito possono lavorare collaborativamente con te su qualsiasi Jupyter Notebook, Terminale Linux o file in questo progetto, e aggiungere o rimuovere altri collaboratori.", + "collaborators.current-collabs.intro2": "Tutti gli utenti elencati di seguito possono lavorare con te in modo collaborativo su qualsiasi Jupyter Notebook, Terminale Linux o file in questo progetto. {manageUsersOnly, select, true { Solo i proprietari del progetto possono aggiungere o rimuovere collaboratori.} other { Anche i collaboratori possono aggiungere o rimuovere altri collaboratori.}}", "collaborators.current-collabs.remove_other": "Sei sicuro di voler rimuovere {user} da questo progetto? Non avranno più accesso a questo progetto.", "collaborators.current-collabs.remove_self": "Sei sicuro di voler rimuovere te stesso da questo progetto? Non avrai più accesso a questo progetto e non potrai aggiungerti di nuovo.", + "collaborators.current-collabs.remove.ok_button": "Sì, rimuovi {role}", + "collaborators.current-collabs.remove.owner_disabled": "I proprietari devono essere retrocessi prima di poter essere rimossi.", + "collaborators.current-collabs.remove.setting_disabled": "Solo i proprietari possono rimuovere i collaboratori quando questa impostazione è attivata.", "collaborators.current-collabs.title": "Collaboratori attuali", "command.format.ai_formula.button": "Formula", "command.format.ai_formula.label": "Formula Generata dall'AI", @@ -634,6 +640,13 @@ "editor.terminal.cmd.help.title": "Mostra la documentazione per l'utilizzo del Terminale Linux in CoCalc.", "editor.toggle_pdf_dark_mode.label": "Attiva/disattiva modalità scura PDF", "editor.toggle_pdf_dark_mode.title": "Disattiva la modalità scura del PDF per vedere il file originale", + "errors.ownership.cannot_remove_owner": "Impossibile rimuovere un proprietario. Declassalo a collaboratore prima.", + "errors.ownership.invalid_project_state": "I dati del progetto sono mancanti o non validi.", + "errors.ownership.invalid_requesting_user": "Non sei un membro del progetto.", + "errors.ownership.invalid_target": "L'utente di destinazione non è un membro di questo progetto.", + "errors.ownership.invalid_user": "Utente non trovato o non valido.", + "errors.ownership.last_owner": "Impossibile rimuovere il proprietario, perché è richiesto almeno un proprietario.", + "errors.ownership.not_owner": "Solo i proprietari del progetto possono cambiare i tipi di utente.", "file_actions.compress.name": "Comprimi", "file_actions.copy.name": "Copia", "file_actions.create.name": "Crea", @@ -982,12 +995,14 @@ "labels.cloud_file_system": "Sistemi di File Cloud", "labels.cloud_storage_remote_filesystems": "Archiviazione Cloud & Sistemi di File Remoti", "labels.code_folding": "Ripiegamento del codice", + "labels.collaborator": "Collaboratore", "labels.collaborators": "Collaboratori", "labels.color": "Colore", "labels.communication": "Comunicazione", "labels.config": "Configura", "labels.configuration": "Configurazione", "labels.configuration.short": "Configura", + "labels.connected": "Connesso", "labels.connecting": "Connessione", "labels.connection": "Connessione", "labels.copied": "copiato", @@ -1016,6 +1031,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}}", @@ -1077,6 +1093,7 @@ "labels.open": "Apri", "labels.other": "Altro", "labels.overview": "Panoramica", + "labels.owner": "Proprietario", "labels.pages": "Pagine", "labels.paste": "Incolla", "labels.pay_as_you_go": "Paga a Consumo", @@ -1095,6 +1112,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", @@ -1283,6 +1301,12 @@ "project_actions.rename_file.what": "rinomina {src}", "project-start-warning.content": "Devi avviare il progetto \"{project_title}\" prima di poter {what}. {title}", "project-start-warning.title": "Avviare questo progetto?", + "project.collaborators.add.owner_only_setting": "Solo i proprietari del progetto possono aggiungere collaboratori quando la gestione riservata ai proprietari è abilitata.", + "project.collaborators.demote.label": "Retrocedi a Collaboratore", + "project.collaborators.demote.tooltip": "{isLastOwner, select, true {Non è possibile declassare l'ultimo proprietario} other {Declassa questo proprietario a collaboratore}}", + "project.collaborators.non_owner_note": "Solo i proprietari del progetto possono gestire i ruoli degli utenti.", + "project.collaborators.promote.label": "Promuovi a Proprietario", + "project.collaborators.promote.tooltip": "Promuovi questo collaboratore a proprietario, dando loro il pieno controllo del progetto", "project.explorer.action-bar.check_all.button": "{checked, select, true {Deseleziona tutto} other {Seleziona tutto}}", "project.explorer.action-bar.currently_selected.info": "Fai clic sulla casella di controllo a sinistra di un file per copiare, scaricare, ecc.", "project.explorer.action-bar.currently_selected.items": "{checked} di {total} {items} selezionati", @@ -1293,6 +1317,7 @@ "project.explorer.misc-side-buttons.open_dir.tooltip": "Apre la directory corrente in un'istanza del server {name}, in esecuzione all'interno di questo progetto.", "project.explorer.search-bar.placeholder": "Filtra file o \"/\" per terminale...", "project.explorer.start_project.warning": "Per vedere i file in questa directory, devi avviare questo progetto.", + "project.history.log-entry.change_collaborator_type": "cambiato {target} da {old_group} a {new_group}", "project.history.log-entry.invited_user": "utente invitato", "project.history.log-entry.invited_user_via": "ha invitato un nuovo utente tramite", "project.history.log-entry.miniterm": "eseguito mini comando terminale {cmd}", @@ -1385,6 +1410,7 @@ "project.settings.about-box.name.label": "Nome (opzionale)", "project.settings.about-box.starred.help": "I progetti con stella possono essere filtrati cliccando sul pulsante di filtro con stella nella tua lista di progetti.", "project.settings.about-box.title.label": "Titolo", + "project.settings.collaborators.title": "Gestione dei collaboratori", "project.settings.compute-image-selector.button.save-restart": "Salva e Riavvia", "project.settings.compute-image-selector.doubt": "{default, select, true {Questa è la selezione predefinita} other {Nota: in caso di dubbio, selezionare \"{default_title}\"}}", "project.settings.compute-image-selector.software-env-info": "Un ambiente software fornisce tutto il software di cui questo progetto può usufruire. Se hai bisogno di software aggiuntivo, puoi installarlo nel progetto o contattare il supporto. Scopri di più su installare pacchetti Python, Python Jupyter Kernel, pacchetti R e pacchetti Julia.", @@ -1408,6 +1434,9 @@ "project.settings.hide-delete-box.hide.label": "{hidden, select, true {Mostra Progetto} other {Nascondi Progetto}}", "project.settings.hide-delete-box.hide.switch": "{hidden, select, true {Nascosto} other {Visibile}}", "project.settings.hide-delete-box.title": "Nascondi o Elimina Progetto", + "project.settings.manage_users_owner_only": "Consenti solo ai proprietari di gestire i collaboratori.", + "project.settings.manage_users_owner_only.note": "Questa impostazione può essere modificata solo dai proprietari del progetto.", + "project.settings.manage_users_owner_only.site_enforced": "Questa impostazione è imposta dall'amministratore del sito per tutti i progetti.", "project.settings.restart-project.button.label": "{is_running, select, true {Riavvia} other {Avvia}}", "project.settings.site-license.body.info": "Informazioni sulle licenze allegate. Fai clic su una riga per espandere i dettagli.", "project.settings.site-license.button.label": "Aggiorna utilizzando una chiave di licenza...", @@ -1423,7 +1452,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 +1483,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..0417f3ae7ef 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 {メールアドレスを確認してください:}}", @@ -177,8 +179,12 @@ "codemirror.extensions.ai_formula.insert_full_reply_button": "返信を挿入", "codemirror.extensions.ai_formula.title": "LaTeX 公式を生成", "collaborators.current-collabs.intro": "以下に記載された全員が、このプロジェクト内の任意のJupyter Notebook、Linux Terminal、またはファイルであなたと共同作業を行い、他の共同作業者を追加または削除することができます。", + "collaborators.current-collabs.intro2": "以下に記載されているすべての人が、このプロジェクト内の任意のJupyter Notebook、Linux Terminal、またはファイルで共同作業を行うことができます。{manageUsersOnly, select, true { プロジェクトの所有者のみがコラボレーターを追加または削除できます。} other { コラボレーターも他のコラボレーターを追加または削除できます。}}", "collaborators.current-collabs.remove_other": "{user} をこのプロジェクトから削除してもよろしいですか?このプロジェクトへのアクセスができなくなります。", "collaborators.current-collabs.remove_self": "本当に自分をこのプロジェクトから削除しますか?このプロジェクトへのアクセスができなくなり、自分を再追加することはできません。", + "collaborators.current-collabs.remove.ok_button": "はい、{role}を削除します", + "collaborators.current-collabs.remove.owner_disabled": "所有者は削除される前に降格される必要があります。", + "collaborators.current-collabs.remove.setting_disabled": "この設定が有効な場合、コラボレーターを削除できるのは所有者のみです。", "collaborators.current-collabs.title": "現在の共同作業者", "command.format.ai_formula.button": "数式", "command.format.ai_formula.label": "AI生成式", @@ -634,6 +640,13 @@ "editor.terminal.cmd.help.title": "CoCalcでLinuxターミナルを使用するためのドキュメントを表示。", "editor.toggle_pdf_dark_mode.label": "PDFダークモードを切り替え", "editor.toggle_pdf_dark_mode.title": "PDFのダークモードをオフにして、元のファイルを表示", + "errors.ownership.cannot_remove_owner": "オーナーを削除できません。まず共同作業者に降格してください。", + "errors.ownership.invalid_project_state": "プロジェクトデータが見つからないか無効です。", + "errors.ownership.invalid_requesting_user": "あなたはプロジェクトメンバーではありません。", + "errors.ownership.invalid_target": "対象ユーザーはこのプロジェクトのメンバーではありません。", + "errors.ownership.invalid_user": "ユーザーが見つからないか無効です。", + "errors.ownership.last_owner": "所有者を削除できません。少なくとも1人の所有者が必要です。", + "errors.ownership.not_owner": "プロジェクト所有者のみがユーザータイプを変更できます。", "file_actions.compress.name": "圧縮", "file_actions.copy.name": "コピー", "file_actions.create.name": "作成", @@ -982,12 +995,14 @@ "labels.cloud_file_system": "クラウドファイルシステム", "labels.cloud_storage_remote_filesystems": "クラウドストレージとリモートファイルシステム", "labels.code_folding": "コードフォールディング", + "labels.collaborator": "共同作業者", "labels.collaborators": "共同作業者", "labels.color": "色", "labels.communication": "通信", "labels.config": "設定", "labels.configuration": "設定", "labels.configuration.short": "設定", + "labels.connected": "接続済み", "labels.connecting": "接続中", "labels.connection": "接続", "labels.copied": "コピー済み", @@ -1016,6 +1031,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 {保存}}", @@ -1077,6 +1093,7 @@ "labels.open": "開く", "labels.other": "その他", "labels.overview": "概要", + "labels.owner": "所有者", "labels.pages": "ページ", "labels.paste": "貼り付け", "labels.pay_as_you_go": "従量課金", @@ -1095,6 +1112,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": "準備完了", @@ -1283,6 +1301,12 @@ "project_actions.rename_file.what": "{src} を名前変更", "project-start-warning.content": "プロジェクト \"{project_title}\" を開始する必要があります。その前に {what} はできません。{title}", "project-start-warning.title": "このプロジェクトを開始しますか?", + "project.collaborators.add.owner_only_setting": "オーナー限定の管理が有効な場合、プロジェクトオーナーのみが共同作業者を追加できます。", + "project.collaborators.demote.label": "共同作業者に降格", + "project.collaborators.demote.tooltip": "{isLastOwner, select, true {最後の所有者を降格することはできません} other {この所有者を共同作業者に降格}}", + "project.collaborators.non_owner_note": "プロジェクトのオーナーのみがユーザーの役割を管理できます。", + "project.collaborators.promote.label": "オーナーに昇格", + "project.collaborators.promote.tooltip": "このコラボレーターをオーナーに昇格し、プロジェクトのフルコントロールを与える", "project.explorer.action-bar.check_all.button": "{checked, select, true {すべてのチェックを外す} other {すべてをチェックする}}", "project.explorer.action-bar.currently_selected.info": "ファイルの左にあるチェックボックスをクリックして、コピーやダウンロードなどを行います。", "project.explorer.action-bar.currently_selected.items": "{checked} 個の {total} 個の {items} が選択されました", @@ -1293,6 +1317,7 @@ "project.explorer.misc-side-buttons.open_dir.tooltip": "このプロジェクト内で実行中の{name}サーバーインスタンスで現在のディレクトリを開きます。", "project.explorer.search-bar.placeholder": "ファイルをフィルターまたは\"/\"でターミナル...", "project.explorer.start_project.warning": "このディレクトリ内のファイルを見るには、このプロジェクトを開始する必要があります。", + "project.history.log-entry.change_collaborator_type": "{target}を{old_group}から{new_group}に変更しました", "project.history.log-entry.invited_user": "招待されたユーザー", "project.history.log-entry.invited_user_via": "経由で新しいユーザーを招待", "project.history.log-entry.miniterm": "{cmd} ミニターミナルコマンドを実行", @@ -1385,6 +1410,7 @@ "project.settings.about-box.name.label": "名前(任意)", "project.settings.about-box.starred.help": "スター付きプロジェクトは、プロジェクトリストでスター付きフィルターボタンをクリックするとフィルタリングできます。", "project.settings.about-box.title.label": "タイトル", + "project.settings.collaborators.title": "共同作業者管理", "project.settings.compute-image-selector.button.save-restart": "保存して再起動", "project.settings.compute-image-selector.doubt": "{default, select, true {これはデフォルトの選択です} other {注: 迷った場合は「{default_title}」を選択してください}}", "project.settings.compute-image-selector.software-env-info": "ソフトウェア環境は、このプロジェクトが利用できるすべてのソフトウェアを提供します。追加のソフトウェアが必要な場合は、プロジェクトにインストールするか、サポートに連絡してください。PythonパッケージのインストールPython JupyterカーネルRパッケージJuliaパッケージについて学びましょう。", @@ -1408,6 +1434,9 @@ "project.settings.hide-delete-box.hide.label": "{hidden, select, true {プロジェクトを表示} other {プロジェクトを非表示}}", "project.settings.hide-delete-box.hide.switch": "{hidden, select, true {非表示} other {表示}}", "project.settings.hide-delete-box.title": "プロジェクトを非表示または削除", + "project.settings.manage_users_owner_only": "所有者のみが共同作業者を管理できるようにする。", + "project.settings.manage_users_owner_only.note": "この設定はプロジェクトオーナーのみが変更できます。", + "project.settings.manage_users_owner_only.site_enforced": "この設定は、すべてのプロジェクトに対してサイト管理者によって強制されています。", "project.settings.restart-project.button.label": "{is_running, select, true {再起動} other {開始}}", "project.settings.site-license.body.info": "添付されたライセンスに関する情報。行をクリックして詳細を表示します。", "project.settings.site-license.button.label": "ライセンスキーを使用してアップグレード...", @@ -1423,7 +1452,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 +1483,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..21b0cd49a4a 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 {이메일 주소를 확인하고 인증해 주세요:}}", @@ -177,8 +179,12 @@ "codemirror.extensions.ai_formula.insert_full_reply_button": "전체 답장 삽입", "codemirror.extensions.ai_formula.title": "LaTeX 수식 생성", "collaborators.current-collabs.intro": "아래에 나열된 모든 사람들은 이 프로젝트의 Jupyter Notebook, Linux Terminal 또는 파일에서 여러분과 공동 작업을 할 수 있으며, 다른 협업자를 추가하거나 제거할 수 있습니다.", + "collaborators.current-collabs.intro2": "아래 나열된 모든 사람들은 이 프로젝트의 Jupyter Notebook, Linux Terminal 또는 파일에서 협업할 수 있습니다. {manageUsersOnly, select, true {프로젝트 소유자만 협력자를 추가하거나 제거할 수 있습니다.} other {협력자도 다른 협력자를 추가하거나 제거할 수 있습니다.}}", "collaborators.current-collabs.remove_other": "이 사용자를 이 프로젝트에서 제거하시겠습니까? 더 이상 이 프로젝트에 접근할 수 없습니다.", "collaborators.current-collabs.remove_self": "이 프로젝트에서 본인을 제거하시겠습니까? 이 프로젝트에 더 이상 접근할 수 없으며 본인을 다시 추가할 수 없습니다.", + "collaborators.current-collabs.remove.ok_button": "예, {role} 제거", + "collaborators.current-collabs.remove.owner_disabled": "소유자는 제거되기 전에 강등되어야 합니다.", + "collaborators.current-collabs.remove.setting_disabled": "이 설정이 활성화되면 소유자만 협업자를 제거할 수 있습니다.", "collaborators.current-collabs.title": "현재 협력자", "command.format.ai_formula.button": "수식", "command.format.ai_formula.label": "AI 생성 공식", @@ -634,6 +640,13 @@ "editor.terminal.cmd.help.title": "CoCalc에서 Linux 터미널 사용 설명서 보기", "editor.toggle_pdf_dark_mode.label": "PDF 다크 모드 전환", "editor.toggle_pdf_dark_mode.title": "PDF의 다크 모드를 끄고 원본 파일을 확인하세요", + "errors.ownership.cannot_remove_owner": "소유자를 제거할 수 없습니다. 먼저 협력자로 강등하세요.", + "errors.ownership.invalid_project_state": "프로젝트 데이터가 누락되었거나 유효하지 않습니다.", + "errors.ownership.invalid_requesting_user": "프로젝트 멤버가 아닙니다.", + "errors.ownership.invalid_target": "대상 사용자는 이 프로젝트의 멤버가 아닙니다.", + "errors.ownership.invalid_user": "사용자를 찾을 수 없거나 잘못되었습니다.", + "errors.ownership.last_owner": "소유자를 제거할 수 없습니다. 최소한 한 명의 소유자가 필요합니다.", + "errors.ownership.not_owner": "프로젝트 소유자만 사용자 유형을 변경할 수 있습니다.", "file_actions.compress.name": "압축", "file_actions.copy.name": "복사", "file_actions.create.name": "생성", @@ -982,12 +995,14 @@ "labels.cloud_file_system": "클라우드 파일 시스템", "labels.cloud_storage_remote_filesystems": "클라우드 저장소 & 원격 파일 시스템", "labels.code_folding": "코드 접기", + "labels.collaborator": "협력자", "labels.collaborators": "협력자", "labels.color": "색상", "labels.communication": "소통", "labels.config": "구성", "labels.configuration": "구성", "labels.configuration.short": "구성", + "labels.connected": "연결됨", "labels.connecting": "연결 중", "labels.connection": "연결", "labels.copied": "복사됨", @@ -1016,6 +1031,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 {저장}}", @@ -1077,6 +1093,7 @@ "labels.open": "열기", "labels.other": "기타", "labels.overview": "개요", + "labels.owner": "소유자", "labels.pages": "페이지", "labels.paste": "붙여넣기", "labels.pay_as_you_go": "사용한 만큼 지불하세요", @@ -1095,6 +1112,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": "준비됨", @@ -1283,6 +1301,12 @@ "project_actions.rename_file.what": "{src} 이름 변경", "project-start-warning.content": "프로젝트 \"{project_title}\"를 시작해야 {what} 할 수 있습니다. {title}", "project-start-warning.title": "이 프로젝트를 시작하시겠습니까?", + "project.collaborators.add.owner_only_setting": "소유자 전용 관리가 활성화된 경우 프로젝트 소유자만 공동 작업자를 추가할 수 있습니다.", + "project.collaborators.demote.label": "협력자로 강등", + "project.collaborators.demote.tooltip": "{isLastOwner, select, true {마지막 소유자를 강등할 수 없습니다} other {이 소유자를 협력자로 강등}}", + "project.collaborators.non_owner_note": "프로젝트 소유자만 사용자 역할을 관리할 수 있습니다.", + "project.collaborators.promote.label": "소유자로 승격", + "project.collaborators.promote.tooltip": "이 협력자를 소유자로 승격하여 전체 프로젝트 제어 권한 부여", "project.explorer.action-bar.check_all.button": "{checked, select, true {모두 선택 해제} other {모두 선택}}", "project.explorer.action-bar.currently_selected.info": "파일 왼쪽의 체크박스를 클릭하여 복사, 다운로드 등을 수행하세요.", "project.explorer.action-bar.currently_selected.items": "{checked}개 중 {total}개의 {items} 선택됨", @@ -1293,6 +1317,7 @@ "project.explorer.misc-side-buttons.open_dir.tooltip": "현재 디렉토리를 이 프로젝트 내부에서 실행 중인 {name} 서버 인스턴스에서 엽니다.", "project.explorer.search-bar.placeholder": "파일 필터 또는 \"/\"로 터미널...", "project.explorer.start_project.warning": "이 디렉터리의 파일을 보려면 이 프로젝트를 시작해야 합니다.", + "project.history.log-entry.change_collaborator_type": "{target}을(를) {old_group}에서 {new_group}(으)로 변경했습니다", "project.history.log-entry.invited_user": "초대된 사용자", "project.history.log-entry.invited_user_via": "새 사용자 초대 via", "project.history.log-entry.miniterm": "미니 터미널 명령 {cmd} 실행됨", @@ -1385,6 +1410,7 @@ "project.settings.about-box.name.label": "이름 (선택 사항)", "project.settings.about-box.starred.help": "별표 표시된 프로젝트는 프로젝트 목록에서 별표 필터 버튼을 클릭하여 필터링할 수 있습니다.", "project.settings.about-box.title.label": "제목", + "project.settings.collaborators.title": "협력자 관리", "project.settings.compute-image-selector.button.save-restart": "저장 및 다시 시작", "project.settings.compute-image-selector.doubt": "{default, select, true {기본 선택입니다} other {참고: 확실하지 않으면 \"{default_title}\"을 선택하세요}}", "project.settings.compute-image-selector.software-env-info": "소프트웨어 환경은 이 프로젝트가 사용할 수 있는 모든 소프트웨어를 제공합니다. 추가 소프트웨어가 필요하면 프로젝트에 설치하거나 지원팀에 문의할 수 있습니다. Python 패키지 설치, Python Jupyter 커널, R 패키지Julia 패키지에 대해 알아보세요.", @@ -1408,6 +1434,9 @@ "project.settings.hide-delete-box.hide.label": "{hidden, select, true {프로젝트 보이기} other {프로젝트 숨기기}}", "project.settings.hide-delete-box.hide.switch": "{hidden, select, true {숨김} other {표시됨}}", "project.settings.hide-delete-box.title": "프로젝트 숨기기 또는 삭제", + "project.settings.manage_users_owner_only": "소유자만 협업자를 관리할 수 있도록 허용하십시오.", + "project.settings.manage_users_owner_only.note": "이 설정은 프로젝트 소유자만 변경할 수 있습니다.", + "project.settings.manage_users_owner_only.site_enforced": "이 설정은 모든 프로젝트에 대해 사이트 관리자가 적용합니다.", "project.settings.restart-project.button.label": "{is_running, select, true {다시 시작} other {시작}}", "project.settings.site-license.body.info": "첨부된 라이선스에 대한 정보. 세부 정보를 확장하려면 행을 클릭하세요.", "project.settings.site-license.button.label": "라이선스 키를 사용하여 업그레이드...", @@ -1423,7 +1452,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 +1483,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..e57085c3cc8 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:}}", @@ -177,8 +179,12 @@ "codemirror.extensions.ai_formula.insert_full_reply_button": "Volledige reactie invoegen", "codemirror.extensions.ai_formula.title": "Genereer LaTeX-formule", "collaborators.current-collabs.intro": "Iedereen die hieronder vermeld staat, kan samen met jou werken aan elk Jupyter Notebook, Linux Terminal of bestand in dit project, en andere medewerkers toevoegen of verwijderen.", + "collaborators.current-collabs.intro2": "Iedereen hieronder vermeld kan samen met jou werken aan elk Jupyter Notebook, Linux Terminal of bestand in dit project. {manageUsersOnly, select, true { Alleen projecteigenaren kunnen medewerkers toevoegen of verwijderen.} other { Medewerkers kunnen ook andere medewerkers toevoegen of verwijderen.}}", "collaborators.current-collabs.remove_other": "Weet je zeker dat je {user} uit dit project wilt verwijderen? Ze hebben dan geen toegang meer tot dit project.", "collaborators.current-collabs.remove_self": "Weet u zeker dat u uzelf van dit project wilt verwijderen? U heeft dan geen toegang meer tot dit project en kunt uzelf niet opnieuw toevoegen.", + "collaborators.current-collabs.remove.ok_button": "Ja, verwijder {role}", + "collaborators.current-collabs.remove.owner_disabled": "Eigenaren moeten worden gedegradeerd voordat ze kunnen worden verwijderd.", + "collaborators.current-collabs.remove.setting_disabled": "Alleen eigenaren kunnen medewerkers verwijderen wanneer deze instelling is ingeschakeld.", "collaborators.current-collabs.title": "Huidige Samenwerkers", "command.format.ai_formula.button": "Formule", "command.format.ai_formula.label": "AI gegenereerde formule", @@ -634,6 +640,13 @@ "editor.terminal.cmd.help.title": "Toon documentatie voor het gebruik van de Linux Terminal in CoCalc.", "editor.toggle_pdf_dark_mode.label": "Schakel PDF Donkere Modus in", "editor.toggle_pdf_dark_mode.title": "Donkere modus van PDF uitschakelen om het originele bestand te zien", + "errors.ownership.cannot_remove_owner": "Kan een eigenaar niet verwijderen. Eerst degraderen naar medewerker.", + "errors.ownership.invalid_project_state": "Projectgegevens ontbreken of zijn ongeldig.", + "errors.ownership.invalid_requesting_user": "Je bent geen projectlid.", + "errors.ownership.invalid_target": "Doelgebruiker is geen lid van dit project.", + "errors.ownership.invalid_user": "Gebruiker niet gevonden of ongeldig.", + "errors.ownership.last_owner": "Kan eigenaar niet verwijderen, omdat er ten minste één eigenaar vereist is.", + "errors.ownership.not_owner": "Alleen projecteigenaren kunnen gebruikers typen wijzigen.", "file_actions.compress.name": "Comprimeer", "file_actions.copy.name": "Kopiëren", "file_actions.create.name": "Creëer", @@ -982,12 +995,14 @@ "labels.cloud_file_system": "Cloud-bestandssystemen", "labels.cloud_storage_remote_filesystems": "Cloudopslag & Externe Bestandssystemen", "labels.code_folding": "Code-vouwen", + "labels.collaborator": "Medewerker", "labels.collaborators": "Medewerkers", "labels.color": "Kleur", "labels.communication": "Communicatie", "labels.config": "Config", "labels.configuration": "Configuratie", "labels.configuration.short": "Config", + "labels.connected": "Verbonden", "labels.connecting": "Verbinden", "labels.connection": "Verbinding", "labels.copied": "gekopieerd", @@ -1016,6 +1031,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}}", @@ -1077,6 +1093,7 @@ "labels.open": "Openen", "labels.other": "Overig", "labels.overview": "Overzicht", + "labels.owner": "Eigenaar", "labels.pages": "Pagina's", "labels.paste": "Plakken", "labels.pay_as_you_go": "Betaal per gebruik", @@ -1095,6 +1112,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", @@ -1283,6 +1301,12 @@ "project_actions.rename_file.what": "hernoem {src}", "project-start-warning.content": "U moet het project \"{project_title}\" starten voordat u kunt {what}. {title}", "project-start-warning.title": "Dit project starten?", + "project.collaborators.add.owner_only_setting": "Alleen projekteigenaren kunnen medewerkers toevoegen wanneer beheer door alleen de eigenaar is ingeschakeld.", + "project.collaborators.demote.label": "Degraderen naar medewerker", + "project.collaborators.demote.tooltip": "{isLastOwner, select, true {Kan de laatste eigenaar niet degraderen} other {Degradeer deze eigenaar tot medewerker}}", + "project.collaborators.non_owner_note": "Alleen projecteigenaren kunnen gebruikersrollen beheren.", + "project.collaborators.promote.label": "Promoveer tot Eigenaar", + "project.collaborators.promote.tooltip": "Promoveer deze medewerker tot eigenaar, zodat ze volledige projectcontrole krijgen", "project.explorer.action-bar.check_all.button": "{checked, select, true {Alles deselecteren} other {Alles selecteren}}", "project.explorer.action-bar.currently_selected.info": "Klik het selectievakje links van een bestand om te kopiëren, downloaden, enz.", "project.explorer.action-bar.currently_selected.items": "{checked} van {total} {items} geselecteerd", @@ -1293,6 +1317,7 @@ "project.explorer.misc-side-buttons.open_dir.tooltip": "Opent de huidige map in een {name} serverinstantie, draaiend binnen dit project.", "project.explorer.search-bar.placeholder": "Filter bestanden of \"/\" voor terminal...", "project.explorer.start_project.warning": "Om de bestanden in deze map te zien, moet u dit project starten.", + "project.history.log-entry.change_collaborator_type": "veranderde {target} van {old_group} naar {new_group}", "project.history.log-entry.invited_user": "uitgenodigde gebruiker", "project.history.log-entry.invited_user_via": "uitgenodigde nieuwe gebruiker via", "project.history.log-entry.miniterm": "uitgevoerde mini terminal opdracht {cmd}", @@ -1385,6 +1410,7 @@ "project.settings.about-box.name.label": "Naam (optioneel)", "project.settings.about-box.starred.help": "Sterprojecten kunnen worden gefilterd door op de sterfilterknop in je projectenlijst te klikken.", "project.settings.about-box.title.label": "Titel", + "project.settings.collaborators.title": "Beheer van medewerkers", "project.settings.compute-image-selector.button.save-restart": "Opslaan en Herstarten", "project.settings.compute-image-selector.doubt": "{default, select, true {Dit is de standaardselectie} other {Opmerking: bij twijfel, selecteer \"{default_title}\"}}", "project.settings.compute-image-selector.software-env-info": "Een software-omgeving biedt alle software die dit project kan gebruiken. Als je extra software nodig hebt, kun je deze in het project installeren of contact opnemen met de ondersteuning. Lees meer over het installeren van Python-pakketten, Python Jupyter Kernel, R-pakketten en Julia-pakketten.", @@ -1408,6 +1434,9 @@ "project.settings.hide-delete-box.hide.label": "{hidden, select, true {Project zichtbaar maken} other {Project verbergen}}", "project.settings.hide-delete-box.hide.switch": "{hidden, select, true {Verborgen} other {Zichtbaar}}", "project.settings.hide-delete-box.title": "Verbergen of Verwijderen Project", + "project.settings.manage_users_owner_only": "Sta alleen eigenaren toe om medewerkers te beheren.", + "project.settings.manage_users_owner_only.note": "Deze instelling kan alleen worden gewijzigd door projecteigenaars.", + "project.settings.manage_users_owner_only.site_enforced": "Deze instelling wordt door de sitebeheerder afgedwongen voor alle projecten.", "project.settings.restart-project.button.label": "{is_running, select, true {Herstarten} other {Starten}}", "project.settings.site-license.body.info": "Informatie over bijgevoegde licenties. Klik op een rij om details uit te vouwen.", "project.settings.site-license.button.label": "Upgrade met een licentiesleutel...", @@ -1423,7 +1452,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 +1483,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..7e2edd32cd7 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:}}", @@ -177,8 +179,12 @@ "codemirror.extensions.ai_formula.insert_full_reply_button": "Wstaw pełną odpowiedź", "codemirror.extensions.ai_formula.title": "Generuj formułę LaTeX", "collaborators.current-collabs.intro": "Każdy wymieniony poniżej może wspólnie z Tobą pracować nad dowolnym Jupyter Notebookiem, Terminalem Linux lub plikiem w tym projekcie, a także dodawać lub usuwać innych współpracowników.", + "collaborators.current-collabs.intro2": "Każda osoba wymieniona poniżej może współpracować z Tobą nad dowolnym notatnikiem Jupyter, terminalem Linux lub plikiem w tym projekcie. {manageUsersOnly, select, true { Tylko właściciele projektu mogą dodawać lub usuwać współpracowników.} other { Współpracownicy mogą również dodawać lub usuwać innych współpracowników.}}", "collaborators.current-collabs.remove_other": "Czy na pewno chcesz usunąć {user} z tego projektu? Nie będą mieli już dostępu do tego projektu.", "collaborators.current-collabs.remove_self": "Czy na pewno chcesz usunąć siebie z tego projektu? Nie będziesz już mieć dostępu do tego projektu i nie możesz dodać siebie ponownie.", + "collaborators.current-collabs.remove.ok_button": "Tak, usuń {role}", + "collaborators.current-collabs.remove.owner_disabled": "Właściciele muszą zostać zdegradowani, zanim będą mogli zostać usunięci.", + "collaborators.current-collabs.remove.setting_disabled": "Tylko właściciele mogą usuwać współpracowników, gdy to ustawienie jest włączone.", "collaborators.current-collabs.title": "Obecni Współpracownicy", "command.format.ai_formula.button": "Formuła", "command.format.ai_formula.label": "Formuła wygenerowana przez AI", @@ -634,6 +640,13 @@ "editor.terminal.cmd.help.title": "Pokaż dokumentację dotyczącą używania terminala Linux w CoCalc", "editor.toggle_pdf_dark_mode.label": "Przełącz Tryb Ciemny PDF", "editor.toggle_pdf_dark_mode.title": "Wyłącz tryb ciemny PDF, aby zobaczyć oryginalny plik", + "errors.ownership.cannot_remove_owner": "Nie można usunąć właściciela. Najpierw zdegraduj do współpracownika.", + "errors.ownership.invalid_project_state": "Brakuje danych projektu lub są one nieprawidłowe.", + "errors.ownership.invalid_requesting_user": "Nie jesteś członkiem projektu.", + "errors.ownership.invalid_target": "Docelowy użytkownik nie jest członkiem tego projektu.", + "errors.ownership.invalid_user": "Użytkownik nie znaleziony lub nieprawidłowy.", + "errors.ownership.last_owner": "Nie można usunąć właściciela, ponieważ wymagany jest przynajmniej jeden właściciel.", + "errors.ownership.not_owner": "Tylko właściciele projektów mogą zmieniać typy użytkowników.", "file_actions.compress.name": "Kompresuj", "file_actions.copy.name": "Kopiuj", "file_actions.create.name": "Utwórz", @@ -982,12 +995,14 @@ "labels.cloud_file_system": "Chmurowe Systemy Plików", "labels.cloud_storage_remote_filesystems": "Przechowywanie w chmurze i zdalne systemy plików", "labels.code_folding": "Składanie kodu", + "labels.collaborator": "Współpracownik", "labels.collaborators": "Współpracownicy", "labels.color": "Kolor", "labels.communication": "Komunikacja", "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 +1031,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}}", @@ -1077,6 +1093,7 @@ "labels.open": "Otwórz", "labels.other": "Inne", "labels.overview": "Przegląd", + "labels.owner": "Właściciel", "labels.pages": "Strony", "labels.paste": "Wklej", "labels.pay_as_you_go": "Płać w miarę użycia", @@ -1095,6 +1112,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", @@ -1283,6 +1301,12 @@ "project_actions.rename_file.what": "zmień nazwę {src}", "project-start-warning.content": "Musisz uruchomić projekt \"{project_title}\" zanim będziesz mógł {what}. {title}", "project-start-warning.title": "Rozpocząć ten projekt?", + "project.collaborators.add.owner_only_setting": "Tylko właściciele projektów mogą dodawać współpracowników, gdy włączone jest zarządzanie tylko dla właścicieli.", + "project.collaborators.demote.label": "Degraduj do Współpracownika", + "project.collaborators.demote.tooltip": "{isLastOwner, select, true {Nie można zdegradować ostatniego właściciela} other {Zdegradować tego właściciela do współpracownika}}", + "project.collaborators.non_owner_note": "Tylko właściciele projektów mogą zarządzać rolami użytkowników.", + "project.collaborators.promote.label": "Awansuj na właściciela", + "project.collaborators.promote.tooltip": "Awansuj tego współpracownika na właściciela, dając mu pełną kontrolę nad projektem", "project.explorer.action-bar.check_all.button": "{checked, select, true {Odznacz wszystkie} other {Zaznacz wszystkie}}", "project.explorer.action-bar.currently_selected.info": "Kliknij pole wyboru po lewej stronie pliku, aby skopiować, pobrać, itp.", "project.explorer.action-bar.currently_selected.items": "{checked} z {total} {items} wybranych", @@ -1293,6 +1317,7 @@ "project.explorer.misc-side-buttons.open_dir.tooltip": "Otwiera bieżący katalog w instancji serwera {name}, działającej w ramach tego projektu.", "project.explorer.search-bar.placeholder": "Filtruj pliki lub \"/\" dla terminala...", "project.explorer.start_project.warning": "Aby zobaczyć pliki w tym katalogu, musisz uruchomić ten projekt.", + "project.history.log-entry.change_collaborator_type": "zmieniono {target} z {old_group} na {new_group}", "project.history.log-entry.invited_user": "zaproszony użytkownik", "project.history.log-entry.invited_user_via": "zaproszono nowego użytkownika przez", "project.history.log-entry.miniterm": "wykonano mini polecenie terminala {cmd}", @@ -1385,6 +1410,7 @@ "project.settings.about-box.name.label": "Nazwa (opcjonalnie)", "project.settings.about-box.starred.help": "Oznaczone gwiazdką projekty można filtrować, klikając przycisk filtru z gwiazdką na liście projektów.", "project.settings.about-box.title.label": "Tytuł", + "project.settings.collaborators.title": "Zarządzanie współpracownikami", "project.settings.compute-image-selector.button.save-restart": "Zapisz i Uruchom Ponownie", "project.settings.compute-image-selector.doubt": "{default, select, true {To jest domyślny wybór} other {Uwaga: w razie wątpliwości, wybierz \"{default_title}\"}}", "project.settings.compute-image-selector.software-env-info": "Środowisko oprogramowania zapewnia całe oprogramowanie, z którego ten projekt może korzystać. Jeśli potrzebujesz dodatkowego oprogramowania, możesz je zainstalować w projekcie lub skontaktować się z pomocą techniczną. Dowiedz się więcej o instalowaniu pakietów Pythona, jądrze Python Jupyter, pakietach R i pakietach Julii.", @@ -1408,6 +1434,9 @@ "project.settings.hide-delete-box.hide.label": "{hidden, select, true {Odkryj Projekt} other {Ukryj Projekt}}", "project.settings.hide-delete-box.hide.switch": "{hidden, select, true {Ukryty} other {Widoczny}}", "project.settings.hide-delete-box.title": "Ukryj lub Usuń Projekt", + "project.settings.manage_users_owner_only": "Zezwalaj tylko właścicielom na zarządzanie współpracownikami.", + "project.settings.manage_users_owner_only.note": "To ustawienie może być zmieniane tylko przez właścicieli projektu.", + "project.settings.manage_users_owner_only.site_enforced": "To ustawienie jest wymuszane przez administratora witryny dla wszystkich projektów.", "project.settings.restart-project.button.label": "{is_running, select, true {Restart} other {Start}}", "project.settings.site-license.body.info": "Informacje o załączonych licencjach. Kliknij wiersz, aby rozwinąć szczegóły.", "project.settings.site-license.button.label": "Uaktualnij za pomocą klucza licencyjnego...", @@ -1423,7 +1452,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 +1483,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..130272bc741 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:}}", @@ -177,8 +179,12 @@ "codemirror.extensions.ai_formula.insert_full_reply_button": "Inserir resposta completa", "codemirror.extensions.ai_formula.title": "Gerar Fórmula LaTeX", "collaborators.current-collabs.intro": "Todos listados abaixo podem trabalhar colaborativamente com você em qualquer Jupyter Notebook, Terminal Linux ou arquivo neste projeto, e adicionar ou remover outros colaboradores.", + "collaborators.current-collabs.intro2": "Todos listados abaixo podem trabalhar colaborativamente com você em qualquer Jupyter Notebook, Terminal Linux ou arquivo neste projeto. {manageUsersOnly, select, true { Somente os proprietários do projeto podem adicionar ou remover colaboradores.} other { Colaboradores também podem adicionar ou remover outros colaboradores.}}", "collaborators.current-collabs.remove_other": "Tem certeza de que deseja remover {user} deste projeto? Eles não terão mais acesso a este projeto.", "collaborators.current-collabs.remove_self": "Tem certeza de que deseja remover você mesmo deste projeto? Você não terá mais acesso a este projeto e não poderá se adicionar novamente.", + "collaborators.current-collabs.remove.ok_button": "Sim, remover {role}", + "collaborators.current-collabs.remove.owner_disabled": "Os proprietários devem ser rebaixados antes de serem removidos.", + "collaborators.current-collabs.remove.setting_disabled": "Somente os proprietários podem remover colaboradores quando esta configuração está ativada.", "collaborators.current-collabs.title": "Colaboradores Atuais", "command.format.ai_formula.button": "Fórmula", "command.format.ai_formula.label": "Fórmula Gerada por IA", @@ -634,6 +640,13 @@ "editor.terminal.cmd.help.title": "Mostrar documentação para usar o Terminal Linux no CoCalc.", "editor.toggle_pdf_dark_mode.label": "Alternar Modo Escuro do PDF", "editor.toggle_pdf_dark_mode.title": "Desativar o modo escuro do PDF para ver o arquivo original", + "errors.ownership.cannot_remove_owner": "Não é possível remover um proprietário. Rebaixe para colaborador primeiro.", + "errors.ownership.invalid_project_state": "Os dados do projeto estão ausentes ou inválidos.", + "errors.ownership.invalid_requesting_user": "Você não é membro do projeto.", + "errors.ownership.invalid_target": "Usuário alvo não é membro deste projeto.", + "errors.ownership.invalid_user": "Usuário não encontrado ou inválido.", + "errors.ownership.last_owner": "Não é possível remover o proprietário, pois é necessário pelo menos um proprietário.", + "errors.ownership.not_owner": "Apenas os proprietários do projeto podem alterar os tipos de usuário.", "file_actions.compress.name": "Comprimir", "file_actions.copy.name": "Copiar", "file_actions.create.name": "Criar", @@ -982,12 +995,14 @@ "labels.cloud_file_system": "Sistemas de Arquivos na Nuvem", "labels.cloud_storage_remote_filesystems": "Armazenamento em Nuvem & Sistemas de Arquivos Remotos", "labels.code_folding": "Dobra de Código", + "labels.collaborator": "Colaborador", "labels.collaborators": "Colaboradores", "labels.color": "Cor", "labels.communication": "Comunicação", "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 +1031,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}}", @@ -1077,6 +1093,7 @@ "labels.open": "Abrir", "labels.other": "Outros", "labels.overview": "Visão geral", + "labels.owner": "Proprietário", "labels.pages": "Páginas", "labels.paste": "Colar", "labels.pay_as_you_go": "Pague Conforme o Uso", @@ -1095,6 +1112,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", @@ -1283,6 +1301,12 @@ "project_actions.rename_file.what": "renomear {src}", "project-start-warning.content": "Você deve iniciar o projeto \"{project_title}\" antes de poder {what}. {title}", "project-start-warning.title": "Iniciar este projeto?", + "project.collaborators.add.owner_only_setting": "Somente os proprietários de projetos podem adicionar colaboradores quando a gestão exclusiva do proprietário está ativada.", + "project.collaborators.demote.label": "Rebaixar para Colaborador", + "project.collaborators.demote.tooltip": "{isLastOwner, select, true {Não é possível rebaixar o último proprietário} other {Rebaixar este proprietário para colaborador}}", + "project.collaborators.non_owner_note": "Somente os proprietários do projeto podem gerenciar funções de usuário.", + "project.collaborators.promote.label": "Promover para Proprietário", + "project.collaborators.promote.tooltip": "Promover este colaborador a proprietário, dando a ele controle total do projeto", "project.explorer.action-bar.check_all.button": "{checked, select, true {Desmarcar Todos} other {Marcar Todos}}", "project.explorer.action-bar.currently_selected.info": "Clique na caixa de seleção à esquerda de um arquivo para copiar, baixar, etc.", "project.explorer.action-bar.currently_selected.items": "{checked} de {total} {items} selecionados", @@ -1293,6 +1317,7 @@ "project.explorer.misc-side-buttons.open_dir.tooltip": "Abre o diretório atual em uma instância do servidor {name}, executando dentro deste projeto.", "project.explorer.search-bar.placeholder": "Filtrar arquivos ou \"/\" para terminal...", "project.explorer.start_project.warning": "Para ver os arquivos neste diretório, você precisa iniciar este projeto.", + "project.history.log-entry.change_collaborator_type": "alterado {target} de {old_group} para {new_group}", "project.history.log-entry.invited_user": "usuário convidado", "project.history.log-entry.invited_user_via": "convidou novo usuário via", "project.history.log-entry.miniterm": "comando de mini terminal executado {cmd}", @@ -1385,6 +1410,7 @@ "project.settings.about-box.name.label": "Nome (opcional)", "project.settings.about-box.starred.help": "Projetos estrelados podem ser filtrados clicando no botão de filtro estrelado na sua lista de projetos.", "project.settings.about-box.title.label": "Título", + "project.settings.collaborators.title": "Gerenciamento de Colaboradores", "project.settings.compute-image-selector.button.save-restart": "Salvar e Reiniciar", "project.settings.compute-image-selector.doubt": "{default, select, true {Esta é a seleção padrão} other {Nota: em caso de dúvida, selecione \"{default_title}\"}}", "project.settings.compute-image-selector.software-env-info": "Um ambiente de software fornece todo o software que este projeto pode utilizar. Se você precisar de software adicional, pode instalá-lo no projeto ou entrar em contato com o suporte. Saiba mais sobre instalação de pacotes Python, Kernel Python Jupyter, Pacotes R e pacotes Julia.", @@ -1408,6 +1434,9 @@ "project.settings.hide-delete-box.hide.label": "{hidden, select, true {Mostrar Projeto} other {Ocultar Projeto}}", "project.settings.hide-delete-box.hide.switch": "{hidden, select, true {Oculto} other {Visível}}", "project.settings.hide-delete-box.title": "Ocultar ou Excluir Projeto", + "project.settings.manage_users_owner_only": "Permitir apenas que os proprietários gerenciem colaboradores.", + "project.settings.manage_users_owner_only.note": "Esta configuração só pode ser alterada pelos proprietários do projeto.", + "project.settings.manage_users_owner_only.site_enforced": "Esta configuração é imposta pelo administrador do site para todos os projetos.", "project.settings.restart-project.button.label": "{is_running, select, true {Reiniciar} other {Iniciar}}", "project.settings.site-license.body.info": "Informações sobre licenças anexadas. Clique em uma linha para expandir os detalhes.", "project.settings.site-license.button.label": "Atualizar usando uma chave de licença...", @@ -1423,7 +1452,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 +1483,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..97025eba3ac 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:}}", @@ -177,8 +179,12 @@ "codemirror.extensions.ai_formula.insert_full_reply_button": "Inserir resposta completa", "codemirror.extensions.ai_formula.title": "Gerar Fórmula LaTeX", "collaborators.current-collabs.intro": "Todos os listados abaixo podem trabalhar colaborativamente consigo em qualquer Jupyter Notebook, Terminal Linux ou ficheiro neste projeto, e adicionar ou remover outros colaboradores.", + "collaborators.current-collabs.intro2": "Todos listados abaixo podem trabalhar colaborativamente consigo em qualquer Jupyter Notebook, Terminal Linux ou ficheiro neste projeto. {manageUsersOnly, select, true { Apenas os proprietários do projeto podem adicionar ou remover colaboradores.} other { Os colaboradores também podem adicionar ou remover outros colaboradores.}}", "collaborators.current-collabs.remove_other": "Tem a certeza de que deseja remover {user} deste projeto? Eles já não terão acesso a este projeto.", "collaborators.current-collabs.remove_self": "Tem a certeza de que quer remover si próprio deste projeto? Deixará de ter acesso a este projeto e não poderá adicionar-se novamente.", + "collaborators.current-collabs.remove.ok_button": "Sim, remover {role}", + "collaborators.current-collabs.remove.owner_disabled": "Os proprietários devem ser rebaixados antes de poderem ser removidos.", + "collaborators.current-collabs.remove.setting_disabled": "Apenas os proprietários podem remover colaboradores quando esta configuração está ativada.", "collaborators.current-collabs.title": "Colaboradores Atuais", "command.format.ai_formula.button": "Fórmula", "command.format.ai_formula.label": "Fórmula Gerada por IA", @@ -634,6 +640,13 @@ "editor.terminal.cmd.help.title": "Mostrar documentação para usar o Terminal Linux no CoCalc", "editor.toggle_pdf_dark_mode.label": "Alternar Modo Escuro do PDF", "editor.toggle_pdf_dark_mode.title": "Desativar o modo escuro do PDF, para ver o ficheiro original", + "errors.ownership.cannot_remove_owner": "Não é possível remover um proprietário. Demote para colaborador primeiro.", + "errors.ownership.invalid_project_state": "Os dados do projeto estão em falta ou são inválidos.", + "errors.ownership.invalid_requesting_user": "Não é membro do projeto.", + "errors.ownership.invalid_target": "O utilizador alvo não é membro deste projeto.", + "errors.ownership.invalid_user": "Utilizador não encontrado ou inválido.", + "errors.ownership.last_owner": "Não é possível remover o proprietário, porque é necessário pelo menos um proprietário.", + "errors.ownership.not_owner": "Só os proprietários do projeto podem alterar os tipos de utilizador.", "file_actions.compress.name": "Comprimir", "file_actions.copy.name": "Copiar", "file_actions.create.name": "Criar", @@ -982,12 +995,14 @@ "labels.cloud_file_system": "Sistemas de Ficheiros na Nuvem", "labels.cloud_storage_remote_filesystems": "Armazenamento na Nuvem e Sistemas de Ficheiros Remotos", "labels.code_folding": "Dobrar Código", + "labels.collaborator": "Colaborador", "labels.collaborators": "Colaboradores", "labels.color": "Cor", "labels.communication": "Comunicação", "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 +1031,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}}", @@ -1077,6 +1093,7 @@ "labels.open": "Abrir", "labels.other": "Outros", "labels.overview": "Visão geral", + "labels.owner": "Proprietário", "labels.pages": "Páginas", "labels.paste": "Colar", "labels.pay_as_you_go": "Pague Conforme o Uso", @@ -1095,6 +1112,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", @@ -1283,6 +1301,12 @@ "project_actions.rename_file.what": "renomear {src}", "project-start-warning.content": "Tem de iniciar o projeto \"{project_title}\" antes de poder {what}. {title}", "project-start-warning.title": "Iniciar este projeto?", + "project.collaborators.add.owner_only_setting": "Só os proprietários dos projetos podem adicionar colaboradores quando a gestão exclusiva do proprietário está ativada.", + "project.collaborators.demote.label": "Rebaixar para Colaborador", + "project.collaborators.demote.tooltip": "{isLastOwner, select, true {Não é possível despromover o último proprietário} other {Despromover este proprietário para colaborador}}", + "project.collaborators.non_owner_note": "Apenas os proprietários do projeto podem gerir os papéis dos utilizadores.", + "project.collaborators.promote.label": "Promover a Proprietário", + "project.collaborators.promote.tooltip": "Promover este colaborador a proprietário, dando-lhe controlo total do projeto", "project.explorer.action-bar.check_all.button": "{checked, select, true {Desmarcar Todos} other {Marcar Todos}}", "project.explorer.action-bar.currently_selected.info": "Clique na caixa de seleção à esquerda de um ficheiro para copiar, descarregar, etc.", "project.explorer.action-bar.currently_selected.items": "{checked} de {total} {items} selecionados", @@ -1293,6 +1317,7 @@ "project.explorer.misc-side-buttons.open_dir.tooltip": "Abre o diretório atual numa instância de servidor {name}, a correr dentro deste projeto.", "project.explorer.search-bar.placeholder": "Filtrar ficheiros ou \"/\" para terminal...", "project.explorer.start_project.warning": "Para ver os ficheiros neste diretório, tem de iniciar este projeto.", + "project.history.log-entry.change_collaborator_type": "alterado {target} de {old_group} para {new_group}", "project.history.log-entry.invited_user": "utilizador convidado", "project.history.log-entry.invited_user_via": "convidou novo utilizador via", "project.history.log-entry.miniterm": "comando de terminal mini executado {cmd}", @@ -1385,6 +1410,7 @@ "project.settings.about-box.name.label": "Nome (opcional)", "project.settings.about-box.starred.help": "Os projetos com estrela podem ser filtrados clicando no botão de filtro de estrelas na sua lista de projetos.", "project.settings.about-box.title.label": "Título", + "project.settings.collaborators.title": "Gestão de Colaboradores", "project.settings.compute-image-selector.button.save-restart": "Guardar e Reiniciar", "project.settings.compute-image-selector.doubt": "{default, select, true {Esta é a seleção padrão} other {Nota: em caso de dúvida, selecione \"{default_title}\"}}", "project.settings.compute-image-selector.software-env-info": "Um ambiente de software fornece todo o software que este projeto pode utilizar. Se precisar de software adicional, pode instalá-lo no projeto ou contactar o suporte. Saiba mais sobre instalar pacotes Python, Kernel Python Jupyter, Pacotes R e Pacotes Julia.", @@ -1408,6 +1434,9 @@ "project.settings.hide-delete-box.hide.label": "{hidden, select, true {Mostrar Projeto} other {Ocultar Projeto}}", "project.settings.hide-delete-box.hide.switch": "{hidden, select, true {Oculto} other {Visível}}", "project.settings.hide-delete-box.title": "Ocultar ou Eliminar Projeto", + "project.settings.manage_users_owner_only": "Permitir apenas aos proprietários gerir colaboradores.", + "project.settings.manage_users_owner_only.note": "Esta definição só pode ser alterada pelos proprietários do projeto.", + "project.settings.manage_users_owner_only.site_enforced": "Esta definição é aplicada pelo administrador do site a todos os projetos.", "project.settings.restart-project.button.label": "{is_running, select, true {Reiniciar} other {Iniciar}}", "project.settings.site-license.body.info": "Informação sobre licenças anexadas. Clique numa linha para expandir os detalhes.", "project.settings.site-license.button.label": "Atualizar usando uma chave de licença...", @@ -1423,7 +1452,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 +1483,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..a23e63a4b41 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 {Пожалуйста, проверьте и подтвердите ваш адрес электронной почты:}}", @@ -177,8 +179,12 @@ "codemirror.extensions.ai_formula.insert_full_reply_button": "Вставить полный ответ", "codemirror.extensions.ai_formula.title": "Создать формулу LaTeX", "collaborators.current-collabs.intro": "Все перечисленные ниже могут совместно работать с вами над любым Jupyter Notebook, терминалом Linux или файлом в этом проекте, а также добавлять или удалять других участников.", + "collaborators.current-collabs.intro2": "Все перечисленные ниже могут совместно работать с вами над любым Jupyter Notebook, терминалом Linux или файлом в этом проекте. {manageUsersOnly, select, true { Только владельцы проекта могут добавлять или удалять соавторов.} other { Соавторы также могут добавлять или удалять других соавторов.}}", "collaborators.current-collabs.remove_other": "Вы уверены, что хотите удалить {user} из этого проекта? У них больше не будет доступа к этому проекту.", "collaborators.current-collabs.remove_self": "Вы уверены, что хотите удалить себя из этого проекта? У вас больше не будет доступа к этому проекту, и вы не сможете добавить себя обратно.", + "collaborators.current-collabs.remove.ok_button": "Да, удалить {role}", + "collaborators.current-collabs.remove.owner_disabled": "Перед удалением владельцы должны быть понижены в должности.", + "collaborators.current-collabs.remove.setting_disabled": "Только владельцы могут удалять сотрудников, когда эта настройка включена.", "collaborators.current-collabs.title": "Текущие сотрудники", "command.format.ai_formula.button": "Формула", "command.format.ai_formula.label": "Формула, сгенерированная ИИ", @@ -634,6 +640,13 @@ "editor.terminal.cmd.help.title": "Показать документацию по использованию терминала Linux в CoCalc", "editor.toggle_pdf_dark_mode.label": "Переключить тёмный режим PDF", "editor.toggle_pdf_dark_mode.title": "Выключите темный режим PDF, чтобы увидеть оригинальный файл", + "errors.ownership.cannot_remove_owner": "Нельзя удалить владельца. Сначала понизьте до уровня сотрудника.", + "errors.ownership.invalid_project_state": "Данные проекта отсутствуют или недействительны.", + "errors.ownership.invalid_requesting_user": "Вы не являетесь участником проекта.", + "errors.ownership.invalid_target": "Целевой пользователь не является участником этого проекта.", + "errors.ownership.invalid_user": "Пользователь не найден или недействителен.", + "errors.ownership.last_owner": "Невозможно удалить владельца, так как требуется как минимум один владелец.", + "errors.ownership.not_owner": "Только владельцы проектов могут изменять типы пользователей.", "file_actions.compress.name": "Сжать", "file_actions.copy.name": "Копировать", "file_actions.create.name": "Создать", @@ -982,12 +995,14 @@ "labels.cloud_file_system": "Облачные файловые системы", "labels.cloud_storage_remote_filesystems": "Облачное хранилище и удаленные файловые системы", "labels.code_folding": "Сворачивание кода", + "labels.collaborator": "Сотрудник", "labels.collaborators": "Участники", "labels.color": "Цвет", "labels.communication": "Общение", "labels.config": "Конфигурация", "labels.configuration": "Конфигурация", "labels.configuration.short": "Конфиг", + "labels.connected": "Подключено", "labels.connecting": "Соединение", "labels.connection": "Соединение", "labels.copied": "скопировано", @@ -1016,6 +1031,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 {Сохранить}}", @@ -1077,6 +1093,7 @@ "labels.open": "Открыть", "labels.other": "Другие", "labels.overview": "Обзор", + "labels.owner": "Владелец", "labels.pages": "Страницы", "labels.paste": "Вставить", "labels.pay_as_you_go": "Оплата по мере использования", @@ -1095,6 +1112,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": "Готово", @@ -1283,6 +1301,12 @@ "project_actions.rename_file.what": "переименовать {src}", "project-start-warning.content": "Вы должны запустить проект \"{project_title}\", прежде чем сможете {what}. {title}", "project-start-warning.title": "Начать этот проект?", + "project.collaborators.add.owner_only_setting": "Только владельцы проектов могут добавлять сотрудников, когда включено управление только владельцами.", + "project.collaborators.demote.label": "Понизить до Сотрудника", + "project.collaborators.demote.tooltip": "{isLastOwner, select, true {Нельзя понизить последнего владельца} other {Понизить этого владельца до сотрудника}}", + "project.collaborators.non_owner_note": "Только владельцы проектов могут управлять ролями пользователей.", + "project.collaborators.promote.label": "Повысить до владельца", + "project.collaborators.promote.tooltip": "Повысить этого сотрудника до владельца, предоставив ему полный контроль над проектом", "project.explorer.action-bar.check_all.button": "{checked, select, true {Снять все} other {Выбрать все}}", "project.explorer.action-bar.currently_selected.info": "Нажмите флажок слева от файла, чтобы копировать, скачать и т.д.", "project.explorer.action-bar.currently_selected.items": "{checked} из {total} {items} выбрано", @@ -1293,6 +1317,7 @@ "project.explorer.misc-side-buttons.open_dir.tooltip": "Открывает текущий каталог в экземпляре сервера {name}, работающем внутри этого проекта", "project.explorer.search-bar.placeholder": "Фильтровать файлы или \"/\" для терминала...", "project.explorer.start_project.warning": "Чтобы увидеть файлы в этом каталоге, вам нужно запустить этот проект.", + "project.history.log-entry.change_collaborator_type": "изменено {target} с {old_group} на {new_group}", "project.history.log-entry.invited_user": "приглашенный пользователь", "project.history.log-entry.invited_user_via": "пригласил нового пользователя через", "project.history.log-entry.miniterm": "выполнена мини-команда терминала {cmd}", @@ -1385,6 +1410,7 @@ "project.settings.about-box.name.label": "Имя (необязательно)", "project.settings.about-box.starred.help": "Помеченные звёздочкой проекты можно отфильтровать, нажав на кнопку фильтрации по звёздочкам в списке ваших проектов.", "project.settings.about-box.title.label": "Заголовок", + "project.settings.collaborators.title": "Управление сотрудниками", "project.settings.compute-image-selector.button.save-restart": "Сохранить и перезапустить", "project.settings.compute-image-selector.doubt": "{default, select, true {Это выбор по умолчанию} other {Примечание: если не уверены, выберите \"{default_title}\"}}", "project.settings.compute-image-selector.software-env-info": "Программная среда предоставляет все программное обеспечение, которое может использовать этот проект. Если вам нужно дополнительное программное обеспечение, вы можете либо установить его в проекте, либо связаться с поддержкой. Узнайте о установке пакетов Python, ядре Python Jupyter, пакетах R и пакетах Julia.", @@ -1408,6 +1434,9 @@ "project.settings.hide-delete-box.hide.label": "{hidden, select, true {Показать проект} other {Скрыть проект}}", "project.settings.hide-delete-box.hide.switch": "{hidden, select, true {Скрыто} other {Видимо}}", "project.settings.hide-delete-box.title": "Скрыть или Удалить Проект", + "project.settings.manage_users_owner_only": "Разрешить только владельцам управлять сотрудниками.", + "project.settings.manage_users_owner_only.note": "Этот параметр может изменяться только владельцами проекта.", + "project.settings.manage_users_owner_only.site_enforced": "Этот параметр установлен администратором сайта для всех проектов.", "project.settings.restart-project.button.label": "{is_running, select, true {Перезапустить} other {Запустить}}", "project.settings.site-license.body.info": "Информация о прикрепленных лицензиях. Щелкните по строке, чтобы развернуть детали.", "project.settings.site-license.button.label": "Обновить с помощью лицензионного ключа...", @@ -1423,7 +1452,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 +1483,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..802f9f9d222 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:}}", @@ -177,8 +179,12 @@ "codemirror.extensions.ai_formula.insert_full_reply_button": "Tam yanıtı ekle", "codemirror.extensions.ai_formula.title": "LaTeX Formülü Oluştur", "collaborators.current-collabs.intro": "Aşağıda listelenen herkes, bu projedeki herhangi bir Jupyter Notebook, Linux Terminal veya dosya üzerinde sizinle işbirliği yapabilir ve diğer işbirlikçileri ekleyebilir veya kaldırabilir.", + "collaborators.current-collabs.intro2": "Aşağıda listelenen herkes bu projedeki herhangi bir Jupyter Notebook, Linux Terminal veya dosya üzerinde sizinle birlikte çalışabilir. {manageUsersOnly, select, true { Yalnızca proje sahipleri işbirlikçileri ekleyebilir veya kaldırabilir.} other { İşbirlikçiler de diğer işbirlikçileri ekleyebilir veya kaldırabilir.}}", "collaborators.current-collabs.remove_other": "Bu {user} kullanıcısını bu projeden kaldırmak istediğinizden emin misiniz? Artık bu projeye erişimleri olmayacak.", "collaborators.current-collabs.remove_self": "Bu projeden kendinizi çıkarmak istediğinizden emin misiniz? Bu projeye artık erişiminiz olmayacak ve kendinizi geri ekleyemezsiniz.", + "collaborators.current-collabs.remove.ok_button": "Evet, {role} kaldır", + "collaborators.current-collabs.remove.owner_disabled": "Sahiplerin kaldırılmadan önce rütbeleri düşürülmelidir.", + "collaborators.current-collabs.remove.setting_disabled": "Bu ayar etkinleştirildiğinde yalnızca sahipler işbirlikçileri kaldırabilir.", "collaborators.current-collabs.title": "Mevcut İşbirlikçiler", "command.format.ai_formula.button": "Formül", "command.format.ai_formula.label": "AI Tarafından Oluşturulan Formül", @@ -634,6 +640,13 @@ "editor.terminal.cmd.help.title": "CoCalc'ta Linux Terminalini kullanma belgelerini göster.", "editor.toggle_pdf_dark_mode.label": "PDF Koyu Modu Değiştir", "editor.toggle_pdf_dark_mode.title": "PDF'nin karanlık modunu kapat, orijinal dosyayı görmek için", + "errors.ownership.cannot_remove_owner": "Bir sahibi kaldıramazsınız. Önce işbirlikçiye düşürün.", + "errors.ownership.invalid_project_state": "Proje verileri eksik veya geçersiz.", + "errors.ownership.invalid_requesting_user": "Proje üyesi değilsiniz.", + "errors.ownership.invalid_target": "Hedef kullanıcı bu projenin bir üyesi değil.", + "errors.ownership.invalid_user": "Kullanıcı bulunamadı veya geçersiz.", + "errors.ownership.last_owner": "Sahibi kaldıramazsınız, çünkü en az bir sahip gereklidir.", + "errors.ownership.not_owner": "Yalnızca proje sahipleri kullanıcı türlerini değiştirebilir.", "file_actions.compress.name": "Sıkıştır", "file_actions.copy.name": "Kopyala", "file_actions.create.name": "Oluştur", @@ -982,12 +995,14 @@ "labels.cloud_file_system": "Bulut Dosya Sistemleri", "labels.cloud_storage_remote_filesystems": "Bulut Depolama & Uzaktan Dosya Sistemleri", "labels.code_folding": "Kod Katlama", + "labels.collaborator": "İşbirlikçi", "labels.collaborators": "Katılımcılar", "labels.color": "Renk", "labels.communication": "İletişim", "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 +1031,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}}", @@ -1077,6 +1093,7 @@ "labels.open": "Aç", "labels.other": "Diğer", "labels.overview": "Genel Bakış", + "labels.owner": "Sahip", "labels.pages": "Sayfalar", "labels.paste": "Yapıştır", "labels.pay_as_you_go": "Kullandıkça Öde", @@ -1095,6 +1112,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", @@ -1283,6 +1301,12 @@ "project_actions.rename_file.what": "{src} yeniden adlandır", "project-start-warning.content": "Projeyi \"{project_title}\" başlatmalısınız, önce {what} yapabilirsiniz. {title}", "project-start-warning.title": "Bu projeyi başlat?", + "project.collaborators.add.owner_only_setting": "Yalnızca proje sahipleri, yalnızca sahip yönetimi etkinleştirildiğinde iş birliği yapabilecek kişileri ekleyebilir.", + "project.collaborators.demote.label": "Ortak Çalışan Olarak Düşür", + "project.collaborators.demote.tooltip": "{isLastOwner, select, true {Son sahibi düşürülemez} other {Bu sahibi işbirlikçiye düşür}}", + "project.collaborators.non_owner_note": "Yalnızca proje sahipleri kullanıcı rollerini yönetebilir.", + "project.collaborators.promote.label": "Sahip Olarak Terfi Et", + "project.collaborators.promote.tooltip": "Bu işbirlikçiyi tam proje kontrolü vererek sahip olarak terfi ettir", "project.explorer.action-bar.check_all.button": "{checked, select, true {Tümünü Kaldır} other {Tümünü Seç}}", "project.explorer.action-bar.currently_selected.info": "Bir dosyayı kopyalamak, indirmek vb. için solundaki onay kutusuna tıklayın", "project.explorer.action-bar.currently_selected.items": "{checked} / {total} {items} seçildi", @@ -1293,6 +1317,7 @@ "project.explorer.misc-side-buttons.open_dir.tooltip": "Bu projede çalışan bir {name} sunucu örneğinde geçerli dizini açar.", "project.explorer.search-bar.placeholder": "Dosyaları filtrele veya terminal için \"/\"...", "project.explorer.start_project.warning": "Bu dizindeki dosyaları görmek için bu projeyi başlatmalısınız.", + "project.history.log-entry.change_collaborator_type": "{target} öğesi {old_group} grubundan {new_group} grubuna değiştirildi", "project.history.log-entry.invited_user": "davet edilen kullanıcı", "project.history.log-entry.invited_user_via": "davet edilen yeni kullanıcı üzerinden", "project.history.log-entry.miniterm": "çalıştırılan mini terminal komutu {cmd}", @@ -1385,6 +1410,7 @@ "project.settings.about-box.name.label": "İsim (isteğe bağlı)", "project.settings.about-box.starred.help": "Yıldızlı projeler, proje listenizdeki yıldızlı filtre düğmesine tıklanarak filtrelenebilir.", "project.settings.about-box.title.label": "Başlık", + "project.settings.collaborators.title": "Katılımcı Yönetimi", "project.settings.compute-image-selector.button.save-restart": "Kaydet ve Yeniden Başlat", "project.settings.compute-image-selector.doubt": "{default, select, true {Bu varsayılan seçimdir} other {Not: şüphe duyarsanız \"{default_title}\" seçin}}", "project.settings.compute-image-selector.software-env-info": "Bir yazılım ortamı, bu projenin kullanabileceği tüm yazılımları sağlar. Ek yazılıma ihtiyacınız varsa projeye yükleyebilir veya destek ile iletişime geçebilirsiniz. Python paketlerini yükleme, Python Jupyter Çekirdeği, R Paketleri ve Julia paketleri hakkında bilgi edinin.", @@ -1408,6 +1434,9 @@ "project.settings.hide-delete-box.hide.label": "{hidden, select, true {Proje Görünür Yap} other {Proje Gizle}}", "project.settings.hide-delete-box.hide.switch": "{hidden, select, true {Gizli} other {Görünür}}", "project.settings.hide-delete-box.title": "Projeyi Gizle veya Sil", + "project.settings.manage_users_owner_only": "Yalnızca sahiplerin işbirlikçileri yönetmesine izin ver.", + "project.settings.manage_users_owner_only.note": "Bu ayar yalnızca proje sahipleri tarafından değiştirilebilir.", + "project.settings.manage_users_owner_only.site_enforced": "Bu ayar, site yöneticisi tarafından tüm projeler için zorunlu kılınmıştır.", "project.settings.restart-project.button.label": "{is_running, select, true {Yeniden Başlat} other {Başlat}}", "project.settings.site-license.body.info": "Bağlı lisanslar hakkında bilgi. Detayları genişletmek için bir satıra tıklayın.", "project.settings.site-license.button.label": "Lisans anahtarı kullanarak yükselt...", @@ -1423,7 +1452,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 +1483,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..f3087392392 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 {请检查并验证您的电子邮箱地址:}}", @@ -177,8 +179,12 @@ "codemirror.extensions.ai_formula.insert_full_reply_button": "插入完整回复", "codemirror.extensions.ai_formula.title": "生成 LaTeX 公式", "collaborators.current-collabs.intro": "以下列出的所有人都可以在此项目中的任何Jupyter Notebook、Linux Terminal或文件上与你协作,并添加或删除其他协作者。", + "collaborators.current-collabs.intro2": "下列所有人都可以在此项目中与你协作处理任何 Jupyter Notebook、Linux 终端或文件。{manageUsersOnly, select, true { 只有项目所有者可以添加或移除协作者。} other { 协作者也可以添加或移除其他协作者。}}", "collaborators.current-collabs.remove_other": "您确定要将{user}从此项目中移除吗?他们将不再有权访问此项目。", "collaborators.current-collabs.remove_self": "您确定要将自己从此项目中移除吗?您将无法再访问此项目,也无法重新添加自己。", + "collaborators.current-collabs.remove.ok_button": "是的,移除{role}", + "collaborators.current-collabs.remove.owner_disabled": "必须先降级所有者,然后才能将其移除。", + "collaborators.current-collabs.remove.setting_disabled": "启用此设置时,只有所有者可以移除协作者。", "collaborators.current-collabs.title": "当前合作者", "command.format.ai_formula.button": "公式", "command.format.ai_formula.label": "AI生成公式", @@ -634,6 +640,13 @@ "editor.terminal.cmd.help.title": "显示在 CoCalc 中使用 Linux 终端的文档", "editor.toggle_pdf_dark_mode.label": "切换 PDF 暗模式", "editor.toggle_pdf_dark_mode.title": "关闭PDF的暗模式,以查看原始文件", + "errors.ownership.cannot_remove_owner": "无法移除所有者。请先降为合作者。", + "errors.ownership.invalid_project_state": "项目数据缺失或无效。", + "errors.ownership.invalid_requesting_user": "您不是项目成员。", + "errors.ownership.invalid_target": "目标用户不是此项目的成员。", + "errors.ownership.invalid_user": "用户未找到或无效。", + "errors.ownership.last_owner": "无法移除所有者,因为至少需要一个所有者。", + "errors.ownership.not_owner": "只有项目所有者可以更改用户类型。", "file_actions.compress.name": "压缩", "file_actions.copy.name": "复制", "file_actions.create.name": "创建", @@ -982,12 +995,14 @@ "labels.cloud_file_system": "云文件系统", "labels.cloud_storage_remote_filesystems": "云存储和远程文件系统", "labels.code_folding": "代码折叠", + "labels.collaborator": "协作者", "labels.collaborators": "合作者", "labels.color": "颜色", "labels.communication": "通信", "labels.config": "配置", "labels.configuration": "配置", "labels.configuration.short": "配置", + "labels.connected": "已连接", "labels.connecting": "连接中", "labels.connection": "连接", "labels.copied": "已复制", @@ -1016,6 +1031,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 {保存}}", @@ -1077,6 +1093,7 @@ "labels.open": "打开", "labels.other": "其他", "labels.overview": "概述", + "labels.owner": "拥有者", "labels.pages": "页面", "labels.paste": "粘贴", "labels.pay_as_you_go": "随用随付", @@ -1095,6 +1112,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": "准备好", @@ -1283,6 +1301,12 @@ "project_actions.rename_file.what": "重命名 {src}", "project-start-warning.content": "你必须启动项目 \"{project_title}\" 才能 {what}. {title}", "project-start-warning.title": "启动这个项目?", + "project.collaborators.add.owner_only_setting": "仅当启用仅限所有者管理时,项目所有者才能添加协作成员。", + "project.collaborators.demote.label": "降级为合作者", + "project.collaborators.demote.tooltip": "{isLastOwner, select, true {无法降级最后一个所有者} other {将此所有者降级为协作者}}", + "project.collaborators.non_owner_note": "只有项目所有者可以管理用户角色。", + "project.collaborators.promote.label": "提升为所有者", + "project.collaborators.promote.tooltip": "将此协作者提升为所有者,给予他们完整的项目控制权", "project.explorer.action-bar.check_all.button": "{checked, select, true {取消全选} other {全选}}", "project.explorer.action-bar.currently_selected.info": "单击文件左侧的复选框以复制、下载等", "project.explorer.action-bar.currently_selected.items": "已选择 {total} 个中的 {checked} 个 {items}", @@ -1293,6 +1317,7 @@ "project.explorer.misc-side-buttons.open_dir.tooltip": "在此项目中运行的 {name} 服务器实例中打开当前目录", "project.explorer.search-bar.placeholder": "筛选文件或输入“/”进入终端...", "project.explorer.start_project.warning": "要查看此目录中的文件,您必须启动此项目。", + "project.history.log-entry.change_collaborator_type": "将 {target} 从 {old_group} 更改为 {new_group}", "project.history.log-entry.invited_user": "受邀用户", "project.history.log-entry.invited_user_via": "通过邀请新用户", "project.history.log-entry.miniterm": "执行了迷你终端命令 {cmd}", @@ -1385,6 +1410,7 @@ "project.settings.about-box.name.label": "姓名(可选)", "project.settings.about-box.starred.help": "可以通过单击项目列表中的加星过滤按钮来筛选加星项目。", "project.settings.about-box.title.label": "标题", + "project.settings.collaborators.title": "协作者管理", "project.settings.compute-image-selector.button.save-restart": "保存并重启", "project.settings.compute-image-selector.doubt": "{default, select, true {这是默认选择} other {注意:如有疑问,选择\"{default_title}\"}}", "project.settings.compute-image-selector.software-env-info": "软件环境提供所有软件,该项目可以使用。如果您需要额外的软件,可以在项目中安装或联系支持。了解安装 Python 包Python Jupyter 内核R 包Julia 包。", @@ -1408,6 +1434,9 @@ "project.settings.hide-delete-box.hide.label": "{hidden, select, true {取消隐藏项目} other {隐藏项目}}", "project.settings.hide-delete-box.hide.switch": "{hidden, select, true {隐藏} other {可见}}", "project.settings.hide-delete-box.title": "隐藏或删除项目", + "project.settings.manage_users_owner_only": "仅允许所有者管理协作者。", + "project.settings.manage_users_owner_only.note": "此设置只能由项目所有者更改。", + "project.settings.manage_users_owner_only.site_enforced": "该设置由网站管理员强制应用于所有项目。", "project.settings.restart-project.button.label": "{is_running, select, true {重启} other {启动}}", "project.settings.site-license.body.info": "有关附加许可证的信息。单击一行以展开详细信息。", "project.settings.site-license.button.label": "使用许可证密钥升级...", @@ -1423,7 +1452,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 +1483,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/project/history/log-entry.tsx b/src/packages/frontend/project/history/log-entry.tsx index 710a7ddce56..988682361f7 100644 --- a/src/packages/frontend/project/history/log-entry.tsx +++ b/src/packages/frontend/project/history/log-entry.tsx @@ -62,6 +62,10 @@ import type { import { isUnknownEvent } from "./types"; const TRUNC = 90; +type CollaboratorInviteOrRemoveEvent = Extract< + CollaboratorEvent, + { event: "invite_user" | "invite_nonuser" | "remove_collaborator" } +>; // eslint-disable-next-line @typescript-eslint/no-var-requires const { User } = require("@cocalc/frontend/users"); @@ -752,7 +756,9 @@ export const LogEntry: React.FC = React.memo( ); } - function render_invite_user(event: CollaboratorEvent): React.JSX.Element { + function render_invite_user( + event: CollaboratorInviteOrRemoveEvent, + ): React.JSX.Element { return ( = React.memo( } function render_invite_nonuser( - event: CollaboratorEvent, + event: CollaboratorInviteOrRemoveEvent, ): React.JSX.Element { return ( @@ -779,11 +785,10 @@ export const LogEntry: React.FC = React.memo( } function render_remove_collaborator( - event: CollaboratorEvent, + event: CollaboratorInviteOrRemoveEvent, ): React.JSX.Element { return ( - {" "} = React.memo( ); } + function render_change_collaborator_type( + event: Extract, + ): React.JSX.Element { + const groupLabel = (group: "owner" | "collaborator") => + intl.formatMessage({ + id: `project.history.log-entry.group.${group}`, + defaultMessage: group, + }); + + const target = + event.target_name != null ? ( + event.target_name + ) : ( + + ); + + return ( + + + + ); + } + function render_desc(): Rendered | Rendered[] { if (typeof event === "string") { return {event}; @@ -835,11 +871,27 @@ export const LogEntry: React.FC = React.memo( case "pay-as-you-go-upgrade": return render_pay_as_you_go(event); case "invite_user": - return render_invite_user(event); + return render_invite_user( + event as Extract, + ); case "invite_nonuser": - return render_invite_nonuser(event); + return render_invite_nonuser( + event as Extract, + ); case "remove_collaborator": - return render_remove_collaborator(event); + return render_remove_collaborator( + event as Extract< + CollaboratorEvent, + { event: "remove_collaborator" } + >, + ); + case "change_collaborator_type": + return render_change_collaborator_type( + event as Extract< + CollaboratorEvent, + { event: "change_collaborator_type" } + >, + ); case "open_project": // not used anymore??? return opened this project; case "library": @@ -917,6 +969,7 @@ export const LogEntry: React.FC = React.memo( case "invite_user": case "invite_nonuser": case "remove_collaborator": + case "change_collaborator_type": return "user"; case "software_environment": return SOFTWARE_ENVIRONMENT_ICON; @@ -940,7 +993,7 @@ export const LogEntry: React.FC = React.memo( } function renderExtra() { - // flyout mode only: if colum is wider, add timestamp + // flyout mode only: if column is wider, add timestamp if (mode === "flyout" && flyoutExtra) { return ( diff --git a/src/packages/frontend/project/history/types.ts b/src/packages/frontend/project/history/types.ts index 32cbf50df4b..9fffda5a428 100644 --- a/src/packages/frontend/project/history/types.ts +++ b/src/packages/frontend/project/history/types.ts @@ -95,12 +95,20 @@ export type X11Event = { path: string; }; -export type CollaboratorEvent = { - event: "invite_user" | "invite_nonuser" | "remove_collaborator"; - invitee_account_id?: string; - invitee_email?: string; - removed_name?: string; -}; +export type CollaboratorEvent = + | { + event: "invite_user" | "invite_nonuser" | "remove_collaborator"; + invitee_account_id?: string; + invitee_email?: string; + removed_name?: string; + } + | { + event: "change_collaborator_type"; + target_account_id: string; + target_name?: string; + old_group: "owner" | "collaborator"; + new_group: "owner" | "collaborator"; + }; export type UpgradeEvent = { event: "upgrade"; diff --git a/src/packages/frontend/projects/actions.ts b/src/packages/frontend/projects/actions.ts index bfd2959e37b..5b45aa6b33c 100644 --- a/src/packages/frontend/projects/actions.ts +++ b/src/packages/frontend/projects/actions.ts @@ -41,6 +41,8 @@ import type { } from "@cocalc/util/db-schema/projects"; export type { Datastore, EnvVars, EnvVarsRecord }; +// cSpell:ignore replyto collabs noncloud Payg + // Define projects actions export class ProjectsActions extends Actions { private getProjectTable = async () => { @@ -426,7 +428,7 @@ export class ProjectsActions extends Actions { license: undefined, }); if (!opts2.image) { - // make falseish same as not specified. + // make false-ish same as not specified. delete opts2.image; } @@ -651,6 +653,36 @@ export class ProjectsActions extends Actions { } } + public async change_user_type( + project_id: string, + target_account_id: string, + new_group: "owner" | "collaborator", + ): Promise { + const old_group = store + .getIn(["project_map", project_id, "users", target_account_id, "group"]) + ?.toString() as "owner" | "collaborator" | undefined; + const target_name = redux.getStore("users").get_name(target_account_id); + try { + await webapp_client.project_collaborators.change_user_type({ + project_id, + target_account_id, + new_group, + }); + // Log AFTER successful change + await this.redux.getProjectActions(project_id).async_log({ + event: "change_collaborator_type", + target_account_id, + target_name, + old_group: (old_group ?? new_group) as "owner" | "collaborator", + new_group, + }); + } catch (err) { + const message = `Error changing ${target_name} to ${new_group} in project ${project_id} -- ${err}`; + alert_message({ type: "error", message }); + throw err; + } + } + // this is for inviting existing users, the email is only known by the back-end public async invite_collaborator( project_id: string, @@ -1050,7 +1082,7 @@ export class ProjectsActions extends Actions { await this.start_project(project_id, options); }; - // Explcitly set whether or not project is hidden for the given account + // Explicitly set whether or not project is hidden for the given account // (hide=true means hidden) public async set_project_hide( account_id: string, diff --git a/src/packages/next/lib/project/get-owner.ts b/src/packages/next/lib/project/get-owner.ts index ce548576bde..3e54a12b618 100644 --- a/src/packages/next/lib/project/get-owner.ts +++ b/src/packages/next/lib/project/get-owner.ts @@ -1,24 +1,42 @@ import getPool from "@cocalc/database/pool"; -// Returns account_id or organization_id of the owner of this project. -export default async function getOwner(project_id: string): Promise { - const pool = getPool("minutes"); // we don't even have a way to change the owner ever in cocalc. +type Users = { [account_id: string]: { group?: string } }; - // TODO: this seems *really* stupid/inefficient in general, e.g., what if - // there are 1000 users? I don't know JSONB PostgreSQL enough to come up - // with a better query... +async function getProjectUsers(project_id: string): Promise { + const pool = getPool("minutes"); const result = await pool.query( "SELECT users FROM projects WHERE project_id=$1", - [project_id] + [project_id], ); - if (result.rows.length == 0) { + if (result.rows.length === 0) { throw Error(`no project with id ${project_id}`); } const { users } = result.rows[0] ?? {}; + return users ?? {}; +} + +function collectOwnerIds(users: Users): string[] { + const owners: string[] = []; for (const account_id in users) { - if (users[account_id].group == "owner") { - return account_id; + if (users[account_id]?.group === "owner") { + owners.push(account_id); } } - throw Error(`project ${project_id} has no owner`); + return owners; +} + +// Returns account_id or organization_id of the first owner found for this project. +// NOTE: Projects may have multiple owners; use getOwners() to get all owners. +export default async function getOwner(project_id: string): Promise { + const owners = await getOwners(project_id); + return owners[0]; +} + +// Returns all account_ids of owners for this project. +export async function getOwners(project_id: string): Promise { + const owners = collectOwnerIds(await getProjectUsers(project_id)); + if (owners.length === 0) { + throw Error(`project ${project_id} has no owner`); + } + return owners; } diff --git a/src/packages/server/projects/collaborators-ownership.test.ts b/src/packages/server/projects/collaborators-ownership.test.ts new file mode 100644 index 00000000000..a6af6e809e3 --- /dev/null +++ b/src/packages/server/projects/collaborators-ownership.test.ts @@ -0,0 +1,320 @@ +/* + * This file is part of CoCalc: Copyright © 2025 Sagemath, Inc. + * License: MS-RSL – see LICENSE.md for details + */ + +import { callback2 } from "@cocalc/util/async-utils"; +import { uuid } from "@cocalc/util/misc"; +import getPool, { initEphemeralDatabase } from "@cocalc/database/pool"; +import { db } from "@cocalc/database"; +import createAccount from "@cocalc/server/accounts/create-account"; +import createProject from "@cocalc/server/projects/create"; +import { + addCollaborator, + changeUserType, + inviteCollaborator, + inviteCollaboratorWithoutAccount, + removeCollaborator, +} from "@cocalc/server/projects/collaborators"; +import { + resetServerSettingsCache, + getServerSettings, +} from "@cocalc/database/settings/server-settings"; +import { OwnershipErrorCode } from "@cocalc/util/project-ownership"; + +async function setSiteStrictCollab(value: "yes" | "no") { + await callback2(db().set_server_setting, { + name: "strict_collaborator_management", + value, + readonly: false, + }); + resetServerSettingsCache(); + await getServerSettings(); // warm cache +} + +beforeAll(async () => { + await initEphemeralDatabase({ reset: true }); +}, 15000); + +afterAll(async () => { + await getPool().end(); +}); + +afterEach(async () => { + await setSiteStrictCollab("no"); +}); + +async function createUser(emailPrefix: string): Promise { + const account_id = uuid(); + await createAccount({ + email: `${emailPrefix}-${account_id}@example.com`, + password: "pass", + firstName: "Test", + lastName: "User", + account_id, + }); + return account_id; +} + +async function createProjectWithOwner(): Promise<{ + ownerId: string; + projectId: string; +}> { + const ownerId = await createUser("owner"); + const projectId = await createProject({ + account_id: ownerId, + title: "Ownership test project", + }); + return { ownerId, projectId }; +} + +describe("changeUserType validations", () => { + test("owner can promote collaborator to owner", async () => { + const { ownerId, projectId } = await createProjectWithOwner(); + const collaboratorId = await createUser("collab"); + await addCollaborator({ + account_id: ownerId, + opts: { project_id: projectId, account_id: collaboratorId }, + }); + + await expect( + changeUserType({ + account_id: ownerId, + opts: { + project_id: projectId, + target_account_id: collaboratorId, + new_group: "owner", + }, + }), + ).resolves.toBeUndefined(); + + const { rows } = await getPool().query( + "SELECT users FROM projects WHERE project_id=$1", + [projectId], + ); + expect(rows[0].users[collaboratorId].group).toBe("owner"); + }); + + test("owner can demote another owner when not last owner", async () => { + const { ownerId, projectId } = await createProjectWithOwner(); + const secondOwnerId = await createUser("owner"); + await addCollaborator({ + account_id: ownerId, + opts: { project_id: projectId, account_id: secondOwnerId }, + }); + await changeUserType({ + account_id: ownerId, + opts: { + project_id: projectId, + target_account_id: secondOwnerId, + new_group: "owner", + }, + }); + + await expect( + changeUserType({ + account_id: ownerId, + opts: { + project_id: projectId, + target_account_id: secondOwnerId, + new_group: "collaborator", + }, + }), + ).resolves.toBeUndefined(); + + const { rows } = await getPool().query( + "SELECT users FROM projects WHERE project_id=$1", + [projectId], + ); + expect(rows[0].users[secondOwnerId].group).toBe("collaborator"); + }); + + test("cannot demote last owner", async () => { + const { ownerId, projectId } = await createProjectWithOwner(); + await expect( + changeUserType({ + account_id: ownerId, + opts: { + project_id: projectId, + target_account_id: ownerId, + new_group: "collaborator", + }, + }), + ).rejects.toMatchObject({ code: OwnershipErrorCode.LAST_OWNER }); + }); + + test("collaborator cannot change user types", async () => { + const { ownerId, projectId } = await createProjectWithOwner(); + const collaboratorId = await createUser("collab"); + await addCollaborator({ + account_id: ownerId, + opts: { project_id: projectId, account_id: collaboratorId }, + }); + + await expect( + changeUserType({ + account_id: collaboratorId, + opts: { + project_id: projectId, + target_account_id: ownerId, + new_group: "collaborator", + }, + }), + ).rejects.toMatchObject({ code: OwnershipErrorCode.NOT_OWNER }); + }); + + test("project not found throws invalid project state", async () => { + const accountId = await createUser("owner"); + await expect( + changeUserType({ + account_id: accountId, + opts: { + project_id: uuid(), + target_account_id: uuid(), + new_group: "owner", + }, + }), + ).rejects.toMatchObject({ + code: OwnershipErrorCode.INVALID_REQUESTING_USER, + }); + }); + + test("target not in project throws invalid user", async () => { + const { ownerId, projectId } = await createProjectWithOwner(); + await expect( + changeUserType({ + account_id: ownerId, + opts: { + project_id: projectId, + target_account_id: uuid(), + new_group: "owner", + }, + }), + ).rejects.toMatchObject({ code: OwnershipErrorCode.INVALID_USER }); + }); +}); + +describe("removal rules", () => { + test("self removal allowed when manage_users_owner_only is true", async () => { + const { ownerId, projectId } = await createProjectWithOwner(); + const collaboratorId = await createUser("collab"); + await addCollaborator({ + account_id: ownerId, + opts: { project_id: projectId, account_id: collaboratorId }, + }); + await getPool().query( + "UPDATE projects SET manage_users_owner_only=$1 WHERE project_id=$2", + [true, projectId], + ); + + await expect( + removeCollaborator({ + account_id: collaboratorId, + opts: { project_id: projectId, account_id: collaboratorId }, + }), + ).resolves.toBeUndefined(); + }); + + test("cannot remove an owner", async () => { + const { ownerId, projectId } = await createProjectWithOwner(); + await expect( + removeCollaborator({ + account_id: ownerId, + opts: { project_id: projectId, account_id: ownerId }, + }), + ).rejects.toMatchObject({ code: OwnershipErrorCode.CANNOT_REMOVE_OWNER }); + }); +}); + +describe("site setting override", () => { + test("site strict setting overrides project flag", async () => { + const { ownerId, projectId } = await createProjectWithOwner(); + const collaboratorId = await createUser("collab"); + const otherCollabId = await createUser("collab"); + await addCollaborator({ + account_id: ownerId, + opts: { project_id: projectId, account_id: collaboratorId }, + }); + await addCollaborator({ + account_id: ownerId, + opts: { project_id: projectId, account_id: otherCollabId }, + }); + await getPool().query( + "UPDATE projects SET manage_users_owner_only=$1 WHERE project_id=$2", + [false, projectId], + ); + await setSiteStrictCollab("yes"); + + await expect( + removeCollaborator({ + account_id: collaboratorId, + opts: { project_id: projectId, account_id: otherCollabId }, + }), + ).rejects.toMatchObject({ code: OwnershipErrorCode.NOT_OWNER }); + }); +}); + +describe("invite permissions", () => { + test("owner can invite when manage_users_owner_only is true", async () => { + const { ownerId, projectId } = await createProjectWithOwner(); + const inviteeId = await createUser("invitee"); + await getPool().query( + "UPDATE projects SET manage_users_owner_only=$1 WHERE project_id=$2", + [true, projectId], + ); + + await expect( + inviteCollaborator({ + account_id: ownerId, + opts: { project_id: projectId, account_id: inviteeId }, + }), + ).resolves.toBeUndefined(); + }); + + test("collaborator cannot invite when manage_users_owner_only is true", async () => { + const { ownerId, projectId } = await createProjectWithOwner(); + const collaboratorId = await createUser("collab"); + const inviteeId = await createUser("invitee"); + await addCollaborator({ + account_id: ownerId, + opts: { project_id: projectId, account_id: collaboratorId }, + }); + await getPool().query( + "UPDATE projects SET manage_users_owner_only=$1 WHERE project_id=$2", + [true, projectId], + ); + + await expect( + inviteCollaborator({ + account_id: collaboratorId, + opts: { project_id: projectId, account_id: inviteeId }, + }), + ).rejects.toMatchObject({ code: OwnershipErrorCode.NOT_OWNER }); + }); + + test("collaborator cannot invite non-user when manage_users_owner_only is true", async () => { + const { ownerId, projectId } = await createProjectWithOwner(); + const collaboratorId = await createUser("collab"); + await addCollaborator({ + account_id: ownerId, + opts: { project_id: projectId, account_id: collaboratorId }, + }); + await getPool().query( + "UPDATE projects SET manage_users_owner_only=$1 WHERE project_id=$2", + [true, projectId], + ); + + await expect( + inviteCollaboratorWithoutAccount({ + account_id: collaboratorId, + opts: { + project_id: projectId, + email: "newuser@example.com", + title: "Invite", + link2proj: "", + to: "newuser@example.com", + }, + }), + ).rejects.toMatchObject({ code: OwnershipErrorCode.NOT_OWNER }); + }); +}); diff --git a/src/packages/server/projects/collaborators.ts b/src/packages/server/projects/collaborators.ts index 2cd644e486f..6b32dbeef9b 100644 --- a/src/packages/server/projects/collaborators.ts +++ b/src/packages/server/projects/collaborators.ts @@ -19,22 +19,119 @@ import getEmailAddress from "@cocalc/server/accounts/get-email-address"; import { is_paying_customer } from "@cocalc/database/postgres/account-queries"; import { project_has_network_access } from "@cocalc/database/postgres/project-queries"; import { RESEND_INVITE_INTERVAL_DAYS } from "@cocalc/util/consts/invites"; +import { + type UserGroup, + validateUserTypeChange, + OwnershipErrorCode, +} from "@cocalc/util/project-ownership"; +import { query } from "@cocalc/database/postgres/query"; +import { getServerSettings } from "@cocalc/database/settings/server-settings"; const logger = getLogger("project:collaborators"); +export class OwnershipError extends Error { + code: OwnershipErrorCode; + constructor(message: string, code: OwnershipErrorCode) { + super(message); + this.name = "OwnershipError"; + this.code = code; + } +} + +/** + * Helper function to check if a user can manage collaborators based on the + * manage_users_owner_only setting. + * + * @throws {OwnershipError} If the project is not found or the user is not allowed to manage collaborators + */ +async function ensureCanManageCollaborators(opts: { + project_id: string; + account_id: string; + database?: any; +}): Promise { + const { project_id, account_id, database = db() } = opts; + const serverSettings = await getServerSettings(); + const siteEnforced = !!serverSettings.strict_collaborator_management; + + const project = await query({ + db: database, + table: "projects", + select: ["users", "manage_users_owner_only"], + where: { project_id }, + one: true, + }); + + if (!project) { + throw new OwnershipError( + "Project not found", + OwnershipErrorCode.INVALID_PROJECT_STATE, + ); + } + + const manage_users_owner_only = project.manage_users_owner_only ?? false; + const requesting_user_group = project.users?.[account_id]?.group as + | UserGroup + | undefined; + + const restrictToOwners = siteEnforced || manage_users_owner_only; + + if (restrictToOwners && requesting_user_group !== "owner") { + throw new OwnershipError( + "Only owners can manage collaborators when this setting is enabled", + OwnershipErrorCode.NOT_OWNER, + ); + } +} + export async function removeCollaborator({ account_id, opts, }: { account_id: string; opts: { - account_id; - project_id; + account_id: string; + project_id: string; }; }): Promise { if (!(await isCollaborator({ account_id, project_id: opts.project_id }))) { throw Error("user must be a collaborator"); } + + // Get fresh project data to check user groups + const project = await query({ + db: db(), + table: "projects", + select: ["users"], + where: { project_id: opts.project_id }, + one: true, + }); + + if (!project) { + throw Error("Project not found"); + } + + const target_user_group = project.users?.[opts.account_id]?.group as + | UserGroup + | undefined; + + // CRITICAL: Block ALL owner removals (anyone trying to remove an owner) + // Owners must be demoted to collaborator first, THEN removed + if (target_user_group === "owner") { + throw new OwnershipError( + "Cannot remove an owner. Demote to collaborator first.", + OwnershipErrorCode.CANNOT_REMOVE_OWNER, + ); + } + + // Check manage_users_owner_only setting (unless removing self) + const is_self_remove = account_id === opts.account_id; + if (!is_self_remove) { + await ensureCanManageCollaborators({ + project_id: opts.project_id, + account_id, + }); + } + // @ts-ignore await callback2(db().remove_collaborator_from_project, opts); } @@ -66,6 +163,15 @@ export async function addCollaborator({ accounts = [accounts]; } + // Check manage_users_owner_only setting for each project + // Only check if not using tokens (tokens have their own permission system) + if (!tokens && projects && projects.length > 0) { + for (const project_id of projects as string[]) { + if (!project_id) continue; // skip empty strings + await ensureCanManageCollaborators({ project_id, account_id }); + } + } + await add_collaborators_to_projects( db(), account_id, @@ -75,7 +181,7 @@ export async function addCollaborator({ ); // Tokens determine the projects, and it may be useful to the client to know what // project they just got added to! - let project_id; + let project_id: string | string[] | undefined; if (is_single_token) { project_id = projects[0]; } else { @@ -84,6 +190,89 @@ export async function addCollaborator({ return { project_id }; } +export async function changeUserType({ + account_id, + opts, +}: { + account_id: string; + opts: { + project_id: string; + target_account_id: string; + new_group: UserGroup; + }; +}): Promise { + const { project_id, target_account_id, new_group } = opts; + + // 1. Verify requester is a project member + if (!(await isCollaborator({ account_id, project_id }))) { + throw new OwnershipError( + "Not a project member", + OwnershipErrorCode.INVALID_REQUESTING_USER, + ); + } + + // 2. Get fresh project data (users field only) + const project = await query({ + db: db(), + table: "projects", + select: ["users"], + where: { project_id }, + one: true, + }); + + if (!project) { + throw new OwnershipError( + "Project not found", + OwnershipErrorCode.INVALID_PROJECT_STATE, + ); + } + + const users = project.users; + + // 3. Get requesting user's group + const requesting_user_group = users?.[account_id]?.group as + | UserGroup + | undefined; + + // 4. Get target user's current group + const target_current_group = users?.[target_account_id]?.group as + | UserGroup + | undefined; + + // 5. Validate the change + const validation = validateUserTypeChange({ + requesting_account_id: account_id, + requesting_user_group, + target_account_id, + target_current_group, + target_new_group: new_group, + all_users: users, + }); + + if (!validation.valid) { + throw new OwnershipError( + validation.error ?? "Invalid user type change", + validation.errorCode ?? OwnershipErrorCode.INVALID_USER, + ); + } + + // 6. Perform the change via add_user_to_project + await callback2(db().add_user_to_project, { + project_id, + account_id: target_account_id, + group: new_group, + }); + + // 7. Log the change for audit trail + logger.info("changeUserType", { + project_id, + actor_account_id: account_id, + target_account_id, + old_group: target_current_group, + new_group, + }); +} + async function allowUrlsInEmails({ project_id, account_id, @@ -116,9 +305,16 @@ export async function inviteCollaborator({ if (!(await isCollaborator({ account_id, project_id: opts.project_id }))) { throw Error("user must be a collaborator"); } - const dbg = (...args) => logger.debug("inviteCollaborator", ...args); + const dbg = (...args: any[]) => logger.debug("inviteCollaborator", ...args); const database = db(); + // Check manage_users_owner_only setting before inviting + await ensureCanManageCollaborators({ + project_id: opts.project_id, + account_id, + database, + }); + // Actually add user to project await callback2(database.add_user_to_project, { project_id: opts.project_id, @@ -209,10 +405,17 @@ export async function inviteCollaboratorWithoutAccount({ if (!(await isCollaborator({ account_id, project_id: opts.project_id }))) { throw Error("user must be a collaborator"); } - const dbg = (...args) => + const dbg = (...args: any[]) => logger.debug("inviteCollaboratorWithoutAccount", ...args); const database = db(); + // Check manage_users_owner_only setting before inviting + await ensureCanManageCollaborators({ + project_id: opts.project_id, + account_id, + database, + }); + if (opts.to.length > 1024) { throw Error( "Specify less recipients when adding collaborators to project.", diff --git a/src/packages/server/projects/manage-users-owner-only.test.ts b/src/packages/server/projects/manage-users-owner-only.test.ts new file mode 100644 index 00000000000..cd7cfdf464f --- /dev/null +++ b/src/packages/server/projects/manage-users-owner-only.test.ts @@ -0,0 +1,197 @@ +/* + * This file is part of CoCalc: Copyright © 2025 Sagemath, Inc. + * License: MS-RSL – see LICENSE.md for details + */ + +import { callback2 } from "@cocalc/util/async-utils"; +import { uuid } from "@cocalc/util/misc"; +import { db } from "@cocalc/database"; +import getPool, { initEphemeralDatabase } from "@cocalc/database/pool"; +import createAccount from "@cocalc/server/accounts/create-account"; +import createProject from "@cocalc/server/projects/create"; +import { + addCollaborator, + removeCollaborator, +} from "@cocalc/server/projects/collaborators"; +import { resetServerSettingsCache } from "@cocalc/database/settings/server-settings"; + +async function setSiteStrictCollab(value: "yes" | "no") { + await callback2(db().set_server_setting, { + name: "strict_collaborator_management", + value, + readonly: false, + }); + resetServerSettingsCache(); +} + +beforeAll(async () => { + await initEphemeralDatabase(); +}, 15000); + +afterAll(async () => { + await getPool().end(); +}); + +describe("without site enforcement (default)", () => { + const ownerId = uuid(); + const collaboratorId = uuid(); + const collaboratorToRemove = uuid(); + const newCollaboratorId = uuid(); + let projectId: string; + + beforeAll(async () => { + await setSiteStrictCollab("no"); + + await createAccount({ + email: `owner-${ownerId}@example.com`, + password: "pass", + firstName: "Owner", + lastName: "One", + account_id: ownerId, + }); + await createAccount({ + email: `collab-${collaboratorId}@example.com`, + password: "pass", + firstName: "Collab", + lastName: "Two", + account_id: collaboratorId, + }); + await createAccount({ + email: `collab-${collaboratorToRemove}@example.com`, + password: "pass", + firstName: "Collab", + lastName: "Three", + account_id: collaboratorToRemove, + }); + await createAccount({ + email: `collab-${newCollaboratorId}@example.com`, + password: "pass", + firstName: "Collab", + lastName: "Four", + account_id: newCollaboratorId, + }); + + projectId = await createProject({ + account_id: ownerId, + title: "Default setting test", + }); + + await addCollaborator({ + account_id: ownerId, + opts: { project_id: projectId, account_id: collaboratorId }, + }); + await addCollaborator({ + account_id: ownerId, + opts: { project_id: projectId, account_id: collaboratorToRemove }, + }); + }); + + test("collaborator can add collaborators when site enforcement is off", async () => { + await expect( + addCollaborator({ + account_id: collaboratorId, + opts: { project_id: projectId, account_id: newCollaboratorId }, + }), + ).resolves.toBeDefined(); + + const { rows } = await getPool().query( + "SELECT users FROM projects WHERE project_id=$1", + [projectId], + ); + expect(rows[0].users[newCollaboratorId]).toEqual({ group: "collaborator" }); + }); + + test("collaborator can remove another collaborator when site enforcement is off", async () => { + await expect( + removeCollaborator({ + account_id: collaboratorId, + opts: { project_id: projectId, account_id: collaboratorToRemove }, + }), + ).resolves.toBeUndefined(); + + const { rows } = await getPool().query( + "SELECT users FROM projects WHERE project_id=$1", + [projectId], + ); + expect(rows[0].users[collaboratorToRemove]).toBeUndefined(); + }); +}); + +describe("strict collaborator management site setting", () => { + const ownerId = uuid(); + const collaboratorId = uuid(); + const otherCollaboratorId = uuid(); + const newCollaboratorId = uuid(); + let projectId: string; + + beforeAll(async () => { + await setSiteStrictCollab("yes"); + + await createAccount({ + email: `owner-${ownerId}@example.com`, + password: "pass", + firstName: "Owner", + lastName: "One", + account_id: ownerId, + }); + await createAccount({ + email: `collab-${collaboratorId}@example.com`, + password: "pass", + firstName: "Collab", + lastName: "Two", + account_id: collaboratorId, + }); + await createAccount({ + email: `collab-${otherCollaboratorId}@example.com`, + password: "pass", + firstName: "Collab", + lastName: "Three", + account_id: otherCollaboratorId, + }); + + projectId = await createProject({ + account_id: ownerId, + title: "Strict setting test", + }); + + await addCollaborator({ + account_id: ownerId, + opts: { project_id: projectId, account_id: collaboratorId }, + }); + await addCollaborator({ + account_id: ownerId, + opts: { project_id: projectId, account_id: otherCollaboratorId }, + }); + }); + + test("owner can still add collaborators when site enforcement is on", async () => { + await expect( + addCollaborator({ + account_id: ownerId, + opts: { project_id: projectId, account_id: newCollaboratorId }, + }), + ).resolves.toBeDefined(); + }); + + test("collaborator cannot add collaborators when site enforcement is on", async () => { + await expect( + addCollaborator({ + account_id: collaboratorId, + opts: { project_id: projectId, account_id: uuid() }, + }), + ).rejects.toThrow( + "Only owners can manage collaborators when this setting is enabled", + ); + }); + + test("collaborator cannot remove another collaborator when site enforcement is on", async () => { + await expect( + removeCollaborator({ + account_id: collaboratorId, + opts: { project_id: projectId, account_id: otherCollaboratorId }, + }), + ).rejects.toThrow( + "Only owners can manage collaborators when this setting is enabled", + ); + }); +}); diff --git a/src/packages/util/db-schema/client-db.ts b/src/packages/util/db-schema/client-db.ts index d26f0f1bcd5..bb3fc94f054 100644 --- a/src/packages/util/db-schema/client-db.ts +++ b/src/packages/util/db-schema/client-db.ts @@ -17,6 +17,8 @@ class ClientDB { this.sha1 = this.sha1.bind(this); this._user_set_query_project_users = this._user_set_query_project_users.bind(this); + this._user_set_query_project_manage_users_owner_only = + this._user_set_query_project_manage_users_owner_only.bind(this); this._user_set_query_project_change_after = this._user_set_query_project_change_after.bind(this); this._user_set_query_project_change_before = @@ -45,6 +47,10 @@ class ClientDB { return obj.users; } + _user_set_query_project_manage_users_owner_only(obj) { + return obj.manage_users_owner_only; + } + _user_set_query_project_change_after(_obj, _old_val, _new_val, cb) { cb(); } diff --git a/src/packages/util/db-schema/projects.ts b/src/packages/util/db-schema/projects.ts index 3951b99ea42..9eb816154f2 100644 --- a/src/packages/util/db-schema/projects.ts +++ b/src/packages/util/db-schema/projects.ts @@ -11,7 +11,9 @@ import { ExecuteCodeOptionsAsyncGet, ExecuteCodeOutput, } from "@cocalc/util/types/execute-code"; +import { callback2 } from "@cocalc/util/async-utils"; import { DEFAULT_QUOTAS } from "@cocalc/util/upgrade-spec"; +import { isUserGroup } from "@cocalc/util/project-ownership"; import { NOTES } from "./crm"; import { FALLBACK_COMPUTE_IMAGE } from "./defaults"; @@ -75,6 +77,7 @@ Table({ run_quota: null, site_license: null, status: null, + manage_users_owner_only: null, // security model is anybody with access to the project should be allowed to know this token. secret_token: null, state: null, @@ -108,6 +111,12 @@ Table({ users(obj, db, account_id) { return db._user_set_query_project_users(obj, account_id); }, + manage_users_owner_only(obj, db, account_id) { + return db._user_set_query_project_manage_users_owner_only( + obj, + account_id, + ); + }, action_request: true, // used to request that an action be performed, e.g., "save"; handled by before_change compute_image: true, site_license: true, @@ -120,6 +129,47 @@ Table({ required_fields: { project_id: true, }, + async check_hook(db, obj, account_id, _project_id, cb) { + // Validate manage_users_owner_only permission if it's being changed + if (obj.manage_users_owner_only !== undefined) { + try { + // Require actor identity before hitting the database + if (!account_id) { + throw Error( + "account_id is required to change manage_users_owner_only", + ); + } + + const siteSettings = + (await callback2(db.get_site_settings, {})) ?? {}; + const siteEnforced = + siteSettings.strict_collaborator_management === true; + if (siteEnforced && obj.manage_users_owner_only !== true) { + throw Error( + "Collaborator management is enforced by the site administrator and cannot be disabled.", + ); + } + + const { rows } = await db.async_query({ + query: "SELECT users FROM projects WHERE project_id = $1", + params: [obj.project_id], + }); + const users = rows?.[0]?.users ?? {}; + + // Check that the user making the change is an owner + const group = users?.[account_id]?.group; + if (!isUserGroup(group) || group !== "owner") { + throw Error( + "Only project owners can change collaborator management settings", + ); + } + } catch (err) { + cb(err.toString()); + return; + } + } + cb(); + }, before_change(database, old_val, new_val, account_id, cb) { database._user_set_query_project_change_before( old_val, @@ -191,6 +241,11 @@ Table({ desc: "This is a map from account_id's to {hide:bool, group:'owner'|'collaborator', upgrades:{memory:1000, ...}, ssh:{...}}.", render: { type: "usersmap", editable: true }, }, + manage_users_owner_only: { + type: "boolean", + desc: "If true, only project owners can add or remove collaborators. Collaborators can still remove themselves. Disabled by default (undefined or false means current behavior where collaborators can manage other collaborators).", + render: { type: "boolean", editable: true }, + }, invite: { type: "map", desc: "Map from email addresses to {time:when invite sent, error:error message if there was one}", diff --git a/src/packages/util/db-schema/site-defaults.ts b/src/packages/util/db-schema/site-defaults.ts index 93ae9926e57..9d39455c285 100644 --- a/src/packages/util/db-schema/site-defaults.ts +++ b/src/packages/util/db-schema/site-defaults.ts @@ -7,6 +7,7 @@ import jsonic from "jsonic"; import { isEqual } from "lodash"; + import { LOCALE } from "@cocalc/util/consts/locale"; import { is_valid_email_address } from "@cocalc/util/misc"; import { @@ -112,6 +113,7 @@ export type SiteSettingsKeys = | "anonymous_signup" | "anonymous_signup_licensed_shares" | "share_server" + | "strict_collaborator_management" | "landing_pages" | "sandbox_projects_enabled" | "sandbox_project_id" @@ -778,6 +780,13 @@ export const site_settings_conf: SiteSettings = { valid: only_booleans, to_val: to_bool, }, + strict_collaborator_management: { + name: "Only project owners can manage collaborators", + desc: "Force collaborator management to owners only across all projects. When enabled, per-project controls are disabled and only owners can add, remove, or change collaborator roles.", + default: "no", + valid: only_booleans, + to_val: to_bool, + }, landing_pages: { name: "Landing pages", desc: "Host landing pages about the functionality of CoCalc.", diff --git a/src/packages/util/project-ownership.test.ts b/src/packages/util/project-ownership.test.ts new file mode 100644 index 00000000000..c5933ab94b1 --- /dev/null +++ b/src/packages/util/project-ownership.test.ts @@ -0,0 +1,576 @@ +/* + * This file is part of CoCalc: Copyright © 2025 Sagemath, Inc. + * License: MS-RSL – see LICENSE.md for details + */ + +/* +## Project Ownership Transfer - Test Coverage + +This test suite validates the ownership transfer and collaborator management rules. + +### Scenario Matrix + +| Actor Type | Action | Target User | Current State | Allowed? | Validation Rule | Test Coverage | +| ------------ | ---------------------- | ------------------ | ---------------- | -------- | --------------------------------- | ------------- | +| Owner | Elevate to owner | Collaborator | Has other owners | ✅ Yes | Owner privilege | ✅ Tested | +| Owner | Demote to collaborator | Owner (self) | Has other owners | ✅ Yes | Can step down if not last owner | ✅ Tested | +| Owner | Demote to collaborator | Owner (other) | Has other owners | ✅ Yes | Owner privilege | ✅ Tested | +| Owner | Demote to collaborator | Owner (any) | Last owner | ❌ No | Must maintain ≥1 owner | ✅ Tested | +| Owner | Add collaborator | N/A | Any | ✅ Yes | Current functionality | ✅ Tested | +| Owner | Remove collaborator | Collaborator | Any | ✅ Yes | Current functionality | ✅ Tested | +| Owner | Remove collaborator | Owner (self) | Any | ❌ No | Must demote to collaborator first | ✅ Tested | +| Owner | Remove collaborator | Owner (other) | Any | ❌ No | Must demote to collaborator first | ✅ Tested | +| Collaborator | Elevate to owner | Self | Any | ❌ No | No self-elevation | ✅ Tested | +| Collaborator | Elevate to owner | Other collaborator | Any | ❌ No | No user type changes | ✅ Tested | +| Collaborator | Elevate to owner | Owner | Any | ❌ No | No user type changes | ✅ Tested | +| Collaborator | Demote to collaborator | Owner | Any | ❌ No | Cannot change owner status | ✅ Tested | +| Collaborator | Add collaborator | N/A | Setting disabled | ✅ Yes | Current behavior | ✅ Tested | +| Collaborator | Add collaborator | N/A | Setting enabled | ❌ No | New constraint | ✅ Tested | +| Collaborator | Remove collaborator | Other collaborator | Setting disabled | ✅ Yes | Current behavior | ✅ Tested | +| Collaborator | Remove collaborator | Other collaborator | Setting enabled | ❌ No | New constraint | ✅ Tested | +| Collaborator | Remove collaborator | Self | Any | ✅ Yes | Can always leave | ✅ Tested | +| Collaborator | Remove collaborator | Owner | Any | ❌ No | Cannot remove owners | ✅ Tested | + +### Core Validation Rules (All Tested) + +1. **Minimum Owner Rule:** Projects must have at least 1 owner at all times +2. **Owner Privilege Rule:** Only owners can change user types (owner ↔ collaborator) +3. **Self-Step-Down Rule:** Owners can demote themselves only if other owners exist +4. **No Self-Elevation Rule:** Collaborators cannot elevate themselves or others +5. **Collaborator Management Rule:** When setting enabled, only owners can add/remove collaborators +6. **Self-Remove Rule:** Users can always remove themselves (except owners - must demote first) +7. **No Direct Owner Removal:** Owners cannot be removed directly. Must demote to collaborator first. + +### Error Codes Tested + +All error codes defined in `OwnershipErrorCode` enum (see project-ownership.ts): + +- `LAST_OWNER` - Cannot demote the last owner +- `NOT_OWNER` - Only owners can perform this action +- `INVALID_TARGET` - Target user is invalid or not in project +- `INVALID_USER` - User not found in project +- `CANNOT_REMOVE_OWNER` - Cannot remove owners directly +- `INVALID_REQUESTING_USER` - Requesting user is not a valid member +- `INVALID_PROJECT_STATE` - Project data is missing or invalid +*/ + +import { + canManageCollaborators, + countOwners, + isLastOwner, + isUserGroup, + OwnershipErrorCode, + validateAddCollaborator, + validateRemoveCollaborator, + validateUserTypeChange, +} from "./project-ownership"; + +describe("isUserGroup", () => { + test("returns true for owner", () => { + expect(isUserGroup("owner")).toBe(true); + }); + + test("returns true for collaborator", () => { + expect(isUserGroup("collaborator")).toBe(true); + }); + + test("returns false for invalid values", () => { + expect(isUserGroup("admin")).toBe(false); + expect(isUserGroup("public")).toBe(false); + expect(isUserGroup(undefined)).toBe(false); + expect(isUserGroup(null)).toBe(false); + expect(isUserGroup("")).toBe(false); + }); +}); + +describe("countOwners", () => { + test("counts owners correctly", () => { + const users = { + user1: { group: "owner" }, + user2: { group: "collaborator" }, + user3: { group: "owner" }, + }; + expect(countOwners(users)).toBe(2); + }); + + test("returns 0 for no owners", () => { + const users = { + user1: { group: "collaborator" }, + user2: { group: "collaborator" }, + }; + expect(countOwners(users)).toBe(0); + }); + + test("handles null users", () => { + expect(countOwners(null)).toBe(0); + }); + + test("handles undefined users", () => { + expect(countOwners(undefined)).toBe(0); + }); + + test("handles empty object", () => { + expect(countOwners({})).toBe(0); + }); +}); + +describe("isLastOwner", () => { + test("returns true when user is the only owner", () => { + const users = { + user1: { group: "owner" }, + user2: { group: "collaborator" }, + }; + expect(isLastOwner("user1", users)).toBe(true); + }); + + test("returns false when there are multiple owners", () => { + const users = { + user1: { group: "owner" }, + user2: { group: "owner" }, + user3: { group: "collaborator" }, + }; + expect(isLastOwner("user1", users)).toBe(false); + }); + + test("returns false when user is not an owner", () => { + const users = { + user1: { group: "owner" }, + user2: { group: "collaborator" }, + }; + expect(isLastOwner("user2", users)).toBe(false); + }); + + test("returns false for null users", () => { + expect(isLastOwner("user1", null)).toBe(false); + }); + + test("returns false for undefined users", () => { + expect(isLastOwner("user1", undefined)).toBe(false); + }); +}); + +describe("validateUserTypeChange", () => { + const mockUsers = { + owner1: { group: "owner" }, + owner2: { group: "owner" }, + collab1: { group: "collaborator" }, + collab2: { group: "collaborator" }, + }; + + test("owner can promote collaborator to owner", () => { + const result = validateUserTypeChange({ + requesting_account_id: "owner1", + requesting_user_group: "owner", + target_account_id: "collab1", + target_current_group: "collaborator", + target_new_group: "owner", + all_users: mockUsers, + }); + expect(result.valid).toBe(true); + }); + + test("owner can demote another owner when multiple owners exist", () => { + const result = validateUserTypeChange({ + requesting_account_id: "owner1", + requesting_user_group: "owner", + target_account_id: "owner2", + target_current_group: "owner", + target_new_group: "collaborator", + all_users: mockUsers, + }); + expect(result.valid).toBe(true); + }); + + test("owner changing collaborator to same group is allowed (no-op)", () => { + const result = validateUserTypeChange({ + requesting_account_id: "owner1", + requesting_user_group: "owner", + target_account_id: "collab1", + target_current_group: "collaborator", + target_new_group: "collaborator", + all_users: mockUsers, + }); + expect(result.valid).toBe(true); + }); + + test("owner can demote self when other owners exist", () => { + const result = validateUserTypeChange({ + requesting_account_id: "owner1", + requesting_user_group: "owner", + target_account_id: "owner1", + target_current_group: "owner", + target_new_group: "collaborator", + all_users: mockUsers, + }); + expect(result.valid).toBe(true); + }); + + test("cannot demote last owner", () => { + const usersWithOneOwner = { + owner1: { group: "owner" }, + collab1: { group: "collaborator" }, + }; + const result = validateUserTypeChange({ + requesting_account_id: "owner1", + requesting_user_group: "owner", + target_account_id: "owner1", + target_current_group: "owner", + target_new_group: "collaborator", + all_users: usersWithOneOwner, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.LAST_OWNER); + }); + + test("collaborator cannot promote self", () => { + const result = validateUserTypeChange({ + requesting_account_id: "collab1", + requesting_user_group: "collaborator", + target_account_id: "collab1", + target_current_group: "collaborator", + target_new_group: "owner", + all_users: mockUsers, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.NOT_OWNER); + }); + + test("collaborator cannot promote others", () => { + const result = validateUserTypeChange({ + requesting_account_id: "collab1", + requesting_user_group: "collaborator", + target_account_id: "collab2", + target_current_group: "collaborator", + target_new_group: "owner", + all_users: mockUsers, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.NOT_OWNER); + }); + + test("collaborator cannot demote owners", () => { + const result = validateUserTypeChange({ + requesting_account_id: "collab1", + requesting_user_group: "collaborator", + target_account_id: "owner1", + target_current_group: "owner", + target_new_group: "collaborator", + all_users: mockUsers, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.NOT_OWNER); + }); + + test("fails when target user not in project", () => { + const result = validateUserTypeChange({ + requesting_account_id: "owner1", + requesting_user_group: "owner", + target_account_id: "nonexistent", + target_current_group: "collaborator", + target_new_group: "owner", + all_users: mockUsers, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.INVALID_USER); + }); + + test("fails when requesting user is invalid", () => { + const result = validateUserTypeChange({ + requesting_account_id: "someone", + requesting_user_group: undefined, + target_account_id: "collab1", + target_current_group: "collaborator", + target_new_group: "owner", + all_users: mockUsers, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.INVALID_REQUESTING_USER); + }); + + test("fails when target has invalid group", () => { + const result = validateUserTypeChange({ + requesting_account_id: "owner1", + requesting_user_group: "owner", + target_account_id: "collab1", + target_current_group: undefined, + target_new_group: "owner", + all_users: mockUsers, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.INVALID_TARGET); + }); + + test("fails when new group is invalid", () => { + const result = validateUserTypeChange({ + requesting_account_id: "owner1", + requesting_user_group: "owner", + target_account_id: "collab1", + target_current_group: "collaborator", + target_new_group: "admin" as any, + all_users: mockUsers, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.INVALID_TARGET); + }); + + test("fails when all_users is null", () => { + const result = validateUserTypeChange({ + requesting_account_id: "owner1", + requesting_user_group: "owner", + target_account_id: "collab1", + target_current_group: "collaborator", + target_new_group: "owner", + all_users: null, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.INVALID_PROJECT_STATE); + }); + + test("fails when all_users is undefined", () => { + const result = validateUserTypeChange({ + requesting_account_id: "owner1", + requesting_user_group: "owner", + target_account_id: "collab1", + target_current_group: "collaborator", + target_new_group: "owner", + all_users: undefined, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.INVALID_PROJECT_STATE); + }); +}); + +describe("canManageCollaborators", () => { + test("owner can manage when setting disabled", () => { + const result = canManageCollaborators({ + user_group: "owner", + manage_users_owner_only: false, + }); + expect(result).toBe(true); + }); + + test("collaborator can manage when setting disabled", () => { + const result = canManageCollaborators({ + user_group: "collaborator", + manage_users_owner_only: false, + }); + expect(result).toBe(true); + }); + + test("owner can manage when setting enabled", () => { + const result = canManageCollaborators({ + user_group: "owner", + manage_users_owner_only: true, + }); + expect(result).toBe(true); + }); + + test("collaborator cannot manage when setting enabled", () => { + const result = canManageCollaborators({ + user_group: "collaborator", + manage_users_owner_only: true, + }); + expect(result).toBe(false); + }); + + test("invalid user cannot manage", () => { + const result = canManageCollaborators({ + user_group: undefined, + manage_users_owner_only: false, + }); + expect(result).toBe(false); + }); + + test("invalid user cannot manage when setting enabled", () => { + const result = canManageCollaborators({ + user_group: undefined, + manage_users_owner_only: true, + }); + expect(result).toBe(false); + }); +}); + +describe("validateRemoveCollaborator", () => { + test("owner can remove collaborator", () => { + const result = validateRemoveCollaborator({ + requesting_account_id: "owner1", + requesting_user_group: "owner", + target_account_id: "collab1", + target_user_group: "collaborator", + manage_users_owner_only: false, + }); + expect(result.valid).toBe(true); + }); + + test("owner can remove collaborator when setting enabled", () => { + const result = validateRemoveCollaborator({ + requesting_account_id: "owner1", + requesting_user_group: "owner", + target_account_id: "collab1", + target_user_group: "collaborator", + manage_users_owner_only: true, + }); + expect(result.valid).toBe(true); + }); + + test("collaborator can remove another collaborator when setting disabled", () => { + const result = validateRemoveCollaborator({ + requesting_account_id: "collab1", + requesting_user_group: "collaborator", + target_account_id: "collab2", + target_user_group: "collaborator", + manage_users_owner_only: false, + }); + expect(result.valid).toBe(true); + }); + + test("collaborator can remove self when setting enabled", () => { + const result = validateRemoveCollaborator({ + requesting_account_id: "collab1", + requesting_user_group: "collaborator", + target_account_id: "collab1", + target_user_group: "collaborator", + manage_users_owner_only: true, + }); + expect(result.valid).toBe(true); + }); + + test("collaborator can remove self when setting disabled", () => { + const result = validateRemoveCollaborator({ + requesting_account_id: "collab1", + requesting_user_group: "collaborator", + target_account_id: "collab1", + target_user_group: "collaborator", + manage_users_owner_only: false, + }); + expect(result.valid).toBe(true); + }); + + test("collaborator cannot remove another collaborator when setting enabled", () => { + const result = validateRemoveCollaborator({ + requesting_account_id: "collab1", + requesting_user_group: "collaborator", + target_account_id: "collab2", + target_user_group: "collaborator", + manage_users_owner_only: true, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.NOT_OWNER); + }); + + test("cannot remove owner directly", () => { + const result = validateRemoveCollaborator({ + requesting_account_id: "owner1", + requesting_user_group: "owner", + target_account_id: "owner2", + target_user_group: "owner", + manage_users_owner_only: false, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.CANNOT_REMOVE_OWNER); + }); + + test("owner cannot remove self (must demote first)", () => { + const result = validateRemoveCollaborator({ + requesting_account_id: "owner1", + requesting_user_group: "owner", + target_account_id: "owner1", + target_user_group: "owner", + manage_users_owner_only: false, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.CANNOT_REMOVE_OWNER); + }); + + test("collaborator cannot remove owner", () => { + const result = validateRemoveCollaborator({ + requesting_account_id: "collab1", + requesting_user_group: "collaborator", + target_account_id: "owner1", + target_user_group: "owner", + manage_users_owner_only: false, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.CANNOT_REMOVE_OWNER); + }); + + test("fails when requesting user is invalid", () => { + const result = validateRemoveCollaborator({ + requesting_account_id: "someone", + requesting_user_group: undefined, + target_account_id: "collab1", + target_user_group: "collaborator", + manage_users_owner_only: false, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.INVALID_REQUESTING_USER); + }); + + test("fails when target user not in project (undefined group)", () => { + const result = validateRemoveCollaborator({ + requesting_account_id: "owner1", + requesting_user_group: "owner", + target_account_id: "nonexistent", + target_user_group: undefined, + manage_users_owner_only: false, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.INVALID_TARGET); + }); + + test("fails when target has invalid group", () => { + const result = validateRemoveCollaborator({ + requesting_account_id: "owner1", + requesting_user_group: "owner", + target_account_id: "someone", + target_user_group: "admin" as any, + manage_users_owner_only: false, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.INVALID_TARGET); + }); +}); + +describe("validateAddCollaborator", () => { + test("owner can add when setting disabled", () => { + const result = validateAddCollaborator({ + user_group: "owner", + manage_users_owner_only: false, + }); + expect(result.valid).toBe(true); + }); + + test("collaborator can add when setting disabled", () => { + const result = validateAddCollaborator({ + user_group: "collaborator", + manage_users_owner_only: false, + }); + expect(result.valid).toBe(true); + }); + + test("owner can add when setting enabled", () => { + const result = validateAddCollaborator({ + user_group: "owner", + manage_users_owner_only: true, + }); + expect(result.valid).toBe(true); + }); + + test("collaborator cannot add when setting enabled", () => { + const result = validateAddCollaborator({ + user_group: "collaborator", + manage_users_owner_only: true, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.NOT_OWNER); + }); + + test("fails when user is invalid", () => { + const result = validateAddCollaborator({ + user_group: undefined, + manage_users_owner_only: false, + }); + expect(result.valid).toBe(false); + expect(result.errorCode).toBe(OwnershipErrorCode.INVALID_REQUESTING_USER); + }); +}); diff --git a/src/packages/util/project-ownership.ts b/src/packages/util/project-ownership.ts new file mode 100644 index 00000000000..3666aef6d5e --- /dev/null +++ b/src/packages/util/project-ownership.ts @@ -0,0 +1,354 @@ +/* + * This file is part of CoCalc: Copyright © 2025 Sagemath, Inc. + * License: MS-RSL – see LICENSE.md for details + */ + +/* +Project ownership transfer validation logic. + +This module provides shared validation functions used by both frontend (for UI) +and backend (for enforcement) to ensure consistent ownership transfer rules. +*/ + +export type UserGroup = "owner" | "collaborator"; + +/** + * Error codes for ownership validation failures. + * + * These codes are machine-friendly identifiers that can be mapped to + * user-friendly error messages in the frontend (see packages/frontend/i18n/common.ts). + * + * All error codes are tested in project-ownership.test.ts with comprehensive + * scenario coverage (see test file header for full scenario matrix). + */ +export enum OwnershipErrorCode { + LAST_OWNER = "LAST_OWNER", // Cannot demote the last owner + NOT_OWNER = "NOT_OWNER", // Only owners can perform this action + INVALID_TARGET = "INVALID_TARGET", // Target user is invalid or not in project + INVALID_USER = "INVALID_USER", // User not found in project + CANNOT_REMOVE_OWNER = "CANNOT_REMOVE_OWNER", // Cannot remove owners directly + INVALID_REQUESTING_USER = "INVALID_REQUESTING_USER", // Requesting user is not a valid member + INVALID_PROJECT_STATE = "INVALID_PROJECT_STATE", // Project data is missing or invalid +} + +export interface ValidationResult { + valid: boolean; + errorCode?: OwnershipErrorCode; + error?: string; +} + +/** + * Type guard to check if a value is a valid UserGroup. + * + * @param value - Value to check + * @returns true if value is "owner" or "collaborator" + */ +export function isUserGroup(value: any): value is UserGroup { + return value === "owner" || value === "collaborator"; +} + +/** + * Count the number of owners in a project. + * + * @param users - Map of account_id to user data with group field + * @returns Number of owners (users with group === "owner") + */ +export function countOwners( + users: { [account_id: string]: { group?: string } } | null | undefined, +): number { + if (!users) { + return 0; + } + let count = 0; + for (const account_id in users) { + if (users[account_id]?.group === "owner") { + count++; + } + } + return count; +} + +/** + * Check if a specific user is the last owner in a project. + * + * @param account_id - The account ID to check + * @param users - Map of all project users + * @returns true if the user is an owner AND is the only owner + */ +export function isLastOwner( + account_id: string, + users: { [account_id: string]: { group?: string } } | null | undefined, +): boolean { + if (!users) { + return false; + } + const userGroup = users[account_id]?.group; + if (userGroup !== "owner") { + return false; + } + return countOwners(users) === 1; +} + +/** + * Validate whether a user type change (promotion/demotion) is allowed. + * + * Validation rules: + * 1. all_users must be provided + * 2. Requesting user must be a valid owner or collaborator + * 3. Only owners can change user types + * 4. Target must be a current project member + * 5. Target must currently be owner or collaborator + * 6. Target new group must be valid (owner or collaborator) + * 7. Cannot demote the last owner (must maintain ≥1 owner) + * + * @param opts.requesting_account_id - Account ID of user making the request + * @param opts.requesting_user_group - Group of the user requesting the change (owner or collaborator) + * @param opts.target_account_id - Account ID of user being changed + * @param opts.target_current_group - Current group of target user + * @param opts.target_new_group - New group to assign to target + * @param opts.all_users - All users in the project + * @returns Validation result with valid flag and optional error details + */ +export function validateUserTypeChange(opts: { + requesting_account_id: string; + requesting_user_group: UserGroup | undefined; + target_account_id: string; + target_current_group: UserGroup | undefined; + target_new_group: UserGroup; + all_users: + | { [account_id: string]: { group?: UserGroup | string } } + | null + | undefined; +}): ValidationResult { + const { + requesting_user_group, + target_account_id, + target_current_group, + target_new_group, + all_users, + } = opts; + + // Rule 1: all_users must be provided (missing = invalid project state) + if (!all_users) { + return { + valid: false, + errorCode: OwnershipErrorCode.INVALID_PROJECT_STATE, + error: "Project users data is required", + }; + } + + // Rule 2: Requesting user must be a valid member (owner or collaborator) + if (!isUserGroup(requesting_user_group)) { + return { + valid: false, + errorCode: OwnershipErrorCode.INVALID_REQUESTING_USER, + error: "Requesting user is not a valid project member", + }; + } + + // Rule 3: Only owners can change user types + if (requesting_user_group !== "owner") { + return { + valid: false, + errorCode: OwnershipErrorCode.NOT_OWNER, + error: "Only project owners can change user types", + }; + } + + // Rule 4: Target must exist in project + if (!all_users[target_account_id]) { + return { + valid: false, + errorCode: OwnershipErrorCode.INVALID_USER, + error: "Target user is not a member of this project", + }; + } + + // Rule 5: Target must currently be owner or collaborator + if (!isUserGroup(target_current_group)) { + return { + valid: false, + errorCode: OwnershipErrorCode.INVALID_TARGET, + error: + "Target user does not have a valid group (must be owner or collaborator)", + }; + } + + // Rule 6: New group must be valid + if (!isUserGroup(target_new_group)) { + return { + valid: false, + errorCode: OwnershipErrorCode.INVALID_TARGET, + error: "New group must be either 'owner' or 'collaborator'", + }; + } + + // Rule 7: If demoting an owner, ensure at least one owner remains + if (target_current_group === "owner" && target_new_group === "collaborator") { + const ownerCount = countOwners(all_users); + if (ownerCount <= 1) { + return { + valid: false, + errorCode: OwnershipErrorCode.LAST_OWNER, + error: + "Cannot change the last owner to collaborator. At least one owner is required.", + }; + } + } + + // All validation passed + return { valid: true }; +} + +/** + * Check if a user can manage collaborators based on their role and project settings. + * + * @param opts.user_group - The user's group (owner or collaborator) + * @param opts.manage_users_owner_only - Project setting for restricting management (database field name) + * @returns true if user can manage collaborators + */ +export function canManageCollaborators(opts: { + user_group: UserGroup | undefined; + manage_users_owner_only: boolean; +}): boolean { + const { user_group, manage_users_owner_only } = opts; + + // User must be a valid member + if (!isUserGroup(user_group)) { + return false; + } + + // If setting is disabled, both owners and collaborators can manage + if (!manage_users_owner_only) { + return true; + } + + // If setting is enabled, only owners can manage + return user_group === "owner"; +} + +/** + * Validate whether removing a collaborator is allowed. + * + * IMPORTANT: Callers MUST provide target_user_group derived from actual project data + * (not from user input). Pass undefined if the target is not in the project. + * This ensures INVALID_TARGET is returned for users not in the project. + * + * Validation rules: + * 1. Requesting user must be a valid member + * 2. Target user must exist in project (undefined target_user_group = not in project) + * 3. Target user must have a valid group + * 4. Cannot remove owners directly (must demote to collaborator first) + * 5. Users can always remove themselves (except owners - they must demote first) + * 6. When onlyOwnersManageCollaborators is enabled, only owners can remove others + * + * @param opts.requesting_account_id - Account ID of user making the request + * @param opts.requesting_user_group - Group of user making the request + * @param opts.target_account_id - Account ID of user being removed + * @param opts.target_user_group - Group of user being removed (undefined if not in project) + * @param opts.manage_users_owner_only - Project setting (database field name) + * @returns Validation result + */ +export function validateRemoveCollaborator(opts: { + requesting_account_id: string; + requesting_user_group: UserGroup | undefined; + target_account_id: string; + target_user_group: UserGroup | undefined; + manage_users_owner_only: boolean; +}): ValidationResult { + const { + requesting_account_id, + requesting_user_group, + target_account_id, + target_user_group, + manage_users_owner_only, + } = opts; + + // Rule 1: Requesting user must be a valid member + if (!isUserGroup(requesting_user_group)) { + return { + valid: false, + errorCode: OwnershipErrorCode.INVALID_REQUESTING_USER, + error: "Requesting user is not a valid project member", + }; + } + + // Rule 2 & 3: Target user must exist and have a valid group + // undefined target_user_group means the target is not in the project + if (!target_user_group) { + return { + valid: false, + errorCode: OwnershipErrorCode.INVALID_TARGET, + error: "Target user is not a member of this project", + }; + } + + if (!isUserGroup(target_user_group)) { + return { + valid: false, + errorCode: OwnershipErrorCode.INVALID_TARGET, + error: "Target user does not have a valid group", + }; + } + + // Rule 4: Cannot remove owners directly (enforces two-step process) + if (target_user_group === "owner") { + return { + valid: false, + errorCode: OwnershipErrorCode.CANNOT_REMOVE_OWNER, + error: "Cannot remove an owner. Demote to collaborator first.", + }; + } + + // Rule 5: Self-removal is always allowed for collaborators + const is_self_remove = requesting_account_id === target_account_id; + if (is_self_remove) { + return { valid: true }; + } + + // Rule 6: Check manage_users_owner_only setting + if (manage_users_owner_only && requesting_user_group !== "owner") { + return { + valid: false, + errorCode: OwnershipErrorCode.NOT_OWNER, + error: + "Only owners can remove collaborators when this setting is enabled", + }; + } + + return { valid: true }; +} + +/** + * Validate whether adding a collaborator is allowed. + * + * @param opts.user_group - Group of user making the request + * @param opts.manage_users_owner_only - Project setting (database field name) + * @returns Validation result + */ +export function validateAddCollaborator(opts: { + user_group: UserGroup | undefined; + manage_users_owner_only: boolean; +}): ValidationResult { + const { user_group, manage_users_owner_only } = opts; + + // Requesting user must be a valid member + if (!isUserGroup(user_group)) { + return { + valid: false, + errorCode: OwnershipErrorCode.INVALID_REQUESTING_USER, + error: "Requesting user is not a valid project member", + }; + } + + // When setting is enabled, only owners can add + if (manage_users_owner_only && user_group !== "owner") { + return { + valid: false, + errorCode: OwnershipErrorCode.NOT_OWNER, + error: "Only owners can add collaborators when this setting is enabled", + }; + } + + return { valid: true }; +}