Skip to content

Commit

Permalink
feat: Add automatic-translation extension for notes - EXO-65429 (#47)
Browse files Browse the repository at this point in the history
Add automatic-translation extension for notes
  • Loading branch information
hakermi authored and exo-swf committed Oct 20, 2023
1 parent fdb6cd4 commit 38a5695
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 22 deletions.
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

0 comments on commit 38a5695

Please sign in to comment.