lesli_babel 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +5 -0
  3. data/app/assets/config/lesli_babel_manifest.js +7 -0
  4. data/app/assets/images/lesli_babel/babel-logo.svg +157 -0
  5. data/app/assets/javascripts/lesli_babel/application.js +3288 -0
  6. data/app/assets/stylesheets/lesli_babel/application.scss +41 -0
  7. data/app/assets/stylesheets/lesli_babel/dashboards.scss +55 -0
  8. data/app/assets/stylesheets/lesli_babel/modules.scss +33 -0
  9. data/app/assets/stylesheets/lesli_babel/translations.scss +58 -0
  10. data/app/controllers/lesli_babel/application_controller.rb +37 -0
  11. data/app/controllers/lesli_babel/buckets_controller.rb +79 -0
  12. data/app/controllers/lesli_babel/clones_controller.rb +80 -0
  13. data/app/controllers/lesli_babel/dashboards_controller.rb +38 -0
  14. data/app/controllers/lesli_babel/modules_controller.rb +91 -0
  15. data/app/controllers/lesli_babel/relevants_controller.rb +38 -0
  16. data/app/controllers/lesli_babel/strings_controller.rb +142 -0
  17. data/app/controllers/lesli_babel/translations_controller.rb +134 -0
  18. data/app/jobs/lesli_babel/application_job.rb +7 -0
  19. data/app/mailers/lesli_babel/application_mailer.rb +6 -0
  20. data/app/models/lesli_babel/application_record.rb +36 -0
  21. data/app/models/lesli_babel/bucket.rb +6 -0
  22. data/app/models/lesli_babel/clone.rb +24 -0
  23. data/app/models/lesli_babel/dashboard.rb +35 -0
  24. data/app/models/lesli_babel/module.rb +35 -0
  25. data/app/models/lesli_babel/relevant.rb +21 -0
  26. data/app/models/lesli_babel/string/activity.rb +5 -0
  27. data/app/models/lesli_babel/string/discussion.rb +68 -0
  28. data/app/models/lesli_babel/string.rb +225 -0
  29. data/app/models/lesli_babel/translation.rb +5 -0
  30. data/app/services/lesli_babel/module_service.rb +18 -0
  31. data/app/services/lesli_babel/old/translations_android_service.rb +82 -0
  32. data/app/services/lesli_babel/old/translations_clone_service.rb +161 -0
  33. data/app/services/lesli_babel/old/translations_flutter_service.rb +102 -0
  34. data/app/services/lesli_babel/old/translations_ios_service.rb +119 -0
  35. data/app/services/lesli_babel/old/translations_js_service.rb +114 -0
  36. data/app/services/lesli_babel/old/translations_middleman_service.rb +77 -0
  37. data/app/services/lesli_babel/old/translations_rails_service.rb +119 -0
  38. data/app/services/lesli_babel/old/translations_service.rb +97 -0
  39. data/app/services/lesli_babel/old/translations_synchronization_service.rb +215 -0
  40. data/app/services/lesli_babel/string_service.rb +80 -0
  41. data/app/views/lesli_babel/buckets/_form.html.erb +17 -0
  42. data/app/views/lesli_babel/buckets/edit.html.erb +6 -0
  43. data/app/views/lesli_babel/buckets/index.html.erb +25 -0
  44. data/app/views/lesli_babel/buckets/new.html.erb +5 -0
  45. data/app/views/lesli_babel/buckets/show.html.erb +4 -0
  46. data/app/views/lesli_babel/clones/_form.html.erb +19 -0
  47. data/app/views/lesli_babel/clones/edit.html.erb +20 -0
  48. data/app/views/lesli_babel/clones/index.html.erb +20 -0
  49. data/app/views/lesli_babel/clones/new.html.erb +20 -0
  50. data/app/views/lesli_babel/clones/show.html.erb +20 -0
  51. data/app/views/lesli_babel/dashboards/show.html.erb +1 -0
  52. data/app/views/lesli_babel/dashboards/stats..html.erb +1 -0
  53. data/app/views/lesli_babel/modules/_form.html.erb +17 -0
  54. data/app/views/lesli_babel/modules/edit.html.erb +1 -0
  55. data/app/views/lesli_babel/modules/index.html.erb +1 -0
  56. data/app/views/lesli_babel/modules/new.html.erb +1 -0
  57. data/app/views/lesli_babel/modules/show.html.erb +1 -0
  58. data/app/views/lesli_babel/partials/_engine-navigation.html.erb +37 -0
  59. data/app/views/lesli_babel/partials/_engine-sidebar.html.erb +45 -0
  60. data/app/views/lesli_babel/relevants/edit.html.erb +20 -0
  61. data/app/views/lesli_babel/relevants/index.html.erb +21 -0
  62. data/app/views/lesli_babel/relevants/new.html.erb +20 -0
  63. data/app/views/lesli_babel/relevants/show.html.erb +20 -0
  64. data/app/views/lesli_babel/string/activities/_form.html.erb +17 -0
  65. data/app/views/lesli_babel/string/activities/edit.html.erb +6 -0
  66. data/app/views/lesli_babel/string/activities/index.html.erb +25 -0
  67. data/app/views/lesli_babel/string/activities/new.html.erb +5 -0
  68. data/app/views/lesli_babel/string/activities/show.html.erb +4 -0
  69. data/app/views/lesli_babel/string/discussions/_form.html.erb +17 -0
  70. data/app/views/lesli_babel/string/discussions/edit.html.erb +6 -0
  71. data/app/views/lesli_babel/string/discussions/index.html.erb +25 -0
  72. data/app/views/lesli_babel/string/discussions/new.html.erb +5 -0
  73. data/app/views/lesli_babel/string/discussions/show.html.erb +4 -0
  74. data/app/views/lesli_babel/strings/_form.html.erb +17 -0
  75. data/app/views/lesli_babel/strings/edit.html.erb +6 -0
  76. data/app/views/lesli_babel/strings/index.html.erb +25 -0
  77. data/app/views/lesli_babel/strings/new.html.erb +5 -0
  78. data/app/views/lesli_babel/strings/show.html.erb +4 -0
  79. data/app/views/lesli_babel/translations/_form.html.erb +17 -0
  80. data/app/views/lesli_babel/translations/edit.html.erb +6 -0
  81. data/app/views/lesli_babel/translations/index.html.erb +1 -0
  82. data/app/views/lesli_babel/translations/new.html.erb +5 -0
  83. data/app/views/lesli_babel/translations/show.html.erb +1 -0
  84. data/config/routes.rb +63 -0
  85. data/db/migrate/v1.0/0901100110_create_lesli_babel_modules.rb +42 -0
  86. data/db/migrate/v1.0/0901110110_create_lesli_babel_buckets.rb +43 -0
  87. data/db/migrate/v1.0/0901120110_create_lesli_babel_strings.rb +80 -0
  88. data/lib/lesli_babel/engine.rb +54 -0
  89. data/lib/lesli_babel/version.rb +3 -0
  90. data/lib/lesli_babel.rb +6 -0
  91. data/lib/tasks/lesli_babel_tasks.rake +121 -0
  92. data/lib/vue/application.js +46 -0
  93. data/lib/vue/apps/dashboards/show.vue +85 -0
  94. data/lib/vue/apps/modules/show.vue +97 -0
  95. data/lib/vue/apps/relevants/index.vue +47 -0
  96. data/lib/vue/apps/translations/index.vue +64 -0
  97. data/lib/vue/components/actions.vue +29 -0
  98. data/lib/vue/components/form-label-editor.vue +439 -0
  99. data/lib/vue/components/form-string-new.vue +171 -0
  100. data/lib/vue/stores/module.js +49 -0
  101. data/lib/vue/stores/statistics.js +42 -0
  102. data/lib/vue/stores/strings.js +141 -0
  103. data/lib/vue/stores/translations.js +73 -0
  104. data/license +674 -0
  105. data/readme.md +19 -0
  106. 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
+ &nbsp;
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
+ &nbsp;
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
+ })