first commit

This commit is contained in:
2024-11-05 12:22:50 +01:00
commit e5682a3912
19641 changed files with 2948548 additions and 0 deletions

View File

@@ -0,0 +1,175 @@
<!--**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*-->
<template>
<div
v-if="isReady"
id="app"
class="translations-app"
>
<div class="container-fluid">
<div class="row justify-content-between align-items-center">
<Search @search="onSearch" />
<div class="translations-summary">
<span>{{ totalTranslations }}</span>
<span v-show="totalMissingTranslations">
-
<span class="missing">{{ totalMissingTranslationsString }}</span>
</span>
</div>
</div>
<div class="row">
<Sidebar
:modal="this.$refs.transModal"
:principal="this.$refs.principal"
/>
<Principal
:modal="this.$refs.transModal"
ref="principal"
/>
</div>
</div>
<PSModal
ref="transModal"
:translations="translations"
/>
</div>
</template>
<script>
import Search from '@app/pages/translations/components/header/search';
import Sidebar from '@app/pages/translations/components/sidebar';
import Principal from '@app/pages/translations/components/principal';
import PSModal from '@app/widgets/ps-modal';
export default {
name: 'App',
computed: {
isReady() {
return this.$store.getters.isReady;
},
totalTranslations() {
return this.$store.state.totalTranslations <= 1
? this.trans('label_total_domain_singular')
.replace('%nb_translation%', this.$store.state.totalTranslations)
: this.trans('label_total_domain')
.replace('%nb_translations%', this.$store.state.totalTranslations);
},
totalMissingTranslations() {
return this.$store.state.totalMissingTranslations;
},
totalMissingTranslationsString() {
return this.totalMissingTranslations === 1
? this.trans('label_missing_singular')
: this.trans('label_missing').replace('%d', this.totalMissingTranslations);
},
translations() {
return {
button_save: this.trans('button_save'),
button_leave: this.trans('button_leave'),
modal_content: this.trans('modal_content'),
modal_title: this.trans('modal_title'),
};
},
},
mounted() {
$('a').on('click', (e) => {
if ($(e.currentTarget).attr('href')) {
this.destHref = $(e.currentTarget).attr('href');
}
});
window.onbeforeunload = () => {
if (!this.destHref && this.isEdited() && !this.leave) {
return true;
}
if (!this.leave && this.isEdited()) {
setTimeout(() => {
window.stop();
}, 500);
this.$refs.transModal.showModal();
this.$refs.transModal.$once('save', () => {
this.$refs.principal.saveTranslations();
this.leavePage();
});
this.$refs.transModal.$once('leave', () => {
this.leavePage();
});
return null;
}
return undefined;
};
},
methods: {
onSearch() {
this.$store.dispatch('getDomainsTree', {
store: this.$store,
});
this.$store.currentDomain = '';
},
/**
* Set leave to true and redirect the user to the new location
*/
leavePage() {
this.leave = true;
window.location.href = this.destHref;
},
isEdited() {
return this.$refs.principal.edited();
},
},
data: () => ({
destHref: null,
leave: false,
}),
components: {
Search,
Sidebar,
Principal,
PSModal,
},
};
</script>
<style lang="scss" type="text/scss">
@import '~@scss/config/_settings.scss';
.flex {
display: flex;
align-items: center;
}
.missing {
color: $danger;
}
.translations-summary {
font-weight: $font-weight-semibold;
font-size: 1rem;
}
</style>

View File

@@ -0,0 +1,87 @@
<!--**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*-->
<template>
<div
id="search"
class="col-md-8 mb-4"
>
<form
class="search-form"
@submit.prevent
>
<label>{{ trans('search_label') }}</label>
<div class="input-group">
<PSTags
ref="psTags"
:tags="tags"
@tagChange="onSearch"
:placeholder="trans('search_placeholder')"
/>
<div class="input-group-append">
<PSButton
@click="onClick"
class="search-button"
:primary="true"
>
<i class="material-icons">search</i>
{{ trans('button_search') }}
</PSButton>
</div>
</div>
</form>
</div>
</template>
<script>
import PSTags from '@app/widgets/ps-tags';
import PSButton from '@app/widgets/ps-button';
export default {
components: {
PSTags,
PSButton,
},
methods: {
onClick() {
const {tag} = this.$refs.psTags;
this.$refs.psTags.add(tag);
},
onSearch() {
this.$store.dispatch('updateSearch', this.tags);
this.$emit('search', this.tags);
},
},
watch: {
$route() {
this.tags = [];
},
},
data() {
return {
tags: [],
};
},
};
</script>

