Bläddra i källkod

feat: translate blocks

Ahmad Kholid 3 år sedan
förälder
incheckning
440e0ceceb

+ 7 - 2
src/components/block/BlockBasic.vue

@@ -14,8 +14,11 @@
       <v-remixicon :name="block.details.icon || 'riGlobalLine'" />
     </span>
     <div style="max-width: 200px">
-      <p class="font-semibold leading-none whitespace-nowrap">
-        {{ block.details.name }}
+      <p
+        v-if="block.details.id"
+        class="font-semibold leading-none whitespace-nowrap"
+      >
+        {{ t(`workflow.blocks.${block.details.id}.name`) }}
       </p>
       <p class="text-gray-600 text-overflow leading-tight">
         {{ block.data.description }}
@@ -31,6 +34,7 @@
 </template>
 <script setup>
 import emitter from 'tiny-emitter/instance';
+import { useI18n } from 'vue-i18n';
 import { useEditorBlock } from '@/composable/editorBlock';
 import { useComponentId } from '@/composable/componentId';
 import BlockBase from './BlockBase.vue';
@@ -42,6 +46,7 @@ const props = defineProps({
   },
 });
 
+const { t } = useI18n();
 const componentId = useComponentId('block-base');
 const block = useEditorBlock(`#${componentId}`, props.editor);
 

+ 18 - 11
src/components/block/BlockConditions.vue

@@ -6,7 +6,7 @@
         class="inline-block text-sm mr-4 p-2 rounded-lg"
       >
         <v-remixicon name="riAB" size="20" class="inline-block mr-1" />
-        <span>conditions</span>
+        <span>{{ t('workflow.blocks.conditions.name') }}</span>
       </div>
       <div class="flex-grow"></div>
       <v-remixicon
@@ -41,7 +41,7 @@
         <div class="flex items-center transition bg-input rounded-lg">
           <select
             v-model="block.data.conditions[index].type"
-            :title="conditions[block.data.conditions[index]?.type] || 'Equals'"
+            :title="getTitle(index)"
             class="
               bg-transparent
               font-mono
@@ -74,16 +74,17 @@
         v-if="block.data.conditions && block.data.conditions.length !== 0"
         class="text-right text-gray-600"
       >
-        <span title="Execute when all comparisons don't meet the requirement">
+        <span :title="t('workflow.blocks.conditions.fallbackTitle')">
           &#9432;
         </span>
-        Fallback
+        {{ t('common.fallback') }}
       </p>
     </div>
   </div>
 </template>
 <script setup>
 import { watch, toRaw } from 'vue';
+import { useI18n } from 'vue-i18n';
 import emitter from 'tiny-emitter/instance';
 import { debounce } from '@/utils/helper';
 import { useComponentId } from '@/composable/componentId';
@@ -96,20 +97,26 @@ const props = defineProps({
   },
 });
 
+const { t } = useI18n();
 const componentId = useComponentId('block-conditions');
 const block = useEditorBlock(`#${componentId}`, props.editor);
 
 const conditions = {
-  '==': 'Equals',
-  '>': 'Greater than',
-  '>=': 'Greater than or equal',
-  '<': 'Less than',
-  '<=': 'Less than or equal',
-  '()': 'Contains',
+  '==': 'equals',
+  '>': 'gt',
+  '>=': 'gte',
+  '<': 'lt',
+  '<=': 'lte',
+  '()': 'contains',
 };
 
+function getTitle(index) {
+  const type = conditions[block.data.conditions[index]?.type] || 'equals';
+  console.log(type, block.data.conditions);
+  return t(`workflow.blocks.conditions.${type}`);
+}
 function addComparison() {
-  if (block.data.conditions.length >= 5) return;
+  if (block.data.conditions.length >= 10) return;
 
   block.data.conditions.push({ type: '==', value: '' });
 

+ 5 - 3
src/components/block/BlockDelay.vue

@@ -6,7 +6,7 @@
         class="inline-block text-sm mr-4 p-2 rounded-lg"
       >
         <v-remixicon name="riTimerLine" size="20" class="inline-block mr-1" />
-        <span>Delay</span>
+        <span>{{ t('workflow.blocks.delay.name') }}</span>
       </div>
       <div class="flex-grow"></div>
       <v-remixicon
@@ -18,9 +18,9 @@
     <input
       :value="block.data.time"
       min="0"
-      title="Delay in millisecond"
+      :title="t('workflow.blocks.delay.input.title')"
+      :placeholder="t('workflow.blocks.delay.input.placeholder')"
       class="px-4 py-2 rounded-lg w-36 bg-input"
-      placeholder="(millisecond)"
       type="number"
       required
       @input="handleInput"
@@ -28,6 +28,7 @@
   </div>
 </template>
 <script setup>
+import { useI18n } from 'vue-i18n';
 import emitter from 'tiny-emitter/instance';
 import { useComponentId } from '@/composable/componentId';
 import { useEditorBlock } from '@/composable/editorBlock';
@@ -39,6 +40,7 @@ const props = defineProps({
   },
 });
 
