translation-content.vue 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. <template>
  2. <div class="message-translation-container">
  3. <div
  4. v-if="translationFinished"
  5. :id="`translation-content-${props.message.ID}`"
  6. :class="{
  7. 'translation-content': true,
  8. 'occur': true
  9. }"
  10. >
  11. <template
  12. v-if="translationTextList.length > 0"
  13. >
  14. <span
  15. v-for="(text, index) in translationTextList"
  16. :key="index"
  17. >
  18. <img
  19. v-if="text.type === 'face'"
  20. class="text-face"
  21. :src="text.value"
  22. >
  23. <span
  24. v-else
  25. class="text-plain"
  26. >
  27. {{ text.value }}
  28. </span>
  29. </span>
  30. </template>
  31. <template v-else>
  32. {{ translationErrorText }}
  33. </template>
  34. </div>
  35. <div
  36. :class="{
  37. 'loading': true,
  38. 'loading-end': translationFinished
  39. }"
  40. >
  41. {{ TUITranslateService.t('TUIChat.翻译中') }}...
  42. </div>
  43. </div>
  44. </template>
  45. <script lang="ts" setup>
  46. import { ref, watch } from '../../../../../adapter-vue';
  47. import {
  48. IMessageModel,
  49. TUITranslateService,
  50. } from '@tencentcloud/chat-uikit-engine';
  51. import { TranslationTextType, translator } from '../../../utils/translation';
  52. interface IProps {
  53. message: IMessageModel;
  54. translationContentVisible: boolean;
  55. isSingleTranslation: boolean;
  56. translationWrapperRef: HTMLDivElement | undefined;
  57. }
  58. const props = withDefaults(defineProps<IProps>(), {
  59. message: () => ({} as IMessageModel),
  60. });
  61. const translationFinished = ref<boolean>(false);
  62. const translationErrorText = ref<string>('');
  63. const translationTextList = ref<TranslationTextType[]>([]);
  64. watch(() => props.translationContentVisible, (newVal: boolean) => {
  65. if (newVal) {
  66. translator.get(props.message)
  67. .then((result) => {
  68. translationFinished.value = true;
  69. translationTextList.value = result;
  70. })
  71. .catch((err) => {
  72. translationFinished.value = true;
  73. emits('toggleErrorStatus', true);
  74. translationErrorText.value = err.message;
  75. });
  76. }
  77. }, { immediate: true });
  78. </script>
  79. <style lang="scss" scoped>
  80. .message-translation-container {
  81. min-height: 16px;
  82. min-width: 80px;
  83. position: relative;
  84. transition: width 0.15s ease-out, height 0.15s ease-out, ;
  85. font-size: 14px;
  86. .loading {
  87. position: absolute;
  88. top: 0;
  89. left: 0;
  90. opacity: 1;
  91. transition: opacity 0.3s ease-out;
  92. &.loading-end {
  93. opacity: 0;
  94. }
  95. }
  96. .translation-content {
  97. opacity: 0;
  98. &.occur {
  99. animation: occur 0.3s ease-out 0.45s forwards;
  100. @keyframes occur {
  101. 100% {
  102. opacity: 1;
  103. }
  104. }
  105. }
  106. .text-face {
  107. width: 20px;
  108. height: 20px;
  109. }
  110. }
  111. }
  112. </style>