View File

@@ -0,0 +1,319 @@
<!--**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*-->
<template>
<transition name="fade">
<div
class="col-sm-9 card"
v-if="principalReady"
>
<div class="p-3 translations-wrapper">
<PSAlert
v-if="noResult"
alert-type="ALERT_TYPE_WARNING"
:has-close="false"
>
{{ noResultInfo }}
</PSAlert>
<div
class="translations-catalog row p-0"
v-else
>
<PSAlert
v-if="searchActive"
class="col-sm-12"
alert-type="ALERT_TYPE_INFO"
:has-close="false"
>
{{ searchInfo }}
</PSAlert>
<div class="col-sm-8 pt-3">
<h3 class="domain-info">
<span>{{ currentDomain }}</span>
<span>{{ currentDomainTotalTranslations }}</span>
<span
v-show="currentDomainTotalMissingTranslations"
> - <span class="missing">{{ currentDomainTotalMissingTranslationsString }}</span></span>
</h3>
</div>
<div class="col-sm-4">
<PSPagination
:current-index="currentPagination"
:pages-count="pagesCount"
class="float-sm-right"
@pageChanged="onPageChanged"
/>
</div>
<form
class="col-sm-12"
method="post"
:action="saveAction"
:isEdited="isEdited"
@submit.prevent="saveTranslations"
>
<div class="row">
<div class="col-sm-12 mb-2">
<PSButton
:primary="true"
type="submit"
class="float-sm-right"
>
{{ trans('button_save') }}
</PSButton>
</div>
</div>
<TranslationInput
v-for="(translation, key) in translationsCatalog"
:key="key"
:id="key"
:translated="translation"
:label="translation.default"
:extra-info="getDomain(translation.tree_domain)"
@editedAction="isEdited"
/>
<div class="row">
<div class="col-sm-12">
<PSButton
:primary="true"
type="submit"
class="float-sm-right mt-3"
>
{{ trans('button_save') }}
</PSButton>
</div>
</div>
</form>
<div class="col-sm-12">
<PSPagination
:current-index="currentPagination"
:pages-count="pagesCount"
@pageChanged="onPageChanged"
/>
</div>
</div>
</div>
</div>
</transition>
</template>
<script>
import PSButton from '@app/widgets/ps-button';
import PSPagination from '@app/widgets/ps-pagination';
import PSAlert from '@app/widgets/ps-alert';
import {EventBus} from '@app/utils/event-bus';
import TranslationInput from './translation-input';
export default {
props: {
modal: {
type: Object,
required: false,
default: () => ({}),
},
},
data: () => ({
originalTranslations: [],
modifiedTranslations: [],
}),
computed: {
principalReady() {
return !this.$store.state.principalLoading;
},
translationsCatalog() {
return this.$store.getters.catalog.data.data;
},
saveAction() {
return this.$store.getters.catalog.data.info ? this.$store.getters.catalog.data.info.edit_url : '';
},
resetAction() {
return this.$store.getters.catalog.data.info ? this.$store.getters.catalog.data.info.reset_url : '';
},
pagesCount() {
return this.$store.getters.totalPages;
},
currentPagination() {
return this.$store.getters.pageIndex;
},
currentDomain() {
return this.$store.state.currentDomain;
},
currentDomainTotalTranslations() {
/* eslint-disable max-len */
return (this.$store.state.currentDomainTotalTranslations <= 1)
? `- ${this.trans('label_total_domain_singular').replace('%nb_translation%', this.$store.state.currentDomainTotalTranslations)}`
: `- ${this.trans('label_total_domain').replace('%nb_translations%', this.$store.state.currentDomainTotalTranslations)}`;
/* eslint-enable max-len */
},
currentDomainTotalMissingTranslations() {
return this.$store.state.currentDomainTotalMissingTranslations;
},
currentDomainTotalMissingTranslationsString() {
let totalMissingTranslationsString = '';
if (this.currentDomainTotalMissingTranslations) {
if (this.currentDomainTotalMissingTranslations === 1) {
totalMissingTranslationsString = this.trans('label_missing_singular');
} else {
totalMissingTranslationsString = this.trans('label_missing')
.replace('%d', this.currentDomainTotalMissingTranslations);
}
}
return totalMissingTranslationsString;
},
noResult() {
return (this.$store.getters.currentDomain === '' || typeof this.$store.getters.currentDomain === 'undefined');
},
noResultInfo() {
return this.trans('no_result').replace('%s', this.$store.getters.searchTags.join(' - '));
},
searchActive() {
return this.$store.getters.searchTags.length;
},
searchInfo() {
const transKey = (this.$store.state.totalTranslations <= 1) ? 'search_info_singular' : 'search_info';
return this.trans(transKey)
.replace('%s', this.$store.getters.searchTags.join(' - '))
.replace('%d', this.$store.state.totalTranslations);
},
},
methods: {
/**
* Dispatch the event to change the page index,
* get the translations and reset the modified translations into the state
* @param {Number} pageIndex
*/
changePage: function changePage(pageIndex) {
this.$store.dispatch('updatePageIndex', pageIndex);
this.fetch();
this.$store.state.modifiedTranslations = [];
},
isEdited(input) {
if (input.translation.edited) {
this.$store.state.modifiedTranslations[input.id] = input.translation;
} else {
this.$store.state.modifiedTranslations.splice(
this.$store.state.modifiedTranslations.indexOf(input.id),
1,
);
}
},
onPageChanged(pageIndex) {
if (this.edited()) {
this.modal.showModal();
this.modal.$once('save', () => {
this.saveTranslations();
this.changePage(pageIndex);
});
this.modal.$once('leave', () => {
this.changePage(pageIndex);
});
} else {
this.changePage(pageIndex);
}
},
fetch() {
this.$store.dispatch('getCatalog', {
url: this.$store.getters.catalog.info.current_url_without_pagination,
page_size: this.$store.state.translationsPerPage,
page_index: this.$store.getters.pageIndex,
});
},
getDomain(domains) {
let domain = '';
domains.forEach((d) => {
domain += `${d} > `;
});
return domain.slice(0, -3);
},
saveTranslations() {
const modifiedTranslations = this.getModifiedTranslations();
if (modifiedTranslations.length) {
this.$store.dispatch('saveTranslations', {
url: this.saveAction,
translations: this.getModifiedTranslations(),
store: this.$store,
});
}
},
getModifiedTranslations() {
this.modifiedTranslations = [];
const targetTheme = (window.data.type === 'modules') ? '' : window.data.selected;
Object.values(this.$store.state.modifiedTranslations).forEach((translation) => {
this.modifiedTranslations.push({
default: translation.default,
edited: translation.edited,
domain: translation.tree_domain.join(''),
locale: window.data.locale,
theme: targetTheme,
});
});
return this.modifiedTranslations;
},
edited() {
return Object.keys(this.$store.state.modifiedTranslations).length > 0;
},
},
mounted() {
EventBus.$on('resetTranslation', (el) => {
const translations = [];
translations.push({
default: el.default,
domain: el.tree_domain.join(''),
locale: window.data.locale,
theme: window.data.selected,
});
this.$store.dispatch('resetTranslation', {
url: this.resetAction,
translations,
});
});
},
components: {
TranslationInput,
PSButton,
PSPagination,
PSAlert,
},
};
</script>
<style lang="scss" scoped>
@import '~@scss/config/_settings.scss';
.fade-enter-active, .fade-leave-active {
transition: opacity .5s
}
.fade-enter, .fade-leave-to /* .fade-leave-active in <2.1.8 */ {
opacity: 0
}
</style>

