浏览代码

多语言

dsy 6 天之前
父节点
当前提交
51641ddb3e

+ 24 - 0
src/components/CommonPreview.vue

@@ -151,6 +151,7 @@ import { isTrue } from '@/utils/validate';
 import MindMap from '@/components/MindMap.vue';
 import VideoPlay from '@/views/book/courseware/preview/components/common/VideoPlay.vue';
 import AudioPlay from '@/views/book/courseware/preview/components/common/AudioPlay.vue';
+import * as OpenCC from 'opencc-js';
 
 import {
   GetBookCoursewareInfo,
@@ -177,6 +178,14 @@ export default {
     AudioPlay,
     VideoPlay,
   },
+  provide() {
+    return {
+      getLang: () => this.lang,
+      getChinese: () => this.chinese,
+      getLangList: () => this.langList,
+      convertText: this.convertText,
+    };
+  },
   props: {
     projectId: {
       type: String,
@@ -266,6 +275,10 @@ export default {
       loading: false,
       isShowGroup: false,
       groupShowAll: true,
+      opencc: OpenCC.Converter({ from: 'cn', to: 'tw' }),
+      langList: [],
+      lang: 'ZH',
+      chinese: 'zh-Hans',
     };
   },
   computed: {
@@ -541,6 +554,17 @@ export default {
         }
       }
     },
+    /**
+     * 文本转换
+     * @param {string} text - 要转换的文本
+     * @returns {string} - 转换后的文本
+     */
+    convertText(text) {
+      if (this.chinese === 'zh-Hant' && this.opencc) {
+        return this.opencc(text);
+      }
+      return text;
+    },
   },
 };
 </script>

+ 27 - 0
src/views/book/courseware/create/components/question/matching/Matching.vue

@@ -8,6 +8,9 @@
             <span class="option-content">
               <RichText v-model="item.content" placeholder="请输入" :inline="true" :height="32" />
             </span>
+            <span class="multilingual" @click="openMultilingual(i, j)">
+              <SvgIcon icon-class="multilingual" class-name="multilingual" width="12" height="12" />
+            </span>
           </div>
         </li>
       </ul>
@@ -29,6 +32,14 @@
           </template>
         </li>
       </ul>
+
+      <MultilingualFill
+        v-if="curSelectRow !== -1 && curSelectColumn !== -1"
+        :visible.sync="multilingualVisible"
+        :text="data.option_list[curSelectRow][curSelectColumn].content"
+        :translations="data.option_list[curSelectRow][curSelectColumn].multilingual"
+        @SubmitTranslation="handleMultilingualTranslation"
+      />
     </template>
   </ModuleBase>
 </template>
@@ -47,6 +58,8 @@ export default {
       data: getMatchingData(),
       computeOptionMethods,
       serialNumberTypeList,
+      curSelectRow: -1,
+      curSelectColumn: -1,
     };
   },
   computed: {
@@ -133,6 +146,14 @@ export default {
         { name: `${this.data.property.row_num}行${this.data.property.column_num}列连线组件` },
       ];
     },
+    openMultilingual(i, j) {
+      this.curSelectRow = i;
+      this.curSelectColumn = j;
+      this.multilingualVisible = true;
+    },
+    handleMultilingualTranslation(translations) {
+      this.$set(this.data.option_list[this.curSelectRow][this.curSelectColumn], 'multilingual', translations);
+    },
   },
 };
 </script>
@@ -165,6 +186,12 @@ export default {
         margin-left: 4px;
         background-color: $fill-color;
       }
+
+      .multilingual {
+        margin-left: 2px;
+        line-height: 12px;
+        cursor: pointer;
+      }
     }
   }
 }

+ 27 - 0
src/views/book/courseware/create/components/question/sort/Sort.vue

@@ -11,6 +11,9 @@
             }"
           >
             <RichText v-model="item.content" :inline="true" placeholder="输入内容" />
+            <span class="multilingual" @click="openMultilingual(i)">
+              <SvgIcon icon-class="multilingual" class-name="multilingual" width="12" height="12" />
+            </span>
           </div>
           <div
             :key="item.mark"
@@ -31,6 +34,14 @@
         </template>
       </div>
       <div class="tips">{{ tips }}</div>
+
+      <MultilingualFill
+        v-if="curSelectIndex !== -1"
+        :visible.sync="multilingualVisible"
+        :text="data.option_list[curSelectIndex].content"
+        :translations="data.option_list[curSelectIndex].multilingual"
+        @SubmitTranslation="handleMultilingualTranslation"
+      />
     </template>
   </ModuleBase>
 </template>
@@ -47,6 +58,7 @@ export default {
     return {
       data: getSortData(),
       arrangeTypeList,
+      curSelectIndex: -1,
     };
   },
   computed: {
@@ -125,6 +137,13 @@ export default {
         },
       ];
     },
