Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add automatic-translation extension for notes - EXO-65429 #47

Merged
merged 1 commit into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion webapps/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/exoplatform/automatic-translation"
},
"scripts": {
"lint": "eslint --fix \"./src/main/webapp/vue-apps/**\"",
"lint": "eslint --fix \"./src/main/webapp/vue-apps/**\" \"./src/main/webapp/javascript/**\"",
"watch": "webpack --config webpack.dev.js --progress --color --watch",
"build": "webpack --config webpack.prod.js --mode production"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
UIActivity.label.translate=Translate
automaticTranslation.hideTranslation=Hide translation
automaticTranslation.errorTranslation=Translation is not available for the moment
notes.automatic.translation.label=Automatic translation
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<template>
<v-chip
v-if="autoTranslatedContent"
small
close
:outlined="!isAutoTranslationSelected"
color="primary"
class="my-auto mx-1"
@click="setAutoTranslationSelected"
@click:close="resetAutoTranslation">
{{ $t('notes.automatic.translation.label') }}
</v-chip>
<v-btn
v-else
text
color="primary"
class="px-1 py-0 text-decoration-underline"
@click="autoTranslate">
{{ $t('UIActivity.label.translate') }}
</v-btn>
</template>

<script>

export default {
data() {
return {
isAutoTranslating: false,
isResetAutoTranslating: false,
autoTranslation: { value: 'autoTranslation', text: this.$t('notes.automatic.translation.label') },
previouslySelectedVersion: null,
autoTranslatedContent: null,
autoTranslatedTitle: null
};
},
props: {
note: {
type: Object,
default: null,
},
selectedTranslation: {
type: Object,
default: null,
},
},
watch: {
isAutoTranslating() {
this.toggleTopBarLoading(this.isAutoTranslating);
},
isResetAutoTranslating() {
this.toggleTopBarLoading(this.isResetAutoTranslating);
}
},
computed: {
isAutoTranslationSelected() {
return this.selectedTranslation?.value === this.autoTranslation?.value;
}
},
methods: {
autoTranslate() {
this.isAutoTranslating = true;
this.fetchAutoTranslation(this.note.title).then(translated => {
this.handleTranslatedTitle(translated.translation);
this.fetchAutoTranslation(this.note.content).then(translated => {
this.handleTranslatedContent(translated.translation);
});
});
},
setAutoTranslationSelected() {
if (!this.isAutoTranslationSelected && this.autoTranslatedTitle && this.autoTranslatedContent) {
this.handleTranslatedTitle(this.autoTranslatedTitle);
this.handleTranslatedContent(this.autoTranslatedContent);
this.updateSelectedTranslation(this.autoTranslation);
}
},
updateNoteContent(content) {
this.$root.$emit('update-note-content', content);
},
updateNoteTitle(title) {
this.$root.$emit('update-note-title', title);
},
updateSelectedTranslation(translation) {
this.$root.$emit('update-selected-translation', translation);
},
resetAutoTranslation() {
this.isResetAutoTranslating = true;
this.autoTranslatedContent = this.autoTranslatedTitle = null;
this.updateNoteTitle(this.note.title);
this.updateNoteContent(this.note.content);
this.updateSelectedTranslation(this.previouslySelectedVersion);
this.isResetAutoTranslating = false;
},
handleTranslatedTitle(translatedText) {
this.autoTranslatedTitle = translatedText;
this.updateNoteTitle(translatedText);
this.checkAutoTranslatedStatus();
},
handleTranslatedContent(translatedText) {
this.autoTranslatedContent = translatedText.replace('<p></p>', '<p>&nbsp;</p>');
this.updateNoteContent(this.autoTranslatedContent);
this.previouslySelectedVersion = this.selectedTranslation;
this.updateSelectedTranslation(this.autoTranslation);
this.checkAutoTranslatedStatus();
},
checkAutoTranslatedStatus() {
if (this.autoTranslatedTitle && this.autoTranslatedContent) {
this.isAutoTranslating = false;
}
},
toggleTopBarLoading(loading) {
if (loading) {
document.dispatchEvent(new CustomEvent('displayTopBarLoading'));
} else {
document.dispatchEvent(new CustomEvent('hideTopBarLoading'));
}
},
fetchAutoTranslation(content) {
const data = `message=${ encodeURIComponent(content) }&locale=${ eXo.env.portal.language}`;
return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/automatic-translation/translate`, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
method: 'POST',
body: data
}).then(resp => {
if (resp?.ok) {
return resp.json();
} else {
throw new Error('Unable to get automatic translation result');
}
});
}
}
};
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,23 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
(function(extensionRegistry,exoi18n) {
(function(extensionRegistry,exoi18n) {


function getTranslatedBody(activity) {
return activity.translatedBody;
}

function fetchTranslation(content, event) {
let data = 'message='+encodeURIComponent(content)+'&locale='+eXo.env.portal.language;
let data = `message=${encodeURIComponent(content)}&locale=${eXo.env.portal.language}`;
if (event?.type) {
data += '&contentType='+event.type;
data += `&contentType=${event.type}`;
}
if (event?.spaceId) {
data += '&spaceId='+event.spaceId;
data += `&spaceId=${event.spaceId}`;
}
return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/automatic-translation/translate`, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
'Content-Type': 'application/x-www-form-urlencoded'
},
method: 'POST',
body: data
Expand All @@ -46,7 +45,7 @@
}

function dispatchError(event) {
document.dispatchEvent(new CustomEvent('activity-translation-error',{ detail:event }));
document.dispatchEvent(new CustomEvent('activity-translation-error',{ detail: event }));
}

function initExtensions() {
Expand All @@ -56,7 +55,7 @@
extensionRegistry.registerExtension('activity', 'action', {
id: 'translate',
rank: 9007199254740992,
isEnabled: (activity, activityTypeExtension) => true,
isEnabled: () => true,
labelKey: 'UIActivity.label.translate',
icon: 'fa-globe-americas',
click: (activity, activityTypeExtension) => {
Expand All @@ -69,17 +68,17 @@
fetchTranslation(activityTypeExtension.getBody(activity),event).then(translated => {
activity.translatedBody = translated.translation;
activityTypeExtension.getTranslatedBody = getTranslatedBody;
document.dispatchEvent(new CustomEvent('activity-translated',{ detail:event }));
document.dispatchEvent(new CustomEvent('activity-translated',{ detail: event }));
});
} else {
document.dispatchEvent(new CustomEvent('activity-translated',{ detail:event }));
document.dispatchEvent(new CustomEvent('activity-translated',{ detail: event }));
}
},
});
extensionRegistry.registerExtension('activity', 'comment-action', {
id: 'translate',
rank: 9007199254740992,
isEnabled: (activity, comment, activityTypeExtension) => true,
isEnabled: () => true,
labelKey: 'UIActivity.label.translate',
icon: 'fa-globe-americas',
click: (activity, comment, activityTypeExtension) => {
Expand All @@ -92,23 +91,19 @@
fetchTranslation(activityTypeExtension.getBody(comment),event).then(translated => {
comment.translatedBody = translated.translation;
activityTypeExtension.getCommentTranslatedBody = getTranslatedBody;
document.dispatchEvent(new CustomEvent('activity-comment-translated',{ detail:event }));
document.dispatchEvent(new CustomEvent('activity-comment-translated',{ detail: event }));
});
} else {
document.dispatchEvent(new CustomEvent('activity-comment-translated',{ detail:event }));
document.dispatchEvent(new CustomEvent('activity-comment-translated',{ detail: event }));
}
},
});

extensionRegistry.registerExtension('notes', 'translation-menu-extension', {
id: 'auto-translate',
rank: 1000,
isEnabled: () => true,
labelKey: 'UIActivity.label.translate',
translate: (message, callback) => {
fetchTranslation(message).then(translated => {
callback(translated.translation);
});
componentOptions: {
vueComponent: Vue.options.components['note-automatic-translation'],
},
});

Expand All @@ -131,7 +126,7 @@
init: () => {
fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/automatic-translation/isEnabled`, {
headers: {
'Content-Type': 'application/json'
'Content-Type': 'application/json'
},
method: 'GET'
}).then(resp => {
Expand All @@ -141,7 +136,7 @@
throw new Error('Unable to get automatic translation configuration');
}
}).then(result => {
if (result === "true") {
if (result === 'true') {
initExtensions();
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
*/
import ActivityTranslatedBody from './components/ActivityTranslatedBody.vue';
import ActivityCommentTranslatedBody from './components/ActivityCommentTranslatedBody.vue';
import NoteAutomaticTranslation from './components/NoteAutomaticTranslation.vue';

const components = {
'activity-translated-body': ActivityTranslatedBody,
'activity-comment-translated-body': ActivityCommentTranslatedBody,
'note-automatic-translation': NoteAutomaticTranslation
};

for (const key in components) {
Expand Down