View File

@@ -0,0 +1,113 @@
<!--**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*-->
<template>
<div class="form-group">
<label>{{ label }}</label>
<textarea
class="form-control"
rows="2"
v-model="getTranslated"
:class="{ missing : isMissing }"
/>
<PSButton
class="mt-3 float-sm-right"
:primary="false"
ghost
@click="resetTranslation"
>
{{ trans('button_reset') }}
</PSButton>
<small class="mt-3">{{ extraInfo }}</small>
</div>
</template>
<script>
import PSButton from '@app/widgets/ps-button';
import {EventBus} from '@app/utils/event-bus';
export default {
name: 'TranslationInput',
props: {
id: {
type: Number,
required: false,
default: 0,
},
extraInfo: {
type: String,
required: false,
default: '',
},
label: {
type: String,
required: true,
},
translated: {
type: Object,
required: true,
},
},
computed: {
getTranslated: {
get() {
return this.translated.user ? this.translated.user : this.translated.project;
},
set(modifiedValue) {
const modifiedTranslated = this.translated;
modifiedTranslated.user = modifiedValue;
modifiedTranslated.edited = modifiedValue;
this.$emit('input', modifiedTranslated);
this.$emit('editedAction', {
translation: modifiedTranslated,
id: this.id,
});
},
},
isMissing() {
return this.getTranslated === null;
},
},
methods: {
resetTranslation() {
this.getTranslated = '';
EventBus.$emit('resetTranslation', this.translated);
},
},
components: {
PSButton,
},
};
</script>
<style lang="scss" scoped>
@import '~@scss/config/_settings.scss';
.form-group {
overflow: hidden;
}
.missing {
border: 1px solid $danger;
}
</style>