+    openMultilingual(i) {
+      this.curSelectIndex = i;
+      this.multilingualVisible = true;
+    },
+    handleMultilingualTranslation(translations) {
+      this.data.option_list[this.curSelectIndex].multilingual = translations;
+    },
   },
 };
 </script>
@@ -137,6 +156,7 @@ export default {
   gap: 12px;
 
   .sort-rich {
+    position: relative;
     padding: 8px;
     background-color: $content-color;
     border: 1px solid #ccc;
@@ -144,6 +164,13 @@ export default {
     :deep p {
       margin: 0;
     }
+
+    .multilingual {
+      position: absolute;
+      top: 2px;
+      right: 2px;
+      cursor: pointer;
+    }
   }
 
   .custom-serial-number {

+ 1 - 0
src/views/book/courseware/data/matching.js

@@ -25,6 +25,7 @@ export function getOptionItem() {
   return {
     content: '',
     mark: getRandomNumber(),
+    multilingual: [], // 多语言
   };
 }
 

+ 1 - 0
src/views/book/courseware/data/sort.js

@@ -12,6 +12,7 @@ export function getOption() {
     mark: getRandomNumber(),
     content: '',
     custom_serial_number: '', // 自定义序号
+    multilingual: [], // 多语言
   };
 }
 

+ 1 - 0
src/views/book/courseware/data/voiceMatrix.js

@@ -38,6 +38,7 @@ export function getOption() {
       end_time: 0,
       text: '',
     },
+    multilingual: [], // 多语言
   };
 }
 

+ 9 - 1
src/views/book/courseware/preview/components/matching/MatchingPreview.vue

@@ -7,7 +7,7 @@
       <ul ref="list" class="option-list">
         <li v-for="(item, i) in data.option_list" :key="i" class="list-item">
           <div
-            v-for="({ content, mark }, j) in item"
+            v-for="({ content, mark, multilingual }, j) in item"
             :key="mark"
             :class="['item-wrapper', `item-${mark}`, computedAnswerClass(mark)]"
             :style="{ cursor: disabled ? 'default' : 'pointer' }"
@@ -16,6 +16,9 @@
             @click="handleClickConnection($event, i, j, mark)"
           >
             <span class="content rich-text" v-html="sanitizeHTML(content)"></span>
+            <div v-if="showLang" class="lang">
+              {{ multilingual.find((item) => item.type === getLang())?.translation }}
+            </div>
           </div>
         </li>
       </ul>
@@ -528,6 +531,7 @@ export default {
         position: relative;
         display: flex;
         flex: 1;
+        flex-wrap: wrap;
         column-gap: 24px;
         align-items: center;
         min-height: 48px;
@@ -554,6 +558,10 @@ export default {
         .content {
           flex: 1;
         }
+
+        .lang {
+          width: 100%;
+        }
       }
     }
   }

+ 10 - 1
src/views/book/courseware/preview/components/select/SelectPreview.vue

@@ -9,7 +9,7 @@
         :style="{ flexDirection: data.property.arrange_type === arrangeTypeList[0].value ? 'column' : 'row' }"
       >
         <li
-          v-for="({ content, mark }, i) in data.option_list"
+          v-for="({ content, mark, multilingual }, i) in data.option_list"
           :key="mark"
           :style="{ cursor: disabled ? 'not-allowed' : 'pointer' }"
           :class="['option-item', { active: isAnswer(mark) }, ...computedAnswerClass(mark)]"
@@ -22,6 +22,9 @@
             {{ i + 1 }}
           </span>
           <span class="content rich-text" v-html="sanitizeHTML(content)"></span>
+          <div v-if="showLang" class="lang">
+            {{ multilingual.find((item) => item.type === getLang())?.translation }}
+          </div>
         </li>
       </ul>
     </div>
@@ -90,6 +93,7 @@ export default {
     .option-item {
       display: flex;
       flex: 1;
+      flex-wrap: wrap;
       column-gap: 8px;
       align-items: center;
       padding: 12px 24px;
@@ -98,6 +102,11 @@ export default {
       background-color: $content-color;
       border-radius: 40px;
 
+      .lang {
+        width: 100%;
+        padding-left: 52px;
+      }
+
       .checkbox {
         display: flex;
         align-items: center;

+ 3 - 0
src/views/book/courseware/preview/components/sort/SortPreview.vue

@@ -25,6 +25,9 @@
               @click="handleClickItem(i)"
             >
               <span class="rich-text" v-html="sanitizeHTML(item.content)"></span>
+              <div v-if="showLang" class="lang">
+                {{ item.multilingual.find((item) => item.type === getLang())?.translation }}
+              </div>
             </li>
           </transition-group>
         </draggable>