+const { t } = useI18n();
 const componentId = useComponentId('block-delay');
 const block = useEditorBlock(`#${componentId}`, props.editor);
 

+ 9 - 5
src/components/block/BlockElementExists.vue

@@ -10,10 +10,10 @@
       class="inline-block text-sm mb-2 p-2 rounded-lg"
     >
       <v-remixicon name="riFocus3Line" size="20" class="inline-block mr-1" />
-      <span>Element exists</span>
+      <span>{{ t('workflow.blocks.element-exists.name') }}</span>
     </div>
     <p
-      title="Element selector"
+      :title="t('workflow.blocks.element-exists.selector')"
       class="
         text-overflow
         p-2
@@ -26,11 +26,13 @@
       "
       style="max-width: 200px"
     >
-      {{ block.data.selector || 'Element selector' }}
+      {{ block.data.selector || t('workflow.blocks.element-exists.selector') }}
     </p>
     <p class="text-right text-gray-600">
-      <span title="Execute when element doesn't exists"> &#9432; </span>
-      Fallback
+      <span :title="t('workflow.blocks.element-exists.fallbackTitle')">
+        &#9432;
+      </span>
+      {{ t('common.fallback') }}
     </p>
     <input
       type="text"
@@ -41,6 +43,7 @@
   </block-base>
 </template>
 <script setup>
+import { useI18n } from 'vue-i18n';
 import emitter from 'tiny-emitter/instance';
 import BlockBase from './BlockBase.vue';
 import { useComponentId } from '@/composable/componentId';
@@ -53,6 +56,7 @@ const props = defineProps({
   },
 });
 
+const { t } = useI18n();
 const componentId = useComponentId('block-delay');
 const block = useEditorBlock(`#${componentId}`, props.editor);
 

+ 4 - 2
src/components/block/BlockExportData.vue

@@ -10,7 +10,7 @@
           size="20"
           class="inline-block mr-1"
         />
-        <span>Export data</span>
+        <span>{{ t('workflow.blocks.export-data.name') }}</span>
       </div>
       <div class="flex-grow"></div>
       <v-remixicon
@@ -21,8 +21,8 @@
     </div>
     <input
       v-model="block.data.name"
+      :placeholder="t('common.fileName')"
       class="bg-input rounded-lg transition w-40 mb-2 py-2 px-4 block"
-      placeholder="File name"
     />
     <ui-select v-model="block.data.type" class="w-40" placeholder="Export as">
       <option v-for="type in dataExportTypes" :key="type.id" :value="type.id">
@@ -32,6 +32,7 @@
   </div>
 </template>
 <script setup>
+import { useI18n } from 'vue-i18n';
 import { watch } from 'vue';
 import emitter from 'tiny-emitter/instance';
 import { dataExportTypes } from '@/utils/shared';
@@ -46,6 +47,7 @@ const props = defineProps({
   },
 });
 
+const { t } = useI18n();
 const componentId = useComponentId('block-delay');
 const block = useEditorBlock(`#${componentId}`, props.editor);
 

+ 3 - 1
src/components/block/BlockLoopBreakpoint.vue

@@ -6,7 +6,7 @@
         class="inline-block text-sm mr-4 p-2 rounded-lg"
       >
         <v-remixicon name="riStopLine" size="20" class="inline-block mr-1" />
-        <span>Loop breakpoint</span>
+        <span>{{ t('workflow.blocks.loop-breakpoint.name') }}</span>
       </div>
       <div class="flex-grow"></div>
       <v-remixicon
@@ -26,6 +26,7 @@
   </div>
 </template>
 <script setup>
+import { useI18n } from 'vue-i18n';
 import emitter from 'tiny-emitter/instance';
 import { useComponentId } from '@/composable/componentId';
 import { useEditorBlock } from '@/composable/editorBlock';
@@ -37,6 +38,7 @@ const props = defineProps({
   },
 });
 