View File

@@ -0,0 +1,231 @@
<!--**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*-->
<template>
<div class="col-sm-3">
<div class="card p-3">
<PSTree
ref="domainTree"
:model="domainsTree"
class-name="translationTree"
:translations="translations"
:current-item="currentItem"
v-if="treeReady"
/>
<PSSpinner v-else />
</div>
</div>
</template>
<script>
import PSTree from '@app/widgets/ps-tree/ps-tree';
import PSSpinner from '@app/widgets/ps-spinner';
import {EventBus} from '@app/utils/event-bus';
export default {
props: {
modal: {
type: Object,
required: false,
default: () => ({}),
},
principal: {
type: Object,
required: false,
default: () => ({}),
},
},
computed: {
treeReady() {
return !this.$store.state.sidebarLoading;
},
currentItem() {
if (this.$store.getters.currentDomain === '' || typeof this.$store.getters.currentDomain === 'undefined') {
if (this.domainsTree.length) {
const domain = this.getFirstDomainToDisplay(this.domainsTree);
EventBus.$emit('reduce');
this.$store.dispatch('updateCurrentDomain', domain);
if (domain !== '') {
this.$store.dispatch('getCatalog', {url: domain.dataValue});
EventBus.$emit('setCurrentElement', domain.full_name);
return domain.full_name;
}
this.$store.dispatch('updatePrincipalLoading', false);
return '';
}
}
return this.$store.getters.currentDomain;
},
domainsTree() {
return this.$store.getters.domainsTree;
},
translations() {
return {
expand: this.trans('sidebar_expand'),
reduce: this.trans('sidebar_collapse'),
extra: this.trans('label_missing'),
extra_singular: this.trans('label_missing_singular'),
};
},
},
mounted() {
this.$store.dispatch('getDomainsTree', {
store: this.$store,
});
EventBus.$on('lastTreeItemClick', (el) => {
if (this.edited()) {
this.modal.showModal();
this.modal.$once('save', () => {
this.principal.saveTranslations();
this.itemClick(el);
});
this.modal.$once('leave', () => {
this.itemClick(el);
});
} else {
this.itemClick(el);
}
});
},
methods: {
/**
* Update the domain, retrieve the translations catalog, set the page to 1
* and reset the modified translations
* @param {object} el - Domain to set
*/
itemClick: function itemClick(el) {
this.$store.dispatch('updateCurrentDomain', el.item);
this.$store.dispatch('getCatalog', {url: el.item.dataValue});
this.$store.dispatch('updatePageIndex', 1);
this.$store.state.modifiedTranslations = [];
},
getFirstDomainToDisplay: function getFirstDomainToDisplay(tree) {
const keys = Object.keys(tree);
let toDisplay = '';
for (let i = 0; i < tree.length; i += 1) {
if (!tree[keys[i]].disable) {
if (tree[keys[i]].children && tree[keys[i]].children.length > 0) {
return getFirstDomainToDisplay(tree[keys[i]].children);
}
toDisplay = tree[keys[i]];
break;
}
}
return toDisplay;
},
/**
* Check if some translations have been edited
* @returns {boolean}
*/
edited: function edited() {
return Object.keys(this.$store.state.modifiedTranslations).length > 0;
},
},
components: {
PSTree,
PSSpinner,
},
};
</script>
<style lang="scss" type="text/scss">
@import '~@scss/config/_settings.scss';
.translationTree {
.tree-name {
margin-bottom: .9375rem;
&.active {
font-weight: bold;
}
&.extra {
color: $danger;
}
}
.tree-extra-label {
color: $danger;
text-transform: uppercase;
font-size: .65rem;
margin-left: auto;
}
.tree-extra-label-mini {
background-color: $danger;
color: #ffffff;
padding: 0 0.5rem;
border-radius: 0.75rem;
display: inline-block;
font-size: .75rem;
height: 1.5rem;
margin-left: auto;
}
.tree-label {
&:hover {
color: $primary;
}
}
}
.ps-loader {
$loader-white-height: 20px;
$loader-line-height: 16px;
.animated-background {
height: 144px!important;
animation-duration: 2s!important;
}
.background-masker {
&.header-left {
left: 0;
top: $loader-line-height;
height: 108px;
width: 20px;
}
&.content-top {
left: 0;
top: $loader-line-height;
height: $loader-white-height;
}
&.content-first-end {
left: 0;
top: $loader-line-height*2+$loader-white-height;
height: $loader-white-height;
}
&.content-second-end {
left: 0;
top: $loader-line-height*3+$loader-white-height*2;
height: $loader-white-height;
}
&.content-third-end {
left: 0;
top: $loader-line-height*4+$loader-white-height*3;
height: $loader-white-height;
}
}
}
</style>

