From 1a590692a2d7a21bc642b5645a096ef54388628d Mon Sep 17 00:00:00 2001 From: Denis Nikiforov Date: Thu, 16 May 2024 00:34:18 +0500 Subject: [PATCH] [1028] Add i18n support for frontend Bug: https://github.com/eclipse-sirius/sirius-web/issues/1028 Signed-off-by: Denis Nikiforov --- CHANGELOG.adoc | 1 + .../cypress/e2e/project/portals/portals.cy.ts | 2 +- package-lock.json | 129 ++++++++++++- .../sirius-components-core/package.json | 2 + .../sirius-components-core/src/index.ts | 2 + .../src/locales/en.json | 14 ++ .../src/locales/ru.json | 14 ++ .../ShareRepresentationModal.tsx | 7 +- .../sirius-components-diagrams/package.json | 2 + .../sirius-components-diagrams/src/index.ts | 2 + .../src/locales/en.json | 47 +++++ .../src/locales/ru.json | 47 +++++ .../src/renderer/delete/useDiagramDelete.tsx | 6 +- .../direct-edit/DiagramDirectEditInput.tsx | 13 +- .../src/renderer/drop/useDrop.tsx | 6 +- .../src/renderer/dropNode/useDropNode.ts | 6 +- .../renderer/fade/useFadeDiagramElements.tsx | 6 +- .../renderer/hide/useHideDiagramElements.tsx | 6 +- .../layout/useSynchronizeLayoutData.ts | 6 +- .../src/renderer/palette/Palette.tsx | 24 +-- .../palette/group-tool/GroupPalette.tsx | 38 ++-- .../src/renderer/panel/DiagramPanel.tsx | 63 +++---- .../renderer/pin/usePinDiagramElements.tsx | 6 +- .../reconnect-edge/useReconnectEdge.tsx | 6 +- .../package.json | 2 + .../src/SelectWidget.tsx | 10 +- .../src/index.ts | 4 +- .../src/locales/en.json | 5 + .../src/locales/ru.json | 5 + .../sirius-components-forms/package.json | 2 + .../sirius-components-forms/src/index.ts | 2 + .../src/locales/en.json | 6 + .../src/locales/ru.json | 6 + .../ButtonPropertySection.tsx | 6 +- .../CheckboxPropertySection.tsx | 6 +- .../propertysections/ListPropertySection.tsx | 13 +- .../MultiSelectPropertySection.tsx | 10 +- .../propertysections/RadioPropertySection.tsx | 6 +- .../RichTextPropertySection.tsx | 10 +- .../SelectPropertySection.tsx | 13 +- .../SliderPropertySection.tsx | 11 +- .../SplitButtonPropertySection.tsx | 6 +- .../TextfieldPropertySection.tsx | 10 +- .../propertysections/TreePropertySection.tsx | 14 +- .../src/toolbaraction/ToolbarAction.tsx | 12 +- .../src/views/FormBasedView.tsx | 4 +- .../sirius-components-forms/vitestSetup.js | 15 +- .../package.json | 2 + .../src/ReferencePropertySection.tsx | 22 +-- .../src/components/FilterableSortableList.tsx | 4 +- .../src/components/ModelBrowserFilterBar.tsx | 6 +- .../ValuedReferenceAutocomplete.tsx | 19 +- .../src/index.ts | 4 +- .../src/locales/en.json | 40 +++++ .../src/locales/ru.json | 40 +++++ .../src/modals/BrowseModal.tsx | 10 +- .../src/modals/CreateModal.tsx | 29 +-- .../src/modals/TransferModal.tsx | 15 +- .../sirius-web-application/package.json | 2 + .../src/core/file-upload/FileUpload.tsx | 19 +- .../sirius-web-application/src/index.ts | 2 + .../src/locales/en.json | 170 ++++++++++++++++++ .../src/locales/ru.json | 170 ++++++++++++++++++ .../delete-project/DeleteProjectModal.tsx | 12 +- .../modals/delete-project/useDeleteProject.ts | 7 +- .../modals/new-document/NewDocumentModal.tsx | 14 +- .../modals/new-document/useCreateDocument.ts | 7 +- .../src/modals/new-object/NewObjectModal.tsx | 25 ++- .../NewRepresentationModal.tsx | 30 ++-- .../NewRepresentationModalMachine.ts | 2 - .../new-root-object/NewRootObjectModal.tsx | 27 +-- .../rename-project/RenameProjectModal.tsx | 13 +- .../modals/rename-project/useRenameProject.ts | 7 +- .../upload-document/UploadDocumentModal.tsx | 8 +- .../src/navigationBar/NavigationBar.tsx | 4 +- .../src/onboarding/NewDocumentArea.tsx | 11 +- .../src/onboarding/NewRepresentationArea.tsx | 15 +- .../src/onboarding/RepresentationsArea.tsx | 6 +- ...ocumentTreeItemContextMenuContribution.tsx | 8 +- .../EditProjectNavbar/EditProjectNavbar.tsx | 10 +- .../views/edit-project/EditProjectView.tsx | 6 +- .../ObjectTreeItemContextMenuContribution.tsx | 8 +- .../NewDocumentModalContribution.tsx | 9 +- .../UploadDocumentModalContribution.tsx | 7 +- .../src/views/new-project/NewProjectView.tsx | 23 +-- .../new-project/NewProjectViewMachine.ts | 4 +- .../CreateProjectArea.tsx | 4 +- .../ProjectTemplateCard.tsx | 16 +- .../ProjectTemplatesModal.tsx | 7 +- .../useCreateProjectFromTemplate.ts | 7 +- .../list-projects-area/ListProjectsArea.tsx | 7 +- .../ProjectActionButton.tsx | 13 +- .../list-projects-area/ProjectsTable.tsx | 4 +- .../project-settings/images/ImageRow.tsx | 4 +- .../project-settings/images/ImageTable.tsx | 8 +- .../images/ProjectImagesSettings.tsx | 8 +- .../images/delete-image/DeleteImageModal.tsx | 11 +- .../images/rename-image/RenameImageModal.tsx | 15 +- .../rename-image/RenameImageModalMachine.ts | 2 - .../images/upload-image/UploadImageModal.tsx | 10 +- .../upload-project/UploadProjectView.tsx | 15 +- .../frontend/sirius-web/package.json | 1 + .../frontend/sirius-web/src/i18n.ts | 62 +++++++ .../frontend/sirius-web/src/index.tsx | 1 + .../sirius-components-trees/package.json | 2 + .../sirius-components-trees/src/index.ts | 4 +- .../src/locales/en.json | 11 ++ .../src/locales/ru.json | 11 ++ .../src/toolbar/TreeToolBar.tsx | 6 +- .../src/treeitems/TreeItemContextMenu.tsx | 9 +- .../src/treeitems/TreeItemDirectEditInput.tsx | 13 +- .../src/views/TreeFiltersMenu.tsx | 4 +- .../sirius-components-validation/package.json | 2 + .../src/ValidationView.tsx | 10 +- .../sirius-components-validation/src/index.ts | 4 +- .../src/locales/en.json | 7 + .../src/locales/ru.json | 8 + 117 files changed, 1376 insertions(+), 360 deletions(-) create mode 100644 packages/core/frontend/sirius-components-core/src/locales/en.json create mode 100644 packages/core/frontend/sirius-components-core/src/locales/ru.json create mode 100644 packages/diagrams/frontend/sirius-components-diagrams/src/locales/en.json create mode 100644 packages/diagrams/frontend/sirius-components-diagrams/src/locales/ru.json create mode 100644 packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/locales/en.json create mode 100644 packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/locales/ru.json create mode 100644 packages/forms/frontend/sirius-components-forms/src/locales/en.json create mode 100644 packages/forms/frontend/sirius-components-forms/src/locales/ru.json create mode 100644 packages/forms/frontend/sirius-components-widget-reference/src/locales/en.json create mode 100644 packages/forms/frontend/sirius-components-widget-reference/src/locales/ru.json create mode 100644 packages/sirius-web/frontend/sirius-web-application/src/locales/en.json create mode 100644 packages/sirius-web/frontend/sirius-web-application/src/locales/ru.json create mode 100644 packages/sirius-web/frontend/sirius-web/src/i18n.ts create mode 100644 packages/trees/frontend/sirius-components-trees/src/locales/en.json create mode 100644 packages/trees/frontend/sirius-components-trees/src/locales/ru.json create mode 100644 packages/validation/frontend/sirius-components-validation/src/locales/en.json create mode 100644 packages/validation/frontend/sirius-components-validation/src/locales/ru.json diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 996c847360..5d3be094a1 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -65,6 +65,7 @@ More existing APIs will be migrated to this new common pattern. - https://github.com/eclipse-sirius/sirius-web/issues/3563[#3563] [sirius-web] Improve NavigationBar extensibility to allow the contribution of components on the left and right of the navigation bar. - https://github.com/eclipse-sirius/sirius-web/issues/3344[#3344] [core] Add support for reloading representations from the database - https://github.com/eclipse-sirius/sirius-web/issues/3553[#3553] [core] Add RepresentationFactory extension point +- https://github.com/eclipse-sirius/sirius-web/issues/1028[#1028] [core] Add i18n support for frontend === Improvements diff --git a/integration-tests/cypress/e2e/project/portals/portals.cy.ts b/integration-tests/cypress/e2e/project/portals/portals.cy.ts index 941ef16750..8b69645fbd 100644 --- a/integration-tests/cypress/e2e/project/portals/portals.cy.ts +++ b/integration-tests/cypress/e2e/project/portals/portals.cy.ts @@ -221,7 +221,7 @@ describe('/projects/:projectId/edit - Portal', () => { portal.addRepresentationFromExplorer('Portal', diagramTitle); // Open the diagram's share modal from inside the portal and compare explorer.getTreeItemByLabel('Portal').click(); - new Diagram().getDiagram(diagramTitle).find('[aria-label="share diagram"]').click(); + new Diagram().getDiagram(diagramTitle).find('[data-testid="share"]').click(); cy.window().then((win) => { win.navigator.clipboard.readText().then((text) => { expect(text).to.eq(diagramURL); diff --git a/package-lock.json b/package-lock.json index 4c01da00f3..df07179d5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -416,9 +416,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz", - "integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz", + "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -4179,6 +4179,14 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "dependencies": { + "void-elements": "3.1.0" + } + }, "node_modules/html-to-image": { "version": "1.11.11", "resolved": "https://registry.npmjs.org/html-to-image/-/html-to-image-1.11.11.tgz", @@ -4225,6 +4233,29 @@ "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" }, + "node_modules/i18next": { + "version": "23.11.4", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.11.4.tgz", + "integrity": "sha512-CCUjtd5TfaCl+mLUzAA0uPSN+AVn4fP/kWCYt/hocPUwusTpMVczdrRyOBUwk6N05iH40qiKx6q1DoNJtBIwdg==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "peer": true, + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -5517,6 +5548,27 @@ "node": ">=6" } }, + "node_modules/react-i18next": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.1.1.tgz", + "integrity": "sha512-QSiKw+ihzJ/CIeIYWrarCmXJUySHDwQr5y8uaNIkbxoGRm/5DukkxZs+RPla79IKyyDPzC/DRlgQCABHtrQuQQ==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -6611,6 +6663,14 @@ "node": ">=0.4.0" } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -7448,6 +7508,7 @@ "jsdom": "16.7.0", "prettier": "2.7.1", "react": "17.0.2", + "react-i18next": "14.1.1", "rollup-plugin-peer-deps-external": "2.2.4", "typescript": "5.4.5", "vite": "5.2.11", @@ -7461,6 +7522,7 @@ "@xstate/react": "1.6.3", "graphql": "16.8.1", "react": "17.0.2", + "react-i18next": "14.1.1", "xstate": "4.32.1" } }, @@ -9340,6 +9402,7 @@ "prettier": "2.7.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "reactflow": "11.10.1", "rollup-plugin-peer-deps-external": "2.2.4", "typescript": "5.4.5", @@ -9356,6 +9419,7 @@ "html-to-image": "1.11.11", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "reactflow": "11.10.1" } }, @@ -10351,6 +10415,7 @@ "graphql": "16.8.1", "prettier": "2.7.1", "react": "17.0.2", + "react-i18next": "14.1.1", "rollup-plugin-peer-deps-external": "2.2.4", "typescript": "5.4.5", "vite": "5.2.11", @@ -10368,6 +10433,7 @@ "graphql": "16.8.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "xstate": "4.32.1" } }, @@ -11326,6 +11392,7 @@ "prettier": "2.7.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "rollup-plugin-peer-deps-external": "2.2.4", "typescript": "5.4.5", "vite": "5.2.11", @@ -11346,6 +11413,7 @@ "lexical": "0.8.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "xstate": "4.32.1" } }, @@ -12305,6 +12373,7 @@ "prettier": "2.7.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "rollup-plugin-peer-deps-external": "2.2.4", "typescript": "5.4.5", "vite": "5.2.11", @@ -12326,6 +12395,7 @@ "lexical": "0.8.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "xstate": "4.32.1" } }, @@ -15898,6 +15968,7 @@ "prop-types": "15.8.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "react-router-dom": "5.2.0", "reactflow": "11.10.1", "subscriptions-transport-ws": "0.11.0", @@ -15944,6 +16015,7 @@ "prettier": "2.7.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "react-router-dom": "5.2.0", "rollup-plugin-peer-deps-external": "2.2.4", "typescript": "5.4.5", @@ -15971,6 +16043,7 @@ "notistack": "3.0.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "react-router-dom": "5.2.0", "reactflow": "11.10.1", "xstate": "4.32.1" @@ -18230,6 +18303,7 @@ "jsdom": "16.7.0", "prettier": "2.7.1", "react": "17.0.2", + "react-i18next": "14.1.1", "rollup-plugin-peer-deps-external": "2.2.4", "typescript": "5.4.5", "vite": "5.2.11", @@ -18244,6 +18318,7 @@ "@xstate/react": "1.6.3", "graphql": "16.8.1", "react": "17.0.2", + "react-i18next": "14.1.1", "xstate": "4.32.1" } }, @@ -19192,6 +19267,7 @@ "graphql": "16.8.1", "prettier": "2.7.1", "react": "17.0.2", + "react-i18next": "14.1.1", "rollup-plugin-peer-deps-external": "2.2.4", "typescript": "5.4.5", "vite": "5.2.11", @@ -19205,6 +19281,7 @@ "@xstate/react": "1.6.3", "graphql": "16.8.1", "react": "17.0.2", + "react-i18next": "14.1.1", "xstate": "4.32.1" } }, @@ -20118,9 +20195,9 @@ } }, "@babel/runtime": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz", - "integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz", + "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==", "requires": { "regenerator-runtime": "^0.14.0" } @@ -20450,6 +20527,7 @@ "jsdom": "16.7.0", "prettier": "2.7.1", "react": "17.0.2", + "react-i18next": "14.1.1", "rollup-plugin-peer-deps-external": "2.2.4", "typescript": "5.4.5", "vite": "5.2.11", @@ -21516,6 +21594,7 @@ "prettier": "2.7.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "reactflow": "11.10.1", "rollup-plugin-peer-deps-external": "2.2.4", "typescript": "5.4.5", @@ -22066,6 +22145,7 @@ "graphql": "16.8.1", "prettier": "2.7.1", "react": "17.0.2", + "react-i18next": "14.1.1", "rollup-plugin-peer-deps-external": "2.2.4", "typescript": "5.4.5", "vite": "5.2.11", @@ -22621,6 +22701,7 @@ "prettier": "2.7.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "rollup-plugin-peer-deps-external": "2.2.4", "typescript": "5.4.5", "vite": "5.2.11", @@ -24834,6 +24915,7 @@ "jsdom": "16.7.0", "prettier": "2.7.1", "react": "17.0.2", + "react-i18next": "14.1.1", "rollup-plugin-peer-deps-external": "2.2.4", "typescript": "5.4.5", "vite": "5.2.11", @@ -25382,6 +25464,7 @@ "graphql": "16.8.1", "prettier": "2.7.1", "react": "17.0.2", + "react-i18next": "14.1.1", "rollup-plugin-peer-deps-external": "2.2.4", "typescript": "5.4.5", "vite": "5.2.11", @@ -25732,6 +25815,7 @@ "prettier": "2.7.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "rollup-plugin-peer-deps-external": "2.2.4", "typescript": "5.4.5", "vite": "5.2.11", @@ -26339,6 +26423,7 @@ "prop-types": "15.8.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "react-router-dom": "5.2.0", "reactflow": "11.10.1", "subscriptions-transport-ws": "0.11.0", @@ -26995,6 +27080,7 @@ "prettier": "2.7.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "react-router-dom": "5.2.0", "rollup-plugin-peer-deps-external": "2.2.4", "typescript": "5.4.5", @@ -29932,6 +30018,14 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "requires": { + "void-elements": "3.1.0" + } + }, "html-to-image": { "version": "1.11.11", "resolved": "https://registry.npmjs.org/html-to-image/-/html-to-image-1.11.11.tgz", @@ -29969,6 +30063,15 @@ "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" }, + "i18next": { + "version": "23.11.4", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.11.4.tgz", + "integrity": "sha512-CCUjtd5TfaCl+mLUzAA0uPSN+AVn4fP/kWCYt/hocPUwusTpMVczdrRyOBUwk6N05iH40qiKx6q1DoNJtBIwdg==", + "peer": true, + "requires": { + "@babel/runtime": "^7.23.2" + } + }, "iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -30929,6 +31032,15 @@ } } }, + "react-i18next": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.1.1.tgz", + "integrity": "sha512-QSiKw+ihzJ/CIeIYWrarCmXJUySHDwQr5y8uaNIkbxoGRm/5DukkxZs+RPla79IKyyDPzC/DRlgQCABHtrQuQQ==", + "requires": { + "@babel/runtime": "^7.23.9", + "html-parse-stringify": "^3.0.1" + } + }, "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -31698,6 +31810,11 @@ } } }, + "void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==" + }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", diff --git a/packages/core/frontend/sirius-components-core/package.json b/packages/core/frontend/sirius-components-core/package.json index 4939d91467..23d3fd8f95 100644 --- a/packages/core/frontend/sirius-components-core/package.json +++ b/packages/core/frontend/sirius-components-core/package.json @@ -38,6 +38,7 @@ "@xstate/react": "1.6.3", "graphql": "16.8.1", "react": "17.0.2", + "react-i18next": "14.1.1", "xstate": "4.32.1" }, "devDependencies": { @@ -53,6 +54,7 @@ "graphql": "16.8.1", "prettier": "2.7.1", "react": "17.0.2", + "react-i18next": "14.1.1", "rollup-plugin-peer-deps-external": "2.2.4", "xstate": "4.32.1", "typescript": "5.4.5", diff --git a/packages/core/frontend/sirius-components-core/src/index.ts b/packages/core/frontend/sirius-components-core/src/index.ts index 12eda8e831..773cf9ff5c 100644 --- a/packages/core/frontend/sirius-components-core/src/index.ts +++ b/packages/core/frontend/sirius-components-core/src/index.ts @@ -33,6 +33,8 @@ export { useComponents } from './extension/useComponents'; export { useData } from './extension/useData'; export * from './graphql/GQLTypes.types'; export * from './icon/IconOverlay'; +export { default as siriusComponentsCoreEn } from './locales/en.json'; +export { default as siriusComponentsCoreRu } from './locales/ru.json'; export * from './materialui'; export * from './modals/confirmation/ConfirmationDialogContext'; export * from './modals/confirmation/ConfirmationDialogContext.types'; diff --git a/packages/core/frontend/sirius-components-core/src/locales/en.json b/packages/core/frontend/sirius-components-core/src/locales/en.json new file mode 100644 index 0000000000..ff44a591d2 --- /dev/null +++ b/packages/core/frontend/sirius-components-core/src/locales/en.json @@ -0,0 +1,14 @@ +{ + "siriusComponentsCore": { + "messages": { + "loading": "Loading..." + }, + "errors": { + "unexpected": "An unexpected error has occurred, please refresh the page" + }, + "share": { + "link": "Shareable link", + "copied": "(copied into the clipboard)" + } + } +} diff --git a/packages/core/frontend/sirius-components-core/src/locales/ru.json b/packages/core/frontend/sirius-components-core/src/locales/ru.json new file mode 100644 index 0000000000..95dfe80f07 --- /dev/null +++ b/packages/core/frontend/sirius-components-core/src/locales/ru.json @@ -0,0 +1,14 @@ +{ + "siriusComponentsCore": { + "messages": { + "loading": "Загрузка..." + }, + "errors": { + "unexpected": "Произошла неожиданная ошибка, пожалуйста, обновите страницу" + }, + "share": { + "link": "Ссылка", + "copied": "(скопирована в буфер обмена)" + } + } +} diff --git a/packages/core/frontend/sirius-components-core/src/modals/share-representation/ShareRepresentationModal.tsx b/packages/core/frontend/sirius-components-core/src/modals/share-representation/ShareRepresentationModal.tsx index 5b2a304924..2342207f58 100644 --- a/packages/core/frontend/sirius-components-core/src/modals/share-representation/ShareRepresentationModal.tsx +++ b/packages/core/frontend/sirius-components-core/src/modals/share-representation/ShareRepresentationModal.tsx @@ -16,6 +16,7 @@ import DialogContent from '@material-ui/core/DialogContent'; import DialogContentText from '@material-ui/core/DialogContentText'; import DialogTitle from '@material-ui/core/DialogTitle'; import { useContext } from 'react'; +import { useTranslation } from 'react-i18next'; import { RepresentationPathContext } from '../../contexts/RepresentationPathContext'; import { RepresentationPathContextValue } from '../../contexts/RepresentationPathContext.types'; import { ShareRepresentationModalProps } from './ShareRepresentationModal.types'; @@ -25,6 +26,8 @@ export const ShareRepresentationModal = ({ representationId, onClose, }: ShareRepresentationModalProps) => { + const { t } = useTranslation('siriusComponentsCore', { keyPrefix: 'share' }); + const refCallback = (node: HTMLElement) => { if (node !== null) { var range = document.createRange(); @@ -40,10 +43,10 @@ export const ShareRepresentationModal = ({ const { getRepresentationPath } = useContext(RepresentationPathContext); const path: string = window.location.origin + getRepresentationPath(editingContextId, representationId); - let title = 'Shareable link'; + let title = t('link'); if (navigator.clipboard && document.hasFocus()) { navigator.clipboard.writeText(path); - title += ' (copied into the clipboard)'; + title += ' ' + t('copied'); } return ( diff --git a/packages/diagrams/frontend/sirius-components-diagrams/package.json b/packages/diagrams/frontend/sirius-components-diagrams/package.json index b560757dd0..187dcbd411 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/package.json +++ b/packages/diagrams/frontend/sirius-components-diagrams/package.json @@ -39,6 +39,7 @@ "html-to-image": "1.11.11", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "reactflow": "11.10.1" }, "devDependencies": { @@ -59,6 +60,7 @@ "prettier": "2.7.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "reactflow": "11.10.1", "rollup-plugin-peer-deps-external": "2.2.4", "typescript": "5.4.5", diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/index.ts b/packages/diagrams/frontend/sirius-components-diagrams/src/index.ts index a1a58ad62c..5cb0c79741 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/index.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/index.ts @@ -25,6 +25,8 @@ export type { GQLDiagram, GQLNodeLayoutData } from './graphql/subscription/diagr export type { GQLEdge } from './graphql/subscription/edgeFragment.types'; export { GQLViewModifier } from './graphql/subscription/nodeFragment.types'; export type { GQLNode, GQLNodeStyle, GraphQLNodeStyleFragment } from './graphql/subscription/nodeFragment.types'; +export { default as siriusComponentsDiagramsEn } from './locales/en.json'; +export { default as siriusComponentsDiagramsRu } from './locales/ru.json'; export { BorderNodePosition as BorderNodePosition } from './renderer/DiagramRenderer.types'; export type { Diagram, NodeData } from './renderer/DiagramRenderer.types'; export { Label } from './renderer/Label'; diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/locales/en.json b/packages/diagrams/frontend/sirius-components-diagrams/src/locales/en.json new file mode 100644 index 0000000000..9d69a28d87 --- /dev/null +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/locales/en.json @@ -0,0 +1,47 @@ +{ + "siriusComponentsDiagrams": { + "edit": { + "enterNewValue": "Enter the new value" + }, + "panel": { + "exitFullScreen": "Exit full screen mode", + "toggleFullScreen": "Toggle full screen mode", + "fitToScreen": "Fit to screen", + "zoomIn": "Zoom in", + "zoomOut": "Zoom out", + "shareDiagram": "Share diagram", + "exportToSvg": "Export to SVG", + "exitSnapToGrid": "Exit snap to grid mode", + "toggleSnapToGrid": "Toggle snap to grid mode", + "hideHelperLines": "Hide helper lines", + "showHelperLines": "Show helper lines", + "arrangeAll": "Arrange all elements", + "revealHidden": "Reveal hidden elements", + "revealFaded": "Reveal faded elements", + "unpinAll": "Unpin all elements" + }, + "palette": { + "unpin": "Unpin element", + "pin": "Pin element", + "adjustSize": "Adjust size", + "fade": "Fade element", + "alignLeft": "Align left", + "alignCenter": "Align center", + "alignRight": "Align right", + "alignTop": "Align top", + "alignMiddle": "Align middle", + "alignBottom": "Align bottom", + "arrangeInRow": "Arrange in row", + "arrangeInColumn": "Arrange in column", + "arrangeInGrid": "Arrange in grid", + "distributeHorizontal": "Distribute horizontal spacing", + "distributeVertical": "Distribute vertical spacing", + "justifyHorizontally": "Justify horizontally", + "justifyVertically": "Justify vertically", + "makeSameSize": "Make same size", + "hideElements": "Hide elements", + "fadeElements": "Fade elements", + "pinElements": "Pin elements" + } + } +} diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/locales/ru.json b/packages/diagrams/frontend/sirius-components-diagrams/src/locales/ru.json new file mode 100644 index 0000000000..8d868edc37 --- /dev/null +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/locales/ru.json @@ -0,0 +1,47 @@ +{ + "siriusComponentsDiagrams": { + "edit": { + "enterNewValue": "Укажите новое значение" + }, + "panel": { + "exitFullScreen": "Выйти из полноэкранного режима", + "toggleFullScreen": "Включить полноэкранный режим", + "fitToScreen": "Вписать в экран", + "zoomIn": "Увеличить масштаб", + "zoomOut": "Уменьшить масштаб", + "shareDiagram": "Поделиться диаграммой", + "exportToSvg": "Экспортировать в SVG", + "exitSnapToGrid": "Выйти из режима привязки к сетке", + "toggleSnapToGrid": "Включить режим привязки к сетке", + "hideHelperLines": "Скрыть вспомогательные линии", + "showHelperLines": "Показать вспомогательные линии", + "arrangeAll": "Разместить все элементы", + "revealHidden": "Показать скрытые элементы", + "revealFaded": "Показать затенённые элементы", + "unpinAll": "Открепить все элементы" + }, + "palette": { + "unpin": "Открепить элемент", + "pin": "Закрепить элемент", + "adjustSize": "Подобрать размер", + "fade": "Затенить элемент", + "alignLeft": "Выровнять по левому краю", + "alignCenter": "Выровнять по центру", + "alignRight": "Выровнять по правому краю", + "alignTop": "Выровнять по верхнему краю", + "alignMiddle": "Выровнять по середине", + "alignBottom": "Выровнять по нижнему краю", + "arrangeInRow": "Разместить в строке", + "arrangeInColumn": "Разместить в столбце", + "arrangeInGrid": "Разместить в сетке", + "distributeHorizontal": "Распределить промежутки горизонтально", + "distributeVertical": "Распределить промежутки вертикально", + "justifyHorizontally": "Выровнять горизонтально", + "justifyVertically": "Выровнять вертикально", + "makeSameSize": "Установить одинаковый размер", + "hideElements": "Скрыть элементы", + "fadeElements": "Затенить элементы", + "pinElements": "Закрепить элементы" + } + } +} diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/delete/useDiagramDelete.tsx b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/delete/useDiagramDelete.tsx index 722a26dc3f..3b0b8e16fb 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/delete/useDiagramDelete.tsx +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/delete/useDiagramDelete.tsx @@ -13,6 +13,7 @@ import { gql, useMutation } from '@apollo/client'; import { useDeletionConfirmationDialog, useMultiToast } from '@eclipse-sirius/sirius-components-core'; import { useCallback, useContext, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { useReactFlow } from 'reactflow'; import { DiagramContext } from '../../contexts/DiagramContext'; import { DiagramContextValue } from '../../contexts/DiagramContext.types'; @@ -54,6 +55,7 @@ const isSuccessPayload = (payload: GQLDeleteFromDiagramPayload): payload is GQLD payload.__typename === 'DeleteFromDiagramSuccessPayload'; export const useDiagramDelete = (): UseDiagramDeleteValue => { + const { t: coreT } = useTranslation('siriusComponentsCore'); const { addErrorMessage, addMessages } = useMultiToast(); const { showDeletionConfirmation } = useDeletionConfirmationDialog(); const { diagramId, editingContextId, readOnly } = useContext(DiagramContext); @@ -66,7 +68,7 @@ export const useDiagramDelete = (): UseDiagramDeleteValue => { useEffect(() => { if (deleteElementsError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (deleteElementsData) { const { deleteFromDiagram } = deleteElementsData; @@ -74,7 +76,7 @@ export const useDiagramDelete = (): UseDiagramDeleteValue => { addMessages(deleteFromDiagram.messages); } } - }, [deleteElementsData, deleteElementsError]); + }, [coreT, deleteElementsData, deleteElementsError]); const onDelete = useCallback((event: React.KeyboardEvent) => { const { key } = event; diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/direct-edit/DiagramDirectEditInput.tsx b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/direct-edit/DiagramDirectEditInput.tsx index feef9db6a5..301330d253 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/direct-edit/DiagramDirectEditInput.tsx +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/direct-edit/DiagramDirectEditInput.tsx @@ -14,6 +14,7 @@ import { gql, useMutation, useQuery } from '@apollo/client'; import { useMultiToast } from '@eclipse-sirius/sirius-components-core'; import TextField from '@material-ui/core/TextField'; import { useContext, useEffect, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { DiagramContext } from '../../contexts/DiagramContext'; import { DiagramContextValue } from '../../contexts/DiagramContext.types'; import { useDiagramElementPalette } from '../palette/useDiagramElementPalette'; @@ -74,6 +75,8 @@ const isSuccessPayload = (payload: GQLRenameElementPayload): payload is GQLSucce payload.__typename === 'EditLabelSuccessPayload'; export const DiagramDirectEditInput = ({ labelId, editingKey, onClose }: DiagramDirectEditInputProps) => { + const { t } = useTranslation('siriusComponentsDiagrams', { keyPrefix: 'edit' }); + const { t: coreT } = useTranslation('siriusComponentsCore'); const initialLabel = editingKey === null || editingKey === '' ? '' : editingKey; const [state, setState] = useState({ newLabel: initialLabel, @@ -109,7 +112,7 @@ export const DiagramDirectEditInput = ({ labelId, editingKey, onClose }: Diagram >(editLabelMutationOp); useEffect(() => { if (editLabelError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (editLabelData) { const { editLabel } = editLabelData; @@ -122,12 +125,12 @@ export const DiagramDirectEditInput = ({ labelId, editingKey, onClose }: Diagram } } } - }, [editLabelData, editLabelError]); + }, [coreT, editLabelData, editLabelError]); useEffect(() => { let cleanup: (() => void) | undefined = undefined; if (initialLabelItemError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (initialLabelItemData?.viewer.editingContext.representation.description.initialDirectEditElementLabel) { const initialLabel = @@ -143,7 +146,7 @@ export const DiagramDirectEditInput = ({ labelId, editingKey, onClose }: Diagram } } return cleanup; - }, [initialLabelItemError, initialLabelItemData]); + }, [coreT, initialLabelItemError, initialLabelItemData]); useEffect(() => { if (textInput.current) { @@ -197,7 +200,7 @@ export const DiagramDirectEditInput = ({ labelId, editingKey, onClose }: Diagram name="name" size="small" inputRef={textInput} - placeholder={'Enter the new value'} + placeholder={t('enterNewValue')} value={state.newLabel} multiline={true} onChange={handleChange} diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/drop/useDrop.tsx b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/drop/useDrop.tsx index 8e701104a1..011172090a 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/drop/useDrop.tsx +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/drop/useDrop.tsx @@ -13,6 +13,7 @@ import { gql, useMutation } from '@apollo/client'; import { DRAG_SOURCES_TYPE, useMultiToast } from '@eclipse-sirius/sirius-components-core'; import { useCallback, useContext, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { useReactFlow } from 'reactflow'; import { DiagramContext } from '../../contexts/DiagramContext'; import { DiagramContextValue } from '../../contexts/DiagramContext.types'; @@ -56,6 +57,7 @@ const isSuccessPayload = (payload: GQLDropOnDiagramPayload): payload is GQLDropO payload.__typename === 'DropOnDiagramSuccessPayload'; export const useDrop = (): UseDropValue => { + const { t: coreT } = useTranslation('siriusComponentsCore'); const { addErrorMessage, addMessages } = useMultiToast(); const { diagramId, editingContextId, readOnly } = useContext(DiagramContext); const [dropMutation, { data: droponDiagramElementData, error: droponDiagramError }] = useMutation< @@ -65,7 +67,7 @@ export const useDrop = (): UseDropValue => { useEffect(() => { if (droponDiagramError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (droponDiagramElementData) { const { dropOnDiagram } = droponDiagramElementData; @@ -76,7 +78,7 @@ export const useDrop = (): UseDropValue => { addMessages(dropOnDiagram.messages); } } - }, [droponDiagramElementData, droponDiagramError]); + }, [coreT, droponDiagramElementData, droponDiagramError]); const reactFlowInstance = useReactFlow(); const onDrop = useCallback( (event: React.DragEvent, diagramElementId?: string) => { diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/dropNode/useDropNode.ts b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/dropNode/useDropNode.ts index 695595b07b..798d3acf6d 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/dropNode/useDropNode.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/dropNode/useDropNode.ts @@ -13,6 +13,7 @@ import { gql, useMutation } from '@apollo/client'; import { useMultiToast } from '@eclipse-sirius/sirius-components-core'; import { useCallback, useContext, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { Node, NodeDragHandler, XYPosition, useReactFlow } from 'reactflow'; import { DiagramContext } from '../../contexts/DiagramContext'; import { DiagramContextValue } from '../../contexts/DiagramContext.types'; @@ -73,6 +74,7 @@ const getNodeDepth = (node: Node, intersections: Node[]): nu }; const useDropNodeMutation = () => { + const { t: coreT } = useTranslation('siriusComponentsCore'); const { diagramId, editingContextId, readOnly } = useContext(DiagramContext); const { addErrorMessage, addMessages } = useMultiToast(); const [dropMutation, { data: dropNodeData, error: dropNodeError }] = useMutation< @@ -82,7 +84,7 @@ const useDropNodeMutation = () => { useEffect(() => { if (dropNodeError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (dropNodeData) { const { dropNode } = dropNodeData; @@ -93,7 +95,7 @@ const useDropNodeMutation = () => { addMessages(dropNode.messages); } } - }, [dropNodeData, dropNodeError]); + }, [coreT, dropNodeData, dropNodeError]); const invokeMutation = useCallback( ( diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/fade/useFadeDiagramElements.tsx b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/fade/useFadeDiagramElements.tsx index 412bbb902e..8831a8135c 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/fade/useFadeDiagramElements.tsx +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/fade/useFadeDiagramElements.tsx @@ -13,6 +13,7 @@ import { gql, useMutation } from '@apollo/client'; import { useMultiToast } from '@eclipse-sirius/sirius-components-core'; import { useCallback, useContext, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { DiagramContext } from '../../contexts/DiagramContext'; import { DiagramContextValue } from '../../contexts/DiagramContext.types'; import { @@ -52,6 +53,7 @@ const isSuccessPayload = (payload: GQLFadeDiagramElementPayload): payload is GQL payload.__typename === 'SuccessPayload'; export const useFadeDiagramElements = (): UseFadeDiagramElements => { + const { t: coreT } = useTranslation('siriusComponentsCore'); const { addErrorMessage, addMessages } = useMultiToast(); const { diagramId, editingContextId } = useContext(DiagramContext); @@ -62,9 +64,9 @@ export const useFadeDiagramElements = (): UseFadeDiagramElements => { useEffect(() => { if (fadeDiagramElementError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } - }, [fadeDiagramElementError]); + }, [coreT, fadeDiagramElementError]); const fadeDiagramElements = useCallback( async (nodeId: string[], fade: boolean) => { diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/hide/useHideDiagramElements.tsx b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/hide/useHideDiagramElements.tsx index 0f56cbb1bd..aec14dd718 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/hide/useHideDiagramElements.tsx +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/hide/useHideDiagramElements.tsx @@ -13,6 +13,7 @@ import { gql, useMutation } from '@apollo/client'; import { useMultiToast } from '@eclipse-sirius/sirius-components-core'; import { useCallback, useContext, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { DiagramContext } from '../../contexts/DiagramContext'; import { DiagramContextValue } from '../../contexts/DiagramContext.types'; import { @@ -52,6 +53,7 @@ const isSuccessPayload = (payload: GQLHideDiagramElementPayload): payload is GQL payload.__typename === 'SuccessPayload'; export const useHideDiagramElements = (): UseHideDiagramElements => { + const { t: coreT } = useTranslation('siriusComponentsCore'); const { addErrorMessage, addMessages } = useMultiToast(); const { diagramId, editingContextId } = useContext(DiagramContext); @@ -62,9 +64,9 @@ export const useHideDiagramElements = (): UseHideDiagramElements => { useEffect(() => { if (hideDiagramElementError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } - }, [hideDiagramElementError]); + }, [coreT, hideDiagramElementError]); const hideDiagramElements = useCallback( async (nodeId: string[], hide: boolean) => { diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/layout/useSynchronizeLayoutData.ts b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/layout/useSynchronizeLayoutData.ts index c753345bbd..d92aa12e8d 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/layout/useSynchronizeLayoutData.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/layout/useSynchronizeLayoutData.ts @@ -14,6 +14,7 @@ import { gql, useMutation } from '@apollo/client'; import { useMultiToast } from '@eclipse-sirius/sirius-components-core'; import { useContext, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { DiagramContext } from '../../contexts/DiagramContext'; import { DiagramContextValue } from '../../contexts/DiagramContext.types'; import { RawDiagram } from './layout.types'; @@ -55,6 +56,7 @@ const isSuccessPayload = (payload: GQLLayoutDiagramPayload): payload is GQLSucce payload.__typename === 'SuccessPayload'; export const useSynchronizeLayoutData = (): UseSynchronizeLayoutDataValue => { + const { t: coreT } = useTranslation('siriusComponentsCore'); const { diagramId: representationId, editingContextId } = useContext(DiagramContext); const { addErrorMessage, addMessages } = useMultiToast(); @@ -63,7 +65,7 @@ export const useSynchronizeLayoutData = (): UseSynchronizeLayoutDataValue => { ); useEffect(() => { if (error) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (data) { const { layoutDiagram } = data; @@ -74,7 +76,7 @@ export const useSynchronizeLayoutData = (): UseSynchronizeLayoutDataValue => { addMessages(layoutDiagram.messages); } } - }, [data, error]); + }, [coreT, data, error]); const toDiagramLayoutData = (diagram: RawDiagram): GQLDiagramLayoutData => { const nodeLayoutData: GQLNodeLayoutData[] = []; diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/palette/Palette.tsx b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/palette/Palette.tsx index 479db75097..1923e492e7 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/palette/Palette.tsx +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/palette/Palette.tsx @@ -20,6 +20,7 @@ import { makeStyles } from '@material-ui/core/styles'; import AdjustIcon from '@material-ui/icons/Adjust'; import TonalityIcon from '@material-ui/icons/Tonality'; import React, { useCallback, useContext, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { useReactFlow, useViewport } from 'reactflow'; import { DiagramContext } from '../../contexts/DiagramContext'; import { DiagramContextValue } from '../../contexts/DiagramContext.types'; @@ -215,6 +216,9 @@ export const Palette = ({ onDirectEditClick, hideableDiagramElement, }: PaletteProps) => { + const { t } = useTranslation('siriusComponentsDiagrams', { keyPrefix: 'palette' }); + const { t: coreT } = useTranslation('siriusComponentsCore'); + const [state, setState] = useState({ expandedToolSectionId: null }); const { fadeDiagramElements } = useFadeDiagramElements(); @@ -261,22 +265,22 @@ export const Palette = ({ let adjustSizeTool: JSX.Element | undefined; if (node) { pinUnpinTool = node.data.pinned ? ( - + pinDiagramElements([diagramElementId], !node.data.pinned)} data-testid="Unpin-element"> ) : ( - + pinDiagramElements([diagramElementId], true)} data-testid="Pin-element"> @@ -284,11 +288,11 @@ export const Palette = ({ ); adjustSizeTool = ( - + adjustSize(diagramElementId)} data-testid="adjust-element"> @@ -307,9 +311,9 @@ export const Palette = ({ useEffect(() => { if (paletteError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } - }, [paletteError]); + }, [coreT, paletteError]); const handleToolSectionExpand = (expandedToolSectionId: string | null) => setState((prevState) => ({ ...prevState, expandedToolSectionId })); @@ -475,11 +479,11 @@ export const Palette = ({ })} {hideableDiagramElement ? ( <> - + diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/palette/group-tool/GroupPalette.tsx b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/palette/group-tool/GroupPalette.tsx index 22c3149f1e..0209a20f45 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/palette/group-tool/GroupPalette.tsx +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/palette/group-tool/GroupPalette.tsx @@ -23,7 +23,8 @@ import ViewColumnIcon from '@material-ui/icons/ViewColumn'; import ViewModuleIcon from '@material-ui/icons/ViewModule'; import ViewStreamIcon from '@material-ui/icons/ViewStream'; import VisibilityOffIcon from '@material-ui/icons/VisibilityOff'; -import { memo, useCallback, useRef, useState, Fragment } from 'react'; +import { Fragment, memo, useCallback, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Node, OnSelectionChangeFunc, useOnSelectionChange, useReactFlow } from 'reactflow'; import { AlignHorizontalCenterIcon } from '../../../icons/AlignHorizontalCenterIcon'; import { AlignHorizontalLeftIcon } from '../../../icons/AlignHorizontalLeftIcon'; @@ -99,6 +100,7 @@ const isListData = (node: Node): node is Node => node.type === 'li const canSelectedNodesBeDistributed = (selectedNodes: Node[]) => selectedNodes.length > 1; export const GroupPalette = memo(({ x, y, isOpened, refElementId, hidePalette }: GroupPaletteProps) => { + const { t } = useTranslation('siriusComponentsDiagrams', { keyPrefix: 'palette' }); const { hideDiagramElements } = useHideDiagramElements(); const { fadeDiagramElements } = useFadeDiagramElements(); const { pinDiagramElements } = usePinDiagramElements(); @@ -164,19 +166,19 @@ export const GroupPalette = memo(({ x, y, isOpened, refElementId, hidePalette }: [ { id: 'align-left', - title: 'Align left', + title: t('alignLeft'), action: () => distributeAlignLeft(state.selectedElementIds, refElementId), icon: , }, { id: 'align-center', - title: 'Align center', + title: t('alignCenter'), action: () => distributeAlignCenter(state.selectedElementIds, refElementId), icon: , }, { id: 'align-right', - title: 'Align right', + title: t('alignRight'), action: () => distributeAlignRight(state.selectedElementIds, refElementId), icon: , }, @@ -184,19 +186,19 @@ export const GroupPalette = memo(({ x, y, isOpened, refElementId, hidePalette }: [ { id: 'align-top', - title: 'Align top', + title: t('alignTop'), action: () => distributeAlignTop(state.selectedElementIds, refElementId), icon: , }, { id: 'align-middle', - title: 'Align middle', + title: t('alignMiddle'), action: () => distributeAlignMiddle(state.selectedElementIds, refElementId), icon: , }, { id: 'align-bottom', - title: 'Align bottom', + title: t('alignBottom'), action: () => distributeAlignBottom(state.selectedElementIds, refElementId), icon: , }, @@ -204,19 +206,19 @@ export const GroupPalette = memo(({ x, y, isOpened, refElementId, hidePalette }: [ { id: 'arrange-in-row', - title: 'Arrange in row', + title: t('arrangeInRow'), action: () => arrangeInRow(state.selectedElementIds), icon: , }, { id: 'arrange-in-column', - title: 'Arrange in column', + title: t('arrangeInColumn'), action: () => arrangeInColumn(state.selectedElementIds), icon: , }, { id: 'arrange-in-grid', - title: 'Arrange in grid', + title: t('arrangeInGrid'), action: () => arrangeInGrid(state.selectedElementIds), icon: , }, @@ -224,13 +226,13 @@ export const GroupPalette = memo(({ x, y, isOpened, refElementId, hidePalette }: [ { id: 'distribute-horizontal-spacing', - title: 'Distribute horizontal spacing', + title: t('distributeHorizontal'), action: () => distributeGapHorizontally(state.selectedElementIds), icon: , }, { id: 'distribute-vertical-spacing', - title: 'Distribute vertical spacing', + title: t('distributeVertical'), action: () => distributeGapVertically(state.selectedElementIds), icon: , }, @@ -238,13 +240,13 @@ export const GroupPalette = memo(({ x, y, isOpened, refElementId, hidePalette }: [ { id: 'justify-horizontally', - title: 'Justify horizontally', + title: t('justifyHorizontally'), action: () => justifyHorizontally(state.selectedElementIds, refElementId), icon: , }, { id: 'justify-vertically', - title: 'Justify vertically', + title: t('justifyVertically'), action: () => justifyVertically(state.selectedElementIds, refElementId), icon: , }, @@ -252,7 +254,7 @@ export const GroupPalette = memo(({ x, y, isOpened, refElementId, hidePalette }: [ { id: 'make-same-size', - title: 'Make same size', + title: t('makeSameSize'), action: () => makeNodesSameSize(state.selectedElementIds, refElementId), icon: , }, @@ -348,14 +350,14 @@ export const GroupPalette = memo(({ x, y, isOpened, refElementId, hidePalette }: - hideDiagramElements(state.selectedElementIds, true)}> + hideDiagramElements(state.selectedElementIds, true)}> - fadeDiagramElements(state.selectedElementIds, true)}> + fadeDiagramElements(state.selectedElementIds, true)}> {!state.isMinimalPalette && ( - pinDiagramElements(state.selectedElementIds, true)}> + pinDiagramElements(state.selectedElementIds, true)}> )} diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/panel/DiagramPanel.tsx b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/panel/DiagramPanel.tsx index 37a8b42a80..0896fa6ea9 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/panel/DiagramPanel.tsx +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/panel/DiagramPanel.tsx @@ -29,6 +29,7 @@ import VisibilityOffIcon from '@material-ui/icons/VisibilityOff'; import ZoomInIcon from '@material-ui/icons/ZoomIn'; import ZoomOutIcon from '@material-ui/icons/ZoomOut'; import { memo, useContext, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Panel, useNodesInitialized, useReactFlow } from 'reactflow'; import { DiagramContext } from '../../contexts/DiagramContext'; import { DiagramContextValue } from '../../contexts/DiagramContext.types'; @@ -46,6 +47,8 @@ import { useExportToImage } from './useExportToImage'; export const DiagramPanel = memo( ({ snapToGrid, onSnapToGrid, helperLines, onHelperLines, reactFlowWrapper }: DiagramPanelProps) => { + const { t } = useTranslation('siriusComponentsDiagrams', { keyPrefix: 'panel' }); + const [state, setState] = useState({ dialogOpen: null, arrangeAllDone: false, @@ -91,89 +94,89 @@ export const DiagramPanel = memo( {fullscreen ? ( - - onFullscreen(false)}> + + onFullscreen(false)}> ) : ( - - onFullscreen(true)}> + + onFullscreen(true)}> )} - + - - + + - - + + - - + + - + {snapToGrid ? ( - - onSnapToGrid(false)}> + + onSnapToGrid(false)}> ) : ( - - onSnapToGrid(true)}> + + onSnapToGrid(true)}> )} {helperLines ? ( - + onHelperLines(false)} data-testid="hide-helper-lines"> ) : ( - + onHelperLines(true)} data-testid="show-helper-lines"> )} - + { setState((prevState) => ({ ...prevState, @@ -196,30 +199,30 @@ export const DiagramPanel = memo( )} - + - + - + diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/pin/usePinDiagramElements.tsx b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/pin/usePinDiagramElements.tsx index 3184008e35..7b15da9957 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/pin/usePinDiagramElements.tsx +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/pin/usePinDiagramElements.tsx @@ -13,6 +13,7 @@ import { gql, useMutation } from '@apollo/client'; import { useMultiToast } from '@eclipse-sirius/sirius-components-core'; import { useCallback, useContext, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { DiagramContext } from '../../contexts/DiagramContext'; import { DiagramContextValue } from '../../contexts/DiagramContext.types'; import { @@ -45,6 +46,7 @@ const isErrorPayload = (payload: GQLPinDiagramElementPayload): payload is GQLErr payload.__typename === 'ErrorPayload'; export const usePinDiagramElements = (): UsePinDiagramElements => { + const { t: coreT } = useTranslation('siriusComponentsCore'); const { addErrorMessage } = useMultiToast(); const { diagramId, editingContextId, readOnly } = useContext(DiagramContext); @@ -55,7 +57,7 @@ export const usePinDiagramElements = (): UsePinDiagramElements => { useEffect(() => { if (pinDiagramElementError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (pinDiagramElementData) { const { pinDiagramElement } = pinDiagramElementData; @@ -63,7 +65,7 @@ export const usePinDiagramElements = (): UsePinDiagramElements => { addErrorMessage(pinDiagramElement.message); } } - }, [pinDiagramElementData, pinDiagramElementError]); + }, [coreT, pinDiagramElementData, pinDiagramElementError]); const pinDiagramElements = useCallback( (nodeId: string[], pinned: boolean) => { diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/reconnect-edge/useReconnectEdge.tsx b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/reconnect-edge/useReconnectEdge.tsx index ea2b288c82..7974b5b334 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/reconnect-edge/useReconnectEdge.tsx +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/reconnect-edge/useReconnectEdge.tsx @@ -13,6 +13,7 @@ import { gql, useMutation } from '@apollo/client'; import { useMultiToast } from '@eclipse-sirius/sirius-components-core'; import { useCallback, useContext, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { Connection, Edge } from 'reactflow'; import { DiagramContext } from '../../contexts/DiagramContext'; import { DiagramContextValue } from '../../contexts/DiagramContext.types'; @@ -53,6 +54,7 @@ const isSuccessPayload = (payload: GQLReconnectEdgePayload): payload is GQLSucce payload.__typename === 'SuccessPayload'; export const useReconnectEdge = (): UseReconnectEdge => { + const { t: coreT } = useTranslation('siriusComponentsCore'); const { addErrorMessage, addMessages } = useMultiToast(); const { diagramId, editingContextId, readOnly } = useContext(DiagramContext); const [updateEdgeEnd, { data: reconnectEdgeData, error: reconnectEdgeError }] = useMutation< @@ -80,7 +82,7 @@ export const useReconnectEdge = (): UseReconnectEdge => { useEffect(() => { if (reconnectEdgeError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (reconnectEdgeData) { const { reconnectEdge } = reconnectEdgeData; @@ -88,7 +90,7 @@ export const useReconnectEdge = (): UseReconnectEdge => { addMessages(reconnectEdge.messages); } } - }, [reconnectEdgeData, reconnectEdgeError]); + }, [coreT, reconnectEdgeData, reconnectEdgeError]); const reconnectEdge = useCallback( (oldEdge: Edge, newConnection: Connection) => { diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/package.json b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/package.json index afad836fd7..7708d40878 100644 --- a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/package.json +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/package.json @@ -42,6 +42,7 @@ "graphql": "16.8.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "xstate": "4.32.1" }, "devDependencies": { @@ -62,6 +63,7 @@ "prettier": "2.7.1", "rollup-plugin-peer-deps-external": "2.2.4", "react": "17.0.2", + "react-i18next": "14.1.1", "xstate": "4.32.1", "typescript": "5.4.5", "vite": "5.2.11", diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/SelectWidget.tsx b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/SelectWidget.tsx index bba40c31c2..202eafd2b7 100644 --- a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/SelectWidget.tsx +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/SelectWidget.tsx @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022, 2023 Obeo. + * Copyright (c) 2022, 2024 Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -11,13 +11,14 @@ * Obeo - initial API and implementation *******************************************************************************/ import { getCSSColor, useSelection } from '@eclipse-sirius/sirius-components-core'; -import { getTextDecorationLineValue, SelectStyleProps } from '@eclipse-sirius/sirius-components-forms'; +import { SelectStyleProps, getTextDecorationLineValue } from '@eclipse-sirius/sirius-components-forms'; import MenuItem from '@material-ui/core/MenuItem'; import Select from '@material-ui/core/Select'; -import { makeStyles, Theme } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; +import { Theme, makeStyles } from '@material-ui/core/styles'; import HelpOutlineOutlined from '@material-ui/icons/HelpOutlineOutlined'; import { useEffect, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { SelectWidgetProps } from './WidgetEntry.types'; const useStyles = makeStyles((theme) => ({ @@ -50,6 +51,7 @@ export const SelectWidget = ({ widget }: SelectWidgetProps) => { strikeThrough: widget.style?.strikeThrough ?? null, }; const classes = useStyles(props); + const { t } = useTranslation('siriusComponentsFormDescriptionEditors'); const [selected, setSelected] = useState(false); const { selection } = useSelection(); @@ -106,7 +108,7 @@ export const SelectWidget = ({ widget }: SelectWidgetProps) => { } : {} }> - None + {t('none')} = ({ iconOnly: widget.buttonLabel ? false : true, }; const classes = useStyle(props); + const { t: coreT } = useTranslation('siriusComponentsCore'); const { httpOrigin } = useContext(ServerContext); @@ -139,7 +141,7 @@ export const ButtonPropertySection: PropertySectionComponent = ({ useEffect(() => { if (!loading) { if (error) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (data) { const { pushButton } = data; @@ -172,7 +174,7 @@ export const ButtonPropertySection: PropertySectionComponent = ({ useEffect(() => { if (!updateWidgetFocusLoading) { if (updateWidgetFocusError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (updateWidgetFocusData) { const { updateWidgetFocus } = updateWidgetFocusData; diff --git a/packages/forms/frontend/sirius-components-forms/src/propertysections/CheckboxPropertySection.tsx b/packages/forms/frontend/sirius-components-forms/src/propertysections/CheckboxPropertySection.tsx index cb19a2f076..89d7801b06 100644 --- a/packages/forms/frontend/sirius-components-forms/src/propertysections/CheckboxPropertySection.tsx +++ b/packages/forms/frontend/sirius-components-forms/src/propertysections/CheckboxPropertySection.tsx @@ -18,6 +18,7 @@ import FormControlLabel from '@material-ui/core/FormControlLabel'; import FormHelperText from '@material-ui/core/FormHelperText'; import { Theme, makeStyles } from '@material-ui/core/styles'; import { useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { PropertySectionComponent, PropertySectionComponentProps } from '../form/Form.types'; import { GQLCheckbox } from '../form/FormEventFragments.types'; import { @@ -98,6 +99,7 @@ export const CheckboxPropertySection: PropertySectionComponent = ({ color: widget.style?.color ?? null, }; const classes = useStyle(props); + const { t: coreT } = useTranslation('siriusComponentsCore'); const [editCheckbox, { loading, error, data }] = useMutation(editCheckboxMutation); const onChange = (event) => { @@ -120,7 +122,7 @@ export const CheckboxPropertySection: PropertySectionComponent = ({ useEffect(() => { if (!loading) { if (error) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (data) { const { editCheckbox } = data; @@ -152,7 +154,7 @@ export const CheckboxPropertySection: PropertySectionComponent = ({ useEffect(() => { if (!updateWidgetFocusLoading) { if (updateWidgetFocusError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (updateWidgetFocusData) { const { updateWidgetFocus } = updateWidgetFocusData; diff --git a/packages/forms/frontend/sirius-components-forms/src/propertysections/ListPropertySection.tsx b/packages/forms/frontend/sirius-components-forms/src/propertysections/ListPropertySection.tsx index 6461097d0c..86db554da2 100644 --- a/packages/forms/frontend/sirius-components-forms/src/propertysections/ListPropertySection.tsx +++ b/packages/forms/frontend/sirius-components-forms/src/propertysections/ListPropertySection.tsx @@ -29,6 +29,7 @@ import Typography from '@material-ui/core/Typography'; import { Theme, makeStyles, useTheme } from '@material-ui/core/styles'; import DeleteIcon from '@material-ui/icons/Delete'; import { MouseEvent, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { PropertySectionComponent, PropertySectionComponentProps } from '../form/Form.types'; import { GQLList, GQLListItem } from '../form/FormEventFragments.types'; import { @@ -135,6 +136,8 @@ export const ListPropertySection: PropertySectionComponent = ({ }; const classes = useListPropertySectionStyles(props); const theme = useTheme(); + const { t } = useTranslation('siriusComponentsForms'); + const { t: coreT } = useTranslation('siriusComponentsCore'); const { setSelection } = useSelection(); const { showDeletionConfirmation } = useDeletionConfirmationDialog(); @@ -143,7 +146,7 @@ export const ListPropertySection: PropertySectionComponent = ({ items.push({ id: NONE_WIDGET_ITEM_ID, iconURL: [], - label: 'None', + label: t('none'), kind: 'Unknown', deletable: false, }); @@ -177,7 +180,7 @@ export const ListPropertySection: PropertySectionComponent = ({ useEffect(() => { if (!deleteLoading) { if (deleteError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (deleteData) { const { deleteListItem } = deleteData; @@ -186,12 +189,12 @@ export const ListPropertySection: PropertySectionComponent = ({ } } } - }, [deleteLoading, deleteError, deleteData]); + }, [coreT, deleteLoading, deleteError, deleteData]); useEffect(() => { if (!clickLoading) { if (clickError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (clickData) { const { clickListItem } = clickData; @@ -200,7 +203,7 @@ export const ListPropertySection: PropertySectionComponent = ({ } } } - }, [clickLoading, clickError, clickData]); + }, [clickLoading, clickError, clickData, coreT]); const onSimpleClick = (item: GQLListItem) => { const { id, label, kind } = item; setSelection({ entries: [{ id, label, kind }] }); diff --git a/packages/forms/frontend/sirius-components-forms/src/propertysections/MultiSelectPropertySection.tsx b/packages/forms/frontend/sirius-components-forms/src/propertysections/MultiSelectPropertySection.tsx index e474c04344..a72ac26fec 100644 --- a/packages/forms/frontend/sirius-components-forms/src/propertysections/MultiSelectPropertySection.tsx +++ b/packages/forms/frontend/sirius-components-forms/src/propertysections/MultiSelectPropertySection.tsx @@ -21,6 +21,7 @@ import MenuItem from '@material-ui/core/MenuItem'; import Select from '@material-ui/core/Select'; import { Theme, makeStyles } from '@material-ui/core/styles'; import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { PropertySectionComponent, PropertySectionComponentProps } from '../form/Form.types'; import { GQLMultiSelect } from '../form/FormEventFragments.types'; import { @@ -108,6 +109,7 @@ export const MultiSelectPropertySection: PropertySectionComponent { if (!loading) { if (error) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (data) { const { editMultiSelect } = data; @@ -141,7 +143,7 @@ export const MultiSelectPropertySection: PropertySectionComponent { if (!updateWidgetFocusLoading) { if (updateWidgetFocusError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (updateWidgetFocusData) { const { updateWidgetFocus } = updateWidgetFocusData; @@ -173,7 +175,7 @@ export const MultiSelectPropertySection: PropertySectionComponent { if (!isFocused) { diff --git a/packages/forms/frontend/sirius-components-forms/src/propertysections/RadioPropertySection.tsx b/packages/forms/frontend/sirius-components-forms/src/propertysections/RadioPropertySection.tsx index f2fe3ef7e4..077b4eb0cd 100644 --- a/packages/forms/frontend/sirius-components-forms/src/propertysections/RadioPropertySection.tsx +++ b/packages/forms/frontend/sirius-components-forms/src/propertysections/RadioPropertySection.tsx @@ -23,6 +23,7 @@ import { useEffect } from 'react'; import { getTextDecorationLineValue } from './getTextDecorationLineValue'; import { getCSSColor } from '@eclipse-sirius/sirius-components-core'; +import { useTranslation } from 'react-i18next'; import { PropertySectionComponent, PropertySectionComponentProps } from '../form/Form.types'; import { GQLRadio } from '../form/FormEventFragments.types'; import { PropertySectionLabel } from './PropertySectionLabel'; @@ -112,6 +113,7 @@ export const RadioPropertySection: PropertySectionComponent = ({ strikeThrough: widget.style?.strikeThrough ?? null, }; const classes = useRadioPropertySectionStyles(props); + const { t: coreT } = useTranslation('siriusComponentsCore'); const [editRadio, { loading, error, data }] = useMutation(editRadioMutation); @@ -133,7 +135,7 @@ export const RadioPropertySection: PropertySectionComponent = ({ useEffect(() => { if (!loading) { if (error) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (data) { const { editRadio } = data; @@ -165,7 +167,7 @@ export const RadioPropertySection: PropertySectionComponent = ({ useEffect(() => { if (!updateWidgetFocusLoading) { if (updateWidgetFocusError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (updateWidgetFocusData) { const { updateWidgetFocus } = updateWidgetFocusData; diff --git a/packages/forms/frontend/sirius-components-forms/src/propertysections/RichTextPropertySection.tsx b/packages/forms/frontend/sirius-components-forms/src/propertysections/RichTextPropertySection.tsx index d4a13a45ac..bec98cb32b 100644 --- a/packages/forms/frontend/sirius-components-forms/src/propertysections/RichTextPropertySection.tsx +++ b/packages/forms/frontend/sirius-components-forms/src/propertysections/RichTextPropertySection.tsx @@ -14,6 +14,7 @@ import { gql, useMutation } from '@apollo/client'; import { useMultiToast } from '@eclipse-sirius/sirius-components-core'; import { useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { PropertySectionComponent, PropertySectionComponentProps } from '../form/Form.types'; import { GQLRichText } from '../form/FormEventFragments.types'; import { RichTextEditor } from '../richtexteditor/RichTextEditor'; @@ -82,6 +83,7 @@ export const RichTextPropertySection: PropertySectionComponent = ({ subscribers, readOnly, }: PropertySectionComponentProps) => { + const { t: coreT } = useTranslation('siriusComponentsCore'); const [editRichText, { loading: updateRichTextLoading, data: updateRichTextData, error: updateRichTextError }] = useMutation(editRichTextMutation); const sendEditedValue = (newValue) => { @@ -101,7 +103,7 @@ export const RichTextPropertySection: PropertySectionComponent = ({ useEffect(() => { if (!updateRichTextLoading) { if (updateRichTextError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (updateRichTextData) { const { editRichText } = updateRichTextData; @@ -110,7 +112,7 @@ export const RichTextPropertySection: PropertySectionComponent = ({ } } } - }, [updateRichTextLoading, updateRichTextData, updateRichTextError]); + }, [coreT, updateRichTextLoading, updateRichTextData, updateRichTextError]); const [ updateWidgetFocus, @@ -133,7 +135,7 @@ export const RichTextPropertySection: PropertySectionComponent = ({ useEffect(() => { if (!updateWidgetFocusLoading) { if (updateWidgetFocusError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (updateWidgetFocusData) { const { updateWidgetFocus } = updateWidgetFocusData; @@ -142,7 +144,7 @@ export const RichTextPropertySection: PropertySectionComponent = ({ } } } - }, [updateWidgetFocusLoading, updateWidgetFocusData, updateWidgetFocusError]); + }, [coreT, updateWidgetFocusLoading, updateWidgetFocusData, updateWidgetFocusError]); const onFocus = () => sendUpdateWidgetFocus(true); const onBlur = (currentText: string) => { diff --git a/packages/forms/frontend/sirius-components-forms/src/propertysections/SelectPropertySection.tsx b/packages/forms/frontend/sirius-components-forms/src/propertysections/SelectPropertySection.tsx index 93149f16a8..d05d2b2d4a 100644 --- a/packages/forms/frontend/sirius-components-forms/src/propertysections/SelectPropertySection.tsx +++ b/packages/forms/frontend/sirius-components-forms/src/propertysections/SelectPropertySection.tsx @@ -19,6 +19,7 @@ import MenuItem from '@material-ui/core/MenuItem'; import Select from '@material-ui/core/Select'; import { Theme, makeStyles } from '@material-ui/core/styles'; import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { PropertySectionComponent, PropertySectionComponentProps } from '../form/Form.types'; import { GQLSelect } from '../form/FormEventFragments.types'; import { PropertySectionLabel } from './PropertySectionLabel'; @@ -102,6 +103,8 @@ export const SelectPropertySection: PropertySectionComponent = ({ strikeThrough: widget.style?.strikeThrough ?? null, }; const classes = useStyle(props); + const { t } = useTranslation('siriusComponentsForms'); + const { t: coreT } = useTranslation('siriusComponentsCore'); const [isFocused, setFocus] = useState(false); @@ -125,7 +128,7 @@ export const SelectPropertySection: PropertySectionComponent = ({ useEffect(() => { if (!loading) { if (error) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (data) { const { editSelect } = data; @@ -134,7 +137,7 @@ export const SelectPropertySection: PropertySectionComponent = ({ } } } - }, [loading, error, data]); + }, [loading, error, data, coreT]); const [ updateWidgetFocus, @@ -156,7 +159,7 @@ export const SelectPropertySection: PropertySectionComponent = ({ useEffect(() => { if (!updateWidgetFocusLoading) { if (updateWidgetFocusError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (updateWidgetFocusData) { const { updateWidgetFocus } = updateWidgetFocusData; @@ -165,7 +168,7 @@ export const SelectPropertySection: PropertySectionComponent = ({ } } } - }, [updateWidgetFocusLoading, updateWidgetFocusData, updateWidgetFocusError]); + }, [coreT, updateWidgetFocusLoading, updateWidgetFocusData, updateWidgetFocusError]); const onFocus = () => { if (!isFocused) { @@ -211,7 +214,7 @@ export const SelectPropertySection: PropertySectionComponent = ({ } : {} }> - None + {t('none')} {widget.options.map((option) => ( = ({ subscribers, readOnly, }: PropertySectionComponentProps) => { + const { t: coreT } = useTranslation('siriusComponentsCore'); + const [editSlider, { loading, data, error }] = useMutation( editSliderMutation ); @@ -86,7 +89,7 @@ export const SliderPropertySection: PropertySectionComponent = ({ useEffect(() => { if (!loading) { if (error) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (data) { const { editSlider } = data; @@ -95,7 +98,7 @@ export const SliderPropertySection: PropertySectionComponent = ({ } } } - }, [loading, error, data]); + }, [loading, error, data, coreT]); const [ updateWidgetFocus, { loading: updateWidgetFocusLoading, data: updateWidgetFocusData, error: updateWidgetFocusError }, @@ -118,7 +121,7 @@ export const SliderPropertySection: PropertySectionComponent = ({ useEffect(() => { if (!updateWidgetFocusLoading) { if (updateWidgetFocusError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (updateWidgetFocusData) { const { updateWidgetFocus } = updateWidgetFocusData; @@ -127,7 +130,7 @@ export const SliderPropertySection: PropertySectionComponent = ({ } } } - }, [updateWidgetFocusLoading, updateWidgetFocusData, updateWidgetFocusError]); + }, [coreT, updateWidgetFocusLoading, updateWidgetFocusData, updateWidgetFocusError]); const onFocus = () => sendUpdateWidgetFocus(true); const onBlur = () => { diff --git a/packages/forms/frontend/sirius-components-forms/src/propertysections/SplitButtonPropertySection.tsx b/packages/forms/frontend/sirius-components-forms/src/propertysections/SplitButtonPropertySection.tsx index 4da8a7c460..10a873db4d 100644 --- a/packages/forms/frontend/sirius-components-forms/src/propertysections/SplitButtonPropertySection.tsx +++ b/packages/forms/frontend/sirius-components-forms/src/propertysections/SplitButtonPropertySection.tsx @@ -24,6 +24,7 @@ import { Theme, makeStyles } from '@material-ui/core/styles'; import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown'; import gql from 'graphql-tag'; import { useContext, useEffect, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { GQLButton } from '../form/FormEventFragments.types'; import { ButtonStyleProps, @@ -170,6 +171,7 @@ export const SplitButtonPropertySection = ({ }); const containerClasses = useContainerStyle(); + const { t: coreT } = useTranslation('siriusComponentsCore'); const [pushButton, { loading, data, error }] = useMutation( pushButtonMutation @@ -178,7 +180,7 @@ export const SplitButtonPropertySection = ({ useEffect(() => { if (!loading) { if (error) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (data) { const { pushButton } = data; @@ -211,7 +213,7 @@ export const SplitButtonPropertySection = ({ useEffect(() => { if (!updateWidgetFocusLoading) { if (updateWidgetFocusError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (updateWidgetFocusData) { const { updateWidgetFocus } = updateWidgetFocusData; diff --git a/packages/forms/frontend/sirius-components-forms/src/propertysections/TextfieldPropertySection.tsx b/packages/forms/frontend/sirius-components-forms/src/propertysections/TextfieldPropertySection.tsx index 59493274ec..b256674939 100644 --- a/packages/forms/frontend/sirius-components-forms/src/propertysections/TextfieldPropertySection.tsx +++ b/packages/forms/frontend/sirius-components-forms/src/propertysections/TextfieldPropertySection.tsx @@ -16,6 +16,7 @@ import TextField from '@material-ui/core/TextField'; import { Theme, makeStyles } from '@material-ui/core/styles'; import { useMachine } from '@xstate/react'; import React, { FocusEvent, useEffect, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { PropertySectionComponent, PropertySectionComponentProps } from '../form/Form.types'; import { GQLTextarea, GQLTextfield, GQLWidget } from '../form/FormEventFragments.types'; import { GQLSuccessPayload } from './ListPropertySection.types'; @@ -159,6 +160,7 @@ export const TextfieldPropertySection: PropertySectionComponent { if (!updateWidgetFocusLoading) { if (updateWidgetFocusError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (updateWidgetFocusData) { const { updateWidgetFocus } = updateWidgetFocusData; @@ -252,7 +254,7 @@ export const TextfieldPropertySection: PropertySectionComponent sendUpdateWidgetFocus(true); const onBlur = () => { diff --git a/packages/forms/frontend/sirius-components-forms/src/propertysections/TreePropertySection.tsx b/packages/forms/frontend/sirius-components-forms/src/propertysections/TreePropertySection.tsx index e3a23194ad..354b43516c 100644 --- a/packages/forms/frontend/sirius-components-forms/src/propertysections/TreePropertySection.tsx +++ b/packages/forms/frontend/sirius-components-forms/src/propertysections/TreePropertySection.tsx @@ -27,6 +27,7 @@ import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import { TreeItem as MuiTreeItem } from '@material-ui/lab'; import TreeView from '@material-ui/lab/TreeView'; import React, { useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { PropertySectionComponent, PropertySectionComponentProps } from '../form/Form.types'; import { GQLTree } from '../form/FormEventFragments.types'; import { PropertySectionLabel } from './PropertySectionLabel'; @@ -116,6 +117,7 @@ export const updateWidgetFocusMutation = gql` const TreeItem = ({ node, nodes, readOnly, editingContextId, formId, widgetId }: TreeItemProps) => { const classes = useTreeItemWidgetStyles(); + const { t: coreT } = useTranslation('siriusComponentsCore'); const { setSelection } = useSelection(); const [editTreeCheckbox, { loading, error, data }] = @@ -142,7 +144,7 @@ const TreeItem = ({ node, nodes, readOnly, editingContextId, formId, widgetId }: useEffect(() => { if (!loading) { if (error) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (data) { const { editTreeCheckbox } = data; @@ -151,7 +153,7 @@ const TreeItem = ({ node, nodes, readOnly, editingContextId, formId, widgetId }: } } } - }, [loading, error, data]); + }, [loading, error, data, coreT]); const handleClick: React.MouseEventHandler = () => { if (node.selectable) { @@ -217,6 +219,8 @@ export const TreePropertySection: PropertySectionComponent = ({ }: PropertySectionComponentProps) => { let { nodes, expandedNodesIds } = widget; + const { t } = useTranslation('siriusComponentsForms'); + const { t: coreT } = useTranslation('siriusComponentsCore'); const { addErrorMessage, addMessages } = useMultiToast(); const [ @@ -241,7 +245,7 @@ export const TreePropertySection: PropertySectionComponent = ({ useEffect(() => { if (!updateWidgetFocusLoading) { if (updateWidgetFocusError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (updateWidgetFocusData) { const { updateWidgetFocus } = updateWidgetFocusData; @@ -250,7 +254,7 @@ export const TreePropertySection: PropertySectionComponent = ({ } } } - }, [updateWidgetFocusLoading, updateWidgetFocusData, updateWidgetFocusError]); + }, [coreT, updateWidgetFocusLoading, updateWidgetFocusData, updateWidgetFocusError]); const onFocus = () => { sendUpdateWidgetFocus(true); @@ -270,7 +274,7 @@ export const TreePropertySection: PropertySectionComponent = ({ { id: 'none', parentId: null, - label: 'None', + label: t('none'), kind: 'siriusComponents://unknown', iconURL: [], endIconsURL: [], diff --git a/packages/forms/frontend/sirius-components-forms/src/toolbaraction/ToolbarAction.tsx b/packages/forms/frontend/sirius-components-forms/src/toolbaraction/ToolbarAction.tsx index 3fa1c683b8..7c58024edf 100644 --- a/packages/forms/frontend/sirius-components-forms/src/toolbaraction/ToolbarAction.tsx +++ b/packages/forms/frontend/sirius-components-forms/src/toolbaraction/ToolbarAction.tsx @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022, 2023 Obeo. + * Copyright (c) 2022, 2024 Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -16,6 +16,7 @@ import Button from '@material-ui/core/Button'; import { Theme, makeStyles } from '@material-ui/core/styles'; import gql from 'graphql-tag'; import { useContext, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { GQLButton } from '../form/FormEventFragments.types'; import { HelpTooltip } from '../propertysections/HelpTooltip'; import { getTextDecorationLineValue } from './../propertysections/getTextDecorationLineValue'; @@ -116,6 +117,7 @@ export const ToolbarAction = ({ editingContextId, formId, widget, readOnly }: To iconOnly: widget.buttonLabel ? false : true, }; const classes = useStyle(props); + const { t: coreT } = useTranslation('siriusComponentsCore'); const { httpOrigin } = useContext(ServerContext); @@ -128,7 +130,7 @@ export const ToolbarAction = ({ editingContextId, formId, widget, readOnly }: To useEffect(() => { if (!loading) { if (error) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (data) { const { pushButton } = data; @@ -137,7 +139,7 @@ export const ToolbarAction = ({ editingContextId, formId, widget, readOnly }: To } } } - }, [loading, error, data]); + }, [loading, error, data, coreT]); const [ updateWidgetFocus, @@ -161,7 +163,7 @@ export const ToolbarAction = ({ editingContextId, formId, widget, readOnly }: To useEffect(() => { if (!updateWidgetFocusLoading) { if (updateWidgetFocusError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (updateWidgetFocusData) { const { updateWidgetFocus } = updateWidgetFocusData; @@ -170,7 +172,7 @@ export const ToolbarAction = ({ editingContextId, formId, widget, readOnly }: To } } } - }, [updateWidgetFocusLoading, updateWidgetFocusData, updateWidgetFocusError]); + }, [coreT, updateWidgetFocusLoading, updateWidgetFocusData, updateWidgetFocusError]); const onFocus = () => sendUpdateWidgetFocus(true); const onBlur = () => { diff --git a/packages/forms/frontend/sirius-components-forms/src/views/FormBasedView.tsx b/packages/forms/frontend/sirius-components-forms/src/views/FormBasedView.tsx index 39c2a471ce..a6940a9f9c 100644 --- a/packages/forms/frontend/sirius-components-forms/src/views/FormBasedView.tsx +++ b/packages/forms/frontend/sirius-components-forms/src/views/FormBasedView.tsx @@ -16,6 +16,7 @@ import Typography from '@material-ui/core/Typography'; import { makeStyles } from '@material-ui/core/styles'; import { useMachine } from '@xstate/react'; import { useContext, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { Form } from '../form/Form'; import { WidgetContribution } from '../form/Form.types'; import { PropertySectionContext } from '../form/FormContext'; @@ -87,6 +88,7 @@ export const FormBasedView = ({ const { toast, formBasedView } = value as SchemaValue; const { id, currentSelection, form, widgetSubscriptions, message } = context; const { selection } = useSelection(); + const { t } = useTranslation('siriusComponentsForms'); /** * Displays another form if the selection indicates that we should display another properties view. @@ -160,7 +162,7 @@ export const FormBasedView = ({ if (formBasedView === 'empty' || formBasedView === 'unsupportedSelection' || formBasedView === 'complete') { content = (
- No object selected + {t('noObjectSelected')}
); } diff --git a/packages/forms/frontend/sirius-components-forms/vitestSetup.js b/packages/forms/frontend/sirius-components-forms/vitestSetup.js index 1ea785c53d..c1909d2dcd 100644 --- a/packages/forms/frontend/sirius-components-forms/vitestSetup.js +++ b/packages/forms/frontend/sirius-components-forms/vitestSetup.js @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 Obeo. + * Copyright (c) 2023, 2024 Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -10,6 +10,19 @@ * Contributors: * Obeo - initial API and implementation *******************************************************************************/ +import i18n from 'i18next'; import crypto from 'node:crypto'; +import { initReactI18next } from 'react-i18next'; +import { default as en } from './src/locales/en.json'; globalThis.crypto = crypto; + +i18n.use(initReactI18next).init({ + lng: 'en', + interpolation: { + escapeValue: false, + }, + resources: { en }, +}); + +export default i18n; diff --git a/packages/forms/frontend/sirius-components-widget-reference/package.json b/packages/forms/frontend/sirius-components-widget-reference/package.json index d8a63abe70..debb83e909 100644 --- a/packages/forms/frontend/sirius-components-widget-reference/package.json +++ b/packages/forms/frontend/sirius-components-widget-reference/package.json @@ -46,6 +46,7 @@ "lexical": "0.8.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "xstate": "4.32.1" }, "devDependencies": { @@ -72,6 +73,7 @@ "rollup-plugin-peer-deps-external": "2.2.4", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "xstate": "4.32.1", "typescript": "5.4.5", "vite": "5.2.11", diff --git a/packages/forms/frontend/sirius-components-widget-reference/src/ReferencePropertySection.tsx b/packages/forms/frontend/sirius-components-widget-reference/src/ReferencePropertySection.tsx index b8d4bc2dbe..c2e5f1161d 100644 --- a/packages/forms/frontend/sirius-components-widget-reference/src/ReferencePropertySection.tsx +++ b/packages/forms/frontend/sirius-components-widget-reference/src/ReferencePropertySection.tsx @@ -27,6 +27,7 @@ import { } from '@eclipse-sirius/sirius-components-forms'; import { Theme, makeStyles } from '@material-ui/core/styles'; import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { GQLAddReferenceValuesMutationData, GQLAddReferenceValuesMutationVariables, @@ -196,6 +197,7 @@ const RawReferencePropertySection: PropertySectionComponent readOnly, }: PropertySectionComponentProps) => { const classes = useStyles(); + const { t: coreT } = useTranslation('siriusComponentsCore'); const { setSelection } = useSelection(); const { showDeletionConfirmation } = useDeletionConfirmationDialog(); @@ -240,7 +242,7 @@ const RawReferencePropertySection: PropertySectionComponent useEffect(() => { if (!clearLoading) { if (clearError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (clearData) { const { clearReference } = clearData; @@ -249,11 +251,11 @@ const RawReferencePropertySection: PropertySectionComponent } } } - }, [clearLoading, clearError, clearData]); + }, [clearLoading, clearError, clearData, coreT]); useEffect(() => { if (!removeLoading) { if (removeError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (removeData) { const { removeReferenceValue } = removeData; @@ -262,11 +264,11 @@ const RawReferencePropertySection: PropertySectionComponent } } } - }, [removeLoading, removeError, removeData]); + }, [coreT, removeLoading, removeError, removeData]); useEffect(() => { if (!setLoading) { if (setError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (setData) { const { setReferenceValue } = setData; @@ -275,11 +277,11 @@ const RawReferencePropertySection: PropertySectionComponent } } } - }, [setLoading, setError, setData]); + }, [coreT, setLoading, setError, setData]); useEffect(() => { if (!addLoading) { if (addError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (addData) { const { addReferenceValues } = addData; @@ -288,11 +290,11 @@ const RawReferencePropertySection: PropertySectionComponent } } } - }, [addLoading, addError, addData]); + }, [addLoading, addError, addData, coreT]); useEffect(() => { if (!moveLoading) { if (moveError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (moveData) { const { moveReferenceValue } = moveData; @@ -301,7 +303,7 @@ const RawReferencePropertySection: PropertySectionComponent } } } - }, [moveLoading, moveError, moveData]); + }, [coreT, moveLoading, moveError, moveData]); const callClearReference = () => { const variables = { diff --git a/packages/forms/frontend/sirius-components-widget-reference/src/components/FilterableSortableList.tsx b/packages/forms/frontend/sirius-components-widget-reference/src/components/FilterableSortableList.tsx index 71d17fdd45..3ce730c20e 100644 --- a/packages/forms/frontend/sirius-components-widget-reference/src/components/FilterableSortableList.tsx +++ b/packages/forms/frontend/sirius-components-widget-reference/src/components/FilterableSortableList.tsx @@ -20,6 +20,7 @@ import { makeStyles, Theme } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; import DragHandleIcon from '@material-ui/icons/DragHandle'; import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { FilterableSortableListProps, FilterableSortableListState, @@ -108,6 +109,7 @@ export const FilterableSortableList = ({ moveElement, }: FilterableSortableListProps) => { const classes = useStyles(); + const { t } = useTranslation('siriusComponentsWidgetReference', { keyPrefix: 'edit' }); const [state, setState] = useState({ filterBarText: '', @@ -202,7 +204,7 @@ export const FilterableSortableList = ({ } text={state.filterBarText} /> - Selected + {t('selected')}
{items diff --git a/packages/forms/frontend/sirius-components-widget-reference/src/components/ModelBrowserFilterBar.tsx b/packages/forms/frontend/sirius-components-widget-reference/src/components/ModelBrowserFilterBar.tsx index 93be499f98..9da34b4b09 100644 --- a/packages/forms/frontend/sirius-components-widget-reference/src/components/ModelBrowserFilterBar.tsx +++ b/packages/forms/frontend/sirius-components-widget-reference/src/components/ModelBrowserFilterBar.tsx @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 Obeo. + * Copyright (c) 2023, 2024 Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -17,6 +17,7 @@ import { makeStyles, Theme } from '@material-ui/core/styles'; import TextField from '@material-ui/core/TextField'; import ClearIcon from '@material-ui/icons/Clear'; import SearchIcon from '@material-ui/icons/Search'; +import { useTranslation } from 'react-i18next'; import { ModelBrowserFilterBarProps } from './ModelBrowserFilterBar.types'; const useFilterBarStyles = makeStyles((theme: Theme) => ({ @@ -35,6 +36,7 @@ const useFilterBarStyles = makeStyles((theme: Theme) => ({ })); export const ModelBrowserFilterBar = ({ onTextChange, onTextClear, text }: ModelBrowserFilterBarProps) => { const classes = useFilterBarStyles(); + const { t } = useTranslation('siriusComponentsWidgetReference', { keyPrefix: 'filter' }); return (
@@ -42,7 +44,7 @@ export const ModelBrowserFilterBar = ({ onTextChange, onTextClear, text }: Model id="filterbar-textfield" data-testid="filterbar-textfield" name="filterbar-textfield" - placeholder="Type to filter" + placeholder={t('typeToFilter')} spellCheck={false} size="small" margin="none" diff --git a/packages/forms/frontend/sirius-components-widget-reference/src/components/ValuedReferenceAutocomplete.tsx b/packages/forms/frontend/sirius-components-widget-reference/src/components/ValuedReferenceAutocomplete.tsx index 4d31bab852..61a2de2385 100644 --- a/packages/forms/frontend/sirius-components-widget-reference/src/components/ValuedReferenceAutocomplete.tsx +++ b/packages/forms/frontend/sirius-components-widget-reference/src/components/ValuedReferenceAutocomplete.tsx @@ -23,6 +23,7 @@ import DeleteIcon from '@material-ui/icons/Delete'; import MoreHorizIcon from '@material-ui/icons/MoreHoriz'; import Autocomplete from '@material-ui/lab/Autocomplete'; import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { GQLReferenceValue, GQLReferenceWidgetStyle } from '../ReferenceWidgetFragment.types'; import { GQLFormDescription, @@ -106,6 +107,8 @@ export const ValuedReferenceAutocomplete = ({ }; const classes = useStyles(props); const theme = useTheme(); + const { t } = useTranslation('siriusComponentsWidgetReference', { keyPrefix: 'view' }); + const { t: coreT } = useTranslation('siriusComponentsCore'); const { addErrorMessage } = useMultiToast(); const [state, setState] = useState({ open: false, options: null }); @@ -125,7 +128,7 @@ export const ValuedReferenceAutocomplete = ({ useEffect(() => { if (!childReferenceValueOptionsLoading) { if (childReferenceValueOptionsError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (childReferenceValueOptionsData) { const representationDescription: GQLRepresentationDescription = @@ -140,7 +143,7 @@ export const ValuedReferenceAutocomplete = ({ } } } - }, [childReferenceValueOptionsLoading, childReferenceValueOptionsData, childReferenceValueOptionsError]); + }, [childReferenceValueOptionsLoading, childReferenceValueOptionsData, childReferenceValueOptionsError, coreT]); useEffect(() => { if (loading) { @@ -198,9 +201,9 @@ export const ValuedReferenceAutocomplete = ({ let placeholder: string; if (widget.reference.manyValued) { - placeholder = 'Values'; + placeholder = t('values'); } else { - placeholder = widget.referenceValues.length > 0 ? '' : 'Value'; + placeholder = widget.referenceValues.length > 0 ? '' : t('value'); } return ( )} disableClearable + openText={t('open')} + closeText={t('close')} renderTags={(value, getTagProps) => value.map((option, index) => ( @@ -284,7 +289,7 @@ export const ValuedReferenceAutocomplete = ({ @@ -293,7 +298,7 @@ export const ValuedReferenceAutocomplete = ({ diff --git a/packages/forms/frontend/sirius-components-widget-reference/src/index.ts b/packages/forms/frontend/sirius-components-widget-reference/src/index.ts index f87623ef26..1443752f41 100644 --- a/packages/forms/frontend/sirius-components-widget-reference/src/index.ts +++ b/packages/forms/frontend/sirius-components-widget-reference/src/index.ts @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 Obeo. + * Copyright (c) 2023, 2024 Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -14,3 +14,5 @@ export * from './ReferenceIcon'; export * from './ReferencePreview'; export * from './ReferencePropertySection'; export * from './ReferenceWidgetFragment.types'; +export { default as siriusComponentsWidgetReferenceEn } from './locales/en.json'; +export { default as siriusComponentsWidgetReferenceRu } from './locales/ru.json'; diff --git a/packages/forms/frontend/sirius-components-widget-reference/src/locales/en.json b/packages/forms/frontend/sirius-components-widget-reference/src/locales/en.json new file mode 100644 index 0000000000..7bdadc04da --- /dev/null +++ b/packages/forms/frontend/sirius-components-widget-reference/src/locales/en.json @@ -0,0 +1,40 @@ +{ + "siriusComponentsWidgetReference": { + "filter": { + "typeToFilter": "Type to filter" + }, + "view": { + "clear": "Clear", + "close": "Close", + "createObject": "Create an object", + "edit": "Edit", + "open": "Open", + "value": "Value", + "values": "Values" + }, + "select": { + "title": "Select an object", + "choices": "Choices", + "submit": "Select" + }, + "create": { + "title": "Create an object", + "container": { + "label": "Select the container" + }, + "domain": { + "label": "Select the domain" + }, + "type": { + "label": "Select the object type" + }, + "submit": "Create" + }, + "edit": { + "title": "Edit reference", + "choices": "Choices", + "selected": "Selected", + "close": "Close" + } + } +} diff --git a/packages/forms/frontend/sirius-components-widget-reference/src/locales/ru.json b/packages/forms/frontend/sirius-components-widget-reference/src/locales/ru.json new file mode 100644 index 0000000000..9cd25ec1fd --- /dev/null +++ b/packages/forms/frontend/sirius-components-widget-reference/src/locales/ru.json @@ -0,0 +1,40 @@ +{ + "siriusComponentsWidgetReference": { + "filter": { + "typeToFilter": "Фильтр" + }, + "view": { + "clear": "Очистить", + "close": "Закрыть", + "createObject": "Создать объект", + "edit": "Изменить", + "open": "Открыть", + "value": "Значение", + "values": "Значения" + }, + "select": { + "title": "Выберите объект", + "choices": "Доступные значения", + "submit": "Выбрать" + }, + "create": { + "title": "Создать объект", + "container": { + "label": "Выберите контейнер" + }, + "domain": { + "label": "Выберите предметную область" + }, + "type": { + "label": "Выберите тип объекта" + }, + "submit": "Создать" + }, + "edit": { + "title": "Изменить ссылку", + "choices": "Доступные значения", + "selected": "Выбранные значения", + "close": "Закрыть" + } + } +} diff --git a/packages/forms/frontend/sirius-components-widget-reference/src/modals/BrowseModal.tsx b/packages/forms/frontend/sirius-components-widget-reference/src/modals/BrowseModal.tsx index 6255f6bee6..bd1e2cd1f2 100644 --- a/packages/forms/frontend/sirius-components-widget-reference/src/modals/BrowseModal.tsx +++ b/packages/forms/frontend/sirius-components-widget-reference/src/modals/BrowseModal.tsx @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 Obeo. + * Copyright (c) 2023, 2024 Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -19,6 +19,7 @@ import DialogContent from '@material-ui/core/DialogContent'; import DialogTitle from '@material-ui/core/DialogTitle'; import { makeStyles } from '@material-ui/core/styles'; import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { ModelBrowserTreeView } from '../components/ModelBrowserTreeView'; import { BrowseModalProps } from './BrowseModal.types'; @@ -30,6 +31,7 @@ const useBrowserModalStyles = makeStyles((_) => ({ export const BrowseModal = ({ editingContextId, widget, onClose }: BrowseModalProps) => { const styles = useBrowserModalStyles(); + const { t } = useTranslation('siriusComponentsWidgetReference', { keyPrefix: 'select' }); const [browserSelection, setBrowserSelection] = useState({ entries: widget.referenceValues }); return ( @@ -44,14 +46,14 @@ export const BrowseModal = ({ editingContextId, widget, onClose }: BrowseModalPr aria-labelledby="dialog-title" fullWidth data-testid="browse-modal"> - Select an object + {t('title')} @@ -68,7 +70,7 @@ export const BrowseModal = ({ editingContextId, widget, onClose }: BrowseModalPr onClose(selectedElement.id); } }}> - Select + {t('submit')} diff --git a/packages/forms/frontend/sirius-components-widget-reference/src/modals/CreateModal.tsx b/packages/forms/frontend/sirius-components-widget-reference/src/modals/CreateModal.tsx index fc26a33ed9..8006155ace 100644 --- a/packages/forms/frontend/sirius-components-widget-reference/src/modals/CreateModal.tsx +++ b/packages/forms/frontend/sirius-components-widget-reference/src/modals/CreateModal.tsx @@ -24,6 +24,7 @@ import Select from '@material-ui/core/Select'; import { makeStyles } from '@material-ui/core/styles'; import { useMachine } from '@xstate/react'; import { useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { ModelBrowserTreeView } from '../components/ModelBrowserTreeView'; import { CreateModalProps, @@ -164,6 +165,8 @@ const isSuccessPayload = ( export const CreateModal = ({ editingContextId, widget, onClose, formId }: CreateModalProps) => { const classes = useStyle(); + const { t } = useTranslation('siriusComponentsWidgetReference', { keyPrefix: 'create' }); + const { t: coreT } = useTranslation('siriusComponentsCore'); const { addErrorMessage, addMessages } = useMultiToast(); const [{ value, context }, dispatch] = useMachine(createModalMachine); const { createModal } = value as SchemaValue; @@ -199,7 +202,7 @@ export const CreateModal = ({ editingContextId, widget, onClose, formId }: Creat useEffect(() => { if (!domainsLoading) { if (domainsError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (domainsData) { const fetchDomainsEvent: FetchedDomainsEvent = { @@ -209,7 +212,7 @@ export const CreateModal = ({ editingContextId, widget, onClose, formId }: Creat dispatch(fetchDomainsEvent); } } - }, [domainsLoading, domainsData, domainsError]); + }, [coreT, domainsLoading, domainsData, domainsError]); const [ getRootObjectCreationDescriptions, @@ -221,7 +224,7 @@ export const CreateModal = ({ editingContextId, widget, onClose, formId }: Creat useEffect(() => { if (!descriptionsLoading) { if (descriptionError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (descriptionsData) { const fetchDescriptionsEvent: FetchedRootObjectCreationDescriptionsEvent = { @@ -231,7 +234,7 @@ export const CreateModal = ({ editingContextId, widget, onClose, formId }: Creat dispatch(fetchDescriptionsEvent); } } - }, [descriptionsLoading, descriptionsData, descriptionError]); + }, [coreT, descriptionsLoading, descriptionsData, descriptionError]); const [ getChildCreationDescription, @@ -247,7 +250,7 @@ export const CreateModal = ({ editingContextId, widget, onClose, formId }: Creat useEffect(() => { if (!childCreationDescriptionsLoading) { if (childCreationDescriptionsError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (childCreationDescriptionsData) { const fetchChildCreationDescriptionsEvent: FetchedChildCreationDescriptionsEvent = { @@ -257,7 +260,7 @@ export const CreateModal = ({ editingContextId, widget, onClose, formId }: Creat dispatch(fetchChildCreationDescriptionsEvent); } } - }, [childCreationDescriptionsLoading, childCreationDescriptionsData, childCreationDescriptionsError]); + }, [childCreationDescriptionsLoading, childCreationDescriptionsData, childCreationDescriptionsError, coreT]); const [ createElementInReference, @@ -269,7 +272,7 @@ export const CreateModal = ({ editingContextId, widget, onClose, formId }: Creat useEffect(() => { if (!createElementLoading) { if (createElementError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (createElementData) { const handleResponseEvent: HandleCreateElementResponseEvent = { @@ -285,7 +288,7 @@ export const CreateModal = ({ editingContextId, widget, onClose, formId }: Creat } } } - }, [createElementLoading, createElementData, createElementError]); + }, [coreT, createElementLoading, createElementData, createElementError]); const onCreateObject = () => { let input: GQLCreateElementInReferenceInput | null = null; @@ -385,7 +388,7 @@ export const CreateModal = ({ editingContextId, widget, onClose, formId }: Creat aria-labelledby="dialog-title" fullWidth data-testid="create-modal"> - Create an object + {t('title')} {widget.reference.containment ? null : ( )} {containerKind === 'siriusWeb://document' && ( <> - Select the domain + {t('domain.label')} - Create + {t('submit')} diff --git a/packages/forms/frontend/sirius-components-widget-reference/src/modals/TransferModal.tsx b/packages/forms/frontend/sirius-components-widget-reference/src/modals/TransferModal.tsx index 67dcbad8b3..143210e2de 100644 --- a/packages/forms/frontend/sirius-components-widget-reference/src/modals/TransferModal.tsx +++ b/packages/forms/frontend/sirius-components-widget-reference/src/modals/TransferModal.tsx @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 Obeo. + * Copyright (c) 2023, 2024 Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -28,6 +28,7 @@ import { makeStyles } from '@material-ui/core/styles'; import ChevronLeftIcon from '@material-ui/icons/ChevronLeft'; import ChevronRightIcon from '@material-ui/icons/ChevronRight'; import React, { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { FilterableSortableList } from '../components/FilterableSortableList'; import { ModelBrowserTreeView } from '../components/ModelBrowserTreeView'; import { @@ -90,6 +91,8 @@ export const TransferModal = ({ moveElement, }: TransferModalProps) => { const classes = useStyles(); + const { t } = useTranslation('siriusComponentsWidgetReference', { keyPrefix: 'edit' }); + const { t: coreT } = useTranslation('siriusComponentsCore'); const { addErrorMessage } = useMultiToast(); const [state, setState] = useState({ right: widget.referenceValues, @@ -117,7 +120,7 @@ export const TransferModal = ({ useEffect(() => { if (!childReferenceValueOptionsLoading) { if (childReferenceValueOptionsError) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (childReferenceValueOptionsData) { const representationDescription: GQLRepresentationDescription = @@ -132,7 +135,7 @@ export const TransferModal = ({ } } } - }, [childReferenceValueOptionsLoading, childReferenceValueOptionsData, childReferenceValueOptionsError]); + }, [childReferenceValueOptionsLoading, childReferenceValueOptionsData, childReferenceValueOptionsError, coreT]); useEffect(() => { setState((prevState) => { @@ -245,7 +248,7 @@ export const TransferModal = ({ aria-labelledby="dialog-title" maxWidth={false} data-testid="transfer-modal"> - Edit reference + {t('title')} @@ -255,7 +258,7 @@ export const TransferModal = ({ widget={widget} markedItemIds={state.right.map((entry) => entry.id)} enableMultiSelection={widget.reference.manyValued} - title={'Choices'} + title={t('choices')} leafType={'reference'} ownerKind={widget.reference.ownerKind} /> @@ -316,7 +319,7 @@ export const TransferModal = ({ type="button" data-testid="close-transfer-modal" onClick={() => onClose()}> - close + {t('close')} diff --git a/packages/sirius-web/frontend/sirius-web-application/package.json b/packages/sirius-web/frontend/sirius-web-application/package.json index 7b20cd3e65..3a342ee2fd 100644 --- a/packages/sirius-web/frontend/sirius-web-application/package.json +++ b/packages/sirius-web/frontend/sirius-web-application/package.json @@ -50,6 +50,7 @@ "notistack": "3.0.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "react-router-dom": "5.2.0", "reactflow": "11.10.1", "xstate": "4.32.1" @@ -75,6 +76,7 @@ "prettier": "2.7.1", "react": "17.0.2", "react-dom": "17.0.2", + "react-i18next": "14.1.1", "react-router-dom": "5.2.0", "rollup-plugin-peer-deps-external": "2.2.4", "xstate": "4.32.1", diff --git a/packages/sirius-web/frontend/sirius-web-application/src/core/file-upload/FileUpload.tsx b/packages/sirius-web/frontend/sirius-web-application/src/core/file-upload/FileUpload.tsx index 7e00e6523e..85c89630bd 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/core/file-upload/FileUpload.tsx +++ b/packages/sirius-web/frontend/sirius-web-application/src/core/file-upload/FileUpload.tsx @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019, 2023 Obeo. + * Copyright (c) 2019, 2024 Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -13,6 +13,7 @@ import Typography from '@material-ui/core/Typography'; import { makeStyles } from '@material-ui/core/styles'; import React, { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { FileUploadProps, FileUploadState } from './FileUpload.types'; const useFileUploadViewStyles = makeStyles((theme) => ({ @@ -41,29 +42,27 @@ const useFileUploadViewStyles = makeStyles((theme) => ({ }, })); -const DEFAULT_MESSAGE = 'Click here to select a file'; - -const initialState: FileUploadState = { - file: null, - message: DEFAULT_MESSAGE, -}; export const FileUpload = ({ onFileSelected, 'data-testid': dataTestId }: FileUploadProps) => { const styles = useFileUploadViewStyles(); + const { t } = useTranslation('siriusWebApplication', { keyPrefix: 'core' }); const fileInput = React.createRef(); - const [state, setState] = useState(initialState); + const [state, setState] = useState({ + file: null, + message: t('clickToSelectFile'), + }); const { file, message } = state; // Update the message useEffect(() => { - let message = DEFAULT_MESSAGE; + let message = t('clickToSelectFile'); if (file) { message = file.name; } setState((prevState) => { return { ...prevState, message }; }); - }, [file]); + }, [file, t]); // Update the file selection. const onFileInputChange = () => { diff --git a/packages/sirius-web/frontend/sirius-web-application/src/index.ts b/packages/sirius-web/frontend/sirius-web-application/src/index.ts index abbd28237a..67477bf835 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/index.ts +++ b/packages/sirius-web/frontend/sirius-web-application/src/index.ts @@ -27,6 +27,8 @@ export { httpOptionsConfigurersExtensionPoint, webSocketOptionsConfigurersExtensionPoint, } from './graphql/useCreateApolloClientExtensionPoints'; +export { default as siriusWebApplicationEn } from './locales/en.json'; +export { default as siriusWebApplicationRu } from './locales/ru.json'; export { type NavigationBarIconProps, type NavigationBarLeftContributionProps, diff --git a/packages/sirius-web/frontend/sirius-web-application/src/locales/en.json b/packages/sirius-web/frontend/sirius-web-application/src/locales/en.json new file mode 100644 index 0000000000..810548b822 --- /dev/null +++ b/packages/sirius-web/frontend/sirius-web-application/src/locales/en.json @@ -0,0 +1,170 @@ +{ + "siriusWebApplication": { + "application": { + "details": "Details", + "explorer": "Explorer", + "relatedElements": "Related Elements", + "representations": "Representations", + "validation": "Validation" + }, + "core": { + "clickToSelectFile": "Click here to select a file" + }, + "navigationBar": { + "backToHomepage": "Back to the homepage" + }, + "project": { + "list": { + "blankProject": "Blank project", + "createNewProject": "Create a new project", + "delete": "Delete", + "download": "Download", + "empty": "No projects found, start by creating one", + "existingProjects": "Existing Projects", + "more": "More", + "name": "Name", + "rename": "Rename", + "selectProjectTemplate": "Select a project template", + "showAllTemplates": "Show all templates", + "uploadProject": "Upload project" + }, + "create": { + "title": "Create a new project", + "description": "Get started by creating a new project", + "name": { + "label": "Name", + "placeholder": "Enter the project name", + "helperText": "The name must contain between 3 and 1024 characters" + }, + "submit": "Create" + }, + "upload": { + "title": "Upload a project", + "description": "Start with an existing project", + "clickToSelectFile": "Click here to select a file", + "submit": "Upload" + }, + "rename": { + "title": "Rename the project", + "name": { + "label": "Name", + "placeholder": "Enter a new project name", + "helperText": "The name is required and must contain less than 1024 characters" + }, + "submit": "Rename" + }, + "delete": { + "title": "Delete the project \"{{name}}\"", + "content": "This action will delete everything in the project. All data and all representations will be lost. It cannot be reversed.", + "submit": "Delete" + }, + "edit": { + "createModel": "Create a new Model", + "createRepresentation": "Create a new Representation", + "delete": "Delete", + "download": "Download", + "newModel": "New model", + "noAccessToCreateModel": "You need edit access to create models", + "noAccessToCreateRepresentation": "You need edit access to create representations", + "noRepresentations": "There are no representations available for the current selection", + "openRepresentation": "Open an existing Representation", + "rename": "Rename", + "selectModelToCreate": "Select the model to create", + "selectRepresentationToCreate": "Select the representation to create on {{name}}", + "selectRepresentationToOpen": "Select the representation to open", + "settings": "Settings", + "newObject": "New object", + "newRepresentation": "New representation", + "uploadModel": "Upload model" + } + }, + "model": { + "create": { + "title": "Create a new model", + "name": { + "label": "Name", + "placeholder": "Enter the name of the model", + "helperText": "The name cannot be empty" + }, + "modelType": { + "label": "Model type" + }, + "submit": "Create" + }, + "upload": { + "title": "Upload new model", + "submit": "Upload", + "cancel": "Close" + } + }, + "object": { + "newRoot": { + "title": "Create a new root object", + "domain": { + "label": "Domain" + }, + "type": { + "label": "Object type" + }, + "suggestedType": { + "label": "Show only suggested root type" + }, + "submit": "Create" + }, + "create": { + "title": "Create a new object", + "type": { + "label": "Object type" + }, + "submit": "Create" + } + }, + "representation": { + "create": { + "title": "Create a new representation", + "name": { + "label": "Name", + "placeholder": "Enter the name of the representation", + "helperText": "The name cannot be empty" + }, + "type": { + "label": "Representation type" + }, + "submit": "Create" + } + }, + "image": { + "list": { + "copyId": "Copy ID to clipboard", + "delete": "Delete", + "empty": "No project images available, start by uploading one", + "id": "ID", + "label": "Label", + "title": "Project Images", + "upload": "Upload" + }, + "upload": { + "title": "Upload new image", + "label": { + "label": "Label", + "placeholder": "Label for the image" + }, + "submit": "Upload" + }, + "rename": { + "title": "Rename the image", + "name": { + "label": "Name", + "placeholder": "Enter the new image name", + "helperText": "The name must contain at least 3 characters" + }, + "submit": "Rename" + }, + "delete": { + "title": "Delete the image", + "content": "This action will delete the image and might break projects which use it. It cannot be reversed.", + "submit": "Delete" + } + } + } +} diff --git a/packages/sirius-web/frontend/sirius-web-application/src/locales/ru.json b/packages/sirius-web/frontend/sirius-web-application/src/locales/ru.json new file mode 100644 index 0000000000..dafcde703e --- /dev/null +++ b/packages/sirius-web/frontend/sirius-web-application/src/locales/ru.json @@ -0,0 +1,170 @@ +{ + "siriusWebApplication": { + "application": { + "details": "Свойства", + "explorer": "Навигатор", + "relatedElements": "Связанные элементы", + "representations": "Представления", + "validation": "Валидация" + }, + "core": { + "clickToSelectFile": "Кликните здесь для выбора файла" + }, + "navigationBar": { + "backToHomepage": "Вернуться на главную страницу" + }, + "project": { + "list": { + "blankProject": "Пустой проект", + "createNewProject": "Создать новый проект", + "delete": "Удалить", + "download": "Скачать", + "empty": "Проекты не найдены, начните работу с создания проекта", + "existingProjects": "Существующие проекты", + "more": "Больше", + "name": "Название", + "rename": "Переименовать", + "selectProjectTemplate": "Выберите шаблон проекта", + "showAllTemplates": "Показать все шаблоны", + "uploadProject": "Загрузить проект" + }, + "create": { + "title": "Создать проект", + "description": "Начните работу с создания нового проекта", + "name": { + "label": "Название", + "placeholder": "Укажите название проекта", + "helperText": "Название должно содержать от 3 до 1024 символов" + }, + "submit": "Создать" + }, + "upload": { + "title": "Загрузить проект", + "description": "Начните работу с существующим проектом", + "clickToSelectFile": "Кликните здесь для выбора файла", + "submit": "Загрузить" + }, + "rename": { + "title": "Переименовать проект", + "name": { + "label": "Название", + "placeholder": "Укажите новое название проекта", + "helperText": "Название обязательно и должно содержать менее 1024 символов" + }, + "submit": "Переименовать" + }, + "delete": { + "title": "Удалить проект \"{{name}}\"", + "content": "Это действие удалит всё содержимое проекта. Все данные и представления будут потеряны. Это не может быть отменено.", + "submit": "Удалить" + }, + "edit": { + "createModel": "Создать новую модель", + "createRepresentation": "Создать новое представление", + "delete": "Удалить", + "download": "Скачать", + "newModel": "Новая модель", + "noAccessToCreateModel": "Вам необходимы права на редактирование, чтобы создавать модели", + "noAccessToCreateRepresentation": "Вам необходимы права на редактирование, чтобы создавать представления", + "noRepresentations": "Для выбранных объектов нет представлений, которые могут быть созданы", + "openRepresentation": "Открыть существующее представление", + "rename": "Переименовать", + "selectModelToCreate": "Выберите модель для создания", + "selectRepresentationToCreate": "Выберите представление, которое необходимо создать для \"{{name}}\"", + "selectRepresentationToOpen": "Выберите представление, чтобы открыть его", + "settings": "Настройки", + "newObject": "Новый объект", + "newRepresentation": "Новое представление", + "uploadModel": "Загрузить модель" + } + }, + "model": { + "create": { + "title": "Создать новую модель", + "name": { + "label": "Название", + "placeholder": "Укажите название модели", + "helperText": "Название не может быть пустым" + }, + "modelType": { + "label": "Тип модели" + }, + "submit": "Создать" + }, + "upload": { + "title": "Загрузить новую модель", + "submit": "Загрузить", + "cancel": "Закрыть" + } + }, + "object": { + "newRoot": { + "title": "Создать новый корневой объект", + "domain": { + "label": "Предметная область" + }, + "type": { + "label": "Тип объекта" + }, + "suggestedType": { + "label": "Показывать только рекомендуемые типы" + }, + "submit": "Создать" + }, + "create": { + "title": "Создать новый объект", + "type": { + "label": "Тип объекта" + }, + "submit": "Создать" + } + }, + "representation": { + "create": { + "title": "Создать представление", + "name": { + "label": "Название", + "placeholder": "Укажите название представления", + "helperText": "Название не может быть пустым" + }, + "type": { + "label": "Тип представления" + }, + "submit": "Создать" + } + }, + "image": { + "list": { + "copyId": "Скопировать идентификатор в буфер обмена", + "delete": "Удалить", + "empty": "Изображений нет, начните работу с загрузки изображения", + "id": "Идентификатор", + "label": "Название", + "title": "Изображения для проекта", + "upload": "Загрузить" + }, + "upload": { + "title": "Загрузить новое изображение", + "label": { + "label": "Название", + "placeholder": "Название изображения" + }, + "submit": "Загрузить" + }, + "rename": { + "title": "Переименовать изображение", + "name": { + "label": "Название", + "placeholder": "Укажите название изображения", + "helperText": "Название должно содержать не менее 3 символов" + }, + "submit": "Переименовать" + }, + "delete": { + "title": "Удалить изображение", + "content": "Это действие удалит изображение и может нарушить работу проектов, использующих его. Это не может быть отменено.", + "submit": "Удалить" + } + } + } +} diff --git a/packages/sirius-web/frontend/sirius-web-application/src/modals/delete-project/DeleteProjectModal.tsx b/packages/sirius-web/frontend/sirius-web-application/src/modals/delete-project/DeleteProjectModal.tsx index 3e6658ef33..1e85b2b088 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/modals/delete-project/DeleteProjectModal.tsx +++ b/packages/sirius-web/frontend/sirius-web-application/src/modals/delete-project/DeleteProjectModal.tsx @@ -17,10 +17,13 @@ import DialogContent from '@material-ui/core/DialogContent'; import DialogContentText from '@material-ui/core/DialogContentText'; import DialogTitle from '@material-ui/core/DialogTitle'; import { useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { DeleteProjectModalProps } from './DeleteProjectModal.types'; import { useDeleteProject } from './useDeleteProject'; export const DeleteProjectModal = ({ project, onCancel, onSuccess }: DeleteProjectModalProps) => { + const { t } = useTranslation('siriusWebApplication', { keyPrefix: 'project.delete' }); + const { deleteProject, loading, projectDeleted } = useDeleteProject(); const onDeleteProject = (event: React.MouseEvent) => { @@ -36,12 +39,9 @@ export const DeleteProjectModal = ({ project, onCancel, onSuccess }: DeleteProje return ( - Delete the project "{project.name}" + {t('title', { name: project.name })} - - This action will delete everything in the project. All data and all representations will be lost. It cannot be - reversed. - + {t('content')} diff --git a/packages/sirius-web/frontend/sirius-web-application/src/modals/delete-project/useDeleteProject.ts b/packages/sirius-web/frontend/sirius-web-application/src/modals/delete-project/useDeleteProject.ts index 58056f77fa..3bde7e0b81 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/modals/delete-project/useDeleteProject.ts +++ b/packages/sirius-web/frontend/sirius-web-application/src/modals/delete-project/useDeleteProject.ts @@ -14,6 +14,7 @@ import { gql, useMutation } from '@apollo/client'; import { useMultiToast } from '@eclipse-sirius/sirius-components-core'; import { useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { GQLDeleteProjectMutationData, GQLDeleteProjectMutationVariables, @@ -43,9 +44,11 @@ export const useDeleteProject = (): UseDeleteProjectValue => { >(deleteProjectMutation); const { addErrorMessage, addMessages } = useMultiToast(); + const { t: coreT } = useTranslation('siriusComponentsCore'); + useEffect(() => { if (error) { - addErrorMessage('An unexpected error has occurred, please refresh the page'); + addErrorMessage(coreT('errors.unexpected')); } if (data) { const { deleteProject } = data; @@ -53,7 +56,7 @@ export const useDeleteProject = (): UseDeleteProjectValue => { addMessages(deleteProject.messages); } } - }, [data, error]); + }, [coreT, data, error]); const deleteProject = (projectId: string) => { const variables: GQLDeleteProjectMutationVariables = { diff --git a/packages/sirius-web/frontend/sirius-web-application/src/modals/new-document/NewDocumentModal.tsx b/packages/sirius-web/frontend/sirius-web-application/src/modals/new-document/NewDocumentModal.tsx index e7da1a380c..060a63afee 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/modals/new-document/NewDocumentModal.tsx +++ b/packages/sirius-web/frontend/sirius-web-application/src/modals/new-document/NewDocumentModal.tsx @@ -21,6 +21,7 @@ import Select from '@material-ui/core/Select'; import TextField from '@material-ui/core/TextField'; import { makeStyles } from '@material-ui/core/styles'; import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { NewDocumentModalProps, NewDocumentModalState } from './NewDocumentModal.types'; import { useCreateDocument } from './useCreateDocument'; import { useStereotypes } from './useStereotypes'; @@ -38,6 +39,7 @@ const useNewDocumentModalStyles = makeStyles((theme) => ({ export const NewDocumentModal = ({ editingContextId, onClose }: NewDocumentModalProps) => { const classes = useNewDocumentModalStyles(); + const { t } = useTranslation('siriusWebApplication', { keyPrefix: 'model.create' }); const [state, setState] = useState({ name: '', nameIsInvalid: true, @@ -84,23 +86,23 @@ export const NewDocumentModal = ({ editingContextId, onClose }: NewDocumentModal maxWidth="xs" fullWidth data-testid="create-new-model"> - Create a new model + {t('title')}
- Model type + {t('modelType.label')} - Create + {t('submit')} diff --git a/packages/sirius-web/frontend/sirius-web-application/src/modals/new-representation/NewRepresentationModal.tsx b/packages/sirius-web/frontend/sirius-web-application/src/modals/new-representation/NewRepresentationModal.tsx index d0c957912d..2ae8ee4589 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/modals/new-representation/NewRepresentationModal.tsx +++ b/packages/sirius-web/frontend/sirius-web-application/src/modals/new-representation/NewRepresentationModal.tsx @@ -25,6 +25,7 @@ import TextField from '@material-ui/core/TextField'; import { makeStyles } from '@material-ui/core/styles'; import { useMachine } from '@xstate/react'; import { useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { GQLCreateRepresentationMutationData, GQLCreateRepresentationPayload, @@ -110,13 +111,14 @@ export const NewRepresentationModal = ({ onClose, }: NewRepresentationModalProps) => { const classes = useNewRepresentationModalStyles(); + const { t } = useTranslation('siriusWebApplication', { keyPrefix: 'representation.create' }); + const { t: coreT } = useTranslation('siriusComponentsCore'); const [{ value, context }, dispatch] = useMachine( newRepresentationModalMachine ); const { newRepresentationModal, toast } = value as SchemaValue; const { name, - nameMessage, nameIsInvalid, selectedRepresentationDescriptionId, representationDescriptions, @@ -140,7 +142,7 @@ export const NewRepresentationModal = ({ if (representationDescriptionsError) { const showToastEvent: ShowToastEvent = { type: 'SHOW_TOAST', - message: 'An unexpected error has occurred, please refresh the page', + message: coreT('errors.unexpected'), }; dispatch(showToastEvent); } @@ -152,7 +154,13 @@ export const NewRepresentationModal = ({ dispatch(fetchRepresentationDescriptionsEvent); } } - }, [representationDescriptionsLoading, representationDescriptionsData, representationDescriptionsError, dispatch]); + }, [ + representationDescriptionsLoading, + representationDescriptionsData, + representationDescriptionsError, + dispatch, + coreT, + ]); const onNameChange = (event) => { const value = event.target.value; @@ -178,7 +186,7 @@ export const NewRepresentationModal = ({ if (createRepresentationError) { const showToastEvent: ShowToastEvent = { type: 'SHOW_TOAST', - message: 'An unexpected error has occurred, please refresh the page', + message: coreT('errors.unexpected'), }; dispatch(showToastEvent); } @@ -194,7 +202,7 @@ export const NewRepresentationModal = ({ } } } - }, [createRepresentationLoading, createRepresentationData, createRepresentationError, dispatch]); + }, [createRepresentationLoading, createRepresentationData, createRepresentationError, dispatch, coreT]); const onCreateRepresentation = () => { dispatch({ type: 'CREATE_REPRESENTATION' } as CreateRepresentationEvent); @@ -232,22 +240,22 @@ export const NewRepresentationModal = ({ return ( <> - Create a new representation + {t('title')}
- Representation type + {t('type.label')} ))} - Object type + {t('type.label')}