+const { t } = useI18n();
 const componentId = useComponentId('block-delay');
 const block = useEditorBlock(`#${componentId}`, props.editor);
 

+ 9 - 3
src/components/block/BlockRepeatTask.vue

@@ -6,7 +6,7 @@
         class="inline-block text-sm mr-4 p-2 rounded-lg"
       >
         <v-remixicon name="riRepeat2Line" size="20" class="inline-block mr-1" />
-        <span>Repeat task</span>
+        <span>{{ t('workflow.blocks.repeat-task.name') }}</span>
       </div>
       <div class="flex-grow"></div>
       <v-remixicon
@@ -34,16 +34,22 @@
         required
         @input="handleInput"
       />
-      <span class="text-gray-600">Times</span>
+      <span class="text-gray-600">{{
+        t('workflow.blocks.repeat-task.times')
+      }}</span>
     </label>
-    <p class="text-right text-gray-600">Repeat from</p>
+    <p class="text-right text-gray-600">
+      {{ t('workflow.blocks.repeat-task.repeatFrom') }}
+    </p>
   </div>
 </template>
 <script setup>
+import { useI18n } from 'vue-i18n';
 import emitter from 'tiny-emitter/instance';
 import { useComponentId } from '@/composable/componentId';
 import { useEditorBlock } from '@/composable/editorBlock';
 
