From 9874c2ea1eac9bc737698bf0654217d3f22ef215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20H=C3=BClscher?= <25116822+eweren@users.noreply.github.com> Date: Sat, 18 Oct 2025 14:26:02 +0200 Subject: [PATCH 01/17] fix darkmode colors for popovers --- src/ui/styles.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ui/styles.css b/src/ui/styles.css index 89ee17e..1c4a8e8 100644 --- a/src/ui/styles.css +++ b/src/ui/styles.css @@ -36,6 +36,7 @@ --figma-color-teal-bg: rgb(53, 196, 176, 0.16); --figma-color-red: rgb(255, 46, 83); --figma-color-red-bg: rgb(255, 46, 83, 0.16); + --figma-color-text-primary: #ffffff; } } From 559498cd3e406793825af8347c5449aecab43d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20H=C3=BClscher?= <25116822+eweren@users.noreply.github.com> Date: Sat, 18 Oct 2025 14:27:25 +0200 Subject: [PATCH 02/17] fix placeholder color --- src/ui/views/Settings/StringsEditor.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ui/views/Settings/StringsEditor.css b/src/ui/views/Settings/StringsEditor.css index dfd2b90..0298666 100644 --- a/src/ui/views/Settings/StringsEditor.css +++ b/src/ui/views/Settings/StringsEditor.css @@ -159,3 +159,8 @@ pointer-events: none; opacity: 0.5; } +@media (prefers-color-scheme: dark) { + .strings-editor .cm-placeholder { + color: var(--figma-color-text-primary) !important; + } +} \ No newline at end of file From e5b256c1fcacf6c9a12aaf4e4766b7967a1d40cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20H=C3=BClscher?= <25116822+eweren@users.noreply.github.com> Date: Sat, 18 Oct 2025 16:14:07 +0200 Subject: [PATCH 03/17] fix: add hidden layers option to include children --- src/main/utils/nodeTools.ts | 28 ++++++++++++++++++---- src/main/utils/settingsTools.ts | 2 ++ src/types.ts | 1 + src/ui/views/Push/Push.tsx | 5 ---- src/ui/views/Settings/StringsSection.tsx | 30 ++++++++++++++++++++++++ 5 files changed, 57 insertions(+), 9 deletions(-) diff --git a/src/main/utils/nodeTools.ts b/src/main/utils/nodeTools.ts index 8ab4f32..ac567b8 100644 --- a/src/main/utils/nodeTools.ts +++ b/src/main/utils/nodeTools.ts @@ -32,11 +32,31 @@ function shouldIncludeNode( return false; } if ( - (settings.ignoreHiddenLayers || - typeof settings.ignoreHiddenLayers === "undefined") && - !node.visible + settings.ignoreHiddenLayers || + typeof settings.ignoreHiddenLayers === "undefined" ) { - return false; + const isNodeVisible = !node.visible; + if (isNodeVisible && !settings.ignoreHiddenLayersIncludingChildren) { + return false; + } + if (settings.ignoreHiddenLayersIncludingChildren) { + let isParentHidden = false; + let parent = node.parent; + try { + while (parent) { + if (!(parent as SceneNode).visible) { + isParentHidden = true; + break; + } + parent = parent.parent; + } + if (isParentHidden) { + return false; + } + } catch (error) { + console.error("Error checking parent visibility:", error); + } + } } if ( settings.ignoreTextLayers && diff --git a/src/main/utils/settingsTools.ts b/src/main/utils/settingsTools.ts index 42c4102..3e64247 100644 --- a/src/main/utils/settingsTools.ts +++ b/src/main/utils/settingsTools.ts @@ -73,6 +73,7 @@ export const setPluginData = async (data: Partial) => { apiKey, apiUrl, ignoreHiddenLayers, + ignoreHiddenLayersIncludingChildren, ignoreNumbers, ignorePrefix, ignoreTextLayers, @@ -92,6 +93,7 @@ export const setPluginData = async (data: Partial) => { apiUrl, documentInfo: true, ignoreHiddenLayers, + ignoreHiddenLayersIncludingChildren, ignoreNumbers, ignorePrefix, ignoreTextLayers, diff --git a/src/types.ts b/src/types.ts index d607019..3b48f27 100644 --- a/src/types.ts +++ b/src/types.ts @@ -115,6 +115,7 @@ export type GlobalSettings = { */ keyFormat?: string; ignoreHiddenLayers?: boolean; + ignoreHiddenLayersIncludingChildren?: boolean; ignoreTextLayers?: boolean; variableCasing?: | "snake_case" diff --git a/src/ui/views/Push/Push.tsx b/src/ui/views/Push/Push.tsx index 61dca45..7e22fce 100644 --- a/src/ui/views/Push/Push.tsx +++ b/src/ui/views/Push/Push.tsx @@ -112,11 +112,6 @@ export const Push: FunctionalComponent = () => { method: "post", }); - const addNewTranslations = useApiMutation({ - url: "/v2/projects/keys/import", - method: "post", - }); - const addTagsToKeys = useApiMutation({ url: "/v2/projects/tag-complex", method: "put", diff --git a/src/ui/views/Settings/StringsSection.tsx b/src/ui/views/Settings/StringsSection.tsx index 288694e..417ec30 100644 --- a/src/ui/views/Settings/StringsSection.tsx +++ b/src/ui/views/Settings/StringsSection.tsx @@ -118,6 +118,11 @@ export const StringsSection: FunctionComponent = ({ const [ignoreHiddenLayers, setIgnoreHiddenLayers] = useState( tolgeeConfig.ignoreHiddenLayers ?? true ); + const [ + ignoreHiddenLayersIncludingChildren, + setIgnoreHiddenLayersIncludingChildren, + ] = useState(tolgeeConfig.ignoreHiddenLayersIncludingChildren ?? false); + const [ignoreTextLayers, setIgnoreTextLayers] = useState( tolgeeConfig.ignoreTextLayers ?? false ); @@ -177,6 +182,16 @@ export const StringsSection: FunctionComponent = ({ }); } + function handleIgnoreHiddenLayersIncludingChildrenChange( + event: TargetedEvent + ): void { + setIgnoreHiddenLayersIncludingChildren(event.currentTarget.checked); + setTolgeeConfig({ + ...tolgeeConfig, + ignoreHiddenLayersIncludingChildren: event.currentTarget.checked, + }); + } + function handleTextLayersChange( event: TargetedEvent ): void { @@ -282,6 +297,21 @@ export const StringsSection: FunctionComponent = ({ hidden layers + {ignoreHiddenLayers && ( + + +
+ + + including all child texts + + +
+
+ )}
Date: Sat, 18 Oct 2025 16:16:10 +0200 Subject: [PATCH 04/17] add better error message --- src/ui/views/Pull/Pull.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ui/views/Pull/Pull.tsx b/src/ui/views/Pull/Pull.tsx index 5375abc..35990f1 100644 --- a/src/ui/views/Pull/Pull.tsx +++ b/src/ui/views/Pull/Pull.tsx @@ -53,6 +53,10 @@ export const Pull: FunctionalComponent = ({ lang }) => { } catch (e) { if (e === "invalid_project_api_key") { setError("Invalid project API key"); + } else if (e === "too_many_uploaded_images") { + setError( + "Too many uploaded images. Disable update screenshots in settings." + ); } else { setError(`Cannot get translation data. ${e}`); } From 9acf8ea3f2d42886954ad63827d1b3097a168522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20H=C3=BClscher?= <25116822+eweren@users.noreply.github.com> Date: Tue, 21 Oct 2025 10:48:30 +0200 Subject: [PATCH 05/17] optimize error handling and text that are displayed --- src/ui/views/Push/Push.tsx | 96 ++++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 36 deletions(-) diff --git a/src/ui/views/Push/Push.tsx b/src/ui/views/Push/Push.tsx index 7e22fce..d113580 100644 --- a/src/ui/views/Push/Push.tsx +++ b/src/ui/views/Push/Push.tsx @@ -44,6 +44,7 @@ export const Push: FunctionalComponent = () => { const [changes, setChanges] = useState(); const selectedNodes = useConnectedNodes({ ignoreSelection: false }); const tolgeeConfig = useGlobalState((c) => c.config); + const [screenshotCount, setScreenshotCount] = useState(0); const nodes = selectedNodes.data?.items ?? []; @@ -226,7 +227,7 @@ export const Push: FunctionalComponent = () => { translations: { [language]: { text: item.newValue, - resolution: "OVERRIDE", + resolution: item.oldValue ? "OVERRIDE" : "NEW", }, }, }); @@ -251,44 +252,63 @@ export const Push: FunctionalComponent = () => { }, }); - // Add tags to keys - if ( - (tolgeeConfig?.addTags ?? false) && - tolgeeConfig?.tags && - tolgeeConfig.tags.length > 0 - ) { - await addTagsToKeys.mutateAsync({ - content: { - "application/json": { - tagFiltered: tolgeeConfig?.tags ?? [], - filterKeys: [ - ...changes.newKeys, - ...changes.unchangedKeys, - ...changes.changedKeys, - ].map((k) => ({ - name: k.key, - namespace: k.ns || undefined, - })), + try { + // Add tags to keys + if ( + (tolgeeConfig?.addTags ?? false) && + tolgeeConfig?.tags && + tolgeeConfig.tags.length > 0 + ) { + await addTagsToKeys.mutateAsync({ + content: { + "application/json": { + tagFiltered: tolgeeConfig?.tags ?? [], + filterKeys: [ + ...changes.newKeys, + ...changes.unchangedKeys, + ...changes.changedKeys, + ].map((k) => ({ + name: k.key, + namespace: k.ns || undefined, + })), + }, }, - }, - }); + }); + } + } catch (e) { + setErrorMessage( + `Error adding tags. ${e}. Translations were still updated.` + ); } if (tolgeeConfig?.updateScreenshots ?? true) { for (const screenshot of changes.screenshots.values()) { - const relatedKeys = screenshot.keys - .map((data) => ({ - keyName: data.key, - namespace: data.ns || undefined, - })) - .slice(0, 100); - await bigMeta.mutateAsync({ - content: { - "application/json": { - relatedKeysInOrder: relatedKeys, + try { + const relatedKeys = screenshot.keys + .map((data) => ({ + keyName: data.key, + namespace: data.ns || undefined, + })) + .slice(0, 100); + await bigMeta.mutateAsync({ + content: { + "application/json": { + relatedKeysInOrder: relatedKeys, + }, }, - }, - }); + }); + setScreenshotCount(screenshotCount + 1); + } catch (e) { + if (e === "too_many_uploaded_images") { + setErrorMessage( + "Too many uploaded images. Disable update screenshots in settings. Translations were still updated." + ); + } else { + setErrorMessage( + `Error updating screenshots. ${e}. Translations were still updated.` + ); + } + } } } @@ -298,8 +318,14 @@ export const Push: FunctionalComponent = () => { setError(true); if (e === "invalid_project_api_key") { setErrorMessage("Invalid project API key"); + } else if (e === "too_many_uploaded_images") { + setErrorMessage( + "Too many uploaded images. Disable update screenshots in settings." + ); + } else if (e === "import_keys_error") { + setErrorMessage("Error importing keys. Please try again."); } else { - setErrorMessage(`Cannot get translation data. ${e}`); + setErrorMessage(`Cannot push translations. ${e}`); } console.error(e); } finally { @@ -322,8 +348,6 @@ export const Push: FunctionalComponent = () => { ? changes.changedKeys.length + changes.newKeys.length : 0; - const screenshotCount = changes?.screenshots.length || 0; - const noChanges = changesSize === 0; return ( From 4c9e4351f600e82940e66f1d7dd9e30704c31af0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20H=C3=BClscher?= <25116822+eweren@users.noreply.github.com> Date: Tue, 21 Oct 2025 13:20:59 +0200 Subject: [PATCH 06/17] fix screenshot label issue --- src/ui/views/Push/Push.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/ui/views/Push/Push.tsx b/src/ui/views/Push/Push.tsx index d113580..43b701b 100644 --- a/src/ui/views/Push/Push.tsx +++ b/src/ui/views/Push/Push.tsx @@ -101,6 +101,10 @@ export const Push: FunctionalComponent = () => { computeDiff(); }, [nodes.length]); + const totalScreenshotCount = useMemo(() => { + return changes?.screenshots.length || 0; + }, [changes]); + const setNodesDataMutation = useSetNodesDataMutation(); const loadingStatus = @@ -392,7 +396,7 @@ export const Push: FunctionalComponent = () => { ) : ( - {screenshotCount !== 0 && ( + {totalScreenshotCount !== 0 && ( { setUploadScreenshots(Boolean(e.currentTarget.checked)) } > - Upload {screenshotCount} screenshot(s) + Upload {totalScreenshotCount} screenshot(s) @@ -416,7 +420,8 @@ export const Push: FunctionalComponent = () => { > Cancel - {noChanges && (screenshotCount === 0 || !uploadScreenshots) ? ( + {noChanges && + (totalScreenshotCount === 0 || !uploadScreenshots) ? (
From 66cc799a95183b1fbc080fe8ad493db6b4a385b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20H=C3=BClscher?= <25116822+eweren@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:16:29 +0100 Subject: [PATCH 08/17] add hidden layers tooltip --- .../ActionsBottom/ActionsBottom.css | 2 +- src/ui/components/InfoTooltip/InfoTooltip.css | 1 + src/ui/views/Settings/StringsSection.tsx | 47 ++++++++++++------- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/ui/components/ActionsBottom/ActionsBottom.css b/src/ui/components/ActionsBottom/ActionsBottom.css index c5e0f2e..21e477c 100644 --- a/src/ui/components/ActionsBottom/ActionsBottom.css +++ b/src/ui/components/ActionsBottom/ActionsBottom.css @@ -7,7 +7,7 @@ flex-direction: column; align-items: flex-end; background-color: var(--figma-color-bg); - z-index: 1; + z-index: 2; } .actions { diff --git a/src/ui/components/InfoTooltip/InfoTooltip.css b/src/ui/components/InfoTooltip/InfoTooltip.css index 28f8aa2..fed355b 100644 --- a/src/ui/components/InfoTooltip/InfoTooltip.css +++ b/src/ui/components/InfoTooltip/InfoTooltip.css @@ -3,5 +3,6 @@ align-items: center; justify-content: center; cursor: pointer; + z-index: 2; color: var(--figma-color-text-primary); } diff --git a/src/ui/views/Settings/StringsSection.tsx b/src/ui/views/Settings/StringsSection.tsx index 417ec30..d3d2448 100644 --- a/src/ui/views/Settings/StringsSection.tsx +++ b/src/ui/views/Settings/StringsSection.tsx @@ -79,6 +79,24 @@ const keyFormatHelpText = ( ); +const hiddenLayersHelpText = ( + +
+ Skips layers with visibility turned off in Figma. +
+
+ With "Including all child texts" enabled, +
+ all text layers inside hidden layers are +
+ also ignored, even if individually set to visible. +
+
+ Otherwise, only the hidden layer itself is ignored. +
+
+); + const formattingStyleHelpText = (
@@ -284,19 +302,18 @@ export const StringsSection: FunctionComponent = ({ Ignore strings - - numbers - + numbers - - - hidden layers - - + + + hidden layers + + {hiddenLayersHelpText} + {ignoreHiddenLayers && ( @@ -305,9 +322,7 @@ export const StringsSection: FunctionComponent = ({ value={ignoreHiddenLayersIncludingChildren} onChange={handleIgnoreHiddenLayersIncludingChildrenChange} > - - including all child texts - + including all child texts
@@ -319,9 +334,7 @@ export const StringsSection: FunctionComponent = ({ value={ignoreTextLayers} onChange={handleTextLayersChange} > - - text layers with prefix - + text layers with prefix Date: Mon, 27 Oct 2025 16:21:54 +0100 Subject: [PATCH 09/17] fix issue with hidden layers false negatives --- src/main/utils/nodeTools.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/utils/nodeTools.ts b/src/main/utils/nodeTools.ts index ac567b8..55122c9 100644 --- a/src/main/utils/nodeTools.ts +++ b/src/main/utils/nodeTools.ts @@ -32,11 +32,12 @@ function shouldIncludeNode( return false; } if ( - settings.ignoreHiddenLayers || - typeof settings.ignoreHiddenLayers === "undefined" + !node.visible && + (settings.ignoreHiddenLayers || + typeof settings.ignoreHiddenLayers === "undefined") ) { - const isNodeVisible = !node.visible; - if (isNodeVisible && !settings.ignoreHiddenLayersIncludingChildren) { + const nodeIsHidden = !node.visible; + if (nodeIsHidden && !settings.ignoreHiddenLayersIncludingChildren) { return false; } if (settings.ignoreHiddenLayersIncludingChildren) { From f95609e34323501bee2663b37d122e3fae2bf468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20H=C3=BClscher?= <25116822+eweren@users.noreply.github.com> Date: Wed, 29 Oct 2025 11:12:40 +0100 Subject: [PATCH 10/17] fix issues with hidden layers --- src/main/utils/nodeTools.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/utils/nodeTools.ts b/src/main/utils/nodeTools.ts index 55122c9..f8775b5 100644 --- a/src/main/utils/nodeTools.ts +++ b/src/main/utils/nodeTools.ts @@ -32,12 +32,10 @@ function shouldIncludeNode( return false; } if ( - !node.visible && - (settings.ignoreHiddenLayers || - typeof settings.ignoreHiddenLayers === "undefined") + settings.ignoreHiddenLayers || + typeof settings.ignoreHiddenLayers === "undefined" ) { - const nodeIsHidden = !node.visible; - if (nodeIsHidden && !settings.ignoreHiddenLayersIncludingChildren) { + if (!node.visible) { return false; } if (settings.ignoreHiddenLayersIncludingChildren) { @@ -45,7 +43,8 @@ function shouldIncludeNode( let parent = node.parent; try { while (parent) { - if (!(parent as SceneNode).visible) { + if ("visible" in parent && !(parent as SceneNode).visible) { + console.log(parent, "PARENT HIDDEN"); isParentHidden = true; break; } From d3f8c04204f97dd5ff17a27fcfeb041146f1c701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20H=C3=BClscher?= <25116822+eweren@users.noreply.github.com> Date: Wed, 17 Dec 2025 12:01:55 +0100 Subject: [PATCH 11/17] fix performance issues with namespaces optimize namespace selector optimize push behavior --- cypress/e2e/index.cy.ts | 14 +- cypress/e2e/push.cy.ts | 70 + package.json | 2 +- src/main/utils/nodeTools.ts | 1 - src/main/utils/settingsTools.ts | 2 - src/tools/getPushChanges.ts | 8 +- src/types.ts | 1 - src/ui/client/apiSchema.custom.ts | 68 + src/ui/client/apiSchema.generated.ts | 9556 +++++++++++------ src/ui/client/client.ts | 8 +- src/ui/client/useQueryApi.ts | 3 +- .../AutocompleteSelect/AutocompleteSelect.css | 61 + .../AutocompleteSelect.css.d.ts | 12 + .../AutocompleteSelect/AutocompleteSelect.tsx | 327 + .../NamespaceSelect/NamespaceSelect.css | 53 + .../NamespaceSelect/NamespaceSelect.css.d.ts | 6 + .../NamespaceSelect/NamespaceSelect.tsx | 152 +- src/ui/components/NodeList/NodeRow.css | 3 + src/ui/components/NodeList/NodeRow.tsx | 3 +- src/ui/hooks/useAllTranslations.ts | 9 + src/ui/hooks/useHasNamespacesEnabled.ts | 35 + src/ui/hooks/useSetNodesDataMutation.ts | 12 +- src/ui/icons/SvgIcons.tsx | 16 + src/ui/views/Index/Index.css | 6 - src/ui/views/Index/Index.css.d.ts | 1 - src/ui/views/Index/Index.tsx | 41 +- src/ui/views/Index/ListItem.tsx | 31 +- src/ui/views/Push/Push.tsx | 209 +- src/ui/views/Settings/ProjectSettings.tsx | 91 +- src/ui/views/Settings/PushSection.tsx | 234 +- src/ui/views/Settings/Settings.tsx | 3 +- 31 files changed, 7380 insertions(+), 3658 deletions(-) create mode 100644 src/ui/client/apiSchema.custom.ts create mode 100644 src/ui/components/AutocompleteSelect/AutocompleteSelect.css create mode 100644 src/ui/components/AutocompleteSelect/AutocompleteSelect.css.d.ts create mode 100644 src/ui/components/AutocompleteSelect/AutocompleteSelect.tsx create mode 100644 src/ui/hooks/useHasNamespacesEnabled.ts diff --git a/cypress/e2e/index.cy.ts b/cypress/e2e/index.cy.ts index d10631f..c0c896c 100644 --- a/cypress/e2e/index.cy.ts +++ b/cypress/e2e/index.cy.ts @@ -23,15 +23,16 @@ describe("Index", () => { .should("have.value", "test_key"); cy.iframe() - .findDcy("general_node_list_row_namespace") - .find("select") - .should("have.value", ""); + .findDcy("general_namespace_select_input") + .should(($input) => { + expect($input.val() || "").to.be.empty; + }); }); it("hides namespace selector", () => { const nodes = [createTestNode({ text: "Test node", key: "test_key" })]; visitWithState({ - config: { ...SIGNED_IN, namespacesDisabled: true }, + config: { ...SIGNED_IN }, selectedNodes: nodes, allNodes: nodes, }); @@ -48,10 +49,7 @@ describe("Index", () => { .find("input") .should("have.value", "test_key"); - cy.iframe() - .findDcy("general_node_list_row_namespace") - .find("select") - .should("not.exist"); + cy.iframe().findDcy("general_namespace_select_input").should("not.exist"); }); it("shows connected node correctly", () => { diff --git a/cypress/e2e/push.cy.ts b/cypress/e2e/push.cy.ts index 198f8b4..4f84d09 100644 --- a/cypress/e2e/push.cy.ts +++ b/cypress/e2e/push.cy.ts @@ -79,6 +79,76 @@ describe("Push", () => { cy.iframe().findDcy("push_ok_button").should("be.visible").click(); }); + it("shows correct key count in success message after pushing new keys", () => { + const nodes = [ + createTestNode({ text: "New key 1", key: "new_key_1" }), + createTestNode({ text: "New key 2", key: "new_key_2" }), + ]; + visitWithState({ + config: SIGNED_IN, + selectedNodes: nodes, + allNodes: nodes, + }); + + cy.frameLoaded("#plugin_iframe"); + + cy.iframe().contains("New key 1").should("exist"); + cy.iframe().findDcy("index_push_button").should("be.visible").click(); + + // Verify we see the new keys in the diff + cy.iframe().contains("New keys").should("exist"); + cy.iframe() + .findDcy("changes_new_keys") + .contains("new_key_1") + .should("be.visible"); + cy.iframe() + .findDcy("changes_new_keys") + .contains("new_key_2") + .should("be.visible"); + + // Push the changes + cy.iframe().findDcy("push_submit_button").should("be.visible").click(); + + // Verify success message shows correct count (2 keys) + cy.iframe().contains("Successfully updated 2 key(s)").should("be.visible"); + cy.iframe().findDcy("push_ok_button").should("be.visible").click(); + }); + + it("shows correct key count in success message after pushing changed keys", () => { + const nodes = [ + createTestNode({ text: "Changed text 1", key: "on-the-road-subtitle" }), + createTestNode({ text: "Changed text 2", key: "on-the-road-title" }), + ]; + visitWithState({ + config: SIGNED_IN, + selectedNodes: nodes, + allNodes: nodes, + }); + + cy.frameLoaded("#plugin_iframe"); + + cy.iframe().contains("Changed text 1").should("exist"); + cy.iframe().findDcy("index_push_button").should("be.visible").click(); + + // Verify we see the changed keys in the diff + cy.iframe().contains("Changed keys").should("exist"); + cy.iframe() + .findDcy("changes_changed_keys") + .contains("on-the-road-subtitle") + .should("be.visible"); + cy.iframe() + .findDcy("changes_changed_keys") + .contains("on-the-road-title") + .should("be.visible"); + + // Push the changes + cy.iframe().findDcy("push_submit_button").should("be.visible").click(); + + // Verify success message shows correct count (2 keys) + cy.iframe().contains("Successfully updated 2 key(s)").should("be.visible"); + cy.iframe().findDcy("push_ok_button").should("be.visible").click(); + }); + it("doesn't push screenshot when disabled", () => { const nodes = [ createTestNode({ text: "On the road", key: "on-the-road-title" }), diff --git a/package.json b/package.json index 896f55e..96c76ab 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "build": "build-figma-plugin --typecheck --minify", "watch": "build-figma-plugin --typecheck --watch", - "schema": "openapi-typescript http://localhost:8080/v3/api-docs/Accessible%20with%20API%20key --output ./src/client/apiSchema.generated.ts", + "schema": "openapi-typescript 'http://localhost:8085/v3/api-docs/Accessible with Project API key (All)' --output ./src/ui/client/apiSchema.generated.ts", "eslint": "eslint --ext .ts,.tsx,.js,.jsx src", "watch:web": "npm run --prefix web watch", "dev:web": "ts-node ./scripts/runAfterApp.ts \"npm run watch:web\"", diff --git a/src/main/utils/nodeTools.ts b/src/main/utils/nodeTools.ts index f8775b5..68f72bf 100644 --- a/src/main/utils/nodeTools.ts +++ b/src/main/utils/nodeTools.ts @@ -44,7 +44,6 @@ function shouldIncludeNode( try { while (parent) { if ("visible" in parent && !(parent as SceneNode).visible) { - console.log(parent, "PARENT HIDDEN"); isParentHidden = true; break; } diff --git a/src/main/utils/settingsTools.ts b/src/main/utils/settingsTools.ts index 3e64247..828ceb0 100644 --- a/src/main/utils/settingsTools.ts +++ b/src/main/utils/settingsTools.ts @@ -80,7 +80,6 @@ export const setPluginData = async (data: Partial) => { keyFormat, language, namespace, - namespacesDisabled, prefillKeyFormat, tags, updateScreenshots, @@ -99,7 +98,6 @@ export const setPluginData = async (data: Partial) => { ignoreTextLayers, keyFormat, namespace, - namespacesDisabled, prefillKeyFormat, tags, updateScreenshots, diff --git a/src/tools/getPushChanges.ts b/src/tools/getPushChanges.ts index a33a352..523b0ff 100644 --- a/src/tools/getPushChanges.ts +++ b/src/tools/getPushChanges.ts @@ -24,7 +24,7 @@ export type KeyChanges = { export const getPushChanges = ( nodes: NodeInfo[], translations: TranslationData, - language: string, + hasNamespacesEnabled: boolean, screenshots: FrameScreenshot[], tolgeeConfig: Partial | null ): KeyChanges => { @@ -37,7 +37,9 @@ export const getPushChanges = ( screenshots.forEach((screenshot) => { if ( screenshot.keys.find( - (node) => node.key === value.key && compareNs(node.ns, value.ns) + (node) => + node.key === value.key && + (!hasNamespacesEnabled || compareNs(node.ns, value.ns)) ) ) { result.push(screenshot); @@ -82,7 +84,7 @@ export const getPushChanges = ( const change: KeyChangeValue = { key: node.key, - ns: node.ns, + ns: hasNamespacesEnabled ? node.ns : undefined, oldValue: oldValue ? oldValue.translation : undefined, oldIsPlural: oldValue ? oldValue.keyIsPlural : undefined, isPlural: node.isPlural, diff --git a/src/types.ts b/src/types.ts index 3b48f27..f071ef2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -127,7 +127,6 @@ export type GlobalSettings = { export type CurrentDocumentSettings = GlobalSettings & { namespace: string; - namespacesDisabled: boolean; documentInfo: true; }; diff --git a/src/ui/client/apiSchema.custom.ts b/src/ui/client/apiSchema.custom.ts new file mode 100644 index 0000000..cce1b30 --- /dev/null +++ b/src/ui/client/apiSchema.custom.ts @@ -0,0 +1,68 @@ +import { components } from "./apiSchema.generated"; + +/** + * This file contains endpoints that are not generated by openapi-typescript but are still needed for the app. + */ +export interface customPaths { + "/v2/projects/{projectId}": { + /** + * Get project info + * @description Returns info about a project + */ + get: operations["get"]; + }; +} + +export interface operations { + /** + * Get project info + * @description Returns info about a project + */ + get: { + parameters: { + path: { + projectId: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["ProjectModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": + | components["schemas"]["ErrorResponseTyped"] + | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; +} diff --git a/src/ui/client/apiSchema.generated.ts b/src/ui/client/apiSchema.generated.ts index 87c3c8b..dd8bdcf 100644 --- a/src/ui/client/apiSchema.generated.ts +++ b/src/ui/client/apiSchema.generated.ts @@ -5,583 +5,801 @@ export interface paths { - "/v2/user": { + "/api/project/export/jsonZip": { /** - * Get user info - * @description Returns information about currently authenticated user. + * Export to ZIP of jsons + * @deprecated + * @description Exports data as ZIP of jsons */ - get: operations["getInfo_2"]; + get: operations["doExportJsonZip_1"]; }; - "/v2/projects/tasks/{taskNumber}/reopen": { - /** Reopen task */ - put: operations["reopenTask_1"]; + "/v2/api-keys/current": { + /** + * Get current API key info + * @description Returns info the API key which user currently authenticated with. Otherwise responds with 400 status code. + */ + get: operations["getCurrent_1"]; }; - "/v2/projects/tasks/{taskNumber}/keys/{keyId}": { + "/v2/api-keys/current-permissions": { /** - * Update task key - * @description Mark key as done, which updates task progress. + * Get current permission info + * @description Returns current PAK or PAT permissions for current user, api-key and project */ - put: operations["updateTaskKey_1"]; + get: operations["getCurrentPermissions"]; }; - "/v2/projects/tasks/{taskNumber}/keys": { - /** Get task keys */ - get: operations["getTaskKeys_1"]; - /** Add or remove task keys */ - put: operations["updateTaskKeys_1"]; + "/v2/auth-provider": { + /** Get current third party authentication provider */ + get: operations["getCurrentAuthProvider"]; + /** Initiate provider change to remove current third party authentication provider */ + delete: operations["deleteCurrentAuthProvider"]; }; - "/v2/projects/tasks/{taskNumber}/finish": { - /** Finish task */ - put: operations["finishTask_1"]; + "/v2/auth-provider/change": { + /** Get info about authentication provider which can replace the current one */ + get: operations["getChangedAuthProvider"]; + /** Accept change of the third party authentication provider */ + post: operations["acceptChangeAuthProvider"]; + /** Reject change of the third party authentication provider */ + delete: operations["rejectChangeAuthProvider"]; }; - "/v2/projects/tasks/{taskNumber}/close": { - /** Close task */ - put: operations["closeTask_1"]; + "/v2/image-upload": { + /** Upload an image for later use */ + post: operations["upload"]; }; - "/v2/projects/tasks/{taskNumber}": { - /** Get task */ - get: operations["getTask_1"]; - /** Update task */ - put: operations["updateTask_1"]; + "/v2/image-upload/{ids}": { + /** Delete uploaded images */ + delete: operations["delete_15"]; }; - "/v2/projects/namespaces/{id}": { - /** Update namespace */ - put: operations["update_2"]; + "/v2/notification": { + /** Gets notifications of the currently logged in user, newest is first. */ + get: operations["getNotifications"]; }; - "/v2/projects/keys/{id}/disabled-languages": { + "/v2/notification-settings": { /** - * Get disabled languages - * @description Returns languages, in which key is disabled + * Get notification settings + * @description Returns notification settings of the currently logged in user */ - get: operations["getDisabledLanguages_1"]; + get: operations["getNotificationsSettings"]; /** - * Set disabled languages - * @description Sets languages, in which key is disabled + * Save notification setting + * @description Saves new value for given parameters */ - put: operations["setDisabledLanguages_1"]; + put: operations["putNotificationSetting"]; }; - "/v2/projects/keys/{id}/complex-update": { + "/v2/notifications-mark-seen": { + /** Marks notifications of the currently logged in user with given IDs as seen. */ + put: operations["markNotificationsAsSeen"]; + }; + "/v2/organizations": { /** - * Edit key and related data - * @description Edits key name, translations, tags, screenshots, and other data + * Get all permitted organizations + * @description Returns all organizations, which is current user allowed to view */ - put: operations["complexEdit_1"]; + get: operations["getAll_10"]; + /** Create organization */ + post: operations["create_12"]; }; - "/v2/projects/keys/{id}": { - /** Get one key */ - get: operations["get_7"]; - /** Edit key name */ - put: operations["edit_1"]; + "/v2/organizations/{id}": { + /** Get one organization */ + get: operations["get_15"]; }; - "/v2/projects/tag-complex": { - /** Execute complex tag operation */ - put: operations["executeComplexTagOperation_1"]; + "/v2/organizations/{organizationId}/glossaries": { + /** Get all organization glossaries */ + get: operations["getAll_12"]; + /** Create glossary */ + post: operations["create_13"]; }; - "/v2/projects/keys/{keyId}/tags": { + "/v2/organizations/{organizationId}/glossaries-with-stats": { + /** Get all organization glossaries with some additional statistics */ + get: operations["getAllWithStats"]; + }; + "/v2/organizations/{organizationId}/glossaries/{glossaryId}": { + /** Get glossary */ + get: operations["get_13"]; + /** Update glossary */ + put: operations["update_8"]; + /** Delete glossary */ + delete: operations["delete_7"]; + }; + "/v2/organizations/{organizationId}/glossaries/{glossaryId}/assigned-projects": { + /** Get all projects assigned to glossary */ + get: operations["getAssignedProjects"]; + }; + "/v2/organizations/{organizationId}/glossaries/{glossaryId}/export": { + /** Export glossary terms as CSV */ + get: operations["export"]; + }; + "/v2/organizations/{organizationId}/glossaries/{glossaryId}/import": { + /** Import glossary terms from CSV */ + post: operations["importCsv"]; + }; + "/v2/organizations/{organizationId}/glossaries/{glossaryId}/languages": { + /** Get all languages in use by the glossary */ + get: operations["getLanguages"]; + }; + "/v2/organizations/{organizationId}/glossaries/{glossaryId}/terms": { + /** Get all glossary terms */ + get: operations["getAll_13"]; + /** Create a new glossary term */ + post: operations["create_14"]; + /** Batch delete multiple terms */ + delete: operations["deleteMultiple"]; + }; + "/v2/organizations/{organizationId}/glossaries/{glossaryId}/terms/{termId}": { + /** Get glossary term */ + get: operations["get_14"]; + /** Update glossary term */ + put: operations["update_9"]; + /** Delete glossary term */ + delete: operations["delete_8"]; + }; + "/v2/organizations/{organizationId}/glossaries/{glossaryId}/terms/{termId}/translations": { + /** Set a new glossary term translation for language */ + post: operations["update_12"]; + }; + "/v2/organizations/{organizationId}/glossaries/{glossaryId}/terms/{termId}/translations/{languageTag}": { + /** Get glossary term translation for language */ + get: operations["get_23"]; + }; + "/v2/organizations/{organizationId}/glossaries/{glossaryId}/termsIds": { + /** Get all glossary terms ids */ + get: operations["getAllIds"]; + }; + "/v2/organizations/{organizationId}/glossaries/{glossaryId}/termsWithTranslations": { + /** Get all glossary terms with translations */ + get: operations["getAllWithTranslations"]; + }; + "/v2/organizations/{organizationId}/machine-translation-credit-balance": { /** - * Tag key - * @description Tags a key with tag. If tag with provided name doesn't exist, it is created + * Get credit balance for organization + * @description Returns machine translation credit balance for organization */ - put: operations["tagKey_1"]; + get: operations["getOrganizationCredits"]; }; - "/v2/projects/import/result/languages/{languageId}/translations/{translationId}/resolve/set-override": { + "/v2/organizations/{slug}": { + /** Get organization by slug */ + get: operations["get_22"]; + }; + "/v2/pats/current": { /** - * Resolve conflict (override) - * @description Resolves translation conflict. The old translation will be overridden. + * Return current PAK + * @description Returns current Personal Access Token. If the request is not authenticated with a Personal Access Token, it will return 400 response status. */ - put: operations["resolveTranslationSetOverride_1"]; + get: operations["getCurrent"]; }; - "/v2/projects/import/result/languages/{languageId}/translations/{translationId}/resolve/set-keep-existing": { + "/v2/projects": { /** - * Resolve conflict (keep existing) - * @description Resolves translation conflict. The old translation will be kept. + * Get all permitted + * @description Returns all projects where current user has any permission */ - put: operations["resolveTranslationSetKeepExisting_1"]; - }; - "/v2/projects/import/result/languages/{languageId}/resolve-all/set-override": { + get: operations["getAll"]; /** - * Resolve all translation conflicts (override) - * @description Resolves all translation conflicts for provided language. The old translations will be overridden. + * Create project + * @description Creates a new project with languages and initial settings. */ - put: operations["resolveTranslationSetOverride_3"]; + post: operations["createProject"]; }; - "/v2/projects/import/result/languages/{languageId}/resolve-all/set-keep-existing": { + "/v2/projects/activity": { + /** Get project activity */ + get: operations["getActivity_1"]; + }; + "/v2/projects/activity/revisions/{revisionId}": { + /** Get one revision data */ + get: operations["getSingleRevision_1"]; + }; + "/v2/projects/batch-jobs": { + /** List batch operations */ + get: operations["list_4"]; + }; + "/v2/projects/batch-jobs/{id}": { + /** Get batch operation */ + get: operations["get_21"]; + }; + "/v2/projects/batch-jobs/{id}/cancel": { /** - * Resolve all translation conflicts (keep existing) - * @description Resolves all translation conflicts for provided language. The old translations will be kept. + * Stop batch operation + * @description Stops batch operation if possible. */ - put: operations["resolveTranslationSetKeepExisting_3"]; + put: operations["cancel_1"]; }; - "/v2/projects/import/result/languages/{importLanguageId}/select-existing/{existingLanguageId}": { + "/v2/projects/big-meta": { /** - * Pair existing language - * @description Sets existing language to pair with language to import. Data will be imported to selected existing language when applied. + * Store Big Meta + * @description Stores a bigMeta for a project */ - put: operations["selectExistingLanguage_1"]; + post: operations["store_3"]; }; - "/v2/projects/import/result/languages/{importLanguageId}/reset-existing": { + "/v2/projects/current-batch-jobs": { /** - * Reset existing language pairing - * @description Resets existing language paired with language to import. + * Get all running and pending batch operations + * @description Returns all running and pending batch operations. Completed batch operations are returned only if they are not older than 1 hour. If user doesn't have permission to view all batch operations, only their operations are returned. */ - put: operations["resetExistingLanguage_1"]; + get: operations["currentJobs_1"]; }; - "/v2/projects/import/result/files/{fileId}/select-namespace": { + "/v2/projects/export": { /** - * Select namespace - * @description Sets namespace for file to import. + * Export data + * @description + * Exports project data in various formats (JSON, properties, YAML, etc.). + * + * ## HTTP Conditional Requests Support + * + * This endpoint supports HTTP conditional requests using both If-Modified-Since and If-None-Match headers: + * + * - **If-Modified-Since header provided**: The server checks if the project data has been modified since the specified date + * - **If-None-Match header provided**: The server checks if the project data has changed by comparing the eTag value + * - **Data not modified**: Returns HTTP 304 Not Modified with empty body + * - **Data modified or no header**: Returns HTTP 200 OK with the exported data, Last-Modified header, and ETag header + * + * The Last-Modified header in the response contains the timestamp of the last project modification, + * and the ETag header contains a unique identifier for the current project state. Both can be used + * for subsequent conditional requests to avoid unnecessary data transfer when the project hasn't changed. + * + * Cache-Control header is set to max-age=0 to ensure validation on each request. */ - put: operations["selectNamespace_1"]; - }; - "/v2/projects/import/apply-streaming": { + get: operations["exportData_1"]; /** - * Apply import (streaming) - * @description Imports the data prepared in previous step. Streams current status. + * Export data (post) + * @description + * Exports project data in various formats (JSON, properties, YAML, etc.). + * Useful when exceeding allowed URL size with GET requests. + * + * ## HTTP Conditional Requests Support + * + * This endpoint supports HTTP conditional requests using both If-Modified-Since and If-None-Match headers: + * + * - **If-Modified-Since header provided**: The server checks if the project data has been modified since the specified date + * - **If-None-Match header provided**: The server checks if the project data has changed by comparing the eTag value + * - **Data not modified**: Returns HTTP 304 Not Modified with empty body + * - **Data modified or no header**: Returns HTTP 200 OK with the exported data, Last-Modified header, and ETag header + * + * Note: This endpoint uses a custom implementation that returns 304 Not Modified for all HTTP methods + * (including POST) when conditional headers indicate the data hasn't changed. This differs from Spring's + * default behavior which returns 412 for POST requests, but is appropriate here since POST is used only + * to accommodate large request parameters, not to modify data. + * + * The Last-Modified header in the response contains the timestamp of the last project modification, + * and the ETag header contains a unique identifier for the current project state. Both can be used + * for subsequent conditional requests to avoid unnecessary data transfer when the project hasn't changed. + * + * Cache-Control header is set to max-age=0 to ensure validation on each request. */ - put: operations["applyImportStreaming_1"]; + post: operations["exportPost_1"]; }; - "/v2/projects/import/apply": { + "/v2/projects/import": { /** - * Apply import - * @description Imports the data prepared in previous step + * Add files + * @description Prepares provided files to import. */ - put: operations["applyImport_1"]; + post: operations["addFiles_1"]; + /** + * Delete + * @description Deletes prepared import data. + */ + delete: operations["cancelImport_1"]; }; "/v2/projects/import-settings": { /** * Get Import Settings * @description Returns import settings for the authenticated user and the project. */ - get: operations["get_11"]; + get: operations["get_1"]; /** * Set Import Settings * @description Stores import settings for the authenticated user and the project. */ put: operations["store_1"]; }; - "/v2/projects/batch-jobs/{id}/cancel": { + "/v2/projects/import/all-namespaces": { /** - * Stop batch operation - * @description Stops batch operation if possible. + * Get namespaces + * @description Returns all existing and imported namespaces */ - put: operations["cancel_1"]; - }; - "/v2/projects/translations/{translationId}/set-state/{state}": { - /** Set translation state */ - put: operations["setTranslationState_1"]; - }; - "/v2/projects/translations/{translationId}/comments/{commentId}/set-state/{state}": { - /** Set state of translation comment */ - put: operations["setState_1"]; - }; - "/v2/projects/translations/{translationId}/comments/{commentId}": { - /** Get one translation comment */ - get: operations["get_15"]; - /** Update translation comment */ - put: operations["update_6"]; - /** Delete translation comment */ - delete: operations["delete_9"]; + get: operations["getAllNamespaces_1"]; }; - "/v2/projects/translations/{translationId}/set-outdated-flag/{state}": { + "/v2/projects/import/apply": { /** - * Set outdated value - * @description Set's "outdated" flag indicating the base translation was changed without updating current translation. + * Apply import + * @description Imports the data prepared in previous step */ - put: operations["setOutdated_1"]; + put: operations["applyImport_1"]; }; - "/v2/projects/translations/{translationId}/dismiss-auto-translated-state": { + "/v2/projects/import/apply-streaming": { /** - * Dismiss auto-translated - * @description Removes "auto translated" indication + * Apply import (streaming) + * @description Imports the data prepared in previous step. Streams current status. */ - put: operations["dismissAutoTranslatedState_1"]; + put: operations["applyImportStreaming_1"]; }; - "/v2/projects/translations": { - /** Get translations in project */ - get: operations["getTranslations_1"]; + "/v2/projects/import/result": { /** - * Update translations for existing key - * @description Sets translations for existing key + * Get result + * @description Returns the result of preparation. */ - put: operations["setTranslations_1"]; + get: operations["getImportResult_1"]; + }; + "/v2/projects/import/result/files/{fileId}/select-namespace": { /** - * Create key or update translations - * @description Sets translations for existing key or creates new key and sets the translations to it. + * Select namespace + * @description Sets namespace for file to import. */ - post: operations["createOrUpdateTranslations_1"]; + put: operations["selectNamespace_1"]; }; - "/v2/projects/languages/{languageId}": { - /** Get one language */ - get: operations["get_17"]; - /** Update language */ - put: operations["editLanguage_1"]; - /** Delete specific language */ - delete: operations["deleteLanguage_3"]; + "/v2/projects/import/result/files/{importFileId}/issues": { + /** + * Get file issues + * @description Returns issues for uploaded file. + */ + get: operations["getImportFileIssues_1"]; }; - "/v2/projects/keys/{keyId}/auto-translate": { + "/v2/projects/import/result/languages/{importLanguageId}/reset-existing": { /** - * Auto translates keys - * @description Uses enabled auto-translation methods. - * You need to set at least one of useMachineTranslation or useTranslationMemory to true. - * - * This will replace the the existing translation with the result obtained from specified source! + * Reset existing language pairing + * @description Resets existing language paired with language to import. */ - put: operations["autoTranslate_1"]; + put: operations["resetExistingLanguage_1"]; }; - "/v2/organizations/{id}": { - /** Get one organization */ - get: operations["get_20"]; + "/v2/projects/import/result/languages/{importLanguageId}/select-existing/{existingLanguageId}": { + /** + * Pair existing language + * @description Sets existing language to pair with language to import. Data will be imported to selected existing language when applied. + */ + put: operations["selectExistingLanguage_1"]; }; - "/v2/projects": { + "/v2/projects/import/result/languages/{languageId}": { /** - * Get all permitted - * @description Returns all projects where current user has any permission + * Get import language + * @description Returns language prepared to import. */ - get: operations["getAll"]; + get: operations["getImportLanguage_1"]; /** - * Create project - * @description Creates a new project with languages and initial settings. + * Delete language + * @description Deletes language prepared to import. */ - post: operations["createProject"]; - }; - "/v2/projects/tasks/create-multiple-tasks": { - /** Create multiple tasks */ - post: operations["createTasks_1"]; - }; - "/v2/projects/tasks/calculate-scope": { - /** Calculate scope */ - post: operations["calculateScope_1"]; + delete: operations["deleteLanguage_3"]; }; - "/v2/projects/tasks": { - /** Get tasks */ - get: operations["getTasks_2"]; - /** Create task */ - post: operations["createTask_1"]; + "/v2/projects/import/result/languages/{languageId}/resolve-all/set-keep-existing": { + /** + * Resolve all translation conflicts (keep existing) + * @description Resolves all translation conflicts for provided language. The old translations will be kept. + */ + put: operations["resolveTranslationSetKeepExisting_3"]; }; - "/v2/projects/keys/info": { + "/v2/projects/import/result/languages/{languageId}/resolve-all/set-override": { /** - * Get key info - * @description Returns information about keys. (KeyData, Screenshots, Translation in specified language)If key is not found, it's not included in the response. + * Resolve all translation conflicts (override) + * @description Resolves all translation conflicts for provided language. The old translations will be overridden. */ - post: operations["getInfo_1"]; + put: operations["resolveTranslationSetOverride_3"]; }; - "/v2/projects/keys/import-resolvable": { + "/v2/projects/import/result/languages/{languageId}/translations": { /** - * Import keys (resolvable) - * @description Import's new keys with translations. Translations can be updated, when specified. + * Get translations + * @description Returns translations prepared to import. */ - post: operations["importKeys_1"]; + get: operations["getImportTranslations_1"]; }; - "/v2/projects/keys/import": { + "/v2/projects/import/result/languages/{languageId}/translations/{translationId}/resolve/set-keep-existing": { /** - * Import keys - * @description Imports new keys with translations. If key already exists, its translations and tags are not updated. + * Resolve conflict (keep existing) + * @description Resolves translation conflict. The old translation will be kept. */ - post: operations["importKeys_3"]; + put: operations["resolveTranslationSetKeepExisting_1"]; }; - "/v2/projects/keys/create": { - /** Create new key */ - post: operations["create_3"]; + "/v2/projects/import/result/languages/{languageId}/translations/{translationId}/resolve/set-override": { + /** + * Resolve conflict (override) + * @description Resolves translation conflict. The old translation will be overridden. + */ + put: operations["resolveTranslationSetOverride_1"]; }; "/v2/projects/keys": { /** Get all keys */ - get: operations["getAll_2"]; + get: operations["getAll_8"]; /** Create new key */ - post: operations["create_4"]; + post: operations["create_8"]; /** * Delete one or multiple keys (post) * @description Delete one or multiple keys by their IDs in request body. Useful for larger requests esxceeding allowed URL length. */ - delete: operations["delete_5"]; - }; - "/v2/projects/start-batch-job/untag-keys": { - /** Remove tags */ - post: operations["untagKeys_1"]; - }; - "/v2/projects/start-batch-job/tag-keys": { - /** Add tags */ - post: operations["tagKeys_1"]; - }; - "/v2/projects/start-batch-job/set-translation-state": { - /** Set translation state */ - post: operations["setTranslationState_3"]; + delete: operations["delete_12"]; }; - "/v2/projects/start-batch-job/set-keys-namespace": { - /** Set keys namespace */ - post: operations["setKeysNamespace_1"]; + "/v2/projects/keys/create": { + /** Create new key */ + post: operations["create_7"]; }; - "/v2/projects/start-batch-job/pre-translate-by-tm": { + "/v2/projects/keys/import": { /** - * Pre-translate by TM - * @description Pre-translate provided keys to provided languages by TM. + * Import keys + * @description Imports new keys with translations. If key already exists, its translations and tags are not updated. */ - post: operations["translate_1"]; + post: operations["importKeys_3"]; }; - "/v2/projects/start-batch-job/machine-translate": { + "/v2/projects/keys/import-resolvable": { /** - * Machine Translation - * @description Translate provided keys to provided languages through primary MT provider. + * Import keys (resolvable) + * @deprecated + * @description + * Import's new keys with translations. Translations can be updated, when specified.\n\n + * DEPRECATED: Use /v2/projects/{projectId}/single-step-import-resolvable instead. */ - post: operations["machineTranslation_1"]; - }; - "/v2/projects/start-batch-job/delete-keys": { - /** Delete keys */ - post: operations["deleteKeys_1"]; + post: operations["importKeys_1"]; }; - "/v2/projects/start-batch-job/copy-translations": { + "/v2/projects/keys/info": { /** - * Copy translation values - * @description Copy translation values from one language to other languages. + * Get key info + * @description Returns information about keys. (KeyData, Screenshots, Translation in specified language)If key is not found, it's not included in the response. */ - post: operations["copyTranslations_1"]; + post: operations["getInfo_2"]; }; - "/v2/projects/start-batch-job/clear-translations": { + "/v2/projects/keys/search": { /** - * Clear translation values - * @description Clear translation values for provided keys in selected languages. + * Search for keys + * @description This endpoint helps you to find desired key by keyName, base translation or translation in specified language. + * + * Sort is ignored for this request. */ - post: operations["clearTranslations_1"]; + get: operations["searchForKey_1"]; }; - "/v2/projects/single-step-import": { + "/v2/projects/keys/select": { /** - * Single step import - * @description Unlike the /v2/projects/{projectId}/import endpoint, imports the data in single request by provided files and parameters. This is useful for automated importing via API or CLI. + * Select keys + * @description Returns all key IDs for specified filter values. This way, you can apply the same filter as in the translation view and get the resulting key IDs for future use. */ - post: operations["doImport_1"]; + get: operations["selectKeys_3"]; }; - "/v2/projects/import": { - /** - * Add files - * @description Prepares provided files to import. - */ - post: operations["addFiles_1"]; - /** - * Delete - * @description Deletes prepared import data. - */ - delete: operations["cancelImport_1"]; + "/v2/projects/keys/{ids}": { + /** Delete one or multiple keys */ + delete: operations["delete_14"]; }; - "/v2/projects/export": { - /** Export data */ - get: operations["export_1"]; - /** - * Export data (post) - * @description Exports data (post). Useful when exceeding allowed URL size. - */ - post: operations["exportPost_1"]; + "/v2/projects/keys/{id}": { + /** Get one key */ + get: operations["get_9"]; + /** Edit key name */ + put: operations["edit_1"]; }; - "/v2/projects/big-meta": { + "/v2/projects/keys/{id}/big-meta": { + /** Get Big Meta for key */ + get: operations["getBigMeta_1"]; + }; + "/v2/projects/keys/{id}/complex-update": { /** - * Store Big Meta - * @description Stores a bigMeta for a project + * Edit key and related data + * @description Edits key name, translations, tags, screenshots, and other data */ - post: operations["store_3"]; + put: operations["complexEdit_1"]; }; - "/v2/projects/translations/{translationId}/comments": { + "/v2/projects/keys/{id}/disabled-languages": { /** - * Get translation comments - * @description Returns translation comments of translation + * Get disabled languages + * @description Returns languages, in which key is disabled */ - get: operations["getAll_6"]; - /** Create translation comment */ - post: operations["create_8"]; - }; - "/v2/projects/translations/create-comment": { + get: operations["getDisabledLanguages_1"]; /** - * Create translation comment - * @description Creates a translation comment. Empty translation is stored, when not exists. + * Set disabled languages + * @description Sets languages, in which key is disabled */ - post: operations["create_10"]; + put: operations["setDisabledLanguages_1"]; }; - "/v2/projects/suggest/translation-memory": { + "/v2/projects/keys/{keyId}/auto-translate": { /** - * Get suggestions from translation memory - * @description Suggests machine translations from translation memory. The result is always sorted by similarity, so sorting is not supported. + * Auto translates keys + * @description Uses enabled auto-translation methods. + * You need to set at least one of useMachineTranslation or useTranslationMemory to true. + * + * This will replace the the existing translation with the result obtained from specified source! */ - post: operations["suggestTranslationMemory_1"]; + put: operations["autoTranslate_1"]; }; - "/v2/projects/suggest/machine-translations-streaming": { + "/v2/projects/keys/{keyId}/screenshots": { + /** Get screenshots */ + get: operations["getKeyScreenshots"]; + /** Upload screenshot */ + post: operations["uploadScreenshot"]; + }; + "/v2/projects/keys/{keyId}/screenshots/{ids}": { + /** Delete screenshots */ + delete: operations["deleteScreenshots"]; + }; + "/v2/projects/keys/{keyId}/tags": { /** - * Get machine translation suggestions (streaming) - * @description Suggests machine translations from enabled services. The results are streamed to the output in ndjson format. If an error occurs when for any service provider used, the error information is returned as a part of the result item, while the response has 200 status code. + * Tag key + * @description Tags a key with tag. If tag with provided name doesn't exist, it is created */ - post: operations["suggestMachineTranslationsStreaming_1"]; + put: operations["tagKey_1"]; }; - "/v2/projects/suggest/machine-translations": { + "/v2/projects/keys/{keyId}/tags/{tagId}": { /** - * Get machine translation suggestions - * @description Suggests machine translations from enabled services + * Remove tag + * @description Removes tag with provided id from key with provided id */ - post: operations["suggestMachineTranslations_1"]; + delete: operations["removeTag_1"]; + }; + "/v2/projects/labels": { + /** Get available project labels */ + get: operations["getAll_2"]; + /** Create label */ + post: operations["createLabel_1"]; + }; + "/v2/projects/labels/ids": { + /** Get labels by ids */ + get: operations["getLabelsByIds_1"]; + }; + "/v2/projects/labels/{labelId}": { + /** Update label */ + put: operations["updateLabel_1"]; + /** Delete label */ + delete: operations["deleteLabel_1"]; }; "/v2/projects/languages": { /** Get all languages */ - get: operations["getAll_8"]; + get: operations["getAll_6"]; /** Create language */ post: operations["createLanguage_1"]; }; - "/v2/projects/keys/{keyId}/screenshots": { - /** Get screenshots */ - get: operations["getKeyScreenshots"]; - /** Upload screenshot */ - post: operations["uploadScreenshot"]; + "/v2/projects/languages/{languageId}": { + /** Get one language */ + get: operations["get_7"]; + /** Update language */ + put: operations["editLanguage_1"]; + /** Delete specific language */ + delete: operations["deleteLanguage_1"]; }; - "/v2/organizations": { + "/v2/projects/languages/{languageId}/key/{keyId}/suggestion": { + /** Get suggestions */ + get: operations["getSuggestions_1"]; + /** Create translation suggestion */ + post: operations["createSuggestion_1"]; + }; + "/v2/projects/languages/{languageId}/key/{keyId}/suggestion/{suggestionId}": { /** - * Get all permitted organizations - * @description Returns all organizations, which is current user allowed to view + * Delete suggestion + * @description User can only delete suggestion created by them */ - get: operations["getAll_10"]; - /** Create organization */ - post: operations["create_12"]; + delete: operations["deleteSuggestion_1"]; }; - "/v2/image-upload": { - /** Upload an image for later use */ - post: operations["upload"]; + "/v2/projects/languages/{languageId}/key/{keyId}/suggestion/{suggestionId}/accept": { + /** Accept suggestion */ + put: operations["acceptSuggestion_1"]; }; - "/v2/user-tasks": { - /** Get user tasks */ - get: operations["getTasks"]; + "/v2/projects/languages/{languageId}/key/{keyId}/suggestion/{suggestionId}/decline": { + /** Decline suggestion */ + put: operations["declineSuggestion_1"]; }; - "/v2/projects/used-namespaces": { + "/v2/projects/languages/{languageId}/key/{keyId}/suggestion/{suggestionId}/set-active": { + /** Set suggestion active */ + put: operations["suggestionSetActive_1"]; + }; + "/v2/projects/my-batch-jobs": { /** - * Get used namespaces - * @description Returns all used project namespaces. Response contains default (null) namespace if used. + * List user batch operations + * @description List all batch operations started by current user */ - get: operations["getUsedNamespaces_1"]; + get: operations["myList_1"]; }; - "/v2/projects/tasks/{taskNumber}/xlsx-report": { + "/v2/projects/namespace-by-name/{name}": { /** - * Get report in XLSX - * @description Detailed statistics about the task results + * Get namespace by name + * @description Returns information about a namespace by its name */ - get: operations["getXlsxReport_1"]; + get: operations["getByName_1"]; }; - "/v2/projects/tasks/{taskNumber}/per-user-report": { + "/v2/projects/namespaces": { + /** Get namespaces */ + get: operations["getAllNamespaces_3"]; + }; + "/v2/projects/namespaces/{id}": { + /** Update namespace */ + put: operations["update_4"]; + }; + "/v2/projects/single-step-import": { /** - * Get report - * @description Detailed statistics for every assignee + * Single step import + * @description Unlike the /v2/projects/{projectId}/import endpoint, imports the data in single request by provided files and parameters. This is useful for automated importing via API or CLI. */ - get: operations["getPerUserReport_1"]; + post: operations["singleStepFromFiles_1"]; }; - "/v2/projects/tasks/{taskNumber}/blocking-tasks": { + "/v2/projects/single-step-import-resolvable": { + /** Single step import from body */ + post: operations["singleStepResolvableImport_1"]; + }; + "/v2/projects/start-batch-job/ai-playground-translate": { + /** Translates via llm and stores result in AiPlaygroundResult */ + post: operations["aiPlaygroundTranslate_1"]; + }; + "/v2/projects/start-batch-job/assign-translation-label": { + /** Assign labels to translations */ + post: operations["assignTranslationLabel_1"]; + }; + "/v2/projects/start-batch-job/clear-translations": { /** - * Get blocking task numbers - * @description If the tasks is blocked by other tasks, it returns numbers of these tasks. + * Clear translation values + * @description Clear translation values for provided keys in selected languages. */ - get: operations["getBlockingTasks_1"]; + post: operations["clearTranslations_1"]; }; - "/v2/projects/tasks/possible-assignees": { - get: operations["getPossibleAssignees_1"]; + "/v2/projects/start-batch-job/copy-translations": { + /** + * Copy translation values + * @description Copy translation values from one language to other languages. + */ + post: operations["copyTranslations_1"]; }; - "/v2/projects/namespaces": { - /** Get namespaces */ - get: operations["getAllNamespaces_1"]; + "/v2/projects/start-batch-job/delete-keys": { + /** Delete keys */ + post: operations["deleteKeys_1"]; }; - "/v2/projects/namespace-by-name/{name}": { + "/v2/projects/start-batch-job/machine-translate": { /** - * Get namespace by name - * @description Returns information about a namespace by its name + * Machine Translation + * @description Translate provided keys to provided languages through primary MT provider. */ - get: operations["getByName_1"]; + post: operations["machineTranslation_1"]; }; - "/v2/projects/keys/search": { + "/v2/projects/start-batch-job/pre-translate-by-tm": { /** - * Search for keys - * @description This endpoint helps you to find desired key by keyName, base translation or translation in specified language. + * Pre-translate by TM + * @description Pre-translate provided keys to provided languages by TM. */ - get: operations["searchForKey_1"]; + post: operations["translate_1"]; }; - "/v2/projects/activity/revisions/{revisionId}": { - /** Get one revision data */ - get: operations["getSingleRevision_1"]; + "/v2/projects/start-batch-job/set-keys-namespace": { + /** Set keys namespace */ + post: operations["setKeysNamespace_1"]; }; - "/v2/projects/activity": { - /** Get project activity */ - get: operations["getActivity_1"]; + "/v2/projects/start-batch-job/set-translation-state": { + /** Set translation state */ + post: operations["setTranslationState_3"]; }; - "/v2/projects/tags": { - /** Get tags */ - get: operations["getAll_4"]; + "/v2/projects/start-batch-job/tag-keys": { + /** Add tags */ + post: operations["tagKeys_1"]; }; - "/v2/projects/my-batch-jobs": { - /** - * List user batch operations - * @description List all batch operations started by current user - */ - get: operations["myList_1"]; + "/v2/projects/start-batch-job/unassign-translation-label": { + /** Unassign labels from translations */ + post: operations["unassignTranslationLabel_1"]; }; - "/v2/projects/keys/{id}/big-meta": { - /** Get Big Meta for key */ - get: operations["getBigMeta_1"]; + "/v2/projects/start-batch-job/untag-keys": { + /** Remove tags */ + post: operations["untagKeys_1"]; }; - "/v2/projects/import/result/languages/{languageId}/translations": { + "/v2/projects/stats": { + /** Get project stats */ + get: operations["getProjectStats_1"]; + }; + "/v2/projects/stats/daily-activity": { + /** Get project daily amount of events */ + get: operations["getProjectDailyActivity_1"]; + }; + "/v2/projects/suggest/machine-translations": { /** - * Get translations - * @description Returns translations prepared to import. + * Get machine translation suggestions + * @description Suggests machine translations from enabled services */ - get: operations["getImportTranslations_1"]; + post: operations["suggestMachineTranslations_1"]; }; - "/v2/projects/import/result/languages/{languageId}": { + "/v2/projects/suggest/machine-translations-streaming": { /** - * Get import language - * @description Returns language prepared to import. + * Get machine translation suggestions (streaming) + * @description Suggests machine translations from enabled services. The results are streamed to the output in ndjson format. If an error occurs when for any service provider used, the error information is returned as a part of the result item, while the response has 200 status code. */ - get: operations["getImportLanguage_1"]; + post: operations["suggestMachineTranslationsStreaming_1"]; + }; + "/v2/projects/suggest/translation-memory": { /** - * Delete language - * @description Deletes language prepared to import. + * Get suggestions from translation memory + * @description Suggests machine translations from translation memory. The result is always sorted by similarity, so sorting is not supported. */ - delete: operations["deleteLanguage_1"]; + post: operations["suggestTranslationMemory_1"]; }; - "/v2/projects/import/result/files/{importFileId}/issues": { + "/v2/projects/tag-complex": { + /** Execute complex tag operation */ + put: operations["executeComplexTagOperation_1"]; + }; + "/v2/projects/tags": { + /** Get tags */ + get: operations["getAll_15"]; + }; + "/v2/projects/tasks": { + /** Get tasks */ + get: operations["getTasks_1"]; + /** Create task */ + post: operations["createTask_1"]; + }; + "/v2/projects/tasks/calculate-scope": { + /** Calculate scope */ + post: operations["calculateScope_1"]; + }; + "/v2/projects/tasks/create-multiple-tasks": { + /** Create multiple tasks */ + post: operations["createTasks_1"]; + }; + "/v2/projects/tasks/possible-assignees": { + /** Get possible assignees */ + get: operations["getPossibleAssignees_1"]; + }; + "/v2/projects/tasks/{taskNumber}": { + /** Get task */ + get: operations["getTask_1"]; + /** Update task */ + put: operations["updateTask_1"]; + }; + "/v2/projects/tasks/{taskNumber}/blocking-tasks": { /** - * Get file issues - * @description Returns issues for uploaded file. + * Get blocking task numbers + * @description If the tasks is blocked by other tasks, it returns numbers of these tasks. */ - get: operations["getImportFileIssues_1"]; + get: operations["getBlockingTasks_1"]; }; - "/v2/projects/import/result": { + "/v2/projects/tasks/{taskNumber}/cancel": { + /** Close task */ + put: operations["cancelTask_1"]; + }; + "/v2/projects/tasks/{taskNumber}/close": { /** - * Get result - * @description Returns the result of preparation. + * Close task + * @deprecated */ - get: operations["getImportResult_1"]; + put: operations["closeTask_1"]; }; - "/v2/projects/import/all-namespaces": { + "/v2/projects/tasks/{taskNumber}/finish": { + /** Finish task */ + put: operations["finishTask_1"]; + }; + "/v2/projects/tasks/{taskNumber}/keys": { + /** Get task keys */ + get: operations["getTaskKeys_1"]; + /** Add or remove task keys */ + put: operations["updateTaskKeys_1"]; + }; + "/v2/projects/tasks/{taskNumber}/keys/{keyId}": { /** - * Get namespaces - * @description Returns all existing and imported namespaces + * Update task key + * @description Mark key as done, which updates task progress. */ - get: operations["getAllNamespaces_3"]; + put: operations["updateTaskKey_1"]; }; - "/v2/projects/current-batch-jobs": { + "/v2/projects/tasks/{taskNumber}/per-user-report": { /** - * Get all running and pending batch operations - * @description Returns all running and pending batch operations. Completed batch operations are returned only if they are not older than 1 hour. If user doesn't have permission to view all batch operations, only their operations are returned. + * Get report + * @description Detailed statistics for every assignee */ - get: operations["currentJobs_1"]; + get: operations["getPerUserReport_1"]; }; - "/v2/projects/batch-jobs/{id}": { - /** Get batch operation */ - get: operations["get_13"]; + "/v2/projects/tasks/{taskNumber}/reopen": { + /** Reopen task */ + put: operations["reopenTask_1"]; }; - "/v2/projects/batch-jobs": { - /** List batch operations */ - get: operations["list_4"]; + "/v2/projects/tasks/{taskNumber}/xlsx-report": { + /** + * Get report in XLSX + * @description Detailed statistics about the task results + */ + get: operations["getXlsxReport_1"]; }; - "/v2/projects/translations/{translationId}/history": { + "/v2/projects/translations": { + /** Get translations in project */ + get: operations["getTranslations_1"]; /** - * Get translation history - * @description Sorting is not supported for supported. It is automatically sorted from newest to oldest. + * Update translations for existing key + * @description Sets translations for existing key */ - get: operations["getTranslationHistory_1"]; + put: operations["setTranslations_1"]; + /** + * Create key or update translations + * @description Sets translations for existing key or creates new key and sets the translations to it. + */ + post: operations["createOrUpdateTranslations_1"]; }; - "/v2/projects/translations/{languages}": { + "/v2/projects/translations/create-comment": { /** - * Get all translations - * @description Returns all translations for specified languages + * Create translation comment + * @description Creates a translation comment. Empty translation is stored, when not exists. */ - get: operations["getAllTranslations_1"]; + post: operations["create_4"]; + }; + "/v2/projects/translations/label": { + /** Add label to translation by key and language id */ + put: operations["assignLabel_3"]; }; "/v2/projects/translations/select-all": { /** @@ -590,71 +808,89 @@ export interface paths { */ get: operations["selectKeys_1"]; }; - "/v2/projects/keys/select": { + "/v2/projects/translations/{languages}": { /** - * Select keys - * @description Returns all key IDs for specified filter values. This way, you can apply the same filter as in the translation view and get the resulting key IDs for future use. + * Get all translations + * @description Returns all translations for specified languages */ - get: operations["selectKeys_3"]; - }; - "/v2/projects/stats/daily-activity": { - /** Get project daily amount of events */ - get: operations["getProjectDailyActivity_1"]; - }; - "/v2/projects/stats": { - /** Get project stats */ - get: operations["getProjectStats_1"]; + get: operations["getAllTranslations_1"]; }; - "/v2/pats/current": { + "/v2/projects/translations/{translationId}/comments": { /** - * Return current PAK - * @description Returns current Personal Access Token. If the request is not authenticated with a Personal Access Token, it will return 400 response status. + * Get translation comments + * @description Returns translation comments of translation */ - get: operations["getCurrent"]; + get: operations["getAll_4"]; + /** Create translation comment */ + post: operations["create_2"]; }; - "/v2/organizations/{slug}": { - /** Get organization by slug */ - get: operations["get_19"]; + "/v2/projects/translations/{translationId}/comments/{commentId}": { + /** Get one translation comment */ + get: operations["get_5"]; + /** Update translation comment */ + put: operations["update_2"]; + /** Delete translation comment */ + delete: operations["delete_3"]; }; - "/v2/organizations/{organizationId}/machine-translation-credit-balance": { + "/v2/projects/translations/{translationId}/comments/{commentId}/set-state/{state}": { + /** Set state of translation comment */ + put: operations["setState_1"]; + }; + "/v2/projects/translations/{translationId}/dismiss-auto-translated-state": { /** - * Get credit balance for organization - * @description Returns machine translation credit balance for organization + * Dismiss auto-translated + * @description Removes "auto translated" indication */ - get: operations["getOrganizationCredits"]; + put: operations["dismissAutoTranslatedState_1"]; }; - "/v2/api-keys/current": { + "/v2/projects/translations/{translationId}/history": { /** - * Get current API key info - * @description Returns info the API key which user currently authenticated with. Otherwise responds with 400 status code. + * Get translation history + * @description Sorting is not supported for supported. It is automatically sorted from newest to oldest. */ - get: operations["getCurrent_1"]; + get: operations["getTranslationHistory_1"]; }; - "/v2/api-keys/current-permissions": { + "/v2/projects/translations/{translationId}/label/{labelId}": { + /** Add label to translation */ + put: operations["assignLabel_1"]; + /** Remove label from translation */ + delete: operations["unassignLabel_1"]; + }; + "/v2/projects/translations/{translationId}/set-outdated-flag/{state}": { /** - * Get current permission info - * @description Returns current PAK or PAT permissions for current user, api-key and project + * Set outdated value + * @description Set's "outdated" flag indicating the base translation was changed without updating current translation. */ - get: operations["getCurrentPermissions"]; + put: operations["setOutdated_1"]; }; - "/v2/projects/keys/{ids}": { - /** Delete one or multiple keys */ - delete: operations["delete_3"]; + "/v2/projects/translations/{translationId}/set-state/{state}": { + /** Set translation state */ + put: operations["setTranslationState_1"]; }; - "/v2/projects/keys/{keyId}/tags/{tagId}": { + "/v2/projects/used-namespaces": { /** - * Remove tag - * @description Removes tag with provided id from key with provided id + * Get used namespaces + * @description Returns all used project namespaces. Response contains default (null) namespace if used. */ - delete: operations["removeTag_1"]; + get: operations["getUsedNamespaces_1"]; }; - "/v2/projects/keys/{keyId}/screenshots/{ids}": { - /** Delete screenshots */ - delete: operations["deleteScreenshots"]; + "/v2/user": { + /** + * Get user info + * @description Returns information about currently authenticated user. + */ + get: operations["getInfo"]; }; - "/v2/image-upload/{ids}": { - /** Delete uploaded images */ - delete: operations["delete_12"]; + "/v2/user-tasks": { + /** Get user tasks */ + get: operations["getTasks_2"]; + }; + "/v2/user/sso": { + /** + * Get information about SSO configuration + * @description Returns information about sso configuration affecting the user. + */ + get: operations["getSso"]; }; } @@ -662,70 +898,40 @@ export type webhooks = Record; export interface components { schemas: { - ErrorResponseTyped: { - /** @enum {string} */ - code: "unauthenticated" | "api_access_forbidden" | "api_key_not_found" | "invalid_api_key" | "invalid_project_api_key" | "project_api_key_expired" | "bad_credentials" | "mfa_enabled" | "invalid_otp_code" | "mfa_not_enabled" | "can_not_revoke_own_permissions" | "data_corrupted" | "invitation_code_does_not_exist_or_expired" | "language_tag_exists" | "language_name_exists" | "language_not_found" | "operation_not_permitted" | "registrations_not_allowed" | "project_not_found" | "resource_not_found" | "scope_not_found" | "key_exists" | "third_party_auth_error_message" | "third_party_auth_no_email" | "third_party_auth_no_sub" | "third_party_auth_unknown_error" | "email_already_verified" | "third_party_unauthorized" | "third_party_google_workspace_mismatch" | "username_already_exists" | "username_or_password_invalid" | "user_already_has_permissions" | "user_already_has_role" | "user_not_found" | "file_not_image" | "file_too_big" | "invalid_timestamp" | "email_not_verified" | "missing_callback_url" | "invalid_jwt_token" | "expired_jwt_token" | "general_jwt_error" | "cannot_find_suitable_address_part" | "address_part_not_unique" | "user_is_not_member_of_organization" | "organization_has_no_other_owner" | "user_has_no_project_access" | "user_is_organization_owner" | "cannot_set_your_own_permissions" | "user_is_organization_member" | "property_not_mutable" | "import_language_not_from_project" | "existing_language_not_selected" | "conflict_is_not_resolved" | "language_already_selected" | "cannot_parse_file" | "could_not_resolve_property" | "cannot_add_more_then_100_languages" | "no_languages_provided" | "language_with_base_language_tag_not_found" | "language_not_from_project" | "namespace_not_from_project" | "cannot_delete_base_language" | "key_not_from_project" | "max_screenshots_exceeded" | "translation_not_from_project" | "can_edit_only_own_comment" | "request_parse_error" | "filter_by_value_state_not_valid" | "import_has_expired" | "tag_not_from_project" | "translation_text_too_long" | "invalid_recaptcha_token" | "cannot_leave_owning_project" | "cannot_leave_project_with_organization_role" | "dont_have_direct_permissions" | "tag_too_log" | "too_many_uploaded_images" | "one_or_more_images_not_found" | "screenshot_not_of_key" | "service_not_found" | "too_many_requests" | "translation_not_found" | "out_of_credits" | "key_not_found" | "organization_not_found" | "cannot_find_base_language" | "base_language_not_found" | "no_exported_result" | "cannot_set_your_own_role" | "only_translate_review_or_view_permission_accepts_view_languages" | "oauth2_token_url_not_set" | "oauth2_user_url_not_set" | "email_already_invited_or_member" | "price_not_found" | "invoice_not_from_organization" | "invoice_not_found" | "plan_not_found" | "plan_not_available_any_more" | "no_auto_translation_method" | "cannot_translate_base_language" | "pat_not_found" | "invalid_pat" | "pat_expired" | "operation_unavailable_for_account_type" | "validation_email_is_not_valid" | "current_password_required" | "cannot_create_organization" | "wrong_current_password" | "wrong_param_type" | "expired_super_jwt_token" | "cannot_delete_your_own_account" | "cannot_sort_by_this_column" | "namespace_not_found" | "namespace_exists" | "invalid_authentication_method" | "unknown_sort_property" | "only_review_permission_accepts_state_change_languages" | "only_translate_or_review_permission_accepts_translate_languages" | "cannot_set_language_permissions_for_admin_scope" | "cannot_set_view_languages_without_translations_view_scope" | "cannot_set_translate_languages_without_translations_edit_scope" | "cannot_set_state_change_languages_without_translations_state_edit_scope" | "language_not_permitted" | "scopes_has_to_be_set" | "set_exactly_one_of_scopes_or_type" | "translation_exists" | "import_keys_error" | "provide_only_one_of_screenshots_and_screenshot_uploaded_image_ids" | "multiple_projects_not_supported" | "plan_translation_limit_exceeded" | "feature_not_enabled" | "license_key_not_found" | "cannot_set_view_languages_without_for_level_based_permissions" | "cannot_set_different_translate_and_state_change_languages_for_level_based_permissions" | "cannot_disable_your_own_account" | "subscription_not_found" | "invoice_does_not_have_usage" | "customer_not_found" | "subscription_not_active" | "organization_already_subscribed" | "organization_not_subscribed" | "license_key_used_by_another_instance" | "translation_spending_limit_exceeded" | "credit_spending_limit_exceeded" | "seats_spending_limit_exceeded" | "this_instance_is_already_licensed" | "big_meta_not_from_project" | "mt_service_not_enabled" | "project_not_selected" | "organization_not_selected" | "plan_has_subscribers" | "translation_failed" | "batch_job_not_found" | "key_exists_in_namespace" | "tag_is_blank" | "execution_failed_on_management_error" | "translation_api_rate_limit" | "cannot_finalize_activity" | "formality_not_supported_by_service" | "language_not_supported_by_service" | "rate_limited" | "pat_access_not_allowed" | "pak_access_not_allowed" | "cannot_modify_disabled_translation" | "azure_config_required" | "s3_config_required" | "content_storage_config_required" | "content_storage_test_failed" | "content_storage_config_invalid" | "invalid_connection_string" | "cannot_create_azure_storage_client" | "s3_access_key_required" | "azure_connection_string_required" | "s3_secret_key_required" | "cannot_store_file_to_content_storage" | "unexpected_error_while_publishing_to_content_storage" | "webhook_responded_with_non_200_status" | "unexpected_error_while_executing_webhook" | "content_storage_is_in_use" | "cannot_set_state_for_missing_translation" | "no_project_id_provided" | "license_key_not_provided" | "subscription_already_canceled" | "user_is_subscribed_to_paid_plan" | "cannot_create_free_plan_without_fixed_type" | "cannot_modify_plan_free_status" | "key_id_not_provided" | "free_self_hosted_seat_limit_exceeded" | "advanced_params_not_supported" | "plural_forms_not_found_for_language" | "nested_plurals_not_supported" | "message_is_not_plural" | "content_outside_plural_forms" | "invalid_plural_form" | "multiple_plurals_not_supported" | "custom_values_json_too_long" | "unsupported_po_message_format" | "plural_forms_data_loss" | "current_user_does_not_own_image" | "user_cannot_view_this_organization" | "user_is_not_owner_of_organization" | "pak_created_for_different_project" | "custom_slug_is_only_applicable_for_custom_storage" | "invalid_slug_format" | "batch_job_cancellation_timeout" | "import_failed" | "cannot_add_more_then_1000_languages" | "no_data_to_import" | "multiple_namespaces_mapped_to_single_file" | "multiple_mappings_for_same_file_language_name" | "multiple_mappings_for_null_file_language_name" | "too_many_mappings_for_file" | "missing_placeholder_in_template" | "tag_not_found" | "cannot_parse_encrypted_slack_login_data" | "slack_workspace_not_found" | "cannot_fetch_user_details_from_slack" | "slack_missing_scope" | "slack_not_connected_to_your_account" | "slack_invalid_command" | "slack_not_subscribed_yet" | "slack_connection_failed" | "tolgee_account_already_connected" | "slack_not_configured" | "slack_workspace_already_connected" | "slack_connection_error" | "email_verification_code_not_valid" | "cannot_subscribe_to_free_plan" | "plan_auto_assignment_only_for_free_plans" | "plan_auto_assignment_only_for_private_plans" | "plan_auto_assignment_organization_ids_not_in_for_organization_ids" | "task_not_found" | "task_not_finished" | "task_not_open"; - params?: Record[]; - }; - ErrorResponseBody: { - code: string; - params?: Record[]; - }; - Avatar: { - large: string; - thumbnail: string; + AcceptAuthProviderChangeRequest: { + id: string; }; - PrivateUserAccountModel: { - /** Format: int64 */ - id: number; - username: string; - name?: string; - emailAwaitingVerification?: string; - mfaEnabled: boolean; - avatar?: components["schemas"]["Avatar"]; - /** @enum {string} */ - accountType: "LOCAL" | "MANAGED" | "THIRD_PARTY"; - /** @enum {string} */ - globalServerRole: "USER" | "ADMIN"; - deletable: boolean; - needsSuperJwtToken: boolean; - }; - ComputedPermissionModel: { - permissionModel?: components["schemas"]["PermissionModel"]; - /** @enum {string} */ - origin: "ORGANIZATION_BASE" | "DIRECT" | "ORGANIZATION_OWNER" | "NONE" | "SERVER_ADMIN"; + ApiKeyPermissionsModel: { + project: components["schemas"]["SimpleProjectModel"]; /** - * @description The user's permission type. This field is null if uses granular permissions - * @enum {string} + * Format: int64 + * @description The API key's project id or the one provided as query param */ - type?: "NONE" | "VIEW" | "TRANSLATE" | "REVIEW" | "EDIT" | "MANAGE"; + projectId: number; /** - * @description List of languages user can view. If null, all languages view is permitted. + * @description Granted scopes to the user. When user has type permissions, this field contains permission scopes of the type. * @example [ - * 200001, - * 200004 + * "KEYS_EDIT", + * "TRANSLATIONS_VIEW" * ] */ - viewLanguageIds?: number[]; + scopes: ("translations.view" | "translations.edit" | "translations.suggest" | "keys.edit" | "screenshots.upload" | "screenshots.delete" | "screenshots.view" | "activity.view" | "languages.edit" | "admin" | "project.edit" | "members.view" | "members.edit" | "translation-comments.add" | "translation-comments.edit" | "translation-comments.set-state" | "translations.state-edit" | "keys.view" | "keys.delete" | "keys.create" | "batch-jobs.view" | "batch-jobs.cancel" | "translations.batch-by-tm" | "translations.batch-machine" | "content-delivery.manage" | "content-delivery.publish" | "webhooks.manage" | "tasks.view" | "tasks.edit" | "prompts.view" | "prompts.edit" | "translation-labels.manage" | "translation-labels.assign" | "all.view")[]; /** - * @description Granted scopes to the user. When user has type permissions, this field contains permission scopes of the type. + * @description List of languages user can change state to. If null, changing state of all language values is permitted. * @example [ - * "KEYS_EDIT", - * "TRANSLATIONS_VIEW" + * 200001, + * 200004 * ] */ - scopes: ("translations.view" | "translations.edit" | "keys.edit" | "screenshots.upload" | "screenshots.delete" | "screenshots.view" | "activity.view" | "languages.edit" | "admin" | "project.edit" | "members.view" | "members.edit" | "translation-comments.add" | "translation-comments.edit" | "translation-comments.set-state" | "translations.state-edit" | "keys.view" | "keys.delete" | "keys.create" | "batch-jobs.view" | "batch-jobs.cancel" | "translations.batch-by-tm" | "translations.batch-machine" | "content-delivery.manage" | "content-delivery.publish" | "webhooks.manage" | "tasks.view" | "tasks.edit")[]; + stateChangeLanguageIds?: number[]; /** - * @deprecated - * @description Deprecated (use translateLanguageIds). - * - * List of languages current user has TRANSLATE permission to. If null, all languages edition is permitted. + * @description List of languages user can suggest to. If null, suggesting to all languages is permitted. * @example [ * 200001, * 200004 * ] */ - permittedLanguageIds?: number[]; + suggestLanguageIds?: number[]; /** * @description List of languages user can translate to. If null, all languages editing is permitted. * @example [ @@ -735,688 +941,663 @@ export interface components { */ translateLanguageIds?: number[]; /** - * @description List of languages user can change state to. If null, changing state of all language values is permitted. + * @description The user's permission type. This field is null if user has assigned granular permissions or if returning API key's permissions + * @enum {string} + */ + type?: "NONE" | "VIEW" | "TRANSLATE" | "REVIEW" | "EDIT" | "MANAGE"; + /** + * @description List of languages user can view. If null, all languages view is permitted. * @example [ * 200001, * 200004 * ] */ - stateChangeLanguageIds?: number[]; + viewLanguageIds?: number[]; }; - LanguageModel: { + ApiKeyWithLanguagesModel: { + description: string; + /** Format: int64 */ + expiresAt?: number; /** Format: int64 */ id: number; + /** Format: int64 */ + lastUsedAt?: number; /** - * @description Language name in english - * @example Czech - */ - name: string; - /** - * @description Language tag according to BCP 47 definition - * @example cs-CZ - */ - tag: string; - /** - * @description Language name in this language - * @example čeština + * @deprecated + * @description Languages for which user has translate permission. */ - originalName?: string; + permittedLanguageIds?: number[]; + /** Format: int64 */ + projectId: number; + projectName: string; + scopes: string[]; + userFullName?: string; + username?: string; + }; + AuthProviderDto: { + /** @enum {string} */ + authType?: "GOOGLE" | "GITHUB" | "OAUTH2" | "SSO" | "SSO_GLOBAL"; + id?: string; + ssoDomain?: string; + }; + Avatar: { + large: string; + thumbnail: string; + }; + BatchJobModel: { /** - * @description Language flag emoji as UTF-8 emoji - * @example 🇨🇿 + * Format: int64 + * @description The activity revision id, that stores the activity details of the job */ - flagEmoji?: string; + activityRevisionId?: number; + /** @description The user who started the job */ + author?: components["schemas"]["SimpleUserAccountModel"]; /** - * @description Whether is base language of project - * @example false + * Format: int64 + * @description The time when the job created */ - base: boolean; - }; - NamespaceModel: { + createdAt: number; + /** @description If the job failed, this is the error message */ + errorMessage?: string; /** * Format: int64 - * @description The id of namespace - * @example 10000048 + * @description Batch job id */ id: number; - /** @example homepage */ - name: string; - }; - /** - * @description Current user's direct permission - * @example MANAGE - */ - PermissionModel: { /** - * @description Granted scopes to the user. When user has type permissions, this field contains permission scopes of the type. - * @example [ - * "KEYS_EDIT", - * "TRANSLATIONS_VIEW" - * ] + * Format: int32 + * @description Total items, that have been processed so far */ - scopes: ("translations.view" | "translations.edit" | "keys.edit" | "screenshots.upload" | "screenshots.delete" | "screenshots.view" | "activity.view" | "languages.edit" | "admin" | "project.edit" | "members.view" | "members.edit" | "translation-comments.add" | "translation-comments.edit" | "translation-comments.set-state" | "translations.state-edit" | "keys.view" | "keys.delete" | "keys.create" | "batch-jobs.view" | "batch-jobs.cancel" | "translations.batch-by-tm" | "translations.batch-machine" | "content-delivery.manage" | "content-delivery.publish" | "webhooks.manage" | "tasks.view" | "tasks.edit")[]; + progress: number; /** - * @description The user's permission type. This field is null if uses granular permissions + * @description Status of the batch job * @enum {string} */ - type?: "NONE" | "VIEW" | "TRANSLATE" | "REVIEW" | "EDIT" | "MANAGE"; + status: "PENDING" | "RUNNING" | "SUCCESS" | "FAILED" | "CANCELLED" | "DEBOUNCED"; /** - * @deprecated - * @description Deprecated (use translateLanguageIds). - * - * List of languages current user has TRANSLATE permission to. If null, all languages edition is permitted. - * @example [ - * 200001, - * 200004 - * ] + * Format: int32 + * @description Total items */ - permittedLanguageIds?: number[]; + totalItems: number; /** - * @description List of languages user can translate to. If null, all languages editing is permitted. - * @example [ - * 200001, - * 200004 - * ] + * @description Type of the batch job + * @enum {string} */ - translateLanguageIds?: number[]; + type: "AI_PLAYGROUND_TRANSLATE" | "PRE_TRANSLATE_BT_TM" | "MACHINE_TRANSLATE" | "AUTO_TRANSLATE" | "DELETE_KEYS" | "SET_TRANSLATIONS_STATE" | "CLEAR_TRANSLATIONS" | "COPY_TRANSLATIONS" | "TAG_KEYS" | "UNTAG_KEYS" | "SET_KEYS_NAMESPACE" | "AUTOMATION" | "BILLING_TRIAL_EXPIRATION_NOTICE" | "ASSIGN_TRANSLATION_LABEL" | "UNASSIGN_TRANSLATION_LABEL"; /** - * @description List of languages user can view. If null, all languages view is permitted. - * @example [ - * 200001, - * 200004 - * ] + * Format: int64 + * @description The time when the job was last updated (status change) */ - viewLanguageIds?: number[]; - /** - * @description List of languages user can change state to. If null, changing state of all language values is permitted. - * @example [ - * 200001, - * 200004 - * ] - */ - stateChangeLanguageIds?: number[]; - }; - ProjectModel: { - /** Format: int64 */ - id: number; - name: string; - description?: string; - slug?: string; - avatar?: components["schemas"]["Avatar"]; - organizationOwner?: components["schemas"]["SimpleOrganizationModel"]; - baseLanguage?: components["schemas"]["LanguageModel"]; - defaultNamespace?: components["schemas"]["NamespaceModel"]; - /** @enum {string} */ - organizationRole?: "MEMBER" | "OWNER"; - directPermission?: components["schemas"]["PermissionModel"]; - computedPermission: components["schemas"]["ComputedPermissionModel"]; - /** @description Whether to disable ICU placeholder visualization in the editor and it's support. */ - icuPlaceholders: boolean; - }; - SimpleOrganizationModel: { - /** Format: int64 */ - id: number; - /** @example Beautiful organization */ - name: string; - /** @example btforg */ - slug: string; - /** @example This is a beautiful organization full of beautiful and clever people */ - description?: string; - basePermissions: components["schemas"]["PermissionModel"]; - avatar?: components["schemas"]["Avatar"]; + updatedAt: number; }; - SimpleUserAccountModel: { - /** Format: int64 */ - id: number; - username: string; - name?: string; - avatar?: components["schemas"]["Avatar"]; - deleted: boolean; + BigMetaDto: { + /** @description Keys in the document used as a context for machine translation. Keys in the same order as they appear in the document. The order is important! We are using it for graph distance calculation. */ + relatedKeysInOrder?: components["schemas"]["RelatedKeyDto"][]; }; - TaskModel: { + CalculateScopeRequest: { + keys: number[]; /** Format: int64 */ - number: number; - name: string; - description: string; + languageId: number; /** @enum {string} */ type: "TRANSLATE" | "REVIEW"; - language: components["schemas"]["LanguageModel"]; - /** Format: int64 */ - dueDate?: number; - assignees: components["schemas"]["SimpleUserAccountModel"][]; - /** Format: int64 */ - totalItems: number; - /** Format: int64 */ - doneItems: number; - /** Format: int64 */ - baseWordCount: number; - /** Format: int64 */ - baseCharacterCount: number; - author?: components["schemas"]["SimpleUserAccountModel"]; - /** Format: int64 */ - createdAt?: number; - /** Format: int64 */ - closedAt?: number; - /** @enum {string} */ - state: "NEW" | "IN_PROGRESS" | "DONE" | "CLOSED"; }; - UpdateTaskKeyRequest: { - done: boolean; + ClearTranslationsRequest: { + keyIds: number[]; + languageIds: number[]; }; - UpdateTaskKeyResponse: { - /** @description Task key is marked as done */ - done: boolean; - /** @description Task progress is 100% */ - taskFinished: boolean; + CollectionModelBatchJobModel: { + _embedded?: { + batchJobs?: components["schemas"]["BatchJobModel"][]; + }; }; - UpdateTaskKeysRequest: { - /** @description Keys to add to task */ - addKeys?: number[]; - /** @description Keys to remove from task */ - removeKeys?: number[]; + CollectionModelGlossaryLanguageDto: { + _embedded?: { + glossaryLanguageDtoList?: components["schemas"]["GlossaryLanguageDto"][]; + }; }; - UpdateTaskRequest: { - name: string; - description: string; - /** - * Format: int64 - * @description Due to date in epoch format (milliseconds). - * @example 1661172869000 - */ - dueDate?: number; - assignees: number[]; + CollectionModelImportNamespaceModel: { + _embedded?: { + namespaces?: components["schemas"]["ImportNamespaceModel"][]; + }; }; - UpdateNamespaceDto: { - name: string; + CollectionModelKeyWithBaseTranslationModel: { + _embedded?: { + keys?: components["schemas"]["KeyWithBaseTranslationModel"][]; + }; }; - SetDisabledLanguagesRequest: { - languageIds: number[]; + CollectionModelKeyWithDataModel: { + _embedded?: { + keys?: components["schemas"]["KeyWithDataModel"][]; + }; }; CollectionModelLanguageModel: { _embedded?: { languages?: components["schemas"]["LanguageModel"][]; }; }; + CollectionModelLong: { + _embedded?: { + longList?: number[]; + }; + }; + CollectionModelScreenshotModel: { + _embedded?: { + screenshots?: components["schemas"]["ScreenshotModel"][]; + }; + }; + CollectionModelSimpleProjectModel: { + _embedded?: { + projects?: components["schemas"]["SimpleProjectModel"][]; + }; + }; + CollectionModelUsedNamespaceModel: { + _embedded?: { + namespaces?: components["schemas"]["UsedNamespaceModel"][]; + }; + }; ComplexEditKeyDto: { + /** @description Custom values of the key. If not provided, custom values won't be modified */ + custom?: { + [key: string]: unknown; + }; + /** @description Description of the key. It's also used as a context for Tolgee AI translator */ + description?: string; + /** @description If key is pluralized. If it will be reflected in the editor. If null, value won't be modified. */ + isPlural?: boolean; /** @description Name of the key */ name: string; namespace?: string; - /** @description Translations to update */ - translations?: { - [key: string]: string; - }; + /** @description The argument name for the plural. If null, value won't be modified. If isPlural is false, this value will be ignored. */ + pluralArgName?: string; + /** @description Keys in the document used as a context for machine translation. Keys in the same order as they appear in the document. The order is important! We are using it for graph distance calculation. */ + relatedKeysInOrder?: components["schemas"]["RelatedKeyDto"][]; + /** @description IDs of screenshots to delete */ + screenshotIdsToDelete?: number[]; + /** + * @deprecated + * @description Ids of screenshots uploaded with /v2/image-upload endpoint + */ + screenshotUploadedImageIds?: number[]; + screenshotsToAdd?: components["schemas"]["KeyScreenshotDto"][]; /** @description Translation states to update, if not provided states won't be modified */ states?: { [key: string]: "TRANSLATED" | "REVIEWED"; }; /** @description Tags of the key. If not provided tags won't be modified */ tags?: string[]; - /** @description IDs of screenshots to delete */ - screenshotIdsToDelete?: number[]; - /** @description Ids of screenshots uploaded with /v2/image-upload endpoint */ - screenshotUploadedImageIds?: number[]; - screenshotsToAdd?: components["schemas"]["KeyScreenshotDto"][]; - /** @description Keys in the document used as a context for machine translation. Keys in the same order as they appear in the document. The order is important! We are using it for graph distance calculation. */ - relatedKeysInOrder?: components["schemas"]["RelatedKeyDto"][]; - /** @description Description of the key. It's also used as a context for Tolgee AI translator */ - description?: string; - /** @description If key is pluralized. If it will be reflected in the editor. If null, value won't be modified. */ - isPlural?: boolean; - /** @description The argument name for the plural. If null, value won't be modified. If isPlural is false, this value will be ignored. */ - pluralArgName?: string; + /** @description Translations to update */ + translations?: { + [key: string]: string; + }; /** @description If true, it will fail with 400 (with code plural_forms_data_loss) if plural is disabled and there are plural forms, which would be lost by the action. You can get rid of this warning by setting this value to false. */ warnOnDataLoss?: boolean; - /** @description Custom values of the key. If not provided, custom values won't be modified */ - custom?: { - [key: string]: Record; - }; }; - KeyInScreenshotPositionDto: { - /** Format: int32 */ - x: number; - /** Format: int32 */ - y: number; - /** Format: int32 */ - width: number; - /** Format: int32 */ - height: number; + ComplexTagKeysRequest: { + /** @description Include keys filtered by the provided key information */ + filterKeys?: components["schemas"]["KeyId"][]; + /** @description Exclude keys filtered by the provided key information */ + filterKeysNot?: components["schemas"]["KeyId"][]; + /** @description Include keys filtered by the provided tag information. This filter supports wildcards. For example, `draft-*` will match all tags starting with `draft-`. */ + filterTag?: string[]; + /** @description Exclude keys filtered by the provided tag information. This filter supports wildcards. For example, `draft-*` will match all tags starting with `draft-`. */ + filterTagNot?: string[]; + /** @description Specified tags will be added to filtered keys */ + tagFiltered?: string[]; + /** @description Specified tags will be added to keys not filtered by any of the specified filters. */ + tagOther?: string[]; + /** @description Specified tags will be removed from filtered keys. It supports wildcards. For example, `draft-*` will remove all tags starting with `draft-`. */ + untagFiltered?: string[]; + /** @description Specified tags will be removed from keys not filtered by any of the specified filters. It supports wildcards. For example, `draft-*` will remove all tags starting with `draft-`. */ + untagOther?: string[]; }; - KeyScreenshotDto: { - text?: string; + ComputedPermissionModel: { + /** @enum {string} */ + origin: "ORGANIZATION_BASE" | "DIRECT" | "ORGANIZATION_OWNER" | "NONE" | "SERVER_ADMIN" | "SERVER_SUPPORTER"; + permissionModel?: components["schemas"]["PermissionModel"]; /** - * Format: int64 - * @description Ids of screenshot uploaded with /v2/image-upload endpoint + * @deprecated + * @description Deprecated (use translateLanguageIds). + * + * List of languages current user has TRANSLATE permission to. If null, all languages edition is permitted. + * @example [ + * 200001, + * 200004 + * ] */ - uploadedImageId: number; - positions?: components["schemas"]["KeyInScreenshotPositionDto"][]; - }; - /** @description Keys in the document used as a context for machine translation. Keys in the same order as they appear in the document. The order is important! We are using it for graph distance calculation. */ - RelatedKeyDto: { - namespace?: string; - keyName: string; - }; - KeyInScreenshotModel: { - /** Format: int64 */ - keyId: number; - position?: components["schemas"]["KeyInScreenshotPosition"]; - keyName: string; - keyNamespace?: string; - originalText?: string; - }; - KeyInScreenshotPosition: { - /** Format: int32 */ - x: number; - /** Format: int32 */ - y: number; - /** Format: int32 */ - width: number; - /** Format: int32 */ - height: number; - }; - KeyWithDataModel: { + permittedLanguageIds?: number[]; /** - * Format: int64 - * @description Id of key record + * @description Granted scopes to the user. When user has type permissions, this field contains permission scopes of the type. + * @example [ + * "KEYS_EDIT", + * "TRANSLATIONS_VIEW" + * ] */ - id: number; + scopes: ("translations.view" | "translations.edit" | "translations.suggest" | "keys.edit" | "screenshots.upload" | "screenshots.delete" | "screenshots.view" | "activity.view" | "languages.edit" | "admin" | "project.edit" | "members.view" | "members.edit" | "translation-comments.add" | "translation-comments.edit" | "translation-comments.set-state" | "translations.state-edit" | "keys.view" | "keys.delete" | "keys.create" | "batch-jobs.view" | "batch-jobs.cancel" | "translations.batch-by-tm" | "translations.batch-machine" | "content-delivery.manage" | "content-delivery.publish" | "webhooks.manage" | "tasks.view" | "tasks.edit" | "prompts.view" | "prompts.edit" | "translation-labels.manage" | "translation-labels.assign" | "all.view")[]; /** - * @description Name of key - * @example this_is_super_key + * @description List of languages user can change state to. If null, changing state of all language values is permitted. + * @example [ + * 200001, + * 200004 + * ] */ - name: string; - /** - * @description Namespace of key - * @example homepage - */ - namespace?: string; + stateChangeLanguageIds?: number[]; /** - * @description Description of key - * @example This key is used on homepage. It's a label of sign up button. + * @description List of languages user can suggest to. If null, suggesting to all languages is permitted. + * @example [ + * 200001, + * 200004 + * ] */ - description?: string; + suggestLanguageIds?: number[]; /** - * @description Translations object containing values updated in this request - * @example { - * "en": { - * "id": 100000003, - * "text": "This is super translation!" - * } - * } + * @description List of languages user can translate to. If null, all languages editing is permitted. + * @example [ + * 200001, + * 200004 + * ] */ - translations: { - [key: string]: components["schemas"]["TranslationModel"]; - }; - /** @description Tags of key */ - tags: components["schemas"]["TagModel"][]; - /** @description Screenshots of the key */ - screenshots: components["schemas"]["ScreenshotModel"][]; - /** @description If key is pluralized. If it will be reflected in the editor */ - isPlural: boolean; - /** @description The argument name for the plural */ - pluralArgName?: string; - /** @description Custom values of the key */ - custom: { - [key: string]: Record; - }; - }; - /** @description Screenshots of the key */ - ScreenshotModel: { - /** Format: int64 */ - id: number; + translateLanguageIds?: number[]; /** - * @description File name, which may be downloaded from the screenshot path. - * - * When images are secured. Encrypted timestamp is appended to the filename. + * @description The user's permission type. This field is null if uses granular permissions + * @enum {string} */ - filename: string; + type?: "NONE" | "VIEW" | "TRANSLATE" | "REVIEW" | "EDIT" | "MANAGE"; /** - * @description Thumbnail file name, which may be downloaded from the screenshot path. - * - * When images are secured. Encrypted timestamp is appended to the filename. + * @description List of languages user can view. If null, all languages view is permitted. + * @example [ + * 200001, + * 200004 + * ] */ - thumbnail: string; - fileUrl: string; - thumbnailUrl: string; - /** Format: date-time */ - createdAt?: string; - keyReferences: components["schemas"]["KeyInScreenshotModel"][]; - location?: string; - /** Format: int32 */ - width?: number; - /** Format: int32 */ - height?: number; + viewLanguageIds?: number[]; }; - /** @description Tags of key */ - TagModel: { + CopyTranslationRequest: { + keyIds: number[]; /** Format: int64 */ - id: number; - name: string; + sourceLanguageId: number; + targetLanguageIds: number[]; }; - /** - * @description Translations object containing values updated in this request - * @example { - * "en": { - * "id": 100000003, - * "text": "This is super translation!" - * } - * } - */ - TranslationModel: { + CreateGlossaryRequest: { + /** @description IDs of projects to be assigned to glossary */ + assignedProjectIds: number[]; /** - * Format: int64 - * @description Id of translation record + * @description Language tag according to BCP 47 definition + * @example cs-CZ */ - id: number; - /** @description Translation text */ - text?: string; + baseLanguageTag: string; /** - * @description State of translation - * @enum {string} + * @description Glossary name + * @example My glossary */ - state: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; - /** @description Whether base language translation was changed after this translation was updated */ - outdated: boolean; - /** @description Was translated using Translation Memory or Machine translation service? */ - auto: boolean; + name: string; + }; + CreateGlossaryTermWithTranslationRequest: { /** - * @description Which machine translation service was used to auto translate this - * @enum {string} + * @description A detailed explanation or definition of the glossary term + * @example It's trademark */ - mtProvider?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; + description: string; + /** @description Specifies whether the term represents a shortened form of a word or phrase */ + flagAbbreviation: boolean; + /** @description When true, the term matching considers uppercase and lowercase characters as distinct */ + flagCaseSensitive: boolean; + /** @description When true, marks this term as prohibited or not recommended for use in translations */ + flagForbiddenTerm: boolean; + /** @description When true, this term will have the same translation across all target languages */ + flagNonTranslatable: boolean; + text: string; }; - EditKeyDto: { - name: string; - namespace?: string; + CreateKeyDto: { /** * @description Description of the key * @example This key is used on homepage. It's a label of sign up button. */ description?: string; - }; - KeyModel: { - /** - * Format: int64 - * @description Id of key record - */ - id: number; - /** - * @description Name of key - * @example this_is_super_key - */ + /** @description If key is pluralized. If it will be reflected in the editor */ + isPlural: boolean; + /** @description Name of the key */ name: string; - /** - * @description Namespace of key - * @example homepage - */ namespace?: string; + /** @description The argument name for the plural. If null, value will be guessed from the values provided in translations. */ + pluralArgName?: string; + /** @description Keys in the document used as a context for machine translation. Keys in the same order as they appear in the document. The order is important! We are using it for graph distance calculation. */ + relatedKeysInOrder?: components["schemas"]["RelatedKeyDto"][]; /** - * @description Description of key - * @example This key is used on homepage. It's a label of sign up button. + * @deprecated + * @description Ids of screenshots uploaded with /v2/image-upload endpoint */ - description?: string; - /** @description Custom values of the key */ - custom?: { - [key: string]: Record; + screenshotUploadedImageIds?: number[]; + screenshots?: components["schemas"]["KeyScreenshotDto"][]; + /** @description Translation states to update, if not provided states won't be modified */ + states?: { + [key: string]: "TRANSLATED" | "REVIEWED"; + }; + tags?: string[]; + translations?: { + [key: string]: string; }; }; - ComplexTagKeysRequest: { - /** @description Include keys filtered by the provided key information */ - filterKeys?: components["schemas"]["KeyId"][]; - /** @description Exclude keys filtered by the provided key information */ - filterKeysNot?: components["schemas"]["KeyId"][]; - /** @description Include keys filtered by the provided tag information. This filter supports wildcards. For example, `draft-*` will match all tags starting with `draft-`. */ - filterTag?: string[]; - /** @description Exclude keys filtered by the provided tag information. This filter supports wildcards. For example, `draft-*` will match all tags starting with `draft-`. */ - filterTagNot?: string[]; - /** @description Specified tags will be added to filtered keys */ - tagFiltered?: string[]; - /** @description Specified tags will be removed from filtered keys. It supports wildcards. For example, `draft-*` will remove all tags starting with `draft-`. */ - untagFiltered?: string[]; - /** @description Specified tags will be added to keys not filtered by any of the specified filters. */ - tagOther?: string[]; - /** @description Specified tags will be removed from keys not filtered by any of the specified filters. It supports wildcards. For example, `draft-*` will remove all tags starting with `draft-`. */ - untagOther?: string[]; + CreateMultipleTasksRequest: { + tasks: components["schemas"]["CreateTaskRequest"][]; }; - /** @description Exclude keys filtered by the provided key information */ - KeyId: { - name?: string; - namespace?: string; + CreateProjectRequest: { + /** @description Tag of one of created languages, to select it as base language. If not provided, first language will be selected as base. */ + baseLanguageTag?: string; + /** @description Whether to use ICU placeholder visualization in the editor and it's support. */ + icuPlaceholders: boolean; + languages: components["schemas"]["LanguageRequest"][]; + name: string; /** * Format: int64 - * @description If key id is provided, name and namespace are ignored. + * @description Organization to create the project in */ - id?: number; - }; - TagKeyDto: { - name: string; - }; - SetFileNamespaceRequest: { - namespace?: string; - }; - StreamingResponseBody: Record; - ImportSettingsRequest: { - /** @description If true, key descriptions will be overridden by the import */ - overrideKeyDescriptions: boolean; - /** @description If true, placeholders from other formats will be converted to ICU when possible */ - convertPlaceholdersToIcu: boolean; - /** @description If false, only updates keys, skipping the creation of new keys */ - createNewKeys: boolean; - }; - ImportSettingsModel: { - /** @description If false, only updates keys, skipping the creation of new keys */ - createNewKeys: boolean; - /** @description If true, key descriptions will be overridden by the import */ - overrideKeyDescriptions: boolean; - /** @description If true, placeholders from other formats will be converted to ICU when possible */ - convertPlaceholdersToIcu: boolean; + organizationId: number; + /** @description Slug of your project used in url e.g. "/v2/projects/what-a-project". If not provided, it will be generated */ + slug?: string; }; - TranslationCommentModel: { + CreateTaskRequest: { + assignees: number[]; + description: string; /** * Format: int64 - * @description Id of translation comment record - */ - id: number; - /** @description Text of comment */ - text: string; - /** - * @description State of translation - * @enum {string} + * @description Due to date in epoch format (milliseconds). + * @example 1661172869000 */ - state: "RESOLUTION_NOT_NEEDED" | "NEEDS_RESOLUTION" | "RESOLVED"; - author: components["schemas"]["SimpleUserAccountModel"]; + dueDate?: number; + keys: number[]; /** - * Format: date-time - * @description Date when it was created + * Format: int64 + * @description Id of language, this task is attached to. + * @example 1 */ - createdAt: string; + languageId: number; + name?: string; + /** @enum {string} */ + type: "TRANSLATE" | "REVIEW"; + }; + CreateTranslationSuggestionRequest: { + translation: string; + }; + CreateUpdateGlossaryTermResponse: { + term: components["schemas"]["SimpleGlossaryTermModel"]; + translation?: components["schemas"]["GlossaryTermTranslationModel"]; + }; + CreditBalanceModel: { + /** Format: int64 */ + bucketSize: number; + /** Format: int64 */ + creditBalance: number; /** - * Format: date-time - * @description Date when it was updated + * Format: int64 + * @deprecated + * @description Customers were able to buy extra credits separately in the past. + * + * This option is not available anymore and this field is kept only for backward compatibility purposes and is always 0. */ - updatedAt: string; + extraCreditBalance: number; }; - TranslationCommentDto: { - text: string; - /** @enum {string} */ - state: "RESOLUTION_NOT_NEEDED" | "NEEDS_RESOLUTION" | "RESOLVED"; + DeleteKeysDto: { + /** @description IDs of keys to delete */ + ids: number[]; }; - SetTranslationsWithKeyDto: { + DeleteKeysRequest: { + keyIds: number[]; + }; + DeleteMultipleGlossaryTermsRequest: { + termIds: number[]; + }; + EditKeyDto: { /** - * @description Key name to set translations for - * @example what_a_key_to_translate + * @description Description of the key + * @example This key is used on homepage. It's a label of sign up button. */ - key: string; - /** @description The namespace of the key. (When empty or null default namespace will be used) */ + description?: string; + name: string; namespace?: string; + }; + EntityDescriptionWithRelations: { + data: { + [key: string]: unknown; + }; + entityClass: string; + /** Format: int64 */ + entityId: number; + }; + ErrorResponseBody: { + code: string; + params?: unknown[]; + }; + ErrorResponseTyped: { + /** @enum {string} */ + code: "unauthenticated" | "api_access_forbidden" | "api_key_not_found" | "invalid_api_key" | "invalid_project_api_key" | "project_api_key_expired" | "bad_credentials" | "mfa_enabled" | "invalid_otp_code" | "mfa_not_enabled" | "can_not_revoke_own_permissions" | "data_corrupted" | "invitation_code_does_not_exist_or_expired" | "language_tag_exists" | "language_name_exists" | "language_not_found" | "operation_not_permitted" | "registrations_not_allowed" | "project_not_found" | "resource_not_found" | "scope_not_found" | "key_exists" | "third_party_auth_error_message" | "third_party_auth_no_email" | "third_party_auth_non_matching_email" | "third_party_auth_no_sub" | "third_party_auth_unknown_error" | "email_already_verified" | "third_party_unauthorized" | "third_party_google_workspace_mismatch" | "third_party_switch_initiated" | "third_party_switch_conflict" | "username_already_exists" | "username_or_password_invalid" | "user_already_has_permissions" | "user_already_has_role" | "user_not_found" | "file_not_image" | "file_too_big" | "invalid_timestamp" | "email_not_verified" | "missing_callback_url" | "invalid_jwt_token" | "expired_jwt_token" | "general_jwt_error" | "cannot_find_suitable_address_part" | "slug_not_unique" | "user_is_not_member_of_organization" | "organization_has_no_other_owner" | "user_has_no_project_access" | "user_is_organization_owner" | "cannot_set_your_own_permissions" | "user_is_organization_member" | "property_not_mutable" | "import_language_not_from_project" | "existing_language_not_selected" | "conflict_is_not_resolved" | "language_already_selected" | "cannot_parse_file" | "could_not_resolve_property" | "cannot_add_more_then_100_languages" | "no_languages_provided" | "language_with_base_language_tag_not_found" | "language_not_from_project" | "namespace_not_from_project" | "cannot_delete_base_language" | "key_not_from_project" | "max_screenshots_exceeded" | "translation_not_from_project" | "can_edit_only_own_comment" | "request_parse_error" | "filter_by_value_state_not_valid" | "import_has_expired" | "tag_not_from_project" | "translation_text_too_long" | "invalid_recaptcha_token" | "cannot_leave_owning_project" | "cannot_leave_project_with_organization_role" | "dont_have_direct_permissions" | "tag_too_log" | "too_many_uploaded_images" | "one_or_more_images_not_found" | "screenshot_not_of_key" | "service_not_found" | "too_many_requests" | "translation_not_found" | "out_of_credits" | "key_not_found" | "organization_not_found" | "cannot_find_base_language" | "base_language_not_found" | "no_exported_result" | "cannot_set_your_own_role" | "only_translate_review_or_view_permission_accepts_view_languages" | "oauth2_token_url_not_set" | "oauth2_user_url_not_set" | "email_already_invited_or_member" | "price_not_found" | "invoice_not_from_organization" | "invoice_not_found" | "plan_not_found" | "plan_not_available_any_more" | "no_auto_translation_method" | "cannot_translate_base_language" | "pat_not_found" | "invalid_pat" | "pat_expired" | "operation_unavailable_for_account_type" | "validation_email_is_not_valid" | "current_password_required" | "cannot_create_organization" | "wrong_current_password" | "wrong_param_type" | "user_missing_password" | "expired_super_jwt_token" | "cannot_delete_your_own_account" | "cannot_sort_by_this_column" | "namespace_not_found" | "namespace_exists" | "invalid_authentication_method" | "unknown_sort_property" | "only_review_permission_accepts_state_change_languages" | "only_translate_or_review_permission_accepts_translate_languages" | "cannot_set_language_permissions_for_admin_scope" | "cannot_set_view_languages_without_translations_view_scope" | "cannot_set_translate_languages_without_translations_edit_scope" | "cannot_set_state_change_languages_without_translations_state_edit_scope" | "language_not_permitted" | "scopes_has_to_be_set" | "set_exactly_one_of_scopes_or_type" | "translation_exists" | "import_keys_error" | "provide_only_one_of_screenshots_and_screenshot_uploaded_image_ids" | "multiple_projects_not_supported" | "plan_translation_limit_exceeded" | "feature_not_enabled" | "license_key_not_found" | "cannot_set_view_languages_without_for_level_based_permissions" | "cannot_set_different_translate_and_state_change_languages_for_level_based_permissions" | "cannot_disable_your_own_account" | "subscription_not_found" | "invoice_does_not_have_usage" | "customer_not_found" | "subscription_not_active" | "organization_already_subscribed" | "organization_not_subscribed" | "license_key_used_by_another_instance" | "translation_spending_limit_exceeded" | "credit_spending_limit_exceeded" | "seats_spending_limit_exceeded" | "this_instance_is_already_licensed" | "big_meta_not_from_project" | "mt_service_not_enabled" | "project_not_selected" | "organization_not_selected" | "plan_has_subscribers" | "translation_failed" | "batch_job_not_found" | "key_exists_in_namespace" | "tag_is_blank" | "execution_failed_on_management_error" | "translation_api_rate_limit" | "cannot_finalize_activity" | "formality_not_supported_by_service" | "language_not_supported_by_service" | "rate_limited" | "pat_access_not_allowed" | "pak_access_not_allowed" | "cannot_modify_disabled_translation" | "azure_config_required" | "s3_config_required" | "content_storage_config_required" | "content_storage_test_failed" | "content_storage_config_invalid" | "invalid_connection_string" | "cannot_create_azure_storage_client" | "s3_access_key_required" | "azure_connection_string_required" | "s3_secret_key_required" | "cannot_store_file_to_content_storage" | "unexpected_error_while_publishing_to_content_storage" | "webhook_responded_with_non_200_status" | "unexpected_error_while_executing_webhook" | "content_storage_is_in_use" | "cannot_set_state_for_missing_translation" | "no_project_id_provided" | "license_key_not_provided" | "subscription_already_canceled" | "user_is_subscribed_to_paid_plan" | "cannot_create_free_plan_without_fixed_type" | "cannot_modify_plan_free_status" | "key_id_not_provided" | "free_self_hosted_seat_limit_exceeded" | "advanced_params_not_supported" | "plural_forms_not_found_for_language" | "nested_plurals_not_supported" | "message_is_not_plural" | "content_outside_plural_forms" | "invalid_plural_form" | "multiple_plurals_not_supported" | "custom_values_json_too_long" | "unsupported_po_message_format" | "plural_forms_data_loss" | "current_user_does_not_own_image" | "user_cannot_view_this_organization" | "user_is_not_owner_of_organization" | "user_is_not_owner_or_maintainer_of_organization" | "pak_created_for_different_project" | "custom_slug_is_only_applicable_for_custom_storage" | "invalid_slug_format" | "batch_job_cancellation_timeout" | "import_failed" | "cannot_add_more_then_1000_languages" | "no_data_to_import" | "multiple_namespaces_mapped_to_single_file" | "multiple_mappings_for_same_file_language_name" | "multiple_mappings_for_null_file_language_name" | "too_many_mappings_for_file" | "missing_placeholder_in_template" | "tag_not_found" | "cannot_parse_encrypted_slack_login_data" | "slack_workspace_not_found" | "cannot_fetch_user_details_from_slack" | "slack_missing_scope" | "slack_not_connected_to_your_account" | "slack_invalid_command" | "slack_not_subscribed_yet" | "slack_connection_failed" | "tolgee_account_already_connected" | "slack_not_configured" | "slack_workspace_already_connected" | "slack_connection_error" | "email_verification_code_not_valid" | "cannot_subscribe_to_free_plan" | "plan_auto_assignment_only_for_free_plans" | "plan_auto_assignment_only_for_private_plans" | "task_not_found" | "task_not_finished" | "task_not_open" | "translation_agency_not_found" | "this_feature_is_not_implemented_in_oss" | "sso_token_exchange_failed" | "sso_user_info_retrieval_failed" | "sso_id_token_expired" | "sso_user_cannot_create_organization" | "sso_cant_verify_user" | "sso_auth_missing_domain" | "sso_domain_not_found_or_disabled" | "authentication_method_disabled" | "native_authentication_disabled" | "invitation_organization_mismatch" | "user_is_managed_by_organization" | "cannot_set_sso_provider_missing_fields" | "namespaces_cannot_be_disabled_when_namespace_exists" | "namespace_cannot_be_used_when_feature_is_disabled" | "sso_domain_not_allowed" | "sso_login_forced_for_this_account" | "use_sso_for_authentication_instead" | "date_has_to_be_in_the_future" | "custom_plan_and_plan_id_cannot_be_set_together" | "specify_plan_id_or_custom_plan" | "custom_plans_has_to_be_private" | "cannot_create_free_plan_with_prices" | "subscription_not_scheduled_for_cancellation" | "cannot_cancel_trial" | "cannot_update_without_modification" | "current_subscription_is_not_trialing" | "sorting_and_paging_is_not_supported_when_using_cursor" | "strings_metric_are_not_supported" | "plan_key_limit_exceeded" | "keys_spending_limit_exceeded" | "plan_seat_limit_exceeded" | "instance_not_using_license_key" | "invalid_path" | "llm_provider_not_found" | "llm_provider_error" | "prompt_not_found" | "llm_provider_not_returned_json" | "llm_template_parsing_error" | "llm_rate_limited" | "llm_provider_timeout" | "no_llm_provider_configured" | "glossary_not_found" | "glossary_term_not_found" | "glossary_term_translation_not_found" | "glossary_non_translatable_term_cannot_be_translated" | "llm_content_filter" | "llm_provider_empty_response" | "label_not_found" | "label_not_from_project" | "label_already_exists" | "filter_by_value_label_not_valid" | "suggestion_not_found" | "user_can_only_delete_his_suggestions" | "cannot_modify_reviewed_translation" | "cannot_modify_keys" | "expect_no_conflict_failed" | "suggestion_cant_be_plural" | "suggestion_must_be_plural" | "duplicate_suggestion" | "unsupported_media_type" | "impersonation_of_admin_by_supporter_not_allowed" | "already_impersonating_user" | "operation_not_permitted_in_read_only_mode" | "file_processing_failed"; + params?: unknown[]; + }; + ExistenceEntityDescription: { + data: { + [key: string]: unknown; + }; + entityClass: string; + /** Format: int64 */ + entityId: number; + exists?: boolean; + relations: { + [key: string]: components["schemas"]["EntityDescriptionWithRelations"]; + }; + }; + ExportParams: { /** - * @description Object mapping language tag to translation - * @example { - * "en": "What a translated value!", - * "cs": "Jaká to přeložená hodnota!" - * } + * @description If true, HTML tags are escaped in the exported file. (Supported in the XLIFF format only). + * + * e.g. Key hello will be exported as <b>hello</b> */ - translations: { - [key: string]: string; - }; + escapeHtml?: boolean; /** - * @description List of languages to return translations for. + * @description This is a template that defines the structure of the resulting .zip file content. * - * If not provided, only modified translation will be provided. + * The template is a string that can contain the following placeholders: {namespace}, {languageTag}, + * {androidLanguageTag}, {snakeLanguageTag}, {extension}. * - * @example [ - * "en", - * "de", - * "fr" - * ] + * For example, when exporting to JSON with the template `{namespace}/{languageTag}.{extension}`, + * the English translations of the `home` namespace will be stored in `home/en.json`. + * + * The `{snakeLanguageTag}` placeholder is the same as `{languageTag}` but in snake case. (e.g., en_US). + * + * The Android specific `{androidLanguageTag}` placeholder is the same as `{languageTag}` + * but in Android format. (e.g., en-rUS) */ - languagesToReturn?: string[]; - }; - SetTranslationsResponseModel: { + fileStructureTemplate?: string; + /** @description Filter key IDs to be contained in export */ + filterKeyId?: number[]; + /** @description Filter key IDs not to be contained in export */ + filterKeyIdNot?: number[]; + /** @description Filter keys with prefix */ + filterKeyPrefix?: string; + /** @description Filter translations with namespace. By default, all namespaces everything are exported. To export default namespace, use empty string. */ + filterNamespace?: string[]; + /** @description Filter translations with state. By default, all states except untranslated is exported. */ + filterState?: ("UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED")[]; /** - * Format: int64 - * @description Id of key record + * @description Filter keys tagged by. + * + * This filter works the same as `filterTagIn` but in this cases it accepts single tag only. */ - keyId: number; + filterTag?: string; + /** @description Filter keys tagged by one of provided tags */ + filterTagIn?: string[]; + /** @description Filter keys not tagged by one of provided tags */ + filterTagNotIn?: string[]; /** - * @description Name of key - * @example this_is_super_key + * @description Format to export to + * @enum {string} */ - keyName: string; + format: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX" | "APPLE_XCSTRINGS" | "ANDROID_SDK" | "APPLE_SDK"; /** - * @description The namespace of the key - * @example homepage + * @description Languages to be contained in export. + * + * If null, all languages are exported + * @example en */ - keyNamespace?: string; - keyIsPlural: boolean; + languages?: string[]; /** - * @description Translations object containing values updated in this request - * @example { - * "en": { - * "id": 100000003, - * "text": "This is super translation!" - * } - * } + * @description Message format to be used for export. + * + * e.g. PHP_PO: Hello %s, ICU: Hello {name}. + * + * This property is honored only for generic formats like JSON or YAML. + * For specific formats like `YAML_RUBY` it's ignored. + * @enum {string} */ - translations: { - [key: string]: components["schemas"]["TranslationModel"]; - }; + messageFormat?: "C_SPRINTF" | "PHP_SPRINTF" | "JAVA_STRING_FORMAT" | "APPLE_SPRINTF" | "RUBY_SPRINTF" | "I18NEXT" | "ICU" | "PYTHON_PERCENT"; + /** + * @description Delimiter to structure file content. + * + * e.g. For key "home.header.title" would result in {"home": {"header": "title": {"Hello"}}} structure. + * + * When null, resulting file won't be structured. Works only for generic structured formats (e.g. JSON, YAML), + * specific formats like `YAML_RUBY` don't honor this parameter. + */ + structureDelimiter?: string; + /** + * @description If true, for structured formats (like JSON) arrays are supported. + * + * e.g. Key hello[0] will be exported as {"hello": ["..."]} + */ + supportArrays: boolean; + zip: boolean; }; - LanguageRequest: { + GetKeysRequestDto: { + keys: components["schemas"]["KeyDefinitionDto"][]; + /** @description Tags to return language translations in */ + languageTags: string[]; + }; + GlossaryImportResult: { /** - * @description Language name in english - * @example Czech + * Format: int32 + * @description Number of imported terms + * @example 42 */ - name: string; + imported: number; + }; + GlossaryLanguageDto: { /** - * @description Language name in this language - * @example čeština + * @description Indicates if this is the base (main) language of the glossary + * @example true */ - originalName: string; + base: boolean; /** - * @description Language tag according to BCP 47 definition - * @example cs-CZ + * @description The language code (e.g., 'en' for English) + * @example en */ tag: string; + }; + GlossaryModel: { /** - * @description Language flag emoji as UTF-8 emoji - * @example 🇨🇿 + * @description Language tag for default translations for terms + * @example en */ - flagEmoji?: string; - }; - OrganizationDto: { - /** @example Beautiful organization */ + baseLanguageTag: string; + /** Format: int64 */ + id: number; name: string; - /** @example This is a beautiful organization full of beautiful and clever people */ - description?: string; - /** @example btforg */ - slug?: string; + organizationOwner: components["schemas"]["SimpleOrganizationModel"]; }; - OrganizationModel: { + GlossaryTermModel: { + description: string; + /** @description Specifies whether the term represents a shortened form of a word or phrase */ + flagAbbreviation: boolean; + /** @description When true, the term matching considers uppercase and lowercase characters as distinct */ + flagCaseSensitive: boolean; + /** @description When true, marks this term as prohibited or not recommended for use in translations */ + flagForbiddenTerm: boolean; + /** @description When true, this term has the same translation across all target languages */ + flagNonTranslatable: boolean; + glossary: components["schemas"]["GlossaryModel"]; /** Format: int64 */ id: number; - /** @example Beautiful organization */ - name: string; - /** @example btforg */ - slug: string; - /** @example This is a beautiful organization full of beautiful and clever people */ - description?: string; - basePermissions: components["schemas"]["PermissionModel"]; + translations: components["schemas"]["GlossaryTermTranslationModel"][]; + }; + GlossaryTermTranslationModel: { + languageTag: string; + text: string; + }; + ImageUploadInfoDto: { + location?: string; + }; + ImportAddFilesResultModel: { + errors: components["schemas"]["ErrorResponseBody"][]; + result?: components["schemas"]["PagedModelImportLanguageModel"]; + warnings: components["schemas"]["ErrorResponseBody"][]; + }; + ImportFileIssueModel: { + /** Format: int64 */ + id: number; + params: components["schemas"]["ImportFileIssueParamModel"][]; + /** @enum {string} */ + type: "KEY_IS_NOT_STRING" | "MULTIPLE_VALUES_FOR_KEY_AND_LANGUAGE" | "VALUE_IS_NOT_STRING" | "KEY_IS_EMPTY" | "VALUE_IS_EMPTY" | "PO_MSGCTXT_NOT_SUPPORTED" | "ID_ATTRIBUTE_NOT_PROVIDED" | "TARGET_NOT_PROVIDED" | "TRANSLATION_TOO_LONG" | "KEY_IS_BLANK" | "TRANSLATION_DEFINED_IN_ANOTHER_FILE" | "INVALID_CUSTOM_VALUES" | "DESCRIPTION_TOO_LONG"; + }; + ImportFileIssueParamModel: { + /** @enum {string} */ + type: "KEY_NAME" | "KEY_ID" | "LANGUAGE_ID" | "KEY_INDEX" | "VALUE" | "LINE" | "FILE_NODE_ORIGINAL" | "LANGUAGE_NAME"; + value?: string; + }; + ImportFileMapping: { + /** @description Name of the file to import. This is the name of the file provided in `files` request part or in uploaded archive. */ + fileName: string; /** - * @description The role of currently authorized user. + * @description Format of the file. If not provided, Tolgee will try to guess the format from the file name or file contents. * - * Can be null when user has direct access to one of the projects owned by the organization. + * It is recommended to provide these values to prevent any issues with format detection. * @enum {string} */ - currentUserRole?: "MEMBER" | "OWNER"; - avatar?: components["schemas"]["Avatar"]; - }; - CreateProjectRequest: { - name: string; - languages: components["schemas"]["LanguageRequest"][]; - /** @description Slug of your project used in url e.g. "/v2/projects/what-a-project". If not provided, it will be generated */ - slug?: string; + format?: "CSV_ICU" | "CSV_JAVA" | "CSV_PHP" | "CSV_RUBY" | "JSON_I18NEXT" | "JSON_ICU" | "JSON_JAVA" | "JSON_PHP" | "JSON_RUBY" | "JSON_C" | "PO_PHP" | "PO_C" | "PO_JAVA" | "PO_ICU" | "PO_RUBY" | "PO_PYTHON" | "STRINGS" | "STRINGSDICT" | "APPLE_XLIFF" | "APPLE_XCSTRINGS" | "PROPERTIES_ICU" | "PROPERTIES_JAVA" | "PROPERTIES_UNKNOWN" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "YAML_RUBY" | "YAML_JAVA" | "YAML_ICU" | "YAML_PHP" | "YAML_UNKNOWN" | "XLIFF_ICU" | "XLIFF_JAVA" | "XLIFF_PHP" | "XLIFF_RUBY" | "RESX_ICU" | "XLSX_ICU" | "XLSX_JAVA" | "XLSX_PHP" | "XLSX_RUBY"; /** - * Format: int64 - * @description Organization to create the project in + * @description The existing language tag in the Tolgee platform to which the imported language should be mapped. + * + * When null, Tolgee will try to guess the language from the file contents or file name. */ - organizationId: number; - /** @description Tag of one of created languages, to select it as base language. If not provided, first language will be selected as base. */ - baseLanguageTag?: string; - /** @description Whether to use ICU placeholder visualization in the editor and it's support. */ - icuPlaceholders: boolean; + languageTag?: string; + /** + * @description Tags of languages to be imported. When null, all languages from will be imported. + * + * This field is useful when the file contains multiple languages and you want to import only some of them. For example when importing Apple String Catalog (APPLE_XCSTRINGS), you might want only to import the base language. + */ + languageTagsToImport?: string[]; + /** @description Namespace to import the file to. If not provided, the key will be imported without namespace. */ + namespace?: string; }; - CreateMultipleTasksRequest: { - tasks: components["schemas"]["CreateTaskRequest"][]; + ImportKeysDto: { + keys: components["schemas"]["ImportKeysItemDto"][]; }; - CreateTaskRequest: { - name: string; - description: string; - /** @enum {string} */ - type: "TRANSLATE" | "REVIEW"; + ImportKeysItemDto: { /** - * Format: int64 - * @description Due to date in epoch format (milliseconds). - * @example 1661172869000 + * @description Description of key + * @example This key is used on homepage. It's a label of sign up button. */ - dueDate?: number; + description?: string; /** - * Format: int64 - * @description Id of language, this task is attached to. - * @example 1 + * @description Key name to set translations for + * @example what_a_key_to_translate */ - languageId: number; - assignees: number[]; - keys: number[]; - }; - CalculateScopeRequest: { - /** Format: int64 */ - languageId: number; - /** @enum {string} */ - type: "TRANSLATE" | "REVIEW"; - keys: number[]; - }; - KeysScopeView: { - /** Format: int64 */ - keyCount: number; - /** Format: int64 */ - characterCount: number; - /** Format: int64 */ - wordCount: number; - /** Format: int64 */ - keyCountIncludingConflicts: number; - }; - GetKeysRequestDto: { - keys: components["schemas"]["KeyDefinitionDto"][]; - /** @description Tags to return language translations in */ - languageTags: string[]; - }; - KeyDefinitionDto: { name: string; + /** @description The namespace of the key. (When empty or null default namespace will be used) */ namespace?: string; - }; - CollectionModelKeyWithDataModel: { - _embedded?: { - keys?: components["schemas"]["KeyWithDataModel"][]; + /** + * @description Tags of the key + * @example [ + * "homepage", + * "user-profile" + * ] + */ + tags?: string[]; + /** + * @description Object mapping language tag to translation + * @example { + * "en": "What a translated value!", + * "cs": "Jaká to přeložená hodnota!" + * } + */ + translations: { + [key: string]: string; }; }; ImportKeysResolvableDto: { @@ -1436,24 +1617,114 @@ export interface components { [key: string]: components["schemas"]["ImportTranslationResolvableDto"]; }; }; - /** @description Object mapping language tag to translation */ - ImportTranslationResolvableDto: { + ImportLanguageModel: { + /** Format: int32 */ + conflictCount: number; /** - * @description Translation text - * @example Hello! I am a translation! + * @deprecated + * @description Use existingLanguageTag */ - text: string; + existingLanguageAbbreviation?: string; + /** Format: int64 */ + existingLanguageId?: number; + existingLanguageName?: string; + existingLanguageTag?: string; + /** Format: int64 */ + id: number; + /** Format: int64 */ + importFileId: number; + /** Format: int32 */ + importFileIssueCount: number; + importFileName: string; + name: string; + namespace?: string; + /** Format: int32 */ + resolvedCount: number; + /** Format: int32 */ + totalCount: number; + }; + ImportNamespaceModel: { + /** + * Format: int64 + * @description The id of namespace. When null, namespace doesn't exist and will be created by import. + * @example 10000048 + */ + id?: number; + /** @example homepage */ + name: string; + }; + ImportResult: { + unresolvedConflicts?: components["schemas"]["SimpleImportConflictResult"][]; + }; + ImportSettingsModel: { + /** @description If true, placeholders from other formats will be converted to ICU when possible */ + convertPlaceholdersToIcu: boolean; + /** @description If false, only updates keys, skipping the creation of new keys */ + createNewKeys: boolean; + /** @description If true, key descriptions will be overridden by the import */ + overrideKeyDescriptions: boolean; + }; + ImportSettingsRequest: { + /** @description If true, placeholders from other formats will be converted to ICU when possible */ + convertPlaceholdersToIcu: boolean; + /** @description If false, only updates keys, skipping the creation of new keys */ + createNewKeys: boolean; + /** @description If true, key descriptions will be overridden by the import */ + overrideKeyDescriptions: boolean; + }; + ImportTranslationModel: { + /** Format: int64 */ + conflictId?: number; + conflictText?: string; + /** @enum {string} */ + conflictType?: "SHOULD_NOT_EDIT_REVIEWED" | "CANNOT_EDIT_REVIEWED" | "CANNOT_EDIT_DISABLED"; + existingKeyIsPlural: boolean; + /** Format: int64 */ + id: number; + isOverridable: boolean; + isPlural: boolean; + keyDescription?: string; + /** Format: int64 */ + keyId: number; + keyName: string; + override: boolean; + resolved: boolean; + text?: string; + }; + ImportTranslationResolvableDto: { /** * @description Determines, how conflict is resolved. - * - * - KEEP: Translation is not changed - * - OVERRIDE: Translation is overridden - * - NEW: New translation is created) + * - KEEP: Translation is not changed + * - OVERRIDE: Translation is overridden + * - NEW: New translation is created + * - FORCE_OVERRIDE: Translation is updated, created or kept. * * @example OVERRIDE * @enum {string} */ - resolution: "KEEP" | "OVERRIDE" | "NEW"; + resolution: "KEEP" | "OVERRIDE" | "NEW" | "FORCE_OVERRIDE"; + /** + * @description Translation text + * @example Hello! I am a translation! + */ + text: string; + }; + JwtAuthenticationResponse: { + accessToken?: string; + tokenType?: string; + }; + KeyDefinitionDto: { + name: string; + namespace?: string; + }; + KeyId: { + /** + * Format: int64 + * @description If key id is provided, name and namespace are ignored. + */ + id?: number; + name?: string; + namespace?: string; }; KeyImportResolvableResultModel: { /** @description List of keys */ @@ -1463,772 +1734,623 @@ export interface components { [key: string]: components["schemas"]["ScreenshotModel"]; }; }; - ImportKeysDto: { - keys: components["schemas"]["ImportKeysItemDto"][]; + KeyInScreenshotModel: { + /** Format: int64 */ + keyId: number; + keyName: string; + keyNamespace?: string; + originalText?: string; + position?: components["schemas"]["KeyInScreenshotPosition"]; }; - ImportKeysItemDto: { - /** - * @description Key name to set translations for - * @example what_a_key_to_translate - */ - name: string; - /** @description The namespace of the key. (When empty or null default namespace will be used) */ - namespace?: string; - /** - * @description Description of key - * @example This key is used on homepage. It's a label of sign up button. - */ - description?: string; - /** - * @description Object mapping language tag to translation - * @example { - * "en": "What a translated value!", - * "cs": "Jaká to přeložená hodnota!" - * } - */ - translations: { - [key: string]: string; - }; - /** - * @description Tags of the key - * @example [ - * "homepage", - * "user-profile" - * ] - */ - tags?: string[]; + KeyInScreenshotPosition: { + /** Format: int32 */ + height: number; + /** Format: int32 */ + width: number; + /** Format: int32 */ + x: number; + /** Format: int32 */ + y: number; }; - CreateKeyDto: { - /** @description Name of the key */ - name: string; - namespace?: string; - translations?: { - [key: string]: string; - }; - /** @description Translation states to update, if not provided states won't be modified */ - states?: { - [key: string]: "TRANSLATED" | "REVIEWED"; + KeyInScreenshotPositionDto: { + /** Format: int32 */ + height: number; + /** Format: int32 */ + width: number; + /** Format: int32 */ + x: number; + /** Format: int32 */ + y: number; + }; + KeyModel: { + /** @description Custom values of the key */ + custom?: { + [key: string]: unknown; }; - tags?: string[]; - /** @description Ids of screenshots uploaded with /v2/image-upload endpoint */ - screenshotUploadedImageIds?: number[]; - screenshots?: components["schemas"]["KeyScreenshotDto"][]; - /** @description Keys in the document used as a context for machine translation. Keys in the same order as they appear in the document. The order is important! We are using it for graph distance calculation. */ - relatedKeysInOrder?: components["schemas"]["RelatedKeyDto"][]; /** - * @description Description of the key + * @description Description of key * @example This key is used on homepage. It's a label of sign up button. */ description?: string; - /** @description If key is pluralized. If it will be reflected in the editor */ - isPlural: boolean; - /** @description The argument name for the plural. If null, value will be guessed from the values provided in translations. */ - pluralArgName?: string; - }; - UntagKeysRequest: { - keyIds: number[]; - tags: string[]; - }; - BatchJobModel: { /** * Format: int64 - * @description Batch job id + * @description Id of key record */ id: number; /** - * @description Status of the batch job - * @enum {string} - */ - status: "PENDING" | "RUNNING" | "SUCCESS" | "FAILED" | "CANCELLED" | "DEBOUNCED"; - /** - * @description Type of the batch job - * @enum {string} - */ - type: "PRE_TRANSLATE_BT_TM" | "MACHINE_TRANSLATE" | "AUTO_TRANSLATE" | "DELETE_KEYS" | "SET_TRANSLATIONS_STATE" | "CLEAR_TRANSLATIONS" | "COPY_TRANSLATIONS" | "TAG_KEYS" | "UNTAG_KEYS" | "SET_KEYS_NAMESPACE" | "AUTOMATION"; - /** - * Format: int32 - * @description Total items, that have been processed so far - */ - progress: number; - /** - * Format: int32 - * @description Total items + * @description Name of key + * @example this_is_super_key */ - totalItems: number; - author?: components["schemas"]["SimpleUserAccountModel"]; + name: string; /** - * Format: int64 - * @description The time when the job created + * @description Namespace of key + * @example homepage */ - createdAt: number; + namespace?: string; + }; + KeyScreenshotDto: { + positions?: components["schemas"]["KeyInScreenshotPositionDto"][]; + text?: string; /** * Format: int64 - * @description The time when the job was last updated (status change) + * @description Ids of screenshot uploaded with /v2/image-upload endpoint */ - updatedAt: number; - /** - * Format: int64 - * @description The activity revision id, that stores the activity details of the job - */ - activityRevisionId?: number; - /** @description If the job failed, this is the error message */ - errorMessage?: string; - }; - TagKeysRequest: { - keyIds: number[]; - tags: string[]; - }; - SetTranslationsStateStateRequest: { - keyIds: number[]; - languageIds: number[]; - /** @enum {string} */ - state: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + uploadedImageId: number; }; - SetKeysNamespaceRequest: { - keyIds: number[]; + KeySearchResultView: { + baseTranslation?: string; + description?: string; + /** Format: int64 */ + id: number; + name: string; namespace?: string; + translation?: string; }; - PreTranslationByTmRequest: { - keyIds: number[]; - targetLanguageIds: number[]; - }; - MachineTranslationRequest: { - keyIds: number[]; - targetLanguageIds: number[]; - }; - DeleteKeysRequest: { - keyIds: number[]; - }; - CopyTranslationRequest: { - keyIds: number[]; + KeySearchSearchResultModel: { + baseTranslation?: string; + description?: string; /** Format: int64 */ - sourceLanguageId: number; - targetLanguageIds: number[]; + id: number; + name: string; + namespace?: string; + translation?: string; + view?: components["schemas"]["KeySearchResultView"]; }; - ClearTranslationsRequest: { - keyIds: number[]; - languageIds: number[]; + KeyTaskViewModel: { + done: boolean; + /** Format: int64 */ + languageId: number; + languageTag: string; + /** Format: int64 */ + number: number; + /** @enum {string} */ + type: "TRANSLATE" | "REVIEW"; + userAssigned: boolean; }; - /** @description Definition of mapping for each file to import. */ - ImportFileMapping: { - /** @description Name of the file to import. This is the name of the file provided in `files` request part or in uploaded archive. */ - fileName: string; - /** @description Namespace to import the file to. If not provided, the key will be imported without namespace. */ - namespace?: string; + KeyWithBaseTranslationModel: { /** - * @description Format of the file. If not provided, Tolgee will try to guess the format from the file name or file contents. - * - * It is recommended to provide these values to prevent any issues with format detection. - * @enum {string} + * @description Base translation + * @example This is translation */ - format?: "JSON_I18NEXT" | "JSON_ICU" | "JSON_JAVA" | "JSON_PHP" | "JSON_RUBY" | "JSON_C" | "PO_PHP" | "PO_C" | "PO_JAVA" | "PO_ICU" | "PO_RUBY" | "STRINGS" | "STRINGSDICT" | "APPLE_XLIFF" | "PROPERTIES_ICU" | "PROPERTIES_JAVA" | "PROPERTIES_UNKNOWN" | "ANDROID_XML" | "FLUTTER_ARB" | "YAML_RUBY" | "YAML_JAVA" | "YAML_ICU" | "YAML_PHP" | "YAML_UNKNOWN" | "XLIFF_ICU" | "XLIFF_JAVA" | "XLIFF_PHP" | "XLIFF_RUBY"; + baseTranslation?: string; /** - * @description The existing language tag in the Tolgee platform to which the imported language should be mapped. - * - * When null, Tolgee will try to guess the language from the file contents or file name. + * Format: int64 + * @description Id of key record */ - languageTag?: string; - }; - /** - * @description Maps the languages from imported files to languages existing in the Tolgee platform. - * - * Use this field only when your files contain multiple languages (e.g., XLIFF files). - * - * Otherwise, use the `languageTag` property of `fileMappings`. - * - * Example: In xliff files, there are `source-language` and `target-language` attributes defined on `file` element. Using this field you can map source and target values to languages stored in the Tolgee Platform. - */ - LanguageMapping: { + id: number; /** - * @description The language from the imported file. - * - * For xliff files, this is the `source-language` or the `target-language` attribute value of `file` element. - * @example en-US + * @description Name of key + * @example this_is_super_key */ - importLanguage: string; + name: string; /** - * @description The tag of language existing in the Tolgee platform to which the imported language should be mapped. - * @example en-US + * @description Namespace of key + * @example homepage */ - platformLanguageTag: string; + namespace?: string; }; - SingleStepImportRequest: { + KeyWithDataModel: { + /** @description Custom values of the key */ + custom: { + [key: string]: unknown; + }; /** - * @description When importing files in structured formats (e.g., JSON, YAML), this field defines the delimiter which will be used in names of imported keys. - * @example . + * @description Description of key + * @example This key is used on homepage. It's a label of sign up button. */ - structureDelimiter?: string; + description?: string; /** - * @description Whether to override existing translation data. - * - * When set to `KEEP`, existing translations will be kept. - * - * When set to `OVERRIDE`, existing translations will be overwrote. - * - * When set to `NO_FORCE`, error will be thrown on conflict. - * @enum {string} + * Format: int64 + * @description Id of key record */ - forceMode: "OVERRIDE" | "KEEP" | "NO_FORCE"; + id: number; + /** @description If key is pluralized. If it will be reflected in the editor */ + isPlural: boolean; /** - * @description Maps the languages from imported files to languages existing in the Tolgee platform. - * - * Use this field only when your files contain multiple languages (e.g., XLIFF files). - * - * Otherwise, use the `languageTag` property of `fileMappings`. - * - * Example: In xliff files, there are `source-language` and `target-language` attributes defined on `file` element. Using this field you can map source and target values to languages stored in the Tolgee Platform. + * @description Name of key + * @example this_is_super_key */ - languageMappings?: components["schemas"]["LanguageMapping"][]; - /** @description If true, key descriptions will be overridden by the import */ - overrideKeyDescriptions: boolean; - /** @description If true, placeholders from other formats will be converted to ICU when possible */ - convertPlaceholdersToIcu: boolean; - /** @description If false, only updates keys, skipping the creation of new keys */ - createNewKeys: boolean; - /** @description Definition of mapping for each file to import. */ - fileMappings: components["schemas"]["ImportFileMapping"][]; - /** @description Keys created by this import will be tagged with these tags. It add tags only to new keys. The keys that already exist will not be tagged. */ - tagNewKeys: string[]; - /** @description If yes, keys from project that were not included in import will be deleted. */ - removeOtherKeys?: boolean; - }; - ImportAddFilesResultModel: { - errors: components["schemas"]["ErrorResponseBody"][]; - result?: components["schemas"]["PagedModelImportLanguageModel"]; - }; - ImportLanguageModel: { - /** Format: int64 */ - id: number; name: string; - /** Format: int64 */ - existingLanguageId?: number; - existingLanguageTag?: string; - existingLanguageAbbreviation?: string; - existingLanguageName?: string; - importFileName: string; - /** Format: int64 */ - importFileId: number; - /** Format: int32 */ - importFileIssueCount: number; + /** + * @description Namespace of key + * @example homepage + */ namespace?: string; - /** Format: int32 */ - totalCount: number; - /** Format: int32 */ - conflictCount: number; - /** Format: int32 */ - resolvedCount: number; - }; - PageMetadata: { - /** Format: int64 */ - size?: number; - /** Format: int64 */ - totalElements?: number; - /** Format: int64 */ - totalPages?: number; - /** Format: int64 */ - number?: number; - }; - PagedModelImportLanguageModel: { - _embedded?: { - languages?: components["schemas"]["ImportLanguageModel"][]; + /** @description The argument name for the plural */ + pluralArgName?: string; + /** @description Screenshots of the key */ + screenshots: components["schemas"]["ScreenshotModel"][]; + /** @description Tags of key */ + tags: components["schemas"]["TagModel"][]; + /** + * @description Translations object containing values updated in this request + * @example { + * "en": { + * "id": 100000003, + * "text": "This is super translation!" + * } + * } + */ + translations: { + [key: string]: components["schemas"]["TranslationModel"]; }; - page?: components["schemas"]["PageMetadata"]; }; - ExportParams: { + KeyWithTranslationsModel: { + /** @description There is a context available for this key */ + contextPresent: boolean; /** - * @description Languages to be contained in export. - * - * If null, all languages are exported - * @example en + * Format: int64 + * @description The time when the key was created */ - languages?: string[]; + createdAt: number; /** - * @description Format to export to - * @enum {string} + * @description The namespace of the key + * @example homepage */ - format: "JSON" | "JSON_TOLGEE" | "JSON_I18NEXT" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "ANDROID_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML"; + keyDescription?: string; /** - * @description Delimiter to structure file content. - * - * e.g. For key "home.header.title" would result in {"home": {"header": "title": {"Hello"}}} structure. - * - * When null, resulting file won't be structured. Works only for generic structured formats (e.g. JSON, YAML), - * specific formats like `YAML_RUBY` don't honor this parameter. + * Format: int64 + * @description Id of key record */ - structureDelimiter?: string; - /** @description Filter key IDs to be contained in export */ - filterKeyId?: number[]; - /** @description Filter key IDs not to be contained in export */ - filterKeyIdNot?: number[]; + keyId: number; /** - * @description Filter keys tagged by. - * - * This filter works the same as `filterTagIn` but in this cases it accepts single tag only. + * @description Is this key a plural? + * @example true */ - filterTag?: string; - /** @description Filter keys tagged by one of provided tags */ - filterTagIn?: string[]; - /** @description Filter keys not tagged by one of provided tags */ - filterTagNotIn?: string[]; - /** @description Filter keys with prefix */ - filterKeyPrefix?: string; - /** @description Filter translations with state. By default, all states except untranslated is exported. */ - filterState?: ("UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED")[]; - /** @description Filter translations with namespace. By default, all namespaces everything are exported. To export default namespace, use empty string. */ - filterNamespace?: string[]; - zip: boolean; + keyIsPlural: boolean; /** - * @description Message format to be used for export. - * - * e.g. PHP_PO: Hello %s, ICU: Hello {name}. - * - * This property is honored only for generic formats like JSON or YAML. - * For specific formats like `YAML_RUBY` it's ignored. - * @enum {string} + * @description Name of key + * @example this_is_super_key */ - messageFormat?: "C_SPRINTF" | "PHP_SPRINTF" | "JAVA_STRING_FORMAT" | "APPLE_SPRINTF" | "RUBY_SPRINTF" | "I18NEXT" | "ICU"; + keyName: string; /** - * @description This is a template that defines the structure of the resulting .zip file content. - * - * The template is a string that can contain the following placeholders: {namespace}, {languageTag}, - * {androidLanguageTag}, {snakeLanguageTag}, {extension}. - * - * For example, when exporting to JSON with the template `{namespace}/{languageTag}.{extension}`, - * the English translations of the `home` namespace will be stored in `home/en.json`. - * - * The `{snakeLanguageTag}` placeholder is the same as `{languageTag}` but in snake case. (e.g., en_US). - * - * The Android specific `{androidLanguageTag}` placeholder is the same as `{languageTag}` - * but in Android format. (e.g., en-rUS) + * @description The namespace of the key + * @example homepage */ - fileStructureTemplate?: string; + keyNamespace?: string; /** - * @description If true, for structured formats (like JSON) arrays are supported. - * - * e.g. Key hello[0] will be exported as {"hello": ["..."]} + * Format: int64 + * @description The namespace id of the key + * @example 100000282 */ - supportArrays: boolean; - }; - BigMetaDto: { - /** @description Keys in the document used as a context for machine translation. Keys in the same order as they appear in the document. The order is important! We are using it for graph distance calculation. */ - relatedKeysInOrder?: components["schemas"]["RelatedKeyDto"][]; - }; - TranslationCommentWithLangKeyDto: { - /** Format: int64 */ - keyId: number; - /** Format: int64 */ - languageId: number; - text: string; - /** @enum {string} */ - state: "RESOLUTION_NOT_NEEDED" | "NEEDS_RESOLUTION" | "RESOLVED"; - }; - TranslationWithCommentModel: { - translation: components["schemas"]["TranslationModel"]; - comment: components["schemas"]["TranslationCommentModel"]; - }; - SuggestRequestDto: { + keyNamespaceId?: number; + /** + * @description The placeholder name for plural parameter + * @example value + */ + keyPluralArgName?: string; + /** @description Tags of key */ + keyTags: components["schemas"]["TagModel"][]; /** * Format: int64 - * @description Key Id to get results for. Use when key is stored already. + * @description Count of screenshots provided for the key + * @example 1 */ - keyId?: number; - /** Format: int64 */ - targetLanguageId: number; - /** @description Text value of base translation. Useful, when base translation is not stored yet. */ - baseText?: string; - /** @description Whether base text is plural. This value is ignored if baseText is null. */ - isPlural?: boolean; - /** @description List of services to use. If null, then all enabled services are used. */ - services?: ("GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE")[]; - plural?: boolean; - }; - PagedModelTranslationMemoryItemModel: { - _embedded?: { - translationMemoryItems?: components["schemas"]["TranslationMemoryItemModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; - }; - TranslationMemoryItemModel: { - targetText: string; - baseText: string; - keyName: string; - /** Format: float */ - similarity: number; - }; - SuggestResultModel: { + screenshotCount: number; + /** @description Key screenshots. Not provided when API key hasn't screenshots.view scope permission. */ + screenshots?: components["schemas"]["ScreenshotModel"][]; + /** @description Tasks related to this key */ + tasks?: components["schemas"]["KeyTaskViewModel"][]; /** - * @deprecated - * @description String translations provided by enabled services. (deprecated, use `result` instead) + * @description Translations object * @example * { - * "GOOGLE": "This was translated by Google", - * "TOLGEE": "This was translated by Tolgee Translator", + * "en": { + * "id": 100000003, + * "text": "This is super translation!" + * "state": "TRANSLATED", + * "commentCount": 1 + * } * } */ - machineTranslations?: { - [key: string]: string; - }; - /** - * @description Results provided by enabled services. - * @example { - * "GOOGLE": { - * "output": "This was translated by Google", - * "contextDescription": null - * }, - * "TOLGEE": { - * "output": "This was translated by Tolgee Translator", - * "contextDescription": "This is an example in swagger" - * } - * } - */ - result?: { - [key: string]: components["schemas"]["TranslationItemModel"]; + translations: { + [key: string]: components["schemas"]["TranslationViewModel"]; }; - /** @description If true, the base translation was empty and no translation was provided. */ - baseBlank: boolean; - }; - /** - * @description Results provided by enabled services. - * @example { - * "GOOGLE": { - * "output": "This was translated by Google", - * "contextDescription": null - * }, - * "TOLGEE": { - * "output": "This was translated by Tolgee Translator", - * "contextDescription": "This is an example in swagger" - * } - * } - */ - TranslationItemModel: { - output: string; - contextDescription?: string; - }; - ScreenshotInfoDto: { - text?: string; - positions?: components["schemas"]["KeyInScreenshotPositionDto"][]; - location?: string; - }; - ImageUploadInfoDto: { - location?: string; }; - UploadedImageModel: { + KeysScopeView: { /** Format: int64 */ - id: number; - filename: string; - fileUrl: string; - requestFilename: string; - /** Format: date-time */ - createdAt: string; - location?: string; + characterCount: number; + /** Format: int64 */ + keyCount: number; + /** Format: int64 */ + keyCountIncludingConflicts: number; + /** Format: int64 */ + wordCount: number; }; - PagedModelTaskWithProjectModel: { + KeysWithTranslationsPageModel: { _embedded?: { - tasks?: components["schemas"]["TaskWithProjectModel"][]; + keys?: components["schemas"]["KeyWithTranslationsModel"][]; }; + /** + * @description Cursor to get next data + * @example eyJrZXlJZCI6eyJkaXJlY3Rpb24iOiJBU0MiLCJ2YWx1ZSI6IjEwMDAwMDAxMjAifX0= + */ + nextCursor?: string; page?: components["schemas"]["PageMetadata"]; + pagedModel?: components["schemas"]["PagedModelKeyWithTranslationsModel"]; + /** @description Provided languages data */ + selectedLanguages: components["schemas"]["LanguageModel"][]; }; - SimpleProjectModel: { + LabelModel: { + color: string; + description?: string; /** Format: int64 */ id: number; name: string; - description?: string; - slug?: string; - avatar?: components["schemas"]["Avatar"]; - baseLanguage?: components["schemas"]["LanguageModel"]; - icuPlaceholders: boolean; }; - TaskWithProjectModel: { - /** Format: int64 */ - number: number; + LabelRequest: { + /** + * @description Hex color in format #RRGGBB. + * @example #FF5733 + */ + color: string; + description?: string; name: string; - description: string; - /** @enum {string} */ - type: "TRANSLATE" | "REVIEW"; - language: components["schemas"]["LanguageModel"]; - /** Format: int64 */ - dueDate?: number; - assignees: components["schemas"]["SimpleUserAccountModel"][]; - /** Format: int64 */ - totalItems: number; - /** Format: int64 */ - doneItems: number; - /** Format: int64 */ - baseWordCount: number; - /** Format: int64 */ - baseCharacterCount: number; - author?: components["schemas"]["SimpleUserAccountModel"]; - /** Format: int64 */ - createdAt?: number; - /** Format: int64 */ - closedAt?: number; - /** @enum {string} */ - state: "NEW" | "IN_PROGRESS" | "DONE" | "CLOSED"; - project: components["schemas"]["SimpleProjectModel"]; - }; - PagedModelProjectModel: { - _embedded?: { - projects?: components["schemas"]["ProjectModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; }; - CollectionModelUsedNamespaceModel: { - _embedded?: { - namespaces?: components["schemas"]["UsedNamespaceModel"][]; - }; + LabelTranslationsRequest: { + keyIds: number[]; + labelIds: number[]; + languageIds: number[]; }; - UsedNamespaceModel: { + LanguageMapping: { /** - * Format: int64 - * @description The id of namespace. Null for default namespace. - * @example 10000048 + * @description The language from the imported file. + * + * For xliff files, this is the `source-language` or the `target-language` attribute value of `file` element. + * @example en-US */ - id?: number; + importLanguage: string; /** - * @description Name of namespace. Null if default. - * @example homepage + * @description The tag of language existing in the Tolgee platform to which the imported language should be mapped. + * @example en-US */ - name?: string; + platformLanguageTag: string; }; - TaskPerUserReportModel: { - user: components["schemas"]["SimpleUserAccountModel"]; - /** Format: int64 */ - doneItems: number; - /** Format: int64 */ - baseCharacterCount: number; - /** Format: int64 */ - baseWordCount: number; - }; - TaskKeysResponse: { - keys: number[]; - }; - PagedModelSimpleUserAccountModel: { - _embedded?: { - users?: components["schemas"]["SimpleUserAccountModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; - }; - PagedModelTaskModel: { - _embedded?: { - tasks?: components["schemas"]["TaskModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; - }; - PagedModelNamespaceModel: { - _embedded?: { - namespaces?: components["schemas"]["NamespaceModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; - }; - KeySearchResultView: { - description?: string; - name: string; + LanguageModel: { + /** + * @description Whether is base language of project + * @example false + */ + base: boolean; + /** + * @description Language flag emoji as UTF-8 emoji + * @example 🇨🇿 + */ + flagEmoji?: string; /** Format: int64 */ id: number; - baseTranslation?: string; - namespace?: string; - translation?: string; - }; - KeySearchSearchResultModel: { - view?: components["schemas"]["KeySearchResultView"]; - description?: string; + /** + * @description Language name in english + * @example Czech + */ name: string; - /** Format: int64 */ - id: number; - baseTranslation?: string; - namespace?: string; - translation?: string; - }; - PagedModelKeySearchSearchResultModel: { - _embedded?: { - keys?: components["schemas"]["KeySearchSearchResultModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; + /** + * @description Language name in this language + * @example čeština + */ + originalName?: string; + /** + * @description Language tag according to BCP 47 definition + * @example cs-CZ + */ + tag: string; }; - PagedModelKeyModel: { - _embedded?: { - keys?: components["schemas"]["KeyModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; + LanguageRequest: { + /** + * @description Language flag emoji as UTF-8 emoji + * @example 🇨🇿 + */ + flagEmoji?: string; + /** + * @description Language name in english + * @example Czech + */ + name: string; + /** + * @description Language name in this language + * @example čeština + */ + originalName: string; + /** + * @description Language tag according to BCP 47 definition + * @example cs-CZ + */ + tag: string; }; - EntityDescriptionWithRelations: { - entityClass: string; + LanguageStatsModel: { + languageFlagEmoji?: string; /** Format: int64 */ - entityId: number; - data: { - [key: string]: Record; - }; - }; - ExistenceEntityDescription: { - entityClass: string; + languageId?: number; + languageName?: string; + languageOriginalName?: string; + languageTag?: string; /** Format: int64 */ - entityId: number; - data: { - [key: string]: Record; - }; - relations: { - [key: string]: components["schemas"]["EntityDescriptionWithRelations"]; - }; - exists?: boolean; + reviewedKeyCount: number; + /** Format: double */ + reviewedPercentage: number; + /** Format: int64 */ + reviewedWordCount: number; + /** Format: int64 */ + translatedKeyCount: number; + /** Format: double */ + translatedPercentage: number; + /** Format: int64 */ + translatedWordCount: number; + /** Format: date-time */ + translationsUpdatedAt?: string; + /** Format: int64 */ + untranslatedKeyCount: number; + /** Format: double */ + untranslatedPercentage: number; + /** Format: int64 */ + untranslatedWordCount: number; + }; + MachineTranslationRequest: { + keyIds: number[]; + llmPrompt?: components["schemas"]["PromptDto"]; + targetLanguageIds: number[]; }; ModifiedEntityModel: { + description?: { + [key: string]: unknown; + }; entityClass: string; /** Format: int64 */ entityId: number; - description?: { - [key: string]: Record; - }; + exists?: boolean; modifications?: { [key: string]: components["schemas"]["PropertyModification"]; }; relations?: { [key: string]: components["schemas"]["ExistenceEntityDescription"]; }; - exists?: boolean; }; - PropertyModification: { - old?: Record; - new?: Record; + NamespaceModel: { + /** + * Format: int64 + * @description The id of namespace + * @example 10000048 + */ + id: number; + /** @example homepage */ + name: string; }; - ProjectActivityAuthorModel: { + NotificationModel: { + /** Format: date-time */ + createdAt?: string; /** Format: int64 */ id: number; - username?: string; - name?: string; + linkedTask?: components["schemas"]["TaskModel"]; + originatingUser?: components["schemas"]["SimpleUserAccountModel"]; + project?: components["schemas"]["SimpleProjectModel"]; + /** @enum {string} */ + type: "TASK_ASSIGNED" | "TASK_FINISHED" | "TASK_CANCELED" | "MFA_ENABLED" | "MFA_DISABLED" | "PASSWORD_CHANGED"; + }; + NotificationSettingGroupModel: { + email: boolean; + inApp: boolean; + }; + NotificationSettingModel: { + accountSecurity: components["schemas"]["NotificationSettingGroupModel"]; + tasks: components["schemas"]["NotificationSettingGroupModel"]; + }; + NotificationSettingsRequest: { + /** + * @example IN_APP + * @enum {string} + */ + channel: "IN_APP" | "EMAIL"; + /** + * @description True if the setting should be enabled, false for disabled + * @example false + */ + enabled: boolean; + /** + * @example TASKS + * @enum {string} + */ + group: "ACCOUNT_SECURITY" | "TASKS"; + }; + NotificationsMarkSeenRequest: { + /** + * @description Notification IDs to be marked as seen + * @example [ + * 1, + * 2, + * 3 + * ] + */ + notificationIds: number[]; + }; + OrganizationDto: { + /** @example This is a beautiful organization full of beautiful and clever people */ + description?: string; + /** @example Beautiful organization */ + name: string; + /** @example btforg */ + slug?: string; + }; + OrganizationModel: { + /** @example Links to avatar images */ avatar?: components["schemas"]["Avatar"]; - deleted: boolean; + basePermissions: components["schemas"]["PermissionModel"]; + /** + * @description The role of currently authorized user. + * + * Can be null when user has direct access to one of the projects owned by the organization. + * @enum {string} + */ + currentUserRole?: "MEMBER" | "OWNER" | "MAINTAINER"; + /** @example This is a beautiful organization full of beautiful and clever people */ + description?: string; + /** Format: int64 */ + id: number; + /** @example Beautiful organization */ + name: string; + /** @example btforg */ + slug: string; }; - ProjectActivityModel: { + PageMetadata: { /** Format: int64 */ - revisionId: number; + number?: number; /** Format: int64 */ - timestamp: number; - /** @enum {string} */ - type: "UNKNOWN" | "SET_TRANSLATION_STATE" | "SET_TRANSLATIONS" | "DISMISS_AUTO_TRANSLATED_STATE" | "SET_OUTDATED_FLAG" | "TRANSLATION_COMMENT_ADD" | "TRANSLATION_COMMENT_DELETE" | "TRANSLATION_COMMENT_EDIT" | "TRANSLATION_COMMENT_SET_STATE" | "SCREENSHOT_DELETE" | "SCREENSHOT_ADD" | "KEY_TAGS_EDIT" | "KEY_NAME_EDIT" | "KEY_DELETE" | "CREATE_KEY" | "COMPLEX_EDIT" | "IMPORT" | "CREATE_LANGUAGE" | "EDIT_LANGUAGE" | "DELETE_LANGUAGE" | "HARD_DELETE_LANGUAGE" | "CREATE_PROJECT" | "EDIT_PROJECT" | "NAMESPACE_EDIT" | "BATCH_PRE_TRANSLATE_BY_TM" | "BATCH_MACHINE_TRANSLATE" | "AUTO_TRANSLATE" | "BATCH_CLEAR_TRANSLATIONS" | "BATCH_COPY_TRANSLATIONS" | "BATCH_SET_TRANSLATION_STATE" | "BATCH_TAG_KEYS" | "BATCH_UNTAG_KEYS" | "BATCH_SET_KEYS_NAMESPACE" | "AUTOMATION" | "CONTENT_DELIVERY_CONFIG_CREATE" | "CONTENT_DELIVERY_CONFIG_UPDATE" | "CONTENT_DELIVERY_CONFIG_DELETE" | "CONTENT_STORAGE_CREATE" | "CONTENT_STORAGE_UPDATE" | "CONTENT_STORAGE_DELETE" | "WEBHOOK_CONFIG_CREATE" | "WEBHOOK_CONFIG_UPDATE" | "WEBHOOK_CONFIG_DELETE" | "COMPLEX_TAG_OPERATION" | "TASKS_CREATE" | "TASK_CREATE" | "TASK_UPDATE" | "TASK_KEYS_UPDATE" | "TASK_FINISH" | "TASK_CLOSE" | "TASK_REOPEN" | "TASK_KEY_UPDATE"; - author?: components["schemas"]["ProjectActivityAuthorModel"]; - modifiedEntities?: { - [key: string]: components["schemas"]["ModifiedEntityModel"][]; + size?: number; + /** Format: int64 */ + totalElements?: number; + /** Format: int64 */ + totalPages?: number; + }; + PagedModelBatchJobModel: { + _embedded?: { + batchJobs?: components["schemas"]["BatchJobModel"][]; }; - meta?: { - [key: string]: Record; + page?: components["schemas"]["PageMetadata"]; + }; + PagedModelImportFileIssueModel: { + _embedded?: { + importFileIssues?: components["schemas"]["ImportFileIssueModel"][]; }; - counts?: { - [key: string]: number; + page?: components["schemas"]["PageMetadata"]; + }; + PagedModelImportLanguageModel: { + _embedded?: { + languages?: components["schemas"]["ImportLanguageModel"][]; }; - params?: Record; + page?: components["schemas"]["PageMetadata"]; }; - PagedModelProjectActivityModel: { + PagedModelImportTranslationModel: { _embedded?: { - activities?: components["schemas"]["ProjectActivityModel"][]; + translations?: components["schemas"]["ImportTranslationModel"][]; }; page?: components["schemas"]["PageMetadata"]; }; - PagedModelTagModel: { + PagedModelKeyModel: { _embedded?: { - tags?: components["schemas"]["TagModel"][]; + keys?: components["schemas"]["KeyModel"][]; }; page?: components["schemas"]["PageMetadata"]; }; - PagedModelBatchJobModel: { + PagedModelKeySearchSearchResultModel: { _embedded?: { - batchJobs?: components["schemas"]["BatchJobModel"][]; + keys?: components["schemas"]["KeySearchSearchResultModel"][]; }; page?: components["schemas"]["PageMetadata"]; }; - CreditBalanceModel: { - /** Format: int64 */ - creditBalance: number; - /** Format: int64 */ - bucketSize: number; - /** Format: int64 */ - extraCreditBalance: number; + PagedModelKeyWithTranslationsModel: { + _embedded?: { + keys?: components["schemas"]["KeyWithTranslationsModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; }; - CollectionModelKeyWithBaseTranslationModel: { + PagedModelLabelModel: { _embedded?: { - keys?: components["schemas"]["KeyWithBaseTranslationModel"][]; + labels?: components["schemas"]["LabelModel"][]; }; + page?: components["schemas"]["PageMetadata"]; }; - KeyWithBaseTranslationModel: { - /** - * Format: int64 - * @description Id of key record - */ - id: number; - /** - * @description Name of key - * @example this_is_super_key - */ - name: string; - /** - * @description Namespace of key - * @example homepage - */ - namespace?: string; - /** - * @description Base translation - * @example This is translation - */ - baseTranslation?: string; + PagedModelLanguageModel: { + _embedded?: { + languages?: components["schemas"]["LanguageModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; }; - ImportTranslationModel: { - /** Format: int64 */ - id: number; - text?: string; - keyName: string; - /** Format: int64 */ - keyId: number; - keyDescription?: string; - /** Format: int64 */ - conflictId?: number; - conflictText?: string; - override: boolean; - resolved: boolean; - isPlural: boolean; - existingKeyIsPlural: boolean; + PagedModelNamespaceModel: { + _embedded?: { + namespaces?: components["schemas"]["NamespaceModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; }; - PagedModelImportTranslationModel: { + PagedModelNotificationModel: { _embedded?: { - translations?: components["schemas"]["ImportTranslationModel"][]; + notificationModelList?: components["schemas"]["NotificationModel"][]; }; page?: components["schemas"]["PageMetadata"]; }; - ImportFileIssueModel: { - /** Format: int64 */ - id: number; - /** @enum {string} */ - type: "KEY_IS_NOT_STRING" | "MULTIPLE_VALUES_FOR_KEY_AND_LANGUAGE" | "VALUE_IS_NOT_STRING" | "KEY_IS_EMPTY" | "VALUE_IS_EMPTY" | "PO_MSGCTXT_NOT_SUPPORTED" | "ID_ATTRIBUTE_NOT_PROVIDED" | "TARGET_NOT_PROVIDED" | "TRANSLATION_TOO_LONG" | "KEY_IS_BLANK" | "TRANSLATION_DEFINED_IN_ANOTHER_FILE" | "INVALID_CUSTOM_VALUES"; - params: components["schemas"]["ImportFileIssueParamModel"][]; + PagedModelOrganizationModel: { + _embedded?: { + organizations?: components["schemas"]["OrganizationModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; }; - ImportFileIssueParamModel: { - /** @enum {string} */ - type: "KEY_NAME" | "KEY_ID" | "LANGUAGE_ID" | "KEY_INDEX" | "VALUE" | "LINE" | "FILE_NODE_ORIGINAL" | "LANGUAGE_NAME"; - value?: string; + PagedModelProjectActivityModel: { + _embedded?: { + activities?: components["schemas"]["ProjectActivityModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; }; - PagedModelImportFileIssueModel: { + PagedModelProjectModel: { _embedded?: { - importFileIssues?: components["schemas"]["ImportFileIssueModel"][]; + projects?: components["schemas"]["ProjectModel"][]; }; page?: components["schemas"]["PageMetadata"]; }; - CollectionModelImportNamespaceModel: { + PagedModelSimpleGlossaryModel: { _embedded?: { - namespaces?: components["schemas"]["ImportNamespaceModel"][]; + glossaries?: components["schemas"]["SimpleGlossaryModel"][]; }; + page?: components["schemas"]["PageMetadata"]; }; - ImportNamespaceModel: { - /** - * Format: int64 - * @description The id of namespace. When null, namespace doesn't exist and will be created by import. - * @example 10000048 - */ - id?: number; - /** @example homepage */ - name: string; + PagedModelSimpleGlossaryTermModel: { + _embedded?: { + glossaryTerms?: components["schemas"]["SimpleGlossaryTermModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; }; - CollectionModelBatchJobModel: { + PagedModelSimpleGlossaryTermWithTranslationsModel: { _embedded?: { - batchJobs?: components["schemas"]["BatchJobModel"][]; + glossaryTerms?: components["schemas"]["SimpleGlossaryTermWithTranslationsModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + PagedModelSimpleGlossaryWithStatsModel: { + _embedded?: { + glossaries?: components["schemas"]["SimpleGlossaryWithStatsModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + PagedModelSimpleUserAccountModel: { + _embedded?: { + users?: components["schemas"]["SimpleUserAccountModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + PagedModelTagModel: { + _embedded?: { + tags?: components["schemas"]["TagModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + PagedModelTaskModel: { + _embedded?: { + tasks?: components["schemas"]["TaskModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + PagedModelTaskWithProjectModel: { + _embedded?: { + tasks?: components["schemas"]["TaskWithProjectModel"][]; }; + page?: components["schemas"]["PageMetadata"]; }; PagedModelTranslationCommentModel: { _embedded?: { @@ -2242,333 +2364,3023 @@ export interface components { }; page?: components["schemas"]["PageMetadata"]; }; - TranslationHistoryModel: { - /** @description Modified fields */ - modifications?: { - [key: string]: components["schemas"]["PropertyModification"]; + PagedModelTranslationMemoryItemModel: { + _embedded?: { + translationMemoryItems?: components["schemas"]["TranslationMemoryItemModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + PagedModelTranslationSuggestionModel: { + _embedded?: { + suggestions?: components["schemas"]["TranslationSuggestionModel"][]; + }; + page?: components["schemas"]["PageMetadata"]; + }; + PagedModelWithNextCursorNotificationModel: { + _embedded?: { + notificationModelList?: components["schemas"]["NotificationModel"][]; }; /** - * Format: int64 - * @description Unix timestamp of the revision + * @description Cursor to get next data + * @example eyJrZXlJZCI6eyJkaXJlY3Rpb24iOiJBU0MiLCJ2YWx1ZSI6IjEwMDAwMDAxMjAifX0= */ - timestamp: number; - author?: components["schemas"]["SimpleUserAccountModel"]; - /** @enum {string} */ - revisionType: "ADD" | "MOD" | "DEL"; - }; - SelectAllResponse: { - ids: number[]; + nextCursor?: string; + page?: components["schemas"]["PageMetadata"]; + pagedModel?: components["schemas"]["PagedModelNotificationModel"]; }; - /** @description Tasks related to this key */ - KeyTaskViewModel: { + PatWithUserModel: { /** Format: int64 */ - number: number; + createdAt: number; + description: string; /** Format: int64 */ - languageId: number; - languageTag: string; - done: boolean; - userAssigned: boolean; - /** @enum {string} */ - type: "TRANSLATE" | "REVIEW"; + expiresAt?: number; + /** Format: int64 */ + id: number; + /** Format: int64 */ + lastUsedAt?: number; + /** Format: int64 */ + updatedAt: number; + user: components["schemas"]["SimpleUserAccountModel"]; }; - KeyWithTranslationsModel: { - /** - * Format: int64 - * @description Id of key record - */ - keyId: number; - /** - * @description Name of key - * @example this_is_super_key - */ - keyName: string; + PermissionModel: { /** - * @description Is this key a plural? - * @example true + * @deprecated + * @description Deprecated (use translateLanguageIds). + * + * List of languages current user has TRANSLATE permission to. If null, all languages edition is permitted. + * @example [ + * 200001, + * 200004 + * ] */ - keyIsPlural: boolean; + permittedLanguageIds?: number[]; /** - * @description The placeholder name for plural parameter - * @example value + * @description Granted scopes to the user. When user has type permissions, this field contains permission scopes of the type. + * @example [ + * "KEYS_EDIT", + * "TRANSLATIONS_VIEW" + * ] */ - keyPluralArgName?: string; + scopes: ("translations.view" | "translations.edit" | "translations.suggest" | "keys.edit" | "screenshots.upload" | "screenshots.delete" | "screenshots.view" | "activity.view" | "languages.edit" | "admin" | "project.edit" | "members.view" | "members.edit" | "translation-comments.add" | "translation-comments.edit" | "translation-comments.set-state" | "translations.state-edit" | "keys.view" | "keys.delete" | "keys.create" | "batch-jobs.view" | "batch-jobs.cancel" | "translations.batch-by-tm" | "translations.batch-machine" | "content-delivery.manage" | "content-delivery.publish" | "webhooks.manage" | "tasks.view" | "tasks.edit" | "prompts.view" | "prompts.edit" | "translation-labels.manage" | "translation-labels.assign" | "all.view")[]; /** - * Format: int64 - * @description The namespace id of the key - * @example 100000282 + * @description List of languages user can change state to. If null, changing state of all language values is permitted. + * @example [ + * 200001, + * 200004 + * ] */ - keyNamespaceId?: number; + stateChangeLanguageIds?: number[]; /** - * @description The namespace of the key - * @example homepage + * @description List of languages user can suggest to. If null, suggesting to all languages is permitted. + * @example [ + * 200001, + * 200004 + * ] */ - keyNamespace?: string; + suggestLanguageIds?: number[]; /** - * @description The namespace of the key - * @example homepage + * @description List of languages user can translate to. If null, all languages editing is permitted. + * @example [ + * 200001, + * 200004 + * ] */ - keyDescription?: string; - /** @description Tags of key */ - keyTags: components["schemas"]["TagModel"][]; + translateLanguageIds?: number[]; /** - * Format: int64 - * @description Count of screenshots provided for the key - * @example 1 + * @description The user's permission type. This field is null if uses granular permissions + * @enum {string} */ - screenshotCount: number; - /** @description Key screenshots. Not provided when API key hasn't screenshots.view scope permission. */ - screenshots?: components["schemas"]["ScreenshotModel"][]; - /** @description There is a context available for this key */ - contextPresent: boolean; + type?: "NONE" | "VIEW" | "TRANSLATE" | "REVIEW" | "EDIT" | "MANAGE"; /** - * @description Translations object - * @example - * { - * "en": { - * "id": 100000003, - * "text": "This is super translation!" - * "state": "TRANSLATED", - * "commentCount": 1 - * } - * } + * @description List of languages user can view. If null, all languages view is permitted. + * @example [ + * 200001, + * 200004 + * ] */ - translations: { - [key: string]: components["schemas"]["TranslationViewModel"]; - }; - /** @description Tasks related to this key */ - tasks?: components["schemas"]["KeyTaskViewModel"][]; + viewLanguageIds?: number[]; }; - KeysWithTranslationsPageModel: { - _embedded?: { - keys?: components["schemas"]["KeyWithTranslationsModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; - /** @description Provided languages data */ - selectedLanguages: components["schemas"]["LanguageModel"][]; - /** - * @description Cursor to get next data - * @example eyJrZXlJZCI6eyJkaXJlY3Rpb24iOiJBU0MiLCJ2YWx1ZSI6IjEwMDAwMDAxMjAifX0= - */ - nextCursor?: string; + PreTranslationByTmRequest: { + keyIds: number[]; + targetLanguageIds: number[]; }; - /** - * @description Translations object - * @example - * { - * "en": { - * "id": 100000003, - * "text": "This is super translation!" - * "state": "TRANSLATED", - * "commentCount": 1 - * } - * } - */ - TranslationViewModel: { + PrivateUserAccountModel: { + /** @enum {string} */ + accountType: "LOCAL" | "MANAGED" | "THIRD_PARTY"; + avatar?: components["schemas"]["Avatar"]; + deletable: boolean; + domain?: string; + emailAwaitingVerification?: string; + /** @enum {string} */ + globalServerRole: "USER" | "ADMIN" | "SUPPORTER"; + /** Format: int64 */ + id: number; + mfaEnabled: boolean; + name?: string; + needsSuperJwtToken: boolean; + /** @enum {string} */ + thirdPartyAuthType?: "GOOGLE" | "GITHUB" | "OAUTH2" | "SSO" | "SSO_GLOBAL"; + username: string; + }; + ProjectActivityAuthorModel: { + avatar?: components["schemas"]["Avatar"]; + deleted: boolean; + /** Format: int64 */ + id: number; + name?: string; + username?: string; + }; + ProjectActivityModel: { + author?: components["schemas"]["ProjectActivityAuthorModel"]; + counts?: { + [key: string]: number; + }; + meta?: { + [key: string]: unknown; + }; + modifiedEntities?: { + [key: string]: components["schemas"]["ModifiedEntityModel"][]; + }; + params?: unknown; + /** Format: int64 */ + revisionId: number; + /** Format: int64 */ + timestamp: number; + /** @enum {string} */ + type: "UNKNOWN" | "SET_TRANSLATION_STATE" | "SET_TRANSLATIONS" | "DISMISS_AUTO_TRANSLATED_STATE" | "SET_OUTDATED_FLAG" | "TRANSLATION_COMMENT_ADD" | "TRANSLATION_COMMENT_DELETE" | "TRANSLATION_COMMENT_EDIT" | "TRANSLATION_COMMENT_SET_STATE" | "SCREENSHOT_DELETE" | "SCREENSHOT_ADD" | "KEY_TAGS_EDIT" | "KEY_NAME_EDIT" | "KEY_DELETE" | "CREATE_KEY" | "COMPLEX_EDIT" | "IMPORT" | "CREATE_LANGUAGE" | "EDIT_LANGUAGE" | "DELETE_LANGUAGE" | "HARD_DELETE_LANGUAGE" | "CREATE_PROJECT" | "EDIT_PROJECT" | "NAMESPACE_EDIT" | "BATCH_PRE_TRANSLATE_BY_TM" | "BATCH_MACHINE_TRANSLATE" | "AUTO_TRANSLATE" | "BATCH_CLEAR_TRANSLATIONS" | "BATCH_COPY_TRANSLATIONS" | "BATCH_SET_TRANSLATION_STATE" | "BATCH_TAG_KEYS" | "BATCH_UNTAG_KEYS" | "BATCH_SET_KEYS_NAMESPACE" | "BATCH_ASSIGN_TRANSLATION_LABEL" | "BATCH_UNASSIGN_TRANSLATION_LABEL" | "AUTOMATION" | "CONTENT_DELIVERY_CONFIG_CREATE" | "CONTENT_DELIVERY_CONFIG_UPDATE" | "CONTENT_DELIVERY_CONFIG_DELETE" | "CONTENT_STORAGE_CREATE" | "CONTENT_STORAGE_UPDATE" | "CONTENT_STORAGE_DELETE" | "WEBHOOK_CONFIG_CREATE" | "WEBHOOK_CONFIG_UPDATE" | "WEBHOOK_CONFIG_DELETE" | "COMPLEX_TAG_OPERATION" | "TASKS_CREATE" | "TASK_CREATE" | "TASK_UPDATE" | "TASK_KEYS_UPDATE" | "TASK_FINISH" | "TASK_CLOSE" | "TASK_REOPEN" | "TASK_KEY_UPDATE" | "ORDER_TRANSLATION" | "GLOSSARY_CREATE" | "GLOSSARY_UPDATE" | "GLOSSARY_DELETE" | "GLOSSARY_IMPORT" | "GLOSSARY_TERM_CREATE" | "GLOSSARY_TERM_UPDATE" | "GLOSSARY_TERM_DELETE" | "GLOSSARY_TERM_TRANSLATION_UPDATE" | "TRANSLATION_LABELS_EDIT" | "TRANSLATION_LABEL_ASSIGN" | "TRANSLATION_LABEL_CREATE" | "TRANSLATION_LABEL_UPDATE" | "TRANSLATION_LABEL_DELETE" | "CREATE_SUGGESTION" | "DECLINE_SUGGESTION" | "ACCEPT_SUGGESTION" | "REVERSE_SUGGESTION" | "DELETE_SUGGESTION" | "SUGGESTION_SET_ACTIVE" | "AI_PROMPT_CREATE" | "AI_PROMPT_UPDATE" | "AI_PROMPT_DELETE"; + }; + ProjectModel: { + avatar?: components["schemas"]["Avatar"]; + baseLanguage?: components["schemas"]["LanguageModel"]; + computedPermission: components["schemas"]["ComputedPermissionModel"]; + defaultNamespace?: components["schemas"]["NamespaceModel"]; + description?: string; /** - * Format: int64 - * @description Id of translation record + * @description Current user's direct permission + * @example MANAGE */ + directPermission?: components["schemas"]["PermissionModel"]; + /** @description Whether to disable ICU placeholder visualization in the editor and it's support. */ + icuPlaceholders: boolean; + /** Format: int64 */ id: number; - /** @description Translation text */ - text?: string; + name: string; + organizationOwner?: components["schemas"]["SimpleOrganizationModel"]; + /** @enum {string} */ + organizationRole?: "MEMBER" | "OWNER" | "MAINTAINER"; + slug?: string; /** - * @description State of translation + * @description Suggestions for translations * @enum {string} */ - state: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; - /** @description Whether base language translation was changed after this translation was updated */ - outdated: boolean; - /** @description Was translated using Translation Memory or Machine translation service? */ - auto: boolean; + suggestionsMode: "DISABLED" | "ENABLED"; /** - * @description Which machine translation service was used to auto translate this + * @description Level of protection of translations * @enum {string} */ - mtProvider?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "TOLGEE"; - /** - * Format: int64 - * @description Count of translation comments - */ - commentCount: number; - /** - * Format: int64 - * @description Count of unresolved translation comments - */ - unresolvedCommentCount: number; - /** @description Was translation memory used to translate this? */ - fromTranslationMemory: boolean; + translationProtection: "NONE" | "PROTECT_REVIEWED"; + useNamespaces: boolean; }; - LanguageStatsModel: { - /** Format: int64 */ - languageId?: number; - languageTag?: string; - languageName?: string; - languageOriginalName?: string; - languageFlagEmoji?: string; + ProjectStatsModel: { /** Format: int64 */ - translatedKeyCount: number; + baseWordsCount: number; /** Format: int64 */ - translatedWordCount: number; - /** Format: double */ - translatedPercentage: number; + keyCount: number; + /** Format: int32 */ + languageCount: number; + languageStats: components["schemas"]["LanguageStatsModel"][]; /** Format: int64 */ - reviewedKeyCount: number; + membersCount: number; /** Format: int64 */ - reviewedWordCount: number; + projectId: number; /** Format: double */ reviewedPercentage: number; /** Format: int64 */ - untranslatedKeyCount: number; - /** Format: int64 */ - untranslatedWordCount: number; - /** Format: double */ - untranslatedPercentage: number; - }; - ProjectStatsModel: { - /** Format: int64 */ - projectId: number; - /** Format: int32 */ - languageCount: number; - /** Format: int64 */ - keyCount: number; + tagCount: number; /** Format: int64 */ taskCount: number; - /** Format: int64 */ - baseWordsCount: number; /** Format: double */ translatedPercentage: number; - /** Format: double */ - reviewedPercentage: number; - /** Format: int64 */ - membersCount: number; - /** Format: int64 */ - tagCount: number; - languageStats: components["schemas"]["LanguageStatsModel"][]; }; - PagedModelLanguageModel: { - _embedded?: { - languages?: components["schemas"]["LanguageModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; + PromptDto: { + basicPromptOptions?: ("KEY_NAME" | "KEY_DESCRIPTION" | "KEY_CONTEXT" | "PROJECT_DESCRIPTION" | "LANGUAGE_NOTES" | "TM_SUGGESTIONS" | "SCREENSHOT" | "GLOSSARY")[]; + name: string; + providerName: string; + template?: string; }; - CollectionModelScreenshotModel: { - _embedded?: { - screenshots?: components["schemas"]["ScreenshotModel"][]; - }; + PropertyModification: { + new?: unknown; + old?: unknown; }; - PatWithUserModel: { - user: components["schemas"]["SimpleUserAccountModel"]; - description: string; - /** Format: int64 */ - id: number; - /** Format: int64 */ - expiresAt?: number; - /** Format: int64 */ - lastUsedAt?: number; - /** Format: int64 */ - createdAt: number; - /** Format: int64 */ - updatedAt: number; + PublicSsoTenantModel: { + domain: string; + force: boolean; + global: boolean; }; - PagedModelOrganizationModel: { - _embedded?: { - organizations?: components["schemas"]["OrganizationModel"][]; - }; - page?: components["schemas"]["PageMetadata"]; + RelatedKeyDto: { + keyName: string; + namespace?: string; }; - ApiKeyWithLanguagesModel: { + ScreenshotInfoDto: { + location?: string; + positions?: components["schemas"]["KeyInScreenshotPositionDto"][]; + text?: string; + }; + ScreenshotModel: { + /** Format: date-time */ + createdAt?: string; + fileUrl: string; /** - * @deprecated - * @description Languages for which user has translate permission. + * @description File name, which may be downloaded from the screenshot path. + * + * When images are secured. Encrypted timestamp is appended to the filename. */ - permittedLanguageIds?: number[]; - description: string; + filename: string; + /** Format: int32 */ + height?: number; /** Format: int64 */ id: number; - userFullName?: string; - projectName: string; - username?: string; - scopes: string[]; - /** Format: int64 */ - expiresAt?: number; - /** Format: int64 */ - projectId: number; - /** Format: int64 */ - lastUsedAt?: number; + keyReferences: components["schemas"]["KeyInScreenshotModel"][]; + location?: string; + middleSized?: string; + middleSizedUrl?: string; + /** + * @description Thumbnail file name, which may be downloaded from the screenshot path. + * + * When images are secured. Encrypted timestamp is appended to the filename. + */ + thumbnail: string; + thumbnailUrl: string; + /** Format: int32 */ + width?: number; }; - ApiKeyPermissionsModel: { + SelectAllResponse: { + ids: number[]; + }; + SetDisabledLanguagesRequest: { + languageIds: number[]; + }; + SetFileNamespaceRequest: { + namespace?: string; + }; + SetKeysNamespaceRequest: { + keyIds: number[]; + namespace?: string; + }; + SetTranslationsResponseModel: { /** * Format: int64 - * @description The API key's project id or the one provided as query param + * @description Id of key record */ - projectId: number; + keyId: number; + keyIsPlural: boolean; /** - * @description List of languages user can view. If null, all languages view is permitted. - * @example [ - * 200001, - * 200004 - * ] + * @description Name of key + * @example this_is_super_key */ - viewLanguageIds?: number[]; + keyName: string; /** - * @description List of languages user can translate to. If null, all languages editing is permitted. - * @example [ - * 200001, - * 200004 - * ] + * @description The namespace of the key + * @example homepage */ - translateLanguageIds?: number[]; + keyNamespace?: string; /** - * @description List of languages user can change state to. If null, changing state of all language values is permitted. - * @example [ - * 200001, - * 200004 - * ] + * @description Translations object containing values updated in this request + * @example { + * "en": { + * "id": 100000003, + * "text": "This is super translation!" + * } + * } */ - stateChangeLanguageIds?: number[]; - /** - * @description Granted scopes to the user. When user has type permissions, this field contains permission scopes of the type. - * @example [ - * "KEYS_EDIT", - * "TRANSLATIONS_VIEW" - * ] + translations: { + [key: string]: components["schemas"]["TranslationModel"]; + }; + }; + SetTranslationsStateStateRequest: { + keyIds: number[]; + languageIds: number[]; + /** @enum {string} */ + state: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + }; + SetTranslationsWithKeyDto: { + /** + * @description Key name to set translations for + * @example what_a_key_to_translate */ - scopes: ("translations.view" | "translations.edit" | "keys.edit" | "screenshots.upload" | "screenshots.delete" | "screenshots.view" | "activity.view" | "languages.edit" | "admin" | "project.edit" | "members.view" | "members.edit" | "translation-comments.add" | "translation-comments.edit" | "translation-comments.set-state" | "translations.state-edit" | "keys.view" | "keys.delete" | "keys.create" | "batch-jobs.view" | "batch-jobs.cancel" | "translations.batch-by-tm" | "translations.batch-machine" | "content-delivery.manage" | "content-delivery.publish" | "webhooks.manage" | "tasks.view" | "tasks.edit")[]; + key: string; /** - * @description The user's permission type. This field is null if user has assigned granular permissions or if returning API key's permissions + * @description List of languages to return translations for. + * + * If not provided, only modified translation will be provided. + * + * @example [ + * "en", + * "de", + * "fr" + * ] + */ + languagesToReturn?: string[]; + /** @description The namespace of the key. (When empty or null default namespace will be used) */ + namespace?: string; + /** + * @description Object mapping language tag to translation + * @example { + * "en": "What a translated value!", + * "cs": "Jaká to přeložená hodnota!" + * } + */ + translations: { + [key: string]: string; + }; + }; + SimpleGlossaryModel: { + /** + * @description Language tag for default translations for terms + * @example en + */ + baseLanguageTag: string; + /** Format: int64 */ + id: number; + name: string; + }; + SimpleGlossaryTermModel: { + description: string; + /** @description Specifies whether the term represents a shortened form of a word or phrase */ + flagAbbreviation: boolean; + /** @description When true, the term matching considers uppercase and lowercase characters as distinct */ + flagCaseSensitive: boolean; + /** @description When true, marks this term as prohibited or not recommended for use in translations */ + flagForbiddenTerm: boolean; + /** @description When true, this term has the same translation across all target languages */ + flagNonTranslatable: boolean; + /** Format: int64 */ + id: number; + }; + SimpleGlossaryTermWithTranslationsModel: { + /** + * @description A detailed explanation or definition of the glossary term + * @example It's trademark + */ + description: string; + /** @description Specifies whether the term represents a shortened form of a word or phrase */ + flagAbbreviation: boolean; + /** @description When true, the term matching considers uppercase and lowercase characters as distinct */ + flagCaseSensitive: boolean; + /** @description When true, marks this term as prohibited or not recommended for use in translations */ + flagForbiddenTerm: boolean; + /** @description When true, this term has the same translation across all target languages */ + flagNonTranslatable: boolean; + /** Format: int64 */ + id: number; + translations: components["schemas"]["GlossaryTermTranslationModel"][]; + }; + SimpleGlossaryWithStatsModel: { + /** + * Format: int64 + * @description Total number of projects currently using this glossary + * @example 69 + */ + assignedProjectsCount: number; + /** + * @description The primary language code used for terms (e.g., 'en' for English) + * @example en + */ + baseLanguageTag: string; + /** + * @description The name of one project using this glossary (can be shown as a preview) + * @example My Project + */ + firstAssignedProjectName?: string; + /** Format: int64 */ + id: number; + name: string; + }; + SimpleImportConflictResult: { + isOverridable: boolean; + keyName: string; + keyNamespace?: string; + language: string; + }; + SimpleOrganizationModel: { + /** @example Links to avatar images */ + avatar?: components["schemas"]["Avatar"]; + basePermissions: components["schemas"]["PermissionModel"]; + /** @example This is a beautiful organization full of beautiful and clever people */ + description?: string; + /** Format: int64 */ + id: number; + /** @example Beautiful organization */ + name: string; + /** @example btforg */ + slug: string; + }; + SimpleProjectModel: { + avatar?: components["schemas"]["Avatar"]; + baseLanguage?: components["schemas"]["LanguageModel"]; + description?: string; + icuPlaceholders: boolean; + /** Format: int64 */ + id: number; + name: string; + slug?: string; + }; + SimpleUserAccountModel: { + avatar?: components["schemas"]["Avatar"]; + deleted: boolean; + /** Format: int64 */ + id: number; + name?: string; + username: string; + }; + SingleStepImportRequest: { + /** @description If true, placeholders from other formats will be converted to ICU when possible */ + convertPlaceholdersToIcu: boolean; + /** @description If false, only updates keys, skipping the creation of new keys */ + createNewKeys: boolean; + /** + * @description If `false`, import will apply all `non-failed` overrides and reports `unresolvedConflict` + * .If `true`, import will fail completely on unresolved conflict and won't apply any changes. Unresolved conflicts are reported in the `params` of the error response + */ + errorOnUnresolvedConflict?: boolean; + /** @description Definition of mapping for each file to import. */ + fileMappings: components["schemas"]["ImportFileMapping"][]; + /** + * @description Whether to override existing translation data. + * + * When set to `KEEP`, existing translations will be kept. + * When set to `NO_FORCE`, error will be thrown on conflict. + * When set to `OVERRIDE`, existing translations will be overwritten * @enum {string} */ - type?: "NONE" | "VIEW" | "TRANSLATE" | "REVIEW" | "EDIT" | "MANAGE"; - project: components["schemas"]["SimpleProjectModel"]; + forceMode: "OVERRIDE" | "KEEP" | "NO_FORCE"; + /** + * @description Maps the languages from imported files to languages existing in the Tolgee platform. + * + * Use this field only when your files contain multiple languages (e.g., XLIFF files). + * + * Otherwise, use the `languageTag` property of `fileMappings`. + * + * Example: In xliff files, there are `source-language` and `target-language` attributes defined on `file` element. Using this field you can map source and target values to languages stored in the Tolgee Platform. + */ + languageMappings?: components["schemas"]["LanguageMapping"][]; + /** @description If true, key descriptions will be overridden by the import */ + overrideKeyDescriptions: boolean; + /** + * @description Some translations are forbidden or protected: + * + * When set to `RECOMMENDED` it will fail for DISABLED translations and protected REVIEWED translations. + * When set to `ALL` it will fail for DISABLED translations, but will try to update protected REVIEWED translations (fails only if user has no permission) + * + * @enum {string} + */ + overrideMode?: "RECOMMENDED" | "ALL"; + /** @description If yes, keys from project that were not included in import will be deleted (only within namespaces which are included in the import). */ + removeOtherKeys?: boolean; + /** + * @description When importing files in structured formats (e.g., JSON, YAML), this field defines the delimiter which will be used in names of imported keys. + * @example . + */ + structureDelimiter?: string; + /** @description Keys created by this import will be tagged with these tags. It add tags only to new keys. The keys that already exist will not be tagged. */ + tagNewKeys: string[]; + }; + SingleStepImportResolvableItemRequest: { + /** + * @description Key name to set translations for + * @example what_a_key_to_translate + */ + name: string; + /** @description The namespace of the key. (When empty or null default namespace will be used) */ + namespace?: string; + screenshots?: components["schemas"]["KeyScreenshotDto"][]; + /** @description Object mapping language tag to translation */ + translations: { + [key: string]: components["schemas"]["SingleStepImportResolvableTranslationRequest"]; + }; + }; + SingleStepImportResolvableRequest: { + /** + * @description If `false`, import will apply all `non-failed` overrides and reports `unresolvedConflict` + * .If `true`, import will fail completely on unresolved conflict and won't apply any changes. Unresolved conflicts are reported in the `params` of the error response + */ + errorOnUnresolvedConflict?: boolean; + /** @description List of keys to import */ + keys: components["schemas"]["SingleStepImportResolvableItemRequest"][]; + /** + * @description Some translations are forbidden or protected: + * + * When set to `RECOMMENDED` it will fail for DISABLED translations and protected REVIEWED translations. + * When set to `ALL` it will fail for DISABLED translations, but will try to update protected REVIEWED translations (fails only if user has no permission) + * + * @enum {string} + */ + overrideMode?: "RECOMMENDED" | "ALL"; + }; + SingleStepImportResolvableTranslationRequest: { + /** + * @description + * To ensure the import doesn't override something that should not be (in case data have changed unexpectedly), + * you can specify what do you "expect": + * - EXPECT_NO_CONFLICT: There should be no conflict, if there is, import fails + * - OVERRIDE: New translation is applied over the existing in every case (Default) + * + * @example OVERRIDE + * @enum {string} + */ + resolution?: "EXPECT_NO_CONFLICT" | "OVERRIDE"; + /** + * @description Translation text + * @example Hello! I am a translation! + */ + text: string; + }; + StreamingResponseBody: unknown; + SuggestRequestDto: { + /** @description Text value of base translation. Useful, when base translation is not stored yet. */ + baseText?: string; + /** @description Whether base text is plural. This value is ignored if baseText is null. */ + isPlural?: boolean; + /** + * Format: int64 + * @description Key Id to get results for. Use when key is stored already. + */ + keyId?: number; + plural?: boolean; + /** @description List of services to use. If null, then all enabled services are used. */ + services?: ("GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "PROMPT")[]; + /** Format: int64 */ + targetLanguageId: number; + }; + SuggestResultModel: { + /** @description If true, the base translation was empty and no translation was provided. */ + baseBlank: boolean; + /** + * @deprecated + * @description String translations provided by enabled services. (deprecated, use `result` instead) + * @example + * { + * "GOOGLE": "This was translated by Google", + * "TOLGEE": "This was translated by Tolgee Translator", + * } + */ + machineTranslations?: { + [key: string]: string; + }; + /** + * @description Results provided by enabled services. + * @example { + * "GOOGLE": { + * "output": "This was translated by Google", + * "contextDescription": null + * }, + * "TOLGEE": { + * "output": "This was translated by Tolgee Translator", + * "contextDescription": "This is an example in swagger" + * } + * } + */ + result?: { + [key: string]: components["schemas"]["TranslationItemModel"]; + }; + }; + TagKeyDto: { + name: string; + }; + TagKeysRequest: { + keyIds: number[]; + tags: string[]; + }; + TagModel: { + /** Format: int64 */ + id: number; + name: string; + }; + TaskKeysResponse: { + keys: number[]; + }; + TaskModel: { + agency?: components["schemas"]["TranslationAgencySimpleModel"]; + assignees: components["schemas"]["SimpleUserAccountModel"][]; + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + baseCharacterCount: number; + /** Format: int64 */ + baseWordCount: number; + /** Format: int64 */ + closedAt?: number; + /** Format: int64 */ + createdAt?: number; + description: string; + /** Format: int64 */ + doneItems: number; + /** Format: int64 */ + dueDate?: number; + language: components["schemas"]["LanguageModel"]; + name?: string; + /** Format: int64 */ + number: number; + /** @enum {string} */ + state: "NEW" | "IN_PROGRESS" | "FINISHED" | "CANCELED"; + /** Format: int64 */ + totalItems: number; + /** @enum {string} */ + type: "TRANSLATE" | "REVIEW"; + }; + TaskPerUserReportModel: { + /** Format: int64 */ + baseCharacterCount: number; + /** Format: int64 */ + baseWordCount: number; + /** Format: int64 */ + doneItems: number; + user: components["schemas"]["SimpleUserAccountModel"]; + }; + TaskWithProjectModel: { + agency?: components["schemas"]["TranslationAgencySimpleModel"]; + assignees: components["schemas"]["SimpleUserAccountModel"][]; + author?: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + baseCharacterCount: number; + /** Format: int64 */ + baseWordCount: number; + /** Format: int64 */ + closedAt?: number; + /** Format: int64 */ + createdAt?: number; + description: string; + /** Format: int64 */ + doneItems: number; + /** Format: int64 */ + dueDate?: number; + language: components["schemas"]["LanguageModel"]; + name?: string; + /** Format: int64 */ + number: number; + project: components["schemas"]["SimpleProjectModel"]; + /** @enum {string} */ + state: "NEW" | "IN_PROGRESS" | "FINISHED" | "CANCELED"; + /** Format: int64 */ + totalItems: number; + /** @enum {string} */ + type: "TRANSLATE" | "REVIEW"; + }; + TranslationAgencySimpleModel: { + avatar?: components["schemas"]["Avatar"]; + /** Format: int64 */ + id: number; + name: string; + url?: string; + }; + TranslationCommentDto: { + /** @enum {string} */ + state: "RESOLUTION_NOT_NEEDED" | "NEEDS_RESOLUTION" | "RESOLVED"; + text: string; + }; + TranslationCommentModel: { + /** @description User who created the comment */ + author: components["schemas"]["SimpleUserAccountModel"]; + /** + * Format: date-time + * @description Date when it was created + */ + createdAt: string; + /** + * Format: int64 + * @description Id of translation comment record + */ + id: number; + /** + * @description State of translation + * @enum {string} + */ + state: "RESOLUTION_NOT_NEEDED" | "NEEDS_RESOLUTION" | "RESOLVED"; + /** @description Text of comment */ + text: string; + /** + * Format: date-time + * @description Date when it was updated + */ + updatedAt: string; + }; + TranslationCommentWithLangKeyDto: { + /** Format: int64 */ + keyId: number; + /** Format: int64 */ + languageId: number; + /** @enum {string} */ + state: "RESOLUTION_NOT_NEEDED" | "NEEDS_RESOLUTION" | "RESOLVED"; + text: string; + }; + TranslationHistoryModel: { + /** @description Author of the change */ + author?: components["schemas"]["SimpleUserAccountModel"]; + /** @description Modified fields */ + modifications?: { + [key: string]: components["schemas"]["PropertyModification"]; + }; + /** @enum {string} */ + revisionType: "ADD" | "MOD" | "DEL"; + /** + * Format: int64 + * @description Unix timestamp of the revision + */ + timestamp: number; + }; + TranslationItemModel: { + contextDescription?: string; + output: string; + }; + TranslationLabelRequest: { + /** Format: int64 */ + keyId: number; + /** Format: int64 */ + labelId: number; + /** Format: int64 */ + languageId: number; + }; + TranslationMemoryItemModel: { + baseText: string; + keyName: string; + /** Format: float */ + similarity: number; + targetText: string; + }; + TranslationModel: { + /** @description Was translated using Translation Memory or Machine translation service? */ + auto: boolean; + /** + * Format: int64 + * @description Id of translation record + */ + id: number; + /** + * @description Which machine translation service was used to auto translate this + * @enum {string} + */ + mtProvider?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "PROMPT"; + /** @description Whether base language translation was changed after this translation was updated */ + outdated: boolean; + /** + * @description State of translation + * @enum {string} + */ + state: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + /** @description Translation text */ + text?: string; + }; + TranslationSuggestionAcceptResponse: { + accepted: components["schemas"]["TranslationSuggestionModel"]; + declined: number[]; + }; + TranslationSuggestionModel: { + author: components["schemas"]["SimpleUserAccountModel"]; + /** Format: date-time */ + createdAt: string; + /** Format: int64 */ + id: number; + isPlural: boolean; + /** Format: int64 */ + keyId: number; + /** Format: int64 */ + languageId: number; + /** @enum {string} */ + state: "ACTIVE" | "ACCEPTED" | "DECLINED"; + translation?: string; + /** Format: date-time */ + updatedAt: string; + }; + TranslationSuggestionSimpleModel: { + author: components["schemas"]["SimpleUserAccountModel"]; + /** Format: int64 */ + id: number; + isPlural: boolean; + /** @enum {string} */ + state: "ACTIVE" | "ACCEPTED" | "DECLINED"; + translation?: string; + }; + TranslationViewModel: { + /** + * Format: int64 + * @description Number of active suggestions + */ + activeSuggestionCount: number; + /** @description Was translated using Translation Memory or Machine translation service? */ + auto: boolean; + /** + * Format: int64 + * @description Count of translation comments + */ + commentCount: number; + /** @description Was translation memory used to translate this? */ + fromTranslationMemory: boolean; + /** + * Format: int64 + * @description Id of translation record + */ + id?: number; + /** @description Labels assigned to this translation */ + labels?: components["schemas"]["LabelModel"][]; + /** + * @description Which machine translation service was used to auto translate this + * @enum {string} + */ + mtProvider?: "GOOGLE" | "AWS" | "DEEPL" | "AZURE" | "BAIDU" | "PROMPT"; + /** @description Whether base language translation was changed after this translation was updated */ + outdated: boolean; + /** + * @description State of translation + * @enum {string} + */ + state: "UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED"; + /** @description First suggestion */ + suggestions?: components["schemas"]["TranslationSuggestionSimpleModel"][]; + /** @description Translation text */ + text?: string; + /** + * Format: int64 + * @description Number of all suggestions + */ + totalSuggestionCount: number; + /** + * Format: int64 + * @description Count of unresolved translation comments + */ + unresolvedCommentCount: number; + }; + TranslationWithCommentModel: { + comment: components["schemas"]["TranslationCommentModel"]; + translation: components["schemas"]["TranslationModel"]; + }; + UntagKeysRequest: { + keyIds: number[]; + tags: string[]; + }; + UpdateGlossaryRequest: { + /** @description Projects assigned to glossary; when null, assigned projects will be kept unchanged. */ + assignedProjectIds?: number[]; + /** + * @description Language tag according to BCP 47 definition + * @example cs-CZ + */ + baseLanguageTag: string; + /** + * @description Glossary name + * @example My glossary + */ + name: string; + }; + UpdateGlossaryTermTranslationRequest: { + /** + * @description Language tag according to BCP 47 definition + * @example cs-CZ + */ + languageTag: string; + /** + * @description Translation text + * @example Translated text to language of languageTag + */ + text: string; + }; + UpdateGlossaryTermWithTranslationRequest: { + description?: string; + /** @description Specifies whether the term represents a shortened form of a word or phrase */ + flagAbbreviation?: boolean; + /** @description When true, the term matching considers uppercase and lowercase characters as distinct */ + flagCaseSensitive?: boolean; + /** @description When true, marks this term as prohibited or not recommended for use in translations */ + flagForbiddenTerm?: boolean; + /** @description When true, this term will have the same translation across all target languages */ + flagNonTranslatable?: boolean; + text?: string; + }; + UpdateNamespaceDto: { + name: string; + }; + UpdateTaskKeyRequest: { + done: boolean; + }; + UpdateTaskKeyResponse: { + /** @description Task key is marked as done */ + done: boolean; + /** @description Task progress is 100% */ + taskFinished: boolean; + }; + UpdateTaskKeysRequest: { + /** @description Keys to add to task */ + addKeys?: number[]; + /** @description Keys to remove from task */ + removeKeys?: number[]; + }; + UpdateTaskRequest: { + assignees: number[]; + description: string; + /** + * Format: int64 + * @description Due to date in epoch format (milliseconds). + * @example 1661172869000 + */ + dueDate?: number; + name?: string; + }; + UploadedImageModel: { + /** Format: date-time */ + createdAt: string; + fileUrl: string; + filename: string; + /** Format: int64 */ + id: number; + location?: string; + requestFilename: string; + }; + UsedNamespaceModel: { + /** + * Format: int64 + * @description The id of namespace. Null for default namespace. + * @example 10000048 + */ + id?: number; + /** + * @description Name of namespace. Null if default. + * @example homepage + */ + name?: string; + }; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +} + +export type $defs = Record; + +export type external = Record; + +export interface operations { + + /** + * Export to ZIP of jsons + * @deprecated + * @description Exports data as ZIP of jsons + */ + doExportJsonZip_1: { + responses: { + /** @description OK */ + 200: { + content: { + "application/zip": components["schemas"]["StreamingResponseBody"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** + * Get current API key info + * @description Returns info the API key which user currently authenticated with. Otherwise responds with 400 status code. + */ + getCurrent_1: { + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["ApiKeyWithLanguagesModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** + * Get current permission info + * @description Returns current PAK or PAT permissions for current user, api-key and project + */ + getCurrentPermissions: { + parameters: { + query?: { + /** @description Required when using with PAT */ + projectId?: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["ApiKeyPermissionsModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Get current third party authentication provider */ + getCurrentAuthProvider: { + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["AuthProviderDto"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Initiate provider change to remove current third party authentication provider */ + deleteCurrentAuthProvider: { + responses: { + /** @description OK */ + 200: { + content: never; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Get info about authentication provider which can replace the current one */ + getChangedAuthProvider: { + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["AuthProviderDto"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Accept change of the third party authentication provider */ + acceptChangeAuthProvider: { + requestBody: { + content: { + "application/json": components["schemas"]["AcceptAuthProviderChangeRequest"]; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["JwtAuthenticationResponse"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Reject change of the third party authentication provider */ + rejectChangeAuthProvider: { + responses: { + /** @description OK */ + 200: { + content: never; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Upload an image for later use */ + upload: { + requestBody?: { + content: { + "multipart/form-data": { + /** Format: binary */ + image: string; + info?: components["schemas"]["ImageUploadInfoDto"]; + }; + }; + }; + responses: { + /** @description Created */ + 201: { + content: { + "*/*": components["schemas"]["UploadedImageModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Delete uploaded images */ + delete_15: { + parameters: { + path: { + ids: number[]; + }; + }; + responses: { + /** @description OK */ + 200: { + content: never; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Gets notifications of the currently logged in user, newest is first. */ + getNotifications: { + parameters: { + query?: { + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + /** + * @description Filter by the `seen` parameter. + * + * no value = request everything + * + * true = only seen + * + * false = only unseen + */ + filterSeen?: boolean; + cursor?: string; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["PagedModelWithNextCursorNotificationModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** + * Get notification settings + * @description Returns notification settings of the currently logged in user + */ + getNotificationsSettings: { + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["NotificationSettingModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** + * Save notification setting + * @description Saves new value for given parameters + */ + putNotificationSetting: { + requestBody: { + content: { + "application/json": components["schemas"]["NotificationSettingsRequest"]; + }; + }; + responses: { + /** @description OK */ + 200: { + content: never; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Marks notifications of the currently logged in user with given IDs as seen. */ + markNotificationsAsSeen: { + requestBody: { + content: { + "application/json": components["schemas"]["NotificationsMarkSeenRequest"]; + }; + }; + responses: { + /** @description OK */ + 200: { + content: never; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** + * Get all permitted organizations + * @description Returns all organizations, which is current user allowed to view + */ + getAll_10: { + parameters: { + query: { + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + filterCurrentUserOwner: boolean; + search?: string; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["PagedModelOrganizationModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Create organization */ + create_12: { + requestBody: { + content: { + "application/json": components["schemas"]["OrganizationDto"]; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["OrganizationModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Get one organization */ + get_15: { + parameters: { + path: { + id: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["OrganizationModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Get all organization glossaries */ + getAll_12: { + parameters: { + query?: { + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + search?: string; + }; + path: { + organizationId: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["PagedModelSimpleGlossaryModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Create glossary */ + create_13: { + parameters: { + path: { + organizationId: number; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateGlossaryRequest"]; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["GlossaryModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Get all organization glossaries with some additional statistics */ + getAllWithStats: { + parameters: { + query?: { + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + search?: string; + }; + path: { + organizationId: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["PagedModelSimpleGlossaryWithStatsModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Get glossary */ + get_13: { + parameters: { + path: { + organizationId: number; + glossaryId: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["GlossaryModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Update glossary */ + update_8: { + parameters: { + path: { + organizationId: number; + glossaryId: number; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateGlossaryRequest"]; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["GlossaryModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Delete glossary */ + delete_7: { + parameters: { + path: { + organizationId: number; + glossaryId: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: never; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Get all projects assigned to glossary */ + getAssignedProjects: { + parameters: { + path: { + organizationId: number; + glossaryId: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["CollectionModelSimpleProjectModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Export glossary terms as CSV */ + export: { + parameters: { + path: { + organizationId: number; + glossaryId: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["StreamingResponseBody"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Import glossary terms from CSV */ + importCsv: { + parameters: { + query?: { + removeExistingTerms?: boolean; + }; + path: { + organizationId: number; + glossaryId: number; + }; + }; + requestBody?: { + content: { + "multipart/form-data": { + /** Format: binary */ + file: string; + }; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["GlossaryImportResult"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Get all languages in use by the glossary */ + getLanguages: { + parameters: { + path: { + organizationId: number; + glossaryId: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["CollectionModelGlossaryLanguageDto"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Get all glossary terms */ + getAll_13: { + parameters: { + query?: { + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + search?: string; + languageTags?: string[]; + }; + path: { + organizationId: number; + glossaryId: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["PagedModelSimpleGlossaryTermModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Create a new glossary term */ + create_14: { + parameters: { + path: { + organizationId: number; + glossaryId: number; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateGlossaryTermWithTranslationRequest"]; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["CreateUpdateGlossaryTermResponse"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Batch delete multiple terms */ + deleteMultiple: { + parameters: { + path: { + organizationId: number; + glossaryId: number; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["DeleteMultipleGlossaryTermsRequest"]; + }; + }; + responses: { + /** @description OK */ + 200: { + content: never; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Get glossary term */ + get_14: { + parameters: { + path: { + organizationId: number; + glossaryId: number; + termId: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["GlossaryTermModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Update glossary term */ + update_9: { + parameters: { + path: { + organizationId: number; + glossaryId: number; + termId: number; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateGlossaryTermWithTranslationRequest"]; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["CreateUpdateGlossaryTermResponse"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Delete glossary term */ + delete_8: { + parameters: { + path: { + organizationId: number; + glossaryId: number; + termId: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: never; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Set a new glossary term translation for language */ + update_12: { + parameters: { + path: { + organizationId: number; + glossaryId: number; + termId: number; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateGlossaryTermTranslationRequest"]; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["GlossaryTermTranslationModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Get glossary term translation for language */ + get_23: { + parameters: { + path: { + organizationId: number; + glossaryId: number; + termId: number; + languageTag: string; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["GlossaryTermTranslationModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Get all glossary terms ids */ + getAllIds: { + parameters: { + query?: { + search?: string; + languageTags?: string[]; + }; + path: { + organizationId: number; + glossaryId: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["CollectionModelLong"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Get all glossary terms with translations */ + getAllWithTranslations: { + parameters: { + query?: { + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + search?: string; + languageTags?: string[]; + }; + path: { + organizationId: number; + glossaryId: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["PagedModelSimpleGlossaryTermWithTranslationsModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** + * Get credit balance for organization + * @description Returns machine translation credit balance for organization + */ + getOrganizationCredits: { + parameters: { + path: { + organizationId: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["CreditBalanceModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Get organization by slug */ + get_22: { + parameters: { + path: { + slug: string; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["OrganizationModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** + * Return current PAK + * @description Returns current Personal Access Token. If the request is not authenticated with a Personal Access Token, it will return 400 response status. + */ + getCurrent: { + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["PatWithUserModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** + * Get all permitted + * @description Returns all projects where current user has any permission + */ + getAll: { + parameters: { + query?: { + /** @description Filter projects by id */ + filterId?: number[]; + /** @description Filter projects without id */ + filterNotId?: number[]; + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + search?: string; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["PagedModelProjectModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** + * Create project + * @description Creates a new project with languages and initial settings. + */ + createProject: { + requestBody: { + content: { + "application/json": components["schemas"]["CreateProjectRequest"]; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["ProjectModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Get project activity */ + getActivity_1: { + parameters: { + query?: { + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["PagedModelProjectActivityModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Get one revision data */ + getSingleRevision_1: { + parameters: { + path: { + revisionId: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["ProjectActivityModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** List batch operations */ + list_4: { + parameters: { + query?: { + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["PagedModelBatchJobModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Get batch operation */ + get_21: { + parameters: { + path: { + id: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["BatchJobModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** + * Stop batch operation + * @description Stops batch operation if possible. + */ + cancel_1: { + parameters: { + path: { + id: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: never; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; }; - DeleteKeysDto: { - /** @description IDs of keys to delete */ - ids: number[]; + }; + /** + * Store Big Meta + * @description Stores a bigMeta for a project + */ + store_3: { + requestBody: { + content: { + "application/json": components["schemas"]["BigMetaDto"]; + }; + }; + responses: { + /** @description OK */ + 200: { + content: never; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; }; }; - responses: never; - parameters: never; - requestBodies: never; - headers: never; - pathItems: never; -} - -export type $defs = Record; - -export type external = Record; - -export interface operations { - /** - * Get user info - * @description Returns information about currently authenticated user. + * Get all running and pending batch operations + * @description Returns all running and pending batch operations. Completed batch operations are returned only if they are not older than 1 hour. If user doesn't have permission to view all batch operations, only their operations are returned. */ - getInfo_2: { + currentJobs_1: { responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["PrivateUserAccountModel"]; + "application/json": components["schemas"]["CollectionModelBatchJobModel"]; }; }; /** @description Bad Request */ @@ -2597,18 +5409,119 @@ export interface operations { }; }; }; - /** Reopen task */ - reopenTask_1: { + /** + * Export data + * @description + * Exports project data in various formats (JSON, properties, YAML, etc.). + * + * ## HTTP Conditional Requests Support + * + * This endpoint supports HTTP conditional requests using both If-Modified-Since and If-None-Match headers: + * + * - **If-Modified-Since header provided**: The server checks if the project data has been modified since the specified date + * - **If-None-Match header provided**: The server checks if the project data has changed by comparing the eTag value + * - **Data not modified**: Returns HTTP 304 Not Modified with empty body + * - **Data modified or no header**: Returns HTTP 200 OK with the exported data, Last-Modified header, and ETag header + * + * The Last-Modified header in the response contains the timestamp of the last project modification, + * and the ETag header contains a unique identifier for the current project state. Both can be used + * for subsequent conditional requests to avoid unnecessary data transfer when the project hasn't changed. + * + * Cache-Control header is set to max-age=0 to ensure validation on each request. + */ + exportData_1: { parameters: { - path: { - taskNumber: number; + query: { + /** + * @description Languages to be contained in export. + * + * If null, all languages are exported + * @example en + */ + languages?: string[]; + /** @description Format to export to */ + format: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX" | "APPLE_XCSTRINGS" | "ANDROID_SDK" | "APPLE_SDK"; + /** + * @description Delimiter to structure file content. + * + * e.g. For key "home.header.title" would result in {"home": {"header": "title": {"Hello"}}} structure. + * + * When null, resulting file won't be structured. Works only for generic structured formats (e.g. JSON, YAML), + * specific formats like `YAML_RUBY` don't honor this parameter. + */ + structureDelimiter?: string; + /** @description Filter key IDs to be contained in export */ + filterKeyId?: number[]; + /** @description Filter key IDs not to be contained in export */ + filterKeyIdNot?: number[]; + /** + * @description Filter keys tagged by. + * + * This filter works the same as `filterTagIn` but in this cases it accepts single tag only. + */ + filterTag?: string; + /** @description Filter keys tagged by one of provided tags */ + filterTagIn?: string[]; + /** @description Filter keys not tagged by one of provided tags */ + filterTagNotIn?: string[]; + /** @description Filter keys with prefix */ + filterKeyPrefix?: string; + /** @description Filter translations with state. By default, all states except untranslated is exported. */ + filterState?: ("UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED")[]; + /** @description Filter translations with namespace. By default, all namespaces everything are exported. To export default namespace, use empty string. */ + filterNamespace?: string[]; + /** + * @description If false, it doesn't return zip of files, but it returns single file. + * + * This is possible only when single language is exported. Otherwise it returns "400 - Bad Request" response. + */ + zip: boolean; + /** + * @description Message format to be used for export. + * + * e.g. PHP_PO: Hello %s, ICU: Hello {name}. + * + * This property is honored only for generic formats like JSON or YAML. + * For specific formats like `YAML_RUBY` it's ignored. + */ + messageFormat?: "C_SPRINTF" | "PHP_SPRINTF" | "JAVA_STRING_FORMAT" | "APPLE_SPRINTF" | "RUBY_SPRINTF" | "I18NEXT" | "ICU" | "PYTHON_PERCENT"; + /** + * @description This is a template that defines the structure of the resulting .zip file content. + * + * The template is a string that can contain the following placeholders: {namespace}, {languageTag}, + * {androidLanguageTag}, {snakeLanguageTag}, {extension}. + * + * For example, when exporting to JSON with the template `{namespace}/{languageTag}.{extension}`, + * the English translations of the `home` namespace will be stored in `home/en.json`. + * + * The `{snakeLanguageTag}` placeholder is the same as `{languageTag}` but in snake case. (e.g., en_US). + * + * The Android specific `{androidLanguageTag}` placeholder is the same as `{languageTag}` + * but in Android format. (e.g., en-rUS) + */ + fileStructureTemplate?: string; + /** + * @description If true, for structured formats (like JSON) arrays are supported. + * + * e.g. Key hello[0] will be exported as {"hello": ["..."]} + */ + supportArrays: boolean; + /** + * @description If true, HTML tags are escaped in the exported file. (Supported in the XLIFF format only). + * + * e.g. Key hello will be exported as <b>hello</b> + */ + escapeHtml?: boolean; }; }; responses: { - /** @description OK */ + /** + * @description When multiple files are exported, they are zipped and returned as a single zip file. + * When a single file is exported, it is returned directly. + */ 200: { content: { - "application/json": components["schemas"]["TaskModel"]; + "application/*": unknown; }; }; /** @description Bad Request */ @@ -2638,26 +5551,45 @@ export interface operations { }; }; /** - * Update task key - * @description Mark key as done, which updates task progress. + * Export data (post) + * @description + * Exports project data in various formats (JSON, properties, YAML, etc.). + * Useful when exceeding allowed URL size with GET requests. + * + * ## HTTP Conditional Requests Support + * + * This endpoint supports HTTP conditional requests using both If-Modified-Since and If-None-Match headers: + * + * - **If-Modified-Since header provided**: The server checks if the project data has been modified since the specified date + * - **If-None-Match header provided**: The server checks if the project data has changed by comparing the eTag value + * - **Data not modified**: Returns HTTP 304 Not Modified with empty body + * - **Data modified or no header**: Returns HTTP 200 OK with the exported data, Last-Modified header, and ETag header + * + * Note: This endpoint uses a custom implementation that returns 304 Not Modified for all HTTP methods + * (including POST) when conditional headers indicate the data hasn't changed. This differs from Spring's + * default behavior which returns 412 for POST requests, but is appropriate here since POST is used only + * to accommodate large request parameters, not to modify data. + * + * The Last-Modified header in the response contains the timestamp of the last project modification, + * and the ETag header contains a unique identifier for the current project state. Both can be used + * for subsequent conditional requests to avoid unnecessary data transfer when the project hasn't changed. + * + * Cache-Control header is set to max-age=0 to ensure validation on each request. */ - updateTaskKey_1: { - parameters: { - path: { - taskNumber: number; - keyId: number; - }; - }; + exportPost_1: { requestBody: { content: { - "application/json": components["schemas"]["UpdateTaskKeyRequest"]; + "application/json": components["schemas"]["ExportParams"]; }; }; responses: { - /** @description OK */ + /** + * @description When multiple files are exported, they are zipped and returned as a single zip file. + * When a single file is exported, it is returned directly. + */ 200: { content: { - "application/json": components["schemas"]["UpdateTaskKeyResponse"]; + "application/*": unknown; }; }; /** @description Bad Request */ @@ -2686,19 +5618,69 @@ export interface operations { }; }; }; - /** Get task keys */ - getTaskKeys_1: { + /** + * Add files + * @description Prepares provided files to import. + */ + addFiles_1: { parameters: { - path: { - taskNumber: number; + query?: { + /** + * @description When importing files in structured formats (e.g., JSON, YAML), this field defines the delimiter which will be used in names of imported keys. + * @example . + */ + structureDelimiter?: string; + }; + }; + requestBody?: { + content: { + "multipart/form-data": { + files: string[]; + }; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["ImportAddFilesResultModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; }; }; + }; + /** + * Delete + * @description Deletes prepared import data. + */ + cancelImport_1: { responses: { /** @description OK */ 200: { - content: { - "application/json": components["schemas"]["TaskKeysResponse"]; - }; + content: never; }; /** @description Bad Request */ 400: { @@ -2726,22 +5708,17 @@ export interface operations { }; }; }; - /** Add or remove task keys */ - updateTaskKeys_1: { - parameters: { - path: { - taskNumber: number; - }; - }; - requestBody: { - content: { - "application/json": components["schemas"]["UpdateTaskKeysRequest"]; - }; - }; + /** + * Get Import Settings + * @description Returns import settings for the authenticated user and the project. + */ + get_1: { responses: { /** @description OK */ 200: { - content: never; + content: { + "application/json": components["schemas"]["ImportSettingsModel"]; + }; }; /** @description Bad Request */ 400: { @@ -2769,18 +5746,21 @@ export interface operations { }; }; }; - /** Finish task */ - finishTask_1: { - parameters: { - path: { - taskNumber: number; + /** + * Set Import Settings + * @description Stores import settings for the authenticated user and the project. + */ + store_1: { + requestBody: { + content: { + "application/json": components["schemas"]["ImportSettingsRequest"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["TaskModel"]; + "application/json": components["schemas"]["ImportSettingsModel"]; }; }; /** @description Bad Request */ @@ -2809,18 +5789,16 @@ export interface operations { }; }; }; - /** Close task */ - closeTask_1: { - parameters: { - path: { - taskNumber: number; - }; - }; + /** + * Get namespaces + * @description Returns all existing and imported namespaces + */ + getAllNamespaces_1: { responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["TaskModel"]; + "application/json": components["schemas"]["CollectionModelImportNamespaceModel"]; }; }; /** @description Bad Request */ @@ -2849,19 +5827,21 @@ export interface operations { }; }; }; - /** Get task */ - getTask_1: { + /** + * Apply import + * @description Imports the data prepared in previous step + */ + applyImport_1: { parameters: { - path: { - taskNumber: number; + query?: { + /** @description Whether override or keep all translations with unresolved conflicts */ + forceMode?: "OVERRIDE" | "KEEP" | "NO_FORCE"; }; }; responses: { /** @description OK */ 200: { - content: { - "application/json": components["schemas"]["TaskModel"]; - }; + content: never; }; /** @description Bad Request */ 400: { @@ -2889,23 +5869,22 @@ export interface operations { }; }; }; - /** Update task */ - updateTask_1: { + /** + * Apply import (streaming) + * @description Imports the data prepared in previous step. Streams current status. + */ + applyImportStreaming_1: { parameters: { - path: { - taskNumber: number; - }; - }; - requestBody: { - content: { - "application/json": components["schemas"]["UpdateTaskRequest"]; + query?: { + /** @description Whether override or keep all translations with unresolved conflicts */ + forceMode?: "OVERRIDE" | "KEEP" | "NO_FORCE"; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["TaskModel"]; + "application/x-ndjson": components["schemas"]["StreamingResponseBody"]; }; }; /** @description Bad Request */ @@ -2934,23 +5913,26 @@ export interface operations { }; }; }; - /** Update namespace */ - update_2: { + /** + * Get result + * @description Returns the result of preparation. + */ + getImportResult_1: { parameters: { - path: { - id: number; - }; - }; - requestBody: { - content: { - "application/json": components["schemas"]["UpdateNamespaceDto"]; + query?: { + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["NamespaceModel"]; + "application/json": components["schemas"]["PagedModelImportLanguageModel"]; }; }; /** @description Bad Request */ @@ -2980,21 +5962,24 @@ export interface operations { }; }; /** - * Get disabled languages - * @description Returns languages, in which key is disabled + * Select namespace + * @description Sets namespace for file to import. */ - getDisabledLanguages_1: { + selectNamespace_1: { parameters: { path: { - id: number; + fileId: number; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["SetFileNamespaceRequest"]; }; }; responses: { /** @description OK */ 200: { - content: { - "application/json": components["schemas"]["CollectionModelLanguageModel"]; - }; + content: never; }; /** @description Bad Request */ 400: { @@ -3023,25 +6008,28 @@ export interface operations { }; }; /** - * Set disabled languages - * @description Sets languages, in which key is disabled + * Get file issues + * @description Returns issues for uploaded file. */ - setDisabledLanguages_1: { + getImportFileIssues_1: { parameters: { - path: { - id: number; + query?: { + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; }; - }; - requestBody: { - content: { - "application/json": components["schemas"]["SetDisabledLanguagesRequest"]; + path: { + importFileId: number; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["CollectionModelLanguageModel"]; + "application/json": components["schemas"]["PagedModelImportFileIssueModel"]; }; }; /** @description Bad Request */ @@ -3071,26 +6059,19 @@ export interface operations { }; }; /** - * Edit key and related data - * @description Edits key name, translations, tags, screenshots, and other data + * Reset existing language pairing + * @description Resets existing language paired with language to import. */ - complexEdit_1: { + resetExistingLanguage_1: { parameters: { path: { - id: number; - }; - }; - requestBody: { - content: { - "application/json": components["schemas"]["ComplexEditKeyDto"]; + importLanguageId: number; }; }; responses: { /** @description OK */ 200: { - content: { - "application/json": components["schemas"]["KeyWithDataModel"]; - }; + content: never; }; /** @description Bad Request */ 400: { @@ -3118,19 +6099,21 @@ export interface operations { }; }; }; - /** Get one key */ - get_7: { + /** + * Pair existing language + * @description Sets existing language to pair with language to import. Data will be imported to selected existing language when applied. + */ + selectExistingLanguage_1: { parameters: { path: { - id: number; + importLanguageId: number; + existingLanguageId: number; }; }; responses: { /** @description OK */ 200: { - content: { - "application/json": components["schemas"]["KeyModel"]; - }; + content: never; }; /** @description Bad Request */ 400: { @@ -3158,23 +6141,21 @@ export interface operations { }; }; }; - /** Edit key name */ - edit_1: { + /** + * Get import language + * @description Returns language prepared to import. + */ + getImportLanguage_1: { parameters: { path: { - id: number; - }; - }; - requestBody: { - content: { - "application/json": components["schemas"]["EditKeyDto"]; + languageId: number; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["KeyModel"]; + "application/json": components["schemas"]["ImportLanguageModel"]; }; }; /** @description Bad Request */ @@ -3203,11 +6184,14 @@ export interface operations { }; }; }; - /** Execute complex tag operation */ - executeComplexTagOperation_1: { - requestBody: { - content: { - "application/json": components["schemas"]["ComplexTagKeysRequest"]; + /** + * Delete language + * @description Deletes language prepared to import. + */ + deleteLanguage_3: { + parameters: { + path: { + languageId: number; }; }; responses: { @@ -3242,26 +6226,19 @@ export interface operations { }; }; /** - * Tag key - * @description Tags a key with tag. If tag with provided name doesn't exist, it is created + * Resolve all translation conflicts (keep existing) + * @description Resolves all translation conflicts for provided language. The old translations will be kept. */ - tagKey_1: { + resolveTranslationSetKeepExisting_3: { parameters: { path: { - keyId: number; - }; - }; - requestBody: { - content: { - "application/json": components["schemas"]["TagKeyDto"]; + languageId: number; }; }; responses: { /** @description OK */ 200: { - content: { - "application/json": components["schemas"]["TagModel"]; - }; + content: never; }; /** @description Bad Request */ 400: { @@ -3290,14 +6267,13 @@ export interface operations { }; }; /** - * Resolve conflict (override) - * @description Resolves translation conflict. The old translation will be overridden. + * Resolve all translation conflicts (override) + * @description Resolves all translation conflicts for provided language. The old translations will be overridden. */ - resolveTranslationSetOverride_1: { + resolveTranslationSetOverride_3: { parameters: { path: { languageId: number; - translationId: number; }; }; responses: { @@ -3332,20 +6308,35 @@ export interface operations { }; }; /** - * Resolve conflict (keep existing) - * @description Resolves translation conflict. The old translation will be kept. + * Get translations + * @description Returns translations prepared to import. */ - resolveTranslationSetKeepExisting_1: { + getImportTranslations_1: { parameters: { + query?: { + /** @description Whether only translations, which are in conflict with existing translations should be returned */ + onlyConflicts?: boolean; + /** @description Whether only translations with unresolved conflictswith existing translations should be returned */ + onlyUnresolved?: boolean; + /** @description String to search in translation text or key */ + search?: string; + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + }; path: { languageId: number; - translationId: number; }; }; responses: { /** @description OK */ 200: { - content: never; + content: { + "application/json": components["schemas"]["PagedModelImportTranslationModel"]; + }; }; /** @description Bad Request */ 400: { @@ -3374,13 +6365,14 @@ export interface operations { }; }; /** - * Resolve all translation conflicts (override) - * @description Resolves all translation conflicts for provided language. The old translations will be overridden. + * Resolve conflict (keep existing) + * @description Resolves translation conflict. The old translation will be kept. */ - resolveTranslationSetOverride_3: { + resolveTranslationSetKeepExisting_1: { parameters: { path: { languageId: number; + translationId: number; }; }; responses: { @@ -3415,13 +6407,14 @@ export interface operations { }; }; /** - * Resolve all translation conflicts (keep existing) - * @description Resolves all translation conflicts for provided language. The old translations will be kept. + * Resolve conflict (override) + * @description Resolves translation conflict. The old translation will be overridden. */ - resolveTranslationSetKeepExisting_3: { + resolveTranslationSetOverride_1: { parameters: { path: { languageId: number; + translationId: number; }; }; responses: { @@ -3455,21 +6448,24 @@ export interface operations { }; }; }; - /** - * Pair existing language - * @description Sets existing language to pair with language to import. Data will be imported to selected existing language when applied. - */ - selectExistingLanguage_1: { + /** Get all keys */ + getAll_8: { parameters: { - path: { - importLanguageId: number; - existingLanguageId: number; + query?: { + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; }; }; responses: { /** @description OK */ 200: { - content: never; + content: { + "application/json": components["schemas"]["PagedModelKeyModel"]; + }; }; /** @description Bad Request */ 400: { @@ -3497,20 +6493,19 @@ export interface operations { }; }; }; - /** - * Reset existing language pairing - * @description Resets existing language paired with language to import. - */ - resetExistingLanguage_1: { - parameters: { - path: { - importLanguageId: number; + /** Create new key */ + create_8: { + requestBody: { + content: { + "application/json": components["schemas"]["CreateKeyDto"]; }; }; responses: { - /** @description OK */ - 200: { - content: never; + /** @description Created */ + 201: { + content: { + "*/*": components["schemas"]["KeyWithDataModel"]; + }; }; /** @description Bad Request */ 400: { @@ -3539,18 +6534,13 @@ export interface operations { }; }; /** - * Select namespace - * @description Sets namespace for file to import. + * Delete one or multiple keys (post) + * @description Delete one or multiple keys by their IDs in request body. Useful for larger requests esxceeding allowed URL length. */ - selectNamespace_1: { - parameters: { - path: { - fileId: number; - }; - }; + delete_12: { requestBody: { content: { - "application/json": components["schemas"]["SetFileNamespaceRequest"]; + "application/json": components["schemas"]["DeleteKeysDto"]; }; }; responses: { @@ -3584,22 +6574,18 @@ export interface operations { }; }; }; - /** - * Apply import (streaming) - * @description Imports the data prepared in previous step. Streams current status. - */ - applyImportStreaming_1: { - parameters: { - query?: { - /** @description Whether override or keep all translations with unresolved conflicts */ - forceMode?: "OVERRIDE" | "KEEP" | "NO_FORCE"; + /** Create new key */ + create_7: { + requestBody: { + content: { + "application/json": components["schemas"]["CreateKeyDto"]; }; }; responses: { - /** @description OK */ - 200: { + /** @description Created */ + 201: { content: { - "application/x-ndjson": components["schemas"]["StreamingResponseBody"]; + "*/*": components["schemas"]["KeyWithDataModel"]; }; }; /** @description Bad Request */ @@ -3629,14 +6615,13 @@ export interface operations { }; }; /** - * Apply import - * @description Imports the data prepared in previous step + * Import keys + * @description Imports new keys with translations. If key already exists, its translations and tags are not updated. */ - applyImport_1: { - parameters: { - query?: { - /** @description Whether override or keep all translations with unresolved conflicts */ - forceMode?: "OVERRIDE" | "KEEP" | "NO_FORCE"; + importKeys_3: { + requestBody: { + content: { + "application/json": components["schemas"]["ImportKeysDto"]; }; }; responses: { @@ -3671,15 +6656,23 @@ export interface operations { }; }; /** - * Get Import Settings - * @description Returns import settings for the authenticated user and the project. + * Import keys (resolvable) + * @deprecated + * @description + * Import's new keys with translations. Translations can be updated, when specified.\n\n + * DEPRECATED: Use /v2/projects/{projectId}/single-step-import-resolvable instead. */ - get_11: { + importKeys_1: { + requestBody: { + content: { + "application/json": components["schemas"]["ImportKeysResolvableDto"]; + }; + }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["ImportSettingsModel"]; + "application/json": components["schemas"]["KeyImportResolvableResultModel"]; }; }; /** @description Bad Request */ @@ -3709,20 +6702,20 @@ export interface operations { }; }; /** - * Set Import Settings - * @description Stores import settings for the authenticated user and the project. + * Get key info + * @description Returns information about keys. (KeyData, Screenshots, Translation in specified language)If key is not found, it's not included in the response. */ - store_1: { + getInfo_2: { requestBody: { content: { - "application/json": components["schemas"]["ImportSettingsRequest"]; + "application/json": components["schemas"]["GetKeysRequestDto"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["ImportSettingsModel"]; + "application/json": components["schemas"]["CollectionModelKeyWithDataModel"]; }; }; /** @description Bad Request */ @@ -3752,19 +6745,32 @@ export interface operations { }; }; /** - * Stop batch operation - * @description Stops batch operation if possible. + * Search for keys + * @description This endpoint helps you to find desired key by keyName, base translation or translation in specified language. + * + * Sort is ignored for this request. */ - cancel_1: { + searchForKey_1: { parameters: { - path: { - id: number; + query: { + /** @description Search query */ + search: string; + /** @description Language to search in */ + languageTag?: string; + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; }; }; responses: { /** @description OK */ 200: { - content: never; + content: { + "application/json": components["schemas"]["PagedModelKeySearchSearchResultModel"]; + }; }; /** @description Bad Request */ 400: { @@ -3792,19 +6798,116 @@ export interface operations { }; }; }; - /** Set translation state */ - setTranslationState_1: { + /** + * Select keys + * @description Returns all key IDs for specified filter values. This way, you can apply the same filter as in the translation view and get the resulting key IDs for future use. + */ + selectKeys_3: { parameters: { - path: { - translationId: number; - state: "TRANSLATED" | "REVIEWED"; + query?: { + /** + * @description Translation state in the format: languageTag,state. You can use this parameter multiple times. + * + * When used with multiple states for same language it is applied with logical OR. + * + * When used with multiple languages, it is applied with logical AND. + */ + filterState?: string[]; + /** + * @description Languages to be contained in response. + * + * To add multiple languages, repeat this param (eg. ?languages=en&languages=de) + * @example en + */ + languages?: string[]; + /** @description String to search in key name or translation text */ + search?: string; + /** @description Selects key with provided names. Use this param multiple times to fetch more keys. */ + filterKeyName?: string[]; + /** @description Selects key with provided ID. Use this param multiple times to fetch more keys. */ + filterKeyId?: number[]; + /** @description Selects only keys for which the translation is missing in any returned language. It only filters for translations included in returned languages. */ + filterUntranslatedAny?: boolean; + /** @description Selects only keys, where translation is provided in any language */ + filterTranslatedAny?: boolean; + /** + * @description Selects only keys where the translation is missing for the specified language. The specified language must be included in the returned languages. Otherwise, this filter doesn't apply. + * @example en-US + */ + filterUntranslatedInLang?: string; + /** + * @description Selects only keys, where translation is provided in specified language + * @example en-US + */ + filterTranslatedInLang?: string; + /** + * @description Selects only keys, where translation was auto translated for specified languages. + * @example en-US + */ + filterAutoTranslatedInLang?: string[]; + /** @description Selects only keys with screenshots */ + filterHasScreenshot?: boolean; + /** @description Selects only keys without screenshots */ + filterHasNoScreenshot?: boolean; + /** + * @description Selects only keys with provided namespaces. + * + * To filter default namespace, set to empty string. + */ + filterNamespace?: string[]; + /** + * @description Selects only keys without provided namespaces. + * + * To filter default namespace, set to empty string. + */ + filterNoNamespace?: string[]; + /** @description Selects only keys with provided tag */ + filterTag?: string[]; + /** @description Selects only keys without provided tag */ + filterNoTag?: string[]; + /** + * @description Selects only keys, where translation in provided langs is in outdated state + * @example en-US + */ + filterOutdatedLanguage?: string[]; + /** + * @description Selects only keys, where translation in provided langs is not in outdated state + * @example en-US + */ + filterNotOutdatedLanguage?: string[]; + /** + * @description Selects only key affected by activity with specidfied revision ID + * @example 1234567 + */ + filterRevisionId?: number[]; + /** @description Select only keys which were not successfully translated by batch job with provided id */ + filterFailedKeysOfJob?: number; + /** @description Select only keys which are in specified task */ + filterTaskNumber?: number[]; + /** @description Filter task keys which are `not done` */ + filterTaskKeysNotDone?: boolean; + /** @description Filter task keys which are `done` */ + filterTaskKeysDone?: boolean; + /** @description Filter keys with unresolved comments in lang */ + filterHasUnresolvedCommentsInLang?: string[]; + /** @description Filter keys with any comments in lang */ + filterHasCommentsInLang?: string[]; + /** + * @description Filter key translations with labels + * @example labelId1,labelId2 + */ + filterLabel?: string[]; + /** @description Filter keys with any suggestions in lang */ + filterHasSuggestionsInLang?: string[]; + /** @description Filter keys with no suggestions in lang */ + filterHasNoSuggestionsInLang?: string[]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["TranslationModel"]; + "application/json": components["schemas"]["SelectAllResponse"]; }; }; /** @description Bad Request */ @@ -3833,21 +6936,17 @@ export interface operations { }; }; }; - /** Set state of translation comment */ - setState_1: { + /** Delete one or multiple keys */ + delete_14: { parameters: { path: { - translationId: number; - commentId: number; - state: "RESOLUTION_NOT_NEEDED" | "NEEDS_RESOLUTION" | "RESOLVED"; + ids: number[]; }; }; responses: { /** @description OK */ 200: { - content: { - "application/json": components["schemas"]["TranslationCommentModel"]; - }; + content: never; }; /** @description Bad Request */ 400: { @@ -3875,19 +6974,18 @@ export interface operations { }; }; }; - /** Get one translation comment */ - get_15: { + /** Get one key */ + get_9: { parameters: { - path: { - translationId: number; - commentId: number; + path: { + id: number; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["TranslationCommentModel"]; + "application/json": components["schemas"]["KeyModel"]; }; }; /** @description Bad Request */ @@ -3916,24 +7014,23 @@ export interface operations { }; }; }; - /** Update translation comment */ - update_6: { + /** Edit key name */ + edit_1: { parameters: { path: { - commentId: number; - translationId: number; + id: number; }; }; requestBody: { content: { - "application/json": components["schemas"]["TranslationCommentDto"]; + "application/json": components["schemas"]["EditKeyDto"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["TranslationCommentModel"]; + "application/json": components["schemas"]["KeyModel"]; }; }; /** @description Bad Request */ @@ -3962,18 +7059,19 @@ export interface operations { }; }; }; - /** Delete translation comment */ - delete_9: { + /** Get Big Meta for key */ + getBigMeta_1: { parameters: { path: { - translationId: number; - commentId: number; + id: number; }; }; responses: { /** @description OK */ 200: { - content: never; + content: { + "application/json": components["schemas"]["CollectionModelKeyWithBaseTranslationModel"]; + }; }; /** @description Bad Request */ 400: { @@ -4002,21 +7100,25 @@ export interface operations { }; }; /** - * Set outdated value - * @description Set's "outdated" flag indicating the base translation was changed without updating current translation. + * Edit key and related data + * @description Edits key name, translations, tags, screenshots, and other data */ - setOutdated_1: { + complexEdit_1: { parameters: { path: { - translationId: number; - state: boolean; + id: number; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["ComplexEditKeyDto"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["TranslationModel"]; + "application/json": components["schemas"]["KeyWithDataModel"]; }; }; /** @description Bad Request */ @@ -4046,20 +7148,20 @@ export interface operations { }; }; /** - * Dismiss auto-translated - * @description Removes "auto translated" indication + * Get disabled languages + * @description Returns languages, in which key is disabled */ - dismissAutoTranslatedState_1: { + getDisabledLanguages_1: { parameters: { path: { - translationId: number; + id: number; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["TranslationModel"]; + "application/json": components["schemas"]["CollectionModelLanguageModel"]; }; }; /** @description Bad Request */ @@ -4088,91 +7190,26 @@ export interface operations { }; }; }; - /** Get translations in project */ - getTranslations_1: { + /** + * Set disabled languages + * @description Sets languages, in which key is disabled + */ + setDisabledLanguages_1: { parameters: { - query?: { - /** @description Cursor to get next data */ - cursor?: string; - /** - * @description Translation state in the format: languageTag,state. You can use this parameter multiple times. - * - * When used with multiple states for same language it is applied with logical OR. - * - * When used with multiple languages, it is applied with logical AND. - */ - filterState?: string[]; - /** - * @description Languages to be contained in response. - * - * To add multiple languages, repeat this param (eg. ?languages=en&languages=de) - * @example en - */ - languages?: string[]; - /** @description String to search in key name or translation text */ - search?: string; - /** @description Selects key with provided names. Use this param multiple times to fetch more keys. */ - filterKeyName?: string[]; - /** @description Selects key with provided ID. Use this param multiple times to fetch more keys. */ - filterKeyId?: number[]; - /** @description Selects only keys for which the translation is missing in any returned language. It only filters for translations included in returned languages. */ - filterUntranslatedAny?: boolean; - /** @description Selects only keys, where translation is provided in any language */ - filterTranslatedAny?: boolean; - /** - * @description Selects only keys where the translation is missing for the specified language. The specified language must be included in the returned languages. Otherwise, this filter doesn't apply. - * @example en-US - */ - filterUntranslatedInLang?: string; - /** - * @description Selects only keys, where translation is provided in specified language - * @example en-US - */ - filterTranslatedInLang?: string; - /** @description Selects only keys with screenshots */ - filterHasScreenshot?: boolean; - /** @description Selects only keys without screenshots */ - filterHasNoScreenshot?: boolean; - /** - * @description Filter namespaces. - * - * To filter default namespace, set to empty string. - */ - filterNamespace?: string[]; - /** @description Selects only keys with provided tag */ - filterTag?: string[]; - /** - * @description Selects only keys, where translation in provided langs is in outdated state - * @example en-US - */ - filterOutdatedLanguage?: string[]; - /** - * @description Selects only keys, where translation in provided langs is not in outdated state - * @example en-US - */ - filterNotOutdatedLanguage?: string[]; - /** - * @description Selects only key affected by activity with specidfied revision ID - * @example 1234567 - */ - filterRevisionId?: number[]; - /** @description Select only keys which were not successfully translated by batch job with provided id */ - filterFailedKeysOfJob?: number; - /** @description Select only keys which are in specified task */ - filterTaskNumber?: number[]; - /** @description Zero-based page index (0..N) */ - page?: number; - /** @description The size of the page to be returned */ - size?: number; - /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; + path: { + id: number; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["SetDisabledLanguagesRequest"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["KeysWithTranslationsPageModel"]; + "application/json": components["schemas"]["CollectionModelLanguageModel"]; }; }; /** @description Bad Request */ @@ -4202,21 +7239,31 @@ export interface operations { }; }; /** - * Update translations for existing key - * @description Sets translations for existing key + * Auto translates keys + * @description Uses enabled auto-translation methods. + * You need to set at least one of useMachineTranslation or useTranslationMemory to true. + * + * This will replace the the existing translation with the result obtained from specified source! */ - setTranslations_1: { - requestBody: { - content: { - "application/json": components["schemas"]["SetTranslationsWithKeyDto"]; + autoTranslate_1: { + parameters: { + query?: { + /** + * @description Tags of languages to auto-translate. + * When no languages provided, it translates only untranslated languages. + */ + languages?: string[]; + useMachineTranslation?: boolean; + useTranslationMemory?: boolean; + }; + path: { + keyId: number; }; }; responses: { /** @description OK */ 200: { - content: { - "application/json": components["schemas"]["SetTranslationsResponseModel"]; - }; + content: never; }; /** @description Bad Request */ 400: { @@ -4244,21 +7291,18 @@ export interface operations { }; }; }; - /** - * Create key or update translations - * @description Sets translations for existing key or creates new key and sets the translations to it. - */ - createOrUpdateTranslations_1: { - requestBody: { - content: { - "application/json": components["schemas"]["SetTranslationsWithKeyDto"]; + /** Get screenshots */ + getKeyScreenshots: { + parameters: { + path: { + keyId: number; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["SetTranslationsResponseModel"]; + "application/json": components["schemas"]["CollectionModelScreenshotModel"]; }; }; /** @description Bad Request */ @@ -4287,18 +7331,27 @@ export interface operations { }; }; }; - /** Get one language */ - get_17: { + /** Upload screenshot */ + uploadScreenshot: { parameters: { path: { - languageId: number; + keyId: number; + }; + }; + requestBody?: { + content: { + "multipart/form-data": { + /** Format: binary */ + screenshot: string; + info?: components["schemas"]["ScreenshotInfoDto"]; + }; }; }; responses: { - /** @description OK */ - 200: { + /** @description Created */ + 201: { content: { - "application/json": components["schemas"]["LanguageModel"]; + "*/*": components["schemas"]["ScreenshotModel"]; }; }; /** @description Bad Request */ @@ -4327,24 +7380,18 @@ export interface operations { }; }; }; - /** Update language */ - editLanguage_1: { + /** Delete screenshots */ + deleteScreenshots: { parameters: { path: { - languageId: number; - }; - }; - requestBody: { - content: { - "application/json": components["schemas"]["LanguageRequest"]; + ids: number[]; + keyId: number; }; }; responses: { /** @description OK */ 200: { - content: { - "application/json": components["schemas"]["LanguageModel"]; - }; + content: never; }; /** @description Bad Request */ 400: { @@ -4372,17 +7419,27 @@ export interface operations { }; }; }; - /** Delete specific language */ - deleteLanguage_3: { + /** + * Tag key + * @description Tags a key with tag. If tag with provided name doesn't exist, it is created + */ + tagKey_1: { parameters: { path: { - languageId: number; + keyId: number; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["TagKeyDto"]; }; }; responses: { /** @description OK */ 200: { - content: never; + content: { + "application/json": components["schemas"]["TagModel"]; + }; }; /** @description Bad Request */ 400: { @@ -4411,25 +7468,14 @@ export interface operations { }; }; /** - * Auto translates keys - * @description Uses enabled auto-translation methods. - * You need to set at least one of useMachineTranslation or useTranslationMemory to true. - * - * This will replace the the existing translation with the result obtained from specified source! + * Remove tag + * @description Removes tag with provided id from key with provided id */ - autoTranslate_1: { - parameters: { - query?: { - /** - * @description Tags of languages to auto-translate. - * When no languages provided, it translates only untranslated languages. - */ - languages?: string[]; - useMachineTranslation?: boolean; - useTranslationMemory?: boolean; - }; + removeTag_1: { + parameters: { path: { keyId: number; + tagId: number; }; }; responses: { @@ -4463,18 +7509,24 @@ export interface operations { }; }; }; - /** Get one organization */ - get_20: { + /** Get available project labels */ + getAll_2: { parameters: { - path: { - id: number; + query?: { + search?: string; + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["OrganizationModel"]; + "application/json": components["schemas"]["PagedModelLabelModel"]; }; }; /** @description Bad Request */ @@ -4503,31 +7555,18 @@ export interface operations { }; }; }; - /** - * Get all permitted - * @description Returns all projects where current user has any permission - */ - getAll: { - parameters: { - query?: { - /** @description Filter projects by id */ - filterId?: number[]; - /** @description Filter projects without id */ - filterNotId?: number[]; - /** @description Zero-based page index (0..N) */ - page?: number; - /** @description The size of the page to be returned */ - size?: number; - /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; - search?: string; + /** Create label */ + createLabel_1: { + requestBody: { + content: { + "application/json": components["schemas"]["LabelRequest"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/hal+json": components["schemas"]["PagedModelProjectModel"]; + "application/json": components["schemas"]["LabelModel"]; }; }; /** @description Bad Request */ @@ -4556,21 +7595,18 @@ export interface operations { }; }; }; - /** - * Create project - * @description Creates a new project with languages and initial settings. - */ - createProject: { - requestBody: { - content: { - "application/json": components["schemas"]["CreateProjectRequest"]; + /** Get labels by ids */ + getLabelsByIds_1: { + parameters: { + query: { + id: number[]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["ProjectModel"]; + "application/json": components["schemas"]["LabelModel"][]; }; }; /** @description Bad Request */ @@ -4599,23 +7635,24 @@ export interface operations { }; }; }; - /** Create multiple tasks */ - createTasks_1: { + /** Update label */ + updateLabel_1: { parameters: { - query?: { - filterState?: ("UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED")[]; - filterOutdated?: boolean; + path: { + labelId: number; }; }; requestBody: { content: { - "application/json": components["schemas"]["CreateMultipleTasksRequest"]; + "application/json": components["schemas"]["LabelRequest"]; }; }; responses: { /** @description OK */ 200: { - content: never; + content: { + "application/json": components["schemas"]["LabelModel"]; + }; }; /** @description Bad Request */ 400: { @@ -4643,25 +7680,17 @@ export interface operations { }; }; }; - /** Calculate scope */ - calculateScope_1: { + /** Delete label */ + deleteLabel_1: { parameters: { - query?: { - filterState?: ("UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED")[]; - filterOutdated?: boolean; - }; - }; - requestBody: { - content: { - "application/json": components["schemas"]["CalculateScopeRequest"]; + path: { + labelId: number; }; }; responses: { /** @description OK */ 200: { - content: { - "application/json": components["schemas"]["KeysScopeView"]; - }; + content: never; }; /** @description Bad Request */ 400: { @@ -4689,38 +7718,21 @@ export interface operations { }; }; }; - /** Get tasks */ - getTasks_2: { + /** Get all languages */ + getAll_6: { parameters: { query?: { - /** @description Filter tasks by state */ - filterState?: ("NEW" | "IN_PROGRESS" | "DONE" | "CLOSED")[]; - /** @description Filter tasks without state */ - filterNotState?: ("NEW" | "IN_PROGRESS" | "DONE" | "CLOSED")[]; - /** @description Filter tasks by assignee */ - filterAssignee?: number[]; - /** @description Filter tasks by type */ - filterType?: ("TRANSLATE" | "REVIEW")[]; - /** @description Filter tasks by id */ - filterId?: number[]; - /** @description Filter tasks without id */ - filterNotId?: number[]; - /** @description Filter tasks by project */ - filterProject?: number[]; - /** @description Filter tasks without project */ - filterNotProject?: number[]; - /** @description Filter tasks by language */ - filterLanguage?: number[]; - /** @description Filter tasks by key */ - filterKey?: number[]; - /** @description Exclude "done" tasks which are older than specified timestamp */ - filterDoneMinClosedAt?: number; /** @description Zero-based page index (0..N) */ page?: number; /** @description The size of the page to be returned */ size?: number; /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ sort?: string[]; + /** @description Filter languages by id */ + filterId?: number[]; + /** @description Filter languages without id */ + filterNotId?: number[]; + /** @description Filter languages by name or tag */ search?: string; }; }; @@ -4728,7 +7740,7 @@ export interface operations { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelTaskModel"]; + "application/json": components["schemas"]["PagedModelLanguageModel"]; }; }; /** @description Bad Request */ @@ -4757,24 +7769,18 @@ export interface operations { }; }; }; - /** Create task */ - createTask_1: { - parameters: { - query?: { - filterState?: ("UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED")[]; - filterOutdated?: boolean; - }; - }; + /** Create language */ + createLanguage_1: { requestBody: { content: { - "application/json": components["schemas"]["CreateTaskRequest"]; + "application/json": components["schemas"]["LanguageRequest"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["TaskModel"]; + "application/json": components["schemas"]["LanguageModel"]; }; }; /** @description Bad Request */ @@ -4803,21 +7809,18 @@ export interface operations { }; }; }; - /** - * Get key info - * @description Returns information about keys. (KeyData, Screenshots, Translation in specified language)If key is not found, it's not included in the response. - */ - getInfo_1: { - requestBody: { - content: { - "application/json": components["schemas"]["GetKeysRequestDto"]; + /** Get one language */ + get_7: { + parameters: { + path: { + languageId: number; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["CollectionModelKeyWithDataModel"]; + "application/json": components["schemas"]["LanguageModel"]; }; }; /** @description Bad Request */ @@ -4846,21 +7849,23 @@ export interface operations { }; }; }; - /** - * Import keys (resolvable) - * @description Import's new keys with translations. Translations can be updated, when specified. - */ - importKeys_1: { + /** Update language */ + editLanguage_1: { + parameters: { + path: { + languageId: number; + }; + }; requestBody: { content: { - "application/json": components["schemas"]["ImportKeysResolvableDto"]; + "application/json": components["schemas"]["LanguageRequest"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["KeyImportResolvableResultModel"]; + "application/json": components["schemas"]["LanguageModel"]; }; }; /** @description Bad Request */ @@ -4889,14 +7894,11 @@ export interface operations { }; }; }; - /** - * Import keys - * @description Imports new keys with translations. If key already exists, its translations and tags are not updated. - */ - importKeys_3: { - requestBody: { - content: { - "application/json": components["schemas"]["ImportKeysDto"]; + /** Delete specific language */ + deleteLanguage_1: { + parameters: { + path: { + languageId: number; }; }; responses: { @@ -4930,18 +7932,29 @@ export interface operations { }; }; }; - /** Create new key */ - create_3: { - requestBody: { - content: { - "application/json": components["schemas"]["CreateKeyDto"]; + /** Get suggestions */ + getSuggestions_1: { + parameters: { + query?: { + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + /** @description Filter by suggestion state */ + filterState?: ("ACTIVE" | "ACCEPTED" | "DECLINED")[]; + }; + path: { + languageId: number; + keyId: number; }; }; responses: { - /** @description Created */ - 201: { + /** @description OK */ + 200: { content: { - "*/*": components["schemas"]["KeyWithDataModel"]; + "application/json": components["schemas"]["PagedModelTranslationSuggestionModel"]; }; }; /** @description Bad Request */ @@ -4970,23 +7983,24 @@ export interface operations { }; }; }; - /** Get all keys */ - getAll_2: { + /** Create translation suggestion */ + createSuggestion_1: { parameters: { - query?: { - /** @description Zero-based page index (0..N) */ - page?: number; - /** @description The size of the page to be returned */ - size?: number; - /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; + path: { + languageId: number; + keyId: number; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateTranslationSuggestionRequest"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelKeyModel"]; + "application/json": components["schemas"]["TranslationSuggestionModel"]; }; }; /** @description Bad Request */ @@ -5015,18 +8029,66 @@ export interface operations { }; }; }; - /** Create new key */ - create_4: { - requestBody: { - content: { - "application/json": components["schemas"]["CreateKeyDto"]; + /** + * Delete suggestion + * @description User can only delete suggestion created by them + */ + deleteSuggestion_1: { + parameters: { + path: { + languageId: number; + keyId: number; + suggestionId: number; }; }; responses: { - /** @description Created */ - 201: { + /** @description OK */ + 200: { + content: never; + }; + /** @description Bad Request */ + 400: { content: { - "*/*": components["schemas"]["KeyWithDataModel"]; + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** Accept suggestion */ + acceptSuggestion_1: { + parameters: { + query?: { + declineOther?: boolean; + }; + path: { + languageId: number; + keyId: number; + suggestionId: number; + }; + }; + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["TranslationSuggestionAcceptResponse"]; }; }; /** @description Bad Request */ @@ -5055,20 +8117,21 @@ export interface operations { }; }; }; - /** - * Delete one or multiple keys (post) - * @description Delete one or multiple keys by their IDs in request body. Useful for larger requests esxceeding allowed URL length. - */ - delete_5: { - requestBody: { - content: { - "application/json": components["schemas"]["DeleteKeysDto"]; + /** Decline suggestion */ + declineSuggestion_1: { + parameters: { + path: { + languageId: number; + keyId: number; + suggestionId: number; }; }; responses: { /** @description OK */ 200: { - content: never; + content: { + "application/json": components["schemas"]["TranslationSuggestionModel"]; + }; }; /** @description Bad Request */ 400: { @@ -5096,18 +8159,20 @@ export interface operations { }; }; }; - /** Remove tags */ - untagKeys_1: { - requestBody: { - content: { - "application/json": components["schemas"]["UntagKeysRequest"]; + /** Set suggestion active */ + suggestionSetActive_1: { + parameters: { + path: { + languageId: number; + keyId: number; + suggestionId: number; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["BatchJobModel"]; + "application/json": components["schemas"]["TranslationSuggestionModel"]; }; }; /** @description Bad Request */ @@ -5136,18 +8201,26 @@ export interface operations { }; }; }; - /** Add tags */ - tagKeys_1: { - requestBody: { - content: { - "application/json": components["schemas"]["TagKeysRequest"]; + /** + * List user batch operations + * @description List all batch operations started by current user + */ + myList_1: { + parameters: { + query?: { + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["BatchJobModel"]; + "application/json": components["schemas"]["PagedModelBatchJobModel"]; }; }; /** @description Bad Request */ @@ -5176,18 +8249,21 @@ export interface operations { }; }; }; - /** Set translation state */ - setTranslationState_3: { - requestBody: { - content: { - "application/json": components["schemas"]["SetTranslationsStateStateRequest"]; + /** + * Get namespace by name + * @description Returns information about a namespace by its name + */ + getByName_1: { + parameters: { + path: { + name: string; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["BatchJobModel"]; + "application/json": components["schemas"]["NamespaceModel"]; }; }; /** @description Bad Request */ @@ -5216,18 +8292,24 @@ export interface operations { }; }; }; - /** Set keys namespace */ - setKeysNamespace_1: { - requestBody: { - content: { - "application/json": components["schemas"]["SetKeysNamespaceRequest"]; + /** Get namespaces */ + getAllNamespaces_3: { + parameters: { + query?: { + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + search?: string; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["BatchJobModel"]; + "application/json": components["schemas"]["PagedModelNamespaceModel"]; }; }; /** @description Bad Request */ @@ -5256,21 +8338,23 @@ export interface operations { }; }; }; - /** - * Pre-translate by TM - * @description Pre-translate provided keys to provided languages by TM. - */ - translate_1: { + /** Update namespace */ + update_4: { + parameters: { + path: { + id: number; + }; + }; requestBody: { content: { - "application/json": components["schemas"]["PreTranslationByTmRequest"]; + "application/json": components["schemas"]["UpdateNamespaceDto"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["BatchJobModel"]; + "application/json": components["schemas"]["NamespaceModel"]; }; }; /** @description Bad Request */ @@ -5300,20 +8384,23 @@ export interface operations { }; }; /** - * Machine Translation - * @description Translate provided keys to provided languages through primary MT provider. + * Single step import + * @description Unlike the /v2/projects/{projectId}/import endpoint, imports the data in single request by provided files and parameters. This is useful for automated importing via API or CLI. */ - machineTranslation_1: { - requestBody: { + singleStepFromFiles_1: { + requestBody?: { content: { - "application/json": components["schemas"]["MachineTranslationRequest"]; + "multipart/form-data": { + files: string[]; + params: components["schemas"]["SingleStepImportRequest"]; + }; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["BatchJobModel"]; + "application/json": components["schemas"]["ImportResult"]; }; }; /** @description Bad Request */ @@ -5342,18 +8429,18 @@ export interface operations { }; }; }; - /** Delete keys */ - deleteKeys_1: { + /** Single step import from body */ + singleStepResolvableImport_1: { requestBody: { content: { - "application/json": components["schemas"]["DeleteKeysRequest"]; + "application/json": components["schemas"]["SingleStepImportResolvableRequest"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["BatchJobModel"]; + "application/json": components["schemas"]["ImportResult"]; }; }; /** @description Bad Request */ @@ -5382,14 +8469,11 @@ export interface operations { }; }; }; - /** - * Copy translation values - * @description Copy translation values from one language to other languages. - */ - copyTranslations_1: { + /** Translates via llm and stores result in AiPlaygroundResult */ + aiPlaygroundTranslate_1: { requestBody: { content: { - "application/json": components["schemas"]["CopyTranslationRequest"]; + "application/json": components["schemas"]["MachineTranslationRequest"]; }; }; responses: { @@ -5425,14 +8509,11 @@ export interface operations { }; }; }; - /** - * Clear translation values - * @description Clear translation values for provided keys in selected languages. - */ - clearTranslations_1: { + /** Assign labels to translations */ + assignTranslationLabel_1: { requestBody: { content: { - "application/json": components["schemas"]["ClearTranslationsRequest"]; + "application/json": components["schemas"]["LabelTranslationsRequest"]; }; }; responses: { @@ -5469,22 +8550,21 @@ export interface operations { }; }; /** - * Single step import - * @description Unlike the /v2/projects/{projectId}/import endpoint, imports the data in single request by provided files and parameters. This is useful for automated importing via API or CLI. + * Clear translation values + * @description Clear translation values for provided keys in selected languages. */ - doImport_1: { - requestBody?: { + clearTranslations_1: { + requestBody: { content: { - "multipart/form-data": { - files: string[]; - params: components["schemas"]["SingleStepImportRequest"]; - }; + "application/json": components["schemas"]["ClearTranslationsRequest"]; }; }; responses: { /** @description OK */ 200: { - content: never; + content: { + "application/json": components["schemas"]["BatchJobModel"]; + }; }; /** @description Bad Request */ 400: { @@ -5513,31 +8593,20 @@ export interface operations { }; }; /** - * Add files - * @description Prepares provided files to import. + * Copy translation values + * @description Copy translation values from one language to other languages. */ - addFiles_1: { - parameters: { - query?: { - /** - * @description When importing files in structured formats (e.g., JSON, YAML), this field defines the delimiter which will be used in names of imported keys. - * @example . - */ - structureDelimiter?: string; - }; - }; - requestBody?: { + copyTranslations_1: { + requestBody: { content: { - "multipart/form-data": { - files: string[]; - }; + "application/json": components["schemas"]["CopyTranslationRequest"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["ImportAddFilesResultModel"]; + "application/json": components["schemas"]["BatchJobModel"]; }; }; /** @description Bad Request */ @@ -5566,15 +8635,19 @@ export interface operations { }; }; }; - /** - * Delete - * @description Deletes prepared import data. - */ - cancelImport_1: { + /** Delete keys */ + deleteKeys_1: { + requestBody: { + content: { + "application/json": components["schemas"]["DeleteKeysRequest"]; + }; + }; responses: { /** @description OK */ 200: { - content: never; + content: { + "application/json": components["schemas"]["BatchJobModel"]; + }; }; /** @description Bad Request */ 400: { @@ -5588,105 +8661,35 @@ export interface operations { "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; }; }; - /** @description Forbidden */ - 403: { - content: { - "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; - }; - }; - /** @description Not Found */ - 404: { - content: { - "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; - }; - }; - }; - }; - /** Export data */ - export_1: { - parameters: { - query?: { - /** - * @description Languages to be contained in export. - * - * If null, all languages are exported - * @example en - */ - languages?: string[]; - /** @description Format to export to */ - format?: "JSON" | "JSON_TOLGEE" | "JSON_I18NEXT" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "ANDROID_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML"; - /** - * @description Delimiter to structure file content. - * - * e.g. For key "home.header.title" would result in {"home": {"header": "title": {"Hello"}}} structure. - * - * When null, resulting file won't be structured. Works only for generic structured formats (e.g. JSON, YAML), - * specific formats like `YAML_RUBY` don't honor this parameter. - */ - structureDelimiter?: string; - /** @description Filter key IDs to be contained in export */ - filterKeyId?: number[]; - /** @description Filter key IDs not to be contained in export */ - filterKeyIdNot?: number[]; - /** - * @description Filter keys tagged by. - * - * This filter works the same as `filterTagIn` but in this cases it accepts single tag only. - */ - filterTag?: string; - /** @description Filter keys tagged by one of provided tags */ - filterTagIn?: string[]; - /** @description Filter keys not tagged by one of provided tags */ - filterTagNotIn?: string[]; - /** @description Filter keys with prefix */ - filterKeyPrefix?: string; - /** @description Filter translations with state. By default, all states except untranslated is exported. */ - filterState?: ("UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED")[]; - /** @description Filter translations with namespace. By default, all namespaces everything are exported. To export default namespace, use empty string. */ - filterNamespace?: string[]; - /** - * @description If false, it doesn't return zip of files, but it returns single file. - * - * This is possible only when single language is exported. Otherwise it returns "400 - Bad Request" response. - */ - zip?: boolean; - /** - * @description Message format to be used for export. - * - * e.g. PHP_PO: Hello %s, ICU: Hello {name}. - * - * This property is honored only for generic formats like JSON or YAML. - * For specific formats like `YAML_RUBY` it's ignored. - */ - messageFormat?: "C_SPRINTF" | "PHP_SPRINTF" | "JAVA_STRING_FORMAT" | "APPLE_SPRINTF" | "RUBY_SPRINTF" | "I18NEXT" | "ICU"; - /** - * @description This is a template that defines the structure of the resulting .zip file content. - * - * The template is a string that can contain the following placeholders: {namespace}, {languageTag}, - * {androidLanguageTag}, {snakeLanguageTag}, {extension}. - * - * For example, when exporting to JSON with the template `{namespace}/{languageTag}.{extension}`, - * the English translations of the `home` namespace will be stored in `home/en.json`. - * - * The `{snakeLanguageTag}` placeholder is the same as `{languageTag}` but in snake case. (e.g., en_US). - * - * The Android specific `{androidLanguageTag}` placeholder is the same as `{languageTag}` - * but in Android format. (e.g., en-rUS) - */ - fileStructureTemplate?: string; - /** - * @description If true, for structured formats (like JSON) arrays are supported. - * - * e.g. Key hello[0] will be exported as {"hello": ["..."]} - */ - supportArrays?: boolean; - }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + /** + * Machine Translation + * @description Translate provided keys to provided languages through primary MT provider. + */ + machineTranslation_1: { + requestBody: { + content: { + "application/json": components["schemas"]["MachineTranslationRequest"]; + }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["StreamingResponseBody"]; + "application/json": components["schemas"]["BatchJobModel"]; }; }; /** @description Bad Request */ @@ -5716,20 +8719,20 @@ export interface operations { }; }; /** - * Export data (post) - * @description Exports data (post). Useful when exceeding allowed URL size. + * Pre-translate by TM + * @description Pre-translate provided keys to provided languages by TM. */ - exportPost_1: { + translate_1: { requestBody: { content: { - "application/json": components["schemas"]["ExportParams"]; + "application/json": components["schemas"]["PreTranslationByTmRequest"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["StreamingResponseBody"]; + "application/json": components["schemas"]["BatchJobModel"]; }; }; /** @description Bad Request */ @@ -5758,20 +8761,19 @@ export interface operations { }; }; }; - /** - * Store Big Meta - * @description Stores a bigMeta for a project - */ - store_3: { + /** Set keys namespace */ + setKeysNamespace_1: { requestBody: { content: { - "application/json": components["schemas"]["BigMetaDto"]; + "application/json": components["schemas"]["SetKeysNamespaceRequest"]; }; }; responses: { /** @description OK */ 200: { - content: never; + content: { + "application/json": components["schemas"]["BatchJobModel"]; + }; }; /** @description Bad Request */ 400: { @@ -5799,29 +8801,18 @@ export interface operations { }; }; }; - /** - * Get translation comments - * @description Returns translation comments of translation - */ - getAll_6: { - parameters: { - query?: { - /** @description Zero-based page index (0..N) */ - page?: number; - /** @description The size of the page to be returned */ - size?: number; - /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; - }; - path: { - translationId: number; + /** Set translation state */ + setTranslationState_3: { + requestBody: { + content: { + "application/json": components["schemas"]["SetTranslationsStateStateRequest"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelTranslationCommentModel"]; + "application/json": components["schemas"]["BatchJobModel"]; }; }; /** @description Bad Request */ @@ -5850,23 +8841,18 @@ export interface operations { }; }; }; - /** Create translation comment */ - create_8: { - parameters: { - path: { - translationId: number; - }; - }; + /** Add tags */ + tagKeys_1: { requestBody: { content: { - "application/json": components["schemas"]["TranslationCommentDto"]; + "application/json": components["schemas"]["TagKeysRequest"]; }; }; responses: { - /** @description Created */ - 201: { + /** @description OK */ + 200: { content: { - "*/*": components["schemas"]["TranslationCommentModel"]; + "application/json": components["schemas"]["BatchJobModel"]; }; }; /** @description Bad Request */ @@ -5895,21 +8881,18 @@ export interface operations { }; }; }; - /** - * Create translation comment - * @description Creates a translation comment. Empty translation is stored, when not exists. - */ - create_10: { + /** Unassign labels from translations */ + unassignTranslationLabel_1: { requestBody: { content: { - "application/json": components["schemas"]["TranslationCommentWithLangKeyDto"]; + "application/json": components["schemas"]["LabelTranslationsRequest"]; }; }; responses: { - /** @description Created */ - 201: { + /** @description OK */ + 200: { content: { - "*/*": components["schemas"]["TranslationWithCommentModel"]; + "application/json": components["schemas"]["BatchJobModel"]; }; }; /** @description Bad Request */ @@ -5938,31 +8921,18 @@ export interface operations { }; }; }; - /** - * Get suggestions from translation memory - * @description Suggests machine translations from translation memory. The result is always sorted by similarity, so sorting is not supported. - */ - suggestTranslationMemory_1: { - parameters: { - query?: { - /** @description Zero-based page index (0..N) */ - page?: number; - /** @description The size of the page to be returned */ - size?: number; - /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; - }; - }; + /** Remove tags */ + untagKeys_1: { requestBody: { content: { - "application/json": components["schemas"]["SuggestRequestDto"]; + "application/json": components["schemas"]["UntagKeysRequest"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelTranslationMemoryItemModel"]; + "application/json": components["schemas"]["BatchJobModel"]; }; }; /** @description Bad Request */ @@ -5991,21 +8961,50 @@ export interface operations { }; }; }; - /** - * Get machine translation suggestions (streaming) - * @description Suggests machine translations from enabled services. The results are streamed to the output in ndjson format. If an error occurs when for any service provider used, the error information is returned as a part of the result item, while the response has 200 status code. - */ - suggestMachineTranslationsStreaming_1: { - requestBody: { - content: { - "application/json": components["schemas"]["SuggestRequestDto"]; + /** Get project stats */ + getProjectStats_1: { + responses: { + /** @description OK */ + 200: { + content: { + "application/json": components["schemas"]["ProjectStatsModel"]; + }; + }; + /** @description Bad Request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; }; }; + }; + /** Get project daily amount of events */ + getProjectDailyActivity_1: { responses: { /** @description OK */ 200: { content: { - "application/x-ndjson": components["schemas"]["StreamingResponseBody"]; + "application/json": { + [key: string]: number; + }; }; }; /** @description Bad Request */ @@ -6077,27 +9076,21 @@ export interface operations { }; }; }; - /** Get all languages */ - getAll_8: { - parameters: { - query?: { - /** @description Zero-based page index (0..N) */ - page?: number; - /** @description The size of the page to be returned */ - size?: number; - /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; - /** @description Filter languages by id */ - filterId?: number[]; - /** @description Filter languages without id */ - filterNotId?: number[]; + /** + * Get machine translation suggestions (streaming) + * @description Suggests machine translations from enabled services. The results are streamed to the output in ndjson format. If an error occurs when for any service provider used, the error information is returned as a part of the result item, while the response has 200 status code. + */ + suggestMachineTranslationsStreaming_1: { + requestBody: { + content: { + "application/json": components["schemas"]["SuggestRequestDto"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelLanguageModel"]; + "application/x-ndjson": components["schemas"]["StreamingResponseBody"]; }; }; /** @description Bad Request */ @@ -6126,18 +9119,31 @@ export interface operations { }; }; }; - /** Create language */ - createLanguage_1: { + /** + * Get suggestions from translation memory + * @description Suggests machine translations from translation memory. The result is always sorted by similarity, so sorting is not supported. + */ + suggestTranslationMemory_1: { + parameters: { + query?: { + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + }; + }; requestBody: { content: { - "application/json": components["schemas"]["LanguageRequest"]; + "application/json": components["schemas"]["SuggestRequestDto"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["LanguageModel"]; + "application/json": components["schemas"]["PagedModelTranslationMemoryItemModel"]; }; }; /** @description Bad Request */ @@ -6166,19 +9172,17 @@ export interface operations { }; }; }; - /** Get screenshots */ - getKeyScreenshots: { - parameters: { - path: { - keyId: number; + /** Execute complex tag operation */ + executeComplexTagOperation_1: { + requestBody: { + content: { + "application/json": components["schemas"]["ComplexTagKeysRequest"]; }; }; responses: { /** @description OK */ 200: { - content: { - "application/json": components["schemas"]["CollectionModelScreenshotModel"]; - }; + content: never; }; /** @description Bad Request */ 400: { @@ -6206,27 +9210,24 @@ export interface operations { }; }; }; - /** Upload screenshot */ - uploadScreenshot: { + /** Get tags */ + getAll_15: { parameters: { - path: { - keyId: number; - }; - }; - requestBody?: { - content: { - "multipart/form-data": { - /** Format: binary */ - screenshot: string; - info?: components["schemas"]["ScreenshotInfoDto"]; - }; + query?: { + search?: string; + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; }; }; responses: { - /** @description Created */ - 201: { + /** @description OK */ + 200: { content: { - "*/*": components["schemas"]["ScreenshotModel"]; + "application/json": components["schemas"]["PagedModelTagModel"]; }; }; /** @description Bad Request */ @@ -6255,20 +9256,40 @@ export interface operations { }; }; }; - /** - * Get all permitted organizations - * @description Returns all organizations, which is current user allowed to view - */ - getAll_10: { + /** Get tasks */ + getTasks_1: { parameters: { query?: { + /** @description Filter tasks by state */ + filterState?: ("NEW" | "IN_PROGRESS" | "FINISHED" | "CANCELED")[]; + /** @description Filter tasks without state */ + filterNotState?: ("NEW" | "IN_PROGRESS" | "FINISHED" | "CANCELED")[]; + /** @description Filter tasks by assignee */ + filterAssignee?: number[]; + /** @description Filter tasks by type */ + filterType?: ("TRANSLATE" | "REVIEW")[]; + /** @description Filter tasks by id */ + filterId?: number[]; + /** @description Filter tasks without id */ + filterNotId?: number[]; + /** @description Filter tasks by project */ + filterProject?: number[]; + /** @description Filter tasks without project */ + filterNotProject?: number[]; + /** @description Filter tasks by language */ + filterLanguage?: number[]; + /** @description Filter tasks by key */ + filterKey?: number[]; + /** @description Filter tasks by agency */ + filterAgency?: number[]; + /** @description Exclude tasks which were closed before specified timestamp */ + filterNotClosedBefore?: number; /** @description Zero-based page index (0..N) */ page?: number; /** @description The size of the page to be returned */ size?: number; /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ sort?: string[]; - filterCurrentUserOwner?: boolean; search?: string; }; }; @@ -6276,7 +9297,7 @@ export interface operations { /** @description OK */ 200: { content: { - "application/hal+json": components["schemas"]["PagedModelOrganizationModel"]; + "application/json": components["schemas"]["PagedModelTaskModel"]; }; }; /** @description Bad Request */ @@ -6305,18 +9326,24 @@ export interface operations { }; }; }; - /** Create organization */ - create_12: { + /** Create task */ + createTask_1: { + parameters: { + query?: { + filterState?: ("UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED")[]; + filterOutdated?: boolean; + }; + }; requestBody: { content: { - "application/json": components["schemas"]["OrganizationDto"]; + "application/json": components["schemas"]["CreateTaskRequest"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["OrganizationModel"]; + "application/json": components["schemas"]["TaskModel"]; }; }; /** @description Bad Request */ @@ -6345,22 +9372,24 @@ export interface operations { }; }; }; - /** Upload an image for later use */ - upload: { - requestBody?: { + /** Calculate scope */ + calculateScope_1: { + parameters: { + query?: { + filterState?: ("UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED")[]; + filterOutdated?: boolean; + }; + }; + requestBody: { content: { - "multipart/form-data": { - /** Format: binary */ - image: string; - info?: components["schemas"]["ImageUploadInfoDto"]; - }; + "application/json": components["schemas"]["CalculateScopeRequest"]; }; }; responses: { - /** @description Created */ - 201: { + /** @description OK */ + 200: { content: { - "*/*": components["schemas"]["UploadedImageModel"]; + "application/json": components["schemas"]["KeysScopeView"]; }; }; /** @description Bad Request */ @@ -6389,47 +9418,23 @@ export interface operations { }; }; }; - /** Get user tasks */ - getTasks: { + /** Create multiple tasks */ + createTasks_1: { parameters: { query?: { - /** @description Filter tasks by state */ - filterState?: ("NEW" | "IN_PROGRESS" | "DONE" | "CLOSED")[]; - /** @description Filter tasks without state */ - filterNotState?: ("NEW" | "IN_PROGRESS" | "DONE" | "CLOSED")[]; - /** @description Filter tasks by assignee */ - filterAssignee?: number[]; - /** @description Filter tasks by type */ - filterType?: ("TRANSLATE" | "REVIEW")[]; - /** @description Filter tasks by id */ - filterId?: number[]; - /** @description Filter tasks without id */ - filterNotId?: number[]; - /** @description Filter tasks by project */ - filterProject?: number[]; - /** @description Filter tasks without project */ - filterNotProject?: number[]; - /** @description Filter tasks by language */ - filterLanguage?: number[]; - /** @description Filter tasks by key */ - filterKey?: number[]; - /** @description Exclude "done" tasks which are older than specified timestamp */ - filterDoneMinClosedAt?: number; - /** @description Zero-based page index (0..N) */ - page?: number; - /** @description The size of the page to be returned */ - size?: number; - /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; - search?: string; + filterState?: ("UNTRANSLATED" | "TRANSLATED" | "REVIEWED" | "DISABLED")[]; + filterOutdated?: boolean; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateMultipleTasksRequest"]; }; }; responses: { /** @description OK */ 200: { - content: { - "application/json": components["schemas"]["PagedModelTaskWithProjectModel"]; - }; + content: never; }; /** @description Bad Request */ 400: { @@ -6457,16 +9462,34 @@ export interface operations { }; }; }; - /** - * Get used namespaces - * @description Returns all used project namespaces. Response contains default (null) namespace if used. - */ - getUsedNamespaces_1: { + /** Get possible assignees */ + getPossibleAssignees_1: { + parameters: { + query?: { + /** @description Filter users by id */ + filterId?: number[]; + /** @description Filter only users that have at least following scopes */ + filterMinimalScope?: string; + /** @description Filter only users that can view language */ + filterViewLanguageId?: number; + /** @description Filter only users that can edit language */ + filterEditLanguageId?: number; + /** @description Filter only users that can edit state of language */ + filterStateLanguageId?: number; + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + search?: string; + }; + }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["CollectionModelUsedNamespaceModel"]; + "application/json": components["schemas"]["PagedModelSimpleUserAccountModel"]; }; }; /** @description Bad Request */ @@ -6495,11 +9518,8 @@ export interface operations { }; }; }; - /** - * Get report in XLSX - * @description Detailed statistics about the task results - */ - getXlsxReport_1: { + /** Get task */ + getTask_1: { parameters: { path: { taskNumber: number; @@ -6509,7 +9529,7 @@ export interface operations { /** @description OK */ 200: { content: { - "application/json": string; + "application/json": components["schemas"]["TaskModel"]; }; }; /** @description Bad Request */ @@ -6538,21 +9558,23 @@ export interface operations { }; }; }; - /** - * Get report - * @description Detailed statistics for every assignee - */ - getPerUserReport_1: { + /** Update task */ + updateTask_1: { parameters: { path: { taskNumber: number; }; }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateTaskRequest"]; + }; + }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["TaskPerUserReportModel"][]; + "application/json": components["schemas"]["TaskModel"]; }; }; /** @description Bad Request */ @@ -6624,33 +9646,18 @@ export interface operations { }; }; }; - getPossibleAssignees_1: { + /** Close task */ + cancelTask_1: { parameters: { - query?: { - /** @description Filter users by id */ - filterId?: number[]; - /** @description Filter only users that have at least following scopes */ - filterMinimalScope?: string; - /** @description Filter only users that can view language */ - filterViewLanguageId?: number; - /** @description Filter only users that can edit language */ - filterEditLanguageId?: number; - /** @description Filter only users that can edit state of language */ - filterStateLanguageId?: number; - /** @description Zero-based page index (0..N) */ - page?: number; - /** @description The size of the page to be returned */ - size?: number; - /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; - search?: string; + path: { + taskNumber: number; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelSimpleUserAccountModel"]; + "application/json": components["schemas"]["TaskModel"]; }; }; /** @description Bad Request */ @@ -6679,23 +9686,21 @@ export interface operations { }; }; }; - /** Get namespaces */ - getAllNamespaces_1: { + /** + * Close task + * @deprecated + */ + closeTask_1: { parameters: { - query?: { - /** @description Zero-based page index (0..N) */ - page?: number; - /** @description The size of the page to be returned */ - size?: number; - /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; + path: { + taskNumber: number; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelNamespaceModel"]; + "application/json": components["schemas"]["TaskModel"]; }; }; /** @description Bad Request */ @@ -6724,21 +9729,18 @@ export interface operations { }; }; }; - /** - * Get namespace by name - * @description Returns information about a namespace by its name - */ - getByName_1: { + /** Finish task */ + finishTask_1: { parameters: { path: { - name: string; + taskNumber: number; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["NamespaceModel"]; + "application/json": components["schemas"]["TaskModel"]; }; }; /** @description Bad Request */ @@ -6767,30 +9769,18 @@ export interface operations { }; }; }; - /** - * Search for keys - * @description This endpoint helps you to find desired key by keyName, base translation or translation in specified language. - */ - searchForKey_1: { + /** Get task keys */ + getTaskKeys_1: { parameters: { - query: { - /** @description Search query */ - search: string; - /** @description Language to search in */ - languageTag?: string; - /** @description Zero-based page index (0..N) */ - page?: number; - /** @description The size of the page to be returned */ - size?: number; - /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; + path: { + taskNumber: number; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelKeySearchSearchResultModel"]; + "application/json": components["schemas"]["TaskKeysResponse"]; }; }; /** @description Bad Request */ @@ -6819,19 +9809,22 @@ export interface operations { }; }; }; - /** Get one revision data */ - getSingleRevision_1: { + /** Add or remove task keys */ + updateTaskKeys_1: { parameters: { path: { - revisionId: number; + taskNumber: number; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateTaskKeysRequest"]; }; }; responses: { /** @description OK */ 200: { - content: { - "application/hal+json": components["schemas"]["ProjectActivityModel"]; - }; + content: never; }; /** @description Bad Request */ 400: { @@ -6859,23 +9852,27 @@ export interface operations { }; }; }; - /** Get project activity */ - getActivity_1: { + /** + * Update task key + * @description Mark key as done, which updates task progress. + */ + updateTaskKey_1: { parameters: { - query?: { - /** @description Zero-based page index (0..N) */ - page?: number; - /** @description The size of the page to be returned */ - size?: number; - /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; + path: { + taskNumber: number; + keyId: number; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateTaskKeyRequest"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/hal+json": components["schemas"]["PagedModelProjectActivityModel"]; + "application/json": components["schemas"]["UpdateTaskKeyResponse"]; }; }; /** @description Bad Request */ @@ -6904,24 +9901,21 @@ export interface operations { }; }; }; - /** Get tags */ - getAll_4: { + /** + * Get report + * @description Detailed statistics for every assignee + */ + getPerUserReport_1: { parameters: { - query?: { - search?: string; - /** @description Zero-based page index (0..N) */ - page?: number; - /** @description The size of the page to be returned */ - size?: number; - /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; + path: { + taskNumber: number; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelTagModel"]; + "application/json": components["schemas"]["TaskPerUserReportModel"][]; }; }; /** @description Bad Request */ @@ -6950,26 +9944,18 @@ export interface operations { }; }; }; - /** - * List user batch operations - * @description List all batch operations started by current user - */ - myList_1: { + /** Reopen task */ + reopenTask_1: { parameters: { - query?: { - /** @description Zero-based page index (0..N) */ - page?: number; - /** @description The size of the page to be returned */ - size?: number; - /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; + path: { + taskNumber: number; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelBatchJobModel"]; + "application/json": components["schemas"]["TaskModel"]; }; }; /** @description Bad Request */ @@ -6998,18 +9984,21 @@ export interface operations { }; }; }; - /** Get Big Meta for key */ - getBigMeta_1: { + /** + * Get report in XLSX + * @description Detailed statistics about the task results + */ + getXlsxReport_1: { parameters: { path: { - id: number; + taskNumber: number; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["CollectionModelKeyWithBaseTranslationModel"]; + "application/json": string; }; }; /** @description Bad Request */ @@ -7038,19 +10027,108 @@ export interface operations { }; }; }; - /** - * Get translations - * @description Returns translations prepared to import. - */ - getImportTranslations_1: { + /** Get translations in project */ + getTranslations_1: { parameters: { query?: { - /** @description Whether only translations, which are in conflict with existing translations should be returned */ - onlyConflicts?: boolean; - /** @description Whether only translations with unresolved conflictswith existing translations should be returned */ - onlyUnresolved?: boolean; - /** @description String to search in translation text or key */ + /** @description Cursor to get next data */ + cursor?: string; + /** + * @description Translation state in the format: languageTag,state. You can use this parameter multiple times. + * + * When used with multiple states for same language it is applied with logical OR. + * + * When used with multiple languages, it is applied with logical AND. + */ + filterState?: string[]; + /** + * @description Languages to be contained in response. + * + * To add multiple languages, repeat this param (eg. ?languages=en&languages=de) + * @example en + */ + languages?: string[]; + /** @description String to search in key name or translation text */ search?: string; + /** @description Selects key with provided names. Use this param multiple times to fetch more keys. */ + filterKeyName?: string[]; + /** @description Selects key with provided ID. Use this param multiple times to fetch more keys. */ + filterKeyId?: number[]; + /** @description Selects only keys for which the translation is missing in any returned language. It only filters for translations included in returned languages. */ + filterUntranslatedAny?: boolean; + /** @description Selects only keys, where translation is provided in any language */ + filterTranslatedAny?: boolean; + /** + * @description Selects only keys where the translation is missing for the specified language. The specified language must be included in the returned languages. Otherwise, this filter doesn't apply. + * @example en-US + */ + filterUntranslatedInLang?: string; + /** + * @description Selects only keys, where translation is provided in specified language + * @example en-US + */ + filterTranslatedInLang?: string; + /** + * @description Selects only keys, where translation was auto translated for specified languages. + * @example en-US + */ + filterAutoTranslatedInLang?: string[]; + /** @description Selects only keys with screenshots */ + filterHasScreenshot?: boolean; + /** @description Selects only keys without screenshots */ + filterHasNoScreenshot?: boolean; + /** + * @description Selects only keys with provided namespaces. + * + * To filter default namespace, set to empty string. + */ + filterNamespace?: string[]; + /** + * @description Selects only keys without provided namespaces. + * + * To filter default namespace, set to empty string. + */ + filterNoNamespace?: string[]; + /** @description Selects only keys with provided tag */ + filterTag?: string[]; + /** @description Selects only keys without provided tag */ + filterNoTag?: string[]; + /** + * @description Selects only keys, where translation in provided langs is in outdated state + * @example en-US + */ + filterOutdatedLanguage?: string[]; + /** + * @description Selects only keys, where translation in provided langs is not in outdated state + * @example en-US + */ + filterNotOutdatedLanguage?: string[]; + /** + * @description Selects only key affected by activity with specidfied revision ID + * @example 1234567 + */ + filterRevisionId?: number[]; + /** @description Select only keys which were not successfully translated by batch job with provided id */ + filterFailedKeysOfJob?: number; + /** @description Select only keys which are in specified task */ + filterTaskNumber?: number[]; + /** @description Filter task keys which are `not done` */ + filterTaskKeysNotDone?: boolean; + /** @description Filter task keys which are `done` */ + filterTaskKeysDone?: boolean; + /** @description Filter keys with unresolved comments in lang */ + filterHasUnresolvedCommentsInLang?: string[]; + /** @description Filter keys with any comments in lang */ + filterHasCommentsInLang?: string[]; + /** + * @description Filter key translations with labels + * @example labelId1,labelId2 + */ + filterLabel?: string[]; + /** @description Filter keys with any suggestions in lang */ + filterHasSuggestionsInLang?: string[]; + /** @description Filter keys with no suggestions in lang */ + filterHasNoSuggestionsInLang?: string[]; /** @description Zero-based page index (0..N) */ page?: number; /** @description The size of the page to be returned */ @@ -7058,15 +10136,12 @@ export interface operations { /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ sort?: string[]; }; - path: { - languageId: number; - }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelImportTranslationModel"]; + "application/json": components["schemas"]["KeysWithTranslationsPageModel"]; }; }; /** @description Bad Request */ @@ -7096,20 +10171,20 @@ export interface operations { }; }; /** - * Get import language - * @description Returns language prepared to import. + * Update translations for existing key + * @description Sets translations for existing key */ - getImportLanguage_1: { - parameters: { - path: { - languageId: number; + setTranslations_1: { + requestBody: { + content: { + "application/json": components["schemas"]["SetTranslationsWithKeyDto"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["ImportLanguageModel"]; + "application/json": components["schemas"]["SetTranslationsResponseModel"]; }; }; /** @description Bad Request */ @@ -7139,19 +10214,21 @@ export interface operations { }; }; /** - * Delete language - * @description Deletes language prepared to import. + * Create key or update translations + * @description Sets translations for existing key or creates new key and sets the translations to it. */ - deleteLanguage_1: { - parameters: { - path: { - languageId: number; + createOrUpdateTranslations_1: { + requestBody: { + content: { + "application/json": components["schemas"]["SetTranslationsWithKeyDto"]; }; }; responses: { /** @description OK */ 200: { - content: never; + content: { + "application/json": components["schemas"]["SetTranslationsResponseModel"]; + }; }; /** @description Bad Request */ 400: { @@ -7180,28 +10257,20 @@ export interface operations { }; }; /** - * Get file issues - * @description Returns issues for uploaded file. + * Create translation comment + * @description Creates a translation comment. Empty translation is stored, when not exists. */ - getImportFileIssues_1: { - parameters: { - query?: { - /** @description Zero-based page index (0..N) */ - page?: number; - /** @description The size of the page to be returned */ - size?: number; - /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; - }; - path: { - importFileId: number; + create_4: { + requestBody: { + content: { + "application/json": components["schemas"]["TranslationCommentWithLangKeyDto"]; }; }; responses: { - /** @description OK */ - 200: { + /** @description Created */ + 201: { content: { - "application/json": components["schemas"]["PagedModelImportFileIssueModel"]; + "*/*": components["schemas"]["TranslationWithCommentModel"]; }; }; /** @description Bad Request */ @@ -7230,26 +10299,18 @@ export interface operations { }; }; }; - /** - * Get result - * @description Returns the result of preparation. - */ - getImportResult_1: { - parameters: { - query?: { - /** @description Zero-based page index (0..N) */ - page?: number; - /** @description The size of the page to be returned */ - size?: number; - /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; + /** Add label to translation by key and language id */ + assignLabel_3: { + requestBody: { + content: { + "application/json": components["schemas"]["TranslationLabelRequest"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelImportLanguageModel"]; + "application/json": components["schemas"]["LabelModel"]; }; }; /** @description Bad Request */ @@ -7277,17 +10338,117 @@ export interface operations { }; }; }; - }; - /** - * Get namespaces - * @description Returns all existing and imported namespaces - */ - getAllNamespaces_3: { + }; + /** + * Select keys + * @description Returns all key IDs for specified filter values. This way, you can apply the same filter as in the translation view and get the resulting key IDs for future use. + */ + selectKeys_1: { + parameters: { + query?: { + /** + * @description Translation state in the format: languageTag,state. You can use this parameter multiple times. + * + * When used with multiple states for same language it is applied with logical OR. + * + * When used with multiple languages, it is applied with logical AND. + */ + filterState?: string[]; + /** + * @description Languages to be contained in response. + * + * To add multiple languages, repeat this param (eg. ?languages=en&languages=de) + * @example en + */ + languages?: string[]; + /** @description String to search in key name or translation text */ + search?: string; + /** @description Selects key with provided names. Use this param multiple times to fetch more keys. */ + filterKeyName?: string[]; + /** @description Selects key with provided ID. Use this param multiple times to fetch more keys. */ + filterKeyId?: number[]; + /** @description Selects only keys for which the translation is missing in any returned language. It only filters for translations included in returned languages. */ + filterUntranslatedAny?: boolean; + /** @description Selects only keys, where translation is provided in any language */ + filterTranslatedAny?: boolean; + /** + * @description Selects only keys where the translation is missing for the specified language. The specified language must be included in the returned languages. Otherwise, this filter doesn't apply. + * @example en-US + */ + filterUntranslatedInLang?: string; + /** + * @description Selects only keys, where translation is provided in specified language + * @example en-US + */ + filterTranslatedInLang?: string; + /** + * @description Selects only keys, where translation was auto translated for specified languages. + * @example en-US + */ + filterAutoTranslatedInLang?: string[]; + /** @description Selects only keys with screenshots */ + filterHasScreenshot?: boolean; + /** @description Selects only keys without screenshots */ + filterHasNoScreenshot?: boolean; + /** + * @description Selects only keys with provided namespaces. + * + * To filter default namespace, set to empty string. + */ + filterNamespace?: string[]; + /** + * @description Selects only keys without provided namespaces. + * + * To filter default namespace, set to empty string. + */ + filterNoNamespace?: string[]; + /** @description Selects only keys with provided tag */ + filterTag?: string[]; + /** @description Selects only keys without provided tag */ + filterNoTag?: string[]; + /** + * @description Selects only keys, where translation in provided langs is in outdated state + * @example en-US + */ + filterOutdatedLanguage?: string[]; + /** + * @description Selects only keys, where translation in provided langs is not in outdated state + * @example en-US + */ + filterNotOutdatedLanguage?: string[]; + /** + * @description Selects only key affected by activity with specidfied revision ID + * @example 1234567 + */ + filterRevisionId?: number[]; + /** @description Select only keys which were not successfully translated by batch job with provided id */ + filterFailedKeysOfJob?: number; + /** @description Select only keys which are in specified task */ + filterTaskNumber?: number[]; + /** @description Filter task keys which are `not done` */ + filterTaskKeysNotDone?: boolean; + /** @description Filter task keys which are `done` */ + filterTaskKeysDone?: boolean; + /** @description Filter keys with unresolved comments in lang */ + filterHasUnresolvedCommentsInLang?: string[]; + /** @description Filter keys with any comments in lang */ + filterHasCommentsInLang?: string[]; + /** + * @description Filter key translations with labels + * @example labelId1,labelId2 + */ + filterLabel?: string[]; + /** @description Filter keys with any suggestions in lang */ + filterHasSuggestionsInLang?: string[]; + /** @description Filter keys with no suggestions in lang */ + filterHasNoSuggestionsInLang?: string[]; + }; + }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["CollectionModelImportNamespaceModel"]; + "application/json": components["schemas"]["SelectAllResponse"]; }; }; /** @description Bad Request */ @@ -7317,55 +10478,50 @@ export interface operations { }; }; /** - * Get all running and pending batch operations - * @description Returns all running and pending batch operations. Completed batch operations are returned only if they are not older than 1 hour. If user doesn't have permission to view all batch operations, only their operations are returned. + * Get all translations + * @description Returns all translations for specified languages */ - currentJobs_1: { - responses: { - /** @description OK */ - 200: { - content: { - "application/json": components["schemas"]["CollectionModelBatchJobModel"]; - }; - }; - /** @description Bad Request */ - 400: { - content: { - "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; - }; - }; - /** @description Unauthorized */ - 401: { - content: { - "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; - }; - }; - /** @description Forbidden */ - 403: { - content: { - "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; - }; - }; - /** @description Not Found */ - 404: { - content: { - "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; - }; - }; - }; - }; - /** Get batch operation */ - get_13: { + getAllTranslations_1: { parameters: { + query?: { + /** @description Namespace to return */ + ns?: string; + /** + * @description Delimiter to structure response content. + * + * e.g. For key "home.header.title" would result in {"home": {"header": {"title": "Hello"}}} structure. + * + * When null, resulting file will be a flat key-value object. + */ + structureDelimiter?: string; + /** + * @description Enables filtering of returned keys by their tags. + * Only keys with at least one provided tag will be returned. + * Optional, filtering is not applied if not specified. + * @example [ + * "productionReady", + * "nextRelease" + * ] + */ + filterTag?: string[]; + }; path: { - id: number; + /** + * @description Comma-separated language tags to return translations in. Languages you are not permitted to see will be silently dropped and not returned. + * @example [ + * "en", + * "de", + * "fr" + * ] + */ + languages: string[]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["BatchJobModel"]; + "application/json": string; }; }; /** @description Bad Request */ @@ -7394,8 +10550,11 @@ export interface operations { }; }; }; - /** List batch operations */ - list_4: { + /** + * Get translation comments + * @description Returns translation comments of translation + */ + getAll_4: { parameters: { query?: { /** @description Zero-based page index (0..N) */ @@ -7405,12 +10564,15 @@ export interface operations { /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ sort?: string[]; }; + path: { + translationId: number; + }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["PagedModelBatchJobModel"]; + "application/json": components["schemas"]["PagedModelTranslationCommentModel"]; }; }; /** @description Bad Request */ @@ -7439,29 +10601,23 @@ export interface operations { }; }; }; - /** - * Get translation history - * @description Sorting is not supported for supported. It is automatically sorted from newest to oldest. - */ - getTranslationHistory_1: { + /** Create translation comment */ + create_2: { parameters: { - query?: { - /** @description Zero-based page index (0..N) */ - page?: number; - /** @description The size of the page to be returned */ - size?: number; - /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ - sort?: string[]; - }; path: { translationId: number; }; }; + requestBody: { + content: { + "application/json": components["schemas"]["TranslationCommentDto"]; + }; + }; responses: { - /** @description OK */ - 200: { + /** @description Created */ + 201: { content: { - "application/json": components["schemas"]["PagedModelTranslationHistoryModel"]; + "*/*": components["schemas"]["TranslationCommentModel"]; }; }; /** @description Bad Request */ @@ -7490,37 +10646,19 @@ export interface operations { }; }; }; - /** - * Get all translations - * @description Returns all translations for specified languages - */ - getAllTranslations_1: { + /** Get one translation comment */ + get_5: { parameters: { - query?: { - /** @description Namespace to return */ - ns?: string; - /** - * @description Delimiter to structure response content. - * - * e.g. For key "home.header.title" would result in {"home": {"header": {"title": "Hello"}}} structure. - * - * When null, resulting file will be a flat key-value object. - */ - structureDelimiter?: string; - }; path: { - /** - * @description Comma-separated language tags to return translations in. Languages you are not permitted to see will be silently dropped and not returned. - * @example en,de,fr - */ - languages: string[]; + translationId: number; + commentId: number; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": string; + "application/json": components["schemas"]["TranslationCommentModel"]; }; }; /** @description Bad Request */ @@ -7549,86 +10687,24 @@ export interface operations { }; }; }; - /** - * Select keys - * @description Returns all key IDs for specified filter values. This way, you can apply the same filter as in the translation view and get the resulting key IDs for future use. - */ - selectKeys_1: { + /** Update translation comment */ + update_2: { parameters: { - query?: { - /** - * @description Translation state in the format: languageTag,state. You can use this parameter multiple times. - * - * When used with multiple states for same language it is applied with logical OR. - * - * When used with multiple languages, it is applied with logical AND. - */ - filterState?: string[]; - /** - * @description Languages to be contained in response. - * - * To add multiple languages, repeat this param (eg. ?languages=en&languages=de) - * @example en - */ - languages?: string[]; - /** @description String to search in key name or translation text */ - search?: string; - /** @description Selects key with provided names. Use this param multiple times to fetch more keys. */ - filterKeyName?: string[]; - /** @description Selects key with provided ID. Use this param multiple times to fetch more keys. */ - filterKeyId?: number[]; - /** @description Selects only keys for which the translation is missing in any returned language. It only filters for translations included in returned languages. */ - filterUntranslatedAny?: boolean; - /** @description Selects only keys, where translation is provided in any language */ - filterTranslatedAny?: boolean; - /** - * @description Selects only keys where the translation is missing for the specified language. The specified language must be included in the returned languages. Otherwise, this filter doesn't apply. - * @example en-US - */ - filterUntranslatedInLang?: string; - /** - * @description Selects only keys, where translation is provided in specified language - * @example en-US - */ - filterTranslatedInLang?: string; - /** @description Selects only keys with screenshots */ - filterHasScreenshot?: boolean; - /** @description Selects only keys without screenshots */ - filterHasNoScreenshot?: boolean; - /** - * @description Filter namespaces. - * - * To filter default namespace, set to empty string. - */ - filterNamespace?: string[]; - /** @description Selects only keys with provided tag */ - filterTag?: string[]; - /** - * @description Selects only keys, where translation in provided langs is in outdated state - * @example en-US - */ - filterOutdatedLanguage?: string[]; - /** - * @description Selects only keys, where translation in provided langs is not in outdated state - * @example en-US - */ - filterNotOutdatedLanguage?: string[]; - /** - * @description Selects only key affected by activity with specidfied revision ID - * @example 1234567 - */ - filterRevisionId?: number[]; - /** @description Select only keys which were not successfully translated by batch job with provided id */ - filterFailedKeysOfJob?: number; - /** @description Select only keys which are in specified task */ - filterTaskNumber?: number[]; + path: { + commentId: number; + translationId: number; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["TranslationCommentDto"]; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["SelectAllResponse"]; + "application/json": components["schemas"]["TranslationCommentModel"]; }; }; /** @description Bad Request */ @@ -7657,87 +10733,18 @@ export interface operations { }; }; }; - /** - * Select keys - * @description Returns all key IDs for specified filter values. This way, you can apply the same filter as in the translation view and get the resulting key IDs for future use. - */ - selectKeys_3: { + /** Delete translation comment */ + delete_3: { parameters: { - query?: { - /** - * @description Translation state in the format: languageTag,state. You can use this parameter multiple times. - * - * When used with multiple states for same language it is applied with logical OR. - * - * When used with multiple languages, it is applied with logical AND. - */ - filterState?: string[]; - /** - * @description Languages to be contained in response. - * - * To add multiple languages, repeat this param (eg. ?languages=en&languages=de) - * @example en - */ - languages?: string[]; - /** @description String to search in key name or translation text */ - search?: string; - /** @description Selects key with provided names. Use this param multiple times to fetch more keys. */ - filterKeyName?: string[]; - /** @description Selects key with provided ID. Use this param multiple times to fetch more keys. */ - filterKeyId?: number[]; - /** @description Selects only keys for which the translation is missing in any returned language. It only filters for translations included in returned languages. */ - filterUntranslatedAny?: boolean; - /** @description Selects only keys, where translation is provided in any language */ - filterTranslatedAny?: boolean; - /** - * @description Selects only keys where the translation is missing for the specified language. The specified language must be included in the returned languages. Otherwise, this filter doesn't apply. - * @example en-US - */ - filterUntranslatedInLang?: string; - /** - * @description Selects only keys, where translation is provided in specified language - * @example en-US - */ - filterTranslatedInLang?: string; - /** @description Selects only keys with screenshots */ - filterHasScreenshot?: boolean; - /** @description Selects only keys without screenshots */ - filterHasNoScreenshot?: boolean; - /** - * @description Filter namespaces. - * - * To filter default namespace, set to empty string. - */ - filterNamespace?: string[]; - /** @description Selects only keys with provided tag */ - filterTag?: string[]; - /** - * @description Selects only keys, where translation in provided langs is in outdated state - * @example en-US - */ - filterOutdatedLanguage?: string[]; - /** - * @description Selects only keys, where translation in provided langs is not in outdated state - * @example en-US - */ - filterNotOutdatedLanguage?: string[]; - /** - * @description Selects only key affected by activity with specidfied revision ID - * @example 1234567 - */ - filterRevisionId?: number[]; - /** @description Select only keys which were not successfully translated by batch job with provided id */ - filterFailedKeysOfJob?: number; - /** @description Select only keys which are in specified task */ - filterTaskNumber?: number[]; + path: { + translationId: number; + commentId: number; }; }; responses: { /** @description OK */ 200: { - content: { - "application/json": components["schemas"]["SelectAllResponse"]; - }; + content: never; }; /** @description Bad Request */ 400: { @@ -7765,15 +10772,20 @@ export interface operations { }; }; }; - /** Get project daily amount of events */ - getProjectDailyActivity_1: { + /** Set state of translation comment */ + setState_1: { + parameters: { + path: { + translationId: number; + commentId: number; + state: "RESOLUTION_NOT_NEEDED" | "NEEDS_RESOLUTION" | "RESOLVED"; + }; + }; responses: { /** @description OK */ 200: { content: { - "application/hal+json": { - [key: string]: number; - }; + "application/json": components["schemas"]["TranslationCommentModel"]; }; }; /** @description Bad Request */ @@ -7802,13 +10814,21 @@ export interface operations { }; }; }; - /** Get project stats */ - getProjectStats_1: { + /** + * Dismiss auto-translated + * @description Removes "auto translated" indication + */ + dismissAutoTranslatedState_1: { + parameters: { + path: { + translationId: number; + }; + }; responses: { /** @description OK */ 200: { content: { - "application/hal+json": components["schemas"]["ProjectStatsModel"]; + "application/json": components["schemas"]["TranslationModel"]; }; }; /** @description Bad Request */ @@ -7838,15 +10858,28 @@ export interface operations { }; }; /** - * Return current PAK - * @description Returns current Personal Access Token. If the request is not authenticated with a Personal Access Token, it will return 400 response status. + * Get translation history + * @description Sorting is not supported for supported. It is automatically sorted from newest to oldest. */ - getCurrent: { + getTranslationHistory_1: { + parameters: { + query?: { + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + }; + path: { + translationId: number; + }; + }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["PatWithUserModel"]; + "application/json": components["schemas"]["PagedModelTranslationHistoryModel"]; }; }; /** @description Bad Request */ @@ -7875,18 +10908,19 @@ export interface operations { }; }; }; - /** Get organization by slug */ - get_19: { + /** Add label to translation */ + assignLabel_1: { parameters: { path: { - slug: string; + translationId: number; + labelId: number; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["OrganizationModel"]; + "application/json": components["schemas"]["LabelModel"]; }; }; /** @description Bad Request */ @@ -7915,22 +10949,18 @@ export interface operations { }; }; }; - /** - * Get credit balance for organization - * @description Returns machine translation credit balance for organization - */ - getOrganizationCredits: { + /** Remove label from translation */ + unassignLabel_1: { parameters: { path: { - organizationId: number; + translationId: number; + labelId: number; }; }; responses: { /** @description OK */ 200: { - content: { - "application/json": components["schemas"]["CreditBalanceModel"]; - }; + content: never; }; /** @description Bad Request */ 400: { @@ -7959,15 +10989,21 @@ export interface operations { }; }; /** - * Get current API key info - * @description Returns info the API key which user currently authenticated with. Otherwise responds with 400 status code. + * Set outdated value + * @description Set's "outdated" flag indicating the base translation was changed without updating current translation. */ - getCurrent_1: { + setOutdated_1: { + parameters: { + path: { + translationId: number; + state: boolean; + }; + }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["ApiKeyWithLanguagesModel"]; + "application/json": components["schemas"]["TranslationModel"]; }; }; /** @description Bad Request */ @@ -7996,22 +11032,19 @@ export interface operations { }; }; }; - /** - * Get current permission info - * @description Returns current PAK or PAT permissions for current user, api-key and project - */ - getCurrentPermissions: { + /** Set translation state */ + setTranslationState_1: { parameters: { - query?: { - /** @description Required when using with PAT */ - projectId?: number; + path: { + translationId: number; + state: "TRANSLATED" | "REVIEWED"; }; }; responses: { /** @description OK */ 200: { content: { - "application/json": components["schemas"]["ApiKeyPermissionsModel"]; + "application/json": components["schemas"]["TranslationModel"]; }; }; /** @description Bad Request */ @@ -8040,17 +11073,17 @@ export interface operations { }; }; }; - /** Delete one or multiple keys */ - delete_3: { - parameters: { - path: { - ids: number[]; - }; - }; + /** + * Get used namespaces + * @description Returns all used project namespaces. Response contains default (null) namespace if used. + */ + getUsedNamespaces_1: { responses: { /** @description OK */ 200: { - content: never; + content: { + "application/json": components["schemas"]["CollectionModelUsedNamespaceModel"]; + }; }; /** @description Bad Request */ 400: { @@ -8079,20 +11112,16 @@ export interface operations { }; }; /** - * Remove tag - * @description Removes tag with provided id from key with provided id + * Get user info + * @description Returns information about currently authenticated user. */ - removeTag_1: { - parameters: { - path: { - keyId: number; - tagId: number; - }; - }; + getInfo: { responses: { /** @description OK */ 200: { - content: never; + content: { + "application/json": components["schemas"]["PrivateUserAccountModel"]; + }; }; /** @description Bad Request */ 400: { @@ -8120,18 +11149,49 @@ export interface operations { }; }; }; - /** Delete screenshots */ - deleteScreenshots: { + /** Get user tasks */ + getTasks_2: { parameters: { - path: { - ids: number[]; - keyId: number; + query?: { + /** @description Filter tasks by state */ + filterState?: ("NEW" | "IN_PROGRESS" | "FINISHED" | "CANCELED")[]; + /** @description Filter tasks without state */ + filterNotState?: ("NEW" | "IN_PROGRESS" | "FINISHED" | "CANCELED")[]; + /** @description Filter tasks by assignee */ + filterAssignee?: number[]; + /** @description Filter tasks by type */ + filterType?: ("TRANSLATE" | "REVIEW")[]; + /** @description Filter tasks by id */ + filterId?: number[]; + /** @description Filter tasks without id */ + filterNotId?: number[]; + /** @description Filter tasks by project */ + filterProject?: number[]; + /** @description Filter tasks without project */ + filterNotProject?: number[]; + /** @description Filter tasks by language */ + filterLanguage?: number[]; + /** @description Filter tasks by key */ + filterKey?: number[]; + /** @description Filter tasks by agency */ + filterAgency?: number[]; + /** @description Exclude tasks which were closed before specified timestamp */ + filterNotClosedBefore?: number; + /** @description Zero-based page index (0..N) */ + page?: number; + /** @description The size of the page to be returned */ + size?: number; + /** @description Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. */ + sort?: string[]; + search?: string; }; }; responses: { /** @description OK */ 200: { - content: never; + content: { + "application/json": components["schemas"]["PagedModelTaskWithProjectModel"]; + }; }; /** @description Bad Request */ 400: { @@ -8159,16 +11219,20 @@ export interface operations { }; }; }; - /** Delete uploaded images */ - delete_12: { - parameters: { - path: { - ids: number[]; - }; - }; + /** + * Get information about SSO configuration + * @description Returns information about sso configuration affecting the user. + */ + getSso: { responses: { /** @description OK */ 200: { + content: { + "application/json": components["schemas"]["PublicSsoTenantModel"]; + }; + }; + /** @description No SSO configuration available for this user */ + 204: { content: never; }; /** @description Bad Request */ diff --git a/src/ui/client/client.ts b/src/ui/client/client.ts index 6483a93..4fd274e 100644 --- a/src/ui/client/client.ts +++ b/src/ui/client/client.ts @@ -3,6 +3,7 @@ import { paths } from "./apiSchema.generated"; import { RequestParamsType, ResponseContent } from "./types"; import { globalState } from "../state/GlobalState"; import { errorToText } from "./errorCodes"; +import { customPaths } from "./apiSchema.custom"; type GlobalOptions = { apiUrl?: string; @@ -123,7 +124,7 @@ export const addProjectIdToUrl = (url: string) => { export async function client< Url extends keyof Paths, Method extends keyof Paths[Url], - Paths = paths + Paths = paths & customPaths >( url: Url, method: Method, @@ -136,9 +137,12 @@ export async function client< let urlResult = url as string; const projectId = getProjectIdFromApiKey(fetchOptions.apiKey); + if (projectId !== undefined) { pathParams.projectId = projectId; - urlResult = addProjectIdToUrl(urlResult); + if (pathParams.projectId === undefined) { + urlResult = addProjectIdToUrl(urlResult); + } } if (pathParams) { diff --git a/src/ui/client/useQueryApi.ts b/src/ui/client/useQueryApi.ts index b43260c..d1b4a78 100644 --- a/src/ui/client/useQueryApi.ts +++ b/src/ui/client/useQueryApi.ts @@ -13,6 +13,7 @@ import { useGlobalState } from "../state/GlobalState"; import { paths } from "./apiSchema.generated"; import { client, ClientOptions } from "./client"; import { RequestParamsType, ResponseContent } from "./types"; +import { customPaths } from "./apiSchema.custom"; export type QueryProps< Url extends keyof Paths, @@ -28,7 +29,7 @@ export type QueryProps< export const useApiQuery = < Url extends keyof Paths, Method extends keyof Paths[Url], - Paths = paths + Paths = paths & customPaths >( props: QueryProps ) => { diff --git a/src/ui/components/AutocompleteSelect/AutocompleteSelect.css b/src/ui/components/AutocompleteSelect/AutocompleteSelect.css new file mode 100644 index 0000000..538e00b --- /dev/null +++ b/src/ui/components/AutocompleteSelect/AutocompleteSelect.css @@ -0,0 +1,61 @@ +.autocompleteDropdown { + position: absolute; + left: 0; + right: 0; + background: var(--figma-color-bg); + border: 1px solid var(--figma-color-border); + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.07); + z-index: 2; + max-height: 180px; + overflow-y: auto; +} + +.autocompleteDropdown.down { + top: 110%; +} +.autocompleteDropdown.up { + bottom: 110%; +} + +.autocompleteDropdownHeader { + padding: 12px 12px 0 12px; + font-size: 10px; +} +.autocompleteDropdownHeaderEmpty { + padding: 12px; + font-size: 10px; +} + +.autocompleteDropdownItem { + padding: 8px 12px; + cursor: pointer; + font-weight: 500; + background: none; + border: none; + color: var(--figma-color-text); +} +.autocompleteDropdownItem:hover { + background: var(--figma-color-bg-hover); +} + +.autocompleteDropdownAdd { + padding: 12px 12px 12px 12px; + color: var(--figma-color-bg-brand); + font-weight: 500; + cursor: pointer; + border-top: 1px solid var(--figma-color-border); + display: flex; + gap: 4px; + align-items: center; + justify-content: space-between; +} +.autocompleteDropdownAdd > * { + cursor: pointer; +} + +.autocompleteDropdownAddHint { + font-style: italic; + color: var(--figma-color-bg-brand); + font-weight: 400; +} diff --git a/src/ui/components/AutocompleteSelect/AutocompleteSelect.css.d.ts b/src/ui/components/AutocompleteSelect/AutocompleteSelect.css.d.ts new file mode 100644 index 0000000..632b67c --- /dev/null +++ b/src/ui/components/AutocompleteSelect/AutocompleteSelect.css.d.ts @@ -0,0 +1,12 @@ +declare const styles: { + readonly "autocompleteDropdown": string; + readonly "autocompleteDropdownAdd": string; + readonly "autocompleteDropdownAddHint": string; + readonly "autocompleteDropdownHeader": string; + readonly "autocompleteDropdownHeaderEmpty": string; + readonly "autocompleteDropdownItem": string; + readonly "down": string; + readonly "up": string; +}; +export = styles; + diff --git a/src/ui/components/AutocompleteSelect/AutocompleteSelect.tsx b/src/ui/components/AutocompleteSelect/AutocompleteSelect.tsx new file mode 100644 index 0000000..8402909 --- /dev/null +++ b/src/ui/components/AutocompleteSelect/AutocompleteSelect.tsx @@ -0,0 +1,327 @@ +import { FunctionComponent, h } from "preact"; +import { + useRef, + useState, + useLayoutEffect, + useMemo, + useEffect, +} from "preact/hooks"; +import { Textbox, Muted } from "@create-figma-plugin/ui"; +import { Badge } from "../Badge/Badge"; +import styles from "./AutocompleteSelect.css"; + +type Props = + | { + value: string; + options: string[]; + placeholder?: string; + existingOptionsPlaceholder?: string; + noOptionsPlaceholder?: string; + onChange: (value: string) => void; + displayValue?: (value: string) => string; + dataCy?: string; + singleSelect: true; // When true, shows value in input instead of as badge + inputRef?: preact.RefObject; // Expose input ref for external control + } + | { + value: string[]; + options: string[]; + placeholder?: string; + existingOptionsPlaceholder?: string; + noOptionsPlaceholder?: string; + onChange: (value: string[]) => void; + displayValue?: (value: string) => string; + dataCy?: string; + singleSelect?: false; // Multi-select mode + inputRef?: preact.RefObject; // Expose input ref for external control + }; + +export const AutocompleteSelect: FunctionComponent = (props) => { + const { + options, + placeholder = "Add...", + existingOptionsPlaceholder = "Existing options", + noOptionsPlaceholder = "No options found", + displayValue = (v) => v || "", + dataCy, + singleSelect = false, + inputRef: externalInputRef, + } = props; + + const isMultiSelect = !singleSelect; + const singleValue = singleSelect ? (props.value as string) : ""; + const multiValues = isMultiSelect ? (props.value as string[]) : []; + const singleOnChange = singleSelect + ? (props.onChange as (value: string) => void) + : null; + const multiOnChange = isMultiSelect + ? (props.onChange as (value: string[]) => void) + : null; + + const [inputValue, setInputValue] = useState( + singleSelect ? singleValue ?? "" : "" + ); + const [isFocused, setIsFocused] = useState(false); + const [showDropdown, setShowDropdown] = useState(false); + const internalInputRef = useRef(null); + const inputRef = externalInputRef || internalInputRef; + const dropdownRef = useRef(null); + const [dropdownDirection, setDropdownDirection] = useState<"down" | "up">( + "down" + ); + + // For single-select mode, show value in input when not focused, otherwise show inputValue + // Ensure we always return a string, not undefined + const displayInputValue = singleSelect + ? isFocused + ? inputValue ?? "" + : singleValue ?? "" + : inputValue ?? ""; + + useLayoutEffect(() => { + if (!showDropdown || !inputRef.current) return; + const inputRect = inputRef.current.getBoundingClientRect(); + const dropdownHeight = dropdownRef.current?.offsetHeight || 180; + const spaceBelow = window.innerHeight - inputRect.bottom - 49; // padding of actionbar + const spaceAbove = inputRect.top; + if (spaceBelow < dropdownHeight && spaceAbove > dropdownHeight) { + setDropdownDirection("up"); + } else { + setDropdownDirection("down"); + } + }, [inputValue, showDropdown]); + + // Sync inputValue with value prop when not focused (for single-select mode) + useEffect(() => { + if (!singleSelect || isFocused) return; + // Sync inputValue with value when not focused + setInputValue(singleValue ?? ""); + }, [singleSelect, singleValue, isFocused]); + + const filteredOptions = useMemo(() => { + const filtered = options.filter((opt) => + opt.toLowerCase().includes(inputValue.toLowerCase()) + ); + // In multi-select mode, exclude already selected values + if (isMultiSelect) { + return filtered.filter((opt) => !multiValues.includes(opt)); + } + return filtered; + }, [options, inputValue, isMultiSelect, multiValues]); + + const exactMatch = useMemo(() => { + return filteredOptions.find( + (opt) => opt.toLowerCase() === inputValue.trim().toLowerCase() + ); + }, [filteredOptions, inputValue]); + + const alreadyExists = isMultiSelect + ? multiValues.includes(inputValue.trim()) || + options.some( + (opt) => opt.toLowerCase() === inputValue.trim().toLowerCase() + ) + : singleValue === inputValue.trim() || + options.some( + (opt) => opt.toLowerCase() === inputValue.trim().toLowerCase() + ); + + const canAdd = inputValue.trim() && !alreadyExists; + + const handleSelect = (selectedValue: string) => { + if (singleSelect && singleOnChange) { + singleOnChange(selectedValue); + setInputValue(selectedValue); + } else if (isMultiSelect && multiOnChange) { + multiOnChange([...multiValues, selectedValue]); + setInputValue(""); + } + setShowDropdown(false); + setIsFocused(false); + }; + + const handleAdd = () => { + const newValue = inputValue.trim(); + if (singleSelect && singleOnChange) { + if (newValue && newValue !== singleValue) { + singleOnChange(newValue); + setInputValue(newValue); + } + } else if (isMultiSelect && multiOnChange) { + if (newValue && !multiValues.includes(newValue)) { + multiOnChange([...multiValues, newValue]); + setInputValue(""); + } + } + setShowDropdown(false); + setIsFocused(false); + }; + + const handleRemove = (removedValue?: string) => { + if (singleSelect && singleOnChange) { + singleOnChange(""); + setInputValue(""); + } else if (isMultiSelect && multiOnChange && removedValue) { + multiOnChange(multiValues.filter((v) => v !== removedValue)); + } + }; + + const handleFocus = () => { + setIsFocused(true); + if (singleSelect && !inputValue) { + setInputValue(singleValue ?? ""); + } + setShowDropdown(true); + }; + + const handleBlur = (e: FocusEvent) => { + // Don't close if clicking on the refresh button or its parent + const relatedTarget = e.relatedTarget as HTMLElement; + if (relatedTarget?.closest("[data-refresh-button]")) { + return; + } + + setIsFocused(false); + // Delay to allow click events on dropdown items + setTimeout(() => { + setShowDropdown(false); + if (singleSelect) { + setInputValue(singleValue ?? ""); + } + }, 200); + }; + + return ( +
+ {isMultiSelect && + multiValues.map((val) => ( + handleRemove(val)}> + {displayValue(val)} + + ))} +
+ setInputValue(e.currentTarget.value)} + onKeyDown={(e) => { + if (e.key === "Enter") { + if (exactMatch) { + handleSelect(exactMatch); + } else if (canAdd) { + handleAdd(); + } + } else if (e.key === "Escape") { + if (singleSelect) { + setInputValue(""); + setIsFocused(false); + setShowDropdown(false); + inputRef.current?.blur(); + } + } + }} + /> + {showDropdown && ( +
+ {filteredOptions.length > 0 ? ( +
+ {existingOptionsPlaceholder} +
+ ) : ( +
+ {noOptionsPlaceholder} +
+ )} + {filteredOptions.map((opt) => { + const matchIndex = opt + .toLowerCase() + .indexOf(inputValue.toLowerCase()); + const isExact = + opt.toLowerCase() === inputValue.trim().toLowerCase(); + if (matchIndex === -1) { + return ( +
handleSelect(opt)} + style={{ + display: "flex", + justifyContent: "space-between", + alignItems: "center", + }} + > + {displayValue(opt)} + {isExact && ( + + Enter + + )} +
+ ); + } + const before = opt.slice(0, matchIndex); + const match = opt.slice( + matchIndex, + matchIndex + inputValue.length + ); + const after = opt.slice(matchIndex + inputValue.length); + return ( +
handleSelect(opt)} + style={{ + display: "flex", + justifyContent: "space-between", + alignItems: "center", + }} + > + + {before} + {match} + {after} + + {isExact && ( + + Enter + + )} +
+ ); + })} + {canAdd && ( +
handleAdd()} + > + + Add "{inputValue}" + + + Enter + +
+ )} +
+ )} +
+
+ ); +}; diff --git a/src/ui/components/NamespaceSelect/NamespaceSelect.css b/src/ui/components/NamespaceSelect/NamespaceSelect.css index 8703f70..2508789 100644 --- a/src/ui/components/NamespaceSelect/NamespaceSelect.css +++ b/src/ui/components/NamespaceSelect/NamespaceSelect.css @@ -8,3 +8,56 @@ justify-content: flex-end; margin: 6px 0px; } +.selectContainer { + padding: 3px 8px; +} + +.container { + width: 100%; +} + +.inputWrapper { + position: relative; + width: 100%; +} + +.inputWrapper > :first-child { + width: 100%; +} + +.refreshButton { + position: absolute; + right: 8px; + top: 50%; + transform: translateY(-50%); + z-index: 2; + padding: 4px; + cursor: pointer; + color: var(--figma-color-text-secondary); + background: var(--figma-color-bg); + border: none; + transition: color 0.2s; + pointer-events: auto; +} + +.refreshButton:hover:not(:disabled) { + color: var(--figma-color-text); +} + +.refreshButton:disabled { + cursor: not-allowed; + opacity: 0.7; +} + +.refreshButton.rotating { + animation: rotate 1s linear infinite; +} + +@keyframes rotate { + from { + transform: translateY(-50%) rotate(0deg); + } + to { + transform: translateY(-50%) rotate(360deg); + } +} diff --git a/src/ui/components/NamespaceSelect/NamespaceSelect.css.d.ts b/src/ui/components/NamespaceSelect/NamespaceSelect.css.d.ts index d3962b4..8511b74 100644 --- a/src/ui/components/NamespaceSelect/NamespaceSelect.css.d.ts +++ b/src/ui/components/NamespaceSelect/NamespaceSelect.css.d.ts @@ -1,6 +1,12 @@ declare const styles: { readonly "actions": string; + readonly "container": string; + readonly "inputWrapper": string; readonly "modalBody": string; + readonly "refreshButton": string; + readonly "rotate": string; + readonly "rotating": string; + readonly "selectContainer": string; }; export = styles; diff --git a/src/ui/components/NamespaceSelect/NamespaceSelect.tsx b/src/ui/components/NamespaceSelect/NamespaceSelect.tsx index 8b4c6db..e7700b3 100644 --- a/src/ui/components/NamespaceSelect/NamespaceSelect.tsx +++ b/src/ui/components/NamespaceSelect/NamespaceSelect.tsx @@ -1,98 +1,96 @@ -import { - Button, - Container, - Divider, - Modal, - Textbox, - VerticalSpace, -} from "@create-figma-plugin/ui"; -import { Fragment, FunctionComponent, h } from "preact"; -import { useState } from "preact/hooks"; +import { FunctionComponent, h } from "preact"; +import { useState, useRef } from "preact/hooks"; +import { AutocompleteSelect } from "../AutocompleteSelect/AutocompleteSelect"; +import { IconButton } from "@create-figma-plugin/ui"; +import { Refresh } from "@/ui/icons/SvgIcons"; import styles from "./NamespaceSelect.css"; type Props = { namespaces: string[]; value: string; onChange: (value: string) => void; - selectProps?: h.JSX.HTMLAttributes; + onRefresh?: () => Promise | void; }; -const ADD_NEW_VALUE = Number.MAX_VALUE; - export const NamespaceSelect: FunctionComponent = ({ value, namespaces, - selectProps, onChange, + onRefresh, }) => { - const [modalOpen, setModalOpen] = useState(false); - const [nsName, setNsName] = useState(""); + const [isRefreshing, setIsRefreshing] = useState(false); + const inputRef = useRef(null); - const handleModalClose = () => { - setModalOpen(false); - }; + // Ensure all namespaces are included, plus the current value if it's not in the list + const allNamespaces = [ + ...new Set([ + ...namespaces, + ...(value && !namespaces.includes(value) ? [value] : []), + ]), + ] + .filter(Boolean) + .sort((a, b) => { + // Sort alphabetically, but put empty string at the end + if (!a) return 1; + if (!b) return -1; + return a.localeCompare(b); + }); + + const handleRefresh = async (e: MouseEvent) => { + e.stopPropagation(); + e.preventDefault(); + if (!onRefresh || isRefreshing) return; - function setValue(value: string) { - onChange(value); - } + // Store if input was focused before refresh + const wasFocused = document.activeElement === inputRef.current; - const handleSetCustomValue = () => { - setValue(nsName); - setModalOpen(false); + setIsRefreshing(true); + try { + await onRefresh(); + // Reopen the dropdown if it was open before + if (wasFocused && inputRef.current) { + setTimeout(() => { + inputRef.current?.focus(); + // Small delay to ensure the options are updated + setTimeout(() => { + inputRef.current?.focus(); + }, 50); + }, 100); + } + } finally { + setIsRefreshing(false); + } }; return ( - - - -
- - - setNsName(e.currentTarget.value)} - onKeyDownCapture={(e) => { - if (e.key === "Enter") { - handleSetCustomValue(); - } - }} - /> - - - - -
- -
-
-
-
-
+
+
+ v || ""} + dataCy="general_namespace_select_input" + singleSelect={true} + inputRef={inputRef} + /> + {onRefresh && ( + + + + )} +
+
); }; diff --git a/src/ui/components/NodeList/NodeRow.css b/src/ui/components/NodeList/NodeRow.css index cbca5bc..de44aa4 100644 --- a/src/ui/components/NodeList/NodeRow.css +++ b/src/ui/components/NodeList/NodeRow.css @@ -38,6 +38,9 @@ .ns { cursor: unset; + overflow: visible; + text-overflow: unset; + margin-top: 4px; grid-column: 1 / span 2; } diff --git a/src/ui/components/NodeList/NodeRow.tsx b/src/ui/components/NodeList/NodeRow.tsx index ae6dd0e..46b89e9 100644 --- a/src/ui/components/NodeList/NodeRow.tsx +++ b/src/ui/components/NodeList/NodeRow.tsx @@ -85,8 +85,7 @@ export const NodeRow = ({ ? nsComponent : node.ns && ( - ns: - {node.ns} + Namespace: {node.ns} )} diff --git a/src/ui/hooks/useAllTranslations.ts b/src/ui/hooks/useAllTranslations.ts index 5768f8b..9ed9390 100644 --- a/src/ui/hooks/useAllTranslations.ts +++ b/src/ui/hooks/useAllTranslations.ts @@ -36,6 +36,12 @@ export const useAllTranslations = () => { ) ?? []; + // Ensure empty string is included if namespaces is provided and contains empty string + // This handles the default namespace case + if (namespaces && namespaces.includes("") && !nsNames.includes("")) { + nsNames.push(""); + } + const data: TranslationData = {}; for (const ns of nsNames) { @@ -92,6 +98,9 @@ export const useAllTranslations = () => { setIsLoading(false); } }, + clearCache() { + setTranslationsData(null); + }, translationsData, isLoading, error: namespacesLoadable.error || translationsLoadable.error, diff --git a/src/ui/hooks/useHasNamespacesEnabled.ts b/src/ui/hooks/useHasNamespacesEnabled.ts new file mode 100644 index 0000000..1fdd001 --- /dev/null +++ b/src/ui/hooks/useHasNamespacesEnabled.ts @@ -0,0 +1,35 @@ +import { useApiQuery } from "../client/useQueryApi"; + +export const useHasNamespacesEnabled = () => { + try { + // First, get the project ID from the API key info (relevant for legacy api keys) + const apiKeyInfo = useApiQuery({ + url: "/v2/api-keys/current", + method: "get", + options: { + cacheTime: 60000, + staleTime: 60000, + }, + }); + + // Then get the project info if we have a project ID + // eslint-disable-next-line react-hooks/rules-of-hooks + const projectQuery = useApiQuery({ + url: "/v2/projects/{projectId}", + method: "get", + path: { + projectId: apiKeyInfo.data?.projectId ?? 0, + }, + options: { + cacheTime: 60000, + staleTime: 60000, + enabled: apiKeyInfo.data?.projectId !== undefined, + }, + }); + + return projectQuery.data?.useNamespaces ?? false; + } catch (error) { + console.error(error); + return false; + } +}; diff --git a/src/ui/hooks/useSetNodesDataMutation.ts b/src/ui/hooks/useSetNodesDataMutation.ts index 58b87e3..1d26748 100644 --- a/src/ui/hooks/useSetNodesDataMutation.ts +++ b/src/ui/hooks/useSetNodesDataMutation.ts @@ -2,13 +2,21 @@ import { SetNodesDataProps, setNodesDataEndpoint, } from "@/main/endpoints/setNodesData"; +import { getConnectedNodesEndpoint } from "@/main/endpoints/getConnectedNodes"; import { delayed } from "@/main/utils/delayed"; -import { useMutation } from "react-query"; +import { useMutation, useQueryClient } from "react-query"; export const useSetNodesDataMutation = () => { + const queryClient = useQueryClient(); const result = useMutation( [setNodesDataEndpoint.name], - delayed((props: SetNodesDataProps) => setNodesDataEndpoint.call(props)) + delayed((props: SetNodesDataProps) => setNodesDataEndpoint.call(props)), + { + onSuccess: () => { + // Invalidate connected nodes query to ensure fresh data is fetched + queryClient.invalidateQueries([getConnectedNodesEndpoint.name]); + }, + } ); return { ...result }; }; diff --git a/src/ui/icons/SvgIcons.tsx b/src/ui/icons/SvgIcons.tsx index 41a77ad..b568b29 100644 --- a/src/ui/icons/SvgIcons.tsx +++ b/src/ui/icons/SvgIcons.tsx @@ -183,3 +183,19 @@ export const ResizeHandleIcon = (props: h.JSX.SVGAttributes) => { ); }; + +export const Refresh = (props: h.JSX.SVGAttributes) => { + return ( + + + + ); +}; diff --git a/src/ui/views/Index/Index.css b/src/ui/views/Index/Index.css index ee0a341..c0e4f3a 100644 --- a/src/ui/views/Index/Index.css +++ b/src/ui/views/Index/Index.css @@ -28,12 +28,6 @@ background: blue; } -.nsSelect { - display: flex; - align-items: center; - height: 21px; -} - .screenshot { position: relative; } diff --git a/src/ui/views/Index/Index.css.d.ts b/src/ui/views/Index/Index.css.d.ts index 3024008..8784682 100644 --- a/src/ui/views/Index/Index.css.d.ts +++ b/src/ui/views/Index/Index.css.d.ts @@ -5,7 +5,6 @@ declare const styles: { readonly "disabled": string; readonly "keyInput": string; readonly "languageContainer": string; - readonly "nsSelect": string; readonly "screenshot": string; readonly "settingsButton": string; }; diff --git a/src/ui/views/Index/Index.tsx b/src/ui/views/Index/Index.tsx index 1ed4447..fd86e9e 100644 --- a/src/ui/views/Index/Index.tsx +++ b/src/ui/views/Index/Index.tsx @@ -1,5 +1,5 @@ import { Fragment, h } from "preact"; -import { useEffect, useState } from "preact/hooks"; +import { useEffect, useState, useMemo } from "preact/hooks"; import { Banner, Button, @@ -16,12 +16,14 @@ import { getConflictingNodes } from "@/tools/getConflictingNodes"; import { FullPageLoading } from "@/ui/components/FullPageLoading/FullPageLoading"; import { useGlobalActions, useGlobalState } from "@/ui/state/GlobalState"; import { useSelectedNodes } from "@/ui/hooks/useSelectedNodes"; +import { useConnectedNodes } from "@/ui/hooks/useConnectedNodes"; import { NodeList } from "../../components/NodeList/NodeList"; import { TopBar } from "../../components/TopBar/TopBar"; import styles from "./Index.css"; import { ListItem } from "./ListItem"; import { useEditorMode } from "../../hooks/useEditorMode"; +import { useHasNamespacesEnabled } from "../../hooks/useHasNamespacesEnabled"; export const Index = () => { const selectionLoadable = useSelectedNodes(); @@ -51,12 +53,43 @@ export const Index = () => { method: "get", }); + const hasNamespacesEnabled = useHasNamespacesEnabled(); + const languages = languagesLoadable.data?._embedded?.languages; const language = useGlobalState((c) => c.config?.language) || languages?.[0]?.tag || ""; const { setRoute } = useGlobalActions(); + const allNodes = useConnectedNodes({ ignoreSelection: true }); + + // Combine API namespaces + all namespaces from nodes + const allAvailableNamespaces = useMemo(() => { + const apiNamespaces = + namespacesLoadable.data?._embedded?.namespaces?.map( + (n) => n.name || "" + ) || []; + const nodeNamespaces = Array.from( + new Set( + (allNodes.data?.items || []) + .map((node) => node.ns) + .filter((ns): ns is string => Boolean(ns)) + ) + ); + return Array.from(new Set([...apiNamespaces, ...nodeNamespaces])) + .filter(Boolean) + .sort((a, b) => { + // Sort alphabetically, but put empty string at the end + if (!a) return 1; + if (!b) return -1; + return a.localeCompare(b); + }); + }, [namespacesLoadable.data, allNodes.data]); + + // Refresh namespaces: refetch API and all nodes + const handleRefreshNamespaces = async () => { + await Promise.all([namespacesLoadable.refetch(), allNodes.refetch()]); + }; const nothingSelected = !selectionLoadable.data?.somethingSelected; @@ -205,8 +238,12 @@ export const Index = () => { items={selection} row={(node) => ( ({ + name, + }))} + onRefreshNamespaces={handleRefreshNamespaces} /> )} /> diff --git a/src/ui/views/Index/ListItem.tsx b/src/ui/views/Index/ListItem.tsx index 74ad26b..7e69ca9 100644 --- a/src/ui/views/Index/ListItem.tsx +++ b/src/ui/views/Index/ListItem.tsx @@ -10,7 +10,6 @@ import { useGlobalActions, useGlobalState } from "@/ui/state/GlobalState"; import { components } from "@/ui/client/apiSchema.generated"; import { InsertLink } from "@/ui/icons/SvgIcons"; import { KeyOptionsButton } from "../../components/KeyOptionsButton/KeyOptionsButton"; -import { useEditorMode } from "../../hooks/useEditorMode"; import { usePrefilledKey } from "../../hooks/usePrefilledKey"; type UsedNamespaceModel = components["schemas"]["UsedNamespaceModel"]; @@ -18,9 +17,16 @@ type UsedNamespaceModel = components["schemas"]["UsedNamespaceModel"]; type Props = { node: NodeInfo; loadedNamespaces: UsedNamespaceModel[] | undefined; + hasNamespacesEnabled: boolean; + onRefreshNamespaces?: () => void; }; -export const ListItem = ({ node, loadedNamespaces }: Props) => { +export const ListItem = ({ + node, + loadedNamespaces, + hasNamespacesEnabled, + onRefreshNamespaces, +}: Props) => { const nodeId = node?.id ?? ""; const tolgeeConfig = useGlobalState((c) => c.config); @@ -39,10 +45,6 @@ export const ListItem = ({ node, loadedNamespaces }: Props) => { const { setRoute } = useGlobalActions(); - const namespacesDisabled = useGlobalState( - (c) => c.config?.namespacesDisabled - ); - useEffect(() => { if (prefilledKey.key && !node.connected) { handleKeyChange(node)(prefilledKey.key); @@ -88,8 +90,6 @@ export const ListItem = ({ node, loadedNamespaces }: Props) => { node.ns = value; }; - const editorMode = useEditorMode(); - return ( { } nsComponent={ !node.connected && - !namespacesDisabled && ( -
- -
+ hasNamespacesEnabled && ( + ) } action={ diff --git a/src/ui/views/Push/Push.tsx b/src/ui/views/Push/Push.tsx index 43b701b..d55061f 100644 --- a/src/ui/views/Push/Push.tsx +++ b/src/ui/views/Push/Push.tsx @@ -29,6 +29,7 @@ import { getScreenshotsEndpoint } from "@/main/endpoints/getScreenshots"; import { useConnectedNodes } from "@/ui/hooks/useConnectedNodes"; import { useSetNodesDataMutation } from "@/ui/hooks/useSetNodesDataMutation"; import { useAllTranslations } from "@/ui/hooks/useAllTranslations"; +import { useHasNamespacesEnabled } from "../../hooks/useHasNamespacesEnabled"; type ImportKeysResolvableItemDto = components["schemas"]["ImportKeysResolvableItemDto"]; @@ -40,8 +41,10 @@ export const Push: FunctionalComponent = () => { const [error, setError] = useState(false); const [errorMessage, setErrorMessage] = useState(); const [success, setSuccess] = useState(false); + const [isPushing, setIsPushing] = useState(false); const [_loadingStatus, setLoadingStatus] = useState(); const [changes, setChanges] = useState(); + const [pushedKeysCount, setPushedKeysCount] = useState(0); const selectedNodes = useConnectedNodes({ ignoreSelection: false }); const tolgeeConfig = useGlobalState((c) => c.config); const [screenshotCount, setScreenshotCount] = useState(0); @@ -50,56 +53,144 @@ export const Push: FunctionalComponent = () => { const [uploadScreenshots, setUploadScreenshots] = useState(true); + // Optimize deduplication from O(n²) to O(n) using Set const deduplicatedNodes = useMemo(() => { + const seen = new Set(); const deduplicatedNodes: NodeInfo[] = []; - nodes.forEach((node) => { - if ( - !deduplicatedNodes.find( - (n) => node.key === n.key && compareNs(node.ns, n.ns) - ) - ) { + for (const node of nodes) { + const key = `${node.key}:${node.ns || ""}`; + if (!seen.has(key)) { + seen.add(key); deduplicatedNodes.push(node); } - }); + } return deduplicatedNodes; }, [nodes]); const allTranslationsLoadable = useAllTranslations(); + const hasNamespacesEnabled = useHasNamespacesEnabled(); - async function computeDiff() { - try { - const translations = await allTranslationsLoadable.getData({ - language, - }); + // Create a stable key from nodes to detect changes (including namespace changes) + const nodesKey = useMemo( + () => nodes.map((n) => `${n.id}:${n.key}:${n.ns || ""}`).join("|"), + [nodes] + ); + + // Extract unique namespaces from nodes being pushed (performance optimization) + // Only load translations for namespaces actually used by the nodes + // This is computed inside the effect to avoid dependency issues + const requiredNamespacesKey = useMemo(() => { + if (!hasNamespacesEnabled) return ""; + const uniqueNamespaces = Array.from( + new Set( + deduplicatedNodes + .map((node) => node.ns) + .filter((ns): ns is string => Boolean(ns)) + ) + ); + return uniqueNamespaces.sort().join(","); + }, [deduplicatedNodes, hasNamespacesEnabled]); + + // Memoize screenshots key to avoid regenerating screenshots unnecessarily + const screenshotsKey = useMemo( + () => + tolgeeConfig?.updateScreenshots + ? nodes.map((n) => `${n.id}:${n.key}:${n.ns || ""}`).join("|") + : "", + [nodes, tolgeeConfig?.updateScreenshots] + ); + + // Extract stable primitive values from tolgeeConfig to avoid object reference issues + const tolgeeConfigTags = useMemo( + () => JSON.stringify(tolgeeConfig?.tags?.sort() || []), + [tolgeeConfig?.tags] + ); + const tolgeeConfigUpdateScreenshots = tolgeeConfig?.updateScreenshots ?? true; + const tolgeeConfigAddTags = tolgeeConfig?.addTags ?? false; + + useEffect(() => { + // Don't recompute if we're showing success screen + if (success) { + return; + } + + let cancelled = false; - const screenshots = - tolgeeConfig?.updateScreenshots ?? true + async function computeDiff() { + setLoadingStatus("Loading translations"); + try { + // Compute requiredNamespaces inside the effect to avoid dependency issues + // Include all namespaces from nodes, including empty string for default namespace + const requiredNamespaces = + hasNamespacesEnabled && deduplicatedNodes.length > 0 + ? Array.from( + new Set(deduplicatedNodes.map((node) => node.ns ?? "")) + ) + : undefined; + + const translations = await allTranslationsLoadable.getData({ + language, + namespaces: requiredNamespaces, + }); + + // Check if cancelled before expensive screenshot operation + if (cancelled) return; + + const screenshots = tolgeeConfigUpdateScreenshots ? await getScreenshotsEndpoint.call(nodes) : []; - setChanges( - getPushChanges( - deduplicatedNodes, - translations, - language, - screenshots, - tolgeeConfig - ) - ); - } catch (e) { - if (e === "invalid_project_api_key") { - setErrorMessage("Invalid API key"); - } else { - setErrorMessage(`Cannot get translation data. ${e}`); + // Check if cancelled before setting state + if (cancelled) return; + + // Reconstruct tolgeeConfig object for getPushChanges + const configForDiff = { + ...tolgeeConfig, + tags: tolgeeConfig?.tags, + updateScreenshots: tolgeeConfigUpdateScreenshots, + addTags: tolgeeConfigAddTags, + }; + + setChanges( + getPushChanges( + deduplicatedNodes, + translations, + hasNamespacesEnabled, + screenshots, + configForDiff + ) + ); + } catch (e) { + if (cancelled) return; + if (e === "invalid_project_api_key") { + setErrorMessage("Invalid API key"); + } else { + setErrorMessage(`Cannot get translation data. ${e}`); + } + } finally { + if (!cancelled) { + setLoadingStatus(undefined); + } } - } finally { - setLoadingStatus(undefined); } - } - useEffect(() => { computeDiff(); - }, [nodes.length]); + + // Cleanup: cancel if dependencies change before async operations complete + return () => { + cancelled = true; + }; + }, [ + nodesKey, + screenshotsKey, + hasNamespacesEnabled, + language, + requiredNamespacesKey, + tolgeeConfigTags, + tolgeeConfigUpdateScreenshots, + tolgeeConfigAddTags, + success, // Include success to prevent recompute when showing success screen + ]); const totalScreenshotCount = useMemo(() => { return changes?.screenshots.length || 0; @@ -161,6 +252,8 @@ export const Push: FunctionalComponent = () => { return; } + setIsPushing(true); + try { const screenshotsMap = new Map(); const requiredScreenshots = uploadScreenshots ? changes.screenshots : []; @@ -169,7 +262,7 @@ export const Push: FunctionalComponent = () => { setLoadingStatus( `Uploading images (${i + 1}/${requiredScreenshots.length})` ); - const imageBlob = new Blob([screenshot.image.buffer], { + const imageBlob = new Blob([screenshot.image.buffer as ArrayBuffer], { type: "image/png", }); const location = `figma-${screenshot.info.id}`; @@ -316,7 +409,15 @@ export const Push: FunctionalComponent = () => { } } + // Store the count of keys that were pushed before clearing cache + const keysPushed = changes.newKeys.length + changes.changedKeys.length; + setPushedKeysCount(keysPushed); + connectNodes(); + + // Clear translations cache so newly pushed keys are recognized on next check + allTranslationsLoadable.clearCache(); + setSuccess(true); } catch (e) { setError(true); @@ -333,6 +434,7 @@ export const Push: FunctionalComponent = () => { } console.error(e); } finally { + setIsPushing(false); setLoadingStatus(undefined); } }; @@ -340,7 +442,8 @@ export const Push: FunctionalComponent = () => { const handleRepeat = () => { setError(false); setSuccess(false); - computeDiff(); + setPushedKeysCount(0); + setErrorMessage(undefined); }; const isLoading = @@ -348,7 +451,10 @@ export const Push: FunctionalComponent = () => { updateTranslations.isLoading || uploadImage.isLoading; - const changesSize = changes + // Use pushedKeysCount if we're showing success (after push), otherwise use current changes + const changesSize = success + ? pushedKeysCount + : changes ? changes.changedKeys.length + changes.newKeys.length : 0; @@ -365,7 +471,22 @@ export const Push: FunctionalComponent = () => { {errorMessage && !error ? ( }>{errorMessage} - ) : isLoading || !changes ? ( + ) : success ? ( + // Show success screen immediately, don't wait for recompute + +
+ Successfully updated {pushedKeysCount} key(s) + {uploadScreenshots + ? ` and uploaded ${screenshotCount} screenshot(s).` + : "."} +
+ + + +
+ ) : isLoading || !changes || isPushing ? ( ) : error ? ( @@ -380,20 +501,6 @@ export const Push: FunctionalComponent = () => { - ) : success ? ( - -
- Successfully updated {changesSize} key(s) - {uploadScreenshots - ? ` and uploaded ${screenshotCount} screenshot(s).` - : "."} -
- - - -
) : ( {totalScreenshotCount !== 0 && ( diff --git a/src/ui/views/Settings/ProjectSettings.tsx b/src/ui/views/Settings/ProjectSettings.tsx index ba3e446..242b1f6 100644 --- a/src/ui/views/Settings/ProjectSettings.tsx +++ b/src/ui/views/Settings/ProjectSettings.tsx @@ -7,6 +7,8 @@ import { Fragment, FunctionComponent, h } from "preact"; import { useEffect, useState } from "preact/hooks"; import styles from "./ProjectSettings.css"; import { InfoTooltip } from "../../components/InfoTooltip/InfoTooltip"; +import { useHasNamespacesEnabled } from "../../hooks/useHasNamespacesEnabled"; +import { getProjectIdFromApiKey } from "../../client/decodeApiKey"; type Props = { apiKey: string; @@ -15,9 +17,27 @@ type Props = { onChange: (data: Partial) => void; }; -const namespaceHelpText = ( +const namespaceHelpText = ({ + apiUrl, + projectId, +}: { + apiUrl: string; + projectId: number; +}) => (
+ Namespaces are enabled in Platform. +
+ Disable them{" "} + + here + {" "} + to no longer user namespaces. +
For more information about namespaces,
check the{" "} @@ -32,6 +52,29 @@ const namespaceHelpText = (
); +const namespaceHelpTextSetUp = ({ + apiUrl, + projectId, +}: { + apiUrl: string; + projectId: number; +}) => ( + +
+ Namespaces are disabled in Platform. +
+ Enable them{" "} + + here + {" "} + to use namespaces. +
+
+); export const ProjectSettings: FunctionComponent = ({ apiKey, @@ -76,6 +119,8 @@ export const ProjectSettings: FunctionComponent = ({ }, }); + const hasNamespacesEnabled = useHasNamespacesEnabled(); + const languages = languagesLoadable.data?._embedded?.languages; const namespaces = namespacesLoadable.data?._embedded?.namespaces?.map( (n) => n.name || "" @@ -87,7 +132,14 @@ export const ProjectSettings: FunctionComponent = ({ ) { namespaces.push(settings.namespace); } - const namespacesNotPresent = namespaces?.length === 1 && !namespaces[0]; + + // Sort namespaces alphabetically + namespaces.sort((a, b) => { + // Sort alphabetically, but put empty string at the end + if (!a) return 1; + if (!b) return -1; + return a.localeCompare(b); + }); useEffect(() => { if (!settings && namespacesLoadable.data && languagesLoadable.data) { @@ -95,8 +147,6 @@ export const ProjectSettings: FunctionComponent = ({ language: initialData?.language || languages?.find((l) => l.base)?.tag || "", namespace: initialData?.namespace ?? namespaces?.[0] ?? "", - namespacesDisabled: - initialData?.namespacesDisabled ?? namespacesNotPresent, }); } }, [languages, namespaces]); @@ -107,16 +157,6 @@ export const ProjectSettings: FunctionComponent = ({ } }, [settings]); - const [namespacesDisabled, setNamespacesDisabled] = useState( - initialData?.namespacesDisabled ?? true - ); - - const handleDisableNamespaces = (e: any) => { - const checked = e.currentTarget.checked; - setNamespacesDisabled(!checked); - setSettings({ ...settings!, namespacesDisabled: !checked }); - }; - if (languagesLoadable.isLoading || namespacesLoadable.isLoading) { return ; } @@ -146,17 +186,28 @@ export const ProjectSettings: FunctionComponent = ({
- + Use namespaces - {namespaceHelpText} + {hasNamespacesEnabled ? ( + + {namespaceHelpText({ + apiUrl, + projectId: getProjectIdFromApiKey(apiKey) ?? 0, + })} + + ) : ( + + {namespaceHelpTextSetUp({ + apiUrl, + projectId: getProjectIdFromApiKey(apiKey) ?? 0, + })} + + )}
- {!namespacesDisabled && ( + {hasNamespacesEnabled && ( diff --git a/src/ui/views/Settings/PushSection.tsx b/src/ui/views/Settings/PushSection.tsx index d454293..c87fa35 100644 --- a/src/ui/views/Settings/PushSection.tsx +++ b/src/ui/views/Settings/PushSection.tsx @@ -1,22 +1,8 @@ import { h, FunctionComponent, Fragment } from "preact"; -import { - useEffect, - useRef, - useState, - useLayoutEffect, - useMemo, -} from "preact/hooks"; -import { - Bold, - Checkbox, - Muted, - Text, - Textbox, - VerticalSpace, -} from "@create-figma-plugin/ui"; +import { useEffect, useState, useMemo } from "preact/hooks"; +import { Bold, Checkbox, Text, VerticalSpace } from "@create-figma-plugin/ui"; import { TolgeeConfig } from "@/types"; -import { Badge } from "../../components/Badge/Badge"; -import styles from "./Settings.css"; +import { AutocompleteSelect } from "../../components/AutocompleteSelect/AutocompleteSelect"; import { useAllTags } from "../../hooks/useAllTags"; export interface PushSectionProps { @@ -33,35 +19,15 @@ export const PushSection: FunctionComponent = ({ onTagsChange, }) => { const [tags, setTags] = useState(tolgeeConfig.tags || []); - const [tagInput, setTagInput] = useState(""); - const [showTagDropDown, setShowTagDropDown] = useState(false); - const inputRef = useRef(null); - const dropdownRef = useRef(null); - const [dropdownDirection, setDropdownDirection] = useState<"down" | "up">( - "down" - ); - useLayoutEffect(() => { - if (!showTagDropDown || !inputRef.current) return; - const inputRect = inputRef.current.getBoundingClientRect(); - const dropdownHeight = dropdownRef.current?.offsetHeight || 180; - const spaceBelow = window.innerHeight - inputRect.bottom - 49; // padding of actionbar - const spaceAbove = inputRect.top; - if (spaceBelow < dropdownHeight && spaceAbove > dropdownHeight) { - setDropdownDirection("up"); - } else { - setDropdownDirection("down"); - } - }, [tagInput, showTagDropDown]); const allTags = useAllTags(); - const filteredTags = useMemo(() => { - return allTags.tagsData.filter( - (t) => - t.name.toLowerCase().includes(tagInput.toLowerCase()) && - !tags.includes(t.name) - ); - }, [allTags.tagsData, tagInput, tags]); + // Get tag names as options + const tagOptions = useMemo(() => { + return allTags.tagsData + .map((t) => t.name) + .sort((a, b) => a.localeCompare(b)); + }, [allTags.tagsData]); useEffect(() => { allTags.getData().catch((e) => { @@ -75,17 +41,6 @@ export const PushSection: FunctionComponent = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [tags]); - const handleAddTag = () => { - const newTag = tagInput.trim(); - if (newTag && !tags.includes(newTag)) { - setTags([...tags, newTag]); - setTagInput(""); - } - }; - const handleRemoveTag = (tag: string) => { - setTags(tags.filter((t) => t !== tag)); - }; - return (
@@ -130,167 +85,16 @@ export const PushSection: FunctionComponent = ({ Tags - -
- {tags.map((tag) => ( - handleRemoveTag(tag)} - key={tag} - > - {tag} - - ))} -
- { - setShowTagDropDown(true); - }} - onBlur={() => { - setShowTagDropDown(false); - }} - onChange={(e) => setTagInput(e.currentTarget.value)} - onKeyDown={(e) => { - if (e.key === "Enter") handleAddTag(); - }} - /> - {showTagDropDown && ( -
- {filteredTags.length > 0 ? ( -
- Tags existing in project -
- ) : ( -
- No tags found -
- )} - {filteredTags.map((t) => { - const matchIndex = t.name - .toLowerCase() - .indexOf(tagInput.toLowerCase()); - const isExact = - t.name.toLowerCase() === tagInput.trim().toLowerCase(); - if (matchIndex === -1) { - return ( -
{ - setTags([...tags, t.name]); - setTagInput(""); - }} - style={{ - display: "flex", - justifyContent: "space-between", - alignItems: "center", - }} - > - {t.name} - {isExact && ( - - Enter - - )} -
- ); - } - const before = t.name.slice(0, matchIndex); - const match = t.name.slice( - matchIndex, - matchIndex + tagInput.length - ); - const after = t.name.slice(matchIndex + tagInput.length); - return ( -
{ - setTags([...tags, t.name]); - setTagInput(""); - }} - style={{ - display: "flex", - justifyContent: "space-between", - alignItems: "center", - }} - > - - {before} - {match} - {after} - - {isExact && ( - - Enter - - )} -
- ); - })} - {(() => { - const alreadyExists = - tags.includes(tagInput.trim()) || - allTags.tagsData.some( - (t) => - t.name.toLowerCase() === - tagInput.trim().toLowerCase() - ); - if (!tagInput.trim() || alreadyExists) return null; - return ( -
{ - if (!alreadyExists) handleAddTag(); - }} - style={{ - opacity: alreadyExists ? 0.5 : 1, - pointerEvents: alreadyExists ? "none" : "auto", - }} - > - - Add "{tagInput}" - - - Enter - -
- ); - })()} -
- )} -
-
+
)} diff --git a/src/ui/views/Settings/Settings.tsx b/src/ui/views/Settings/Settings.tsx index 5bae9b7..bf87e6a 100644 --- a/src/ui/views/Settings/Settings.tsx +++ b/src/ui/views/Settings/Settings.tsx @@ -12,7 +12,7 @@ import { } from "@create-figma-plugin/ui"; import { useGlobalActions, useGlobalState } from "@/ui/state/GlobalState"; -import { useApiMutation } from "@/ui/client/useQueryApi"; +import { useApiMutation, useApiQuery } from "@/ui/client/useQueryApi"; import { ActionsBottom } from "@/ui/components/ActionsBottom/ActionsBottom"; import { TopBar } from "../../components/TopBar/TopBar"; import { useQueryClient } from "react-query"; @@ -20,6 +20,7 @@ import { Expandable } from "./Expandable"; import { ProjectSection } from "./ProjectSection"; import { PushSection } from "./PushSection"; import { StringsSection } from "./StringsSection"; +import { getProjectIdFromApiKey } from "../../client/decodeApiKey"; const DEFAULT_TOLGEE_URL = "https://app.tolgee.io"; From b95adada1f2e2dfb53076c2fcd221d87ac4a6760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20H=C3=BClscher?= <25116822+eweren@users.noreply.github.com> Date: Wed, 17 Dec 2025 12:05:40 +0100 Subject: [PATCH 12/17] adjust screenshots stale update issues --- src/ui/views/Push/Push.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ui/views/Push/Push.tsx b/src/ui/views/Push/Push.tsx index d55061f..2961d8a 100644 --- a/src/ui/views/Push/Push.tsx +++ b/src/ui/views/Push/Push.tsx @@ -47,7 +47,7 @@ export const Push: FunctionalComponent = () => { const [pushedKeysCount, setPushedKeysCount] = useState(0); const selectedNodes = useConnectedNodes({ ignoreSelection: false }); const tolgeeConfig = useGlobalState((c) => c.config); - const [screenshotCount, setScreenshotCount] = useState(0); + const [uploadedScreenshotCount, setUploadedScreenshotCount] = useState(0); const nodes = selectedNodes.data?.items ?? []; @@ -252,6 +252,7 @@ export const Push: FunctionalComponent = () => { return; } + setUploadedScreenshotCount(0); setIsPushing(true); try { @@ -394,7 +395,7 @@ export const Push: FunctionalComponent = () => { }, }, }); - setScreenshotCount(screenshotCount + 1); + setUploadedScreenshotCount((c) => c + 1); } catch (e) { if (e === "too_many_uploaded_images") { setErrorMessage( @@ -477,7 +478,7 @@ export const Push: FunctionalComponent = () => {
Successfully updated {pushedKeysCount} key(s) {uploadScreenshots - ? ` and uploaded ${screenshotCount} screenshot(s).` + ? ` and uploaded ${uploadedScreenshotCount} screenshot(s).` : "."}
From 30152a114ef2cea1094da9c689582e97179da788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20H=C3=BClscher?= <25116822+eweren@users.noreply.github.com> Date: Wed, 17 Dec 2025 12:28:23 +0100 Subject: [PATCH 13/17] fix tests --- cypress/e2e/index.cy.ts | 23 ----------------------- cypress/e2e/push.cy.ts | 4 ++-- src/ui/views/Push/Push.tsx | 2 +- 3 files changed, 3 insertions(+), 26 deletions(-) diff --git a/cypress/e2e/index.cy.ts b/cypress/e2e/index.cy.ts index c0c896c..28946e3 100644 --- a/cypress/e2e/index.cy.ts +++ b/cypress/e2e/index.cy.ts @@ -29,29 +29,6 @@ describe("Index", () => { }); }); - it("hides namespace selector", () => { - const nodes = [createTestNode({ text: "Test node", key: "test_key" })]; - visitWithState({ - config: { ...SIGNED_IN }, - selectedNodes: nodes, - allNodes: nodes, - }); - - cy.iframe().contains("Test node").should("be.visible"); - - cy.iframe() - .findDcy("general_node_list_row_text") - .contains("Test node") - .should("be.visible"); - - cy.iframe() - .findDcy("general_node_list_row_key") - .find("input") - .should("have.value", "test_key"); - - cy.iframe().findDcy("general_namespace_select_input").should("not.exist"); - }); - it("shows connected node correctly", () => { const nodes = [ createTestNode({ text: "Test node", key: "test_key", connected: true }), diff --git a/cypress/e2e/push.cy.ts b/cypress/e2e/push.cy.ts index 4f84d09..57972c7 100644 --- a/cypress/e2e/push.cy.ts +++ b/cypress/e2e/push.cy.ts @@ -151,7 +151,7 @@ describe("Push", () => { it("doesn't push screenshot when disabled", () => { const nodes = [ - createTestNode({ text: "On the road", key: "on-the-road-title" }), + createTestNode({ text: "Changed text 2", key: "on-the-road-title" }), ]; visitWithState({ config: { ...SIGNED_IN, updateScreenshots: false }, @@ -161,7 +161,7 @@ describe("Push", () => { cy.frameLoaded("#plugin_iframe"); - cy.iframe().contains("On the road").should("exist"); + cy.iframe().contains("Changed text 2").should("exist"); cy.iframe().findDcy("index_push_button").should("be.visible").click(); cy.iframe().contains("No changes necessary").should("be.visible"); diff --git a/src/ui/views/Push/Push.tsx b/src/ui/views/Push/Push.tsx index 2961d8a..aa7b4de 100644 --- a/src/ui/views/Push/Push.tsx +++ b/src/ui/views/Push/Push.tsx @@ -379,7 +379,7 @@ export const Push: FunctionalComponent = () => { ); } - if (tolgeeConfig?.updateScreenshots ?? true) { + if ((tolgeeConfig?.updateScreenshots ?? true) && uploadScreenshots) { for (const screenshot of changes.screenshots.values()) { try { const relatedKeys = screenshot.keys From 39a33d2a4e70ab35fff1f557778cfd92f9a60bf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20H=C3=BClscher?= <25116822+eweren@users.noreply.github.com> Date: Fri, 2 Jan 2026 18:00:12 +0100 Subject: [PATCH 14/17] implement quality suggestions from coderabbit --- src/ui/client/client.ts | 2 +- src/ui/hooks/useHasNamespacesEnabled.ts | 53 +++++++++++-------------- src/ui/views/Push/Push.tsx | 1 + src/ui/views/Settings/Settings.tsx | 3 +- 4 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/ui/client/client.ts b/src/ui/client/client.ts index 4fd274e..c6d3257 100644 --- a/src/ui/client/client.ts +++ b/src/ui/client/client.ts @@ -139,10 +139,10 @@ export async function client< const projectId = getProjectIdFromApiKey(fetchOptions.apiKey); if (projectId !== undefined) { - pathParams.projectId = projectId; if (pathParams.projectId === undefined) { urlResult = addProjectIdToUrl(urlResult); } + pathParams.projectId = projectId; } if (pathParams) { diff --git a/src/ui/hooks/useHasNamespacesEnabled.ts b/src/ui/hooks/useHasNamespacesEnabled.ts index 1fdd001..c99e89b 100644 --- a/src/ui/hooks/useHasNamespacesEnabled.ts +++ b/src/ui/hooks/useHasNamespacesEnabled.ts @@ -1,35 +1,30 @@ import { useApiQuery } from "../client/useQueryApi"; export const useHasNamespacesEnabled = () => { - try { - // First, get the project ID from the API key info (relevant for legacy api keys) - const apiKeyInfo = useApiQuery({ - url: "/v2/api-keys/current", - method: "get", - options: { - cacheTime: 60000, - staleTime: 60000, - }, - }); + // First, get the project ID from the API key info (relevant for legacy api keys) + const apiKeyInfo = useApiQuery({ + url: "/v2/api-keys/current", + method: "get", + options: { + cacheTime: 60000, + staleTime: 60000, + }, + }); - // Then get the project info if we have a project ID - // eslint-disable-next-line react-hooks/rules-of-hooks - const projectQuery = useApiQuery({ - url: "/v2/projects/{projectId}", - method: "get", - path: { - projectId: apiKeyInfo.data?.projectId ?? 0, - }, - options: { - cacheTime: 60000, - staleTime: 60000, - enabled: apiKeyInfo.data?.projectId !== undefined, - }, - }); + // Then get the project info if we have a project ID + // eslint-disable-next-line react-hooks/rules-of-hooks + const projectQuery = useApiQuery({ + url: "/v2/projects/{projectId}", + method: "get", + path: { + projectId: apiKeyInfo.data?.projectId ?? 0, + }, + options: { + cacheTime: 60000, + staleTime: 60000, + enabled: apiKeyInfo.data?.projectId !== undefined, + }, + }); - return projectQuery.data?.useNamespaces ?? false; - } catch (error) { - console.error(error); - return false; - } + return projectQuery.data?.useNamespaces ?? false; }; diff --git a/src/ui/views/Push/Push.tsx b/src/ui/views/Push/Push.tsx index aa7b4de..ba21275 100644 --- a/src/ui/views/Push/Push.tsx +++ b/src/ui/views/Push/Push.tsx @@ -444,6 +444,7 @@ export const Push: FunctionalComponent = () => { setError(false); setSuccess(false); setPushedKeysCount(0); + setUploadedScreenshotCount(0); setErrorMessage(undefined); }; diff --git a/src/ui/views/Settings/Settings.tsx b/src/ui/views/Settings/Settings.tsx index bf87e6a..5bae9b7 100644 --- a/src/ui/views/Settings/Settings.tsx +++ b/src/ui/views/Settings/Settings.tsx @@ -12,7 +12,7 @@ import { } from "@create-figma-plugin/ui"; import { useGlobalActions, useGlobalState } from "@/ui/state/GlobalState"; -import { useApiMutation, useApiQuery } from "@/ui/client/useQueryApi"; +import { useApiMutation } from "@/ui/client/useQueryApi"; import { ActionsBottom } from "@/ui/components/ActionsBottom/ActionsBottom"; import { TopBar } from "../../components/TopBar/TopBar"; import { useQueryClient } from "react-query"; @@ -20,7 +20,6 @@ import { Expandable } from "./Expandable"; import { ProjectSection } from "./ProjectSection"; import { PushSection } from "./PushSection"; import { StringsSection } from "./StringsSection"; -import { getProjectIdFromApiKey } from "../../client/decodeApiKey"; const DEFAULT_TOLGEE_URL = "https://app.tolgee.io"; From 19a4d97971164c60cbc7962d55a0faf2e7e5d826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20H=C3=BClscher?= <25116822+eweren@users.noreply.github.com> Date: Mon, 19 Jan 2026 12:26:40 +0100 Subject: [PATCH 15/17] implement debounced key updates in ListItem and adjust row height in Changes component --- src/ui/views/Index/ListItem.tsx | 20 ++++++++++++++------ src/ui/views/Push/Changes.tsx | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/ui/views/Index/ListItem.tsx b/src/ui/views/Index/ListItem.tsx index 7e69ca9..08cfd57 100644 --- a/src/ui/views/Index/ListItem.tsx +++ b/src/ui/views/Index/ListItem.tsx @@ -1,5 +1,6 @@ import { h } from "preact"; import { useEffect, useMemo, useState } from "preact/hooks"; +import { useDebounce } from "use-debounce"; import { NodeInfo } from "@/types"; import { NodeRow } from "@/ui/components/NodeList/NodeRow"; import { KeyInput } from "./KeyInput"; @@ -37,6 +38,7 @@ export const ListItem = ({ ); const [keyName, setKeyName] = useState((node.key || prefilledKey.key) ?? ""); + const [debouncedKeyName] = useDebounce(keyName, 300); const defaultNamespace = useGlobalState((c) => c.config?.namespace); const [namespace, setNamespace] = useState(node.ns ?? defaultNamespace); @@ -47,10 +49,19 @@ export const ListItem = ({ useEffect(() => { if (prefilledKey.key && !node.connected) { - handleKeyChange(node)(prefilledKey.key); + setKeyName(prefilledKey.key); } }, [prefilledKey.key]); + // Debounced mutation: only update Figma nodes after user stops typing + useEffect(() => { + if (debouncedKeyName !== (node.key || "")) { + setNodesDataMutation.mutate({ + nodes: [{ ...node, key: debouncedKeyName, ns: namespace }], + }); + } + }, [debouncedKeyName, namespace, node]); + const handleConnect = (node: NodeInfo) => { setRoute("connect", { node }); }; @@ -66,11 +77,8 @@ export const ListItem = ({ [loadedNamespaces, defaultNamespace] ); - const handleKeyChange = (node: NodeInfo) => (value: string) => { + const handleKeyChange = () => (value: string) => { setKeyName(value); - setNodesDataMutation.mutate({ - nodes: [{ ...node, key: value, ns: namespace }], - }); }; useEffect(() => { @@ -95,7 +103,7 @@ export const ListItem = ({ node={node} keyComponent={ !node.connected && ( - + ) } nsComponent={ diff --git a/src/ui/views/Push/Changes.tsx b/src/ui/views/Push/Changes.tsx index 05c910f..3df9689 100644 --- a/src/ui/views/Push/Changes.tsx +++ b/src/ui/views/Push/Changes.tsx @@ -25,7 +25,7 @@ export const Changes = ({ changes }: Props) => { data-cy="changes_new_keys" > ({ id: k.key, key: k.key, From b0287649660bee202710bb41c2eed0c6ef103819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20H=C3=BClscher?= <25116822+eweren@users.noreply.github.com> Date: Mon, 19 Jan 2026 14:40:48 +0100 Subject: [PATCH 16/17] address unstable allTranslationsLoadable dependency --- src/ui/hooks/useAllTranslations.ts | 80 ++++++++++++++++++------------ src/ui/views/Push/Push.tsx | 3 +- 2 files changed, 51 insertions(+), 32 deletions(-) diff --git a/src/ui/hooks/useAllTranslations.ts b/src/ui/hooks/useAllTranslations.ts index 9ed9390..6b9e9f4 100644 --- a/src/ui/hooks/useAllTranslations.ts +++ b/src/ui/hooks/useAllTranslations.ts @@ -1,4 +1,4 @@ -import { useState } from "preact/hooks"; +import { useState, useCallback, useRef, useEffect } from "preact/hooks"; import { useApiMutation } from "../client/useQueryApi"; import { components } from "../client/apiSchema.generated"; import { TranslationData } from "../client/types"; @@ -28,12 +28,25 @@ export const useAllTranslations = () => { const [translationsData, setTranslationsData] = useState(null); + const [isLoading, setIsLoading] = useState(false); + + // Use refs to store the latest mutation functions to avoid dependency issues + const namespacesLoadableRef = useRef(namespacesLoadable); + const translationsBaseLoadableRef = useRef(translationsBaseLoadable); + const notifierRef = useRef(notifier); + + useEffect(() => { + namespacesLoadableRef.current = namespacesLoadable; + translationsBaseLoadableRef.current = translationsBaseLoadable; + notifierRef.current = notifier; + }, [namespacesLoadable, translationsBaseLoadable, notifier]); + async function loadData({ language, namespaces }: Props) { const nsNames = namespaces ?? - (await namespacesLoadable.mutateAsync({}))._embedded?.namespaces?.map( - (n) => n.name ?? "" - ) ?? + ( + await namespacesLoadableRef.current.mutateAsync({}) + )._embedded?.namespaces?.map((n) => n.name ?? "") ?? []; // Ensure empty string is included if namespaces is provided and contains empty string @@ -52,14 +65,15 @@ export const useAllTranslations = () => { []; do { - const batchOfTranslations = await translationsBaseLoadable.mutateAsync({ - query: { - filterNamespace: [ns], - languages: [language], - size: 1000, - cursor, - }, - }); + const batchOfTranslations = + await translationsBaseLoadableRef.current.mutateAsync({ + query: { + filterNamespace: [ns], + languages: [language], + size: 1000, + cursor, + }, + }); translationsData.push(...(batchOfTranslations._embedded?.keys ?? [])); cursor = batchOfTranslations.nextCursor; @@ -81,28 +95,32 @@ export const useAllTranslations = () => { return data; } - const [isLoading, setIsLoading] = useState(false); + const getData = useCallback(async (props: Props) => { + setIsLoading(true); + try { + return await loadData(props); + } catch (e) { + if (e === "invalid_project_api_key") { + notifierRef.current.mutate("Invalid project API key"); + } + + throw e; + } finally { + setIsLoading(false); + } + }, []); // Empty deps - we use refs for the mutation objects + + const clearCache = useCallback(() => { + setTranslationsData(null); + }, []); + + const error = namespacesLoadable.error || translationsLoadable.error; return { - async getData(props: Props) { - setIsLoading(true); - try { - return await loadData(props); - } catch (e) { - if (e === "invalid_project_api_key") { - notifier.mutate("Invalid project API key"); - } - - throw e; - } finally { - setIsLoading(false); - } - }, - clearCache() { - setTranslationsData(null); - }, + getData, + clearCache, translationsData, isLoading, - error: namespacesLoadable.error || translationsLoadable.error, + error, }; }; diff --git a/src/ui/views/Push/Push.tsx b/src/ui/views/Push/Push.tsx index ba21275..dd014ce 100644 --- a/src/ui/views/Push/Push.tsx +++ b/src/ui/views/Push/Push.tsx @@ -146,7 +146,6 @@ export const Push: FunctionalComponent = () => { // Reconstruct tolgeeConfig object for getPushChanges const configForDiff = { ...tolgeeConfig, - tags: tolgeeConfig?.tags, updateScreenshots: tolgeeConfigUpdateScreenshots, addTags: tolgeeConfigAddTags, }; @@ -190,6 +189,8 @@ export const Push: FunctionalComponent = () => { tolgeeConfigUpdateScreenshots, tolgeeConfigAddTags, success, // Include success to prevent recompute when showing success screen + // Note: allTranslationsLoadable.getData is stable via useCallback with refs + // We don't include allTranslationsLoadable itself to avoid infinite loops ]); const totalScreenshotCount = useMemo(() => { From 8849a3dab62ecc0ef1b6f75f1376df859f58579c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20H=C3=BClscher?= <25116822+eweren@users.noreply.github.com> Date: Mon, 19 Jan 2026 14:46:47 +0100 Subject: [PATCH 17/17] remove unused code --- src/ui/hooks/useAllTranslations.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/ui/hooks/useAllTranslations.ts b/src/ui/hooks/useAllTranslations.ts index 6b9e9f4..8979dfd 100644 --- a/src/ui/hooks/useAllTranslations.ts +++ b/src/ui/hooks/useAllTranslations.ts @@ -14,10 +14,6 @@ export const useAllTranslations = () => { url: "/v2/projects/used-namespaces", method: "get", }); - const translationsLoadable = useApiMutation({ - url: "/v2/projects/translations/{languages}", - method: "get", - }); const translationsBaseLoadable = useApiMutation({ url: "/v2/projects/translations", method: "get", @@ -114,7 +110,7 @@ export const useAllTranslations = () => { setTranslationsData(null); }, []); - const error = namespacesLoadable.error || translationsLoadable.error; + const error = namespacesLoadable.error || translationsBaseLoadable.error; return { getData,