@tencentcloud/ai-desk-customer-vue 1.5.10 → 1.6.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.
- package/CHANGELOG.md +22 -1
- package/README.md +103 -77
- package/README_EN.md +873 -0
- package/assets/audio-blue.svg +4 -0
- package/assets/audio_icon_1.svg +3 -0
- package/assets/audio_icon_2.svg +3 -0
- package/assets/audio_icon_3.svg +3 -0
- package/assets/keyboard-icon.svg +9 -0
- package/components/CustomerServiceChat/chat-header/index-web.vue +41 -10
- package/components/CustomerServiceChat/feedback-modal/index.vue +1 -1
- package/components/CustomerServiceChat/index-web.vue +13 -3
- package/components/CustomerServiceChat/message-input/index-web.vue +57 -10
- package/components/CustomerServiceChat/message-input/message-input-editor-web.vue +342 -11
- package/components/CustomerServiceChat/message-list/index-web.vue +13 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-audio-web.vue +50 -78
- package/components/CustomerServiceChat/message-list/message-elements/message-bubble-web.vue +1 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/marked.ts +4 -3
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-robot-welcome.vue +13 -6
- package/components/CustomerServiceChat/message-list/message-elements/message-text.vue +3 -2
- package/components/CustomerServiceChat/message-toolbar-button/index.vue +11 -6
- package/components/CustomerServiceChat/message-toolbar-button/toolbar-button-end-human-service.vue +16 -5
- package/components/CustomerServiceChat/message-toolbar-button/toolbar-button-human-service.vue +8 -5
- package/components/CustomerServiceChat/message-toolbar-button/toolbar-button-service-rating.vue +8 -5
- package/components/common/Toast/index-web.ts +16 -3
- package/components/common/Toast/index-web.vue +16 -6
- package/constant.ts +1 -0
- package/interface.ts +8 -0
- package/locales/en/TUIChat.ts +6 -2
- package/locales/fil/TUIChat.ts +6 -2
- package/locales/id/TUIChat.ts +76 -72
- package/locales/ja/TUIChat.ts +76 -72
- package/locales/ms/TUIChat.ts +76 -72
- package/locales/ru/TUIChat.ts +6 -2
- package/locales/th/TUIChat.ts +76 -72
- package/locales/vi/TUIChat.ts +76 -72
- package/locales/zh_cn/TUIChat.ts +6 -2
- package/locales/zh_tw/TUIChat.ts +6 -2
- package/package.json +2 -1
- package/server.ts +22 -3
- package/utils/utils.ts +13 -0
- package/assets/keyboard_icon.png +0 -0
|
@@ -2,7 +2,7 @@ import {Marked} from 'marked';
|
|
|
2
2
|
import Log from '../../../../../../utils/logger';
|
|
3
3
|
|
|
4
4
|
export const marked = new Marked(
|
|
5
|
-
{mangle: false, headerIds: false},
|
|
5
|
+
{mangle: false, headerIds: false, breaks: true},
|
|
6
6
|
{
|
|
7
7
|
renderer: {
|
|
8
8
|
image(this: any, href: string | null, title: string | null, text: string) {
|
|
@@ -31,7 +31,7 @@ export const marked = new Marked(
|
|
|
31
31
|
link(this: any, href: string | null, title: string | null, text: string) {
|
|
32
32
|
if (href) {
|
|
33
33
|
// 匹配以 http:// 或 https:// 开头,所有 URL 主体字符,遇到第一个非主体字符(如中文括号、空格、表情符号等)时停止
|
|
34
|
-
let ret = href.replace(/https?:\/\/[\w\-./?=&:#]+(?=[^\w\-./?=&:#]|$)/g, (matchedUrl) => {
|
|
34
|
+
let ret = href.replace(/&/g, '&').replace(/https?:\/\/[\w\-./?=&:#]+(?=[^\w\-./?=&:#]|$)/g, (matchedUrl) => {
|
|
35
35
|
let isURLInText = false;
|
|
36
36
|
if (matchedUrl !== href) {
|
|
37
37
|
// 如果 text 里包含 url,我们就用 matchedUrl 作为 a 标签的值;否则用 text 作为值
|
|
@@ -57,6 +57,7 @@ const extractVideoSrc = (text: string) => {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
export const parseMarkdown = (text: string) => {
|
|
60
|
-
|
|
60
|
+
// 漫游消息里存储的换行符可能是\n\n,marked 库没法识别成换行(能识别\n),这里替换成<br/>
|
|
61
|
+
let ret = marked.parse(text.replace(/\n\n/g, '<br/>'));
|
|
61
62
|
return typeof ret === 'string' ? ret : '';
|
|
62
63
|
};
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
class="welcome-item"
|
|
25
25
|
@click="handleContentListItemClick(item)"
|
|
26
26
|
>
|
|
27
|
-
<div class="item-
|
|
27
|
+
<div class="item-container">
|
|
28
|
+
<div class="item-content">{{ item.content }}</div>
|
|
29
|
+
</div>
|
|
28
30
|
</div>
|
|
29
31
|
<div class="welcome-item welcome-item-hidden">
|
|
30
32
|
{{ longestContent }}
|
|
@@ -195,13 +197,18 @@ export default {
|
|
|
195
197
|
color: #1c66e5;
|
|
196
198
|
gap: 10px;
|
|
197
199
|
box-sizing: border-box;
|
|
198
|
-
.item-
|
|
200
|
+
.item-container {
|
|
199
201
|
text-align: center;
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
202
|
+
max-width: 100%;
|
|
203
|
+
.item-content {
|
|
204
|
+
display: inline-block;
|
|
205
|
+
text-align: left;
|
|
206
|
+
overflow-wrap: break-word;
|
|
207
|
+
word-break: normal;
|
|
208
|
+
width: 100%;
|
|
209
|
+
}
|
|
204
210
|
}
|
|
211
|
+
|
|
205
212
|
}
|
|
206
213
|
|
|
207
214
|
.welcome-item:hover {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<span
|
|
4
4
|
v-for="(item, index) in textMessageData.text"
|
|
5
5
|
:key="index"
|
|
6
|
-
>
|
|
6
|
+
>
|
|
7
7
|
<span v-if="item.name === 'text' && enableURLDetection === 1"
|
|
8
8
|
class="text"
|
|
9
9
|
v-html="item.text"
|
|
@@ -64,7 +64,8 @@ const textMessageData = computed(() => {
|
|
|
64
64
|
+ CUSTOM_BASIC_EMOJI_URL_MAPPING[item.emojiKey];
|
|
65
65
|
}
|
|
66
66
|
} else if (item.name === 'text' && enableURLDetection.value) {
|
|
67
|
-
|
|
67
|
+
// 开启 url 识别时先移除 html 标签,避免 xss 漏洞
|
|
68
|
+
item.text = item.text.replace(/<[^>]+>/g, '').replace(/https?:\/\/[\w\-./?=&:#]+(?=[^\w\-./?=&:#]|$)/g, (url) => {
|
|
68
69
|
return `<a href="${url}" target="_blank" rel="noopener noreferrer" class="message-text-link" style="color: ${linkColor.value}; text-decoration: underline;">${url}</a>`;
|
|
69
70
|
}) || '';
|
|
70
71
|
}
|
|
@@ -27,7 +27,7 @@ import { isH5 } from '../../../utils/env';
|
|
|
27
27
|
import { ToolbarButtonModel } from '../../../interface';
|
|
28
28
|
import Icon from '../../common/Icon.vue';
|
|
29
29
|
import { TOOLBAR_BUTTON_TYPE } from '../../../constant';
|
|
30
|
-
import { isEnabledMessageReadReceiptGlobal, openSafeUrl, getTo, isNonEmptyObject, transferToTaskFlow, transferToHuman } from '../../../utils/utils';
|
|
30
|
+
import { isEnabledMessageReadReceiptGlobal, openSafeUrl, getTo, isNonEmptyObject, transferToTaskFlow, transferToHuman, debounce } from '../../../utils/utils';
|
|
31
31
|
import ToolbarButtonHumanService from './toolbar-button-human-service.vue';
|
|
32
32
|
import ToolbarButtonServiceRating from './toolbar-button-service-rating.vue';
|
|
33
33
|
import ToolbarButtonEndHumanService from './toolbar-button-end-human-service.vue';
|
|
@@ -77,11 +77,14 @@ const onCanEndConversationUpdate = (data: {conversationID: string, value: boolea
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
const onClick = debounce((item:ToolbarButtonModel, index: number) => {
|
|
81
|
+
if (!currentConversation.value) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
81
84
|
if (item.type === 1 && item.content) {
|
|
82
85
|
TUIChatService.sendTextMessage({
|
|
83
|
-
to: getTo(currentConversation
|
|
84
|
-
conversationType: currentConversation
|
|
86
|
+
to: getTo(currentConversation.value),
|
|
87
|
+
conversationType: currentConversation.value.type,
|
|
85
88
|
payload: {
|
|
86
89
|
text: item.content
|
|
87
90
|
},
|
|
@@ -96,9 +99,9 @@ function onClick(item:ToolbarButtonModel, index: number) {
|
|
|
96
99
|
} else if (props.toolbarButtonList !== undefined && typeof props.toolbarButtonList[index].clickEvent === 'function') {
|
|
97
100
|
props.toolbarButtonList[index].clickEvent();
|
|
98
101
|
}
|
|
99
|
-
}
|
|
102
|
+
}, 300);
|
|
100
103
|
|
|
101
|
-
|
|
104
|
+
const shouldRender = (item: ToolbarButtonModel) => {
|
|
102
105
|
if (item.isEnabled === 1) {
|
|
103
106
|
return true;
|
|
104
107
|
} else if (item.isEnabled === 0) {
|
|
@@ -155,5 +158,7 @@ function shouldRender(item: ToolbarButtonModel) {
|
|
|
155
158
|
text-overflow: ellipsis;
|
|
156
159
|
max-width: 100px;
|
|
157
160
|
overflow: hidden;
|
|
161
|
+
min-width: 25px;
|
|
162
|
+
text-align: center;
|
|
158
163
|
}
|
|
159
164
|
</style>
|
package/components/CustomerServiceChat/message-toolbar-button/toolbar-button-end-human-service.vue
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div :class="['toolbar-button', isH5 ? 'toolbar-button-h5' : '']" @click="onClick">
|
|
2
|
+
<div :class="['toolbar-button', isH5 ? 'toolbar-button-h5' : '', isClicked ? 'end-conversation-button-clicked' : '']" @click="onClick">
|
|
3
3
|
<Icon v-if="props.icon" class="toolbar-button-icon" :file="props.icon" width="14px" height="14px"/>
|
|
4
4
|
<div class="toolbar-button-text">
|
|
5
5
|
{{ props.title || TUITranslateService.t('AIDesk.结束人工会话') }}
|
|
6
6
|
</div>
|
|
7
|
-
|
|
7
|
+
</div>
|
|
8
8
|
</template>
|
|
9
9
|
<script lang="ts" setup>
|
|
10
10
|
import vue from '../../../adapter-vue';
|
|
@@ -15,6 +15,7 @@ import { TUITranslateService, TUIChatService, IConversationModel, TUIStore, Stor
|
|
|
15
15
|
import { CUSTOM_MESSAGE_SRC } from '../../../constant';
|
|
16
16
|
import { isEnabledMessageReadReceiptGlobal, getTo } from '../../../utils/utils';
|
|
17
17
|
const currentConversation = ref<IConversationModel>();
|
|
18
|
+
const isClicked = ref(false);
|
|
18
19
|
interface IProps {
|
|
19
20
|
title?:string;
|
|
20
21
|
icon?:string | undefined;
|
|
@@ -42,9 +43,13 @@ const onCurrentConversationUpdate = (conversation: IConversationModel) => {
|
|
|
42
43
|
};
|
|
43
44
|
|
|
44
45
|
const onClick = () => {
|
|
46
|
+
if (isClicked.value || !currentConversation.value) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
isClicked.value = true;
|
|
45
50
|
TUIChatService.sendCustomMessage({
|
|
46
|
-
to: getTo(currentConversation
|
|
47
|
-
conversationType: currentConversation
|
|
51
|
+
to: getTo(currentConversation.value),
|
|
52
|
+
conversationType: currentConversation.value.type,
|
|
48
53
|
payload: {
|
|
49
54
|
data: JSON.stringify({
|
|
50
55
|
customerServicePlugin: 0,
|
|
@@ -56,4 +61,10 @@ const onClick = () => {
|
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
</script>
|
|
59
|
-
<style
|
|
64
|
+
<style>
|
|
65
|
+
.end-conversation-button-clicked {
|
|
66
|
+
background: #f0f2f9;
|
|
67
|
+
color: #97A3B4;
|
|
68
|
+
cursor: default;
|
|
69
|
+
}
|
|
70
|
+
</style>
|
package/components/CustomerServiceChat/message-toolbar-button/toolbar-button-human-service.vue
CHANGED
|
@@ -12,7 +12,7 @@ const { ref, onMounted, onUnmounted } = vue;
|
|
|
12
12
|
import { isH5 } from '../../../utils/env';
|
|
13
13
|
import Icon from '../../common/Icon.vue';
|
|
14
14
|
import { TUITranslateService, TUIChatService, IConversationModel, StoreName, TUIStore } from '@tencentcloud/chat-uikit-engine';
|
|
15
|
-
import { isEnabledMessageReadReceiptGlobal, getTo } from '../../../utils/utils';
|
|
15
|
+
import { isEnabledMessageReadReceiptGlobal, getTo, debounce } from '../../../utils/utils';
|
|
16
16
|
const currentConversation = ref<IConversationModel>();
|
|
17
17
|
interface IProps {
|
|
18
18
|
title?:string;
|
|
@@ -40,16 +40,19 @@ const onCurrentConversationUpdate = (conversation: IConversationModel) => {
|
|
|
40
40
|
currentConversation.value = conversation;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
const onClick = () => {
|
|
43
|
+
const onClick = debounce(() => {
|
|
44
|
+
if (!currentConversation.value) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
44
47
|
TUIChatService.sendTextMessage({
|
|
45
|
-
to: getTo(currentConversation
|
|
46
|
-
conversationType: currentConversation
|
|
48
|
+
to: getTo(currentConversation.value),
|
|
49
|
+
conversationType: currentConversation.value.type,
|
|
47
50
|
payload: {
|
|
48
51
|
text: TUITranslateService.t('AIDesk.转人工服务')
|
|
49
52
|
},
|
|
50
53
|
needReadReceipt: isEnabledMessageReadReceiptGlobal(),
|
|
51
54
|
});
|
|
52
|
-
}
|
|
55
|
+
}, 300);
|
|
53
56
|
|
|
54
57
|
</script>
|
|
55
58
|
<style></style>
|
package/components/CustomerServiceChat/message-toolbar-button/toolbar-button-service-rating.vue
CHANGED
|
@@ -13,7 +13,7 @@ import { isH5 } from '../../../utils/env';
|
|
|
13
13
|
import Icon from '../../common/Icon.vue';
|
|
14
14
|
import { TUITranslateService, TUIChatService, IConversationModel, StoreName, TUIStore } from '@tencentcloud/chat-uikit-engine';
|
|
15
15
|
import { CUSTOM_MESSAGE_SRC } from '../../../constant';
|
|
16
|
-
import { isEnabledMessageReadReceiptGlobal, getTo } from '../../../utils/utils';
|
|
16
|
+
import { isEnabledMessageReadReceiptGlobal, getTo, debounce } from '../../../utils/utils';
|
|
17
17
|
const currentConversation = ref<IConversationModel>();
|
|
18
18
|
interface IProps {
|
|
19
19
|
title?:string;
|
|
@@ -41,10 +41,13 @@ const onCurrentConversationUpdate = (conversation: IConversationModel) => {
|
|
|
41
41
|
currentConversation.value = conversation;
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
-
const onClick = () => {
|
|
44
|
+
const onClick = debounce(() => {
|
|
45
|
+
if (!currentConversation.value) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
45
48
|
TUIChatService.sendCustomMessage({
|
|
46
|
-
to: getTo(currentConversation
|
|
47
|
-
conversationType: currentConversation
|
|
49
|
+
to: getTo(currentConversation.value),
|
|
50
|
+
conversationType: currentConversation.value.type,
|
|
48
51
|
payload: {
|
|
49
52
|
data:JSON.stringify({
|
|
50
53
|
src: CUSTOM_MESSAGE_SRC.USER_SATISFACTION,
|
|
@@ -53,7 +56,7 @@ const onClick = () => {
|
|
|
53
56
|
},
|
|
54
57
|
needReadReceipt: isEnabledMessageReadReceiptGlobal(),
|
|
55
58
|
},{ onlineUserOnly: true });
|
|
56
|
-
}
|
|
59
|
+
}, 300);
|
|
57
60
|
|
|
58
61
|
</script>
|
|
59
62
|
<style></style>
|
|
@@ -5,7 +5,7 @@ import TOAST_TYPE from './type';
|
|
|
5
5
|
import MessageConstructor from './index-web.vue';
|
|
6
6
|
//@ts-ignore
|
|
7
7
|
import { vueVersion } from '../../../adapter-vue-web';
|
|
8
|
-
import { VNode } from 'vue';
|
|
8
|
+
import { VNode, ref } from 'vue';
|
|
9
9
|
//@ts-ignore
|
|
10
10
|
const { createVNode, render } = vue;
|
|
11
11
|
|
|
@@ -39,6 +39,7 @@ const Toast = function (options: IToast): IToastReturnType {
|
|
|
39
39
|
zIndex: 20 + seed,
|
|
40
40
|
offset: verticalOffset,
|
|
41
41
|
id,
|
|
42
|
+
visible: true,
|
|
42
43
|
...options,
|
|
43
44
|
onClose: () => {
|
|
44
45
|
Toast.close(id, userOnClose);
|
|
@@ -66,8 +67,20 @@ const Toast = function (options: IToast): IToastReturnType {
|
|
|
66
67
|
},
|
|
67
68
|
};
|
|
68
69
|
case 3:
|
|
70
|
+
let visible = ref(true);
|
|
69
71
|
// @ts-ignore
|
|
70
|
-
vm = createVNode(MessageConstructor,
|
|
72
|
+
vm = createVNode(MessageConstructor, {
|
|
73
|
+
...props,
|
|
74
|
+
'onUpdate:visible': (val: boolean) => {
|
|
75
|
+
visible.value = val;
|
|
76
|
+
if (!val) {
|
|
77
|
+
render(null, container);
|
|
78
|
+
if (container.parentNode) {
|
|
79
|
+
container.parentNode.removeChild(container);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
});
|
|
71
84
|
container = document.createElement('div');
|
|
72
85
|
vm?.props
|
|
73
86
|
&& (vm.props!.onDestroy = () => {
|
|
@@ -83,7 +96,7 @@ const Toast = function (options: IToast): IToastReturnType {
|
|
|
83
96
|
appendTo.appendChild(container.firstElementChild!);
|
|
84
97
|
return {
|
|
85
98
|
close: () => {
|
|
86
|
-
vm?.component?.
|
|
99
|
+
vm?.component?.emit('update:visible', false);
|
|
87
100
|
},
|
|
88
101
|
};
|
|
89
102
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
@after-leave="$emit('destroy')"
|
|
5
5
|
>
|
|
6
6
|
<div
|
|
7
|
-
v-show="
|
|
7
|
+
v-show="toastVisible"
|
|
8
8
|
class="message"
|
|
9
9
|
:class="[handleStyle(type), isH5 && 'message-h5']"
|
|
10
10
|
:style="customStyle"
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
import vue from '../../../adapter-vue';
|
|
21
21
|
import { isH5 } from '../../../utils/env';
|
|
22
22
|
import TOAST_TYPE from './type';
|
|
23
|
-
const { computed, onMounted, ref, watch } = vue;
|
|
23
|
+
const { computed, onMounted, ref, watch, onUnmounted } = vue;
|
|
24
24
|
|
|
25
25
|
const props = defineProps({
|
|
26
26
|
message: {
|
|
@@ -55,14 +55,19 @@ const props = defineProps({
|
|
|
55
55
|
type: String,
|
|
56
56
|
default: '',
|
|
57
57
|
},
|
|
58
|
+
visible: {
|
|
59
|
+
type: Boolean,
|
|
60
|
+
default: false,
|
|
61
|
+
},
|
|
58
62
|
});
|
|
59
|
-
const
|
|
63
|
+
const emit = defineEmits(['update:visible']);
|
|
64
|
+
const toastVisible = ref(props.visible);
|
|
60
65
|
let timer: any;
|
|
61
66
|
|
|
62
67
|
const startTimer = () => {
|
|
63
68
|
if (props.duration > 0) {
|
|
64
69
|
timer = setTimeout(() => {
|
|
65
|
-
if (
|
|
70
|
+
if (toastVisible.value) {
|
|
66
71
|
close();
|
|
67
72
|
}
|
|
68
73
|
}, props.duration);
|
|
@@ -74,7 +79,7 @@ const clearTimer = () => {
|
|
|
74
79
|
};
|
|
75
80
|
|
|
76
81
|
const close = () => {
|
|
77
|
-
visible
|
|
82
|
+
emit('update:visible', false);
|
|
78
83
|
if (typeof props.onClose === 'function') {
|
|
79
84
|
props.onClose();
|
|
80
85
|
}
|
|
@@ -95,7 +100,12 @@ const customStyle = computed<CSSProperties>(() => ({
|
|
|
95
100
|
|
|
96
101
|
onMounted(() => {
|
|
97
102
|
startTimer();
|
|
98
|
-
|
|
103
|
+
toastVisible.value = true;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
onUnmounted(() => {
|
|
107
|
+
clearTimer();
|
|
108
|
+
toastVisible.value = false;
|
|
99
109
|
});
|
|
100
110
|
|
|
101
111
|
const handleStyle = (type?: string) => {
|
package/constant.ts
CHANGED
package/interface.ts
CHANGED
|
@@ -238,4 +238,12 @@ export interface ITransferToHumanModel {
|
|
|
238
238
|
groupID?: number;
|
|
239
239
|
specificMemberList?: Array<string>;
|
|
240
240
|
description?: string;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export interface IHeaderConfig {
|
|
244
|
+
title?: string;
|
|
245
|
+
logo?: string;
|
|
246
|
+
showLogo?: boolean;
|
|
247
|
+
logoWidth?: string;
|
|
248
|
+
logoHeight?: string;
|
|
241
249
|
}
|
package/locales/en/TUIChat.ts
CHANGED
|
@@ -105,8 +105,12 @@ const TUIChat = {
|
|
|
105
105
|
'空': 'Empty',
|
|
106
106
|
'文本包含本地审核拦截词': 'Text contains local moderation blocking words',
|
|
107
107
|
'按住说话': 'Hold to speak',
|
|
108
|
-
'
|
|
109
|
-
'
|
|
108
|
+
'松开发送': 'Release to send',
|
|
109
|
+
'松手取消': 'Release to cancel',
|
|
110
|
+
'录音结束提醒': 'Recording will stop in',
|
|
111
|
+
'语音播放失败': 'Voice playback failed',
|
|
112
|
+
'请检查麦克风访问权限': 'Please check microphone access permissions',
|
|
113
|
+
'按压时间过短,请按压超过1秒': 'Press time too short, please hold for more than 1 second',
|
|
110
114
|
'正在录音': 'Recording',
|
|
111
115
|
'继续上滑可取消': 'Continue to swipe to cancel',
|
|
112
116
|
'松开手指 取消发送': 'Release to cancel',
|
package/locales/fil/TUIChat.ts
CHANGED
|
@@ -106,8 +106,12 @@ const TUIChat = {
|
|
|
106
106
|
'空': 'Walang laman',
|
|
107
107
|
'文本包含本地审核拦截词': 'May mga salitang sinusuri sa lokal na pagbabawal sa teksto',
|
|
108
108
|
'按住说话': 'Pindutin at magsalita',
|
|
109
|
-
'
|
|
110
|
-
'
|
|
109
|
+
'松开发送': 'Ibaba at ipadala',
|
|
110
|
+
'松手取消': 'Ibaba at kanselahin',
|
|
111
|
+
'录音结束提醒': 'Magtatapos ang pag-record sa loob ng',
|
|
112
|
+
'语音播放失败': 'Nabigo ang pag-play ng boses',
|
|
113
|
+
'请检查麦克风访问权限': 'Mangyaring suriin ang mga pahintulot sa access ng mikropono',
|
|
114
|
+
'按压时间过短,请按压超过1秒': 'Masyadong maikli ang pagpindot, pindutin nang higit sa 1 segundo',
|
|
111
115
|
'正在录音': 'Nagre-record',
|
|
112
116
|
'继续上滑可取消': 'Magpatuloy sa pag-swipe pataas para kanselahin',
|
|
113
117
|
'松开手指 取消发送': 'Bitawan ang daliri para kanselahin',
|
package/locales/id/TUIChat.ts
CHANGED
|
@@ -1,75 +1,75 @@
|
|
|
1
1
|
const TUIChat = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
2
|
+
'查看内容': 'Lihat konten',
|
|
3
|
+
'立即填写': 'Isi sekarang',
|
|
4
|
+
'已提交': 'Terkirim',
|
|
5
|
+
'不能为空': 'Tidak boleh kosong',
|
|
6
|
+
'提交': 'Kirim',
|
|
7
|
+
'撤回': 'Tarik kembali',
|
|
8
|
+
'删除': 'Hapus',
|
|
9
|
+
'复制': 'Salin',
|
|
10
|
+
'重新发送': 'Kirim ulang',
|
|
11
|
+
'转发': 'Teruskan',
|
|
12
|
+
'引用': 'Kutip',
|
|
13
|
+
'打开': 'Buka',
|
|
14
|
+
'已读': 'Dibaca',
|
|
15
|
+
'全部已读': 'Semua dibaca',
|
|
16
|
+
'人已读': ' dibaca',
|
|
17
|
+
'人未读': ' belum dibaca',
|
|
18
|
+
'人关闭阅读状态': ' status baca ditutup',
|
|
19
|
+
'消息详情': 'Detail Pesan',
|
|
20
|
+
'关闭阅读状态': 'Status baca ditutup',
|
|
21
|
+
'该消息不存在': 'Pesan tidak ada',
|
|
22
|
+
'无法定位到原消息': 'Tidak dapat menavigasi ke pesan asli',
|
|
23
|
+
'未读': 'Belum dibaca',
|
|
24
|
+
'您': 'Anda',
|
|
25
|
+
'撤回了一条消息': 'menarik kembali pesan',
|
|
26
|
+
'重新编辑': 'Edit ulang',
|
|
27
|
+
'我': 'Saya',
|
|
28
|
+
'查看更多': 'Lihat lebih banyak',
|
|
29
|
+
'转发给': 'Teruskan ke',
|
|
30
|
+
'请输入消息': 'Masukkan pesan',
|
|
31
|
+
'描述': 'Deskripsi',
|
|
32
|
+
'经度': 'Garis bujur',
|
|
33
|
+
'纬度': 'Garis lintang',
|
|
34
|
+
'自定义消息': 'Pesan kustom',
|
|
35
|
+
'图片': '[foto]',
|
|
36
|
+
'语音': '[suara]',
|
|
37
|
+
'视频': '[rekaman video]',
|
|
38
|
+
'表情': '[wajah]',
|
|
39
|
+
'文件': '[dokumen]',
|
|
40
|
+
'自定义': '[pesan kustom]',
|
|
41
|
+
'管理员开启全员禁言': 'Admin mengaktifkan Bisukan Semua',
|
|
42
|
+
'您已被管理员禁言': 'Anda telah dibisukan oleh admin',
|
|
43
|
+
'按Enter发送': 'Tekan Enter untuk mengirim pesan',
|
|
44
|
+
'单击下载': 'Klik untuk mengunduh',
|
|
45
45
|
'下载': 'Unduh',
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
46
|
+
'确认重发该消息?': 'Konfirmasi untuk mengirim ulang pesan?',
|
|
47
|
+
'取消': 'Batal',
|
|
48
|
+
'确定': 'Kirim',
|
|
49
|
+
'对方正在输入': 'Sedang mengetik...',
|
|
50
|
+
'回到最新位置': 'Kembali ke lokasi terbaru',
|
|
51
|
+
'条新消息': ' pesan baru',
|
|
52
|
+
'点此投诉': 'Keluhan',
|
|
53
|
+
'语音通话': 'Panggilan Suara',
|
|
54
|
+
'视频通话': 'Panggilan Video',
|
|
55
|
+
'发起群语音': 'Mulai panggilan suara grup',
|
|
56
|
+
'发起群视频': 'Mulai panggilan video grup',
|
|
57
|
+
'已接听': 'Dijawab',
|
|
58
|
+
'拒绝通话': 'Tolak Panggilan',
|
|
59
|
+
'无应答': 'Tidak Ada Jawaban',
|
|
60
|
+
'取消通话': 'Batalkan Panggilan',
|
|
61
|
+
'发起通话': 'Mulai Panggilan',
|
|
62
|
+
'结束群聊': 'Akhiri Panggilan Grup',
|
|
63
|
+
'通话时长': 'Durasi',
|
|
64
|
+
'欢迎使用TUICallKit': 'Selamat datang di TUICallKit',
|
|
65
|
+
'检测到您暂未集成TUICallKit,无法体验音视频通话功能': 'Terdeteksi bahwa Anda belum mengintegrasikan TUI CallKit, sehingga Anda tidak dapat merasakan panggilan audio dan video.',
|
|
66
|
+
'请点击': 'Silakan klik',
|
|
67
|
+
'集成TUICallKit': ' Integrasikan TUICallKit ',
|
|
68
|
+
'开通腾讯实时音视频服务': 'Integrasi Komunikasi Real-Time Tencent',
|
|
69
|
+
'进行体验': 'untuk merasakan.',
|
|
70
|
+
'您当前购买使用的套餐包暂未开通此功能': 'Paket yang Anda beli tidak mendukung kemampuan ini.',
|
|
71
|
+
'系统消息': 'Bot',
|
|
72
|
+
'转人工服务': 'layanan manusia',
|
|
73
73
|
'点击处理': 'Klik Proses',
|
|
74
74
|
'发送失败': 'Gagal mengirim',
|
|
75
75
|
'复制成功': 'Berhasil disalin ke clipboard',
|
|
@@ -110,8 +110,12 @@ const TUIChat = {
|
|
|
110
110
|
'空': 'Kosong',
|
|
111
111
|
'文本包含本地审核拦截词': 'Teks mengandung kata-kata yang dicegah oleh peninjauan lokal',
|
|
112
112
|
'按住说话': 'Tahan dan bicara',
|
|
113
|
-
'
|
|
114
|
-
'
|
|
113
|
+
'松开发送': 'Lepaskan untuk mengirim',
|
|
114
|
+
'松手取消': 'Lepaskan untuk membatalkan',
|
|
115
|
+
'录音结束提醒': 'Rekaman akan berhenti dalam',
|
|
116
|
+
'语音播放失败': 'Pemutaran suara gagal',
|
|
117
|
+
'请检查麦克风访问权限': 'Harap periksa izin akses mikrofon',
|
|
118
|
+
'按压时间过短,请按压超过1秒': 'Waktu penekanan terlalu singkat, tekan lebih dari 1 detik',
|
|
115
119
|
'正在录音': 'Sedang merekam',
|
|
116
120
|
'继续上滑可取消': 'Lanjutkan menggeser ke atas untuk membatalkan',
|
|
117
121
|
'松开手指 取消发送': 'Lepaskan jari untuk membatalkan',
|