View File

@@ -0,0 +1,42 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
import Vue from 'vue';
import app from './components/app';
import store from './store';
import router from './router';
import Translation from './mixins/translate';
Vue.mixin(Translation);
new Vue({
router,
store,
el: '#translations-app',
template: '<app />',
components: {app},
beforeMount() {
this.$store.dispatch('getTranslations');
},
});

View File

@@ -0,0 +1,31 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
export default {
methods: {
trans(key) {
return this.$store.getters.translations[key];
},
},
};

View File

@@ -0,0 +1,41 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
import Vue from 'vue';
import VueRouter from 'vue-router';
import Overview from '@app/pages/translations/components/app';
Vue.use(VueRouter);
export default new VueRouter({
mode: 'history',
base: `${window.data.baseUrl}/translations`,
routes: [
{
path: '/',
name: 'overview',
component: Overview,
},
],
});

View File

@@ -0,0 +1,172 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
import Vue from 'vue';
import VueResource from 'vue-resource';
import * as types from '@app/pages/translations/store/mutation-types';
import {showGrowl} from '@app/utils/growl';
Vue.use(VueResource);
export const getTranslations = ({commit}) => {
const url = window.data.translationUrl;
Vue.http.get(url).then(
(response) => {
commit(types.SET_TRANSLATIONS, response.body);
commit(types.APP_IS_READY);
},
(error) => {
showGrowl('error', error.bodyText ? JSON.parse(error.bodyText).error : error.statusText);
},
);
};
export const getCatalog = ({commit}, payload) => {
commit(types.PRINCIPAL_LOADING, true);
Vue.http
.get(payload.url, {
params: {
page_size: payload.page_size,
page_index: payload.page_index,
},
})
.then(
(response) => {
commit(types.SET_TOTAL_PAGES, response.headers.get('Total-Pages'));
commit(types.SET_CATALOG, response.body);
commit(types.PRINCIPAL_LOADING, false);
},
(error) => {
showGrowl('error', error.bodyText ? JSON.parse(error.bodyText).error : error.statusText);
},
);
};
export const getDomainsTree = ({commit}, payload) => {
const url = window.data.domainsTreeUrl;
const params = {};
commit(types.SIDEBAR_LOADING, true);
commit(types.PRINCIPAL_LOADING, true);
if (payload.store.getters.searchTags.length) {
params.search = payload.store.getters.searchTags;
}
Vue.http
.get(url, {
params,
})
.then(
(response) => {
commit(types.SET_DOMAINS_TREE, response.body);
commit(types.SIDEBAR_LOADING, false);
commit(types.RESET_CURRENT_DOMAIN);
},
(error) => {
showGrowl('error', error.bodyText ? JSON.parse(error.bodyText).error : error.statusText);
},
);
};
export const refreshCounts = ({commit}, payload) => {
const url = window.data.domainsTreeUrl;
const params = {};
if (payload.store.getters.searchTags.length) {
params.search = payload.store.getters.searchTags;
}
Vue.http
.get(url, {
params,
})
.then(
(response) => {
commit(types.DECREASE_CURRENT_DOMAIN_TOTAL_MISSING_TRANSLATIONS, payload.successfullySaved);
commit(types.SET_DOMAINS_TREE, response.body);
},
(error) => {
showGrowl('error', error.bodyText ? JSON.parse(error.bodyText).error : error.statusText);
},
);
};
export const saveTranslations = ({commit}, payload) => {
const {url} = payload;
const {translations} = payload;
Vue.http
.post(url, {
translations,
})
.then(
() => {
payload.store.dispatch('refreshCounts', {
successfullySaved: translations.length,
store: payload.store,
});
commit(types.RESET_MODIFIED_TRANSLATIONS);
return showGrowl('success', 'Translations successfully updated');
},
(error) => {
showGrowl('error', error.bodyText ? JSON.parse(error.bodyText).error : error.statusText);
},
);
};
/* eslint-disable-next-line no-unused-vars */
export const resetTranslation = ({commit}, payload) => {
const {url} = payload;
const {translations} = payload;
Vue.http
.post(url, {
translations,
})
.then(
() => {
showGrowl('success', 'Translations successfully reset');
},
(error) => {
showGrowl('error', error.bodyText ? JSON.parse(error.bodyText).error : error.statusText);
},
);
};
export const updatePageIndex = ({commit}, pageIndex) => {
commit(types.SET_PAGE_INDEX, pageIndex);
};
export const updateCurrentDomain = ({commit}, currentDomain) => {
commit(types.SET_CURRENT_DOMAIN, currentDomain);
};
export const updatePrincipalLoading = ({commit}, principalLoading) => {
commit(types.PRINCIPAL_LOADING, principalLoading);
};
export const updateSearch = ({commit}, searchTags) => {
commit(types.SEARCH_TAGS, searchTags);
};