+const { t } = useI18n();
 const props = defineProps({
   editor: {
     type: Object,

+ 14 - 11
src/components/newtab/workflow/WorkflowDetailsCard.vue

@@ -32,7 +32,7 @@
     class="px-4 mt-4 mb-2"
   />
   <div class="scroll bg-scroll overflow-auto px-4 flex-1 overflow-auto">
-    <template v-for="(items, catId) in taskList" :key="catId">
+    <template v-for="(items, catId) in blocks" :key="catId">
       <div class="flex items-center top-0 space-x-2 mb-2">
         <span
           :class="categories[catId].color"
@@ -78,7 +78,7 @@
           </a>
           <v-remixicon :name="block.icon" size="24" class="mb-2" />
           <p class="leading-tight text-overflow">
-            {{ t(`workflow.blocks.${block.id}.name`) }}
+            {{ block.name }}
           </p>
         </div>
       </div>
@@ -119,16 +119,19 @@ const icons = [
   'riCommandLine',
 ];
 
-const query = ref('');
-const taskList = computed(() =>
-  Object.keys(tasks).reduce((arr, key) => {
-    const task = tasks[key];
+const blocksArr = Object.entries(tasks).map(([key, block]) => ({
+  ...block,
+  id: key,
+  name: t(`workflow.blocks.${key}.name`),
+}));
 
-    if (tasks[key].name.toLowerCase().includes(query.value.toLowerCase())) {
-      (arr[task.category] = arr[task.category] || []).push({
-        id: key,
-        ...task,
-      });
+const query = ref('');
+const blocks = computed(() =>
+  blocksArr.reduce((arr, block) => {
+    if (
+      block.name.toLocaleLowerCase().includes(query.value.toLocaleLowerCase())
+    ) {
+      (arr[block.category] = arr[block.category] || []).push(block);
     }
 
     return arr;

+ 1 - 1
src/components/newtab/workflow/WorkflowEditBlock.vue

@@ -5,7 +5,7 @@
         <v-remixicon name="riArrowLeftLine" />
       </button>
       <p class="font-semibold inline-block align-middle">
-        {{ data.name }}
+        {{ t(`workflow.blocks.${data.id}.name`) }}
       </p>
     </div>
     <component

+ 4 - 1
src/lib/vue-i18n.js

@@ -4,7 +4,6 @@ import { supportLocales } from '@/utils/shared';
 import dayjs from './dayjs';
 
 const i18n = createI18n({
-  locale: 'en',
   legacy: false,
   fallbackLocale: 'en',
 });
@@ -42,6 +41,10 @@ export async function loadLocaleMessages(locale, location) {
 
   dayjs.locale(locale);
 
+  if (locale !== 'en' && !i18n.global.availableLocales.includes('en')) {
+    await loadLocaleMessages('en', location);
+  }
+
   await importLocale('common.json');
   await importLocale(`${location}.json`, true);
   await importLocale('blocks.json', true);

+ 17 - 3
src/locales/en/blocks.json

@@ -98,7 +98,11 @@
       },
       "delay": {
         "name": "Delay",
-        "description": "Add delay before executing the next block"
+        "description": "Add delay before executing the next block",
+        "input": {
+          "title": "Delay in millisecond",
+          "placeholder": "(millisecond)"
+        }
       },
       "get-text": {
         "name": "Get text",
@@ -169,7 +173,9 @@
       },
       "repeat-task": {
         "name": "Repeat task",
-        "description": ""
+        "description": "",
+        "times": "times",
+        "repeatFrom": "Repeat from"
       },
       "javascript-code": {
         "name": "JavaScript code",
@@ -188,12 +194,20 @@
       },
       "conditions": {
         "name": "Conditions",
-        "description": "Conditional block"
+        "description": "Conditional block",
+        "fallbackTitle": "Execute when all comparisons don't meet the requirement",
+        "equals": "Equals",
+        "gt": "Greater than",
+        "gte": "Greater than or equal",
+        "lt": "Less than",
+        "lte": "Less than or equal",
+        "contains": "Contains"
       },
       "element-exists": {
         "name": "Element exists",
         "description": "Check if an element is exists",
         "selector": "Element selector",
+        "fallbackTitle": "Execute when element doesn't exists",
         "tryFor": {
           "title": "Try to check if element exist",
           "label": "Try for"

+ 1 - 0
src/locales/en/common.json

@@ -30,6 +30,7 @@
     "disable": "Disable",
     "disabled": "Disabled",
     "enable": "Enable",
+    "fallback": "Fallback"
   },
   "message": {
     "noBlock": "No block",

+ 32 - 30
src/newtab/pages/logs.vue

@@ -7,37 +7,39 @@
       @updateSorts="sortsBuilder[$event.key] = $event.value"
       @updateFilters="filtersBuilder[$event.key] = $event.value"
     />
-    <shared-logs-table :logs="logs" class="w-full" style="min-height: 320px">
-      <template #item-prepend="{ log }">
-        <td class="w-8">
-          <ui-checkbox
-            :model-value="selectedLogs.includes(log.id)"
-            class="align-text-bottom"
-            @change="toggleSelectedLog($event, log.id)"
-          />
-        </td>
-      </template>
-      <template #item-append="{ log }">
-        <td class="ml-4">
-          <div class="flex items-center justify-end space-x-4">
-            <v-remixicon
-              v-if="Object.keys(log.data).length !== 0"
-              name="riFileTextLine"
-              class="cursor-pointer"
-              @click="
-                exportDataModal.show = true;
-                exportDataModal.log = log;
-              "
-            />
-            <v-remixicon
-              name="riDeleteBin7Line"
-              class="text-red-500 cursor-pointer"
-              @click="deleteLog(log.id)"
+    <div style="min-height: 320px">
+      <shared-logs-table :logs="logs" class="w-full">
+        <template #item-prepend="{ log }">
+          <td class="w-8">
+            <ui-checkbox
+              :model-value="selectedLogs.includes(log.id)"
+              class="align-text-bottom"
+              @change="toggleSelectedLog($event, log.id)"
             />
-          </div>
-        </td>
-      </template>
-    </shared-logs-table>
+          </td>
+        </template>
+        <template #item-append="{ log }">
+          <td class="ml-4">
+            <div class="flex items-center justify-end space-x-4">
+              <v-remixicon
+                v-if="Object.keys(log.data).length !== 0"
+                name="riFileTextLine"
+                class="cursor-pointer"
+                @click="
+                  exportDataModal.show = true;
+                  exportDataModal.log = log;
+                "
+              />
+              <v-remixicon
+                name="riDeleteBin7Line"
+                class="text-red-500 cursor-pointer"
+                @click="deleteLog(log.id)"
+              />
+            </div>
+          </td>
+        </template>
+      </shared-logs-table>
+    </div>
     <div class="flex items-center justify-between mt-4">
       <div>
         {{ t('components.pagination.text1') }}

+ 2 - 2
src/newtab/pages/workflows/[id].vue

@@ -302,7 +302,7 @@ provide('workflow', {
 onBeforeRouteLeave(() => {
   if (!state.isDataChanged) return;
 
-  const answer = window.confirm(t('common.notSaved'));
+  const answer = window.confirm(t('message.notSaved'));
 
   if (!answer) return false;
 });
@@ -315,7 +315,7 @@ onMounted(() => {
 
   window.onbeforeunload = () => {
     if (state.isDataChanged) {
-      return t('common.notSaved');
+      return t('message.notSaved');
     }
   };