lesli_babel 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Rakefile +5 -0
- data/app/assets/config/lesli_babel_manifest.js +7 -0
- data/app/assets/images/lesli_babel/babel-logo.svg +157 -0
- data/app/assets/javascripts/lesli_babel/application.js +3288 -0
- data/app/assets/stylesheets/lesli_babel/application.scss +41 -0
- data/app/assets/stylesheets/lesli_babel/dashboards.scss +55 -0
- data/app/assets/stylesheets/lesli_babel/modules.scss +33 -0
- data/app/assets/stylesheets/lesli_babel/translations.scss +58 -0
- data/app/controllers/lesli_babel/application_controller.rb +37 -0
- data/app/controllers/lesli_babel/buckets_controller.rb +79 -0
- data/app/controllers/lesli_babel/clones_controller.rb +80 -0
- data/app/controllers/lesli_babel/dashboards_controller.rb +38 -0
- data/app/controllers/lesli_babel/modules_controller.rb +91 -0
- data/app/controllers/lesli_babel/relevants_controller.rb +38 -0
- data/app/controllers/lesli_babel/strings_controller.rb +142 -0
- data/app/controllers/lesli_babel/translations_controller.rb +134 -0
- data/app/jobs/lesli_babel/application_job.rb +7 -0
- data/app/mailers/lesli_babel/application_mailer.rb +6 -0
- data/app/models/lesli_babel/application_record.rb +36 -0
- data/app/models/lesli_babel/bucket.rb +6 -0
- data/app/models/lesli_babel/clone.rb +24 -0
- data/app/models/lesli_babel/dashboard.rb +35 -0
- data/app/models/lesli_babel/module.rb +35 -0
- data/app/models/lesli_babel/relevant.rb +21 -0
- data/app/models/lesli_babel/string/activity.rb +5 -0
- data/app/models/lesli_babel/string/discussion.rb +68 -0
- data/app/models/lesli_babel/string.rb +225 -0
- data/app/models/lesli_babel/translation.rb +5 -0
- data/app/services/lesli_babel/module_service.rb +18 -0
- data/app/services/lesli_babel/old/translations_android_service.rb +82 -0
- data/app/services/lesli_babel/old/translations_clone_service.rb +161 -0
- data/app/services/lesli_babel/old/translations_flutter_service.rb +102 -0
- data/app/services/lesli_babel/old/translations_ios_service.rb +119 -0
- data/app/services/lesli_babel/old/translations_js_service.rb +114 -0
- data/app/services/lesli_babel/old/translations_middleman_service.rb +77 -0
- data/app/services/lesli_babel/old/translations_rails_service.rb +119 -0
- data/app/services/lesli_babel/old/translations_service.rb +97 -0
- data/app/services/lesli_babel/old/translations_synchronization_service.rb +215 -0
- data/app/services/lesli_babel/string_service.rb +80 -0
- data/app/views/lesli_babel/buckets/_form.html.erb +17 -0
- data/app/views/lesli_babel/buckets/edit.html.erb +6 -0
- data/app/views/lesli_babel/buckets/index.html.erb +25 -0
- data/app/views/lesli_babel/buckets/new.html.erb +5 -0
- data/app/views/lesli_babel/buckets/show.html.erb +4 -0
- data/app/views/lesli_babel/clones/_form.html.erb +19 -0
- data/app/views/lesli_babel/clones/edit.html.erb +20 -0
- data/app/views/lesli_babel/clones/index.html.erb +20 -0
- data/app/views/lesli_babel/clones/new.html.erb +20 -0
- data/app/views/lesli_babel/clones/show.html.erb +20 -0
- data/app/views/lesli_babel/dashboards/show.html.erb +1 -0
- data/app/views/lesli_babel/dashboards/stats..html.erb +1 -0
- data/app/views/lesli_babel/modules/_form.html.erb +17 -0
- data/app/views/lesli_babel/modules/edit.html.erb +1 -0
- data/app/views/lesli_babel/modules/index.html.erb +1 -0
- data/app/views/lesli_babel/modules/new.html.erb +1 -0
- data/app/views/lesli_babel/modules/show.html.erb +1 -0
- data/app/views/lesli_babel/partials/_engine-navigation.html.erb +37 -0
- data/app/views/lesli_babel/partials/_engine-sidebar.html.erb +45 -0
- data/app/views/lesli_babel/relevants/edit.html.erb +20 -0
- data/app/views/lesli_babel/relevants/index.html.erb +21 -0
- data/app/views/lesli_babel/relevants/new.html.erb +20 -0
- data/app/views/lesli_babel/relevants/show.html.erb +20 -0
- data/app/views/lesli_babel/string/activities/_form.html.erb +17 -0
- data/app/views/lesli_babel/string/activities/edit.html.erb +6 -0
- data/app/views/lesli_babel/string/activities/index.html.erb +25 -0
- data/app/views/lesli_babel/string/activities/new.html.erb +5 -0
- data/app/views/lesli_babel/string/activities/show.html.erb +4 -0
- data/app/views/lesli_babel/string/discussions/_form.html.erb +17 -0
- data/app/views/lesli_babel/string/discussions/edit.html.erb +6 -0
- data/app/views/lesli_babel/string/discussions/index.html.erb +25 -0
- data/app/views/lesli_babel/string/discussions/new.html.erb +5 -0
- data/app/views/lesli_babel/string/discussions/show.html.erb +4 -0
- data/app/views/lesli_babel/strings/_form.html.erb +17 -0
- data/app/views/lesli_babel/strings/edit.html.erb +6 -0
- data/app/views/lesli_babel/strings/index.html.erb +25 -0
- data/app/views/lesli_babel/strings/new.html.erb +5 -0
- data/app/views/lesli_babel/strings/show.html.erb +4 -0
- data/app/views/lesli_babel/translations/_form.html.erb +17 -0
- data/app/views/lesli_babel/translations/edit.html.erb +6 -0
- data/app/views/lesli_babel/translations/index.html.erb +1 -0
- data/app/views/lesli_babel/translations/new.html.erb +5 -0
- data/app/views/lesli_babel/translations/show.html.erb +1 -0
- data/config/routes.rb +63 -0
- data/db/migrate/v1.0/0901100110_create_lesli_babel_modules.rb +42 -0
- data/db/migrate/v1.0/0901110110_create_lesli_babel_buckets.rb +43 -0
- data/db/migrate/v1.0/0901120110_create_lesli_babel_strings.rb +80 -0
- data/lib/lesli_babel/engine.rb +54 -0
- data/lib/lesli_babel/version.rb +3 -0
- data/lib/lesli_babel.rb +6 -0
- data/lib/tasks/lesli_babel_tasks.rake +121 -0
- data/lib/vue/application.js +46 -0
- data/lib/vue/apps/dashboards/show.vue +85 -0
- data/lib/vue/apps/modules/show.vue +97 -0
- data/lib/vue/apps/relevants/index.vue +47 -0
- data/lib/vue/apps/translations/index.vue +64 -0
- data/lib/vue/components/actions.vue +29 -0
- data/lib/vue/components/form-label-editor.vue +439 -0
- data/lib/vue/components/form-string-new.vue +171 -0
- data/lib/vue/stores/module.js +49 -0
- data/lib/vue/stores/statistics.js +42 -0
- data/lib/vue/stores/strings.js +141 -0
- data/lib/vue/stores/translations.js +73 -0
- data/license +674 -0
- data/readme.md +19 -0
- metadata +149 -0
@@ -0,0 +1,439 @@
|
|
1
|
+
<script setup>
|
2
|
+
/*
|
3
|
+
Copyright (c) 2022, all rights reserved.
|
4
|
+
|
5
|
+
All the information provided by this platform is protected by international laws related to
|
6
|
+
industrial property, intellectual property, copyright and relative international laws.
|
7
|
+
All intellectual or industrial property rights of the code, texts, trade mark, design,
|
8
|
+
pictures and any other information belongs to the owner of this platform.
|
9
|
+
|
10
|
+
Without the written permission of the owner, any replication, modification,
|
11
|
+
transmission, publication is strictly forbidden.
|
12
|
+
|
13
|
+
For more information read the license file including with this software.
|
14
|
+
|
15
|
+
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
16
|
+
// ·
|
17
|
+
*/
|
18
|
+
|
19
|
+
|
20
|
+
// · import vue tools
|
21
|
+
import { ref, reactive, onMounted, watch, computed, onUnmounted } from "vue"
|
22
|
+
import { useRouter, useRoute } from 'vue-router'
|
23
|
+
|
24
|
+
|
25
|
+
// · import lesli stores
|
26
|
+
const route = useRoute()
|
27
|
+
import { useStrings } from "LesliBabel/stores/strings"
|
28
|
+
import { useTranslations } from "LesliBabel/stores/translations"
|
29
|
+
import { useServiceTranslator } from "Lesli/stores/services/translator"
|
30
|
+
|
31
|
+
|
32
|
+
// · implement stores
|
33
|
+
const storeStrings = useStrings()
|
34
|
+
const storeTranslations = useTranslations()
|
35
|
+
const storeServiceTranslator = useServiceTranslator()
|
36
|
+
|
37
|
+
|
38
|
+
// ·
|
39
|
+
const props = defineProps({
|
40
|
+
module: {
|
41
|
+
type: [Number, String],
|
42
|
+
require: false
|
43
|
+
}
|
44
|
+
})
|
45
|
+
|
46
|
+
|
47
|
+
// · columns of the editor table
|
48
|
+
const columns = ref([])
|
49
|
+
|
50
|
+
|
51
|
+
// · selected language to work with
|
52
|
+
const language = ref(null)
|
53
|
+
|
54
|
+
|
55
|
+
// ·
|
56
|
+
onMounted(() => {
|
57
|
+
|
58
|
+
// english by default if custom language not sent through url
|
59
|
+
language.value = route.query?.locale ?? 'en'
|
60
|
+
|
61
|
+
// get options for translations
|
62
|
+
storeTranslations.fetchOptions()
|
63
|
+
|
64
|
+
})
|
65
|
+
|
66
|
+
|
67
|
+
// · get translations checking configuration provided through the store or query
|
68
|
+
function fetchTranslations() {
|
69
|
+
|
70
|
+
// always reset the config
|
71
|
+
storeStrings.search = ""
|
72
|
+
storeStrings.module = 0
|
73
|
+
storeStrings.ids = null
|
74
|
+
|
75
|
+
// work with relevant translations
|
76
|
+
if (props.module == "relevants") {
|
77
|
+
return storeStrings.fetchRelevant()
|
78
|
+
}
|
79
|
+
|
80
|
+
// check if labels ids are provided
|
81
|
+
if (route.query?.ids) {
|
82
|
+
storeStrings.ids = route.query?.ids
|
83
|
+
}
|
84
|
+
|
85
|
+
// check if search params is provided through query
|
86
|
+
if (route.query?.search) {
|
87
|
+
storeStrings.search = route.query?.search
|
88
|
+
}
|
89
|
+
|
90
|
+
// work with an specific module if provided
|
91
|
+
if (props.module) {
|
92
|
+
storeStrings.module = props.module
|
93
|
+
}
|
94
|
+
|
95
|
+
return storeStrings.fetchStrings()
|
96
|
+
|
97
|
+
}
|
98
|
+
|
99
|
+
|
100
|
+
// · load all the columns available for the editor
|
101
|
+
function resetColumns() {
|
102
|
+
|
103
|
+
// reset columns
|
104
|
+
columns.value = []
|
105
|
+
|
106
|
+
// load defaults columns for the editor table
|
107
|
+
columns.value.push({
|
108
|
+
label: 'Label to translate',
|
109
|
+
field: 'label'
|
110
|
+
})
|
111
|
+
|
112
|
+
// dynamic add the column related to the selected working language
|
113
|
+
columns.value.push({
|
114
|
+
label: storeTranslations?.options?.locales_available[language.value],
|
115
|
+
field: language.value,
|
116
|
+
width: '100%'
|
117
|
+
})
|
118
|
+
}
|
119
|
+
|
120
|
+
|
121
|
+
// · build the title for the table custom headers
|
122
|
+
// · this is necessary to show the custom header cell for every language
|
123
|
+
// · (we show only one language at the time)
|
124
|
+
function languageHead(language) {
|
125
|
+
return 'head('+language+')'
|
126
|
+
}
|
127
|
+
|
128
|
+
|
129
|
+
// suggest translation from english to desire language
|
130
|
+
// to make this work we need to have the label already translated to english
|
131
|
+
function suggestTranslation(label, locale) {
|
132
|
+
|
133
|
+
// we use the translator service (integrated with google translate)
|
134
|
+
// we always send the text in english due the label key is compound with the
|
135
|
+
// collection and bucket names
|
136
|
+
storeServiceTranslator.getTranslation(label["en"], "en", locale).then(result => {
|
137
|
+
|
138
|
+
// update the translation
|
139
|
+
label[locale] = result.translatedText
|
140
|
+
|
141
|
+
// custom property added just here to let the editor know that an automatic
|
142
|
+
// translation was added to the label
|
143
|
+
label[`translated_${locale}`] = true
|
144
|
+
})
|
145
|
+
}
|
146
|
+
|
147
|
+
|
148
|
+
// remove a translation for a specific locale
|
149
|
+
// mostly used with suggested translations
|
150
|
+
function clearStringTranslation(record, locale) {
|
151
|
+
record[locale] = ''
|
152
|
+
record[`translated_${locale}`] = false
|
153
|
+
}
|
154
|
+
|
155
|
+
|
156
|
+
// build a string to use as direct link to the selected label
|
157
|
+
function getLabelLink(id) {
|
158
|
+
return `${window.location.host}/babel/translations?ids=${id}`
|
159
|
+
}
|
160
|
+
|
161
|
+
|
162
|
+
// switch a label as help needed
|
163
|
+
function askForHelp(record) {
|
164
|
+
record.need_help = !record.need_help
|
165
|
+
storeStrings.putString(record)
|
166
|
+
}
|
167
|
+
|
168
|
+
|
169
|
+
// switch a label as help needed
|
170
|
+
function askForTranslation(record) {
|
171
|
+
record.need_translation = !record.need_translation
|
172
|
+
storeStrings.putString(record)
|
173
|
+
}
|
174
|
+
|
175
|
+
|
176
|
+
// · get strings for the module selected, reset if module changed
|
177
|
+
watch(() => props.module, () => {
|
178
|
+
storeStrings.search = ""
|
179
|
+
storeStrings.module = props.module
|
180
|
+
fetchTranslations()
|
181
|
+
})
|
182
|
+
|
183
|
+
|
184
|
+
watch(() => route.query.search, string => {
|
185
|
+
storeStrings.search = string
|
186
|
+
fetchTranslations()
|
187
|
+
})
|
188
|
+
|
189
|
+
|
190
|
+
// · changing the working language, keep config if language changed
|
191
|
+
watch(() => language.value, (language) => {
|
192
|
+
storeStrings.language = language
|
193
|
+
fetchTranslations()
|
194
|
+
resetColumns()
|
195
|
+
})
|
196
|
+
|
197
|
+
|
198
|
+
// · watch for the locales available to dynamically show language columns in the editor
|
199
|
+
watch(() => storeTranslations.options.locales_available, () => {
|
200
|
+
resetColumns()
|
201
|
+
})
|
202
|
+
|
203
|
+
|
204
|
+
// · go to the first input once translations loaded
|
205
|
+
watch(() => storeStrings.strings.records, () => {
|
206
|
+
setTimeout(() => { nextTranslation() }, 1000)
|
207
|
+
})
|
208
|
+
|
209
|
+
|
210
|
+
// ·
|
211
|
+
function copyToClipboard(button, text) {
|
212
|
+
const el = document.createElement('textarea');
|
213
|
+
el.value = text; // text to copy
|
214
|
+
el.setAttribute('readonly', '');
|
215
|
+
el.style.position = 'absolute';
|
216
|
+
el.style.left = '-9999px';
|
217
|
+
document.body.appendChild(el);
|
218
|
+
el.select();
|
219
|
+
document.execCommand('copy');
|
220
|
+
document.body.removeChild(el);
|
221
|
+
button.target.classList.add('copied')
|
222
|
+
setTimeout(() => button.target.classList.remove('copied'), 1000)
|
223
|
+
}
|
224
|
+
|
225
|
+
|
226
|
+
// · Navigate to the next translation using arrow keys
|
227
|
+
function nextTranslation () {
|
228
|
+
|
229
|
+
var table = document.getElementById("babel-translations")
|
230
|
+
var inputs = table.getElementsByTagName("input")
|
231
|
+
|
232
|
+
for(var i = 0 ; i < inputs.length;i++) {
|
233
|
+
|
234
|
+
// add a listener for keydown
|
235
|
+
inputs[i].addEventListener('keydown', function(e){
|
236
|
+
|
237
|
+
// execute only for down/up/enter keys
|
238
|
+
if (e.keyCode == 38 || e.keyCode == 40 || e.keyCode == 13) {
|
239
|
+
|
240
|
+
// remove default behavior for arrow keys
|
241
|
+
e.preventDefault()
|
242
|
+
|
243
|
+
// get the index of the current index
|
244
|
+
var currentIndex = findElement(e.target)
|
245
|
+
|
246
|
+
// work only with valid index between 0 ~ n
|
247
|
+
if (currentIndex < 0 || currentIndex > inputs.length) {
|
248
|
+
return
|
249
|
+
}
|
250
|
+
|
251
|
+
// downkey
|
252
|
+
if (e.keyCode == 38) {
|
253
|
+
if (inputs[currentIndex-1]) {
|
254
|
+
inputs[currentIndex-1].focus();
|
255
|
+
}
|
256
|
+
}
|
257
|
+
|
258
|
+
// upkey
|
259
|
+
if (e.keyCode == 40 || e.keyCode == 13) {
|
260
|
+
if (inputs[currentIndex+1]) {
|
261
|
+
inputs[currentIndex+1].focus();
|
262
|
+
}
|
263
|
+
}
|
264
|
+
|
265
|
+
}
|
266
|
+
|
267
|
+
});
|
268
|
+
}
|
269
|
+
|
270
|
+
// get the current selected input
|
271
|
+
function findElement(element) {
|
272
|
+
var index = -1;
|
273
|
+
for(var i = 0; i < inputs.length; i++) {
|
274
|
+
if(inputs[i] == element) {
|
275
|
+
return i;
|
276
|
+
}
|
277
|
+
}
|
278
|
+
return index;
|
279
|
+
}
|
280
|
+
|
281
|
+
}
|
282
|
+
|
283
|
+
</script>
|
284
|
+
<template>
|
285
|
+
<lesli-table
|
286
|
+
id="babel-translations"
|
287
|
+
:loading="storeStrings.strings.loading"
|
288
|
+
:records="storeStrings.strings.records"
|
289
|
+
:columns="columns"
|
290
|
+
@paginate="storeStrings.fetchStrings()"
|
291
|
+
@details="nextTranslation()">
|
292
|
+
|
293
|
+
<!--
|
294
|
+
Table custom header, renders a language selector
|
295
|
+
-->
|
296
|
+
<template #[languageHead(language)]="{ column }">
|
297
|
+
<lesli-select
|
298
|
+
icon="public"
|
299
|
+
v-model="language"
|
300
|
+
:options="storeTranslations.locales">
|
301
|
+
</lesli-select>
|
302
|
+
</template>
|
303
|
+
|
304
|
+
|
305
|
+
<!--
|
306
|
+
Print the label string with a button to easely copy to clipboard
|
307
|
+
-->
|
308
|
+
<template #label="{ record }">
|
309
|
+
<button
|
310
|
+
class="button is-white p-0"
|
311
|
+
@click.stop="copyToClipboard($event, record.label)"
|
312
|
+
@contextmenu.capture.prevent="copyToClipboard($event, record.path)">
|
313
|
+
<span class="icon has-text-grey">
|
314
|
+
<span class="material-icons">
|
315
|
+
content_copy
|
316
|
+
</span>
|
317
|
+
</span>
|
318
|
+
<span>
|
319
|
+
{{ record.label }}
|
320
|
+
</span>
|
321
|
+
</button>
|
322
|
+
</template>
|
323
|
+
|
324
|
+
<!--
|
325
|
+
Print a input to edit the translation for the current locale
|
326
|
+
-->
|
327
|
+
<template #[language]="{ value, record }">
|
328
|
+
<div class="is-flex is-align-items-center">
|
329
|
+
<input
|
330
|
+
type="text"
|
331
|
+
class="input"
|
332
|
+
placeholder="Add translations..."
|
333
|
+
@input="storeStrings.updateString(record, language)"
|
334
|
+
v-model="record[language]"
|
335
|
+
/>
|
336
|
+
<span class="icon mx-1" v-if="record.need_help">
|
337
|
+
<span class="material-icons has-text-info">
|
338
|
+
help_outline
|
339
|
+
</span>
|
340
|
+
</span>
|
341
|
+
<span class="icon mx-1" v-if="record.need_translation">
|
342
|
+
<span class="material-icons has-text-warning-dark">
|
343
|
+
translate
|
344
|
+
</span>
|
345
|
+
</span>
|
346
|
+
</div>
|
347
|
+
</template>
|
348
|
+
|
349
|
+
<template #detail="{ record }">
|
350
|
+
<tr v-for="(locale_name, locale_code) in storeTranslations.options.locales_available">
|
351
|
+
<td></td>
|
352
|
+
<td class="has-text-right">{{ locale_name }}</td>
|
353
|
+
<td class="is-flex is-align-items-center">
|
354
|
+
<input
|
355
|
+
type="text"
|
356
|
+
class="input"
|
357
|
+
placeholder="Add translations..."
|
358
|
+
v-model="record[locale_code]"
|
359
|
+
@input="storeStrings.updateString(record, locale_code)"
|
360
|
+
/>
|
361
|
+
<lesli-button
|
362
|
+
icon-only small danger icon="clear"
|
363
|
+
v-if="record[`translated_${locale_code}`] == true"
|
364
|
+
@click="clearStringTranslation(record, locale_code)">
|
365
|
+
</lesli-button>
|
366
|
+
|
367
|
+
<lesli-button
|
368
|
+
icon-only small icon="save"
|
369
|
+
v-if="record[`translated_${locale_code}`] == true"
|
370
|
+
@click="storeStrings.putString(record)">
|
371
|
+
</lesli-button>
|
372
|
+
|
373
|
+
<lesli-button
|
374
|
+
icon-only small icon="translate"
|
375
|
+
v-if="!!record['en']"
|
376
|
+
@click="suggestTranslation(record, locale_code)">
|
377
|
+
</lesli-button>
|
378
|
+
</td>
|
379
|
+
</tr>
|
380
|
+
<tr>
|
381
|
+
<td></td>
|
382
|
+
<td class="has-text-right">Context</td>
|
383
|
+
<td>
|
384
|
+
<input
|
385
|
+
type="text"
|
386
|
+
class="input"
|
387
|
+
placeholder="Add translation context..."
|
388
|
+
v-model="record.context"
|
389
|
+
@input="storeStrings.updateString(record)"
|
390
|
+
/>
|
391
|
+
</td>
|
392
|
+
</tr>
|
393
|
+
<tr>
|
394
|
+
<td></td>
|
395
|
+
<td class="has-text-right">Full path</td>
|
396
|
+
<td>
|
397
|
+
<button
|
398
|
+
class="button is-primary is-inverted"
|
399
|
+
@click.stop="copyToClipboard($event, record.path)">
|
400
|
+
<span class="icon has-text-grey">
|
401
|
+
<span class="material-icons">
|
402
|
+
content_copy
|
403
|
+
</span>
|
404
|
+
</span>
|
405
|
+
<span>
|
406
|
+
{{ record.path }}
|
407
|
+
</span>
|
408
|
+
</button>
|
409
|
+
</td>
|
410
|
+
</tr>
|
411
|
+
<tr>
|
412
|
+
<td colspan="100%">
|
413
|
+
<div class="buttons is-justify-content-center">
|
414
|
+
<button
|
415
|
+
class="button is-primary is-small"
|
416
|
+
@click="copyToClipboard($event, getLabelLink(record.id))">
|
417
|
+
<span class="icon is-small">
|
418
|
+
<span class="material-icons">link</span>
|
419
|
+
</span>
|
420
|
+
<span>Copy link</span>
|
421
|
+
</button>
|
422
|
+
|
423
|
+
<lesli-button
|
424
|
+
small info solid icon="help_outline"
|
425
|
+
@click="askForHelp(record)">
|
426
|
+
Need help
|
427
|
+
</lesli-button>
|
428
|
+
|
429
|
+
<lesli-button
|
430
|
+
small warning solid icon="translate"
|
431
|
+
@click="askForTranslation(record)">
|
432
|
+
Need translation
|
433
|
+
</lesli-button>
|
434
|
+
</div>
|
435
|
+
</td>
|
436
|
+
</tr>
|
437
|
+
</template>
|
438
|
+
</lesli-table>
|
439
|
+
</template>
|
@@ -0,0 +1,171 @@
|
|
1
|
+
<script setup>
|
2
|
+
/*
|
3
|
+
Copyright (c) 2022, all rights reserved.
|
4
|
+
|
5
|
+
All the information provided by this platform is protected by international laws related to
|
6
|
+
industrial property, intellectual property, copyright and relative international laws.
|
7
|
+
All intellectual or industrial property rights of the code, texts, trade mark, design,
|
8
|
+
pictures and any other information belongs to the owner of this platform.
|
9
|
+
|
10
|
+
Without the written permission of the owner, any replication, modification,
|
11
|
+
transmission, publication is strictly forbidden.
|
12
|
+
|
13
|
+
For more information read the license file including with this software.
|
14
|
+
|
15
|
+
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
16
|
+
// ·
|
17
|
+
*/
|
18
|
+
|
19
|
+
|
20
|
+
// · import vue tools
|
21
|
+
import { ref, reactive, onMounted, watch, computed, onUnmounted } from "vue"
|
22
|
+
|
23
|
+
|
24
|
+
// ·
|
25
|
+
import { useStrings } from "LesliBabel/stores/strings"
|
26
|
+
import { useModule } from "LesliBabel/stores/module"
|
27
|
+
|
28
|
+
|
29
|
+
// · implement stores
|
30
|
+
const storeModule = useModule()
|
31
|
+
const storeString = useStrings()
|
32
|
+
|
33
|
+
|
34
|
+
// ·
|
35
|
+
const props = defineProps({
|
36
|
+
moduleId: {
|
37
|
+
type: Number,
|
38
|
+
require: true
|
39
|
+
}
|
40
|
+
})
|
41
|
+
|
42
|
+
|
43
|
+
// ·
|
44
|
+
onMounted(() => {
|
45
|
+
|
46
|
+
})
|
47
|
+
|
48
|
+
|
49
|
+
// ·
|
50
|
+
const bucket = ref('')
|
51
|
+
const prefix = ref('')
|
52
|
+
const string = ref('')
|
53
|
+
|
54
|
+
|
55
|
+
// ·
|
56
|
+
const prefixes = [{
|
57
|
+
label: 'account_init',
|
58
|
+
value: 'account_init'
|
59
|
+
}, {
|
60
|
+
label: 'activity_description',
|
61
|
+
value: 'activity_description'
|
62
|
+
}, {
|
63
|
+
label: "column",
|
64
|
+
value: "column"
|
65
|
+
}, {
|
66
|
+
label: "column_enum",
|
67
|
+
value: "column_enum"
|
68
|
+
}, {
|
69
|
+
label: "mailer",
|
70
|
+
value: "mailer"
|
71
|
+
}, {
|
72
|
+
label: "messages_success",
|
73
|
+
value: "messages_success"
|
74
|
+
}, {
|
75
|
+
label: "messages_info",
|
76
|
+
value: "messages_info"
|
77
|
+
}, {
|
78
|
+
label: "messages_warning",
|
79
|
+
value: "messages_warning"
|
80
|
+
}, {
|
81
|
+
label: "messages_danger",
|
82
|
+
value: "messages_danger"
|
83
|
+
}, {
|
84
|
+
label: "sidebar_nav",
|
85
|
+
value: "sidebar_nav"
|
86
|
+
}, {
|
87
|
+
label: "error",
|
88
|
+
value: "error"
|
89
|
+
}, {
|
90
|
+
label: "view",
|
91
|
+
value: "view"
|
92
|
+
}, {
|
93
|
+
label: "view_btn",
|
94
|
+
value: "view_btn"
|
95
|
+
}, {
|
96
|
+
label: "view_chart_title",
|
97
|
+
value: "view_chart_title"
|
98
|
+
}, {
|
99
|
+
label: "view_placeholder",
|
100
|
+
value: "view_placeholder"
|
101
|
+
}, {
|
102
|
+
label: "view_tab_title",
|
103
|
+
value: "view_tab_title"
|
104
|
+
}, {
|
105
|
+
label: "view_table_action",
|
106
|
+
value: "view_table_action"
|
107
|
+
}, {
|
108
|
+
label: "view_table_header",
|
109
|
+
value: "view_table_header"
|
110
|
+
}, {
|
111
|
+
label: "view_text",
|
112
|
+
value: "view_text"
|
113
|
+
}, {
|
114
|
+
label: "view_title",
|
115
|
+
value: "view_title"
|
116
|
+
}, {
|
117
|
+
label: "view_toolbar_filter",
|
118
|
+
value: "view_toolbar_filter"
|
119
|
+
}, {
|
120
|
+
label: "view_toolbar_filter_placeholder",
|
121
|
+
value: "view_toolbar_filter_placeholder"
|
122
|
+
}, {
|
123
|
+
label: "view_toolbar_search_by_placeholder",
|
124
|
+
value: "view_toolbar_search_by_placeholder"
|
125
|
+
}]
|
126
|
+
|
127
|
+
|
128
|
+
function postString() {
|
129
|
+
storeString.post({
|
130
|
+
cloud_babel_buckets_id: bucket.value,
|
131
|
+
context: '',
|
132
|
+
label: prefix.value + "_" + string.value
|
133
|
+
})
|
134
|
+
|
135
|
+
string.value = ''
|
136
|
+
}
|
137
|
+
|
138
|
+
</script>
|
139
|
+
<template>
|
140
|
+
<form v-on:submit.prevent="postString" class="card is-shadowless">
|
141
|
+
<div class="card-content">
|
142
|
+
<div class="field">
|
143
|
+
<label class="label">Bucket</label>
|
144
|
+
<div class="control">
|
145
|
+
<lesli-select
|
146
|
+
v-model="bucket"
|
147
|
+
:options="storeModule.buckets.map(b => { return { value: b.id, label: b.name }})">
|
148
|
+
</lesli-select>
|
149
|
+
</div>
|
150
|
+
</div>
|
151
|
+
<div class="field">
|
152
|
+
<label class="label">Prefix</label>
|
153
|
+
<div class="control">
|
154
|
+
<lesli-select
|
155
|
+
v-model="prefix"
|
156
|
+
:options="prefixes">
|
157
|
+
</lesli-select>
|
158
|
+
</div>
|
159
|
+
</div>
|
160
|
+
<div class="field">
|
161
|
+
<label class="label">Label</label>
|
162
|
+
<div class="control">
|
163
|
+
<input required v-model="string" class="input" type="text" placeholder="Add label to translation workflow" />
|
164
|
+
</div>
|
165
|
+
</div>
|
166
|
+
<div class="control">
|
167
|
+
<input class="button is-primary" type="submit" value="Save" />
|
168
|
+
</div>
|
169
|
+
</div>
|
170
|
+
</form>
|
171
|
+
</template>
|
@@ -0,0 +1,49 @@
|
|
1
|
+
/*
|
2
|
+
Copyright (c) 2022, all rights reserved.
|
3
|
+
|
4
|
+
All the information provided by this platform is protected by international laws related to
|
5
|
+
industrial property, intellectual property, copyright and relative international laws.
|
6
|
+
All intellectual or industrial property rights of the code, texts, trade mark, design,
|
7
|
+
pictures and any other information belongs to the owner of this platform.
|
8
|
+
|
9
|
+
Without the written permission of the owner, any replication, modification,
|
10
|
+
transmission, publication is strictly forbidden.
|
11
|
+
|
12
|
+
For more information read the license file including with this software.
|
13
|
+
|
14
|
+
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
15
|
+
// ·
|
16
|
+
*/
|
17
|
+
|
18
|
+
|
19
|
+
// ·
|
20
|
+
import { defineStore } from "pinia"
|
21
|
+
|
22
|
+
|
23
|
+
// ·
|
24
|
+
export const useModule = defineStore("babel.module", {
|
25
|
+
state: () => {
|
26
|
+
return {
|
27
|
+
id: 0,
|
28
|
+
name: "",
|
29
|
+
platform: "",
|
30
|
+
buckets: []
|
31
|
+
}
|
32
|
+
},
|
33
|
+
actions: {
|
34
|
+
fetchModule(modulo) {
|
35
|
+
if (!modulo) return;
|
36
|
+
this.http.get(this.url.babel("modules/:id", modulo)).then(result => {
|
37
|
+
this.id = result.id
|
38
|
+
this.name = result.name
|
39
|
+
this.platform = result.platform
|
40
|
+
this.fetchBuckets()
|
41
|
+
})
|
42
|
+
},
|
43
|
+
fetchBuckets() {
|
44
|
+
this.http.get(this.url.babel("modules/:id/buckets", this.id)).then(result => {
|
45
|
+
this.buckets = result
|
46
|
+
})
|
47
|
+
}
|
48
|
+
}
|
49
|
+
})
|
@@ -0,0 +1,42 @@
|
|
1
|
+
/*
|
2
|
+
Copyright (c) 2022, all rights reserved.
|
3
|
+
|
4
|
+
All the information provided by this platform is protected by international laws related to
|
5
|
+
industrial property, intellectual property, copyright and relative international laws.
|
6
|
+
All intellectual or industrial property rights of the code, texts, trade mark, design,
|
7
|
+
pictures and any other information belongs to the owner of this platform.
|
8
|
+
|
9
|
+
Without the written permission of the owner, any replication, modification,
|
10
|
+
transmission, publication is strictly forbidden.
|
11
|
+
|
12
|
+
For more information read the license file including with this software.
|
13
|
+
|
14
|
+
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
15
|
+
// ·
|
16
|
+
*/
|
17
|
+
|
18
|
+
|
19
|
+
// ·
|
20
|
+
import { defineStore } from "pinia"
|
21
|
+
|
22
|
+
|
23
|
+
// ·
|
24
|
+
export const useStatistics = defineStore("statistics", {
|
25
|
+
state: () => {
|
26
|
+
return {
|
27
|
+
lastSyncronizationAt: "",
|
28
|
+
totalStrings: 0,
|
29
|
+
languages: []
|
30
|
+
}
|
31
|
+
},
|
32
|
+
actions: {
|
33
|
+
fetch() {
|
34
|
+
this.http.get(this.url.babel('strings/stats')).then(result => {
|
35
|
+
this.lastSyncronizationAt = result.last_syncronization_at
|
36
|
+
this.totalStrings = result.total_strings
|
37
|
+
this.languages = result.total_strings_translations
|
38
|
+
})
|
39
|
+
},
|
40
|
+
|
41
|
+
}
|
42
|
+
})
|