View File

@@ -0,0 +1,108 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
import Vue from 'vue';
import Vuex from 'vuex';
import _ from 'lodash';
import * as actions from './actions';
import mutations from './mutations';
Vue.use(Vuex);
// root state object.
const state = {
pageIndex: 1,
totalPages: 0,
translationsPerPage: 20,
currentDomain: '',
translations: {
data: {},
info: {},
},
catalog: {
data: {},
info: {},
},
domainsTree: [],
totalMissingTranslations: 0,
totalTranslations: 0,
currentDomainTotalTranslations: 0,
currentDomainTotalMissingTranslations: 0,
isReady: false,
sidebarLoading: true,
principalLoading: true,
searchTags: [],
modifiedTranslations: [],
};
// getters are functions
const getters = {
totalPages(rootState) {
return rootState.totalPages;
},
pageIndex(rootState) {
return rootState.pageIndex;
},
currentDomain(rootState) {
return rootState.currentDomain;
},
translations(rootState) {
return rootState.translations;
},
catalog(rootState) {
return rootState.catalog;
},
domainsTree() {
function convert(domains) {
domains.forEach((domain) => {
domain.children = _.values(domain.children);
domain.extraLabel = domain.total_missing_translations;
domain.dataValue = domain.domain_catalog_link;
domain.warning = Boolean(domain.total_missing_translations);
domain.disable = !domain.total_translations;
domain.id = domain.full_name;
convert(domain.children);
});
return domains;
}
return convert(state.domainsTree);
},
isReady(rootState) {
return rootState.isReady;
},
searchTags(rootState) {
return rootState.searchTags;
},
};
// A Vuex instance is created by combining the state, mutations, actions,
// and getters.
export default new Vuex.Store({
state,
getters,
actions,
mutations,
});

View File

@@ -0,0 +1,37 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
export const SET_TRANSLATIONS = 'SET_TRANSLATIONS';
export const SET_CATALOG = 'SET_CATALOG';
export const SET_DOMAINS_TREE = 'SET_DOMAINS_TREE';
export const APP_IS_READY = 'APP_IS_READY';
export const SET_TOTAL_PAGES = 'SET_TOTAL_PAGES';
export const SET_PAGE_INDEX = 'SET_PAGE_INDEX';
export const SET_CURRENT_DOMAIN = 'SET_CURRENT_DOMAIN';
export const RESET_CURRENT_DOMAIN = 'RESET_CURRENT_DOMAIN';
export const SIDEBAR_LOADING = 'SIDEBAR_LOADING';
export const PRINCIPAL_LOADING = 'PRINCIPAL_LOADING';
export const SEARCH_TAGS = 'SEARCH_TAGS';
export const DECREASE_CURRENT_DOMAIN_TOTAL_MISSING_TRANSLATIONS = 'DECREASE_CURRENT_DOMAIN_TOTAL_MISSING_TRANSLATIONS';
export const RESET_MODIFIED_TRANSLATIONS = 'RESET_MODIFIED_TRANSLATIONS';

View File

@@ -0,0 +1,76 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
import * as types from './mutation-types';
export default {
[types.SET_TRANSLATIONS](state, translations) {
translations.data.forEach((t) => {
state.translations[t.translation_id] = t.name;
});
},
[types.SET_CATALOG](state, catalog) {
state.catalog = catalog;
},
[types.SET_DOMAINS_TREE](state, domainsTree) {
state.totalMissingTranslations = domainsTree.data.tree.total_missing_translations;
state.totalTranslations = domainsTree.data.tree.total_translations;
state.domainsTree = domainsTree.data.tree.children;
},
[types.APP_IS_READY](state) {
state.isReady = true;
},
[types.SET_TOTAL_PAGES](state, totalPages) {
state.totalPages = Number(totalPages);
},
[types.SET_PAGE_INDEX](state, pageIndex) {
state.pageIndex = pageIndex;
},
[types.SET_CURRENT_DOMAIN](state, currentDomain) {
state.currentDomain = currentDomain.full_name;
state.currentDomainTotalTranslations = currentDomain.total_translations;
state.currentDomainTotalMissingTranslations = currentDomain.total_missing_translations;
},
[types.RESET_CURRENT_DOMAIN](state) {
state.currentDomain = '';
state.currentDomainTotalTranslations = 0;
state.currentDomainTotalMissingTranslations = 0;
},
[types.SIDEBAR_LOADING](state, isLoading) {
state.sidebarLoading = isLoading;
},
[types.PRINCIPAL_LOADING](state, isLoading) {
state.principalLoading = isLoading;
},
[types.SEARCH_TAGS](state, searchTags) {
state.searchTags = searchTags;
},
[types.DECREASE_CURRENT_DOMAIN_TOTAL_MISSING_TRANSLATIONS](state, successfullySaved) {
state.currentDomainTotalMissingTranslations -= successfullySaved;
},
[types.RESET_MODIFIED_TRANSLATIONS](state) {
state.modifiedTranslations = [];
},
};