Merge branch 'feat/saml-controllers' into feat/saml-ui

This commit is contained in:
Shivam Mishra
2025-09-09 13:17:19 +05:30
committed by GitHub
521 changed files with 13879 additions and 896 deletions
@@ -0,0 +1,63 @@
<script setup>
import AssignmentCard from './AssignmentCard.vue';
const agentAssignments = [
{
id: 1,
title: 'Assignment policy',
description: 'Manage how conversations get assigned in inboxes.',
features: [
{
icon: 'i-lucide-circle-fading-arrow-up',
label: 'Assign by conversations evenly or by available capacity',
},
{
icon: 'i-lucide-scale',
label: 'Add fair distribution rules to avoid overloading any agent',
},
{
icon: 'i-lucide-inbox',
label: 'Add inboxes to a policy - one policy per inbox',
},
],
},
{
id: 2,
title: 'Agent capacity policy',
description: 'Manage workload for agents.',
features: [
{
icon: 'i-lucide-glass-water',
label: 'Define maximum conversations per inbox',
},
{
icon: 'i-lucide-circle-minus',
label: 'Create exceptions based on labels and time',
},
{
icon: 'i-lucide-users-round',
label: 'Add agents to a policy - one policy per agent',
},
],
},
];
</script>
<template>
<Story
title="Components/AgentManagementPolicy/AssignmentCard"
:layout="{ type: 'grid', width: '1000px' }"
>
<Variant title="Assignment Card">
<div class="px-4 py-4 bg-n-background flex gap-6 justify-between">
<AssignmentCard
v-for="(item, index) in agentAssignments"
:key="index"
:title="item.title"
:description="item.description"
:features="item.features"
/>
</div>
</Variant>
</Story>
</template>
@@ -0,0 +1,49 @@
<script setup>
import Icon from 'dashboard/components-next/icon/Icon.vue';
import Button from 'dashboard/components-next/button/Button.vue';
import CardLayout from 'dashboard/components-next/CardLayout.vue';
defineProps({
title: { type: String, default: '' },
description: { type: String, default: '' },
features: { type: Array, default: () => [] },
});
const emit = defineEmits(['click']);
const handleClick = () => {
emit('click');
};
</script>
<template>
<CardLayout class="[&>div]:px-5 cursor-pointer" @click="handleClick">
<div class="flex flex-col items-start gap-2">
<div class="flex justify-between w-full items-center">
<h3 class="text-n-slate-12 text-base font-medium">{{ title }}</h3>
<Button
xs
slate
ghost
icon="i-lucide-chevron-right"
@click.stop="handleClick"
/>
</div>
<p class="text-n-slate-11 text-sm mb-0">{{ description }}</p>
</div>
<ul class="flex flex-col items-start gap-3 mt-3">
<li
v-for="feature in features"
:key="feature.id"
class="flex items-center gap-3 text-sm"
>
<Icon
:icon="feature.icon"
class="text-n-slate-11 size-4 flex-shrink-0"
/>
{{ feature.label }}
</li>
</ul>
</CardLayout>
</template>
@@ -62,6 +62,7 @@ const segmentsQuery = ref({});
const appliedFilters = useMapGetter('contacts/getAppliedContactFiltersV4');
const contactAttributes = useMapGetter('attributes/getContactAttributes');
const labels = useMapGetter('labels/getLabels');
const hasActiveSegments = computed(
() => props.activeSegment && props.segmentsId !== 0
);
@@ -215,6 +216,7 @@ const setParamsForEditSegmentModal = () => {
countries,
filterTypes: contactFilterItems,
allCustomAttributes: useSnakeCase(contactAttributes.value),
labels: labels.value || [],
};
};
@@ -4,6 +4,10 @@ import { useToggle } from '@vueuse/core';
import { useI18n } from 'vue-i18n';
import { dynamicTime } from 'shared/helpers/timeHelper';
import { usePolicy } from 'dashboard/composables/usePolicy';
import {
isPdfDocument,
formatDocumentLink,
} from 'shared/helpers/documentHelper';
import CardLayout from 'dashboard/components-next/CardLayout.vue';
import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.vue';
@@ -63,6 +67,11 @@ const menuItems = computed(() => {
const createdAt = computed(() => dynamicTime(props.createdAt));
const displayLink = computed(() => formatDocumentLink(props.externalLink));
const linkIcon = computed(() =>
isPdfDocument(props.externalLink) ? 'i-ph-file-pdf' : 'i-ph-link-simple'
);
const handleAction = ({ action, value }) => {
toggleDropdown(false);
emit('action', { action, value, id: props.id });
@@ -71,14 +80,14 @@ const handleAction = ({ action, value }) => {
<template>
<CardLayout>
<div class="flex justify-between w-full gap-1">
<div class="flex gap-1 justify-between w-full">
<span class="text-base text-n-slate-12 line-clamp-1">
{{ name }}
</span>
<div class="flex items-center gap-2">
<div class="flex gap-2 items-center">
<div
v-on-clickaway="() => toggleDropdown(false)"
class="relative flex items-center group"
class="flex relative items-center group"
>
<Button
icon="i-lucide-ellipsis-vertical"
@@ -90,26 +99,26 @@ const handleAction = ({ action, value }) => {
<DropdownMenu
v-if="showActionsDropdown"
:menu-items="menuItems"
class="mt-1 ltr:right-0 rtl:left-0 xl:ltr:right-0 xl:rtl:left-0 top-full"
class="top-full mt-1 ltr:right-0 rtl:left-0 xl:ltr:right-0 xl:rtl:left-0"
@action="handleAction($event)"
/>
</div>
</div>
</div>
<div class="flex items-center justify-between w-full gap-4">
<div class="flex gap-4 justify-between items-center w-full">
<span
class="text-sm shrink-0 truncate text-n-slate-11 flex items-center gap-1"
class="flex gap-1 items-center text-sm truncate shrink-0 text-n-slate-11"
>
<i class="i-woot-captain" />
{{ assistant?.name || '' }}
</span>
<span
class="text-n-slate-11 text-sm truncate flex justify-start flex-1 items-center gap-1"
class="flex flex-1 gap-1 justify-start items-center text-sm truncate text-n-slate-11"
>
<i class="i-ph-link-simple shrink-0" />
<span class="truncate">{{ externalLink }}</span>
<i :class="linkIcon" class="shrink-0" />
<span class="truncate">{{ displayLink }}</span>
</span>
<div class="shrink-0 text-sm text-n-slate-11 line-clamp-1">
<div class="text-sm shrink-0 text-n-slate-11 line-clamp-1">
{{ createdAt }}
</div>
</div>
@@ -3,6 +3,7 @@ import { ref } from 'vue';
import { useStore } from 'dashboard/composables/store';
import { useAlert } from 'dashboard/composables';
import { useI18n } from 'vue-i18n';
import { parseAPIErrorResponse } from 'dashboard/store/utils/api';
import Dialog from 'dashboard/components-next/dialog/Dialog.vue';
import DocumentForm from './DocumentForm.vue';
@@ -12,7 +13,6 @@ const { t } = useI18n();
const store = useStore();
const dialogRef = ref(null);
const documentForm = ref(null);
const i18nKey = 'CAPTAIN.DOCUMENTS.CREATE';
@@ -23,7 +23,7 @@ const handleSubmit = async newDocument => {
dialogRef.value.close();
} catch (error) {
const errorMessage =
error?.response?.message || t(`${i18nKey}.ERROR_MESSAGE`);
parseAPIErrorResponse(error) || t(`${i18nKey}.ERROR_MESSAGE`);
useAlert(errorMessage);
}
};
@@ -48,11 +48,7 @@ defineExpose({ dialogRef });
:show-confirm-button="false"
@close="handleClose"
>
<DocumentForm
ref="documentForm"
@submit="handleSubmit"
@cancel="handleCancel"
/>
<DocumentForm @submit="handleSubmit" @cancel="handleCancel" />
<template #footer />
</Dialog>
</template>
@@ -1,9 +1,10 @@
<script setup>
import { reactive, computed } from 'vue';
import { reactive, computed, ref, nextTick } from 'vue';
import { useI18n } from 'vue-i18n';
import { useVuelidate } from '@vuelidate/core';
import { required, minLength, url } from '@vuelidate/validators';
import { required, minLength, requiredIf, url } from '@vuelidate/validators';
import { useMapGetter } from 'dashboard/composables/store';
import { useAlert } from 'dashboard/composables';
import Input from 'dashboard/components-next/input/Input.vue';
import Button from 'dashboard/components-next/button/Button.vue';
@@ -11,6 +12,8 @@ import ComboBox from 'dashboard/components-next/combobox/ComboBox.vue';
const emit = defineEmits(['submit', 'cancel']);
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
const { t } = useI18n();
const formState = {
@@ -20,14 +23,25 @@ const formState = {
const initialState = {
name: '',
url: '',
assistantId: null,
documentType: 'url',
pdfFile: null,
};
const state = reactive({ ...initialState });
const fileInputRef = ref(null);
const validationRules = {
url: { required, url, minLength: minLength(1) },
url: {
required: requiredIf(() => state.documentType === 'url'),
url: requiredIf(() => state.documentType === 'url' && url),
minLength: requiredIf(() => state.documentType === 'url' && minLength(1)),
},
assistantId: { required },
pdfFile: {
required: requiredIf(() => state.documentType === 'pdf'),
},
};
const assistantList = computed(() =>
@@ -37,10 +51,17 @@ const assistantList = computed(() =>
}))
);
const documentTypeOptions = [
{ value: 'url', label: t('CAPTAIN.DOCUMENTS.FORM.TYPE.URL') },
{ value: 'pdf', label: t('CAPTAIN.DOCUMENTS.FORM.TYPE.PDF') },
];
const v$ = useVuelidate(validationRules, state);
const isLoading = computed(() => formState.uiFlags.value.creatingItem);
const hasPdfFileError = computed(() => v$.value.pdfFile.$error);
const getErrorMessage = (field, errorKey) => {
return v$.value[field].$error
? t(`CAPTAIN.DOCUMENTS.FORM.${errorKey}.ERROR`)
@@ -50,14 +71,57 @@ const getErrorMessage = (field, errorKey) => {
const formErrors = computed(() => ({
url: getErrorMessage('url', 'URL'),
assistantId: getErrorMessage('assistantId', 'ASSISTANT'),
pdfFile: getErrorMessage('pdfFile', 'PDF_FILE'),
}));
const handleCancel = () => emit('cancel');
const prepareDocumentDetails = () => ({
external_link: state.url,
assistant_id: state.assistantId,
});
const handleFileChange = event => {
const file = event.target.files[0];
if (file) {
if (file.type !== 'application/pdf') {
useAlert(t('CAPTAIN.DOCUMENTS.FORM.PDF_FILE.INVALID_TYPE'));
event.target.value = '';
return;
}
if (file.size > MAX_FILE_SIZE) {
// 10MB
useAlert(t('CAPTAIN.DOCUMENTS.FORM.PDF_FILE.TOO_LARGE'));
event.target.value = '';
return;
}
state.pdfFile = file;
state.name = file.name.replace(/\.pdf$/i, '');
}
};
const openFileDialog = () => {
// Use nextTick to ensure the ref is available
nextTick(() => {
if (fileInputRef.value) {
fileInputRef.value.click();
}
});
};
const prepareDocumentDetails = () => {
const formData = new FormData();
formData.append('document[assistant_id]', state.assistantId);
if (state.documentType === 'url') {
formData.append('document[external_link]', state.url);
formData.append('document[name]', state.name || state.url);
} else {
formData.append('document[pdf_file]', state.pdfFile);
formData.append(
'document[name]',
state.name || state.pdfFile.name.replace('.pdf', '')
);
// No need to send external_link for PDF - it's auto-generated in the backend
}
return formData;
};
const handleSubmit = async () => {
const isFormValid = await v$.value.$validate();
@@ -71,13 +135,89 @@ const handleSubmit = async () => {
<template>
<form class="flex flex-col gap-4" @submit.prevent="handleSubmit">
<div class="flex flex-col gap-1">
<label
for="documentType"
class="mb-0.5 text-sm font-medium text-n-slate-12"
>
{{ t('CAPTAIN.DOCUMENTS.FORM.TYPE.LABEL') }}
</label>
<ComboBox
id="documentType"
v-model="state.documentType"
:options="documentTypeOptions"
class="[&>div>button]:bg-n-alpha-black2"
/>
</div>
<Input
v-if="state.documentType === 'url'"
v-model="state.url"
:label="t('CAPTAIN.DOCUMENTS.FORM.URL.LABEL')"
:placeholder="t('CAPTAIN.DOCUMENTS.FORM.URL.PLACEHOLDER')"
:message="formErrors.url"
:message-type="formErrors.url ? 'error' : 'info'"
/>
<div v-if="state.documentType === 'pdf'" class="flex flex-col gap-2">
<label class="text-sm font-medium text-n-slate-12">
{{ t('CAPTAIN.DOCUMENTS.FORM.PDF_FILE.LABEL') }}
</label>
<div class="relative">
<input
ref="fileInputRef"
type="file"
accept=".pdf"
class="hidden"
@change="handleFileChange"
/>
<Button
type="button"
:color="hasPdfFileError ? 'ruby' : 'slate'"
:variant="hasPdfFileError ? 'outline' : 'solid'"
class="!w-full !h-auto !justify-between !py-4"
@click="openFileDialog"
>
<template #default>
<div class="flex gap-2 items-center">
<div
class="flex justify-center items-center w-10 h-10 rounded-lg bg-n-slate-3"
>
<i class="text-xl i-ph-file-pdf text-n-slate-11" />
</div>
<div class="flex flex-col flex-1 gap-1 items-start">
<p class="m-0 text-sm font-medium text-n-slate-12">
{{
state.pdfFile
? state.pdfFile.name
: t('CAPTAIN.DOCUMENTS.FORM.PDF_FILE.CHOOSE_FILE')
}}
</p>
<p class="m-0 text-xs text-n-slate-11">
{{
state.pdfFile
? `${(state.pdfFile.size / 1024 / 1024).toFixed(2)} MB`
: t('CAPTAIN.DOCUMENTS.FORM.PDF_FILE.HELP_TEXT')
}}
</p>
</div>
</div>
<i class="i-lucide-upload text-n-slate-11" />
</template>
</Button>
</div>
<p v-if="formErrors.pdfFile" class="text-xs text-n-ruby-9">
{{ formErrors.pdfFile }}
</p>
</div>
<Input
v-model="state.name"
:label="t('CAPTAIN.DOCUMENTS.FORM.NAME.LABEL')"
:placeholder="t('CAPTAIN.DOCUMENTS.FORM.NAME.PLACEHOLDER')"
/>
<div class="flex flex-col gap-1">
<label for="assistant" class="mb-0.5 text-sm font-medium text-n-slate-12">
{{ t('CAPTAIN.DOCUMENTS.FORM.ASSISTANT.LABEL') }}
@@ -88,12 +228,12 @@ const handleSubmit = async () => {
:options="assistantList"
:has-error="!!formErrors.assistantId"
:placeholder="t('CAPTAIN.DOCUMENTS.FORM.ASSISTANT.PLACEHOLDER')"
class="[&>div>button]:bg-n-alpha-black2 [&>div>button:not(.focused)]:dark:outline-n-weak [&>div>button:not(.focused)]:hover:!outline-n-slate-6"
class="[&>div>button]:bg-n-alpha-black2"
:message="formErrors.assistantId"
/>
</div>
<div class="flex items-center justify-between w-full gap-3">
<div class="flex gap-3 justify-between items-center w-full">
<Button
type="button"
variant="faded"
@@ -96,8 +96,12 @@ watch(
:label="selectedLabel"
trailing-icon
:disabled="disabled"
class="justify-between w-full !px-3 !py-2.5 text-n-slate-12 font-normal group-hover/combobox:border-n-slate-6 [&:not(.focused)]:hover:enabled:outline-n-slate-6 [&:not(.focused)]:dark:hover:enabled:outline-n-slate-6 [&:not(.focused)]:dark:outline-n-weak focus:outline-n-brand"
:class="{ focused: open }"
class="justify-between w-full !px-3 !py-2.5 text-n-slate-12 font-normal group-hover/combobox:border-n-slate-6 focus:outline-n-brand"
:class="{
focused: open,
'[&:not(.focused)]:dark:outline-n-weak [&:not(.focused)]:hover:enabled:outline-n-slate-6 [&:not(.focused)]:dark:hover:enabled:outline-n-slate-6':
!hasError,
}"
:icon="open ? 'i-lucide-chevron-up' : 'i-lucide-chevron-down'"
@click="toggleDropdown"
/>
@@ -15,7 +15,7 @@ defineProps({
>
{{ title }}
</div>
<ul class="gap-2 grid reset-base list-none px-2">
<ul class="gap-2 grid reset-base list-none px-2 max-h-96 overflow-y-auto">
<slot />
</ul>
</div>
@@ -34,14 +34,17 @@ const formatOperatorLabel = operator => {
};
const formatFilterValue = value => {
// Case 1: null, undefined, empty string
if (!value) return '';
// Case 2: array → map each item, use name if present, else the item itself
if (Array.isArray(value)) {
return value.join(', ');
return value.map(item => item?.name ?? item).join(', ');
}
if (typeof value === 'object' && value.name) {
return value.name;
}
return value;
// Case 3: object with a "name" property → return name
// Case 4: primitive (string, number, etc.) → return as is
return value?.name ?? value;
};
</script>
@@ -66,6 +69,7 @@ const formatFilterValue = value => {
</span>
<span
v-if="filter.values"
:title="formatFilterValue(filter.values)"
class="lowercase truncate text-n-slate-12"
:class="{
'first-letter:capitalize': shouldCapitalizeFirstLetter(
@@ -50,6 +50,7 @@ export function useContactFilterContext() {
const { t } = useI18n();
const contactAttributes = useMapGetter('attributes/getContactAttributes');
const labels = useMapGetter('labels/getLabels');
const {
equalityOperators,
@@ -184,6 +185,20 @@ export function useContactFilterContext() {
filterOperators: equalityOperators.value,
attributeModel: 'standard',
},
{
attributeKey: CONTACT_ATTRIBUTES.LABELS,
value: CONTACT_ATTRIBUTES.LABELS,
attributeName: t('CONTACTS_FILTER.ATTRIBUTES.LABELS'),
label: t('CONTACTS_FILTER.ATTRIBUTES.LABELS'),
inputType: 'multiSelect',
options: labels.value?.map(label => ({
id: label.title,
name: label.title,
})),
dataType: 'text',
filterOperators: equalityOperators.value,
attributeModel: 'standard',
},
...customFilterTypes.value,
]);
@@ -28,6 +28,7 @@ export const CONTACT_ATTRIBUTES = {
LAST_ACTIVITY_AT: 'last_activity_at',
REFERER: 'referer',
BLOCKED: 'blocked',
LABELS: 'labels',
};
/**
@@ -2,23 +2,23 @@ import { computed } from 'vue';
export function useChannelIcon(inbox) {
const channelTypeIconMap = {
'Channel::Api': 'i-ri-cloudy-fill',
'Channel::Email': 'i-ri-mail-fill',
'Channel::FacebookPage': 'i-ri-messenger-fill',
'Channel::Line': 'i-ri-line-fill',
'Channel::Sms': 'i-ri-chat-1-fill',
'Channel::Telegram': 'i-ri-telegram-fill',
'Channel::TwilioSms': 'i-ri-chat-1-fill',
'Channel::Api': 'i-woot-api',
'Channel::Email': 'i-woot-mail',
'Channel::FacebookPage': 'i-woot-messenger',
'Channel::Line': 'i-woot-line',
'Channel::Sms': 'i-woot-sms',
'Channel::Telegram': 'i-woot-telegram',
'Channel::TwilioSms': 'i-woot-sms',
'Channel::TwitterProfile': 'i-ri-twitter-x-fill',
'Channel::WebWidget': 'i-ri-global-fill',
'Channel::Whatsapp': 'i-ri-whatsapp-fill',
'Channel::Instagram': 'i-ri-instagram-fill',
'Channel::WebWidget': 'i-woot-website',
'Channel::Whatsapp': 'i-woot-whatsapp',
'Channel::Instagram': 'i-woot-instagram',
'Channel::Voice': 'i-ri-phone-fill',
};
const providerIconMap = {
microsoft: 'i-ri-microsoft-fill',
google: 'i-ri-google-fill',
microsoft: 'i-woot-outlook',
google: 'i-woot-gmail',
};
const channelIcon = computed(() => {
@@ -34,7 +34,7 @@ export function useChannelIcon(inbox) {
// Special case for Twilio whatsapp
if (type === 'Channel::TwilioSms' && inboxDetails.medium === 'whatsapp') {
icon = 'i-ri-whatsapp-fill';
icon = 'i-woot-whatsapp';
}
return icon ?? 'i-ri-global-fill';
@@ -4,19 +4,19 @@ describe('useChannelIcon', () => {
it('returns correct icon for API channel', () => {
const inbox = { channel_type: 'Channel::Api' };
const { value: icon } = useChannelIcon(inbox);
expect(icon).toBe('i-ri-cloudy-fill');
expect(icon).toBe('i-woot-api');
});
it('returns correct icon for Facebook channel', () => {
const inbox = { channel_type: 'Channel::FacebookPage' };
const { value: icon } = useChannelIcon(inbox);
expect(icon).toBe('i-ri-messenger-fill');
expect(icon).toBe('i-woot-messenger');
});
it('returns correct icon for WhatsApp channel', () => {
const inbox = { channel_type: 'Channel::Whatsapp' };
const { value: icon } = useChannelIcon(inbox);
expect(icon).toBe('i-ri-whatsapp-fill');
expect(icon).toBe('i-woot-whatsapp');
});
it('returns correct icon for Voice channel', () => {
@@ -28,19 +28,19 @@ describe('useChannelIcon', () => {
it('returns correct icon for Line channel', () => {
const inbox = { channel_type: 'Channel::Line' };
const { value: icon } = useChannelIcon(inbox);
expect(icon).toBe('i-ri-line-fill');
expect(icon).toBe('i-woot-line');
});
it('returns correct icon for SMS channel', () => {
const inbox = { channel_type: 'Channel::Sms' };
const { value: icon } = useChannelIcon(inbox);
expect(icon).toBe('i-ri-chat-1-fill');
expect(icon).toBe('i-woot-sms');
});
it('returns correct icon for Telegram channel', () => {
const inbox = { channel_type: 'Channel::Telegram' };
const { value: icon } = useChannelIcon(inbox);
expect(icon).toBe('i-ri-telegram-fill');
expect(icon).toBe('i-woot-telegram');
});
it('returns correct icon for Twitter channel', () => {
@@ -52,20 +52,20 @@ describe('useChannelIcon', () => {
it('returns correct icon for WebWidget channel', () => {
const inbox = { channel_type: 'Channel::WebWidget' };
const { value: icon } = useChannelIcon(inbox);
expect(icon).toBe('i-ri-global-fill');
expect(icon).toBe('i-woot-website');
});
it('returns correct icon for Instagram channel', () => {
const inbox = { channel_type: 'Channel::Instagram' };
const { value: icon } = useChannelIcon(inbox);
expect(icon).toBe('i-ri-instagram-fill');
expect(icon).toBe('i-woot-instagram');
});
describe('TwilioSms channel', () => {
it('returns chat icon for regular Twilio SMS channel', () => {
const inbox = { channel_type: 'Channel::TwilioSms' };
const { value: icon } = useChannelIcon(inbox);
expect(icon).toBe('i-ri-chat-1-fill');
expect(icon).toBe('i-woot-sms');
});
it('returns WhatsApp icon for Twilio SMS with WhatsApp medium', () => {
@@ -74,7 +74,7 @@ describe('useChannelIcon', () => {
medium: 'whatsapp',
};
const { value: icon } = useChannelIcon(inbox);
expect(icon).toBe('i-ri-whatsapp-fill');
expect(icon).toBe('i-woot-whatsapp');
});
it('returns chat icon for Twilio SMS with non-WhatsApp medium', () => {
@@ -83,7 +83,7 @@ describe('useChannelIcon', () => {
medium: 'sms',
};
const { value: icon } = useChannelIcon(inbox);
expect(icon).toBe('i-ri-chat-1-fill');
expect(icon).toBe('i-woot-sms');
});
it('returns chat icon for Twilio SMS with undefined medium', () => {
@@ -92,7 +92,7 @@ describe('useChannelIcon', () => {
medium: undefined,
};
const { value: icon } = useChannelIcon(inbox);
expect(icon).toBe('i-ri-chat-1-fill');
expect(icon).toBe('i-woot-sms');
});
});
@@ -100,7 +100,7 @@ describe('useChannelIcon', () => {
it('returns mail icon for generic email channel', () => {
const inbox = { channel_type: 'Channel::Email' };
const { value: icon } = useChannelIcon(inbox);
expect(icon).toBe('i-ri-mail-fill');
expect(icon).toBe('i-woot-mail');
});
it('returns Microsoft icon for Microsoft email provider', () => {
@@ -109,7 +109,7 @@ describe('useChannelIcon', () => {
provider: 'microsoft',
};
const { value: icon } = useChannelIcon(inbox);
expect(icon).toBe('i-ri-microsoft-fill');
expect(icon).toBe('i-woot-outlook');
});
it('returns Google icon for Google email provider', () => {
@@ -118,7 +118,7 @@ describe('useChannelIcon', () => {
provider: 'google',
};
const { value: icon } = useChannelIcon(inbox);
expect(icon).toBe('i-ri-google-fill');
expect(icon).toBe('i-woot-gmail');
});
});
@@ -36,6 +36,7 @@ import DyteBubble from './bubbles/Dyte.vue';
import LocationBubble from './bubbles/Location.vue';
import CSATBubble from './bubbles/CSAT.vue';
import FormBubble from './bubbles/Form.vue';
import VoiceCallBubble from './bubbles/VoiceCall.vue';
import MessageError from './MessageError.vue';
import ContextMenu from 'dashboard/modules/conversations/components/MessageContextMenu.vue';
@@ -280,6 +281,10 @@ const componentToRender = computed(() => {
return FormBubble;
}
if (props.contentType === CONTENT_TYPES.VOICE_CALL) {
return VoiceCallBubble;
}
if (props.contentType === CONTENT_TYPES.INCOMING_EMAIL) {
return EmailBubble;
}
@@ -10,6 +10,10 @@ import { useI18n } from 'vue-i18n';
import { BUS_EVENTS } from 'shared/constants/busEvents';
import { MESSAGE_VARIANTS, ORIENTATION } from '../constants';
const props = defineProps({
hideMeta: { type: Boolean, default: false },
});
const { variant, orientation, inReplyTo, shouldGroupWithNext } =
useMessageContext();
const { t } = useI18n();
@@ -64,6 +68,13 @@ const scrollToMessage = () => {
});
};
const shouldShowMeta = computed(
() =>
!props.hideMeta &&
!shouldGroupWithNext.value &&
variant.value !== MESSAGE_VARIANTS.ACTIVITY
);
const replyToPreview = computed(() => {
if (!inReplyTo) return '';
@@ -93,16 +104,16 @@ const replyToPreview = computed(() => {
>
<div
v-if="inReplyTo"
class="bg-n-alpha-black1 rounded-lg p-2 -mx-1 mb-2 cursor-pointer"
class="p-2 -mx-1 mb-2 rounded-lg cursor-pointer bg-n-alpha-black1"
@click="scrollToMessage"
>
<span class="line-clamp-2 break-all">
<span class="break-all line-clamp-2">
{{ replyToPreview }}
</span>
</div>
<slot />
<MessageMeta
v-if="!shouldGroupWithNext && variant !== MESSAGE_VARIANTS.ACTIVITY"
v-if="shouldShowMeta"
:class="[
flexOrientationClass,
variant === MESSAGE_VARIANTS.EMAIL ? 'px-3 pb-3' : '',
@@ -1,6 +1,7 @@
<script setup>
import { computed, useTemplateRef, ref, onMounted } from 'vue';
import { Letter } from 'vue-letter';
import { sanitizeTextForRender } from '@chatwoot/utils';
import { allowedCssProperties } from 'lettersanitizer';
import Icon from 'next/icon/Icon.vue';
@@ -37,11 +38,13 @@ const { hasTranslations, translationContent } =
const originalEmailText = computed(() => {
const text =
contentAttributes?.value?.email?.textContent?.full ?? content.value;
return text?.replace(/\n/g, '<br>');
return sanitizeTextForRender(text);
});
const originalEmailHtml = computed(
() => contentAttributes?.value?.email?.htmlContent?.full || ''
() =>
contentAttributes?.value?.email?.htmlContent?.full ||
originalEmailText.value
);
const messageContent = computed(() => {
@@ -0,0 +1,43 @@
<script setup>
import { computed } from 'vue';
import BaseBubble from 'next/message/bubbles/Base.vue';
import { useMessageContext } from '../provider.js';
import { useVoiceCallStatus } from 'dashboard/composables/useVoiceCallStatus';
const { contentAttributes } = useMessageContext();
const data = computed(() => contentAttributes.value?.data);
const status = computed(() => data.value?.status);
const direction = computed(() => data.value?.call_direction);
const { labelKey, subtextKey, bubbleIconBg, bubbleIconName } =
useVoiceCallStatus(status, direction);
const containerRingClass = computed(() => {
return status.value === 'ringing' ? 'ring-1 ring-emerald-300' : '';
});
</script>
<template>
<BaseBubble class="p-0 border-none" hide-meta>
<div
class="flex overflow-hidden flex-col w-full max-w-xs bg-white rounded-lg border border-slate-100 text-slate-900 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-100"
:class="containerRingClass"
>
<div class="flex gap-3 items-center p-3 w-full">
<div
class="flex justify-center items-center rounded-full size-10 shrink-0"
:class="bubbleIconBg"
>
<span class="text-xl" :class="bubbleIconName" />
</div>
<div class="flex overflow-hidden flex-col flex-grow">
<span class="text-base font-medium truncate">{{ $t(labelKey) }}</span>
<span class="text-xs text-slate-500">{{ $t(subtextKey) }}</span>
</div>
</div>
</div>
</BaseBubble>
</template>
@@ -64,6 +64,7 @@ export const CONTENT_TYPES = {
INPUT_CSAT: 'input_csat',
INTEGRATIONS: 'integrations',
STICKER: 'sticker',
VOICE_CALL: 'voice_call',
};
export const MEDIA_TYPES = [
@@ -25,7 +25,7 @@ const reauthorizationRequired = computed(() => {
<template>
<span
class="size-4 grid place-content-center rounded-full bg-n-alpha-2"
class="size-5 grid place-content-center rounded-full bg-n-alpha-2"
:class="{ 'bg-n-solid-blue': active }"
>
<ChannelIcon :inbox="inbox" class="size-3" />
@@ -128,7 +128,7 @@ const menuItems = computed(() => {
to: accountScopedRoute('inbox_view'),
activeOn: ['inbox_view', 'inbox_view_conversation'],
getterKeys: {
badge: 'notifications/getHasUnreadNotifications',
count: 'notifications/getUnreadCount',
},
},
{
@@ -422,6 +422,12 @@ const menuItems = computed(() => {
icon: 'i-lucide-users',
to: accountScopedRoute('settings_teams_list'),
},
{
name: 'Settings Agent Assignment',
label: t('SIDEBAR.AGENT_ASSIGNMENT'),
icon: 'i-lucide-user-cog',
to: accountScopedRoute('assignment_policy_index'),
},
{
name: 'Settings Inboxes',
label: t('SIDEBAR.INBOXES'),
@@ -1,4 +1,5 @@
<script setup>
import { computed } from 'vue';
import { useMapGetter } from 'dashboard/composables/store.js';
import Icon from 'next/icon/Icon.vue';
@@ -16,12 +17,16 @@ const props = defineProps({
const emit = defineEmits(['toggle']);
const showBadge = useMapGetter(props.getterKeys.badge);
const dynamicCount = useMapGetter(props.getterKeys.count);
const count = computed(() =>
dynamicCount.value > 99 ? '99+' : dynamicCount.value
);
</script>
<template>
<component
:is="to ? 'router-link' : 'div'"
class="flex items-center gap-2 px-2 py-1.5 rounded-lg h-8"
class="flex items-center gap-2 px-2 py-1.5 rounded-lg h-8 min-w-0"
role="button"
draggable="false"
:to="to"
@@ -40,9 +45,21 @@ const showBadge = useMapGetter(props.getterKeys.badge);
class="size-2 -top-px ltr:-right-px rtl:-left-px bg-n-brand absolute rounded-full border border-n-solid-2"
/>
</div>
<span class="text-sm font-medium leading-5 flex-grow">
{{ label }}
</span>
<div class="flex items-center gap-1.5 flex-grow min-w-0">
<span class="text-sm font-medium leading-5 truncate">
{{ label }}
</span>
<span
v-if="dynamicCount && !expandable"
class="rounded-md capitalize text-xs leading-5 font-medium text-center outline outline-1 px-1 flex-shrink-0"
:class="{
'text-n-blue-text outline-n-slate-6': isActive,
'text-n-slate-11 outline-n-strong': !isActive,
}"
>
{{ count }}
</span>
</div>
<span
v-if="expandable"
v-show="isExpanded"
@@ -1,50 +1,57 @@
<script>
export default {
props: {
title: {
type: String,
required: true,
},
src: {
type: String,
required: true,
},
isComingSoon: {
type: Boolean,
default: false,
},
<script setup>
import Icon from 'next/icon/Icon.vue';
defineProps({
title: {
type: String,
required: true,
},
};
description: {
type: String,
default: '',
},
icon: {
type: String,
required: true,
},
isComingSoon: {
type: Boolean,
default: false,
},
});
</script>
<template>
<button
class="relative bg-n-background cursor-pointer flex flex-col justify-end transition-all duration-200 ease-in -m-px py-4 px-0 items-center border border-solid border-n-weak hover:border-n-brand hover:shadow-md hover:z-50 disabled:opacity-60"
class="relative bg-n-solid-1 gap-6 cursor-pointer rounded-2xl flex flex-col justify-start transition-all duration-200 ease-in -m-px py-6 px-5 items-start border border-solid border-n-weak"
:class="{
'hover:enabled:border-n-blue-9 hover:enabled:shadow-md disabled:opacity-60 disabled:cursor-not-allowed':
!isComingSoon,
'cursor-not-allowed disabled:opacity-80': isComingSoon,
}"
>
<img :src="src" :alt="title" draggable="false" class="w-1/2 my-4 mx-auto" />
<h3 class="text-n-slate-12 text-base text-center capitalize">
{{ title }}
</h3>
<div
class="flex size-10 items-center justify-center rounded-full bg-n-alpha-2"
>
<Icon :icon="icon" class="text-n-slate-10 size-6" />
</div>
<div class="flex flex-col items-start gap-1.5">
<h3 class="text-n-slate-12 text-sm text-start font-medium capitalize">
{{ title }}
</h3>
<p class="text-n-slate-11 text-start text-sm">
{{ description }}
</p>
</div>
<div
v-if="isComingSoon"
class="absolute inset-0 flex items-center justify-center backdrop-blur-[2px] rounded-md bg-gradient-to-br from-n-background/90 via-n-background/70 to-n-background/95"
class="absolute inset-0 flex items-center justify-center backdrop-blur-[2px] rounded-2xl bg-gradient-to-br from-n-background/90 via-n-background/70 to-n-background/95 cursor-not-allowed"
>
<span class="text-n-slate-12 font-medium text-base">
<span class="text-n-slate-12 font-medium text-sm">
{{ $t('CHANNEL_SELECTOR.COMING_SOON') }} 🚀
</span>
</div>
</button>
</template>
<style scoped lang="scss">
.inactive {
img {
filter: grayscale(100%);
}
&:hover {
@apply border-n-strong shadow-none cursor-not-allowed;
}
}
</style>
@@ -1,97 +1,81 @@
<script>
export default {
props: {
items: {
type: Array,
default: () => [],
},
<script setup>
import { computed } from 'vue';
import { useRoute } from 'vue-router';
import Icon from 'next/icon/Icon.vue';
const props = defineProps({
items: {
type: Array,
default: () => [],
},
computed: {
classObject() {
return 'w-full';
},
activeIndex() {
return this.items.findIndex(i => i.route === this.$route.name);
},
},
methods: {
isActive(item) {
return this.items.indexOf(item) === this.activeIndex;
},
isOver(item) {
return this.items.indexOf(item) < this.activeIndex;
},
},
};
});
const route = useRoute();
const activeIndex = computed(() => {
const index = props.items.findIndex(i => i.route === route.name);
return index === -1 ? 0 : index;
});
const steps = computed(() =>
props.items.map((item, index) => {
const isActive = index === activeIndex.value;
const isOver = index < activeIndex.value;
return {
...item,
index,
isActive,
isOver,
};
})
);
</script>
<template>
<transition-group
name="wizard-items"
tag="div"
class="wizard-box"
:class="classObject"
>
<transition-group tag="div">
<div
v-for="item in items"
:key="item.route"
class="item"
:class="{ active: isActive(item), over: isOver(item) }"
v-for="step in steps"
:key="step.route"
class="cursor-pointer flex items-start gap-6 relative after:content-[''] after:absolute after:w-0.5 after:h-full after:top-5 ltr:after:left-4 rtl:after:right-4 before:content-[''] before:absolute before:w-0.5 before:h-4 before:top-0 before:left-4 rtl:before:right-4 last:after:hidden last:before:hidden after:bg-n-slate-3 before:bg-n-slate-3"
>
<div class="flex items-center">
<h3
class="text-n-slate-12 text-base font-medium pl-6 overflow-hidden whitespace-nowrap mt-0.5 text-ellipsis leading-tight"
<!-- Circle -->
<div
class="rounded-2xl flex-shrink-0 size-8 border-2 border-n-slate-3 flex items-center justify-center left-2 leading-4 z-10 top-5 transition-all duration-300 ease-in-out"
:class="{
'bg-n-slate-3': step.isActive || step.isOver,
'bg-n-background': !step.isActive && !step.isOver,
}"
>
<span
v-if="!step.isOver"
:key="'num-' + step.index"
class="text-xs font-bold transition-colors duration-300"
:class="step.isActive ? 'text-n-blue-11' : 'text-n-slate-11'"
>
{{ item.title }}
</h3>
<span v-if="isOver(item)" class="mx-1 mt-0.5 text-n-teal-9">
<fluent-icon icon="checkmark" />
{{ step.index + 1 }}
</span>
<Icon
v-else
:key="'check-' + step.index"
icon="i-lucide-check"
class="text-n-slate-11 size-4"
/>
</div>
<!-- Content -->
<div class="flex flex-col items-start gap-1.5 pb-10 pt-1">
<div class="flex items-center">
<h3
class="text-sm font-medium overflow-hidden whitespace-nowrap mt-0.5 text-ellipsis leading-tight"
:class="step.isActive ? 'text-n-blue-11' : 'text-n-slate-12'"
>
{{ step.title }}
</h3>
</div>
<p class="m-0 mt-1.5 text-sm text-n-slate-11">
{{ step.body }}
</p>
</div>
<span class="step">
{{ items.indexOf(item) + 1 }}
</span>
<p class="pl-6 m-0 mt-1.5 text-sm text-n-slate-11">
{{ item.body }}
</p>
</div>
</transition-group>
</template>
<style lang="scss" scoped>
.wizard-box {
.item {
@apply cursor-pointer after:bg-n-slate-6 before:bg-n-slate-6 py-4 ltr:pr-4 rtl:pl-4 ltr:pl-6 rtl:pr-6 relative before:h-4 before:top-0 last:before:h-0 first:before:h-0 last:after:h-0 before:content-[''] before:absolute before:w-0.5 after:content-[''] after:h-full after:absolute after:top-5 after:w-0.5 rtl:after:left-6 rtl:before:left-6;
&.active {
h3 {
@apply text-n-blue-text dark:text-n-blue-text;
}
.step {
@apply bg-n-brand dark:bg-n-brand;
}
}
&.over {
&::after {
@apply bg-n-brand dark:bg-n-brand;
}
.step {
@apply bg-n-brand dark:bg-n-brand;
}
& + .item {
&::before {
@apply bg-n-brand dark:bg-n-brand;
}
}
}
.step {
@apply bg-n-slate-7 rounded-2xl font-medium w-4 left-4 leading-4 z-10 absolute text-center text-white dark:text-white text-xxs top-5;
}
}
}
</style>
@@ -1,91 +1,87 @@
<script>
<script setup>
import { computed } from 'vue';
import ChannelSelector from '../ChannelSelector.vue';
export default {
components: { ChannelSelector },
props: {
channel: {
type: Object,
required: true,
},
enabledFeatures: {
type: Object,
required: true,
},
},
emits: ['channelItemClick'],
computed: {
hasFbConfigured() {
return window.chatwootConfig?.fbAppId;
},
hasInstagramConfigured() {
return window.chatwootConfig?.instagramAppId;
},
isActive() {
const { key } = this.channel;
if (Object.keys(this.enabledFeatures).length === 0) {
return false;
}
if (key === 'website') {
return this.enabledFeatures.channel_website;
}
if (key === 'facebook') {
return this.enabledFeatures.channel_facebook && this.hasFbConfigured;
}
if (key === 'email') {
return this.enabledFeatures.channel_email;
}
if (key === 'instagram') {
return (
this.enabledFeatures.channel_instagram && this.hasInstagramConfigured
);
}
if (key === 'voice') {
return this.enabledFeatures.channel_voice;
}
return [
'website',
'twilio',
'api',
'whatsapp',
'sms',
'telegram',
'line',
'instagram',
'voice',
].includes(key);
},
isComingSoon() {
const { key } = this.channel;
// Show "Coming Soon" only if the channel is marked as coming soon
// and the corresponding feature flag is not enabled yet.
return ['voice'].includes(key) && !this.isActive;
},
const props = defineProps({
channel: {
type: Object,
required: true,
},
methods: {
getChannelThumbnail() {
if (this.channel.key === 'api' && this.channel.thumbnail) {
return this.channel.thumbnail;
}
return `/assets/images/dashboard/channels/${this.channel.key}.png`;
},
onItemClick() {
if (this.isActive) {
this.$emit('channelItemClick', this.channel.key);
}
},
enabledFeatures: {
type: Object,
required: true,
},
});
const emit = defineEmits(['channelItemClick']);
const hasFbConfigured = computed(() => {
return window.chatwootConfig?.fbAppId;
});
const hasInstagramConfigured = computed(() => {
return window.chatwootConfig?.instagramAppId;
});
const isActive = computed(() => {
const { key } = props.channel;
if (Object.keys(props.enabledFeatures).length === 0) {
return false;
}
if (key === 'website') {
return props.enabledFeatures.channel_website;
}
if (key === 'facebook') {
return props.enabledFeatures.channel_facebook && hasFbConfigured.value;
}
if (key === 'email') {
return props.enabledFeatures.channel_email;
}
if (key === 'instagram') {
return (
props.enabledFeatures.channel_instagram && hasInstagramConfigured.value
);
}
if (key === 'voice') {
return props.enabledFeatures.channel_voice;
}
return [
'website',
'twilio',
'api',
'whatsapp',
'sms',
'telegram',
'line',
'instagram',
'voice',
].includes(key);
});
const isComingSoon = computed(() => {
const { key } = props.channel;
// Show "Coming Soon" only if the channel is marked as coming soon
// and the corresponding feature flag is not enabled yet.
return ['voice'].includes(key) && !isActive.value;
});
const onItemClick = () => {
if (isActive.value) {
emit('channelItemClick', props.channel.key);
}
};
</script>
<template>
<ChannelSelector
:class="{ inactive: !isActive }"
:title="channel.name"
:src="getChannelThumbnail()"
:title="channel.title"
:description="channel.description"
:icon="channel.icon"
:is-coming-soon="isComingSoon"
:disabled="!isActive"
@click="onItemClick"
/>
</template>
@@ -13,7 +13,7 @@ defineProps({
<div class="flex items-center text-n-slate-11 text-xs min-w-0">
<ChannelIcon
:inbox="inbox"
class="size-3 ltr:mr-0.5 rtl:ml-0.5 flex-shrink-0"
class="size-3 ltr:mr-1 rtl:ml-1 flex-shrink-0"
/>
<span class="truncate">
{{ inbox.name }}
@@ -3,6 +3,7 @@ import { computed, ref } from 'vue';
import { useRouter } from 'vue-router';
import { useStore, useMapGetter } from 'dashboard/composables/store';
import { getLastMessage } from 'dashboard/helper/conversationHelper';
import { useVoiceCallStatus } from 'dashboard/composables/useVoiceCallStatus';
import { frontendURL, conversationUrl } from 'dashboard/helper/URLHelper';
import Avatar from 'next/avatar/Avatar.vue';
import MessagePreview from './MessagePreview.vue';
@@ -82,6 +83,16 @@ const isInboxNameVisible = computed(() => !activeInbox.value);
const lastMessageInChat = computed(() => getLastMessage(props.chat));
const callStatus = computed(
() => props.chat.additional_attributes?.call_status
);
const callDirection = computed(
() => props.chat.additional_attributes?.call_direction
);
const { labelKey: voiceLabelKey, listIconColor: voiceIconColor } =
useVoiceCallStatus(callStatus, callDirection);
const inboxId = computed(() => props.chat.inbox_id);
const inbox = computed(() => {
@@ -250,7 +261,6 @@ const deleteConversation = () => {
:src="currentContact.thumbnail"
:size="32"
:status="currentContact.availability_status"
:inbox="inbox"
:class="!showInboxName ? 'mt-4' : 'mt-8'"
hide-offline-status
rounded-full
@@ -307,14 +317,30 @@ const deleteConversation = () => {
>
{{ currentContact.name }}
</h4>
<div
v-if="callStatus"
key="voice-status-row"
class="my-0 mx-2 leading-6 h-6 flex-1 min-w-0 text-sm overflow-hidden text-ellipsis whitespace-nowrap"
:class="messagePreviewClass"
>
<span
class="inline-block -mt-0.5 align-middle text-[16px] i-ph-phone-incoming"
:class="[voiceIconColor]"
/>
<span class="mx-1">
{{ $t(voiceLabelKey) }}
</span>
</div>
<MessagePreview
v-if="lastMessageInChat"
v-else-if="lastMessageInChat"
key="message-preview"
:message="lastMessageInChat"
class="my-0 mx-2 leading-6 h-6 flex-1 min-w-0 text-sm"
:class="messagePreviewClass"
/>
<p
v-else
key="no-messages"
class="text-n-slate-11 text-sm my-0 mx-2 leading-6 h-6 flex-1 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap"
:class="messagePreviewClass"
>
@@ -0,0 +1,161 @@
import { computed, unref } from 'vue';
const CALL_STATUSES = {
IN_PROGRESS: 'in-progress',
RINGING: 'ringing',
NO_ANSWER: 'no-answer',
BUSY: 'busy',
FAILED: 'failed',
COMPLETED: 'completed',
CANCELED: 'canceled',
};
const CALL_DIRECTIONS = {
INBOUND: 'inbound',
OUTBOUND: 'outbound',
};
/**
* Composable for handling voice call status display logic
* @param {Ref|string} statusRef - Call status (ringing, in-progress, etc.)
* @param {Ref|string} directionRef - Call direction (inbound, outbound)
* @returns {Object} UI properties for displaying call status
*/
export function useVoiceCallStatus(statusRef, directionRef) {
const status = computed(() => unref(statusRef)?.toString());
const direction = computed(() => unref(directionRef)?.toString());
// Status group helpers
const isFailedStatus = computed(() =>
[
CALL_STATUSES.NO_ANSWER,
CALL_STATUSES.BUSY,
CALL_STATUSES.FAILED,
].includes(status.value)
);
const isEndedStatus = computed(() =>
[CALL_STATUSES.COMPLETED, CALL_STATUSES.CANCELED].includes(status.value)
);
const isOutbound = computed(
() => direction.value === CALL_DIRECTIONS.OUTBOUND
);
const labelKey = computed(() => {
const s = status.value;
if (s === CALL_STATUSES.IN_PROGRESS) {
return isOutbound.value
? 'CONVERSATION.VOICE_CALL.OUTGOING_CALL'
: 'CONVERSATION.VOICE_CALL.CALL_IN_PROGRESS';
}
if (s === CALL_STATUSES.RINGING) {
return isOutbound.value
? 'CONVERSATION.VOICE_CALL.OUTGOING_CALL'
: 'CONVERSATION.VOICE_CALL.INCOMING_CALL';
}
if (s === CALL_STATUSES.NO_ANSWER) {
return 'CONVERSATION.VOICE_CALL.MISSED_CALL';
}
if (isFailedStatus.value) {
return 'CONVERSATION.VOICE_CALL.NO_ANSWER';
}
if (isEndedStatus.value) {
return 'CONVERSATION.VOICE_CALL.CALL_ENDED';
}
return 'CONVERSATION.VOICE_CALL.INCOMING_CALL';
});
const subtextKey = computed(() => {
const s = status.value;
if (s === CALL_STATUSES.RINGING) {
return 'CONVERSATION.VOICE_CALL.NOT_ANSWERED_YET';
}
if (s === CALL_STATUSES.IN_PROGRESS) {
return isOutbound.value
? 'CONVERSATION.VOICE_CALL.THEY_ANSWERED'
: 'CONVERSATION.VOICE_CALL.YOU_ANSWERED';
}
if (isFailedStatus.value) {
return 'CONVERSATION.VOICE_CALL.NO_ANSWER';
}
if (isEndedStatus.value) {
return 'CONVERSATION.VOICE_CALL.CALL_ENDED';
}
return 'CONVERSATION.VOICE_CALL.NOT_ANSWERED_YET';
});
const bubbleIconName = computed(() => {
const s = status.value;
if (s === CALL_STATUSES.IN_PROGRESS) {
return isOutbound.value
? 'i-ph-phone-outgoing-fill'
: 'i-ph-phone-incoming-fill';
}
if (isFailedStatus.value) {
return 'i-ph-phone-x-fill';
}
// For ringing/completed/canceled show direction when possible
return isOutbound.value
? 'i-ph-phone-outgoing-fill'
: 'i-ph-phone-incoming-fill';
});
const bubbleIconBg = computed(() => {
const s = status.value;
if (s === CALL_STATUSES.IN_PROGRESS) {
return 'bg-n-teal-9';
}
if (isFailedStatus.value) {
return 'bg-n-ruby-9';
}
if (isEndedStatus.value) {
return 'bg-n-slate-11';
}
// default (e.g., ringing)
return 'bg-n-teal-9 animate-pulse';
});
const listIconColor = computed(() => {
const s = status.value;
if (s === CALL_STATUSES.IN_PROGRESS || s === CALL_STATUSES.RINGING) {
return 'text-n-teal-9';
}
if (isFailedStatus.value) {
return 'text-n-ruby-9';
}
if (isEndedStatus.value) {
return 'text-n-slate-11';
}
return 'text-n-teal-9';
});
return {
status,
labelKey,
subtextKey,
bubbleIconName,
bubbleIconBg,
listIconColor,
};
}
+1
View File
@@ -1,6 +1,7 @@
export const FEATURE_FLAGS = {
AGENT_BOTS: 'agent_bots',
AGENT_MANAGEMENT: 'agent_management',
ASSIGNMENT_V2: 'assignment_v2',
AUTO_RESOLVE_CONVERSATIONS: 'auto_resolve_conversations',
AUTOMATIONS: 'automations',
CAMPAIGNS: 'campaigns',
@@ -610,6 +610,15 @@
"SEND_MESSAGE": "Send message"
}
},
"TWILIO_OPTIONS": {
"LABEL": "Select template",
"SEARCH_PLACEHOLDER": "Search templates",
"EMPTY_STATE": "No templates found",
"TEMPLATE_PARSER": {
"BACK": "Go back",
"SEND_MESSAGE": "Send message"
}
},
"ACTION_BUTTONS": {
"DISCARD": "Discard",
"SEND": "Send ({keyCode})"
@@ -48,7 +48,8 @@
"CREATED_AT": "Created At",
"LAST_ACTIVITY": "Last Activity",
"REFERER_LINK": "Referrer link",
"BLOCKED": "Blocked"
"BLOCKED": "Blocked",
"LABELS": "Labels"
},
"GROUPS": {
"STANDARD_FILTERS": "Standard Filters",
@@ -0,0 +1,51 @@
{
"CONTENT_TEMPLATES": {
"MODAL": {
"TITLE": "Twilio Templates",
"SUBTITLE": "Select the Twilio template you want to send",
"TEMPLATE_SELECTED_SUBTITLE": "Configure template: {templateName}"
},
"PICKER": {
"SEARCH_PLACEHOLDER": "Search Templates",
"NO_TEMPLATES_FOUND": "No templates found for",
"NO_CONTENT": "No content",
"HEADER": "Header",
"BODY": "Body",
"FOOTER": "Footer",
"BUTTONS": "Buttons",
"CATEGORY": "Category",
"MEDIA_CONTENT": "Media Content",
"MEDIA_CONTENT_FALLBACK": "media content",
"NO_TEMPLATES_AVAILABLE": "No Twilio templates available. Click refresh to sync templates from Twilio.",
"REFRESH_BUTTON": "Refresh templates",
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
"LABELS": {
"LANGUAGE": "Language",
"TEMPLATE_BODY": "Template Body",
"CATEGORY": "Category"
},
"TYPES": {
"MEDIA": "Media",
"QUICK_REPLY": "Quick Reply",
"TEXT": "Text"
}
},
"PARSER": {
"VARIABLES_LABEL": "Variables",
"LANGUAGE": "Language",
"CATEGORY": "Category",
"VARIABLE_PLACEHOLDER": "Enter {variable} value",
"GO_BACK_LABEL": "Go Back",
"SEND_MESSAGE_LABEL": "Send Message",
"FORM_ERROR_MESSAGE": "Please fill all variables before sending",
"MEDIA_HEADER_LABEL": "{type} Header",
"MEDIA_URL_LABEL": "Enter full media URL",
"MEDIA_URL_PLACEHOLDER": "https://example.com/image.jpg"
},
"FORM": {
"BACK_BUTTON": "Back",
"SEND_MESSAGE_BUTTON": "Send Message"
}
}
}
@@ -35,6 +35,11 @@
"API_HOURS_WINDOW": "ለዚህ ውይይት መመለስ በ{hours} ሰአታት ውስጥ ብቻ ይቻላል",
"NOT_ASSIGNED_TO_YOU": "This conversation is not assigned to you. Would you like to assign this conversation to yourself?",
"ASSIGN_TO_ME": "Assign to me",
"BOT_HANDOFF_MESSAGE": "You are responding to a conversation which is currently handled by an assistant or a bot.",
"BOT_HANDOFF_ACTION": "Mark open and assign to you",
"BOT_HANDOFF_REOPEN_ACTION": "Mark conversation open",
"BOT_HANDOFF_SUCCESS": "Conversation has been handed over to you",
"BOT_HANDOFF_ERROR": "Failed to take over the conversation. Please try again.",
"TWILIO_WHATSAPP_CAN_REPLY": "You can only reply to this conversation using a template message due to",
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "24 hour message window restriction",
"OLD_INSTAGRAM_INBOX_REPLY_BANNER": "ይህ የInstagram መለያ ወደ አዲሱ የInstagram ቻናል ገቢ ሳጥን ተዛውሯል። ሁሉም አዲስ መልዕክቶች በዚያ ይታያሉ። ከአሁን ጀምሮ ከዚህ ውይይት መልዕክቶች መላክ አትችሉም።",
@@ -807,6 +807,58 @@
"ERROR_MESSAGE": "Unable to update portal"
}
}
},
"PDF_UPLOAD": {
"TITLE": "Upload PDF Document",
"DESCRIPTION": "Upload a PDF document to automatically generate FAQs using AI",
"DRAG_DROP_TEXT": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"ADDITIONAL_CONTEXT_LABEL": "Additional Context (Optional)",
"ADDITIONAL_CONTEXT_PLACEHOLDER": "Provide any additional context or instructions for FAQ generation...",
"UPLOADING": "Uploading...",
"UPLOAD": "Upload & Process",
"CANCEL": "Cancel",
"ERROR_INVALID_TYPE": "Please select a valid PDF file",
"ERROR_FILE_TOO_LARGE": "File size must be less than 512MB",
"ERROR_UPLOAD_FAILED": "Failed to upload PDF. Please try again."
},
"PDF_DOCUMENTS": {
"TITLE": "PDF Documents",
"DESCRIPTION": "Manage uploaded PDF documents and generate FAQs from them",
"UPLOAD_PDF": "Upload PDF",
"UPLOAD_FIRST_PDF": "Upload your first PDF",
"UPLOADED_BY": "Uploaded by",
"GENERATE_FAQS": "Generate FAQs",
"GENERATING": "Generating...",
"CONFIRM_DELETE": "Are you sure you want to delete {filename}?",
"EMPTY_STATE": {
"TITLE": "No PDF documents yet",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQs using AI"
},
"STATUS": {
"UPLOADED": "Ready",
"PROCESSING": "Processing",
"PROCESSED": "Completed",
"FAILED": "Failed"
}
},
"CONTENT_GENERATION": {
"TITLE": "Content Generation",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQ content using AI",
"UPLOAD_TITLE": "Upload PDF Document",
"DRAG_DROP": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"UPLOADING": "Processing document...",
"UPLOAD_SUCCESS": "Document processed successfully!",
"UPLOAD_ERROR": "Failed to upload document. Please try again.",
"INVALID_FILE_TYPE": "Please select a valid PDF file",
"FILE_TOO_LARGE": "File size must be less than 512MB",
"GENERATED_CONTENT": "Generated FAQ Content",
"PUBLISH_SELECTED": "Publish Selected",
"PUBLISHING": "Publishing...",
"FROM_DOCUMENT": "From document",
"NO_CONTENT": "No generated content available. Upload a PDF document to get started.",
"LOADING": "Loading generated content..."
}
}
}
@@ -424,7 +424,51 @@
},
"AUTH": {
"TITLE": "Choose a channel",
"DESC": "Chatwoot supports live-chat widgets, Facebook Messenger, WhatsApp, Emails, etc., as channels. If you want to build a custom channel, you can create it using the API channel. To get started, choose one of the channels below."
"DESC": "Chatwoot supports live-chat widgets, Facebook Messenger, WhatsApp, Emails, etc., as channels. If you want to build a custom channel, you can create it using the API channel. To get started, choose one of the channels below.",
"TITLE_NEXT": "Complete the setup",
"TITLE_FINISH": "Voilà!",
"CHANNEL": {
"WEBSITE": {
"TITLE": "Website",
"DESCRIPTION": "Create a live-chat widget"
},
"FACEBOOK": {
"TITLE": "Facebook",
"DESCRIPTION": "Connect your Facebook page"
},
"WHATSAPP": {
"TITLE": "WhatsApp",
"DESCRIPTION": "Support your customers on WhatsApp"
},
"EMAIL": {
"TITLE": "Email",
"DESCRIPTION": "Connect with Gmail, Outlook, or other providers"
},
"SMS": {
"TITLE": "SMS",
"DESCRIPTION": "Integrate SMS channel with Twilio or bandwidth"
},
"API": {
"TITLE": "API",
"DESCRIPTION": "Make a custom channel using our API"
},
"TELEGRAM": {
"TITLE": "Telegram",
"DESCRIPTION": "Configure Telegram channel using Bot token"
},
"LINE": {
"TITLE": "Line",
"DESCRIPTION": "Integrate your Line channel"
},
"INSTAGRAM": {
"TITLE": "Instagram",
"DESCRIPTION": "Connect your instagram account"
},
"VOICE": {
"TITLE": "Voice",
"DESCRIPTION": "Integrate with Twilio Voice"
}
}
},
"AGENTS": {
"TITLE": "Agents",
@@ -478,7 +522,10 @@
"MESSAGE": "You can now engage with your customers through your new Channel. Happy supporting",
"BUTTON_TEXT": "Take me there",
"MORE_SETTINGS": "More settings",
"WEBSITE_SUCCESS": "You have successfully finished creating a website channel. Copy the code shown below and paste it on your website. Next time a customer use the live chat, the conversation will automatically appear on your inbox."
"WEBSITE_SUCCESS": "You have successfully finished creating a website channel. Copy the code shown below and paste it on your website. Next time a customer use the live chat, the conversation will automatically appear on your inbox.",
"WHATSAPP_QR_INSTRUCTION": "Scan the QR code above to quickly test your WhatsApp inbox",
"MESSENGER_QR_INSTRUCTION": "Scan the QR code above to quickly test your Facebook Messenger inbox",
"TELEGRAM_QR_INSTRUCTION": "Scan the QR code above to quickly test your Telegram inbox"
},
"REAUTH": "Reauthorize",
"VIEW": "View",
@@ -868,9 +915,18 @@
"SCRIPT_SETTINGS": "\n window.chatwootSettings = {options};"
},
"EMAIL_PROVIDERS": {
"MICROSOFT": "Microsoft",
"GOOGLE": "Google",
"OTHER_PROVIDERS": "Other Providers"
"MICROSOFT": {
"TITLE": "Microsoft",
"DESCRIPTION": "Connect with Microsoft"
},
"GOOGLE": {
"TITLE": "Google",
"DESCRIPTION": "Connect with Google"
},
"OTHER_PROVIDERS": {
"TITLE": "Other Providers",
"DESCRIPTION": "Connect with Other Providers"
}
},
"CHANNELS": {
"MESSENGER": "Messenger",
@@ -704,11 +704,28 @@
"ERROR_MESSAGE": "There was an error creating the document, please try again."
},
"FORM": {
"TYPE": {
"LABEL": "Document Type",
"URL": "URL",
"PDF": "PDF File"
},
"URL": {
"LABEL": "URL",
"PLACEHOLDER": "Enter the URL of the document",
"ERROR": "Please provide a valid URL for the document"
},
"PDF_FILE": {
"LABEL": "PDF File",
"CHOOSE_FILE": "Choose PDF file",
"ERROR": "Please select a PDF file",
"HELP_TEXT": "Maximum file size: 10MB",
"INVALID_TYPE": "Please select a valid PDF file",
"TOO_LARGE": "File size exceeds 10MB limit"
},
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
},
"ASSISTANT": {
"LABEL": "Assistant",
"PLACEHOLDER": "Select the assistant",
@@ -610,6 +610,15 @@
"SEND_MESSAGE": "إرسال الرسالة"
}
},
"TWILIO_OPTIONS": {
"LABEL": "Select template",
"SEARCH_PLACEHOLDER": "Search templates",
"EMPTY_STATE": "No templates found",
"TEMPLATE_PARSER": {
"BACK": "العودة للخلف",
"SEND_MESSAGE": "إرسال الرسالة"
}
},
"ACTION_BUTTONS": {
"DISCARD": "Discard",
"SEND": "Send ({keyCode})"
@@ -48,7 +48,8 @@
"CREATED_AT": "تم إنشاؤها في",
"LAST_ACTIVITY": "آخر نشاط",
"REFERER_LINK": "رابط المرجع",
"BLOCKED": "محظور"
"BLOCKED": "محظور",
"LABELS": "الوسوم"
},
"GROUPS": {
"STANDARD_FILTERS": "الفلاتر القياسية",
@@ -0,0 +1,51 @@
{
"CONTENT_TEMPLATES": {
"MODAL": {
"TITLE": "Twilio Templates",
"SUBTITLE": "Select the Twilio template you want to send",
"TEMPLATE_SELECTED_SUBTITLE": "Configure template: {templateName}"
},
"PICKER": {
"SEARCH_PLACEHOLDER": "نماذج البحث",
"NO_TEMPLATES_FOUND": "لم يتم العثور على قوالب",
"NO_CONTENT": "لا يوجد محتوى",
"HEADER": "Header",
"BODY": "Body",
"FOOTER": "Footer",
"BUTTONS": "Buttons",
"CATEGORY": "الفئة",
"MEDIA_CONTENT": "Media Content",
"MEDIA_CONTENT_FALLBACK": "media content",
"NO_TEMPLATES_AVAILABLE": "No Twilio templates available. Click refresh to sync templates from Twilio.",
"REFRESH_BUTTON": "Refresh templates",
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
"LABELS": {
"LANGUAGE": "اللغة",
"TEMPLATE_BODY": "نص القالب",
"CATEGORY": "الفئة"
},
"TYPES": {
"MEDIA": "Media",
"QUICK_REPLY": "Quick Reply",
"TEXT": "النص"
}
},
"PARSER": {
"VARIABLES_LABEL": "المتغيرات",
"LANGUAGE": "اللغة",
"CATEGORY": "الفئة",
"VARIABLE_PLACEHOLDER": "أدخل قيمة {variable}",
"GO_BACK_LABEL": "العودة للخلف",
"SEND_MESSAGE_LABEL": "إرسال الرسالة",
"FORM_ERROR_MESSAGE": "يرجى ملء جميع المتغيرات قبل الإرسال",
"MEDIA_HEADER_LABEL": "{type} Header",
"MEDIA_URL_LABEL": "Enter full media URL",
"MEDIA_URL_PLACEHOLDER": "https://example.com/image.jpg"
},
"FORM": {
"BACK_BUTTON": "العودة",
"SEND_MESSAGE_BUTTON": "إرسال الرسالة"
}
}
}
@@ -35,6 +35,11 @@
"API_HOURS_WINDOW": "You can only reply to this conversation within {hours} hours",
"NOT_ASSIGNED_TO_YOU": "لم يتم تعيين هذه المحادثة لك. هل ترغب في تعيين هذه المحادثة لنفسك؟",
"ASSIGN_TO_ME": "إسناد لي",
"BOT_HANDOFF_MESSAGE": "You are responding to a conversation which is currently handled by an assistant or a bot.",
"BOT_HANDOFF_ACTION": "Mark open and assign to you",
"BOT_HANDOFF_REOPEN_ACTION": "Mark conversation open",
"BOT_HANDOFF_SUCCESS": "Conversation has been handed over to you",
"BOT_HANDOFF_ERROR": "Failed to take over the conversation. Please try again.",
"TWILIO_WHATSAPP_CAN_REPLY": "يمكنك فقط الرد على هذه المحادثة باستخدام رسالة قالب بسبب",
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "قيد نافذة الـ 24 ساعة",
"OLD_INSTAGRAM_INBOX_REPLY_BANNER": "This Instagram account was migrated to the new Instagram channel inbox. All new messages will show up there. You wont be able to send messages from this conversation anymore.",
@@ -807,6 +807,58 @@
"ERROR_MESSAGE": "Unable to update portal"
}
}
},
"PDF_UPLOAD": {
"TITLE": "Upload PDF Document",
"DESCRIPTION": "Upload a PDF document to automatically generate FAQs using AI",
"DRAG_DROP_TEXT": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"ADDITIONAL_CONTEXT_LABEL": "Additional Context (Optional)",
"ADDITIONAL_CONTEXT_PLACEHOLDER": "Provide any additional context or instructions for FAQ generation...",
"UPLOADING": "جاري الرفع...",
"UPLOAD": "Upload & Process",
"CANCEL": "إلغاء",
"ERROR_INVALID_TYPE": "Please select a valid PDF file",
"ERROR_FILE_TOO_LARGE": "File size must be less than 512MB",
"ERROR_UPLOAD_FAILED": "Failed to upload PDF. Please try again."
},
"PDF_DOCUMENTS": {
"TITLE": "PDF Documents",
"DESCRIPTION": "Manage uploaded PDF documents and generate FAQs from them",
"UPLOAD_PDF": "Upload PDF",
"UPLOAD_FIRST_PDF": "Upload your first PDF",
"UPLOADED_BY": "Uploaded by",
"GENERATE_FAQS": "Generate FAQs",
"GENERATING": "Generating...",
"CONFIRM_DELETE": "Are you sure you want to delete {filename}?",
"EMPTY_STATE": {
"TITLE": "No PDF documents yet",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQs using AI"
},
"STATUS": {
"UPLOADED": "Ready",
"PROCESSING": "Processing",
"PROCESSED": "مكتمل",
"FAILED": "Failed"
}
},
"CONTENT_GENERATION": {
"TITLE": "Content Generation",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQ content using AI",
"UPLOAD_TITLE": "Upload PDF Document",
"DRAG_DROP": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"UPLOADING": "Processing document...",
"UPLOAD_SUCCESS": "Document processed successfully!",
"UPLOAD_ERROR": "Failed to upload document. Please try again.",
"INVALID_FILE_TYPE": "Please select a valid PDF file",
"FILE_TOO_LARGE": "File size must be less than 512MB",
"GENERATED_CONTENT": "Generated FAQ Content",
"PUBLISH_SELECTED": "Publish Selected",
"PUBLISHING": "Publishing...",
"FROM_DOCUMENT": "From document",
"NO_CONTENT": "No generated content available. Upload a PDF document to get started.",
"LOADING": "Loading generated content..."
}
}
}
@@ -424,7 +424,51 @@
},
"AUTH": {
"TITLE": "اختر قناة",
"DESC": "يدعم أدوات الدردشة الحية، والميسنجر الفيسبوك، وملفات التويتر الشخصية، و WhatsApp، ورسائل البريد الإلكتروني، إلخ، كقنوات. إذا كنت ترغب في إنشاء قناة مخصصة، يمكنك إنشاءها باستخدام قناة API. للبدء، اختر إحدى القنوات أدناه."
"DESC": "يدعم أدوات الدردشة الحية، والميسنجر الفيسبوك، وملفات التويتر الشخصية، و WhatsApp، ورسائل البريد الإلكتروني، إلخ، كقنوات. إذا كنت ترغب في إنشاء قناة مخصصة، يمكنك إنشاءها باستخدام قناة API. للبدء، اختر إحدى القنوات أدناه.",
"TITLE_NEXT": "Complete the setup",
"TITLE_FINISH": "Voilà!",
"CHANNEL": {
"WEBSITE": {
"TITLE": "الموقع الإلكتروني",
"DESCRIPTION": "Create a live-chat widget"
},
"FACEBOOK": {
"TITLE": "فيسبوك",
"DESCRIPTION": "Connect your Facebook page"
},
"WHATSAPP": {
"TITLE": "واتساب",
"DESCRIPTION": "Support your customers on WhatsApp"
},
"EMAIL": {
"TITLE": "البريد الإلكتروني",
"DESCRIPTION": "Connect with Gmail, Outlook, or other providers"
},
"SMS": {
"TITLE": "SMS",
"DESCRIPTION": "Integrate SMS channel with Twilio or bandwidth"
},
"API": {
"TITLE": "API",
"DESCRIPTION": "Make a custom channel using our API"
},
"TELEGRAM": {
"TITLE": "تيليجرام",
"DESCRIPTION": "Configure Telegram channel using Bot token"
},
"LINE": {
"TITLE": "Line",
"DESCRIPTION": "Integrate your Line channel"
},
"INSTAGRAM": {
"TITLE": "Instagram",
"DESCRIPTION": "Connect your instagram account"
},
"VOICE": {
"TITLE": "Voice",
"DESCRIPTION": "Integrate with Twilio Voice"
}
}
},
"AGENTS": {
"TITLE": "وكيل الدعم",
@@ -478,7 +522,10 @@
"MESSAGE": "يمكنك الآن التواصل مع عملائك من خلال قناتك الجديدة",
"BUTTON_TEXT": "خذني إلى هناك",
"MORE_SETTINGS": "المزيد من الإعدادات",
"WEBSITE_SUCCESS": "لقد انتهيت بنجاح من إنشاء قناة دردشة مباشرة لموقعك. انسخ الرمز الموضح أدناه وقم بإضافته إلى موقع الويب الخاص بك. في المرة القادمة التي يستخدم فيها العميل الدردشة المباشرة، ستظهر المحادثة تلقائياً على صندوق الوارد الخاص بك."
"WEBSITE_SUCCESS": "لقد انتهيت بنجاح من إنشاء قناة دردشة مباشرة لموقعك. انسخ الرمز الموضح أدناه وقم بإضافته إلى موقع الويب الخاص بك. في المرة القادمة التي يستخدم فيها العميل الدردشة المباشرة، ستظهر المحادثة تلقائياً على صندوق الوارد الخاص بك.",
"WHATSAPP_QR_INSTRUCTION": "Scan the QR code above to quickly test your WhatsApp inbox",
"MESSENGER_QR_INSTRUCTION": "Scan the QR code above to quickly test your Facebook Messenger inbox",
"TELEGRAM_QR_INSTRUCTION": "Scan the QR code above to quickly test your Telegram inbox"
},
"REAUTH": "إعادة التصريح",
"VIEW": "عرض",
@@ -868,9 +915,18 @@
"SCRIPT_SETTINGS": "\n window.chatwootSettings = {options};"
},
"EMAIL_PROVIDERS": {
"MICROSOFT": "Microsoft",
"GOOGLE": "Google",
"OTHER_PROVIDERS": "Other Providers"
"MICROSOFT": {
"TITLE": "Microsoft",
"DESCRIPTION": "Connect with Microsoft"
},
"GOOGLE": {
"TITLE": "Google",
"DESCRIPTION": "Connect with Google"
},
"OTHER_PROVIDERS": {
"TITLE": "Other Providers",
"DESCRIPTION": "Connect with Other Providers"
}
},
"CHANNELS": {
"MESSENGER": "Messenger",
@@ -704,11 +704,28 @@
"ERROR_MESSAGE": "There was an error creating the document, please try again."
},
"FORM": {
"TYPE": {
"LABEL": "Document Type",
"URL": "الرابط",
"PDF": "PDF File"
},
"URL": {
"LABEL": "الرابط",
"PLACEHOLDER": "Enter the URL of the document",
"ERROR": "Please provide a valid URL for the document"
},
"PDF_FILE": {
"LABEL": "PDF File",
"CHOOSE_FILE": "Choose PDF file",
"ERROR": "Please select a PDF file",
"HELP_TEXT": "Maximum file size: 10MB",
"INVALID_TYPE": "Please select a valid PDF file",
"TOO_LARGE": "File size exceeds 10MB limit"
},
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
},
"ASSISTANT": {
"LABEL": "Assistant",
"PLACEHOLDER": "Select the assistant",
@@ -610,6 +610,15 @@
"SEND_MESSAGE": "Send message"
}
},
"TWILIO_OPTIONS": {
"LABEL": "Select template",
"SEARCH_PLACEHOLDER": "Search templates",
"EMPTY_STATE": "No templates found",
"TEMPLATE_PARSER": {
"BACK": "Go back",
"SEND_MESSAGE": "Send message"
}
},
"ACTION_BUTTONS": {
"DISCARD": "Discard",
"SEND": "Send ({keyCode})"
@@ -48,7 +48,8 @@
"CREATED_AT": "Created At",
"LAST_ACTIVITY": "Last Activity",
"REFERER_LINK": "Referrer link",
"BLOCKED": "Blocked"
"BLOCKED": "Blocked",
"LABELS": "Labels"
},
"GROUPS": {
"STANDARD_FILTERS": "Standard Filters",
@@ -0,0 +1,51 @@
{
"CONTENT_TEMPLATES": {
"MODAL": {
"TITLE": "Twilio Templates",
"SUBTITLE": "Select the Twilio template you want to send",
"TEMPLATE_SELECTED_SUBTITLE": "Configure template: {templateName}"
},
"PICKER": {
"SEARCH_PLACEHOLDER": "Search Templates",
"NO_TEMPLATES_FOUND": "No templates found for",
"NO_CONTENT": "No content",
"HEADER": "Header",
"BODY": "Body",
"FOOTER": "Footer",
"BUTTONS": "Buttons",
"CATEGORY": "Category",
"MEDIA_CONTENT": "Media Content",
"MEDIA_CONTENT_FALLBACK": "media content",
"NO_TEMPLATES_AVAILABLE": "No Twilio templates available. Click refresh to sync templates from Twilio.",
"REFRESH_BUTTON": "Refresh templates",
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
"LABELS": {
"LANGUAGE": "Language",
"TEMPLATE_BODY": "Template Body",
"CATEGORY": "Category"
},
"TYPES": {
"MEDIA": "Media",
"QUICK_REPLY": "Quick Reply",
"TEXT": "Text"
}
},
"PARSER": {
"VARIABLES_LABEL": "Variables",
"LANGUAGE": "Language",
"CATEGORY": "Category",
"VARIABLE_PLACEHOLDER": "Enter {variable} value",
"GO_BACK_LABEL": "Go Back",
"SEND_MESSAGE_LABEL": "Send Message",
"FORM_ERROR_MESSAGE": "Please fill all variables before sending",
"MEDIA_HEADER_LABEL": "{type} Header",
"MEDIA_URL_LABEL": "Enter full media URL",
"MEDIA_URL_PLACEHOLDER": "https://example.com/image.jpg"
},
"FORM": {
"BACK_BUTTON": "Back",
"SEND_MESSAGE_BUTTON": "Send Message"
}
}
}
@@ -35,6 +35,11 @@
"API_HOURS_WINDOW": "You can only reply to this conversation within {hours} hours",
"NOT_ASSIGNED_TO_YOU": "This conversation is not assigned to you. Would you like to assign this conversation to yourself?",
"ASSIGN_TO_ME": "Assign to me",
"BOT_HANDOFF_MESSAGE": "You are responding to a conversation which is currently handled by an assistant or a bot.",
"BOT_HANDOFF_ACTION": "Mark open and assign to you",
"BOT_HANDOFF_REOPEN_ACTION": "Mark conversation open",
"BOT_HANDOFF_SUCCESS": "Conversation has been handed over to you",
"BOT_HANDOFF_ERROR": "Failed to take over the conversation. Please try again.",
"TWILIO_WHATSAPP_CAN_REPLY": "You can only reply to this conversation using a template message due to",
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "24 hour message window restriction",
"OLD_INSTAGRAM_INBOX_REPLY_BANNER": "This Instagram account was migrated to the new Instagram channel inbox. All new messages will show up there. You wont be able to send messages from this conversation anymore.",
@@ -807,6 +807,58 @@
"ERROR_MESSAGE": "Unable to update portal"
}
}
},
"PDF_UPLOAD": {
"TITLE": "Upload PDF Document",
"DESCRIPTION": "Upload a PDF document to automatically generate FAQs using AI",
"DRAG_DROP_TEXT": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"ADDITIONAL_CONTEXT_LABEL": "Additional Context (Optional)",
"ADDITIONAL_CONTEXT_PLACEHOLDER": "Provide any additional context or instructions for FAQ generation...",
"UPLOADING": "Uploading...",
"UPLOAD": "Upload & Process",
"CANCEL": "Cancel",
"ERROR_INVALID_TYPE": "Please select a valid PDF file",
"ERROR_FILE_TOO_LARGE": "File size must be less than 512MB",
"ERROR_UPLOAD_FAILED": "Failed to upload PDF. Please try again."
},
"PDF_DOCUMENTS": {
"TITLE": "PDF Documents",
"DESCRIPTION": "Manage uploaded PDF documents and generate FAQs from them",
"UPLOAD_PDF": "Upload PDF",
"UPLOAD_FIRST_PDF": "Upload your first PDF",
"UPLOADED_BY": "Uploaded by",
"GENERATE_FAQS": "Generate FAQs",
"GENERATING": "Generating...",
"CONFIRM_DELETE": "Are you sure you want to delete {filename}?",
"EMPTY_STATE": {
"TITLE": "No PDF documents yet",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQs using AI"
},
"STATUS": {
"UPLOADED": "Ready",
"PROCESSING": "Processing",
"PROCESSED": "Completed",
"FAILED": "Failed"
}
},
"CONTENT_GENERATION": {
"TITLE": "Content Generation",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQ content using AI",
"UPLOAD_TITLE": "Upload PDF Document",
"DRAG_DROP": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"UPLOADING": "Processing document...",
"UPLOAD_SUCCESS": "Document processed successfully!",
"UPLOAD_ERROR": "Failed to upload document. Please try again.",
"INVALID_FILE_TYPE": "Please select a valid PDF file",
"FILE_TOO_LARGE": "File size must be less than 512MB",
"GENERATED_CONTENT": "Generated FAQ Content",
"PUBLISH_SELECTED": "Publish Selected",
"PUBLISHING": "Publishing...",
"FROM_DOCUMENT": "From document",
"NO_CONTENT": "No generated content available. Upload a PDF document to get started.",
"LOADING": "Loading generated content..."
}
}
}
@@ -424,7 +424,51 @@
},
"AUTH": {
"TITLE": "Choose a channel",
"DESC": "Chatwoot supports live-chat widgets, Facebook Messenger, WhatsApp, Emails, etc., as channels. If you want to build a custom channel, you can create it using the API channel. To get started, choose one of the channels below."
"DESC": "Chatwoot supports live-chat widgets, Facebook Messenger, WhatsApp, Emails, etc., as channels. If you want to build a custom channel, you can create it using the API channel. To get started, choose one of the channels below.",
"TITLE_NEXT": "Complete the setup",
"TITLE_FINISH": "Voilà!",
"CHANNEL": {
"WEBSITE": {
"TITLE": "Website",
"DESCRIPTION": "Create a live-chat widget"
},
"FACEBOOK": {
"TITLE": "Facebook",
"DESCRIPTION": "Connect your Facebook page"
},
"WHATSAPP": {
"TITLE": "WhatsApp",
"DESCRIPTION": "Support your customers on WhatsApp"
},
"EMAIL": {
"TITLE": "Email",
"DESCRIPTION": "Connect with Gmail, Outlook, or other providers"
},
"SMS": {
"TITLE": "SMS",
"DESCRIPTION": "Integrate SMS channel with Twilio or bandwidth"
},
"API": {
"TITLE": "API",
"DESCRIPTION": "Make a custom channel using our API"
},
"TELEGRAM": {
"TITLE": "Telegram",
"DESCRIPTION": "Configure Telegram channel using Bot token"
},
"LINE": {
"TITLE": "Line",
"DESCRIPTION": "Integrate your Line channel"
},
"INSTAGRAM": {
"TITLE": "Instagram",
"DESCRIPTION": "Connect your instagram account"
},
"VOICE": {
"TITLE": "Voice",
"DESCRIPTION": "Integrate with Twilio Voice"
}
}
},
"AGENTS": {
"TITLE": "Agents",
@@ -478,7 +522,10 @@
"MESSAGE": "You can now engage with your customers through your new Channel. Happy supporting",
"BUTTON_TEXT": "Take me there",
"MORE_SETTINGS": "More settings",
"WEBSITE_SUCCESS": "You have successfully finished creating a website channel. Copy the code shown below and paste it on your website. Next time a customer use the live chat, the conversation will automatically appear on your inbox."
"WEBSITE_SUCCESS": "You have successfully finished creating a website channel. Copy the code shown below and paste it on your website. Next time a customer use the live chat, the conversation will automatically appear on your inbox.",
"WHATSAPP_QR_INSTRUCTION": "Scan the QR code above to quickly test your WhatsApp inbox",
"MESSENGER_QR_INSTRUCTION": "Scan the QR code above to quickly test your Facebook Messenger inbox",
"TELEGRAM_QR_INSTRUCTION": "Scan the QR code above to quickly test your Telegram inbox"
},
"REAUTH": "Reauthorize",
"VIEW": "View",
@@ -868,9 +915,18 @@
"SCRIPT_SETTINGS": "\n window.chatwootSettings = {options};"
},
"EMAIL_PROVIDERS": {
"MICROSOFT": "Microsoft",
"GOOGLE": "Google",
"OTHER_PROVIDERS": "Other Providers"
"MICROSOFT": {
"TITLE": "Microsoft",
"DESCRIPTION": "Connect with Microsoft"
},
"GOOGLE": {
"TITLE": "Google",
"DESCRIPTION": "Connect with Google"
},
"OTHER_PROVIDERS": {
"TITLE": "Other Providers",
"DESCRIPTION": "Connect with Other Providers"
}
},
"CHANNELS": {
"MESSENGER": "Messenger",
@@ -704,11 +704,28 @@
"ERROR_MESSAGE": "There was an error creating the document, please try again."
},
"FORM": {
"TYPE": {
"LABEL": "Document Type",
"URL": "URL",
"PDF": "PDF File"
},
"URL": {
"LABEL": "URL",
"PLACEHOLDER": "Enter the URL of the document",
"ERROR": "Please provide a valid URL for the document"
},
"PDF_FILE": {
"LABEL": "PDF File",
"CHOOSE_FILE": "Choose PDF file",
"ERROR": "Please select a PDF file",
"HELP_TEXT": "Maximum file size: 10MB",
"INVALID_TYPE": "Please select a valid PDF file",
"TOO_LARGE": "File size exceeds 10MB limit"
},
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
},
"ASSISTANT": {
"LABEL": "Assistant",
"PLACEHOLDER": "Select the assistant",
@@ -610,6 +610,15 @@
"SEND_MESSAGE": "Изпрати съобщение"
}
},
"TWILIO_OPTIONS": {
"LABEL": "Select template",
"SEARCH_PLACEHOLDER": "Search templates",
"EMPTY_STATE": "No templates found",
"TEMPLATE_PARSER": {
"BACK": "Go back",
"SEND_MESSAGE": "Изпрати съобщение"
}
},
"ACTION_BUTTONS": {
"DISCARD": "Discard",
"SEND": "Send ({keyCode})"
@@ -48,7 +48,8 @@
"CREATED_AT": "Created At",
"LAST_ACTIVITY": "Последна активност",
"REFERER_LINK": "Referrer link",
"BLOCKED": "Blocked"
"BLOCKED": "Blocked",
"LABELS": "Labels"
},
"GROUPS": {
"STANDARD_FILTERS": "Standard Filters",
@@ -0,0 +1,51 @@
{
"CONTENT_TEMPLATES": {
"MODAL": {
"TITLE": "Twilio Templates",
"SUBTITLE": "Select the Twilio template you want to send",
"TEMPLATE_SELECTED_SUBTITLE": "Configure template: {templateName}"
},
"PICKER": {
"SEARCH_PLACEHOLDER": "Search Templates",
"NO_TEMPLATES_FOUND": "No templates found for",
"NO_CONTENT": "No content",
"HEADER": "Header",
"BODY": "Body",
"FOOTER": "Footer",
"BUTTONS": "Buttons",
"CATEGORY": "Category",
"MEDIA_CONTENT": "Media Content",
"MEDIA_CONTENT_FALLBACK": "media content",
"NO_TEMPLATES_AVAILABLE": "No Twilio templates available. Click refresh to sync templates from Twilio.",
"REFRESH_BUTTON": "Refresh templates",
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
"LABELS": {
"LANGUAGE": "Language",
"TEMPLATE_BODY": "Template Body",
"CATEGORY": "Category"
},
"TYPES": {
"MEDIA": "Media",
"QUICK_REPLY": "Quick Reply",
"TEXT": "Text"
}
},
"PARSER": {
"VARIABLES_LABEL": "Variables",
"LANGUAGE": "Language",
"CATEGORY": "Category",
"VARIABLE_PLACEHOLDER": "Enter {variable} value",
"GO_BACK_LABEL": "Go Back",
"SEND_MESSAGE_LABEL": "Send Message",
"FORM_ERROR_MESSAGE": "Please fill all variables before sending",
"MEDIA_HEADER_LABEL": "{type} Header",
"MEDIA_URL_LABEL": "Enter full media URL",
"MEDIA_URL_PLACEHOLDER": "https://example.com/image.jpg"
},
"FORM": {
"BACK_BUTTON": "Back",
"SEND_MESSAGE_BUTTON": "Send Message"
}
}
}
@@ -35,6 +35,11 @@
"API_HOURS_WINDOW": "You can only reply to this conversation within {hours} hours",
"NOT_ASSIGNED_TO_YOU": "This conversation is not assigned to you. Would you like to assign this conversation to yourself?",
"ASSIGN_TO_ME": "Assign to me",
"BOT_HANDOFF_MESSAGE": "You are responding to a conversation which is currently handled by an assistant or a bot.",
"BOT_HANDOFF_ACTION": "Mark open and assign to you",
"BOT_HANDOFF_REOPEN_ACTION": "Mark conversation open",
"BOT_HANDOFF_SUCCESS": "Conversation has been handed over to you",
"BOT_HANDOFF_ERROR": "Failed to take over the conversation. Please try again.",
"TWILIO_WHATSAPP_CAN_REPLY": "You can only reply to this conversation using a template message due to",
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "24 hour message window restriction",
"OLD_INSTAGRAM_INBOX_REPLY_BANNER": "This Instagram account was migrated to the new Instagram channel inbox. All new messages will show up there. You wont be able to send messages from this conversation anymore.",
@@ -807,6 +807,58 @@
"ERROR_MESSAGE": "Unable to update portal"
}
}
},
"PDF_UPLOAD": {
"TITLE": "Upload PDF Document",
"DESCRIPTION": "Upload a PDF document to automatically generate FAQs using AI",
"DRAG_DROP_TEXT": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"ADDITIONAL_CONTEXT_LABEL": "Additional Context (Optional)",
"ADDITIONAL_CONTEXT_PLACEHOLDER": "Provide any additional context or instructions for FAQ generation...",
"UPLOADING": "Качване...",
"UPLOAD": "Upload & Process",
"CANCEL": "Отмени",
"ERROR_INVALID_TYPE": "Please select a valid PDF file",
"ERROR_FILE_TOO_LARGE": "File size must be less than 512MB",
"ERROR_UPLOAD_FAILED": "Failed to upload PDF. Please try again."
},
"PDF_DOCUMENTS": {
"TITLE": "PDF Documents",
"DESCRIPTION": "Manage uploaded PDF documents and generate FAQs from them",
"UPLOAD_PDF": "Upload PDF",
"UPLOAD_FIRST_PDF": "Upload your first PDF",
"UPLOADED_BY": "Uploaded by",
"GENERATE_FAQS": "Generate FAQs",
"GENERATING": "Generating...",
"CONFIRM_DELETE": "Are you sure you want to delete {filename}?",
"EMPTY_STATE": {
"TITLE": "No PDF documents yet",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQs using AI"
},
"STATUS": {
"UPLOADED": "Ready",
"PROCESSING": "Processing",
"PROCESSED": "Завършено",
"FAILED": "Failed"
}
},
"CONTENT_GENERATION": {
"TITLE": "Content Generation",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQ content using AI",
"UPLOAD_TITLE": "Upload PDF Document",
"DRAG_DROP": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"UPLOADING": "Processing document...",
"UPLOAD_SUCCESS": "Document processed successfully!",
"UPLOAD_ERROR": "Failed to upload document. Please try again.",
"INVALID_FILE_TYPE": "Please select a valid PDF file",
"FILE_TOO_LARGE": "File size must be less than 512MB",
"GENERATED_CONTENT": "Generated FAQ Content",
"PUBLISH_SELECTED": "Publish Selected",
"PUBLISHING": "Publishing...",
"FROM_DOCUMENT": "From document",
"NO_CONTENT": "No generated content available. Upload a PDF document to get started.",
"LOADING": "Loading generated content..."
}
}
}
@@ -424,7 +424,51 @@
},
"AUTH": {
"TITLE": "Choose a channel",
"DESC": "Chatwoot supports live-chat widgets, Facebook Messenger, Twitter profiles, WhatsApp, Emails, etc., as channels. If you want to build a custom channel, you can create it using the API channel. To get started, choose one of the channels below."
"DESC": "Chatwoot supports live-chat widgets, Facebook Messenger, Twitter profiles, WhatsApp, Emails, etc., as channels. If you want to build a custom channel, you can create it using the API channel. To get started, choose one of the channels below.",
"TITLE_NEXT": "Complete the setup",
"TITLE_FINISH": "Voilà!",
"CHANNEL": {
"WEBSITE": {
"TITLE": "Website",
"DESCRIPTION": "Create a live-chat widget"
},
"FACEBOOK": {
"TITLE": "Facebook",
"DESCRIPTION": "Connect your Facebook page"
},
"WHATSAPP": {
"TITLE": "WhatsApp",
"DESCRIPTION": "Support your customers on WhatsApp"
},
"EMAIL": {
"TITLE": "Email",
"DESCRIPTION": "Connect with Gmail, Outlook, or other providers"
},
"SMS": {
"TITLE": "SMS",
"DESCRIPTION": "Integrate SMS channel with Twilio or bandwidth"
},
"API": {
"TITLE": "API",
"DESCRIPTION": "Make a custom channel using our API"
},
"TELEGRAM": {
"TITLE": "Telegram",
"DESCRIPTION": "Configure Telegram channel using Bot token"
},
"LINE": {
"TITLE": "Line",
"DESCRIPTION": "Integrate your Line channel"
},
"INSTAGRAM": {
"TITLE": "Instagram",
"DESCRIPTION": "Connect your instagram account"
},
"VOICE": {
"TITLE": "Voice",
"DESCRIPTION": "Integrate with Twilio Voice"
}
}
},
"AGENTS": {
"TITLE": "Агенти",
@@ -478,7 +522,10 @@
"MESSAGE": "You can now engage with your customers through your new Channel. Happy supporting",
"BUTTON_TEXT": "Take me there",
"MORE_SETTINGS": "More settings",
"WEBSITE_SUCCESS": "You have successfully finished creating a website channel. Copy the code shown below and paste it on your website. Next time a customer use the live chat, the conversation will automatically appear on your inbox."
"WEBSITE_SUCCESS": "You have successfully finished creating a website channel. Copy the code shown below and paste it on your website. Next time a customer use the live chat, the conversation will automatically appear on your inbox.",
"WHATSAPP_QR_INSTRUCTION": "Scan the QR code above to quickly test your WhatsApp inbox",
"MESSENGER_QR_INSTRUCTION": "Scan the QR code above to quickly test your Facebook Messenger inbox",
"TELEGRAM_QR_INSTRUCTION": "Scan the QR code above to quickly test your Telegram inbox"
},
"REAUTH": "Reauthorize",
"VIEW": "View",
@@ -868,9 +915,18 @@
"SCRIPT_SETTINGS": "\n window.chatwootSettings = {options};"
},
"EMAIL_PROVIDERS": {
"MICROSOFT": "Microsoft",
"GOOGLE": "Google",
"OTHER_PROVIDERS": "Other Providers"
"MICROSOFT": {
"TITLE": "Microsoft",
"DESCRIPTION": "Connect with Microsoft"
},
"GOOGLE": {
"TITLE": "Google",
"DESCRIPTION": "Connect with Google"
},
"OTHER_PROVIDERS": {
"TITLE": "Other Providers",
"DESCRIPTION": "Connect with Other Providers"
}
},
"CHANNELS": {
"MESSENGER": "Messenger",
@@ -704,11 +704,28 @@
"ERROR_MESSAGE": "There was an error creating the document, please try again."
},
"FORM": {
"TYPE": {
"LABEL": "Document Type",
"URL": "URL",
"PDF": "PDF File"
},
"URL": {
"LABEL": "URL",
"PLACEHOLDER": "Enter the URL of the document",
"ERROR": "Please provide a valid URL for the document"
},
"PDF_FILE": {
"LABEL": "PDF File",
"CHOOSE_FILE": "Choose PDF file",
"ERROR": "Please select a PDF file",
"HELP_TEXT": "Maximum file size: 10MB",
"INVALID_TYPE": "Please select a valid PDF file",
"TOO_LARGE": "File size exceeds 10MB limit"
},
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
},
"ASSISTANT": {
"LABEL": "Assistant",
"PLACEHOLDER": "Select the assistant",
@@ -610,6 +610,15 @@
"SEND_MESSAGE": "Envia missatge"
}
},
"TWILIO_OPTIONS": {
"LABEL": "Select template",
"SEARCH_PLACEHOLDER": "Search templates",
"EMPTY_STATE": "No templates found",
"TEMPLATE_PARSER": {
"BACK": "Torna",
"SEND_MESSAGE": "Envia missatge"
}
},
"ACTION_BUTTONS": {
"DISCARD": "Discard",
"SEND": "Send ({keyCode})"
@@ -48,7 +48,8 @@
"CREATED_AT": "Creat per",
"LAST_ACTIVITY": "Darrera activitat",
"REFERER_LINK": "Enllaç de referència",
"BLOCKED": "Blocat"
"BLOCKED": "Blocat",
"LABELS": "Etiquetes"
},
"GROUPS": {
"STANDARD_FILTERS": "Filtres estàndard",
@@ -0,0 +1,51 @@
{
"CONTENT_TEMPLATES": {
"MODAL": {
"TITLE": "Twilio Templates",
"SUBTITLE": "Select the Twilio template you want to send",
"TEMPLATE_SELECTED_SUBTITLE": "Configure template: {templateName}"
},
"PICKER": {
"SEARCH_PLACEHOLDER": "Cerca plantilles",
"NO_TEMPLATES_FOUND": "No s'han trobat plantilles per a",
"NO_CONTENT": "Sense contingut",
"HEADER": "Header",
"BODY": "Body",
"FOOTER": "Footer",
"BUTTONS": "Buttons",
"CATEGORY": "Categoria",
"MEDIA_CONTENT": "Media Content",
"MEDIA_CONTENT_FALLBACK": "media content",
"NO_TEMPLATES_AVAILABLE": "No Twilio templates available. Click refresh to sync templates from Twilio.",
"REFRESH_BUTTON": "Refresh templates",
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
"LABELS": {
"LANGUAGE": "Idioma",
"TEMPLATE_BODY": "Cos de la plantilla",
"CATEGORY": "Categoria"
},
"TYPES": {
"MEDIA": "Media",
"QUICK_REPLY": "Quick Reply",
"TEXT": "Llista"
}
},
"PARSER": {
"VARIABLES_LABEL": "Variables",
"LANGUAGE": "Idioma",
"CATEGORY": "Categoria",
"VARIABLE_PLACEHOLDER": "Introdueix el valor {variable}",
"GO_BACK_LABEL": "Torna enrere",
"SEND_MESSAGE_LABEL": "Envia missatge",
"FORM_ERROR_MESSAGE": "Omple totes les variables abans d'enviar-les",
"MEDIA_HEADER_LABEL": "{type} Header",
"MEDIA_URL_LABEL": "Enter full media URL",
"MEDIA_URL_PLACEHOLDER": "https://example.com/image.jpg"
},
"FORM": {
"BACK_BUTTON": "Enrere",
"SEND_MESSAGE_BUTTON": "Envia missatge"
}
}
}
@@ -35,6 +35,11 @@
"API_HOURS_WINDOW": "You can only reply to this conversation within {hours} hours",
"NOT_ASSIGNED_TO_YOU": "Aquesta conversa no està assignada a tu. Vols assignar-te-la?",
"ASSIGN_TO_ME": "Assigna'm",
"BOT_HANDOFF_MESSAGE": "You are responding to a conversation which is currently handled by an assistant or a bot.",
"BOT_HANDOFF_ACTION": "Mark open and assign to you",
"BOT_HANDOFF_REOPEN_ACTION": "Mark conversation open",
"BOT_HANDOFF_SUCCESS": "Conversation has been handed over to you",
"BOT_HANDOFF_ERROR": "Failed to take over the conversation. Please try again.",
"TWILIO_WHATSAPP_CAN_REPLY": "Només pots respondre a aquesta conversa mitjançant una plantilla de missatge a causa de",
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "Restricció de finestra de missatges de 24 hores",
"OLD_INSTAGRAM_INBOX_REPLY_BANNER": "This Instagram account was migrated to the new Instagram channel inbox. All new messages will show up there. You wont be able to send messages from this conversation anymore.",
@@ -807,6 +807,58 @@
"ERROR_MESSAGE": "Unable to update portal"
}
}
},
"PDF_UPLOAD": {
"TITLE": "Upload PDF Document",
"DESCRIPTION": "Upload a PDF document to automatically generate FAQs using AI",
"DRAG_DROP_TEXT": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"ADDITIONAL_CONTEXT_LABEL": "Additional Context (Optional)",
"ADDITIONAL_CONTEXT_PLACEHOLDER": "Provide any additional context or instructions for FAQ generation...",
"UPLOADING": "S'està carregant...",
"UPLOAD": "Upload & Process",
"CANCEL": "Cancel·la",
"ERROR_INVALID_TYPE": "Please select a valid PDF file",
"ERROR_FILE_TOO_LARGE": "File size must be less than 512MB",
"ERROR_UPLOAD_FAILED": "Failed to upload PDF. Please try again."
},
"PDF_DOCUMENTS": {
"TITLE": "PDF Documents",
"DESCRIPTION": "Manage uploaded PDF documents and generate FAQs from them",
"UPLOAD_PDF": "Upload PDF",
"UPLOAD_FIRST_PDF": "Upload your first PDF",
"UPLOADED_BY": "Uploaded by",
"GENERATE_FAQS": "Generate FAQs",
"GENERATING": "Generant...",
"CONFIRM_DELETE": "Are you sure you want to delete {filename}?",
"EMPTY_STATE": {
"TITLE": "No PDF documents yet",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQs using AI"
},
"STATUS": {
"UPLOADED": "Ready",
"PROCESSING": "Processing",
"PROCESSED": "Completat",
"FAILED": "Failed"
}
},
"CONTENT_GENERATION": {
"TITLE": "Content Generation",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQ content using AI",
"UPLOAD_TITLE": "Upload PDF Document",
"DRAG_DROP": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"UPLOADING": "Processing document...",
"UPLOAD_SUCCESS": "Document processed successfully!",
"UPLOAD_ERROR": "Failed to upload document. Please try again.",
"INVALID_FILE_TYPE": "Please select a valid PDF file",
"FILE_TOO_LARGE": "File size must be less than 512MB",
"GENERATED_CONTENT": "Generated FAQ Content",
"PUBLISH_SELECTED": "Publish Selected",
"PUBLISHING": "Publishing...",
"FROM_DOCUMENT": "From document",
"NO_CONTENT": "No generated content available. Upload a PDF document to get started.",
"LOADING": "Loading generated content..."
}
}
}
@@ -424,7 +424,51 @@
},
"AUTH": {
"TITLE": "Escull un canal",
"DESC": "Chatwoot admet widgets de xat en directe, Facebook Messenger, WhatsApp, correus electrònics, etc., com a canals. Si voleu crear un canal personalitzat, podeu crear-lo mitjançant el canal API. Per començar, tria un dels canals següents."
"DESC": "Chatwoot admet widgets de xat en directe, Facebook Messenger, WhatsApp, correus electrònics, etc., com a canals. Si voleu crear un canal personalitzat, podeu crear-lo mitjançant el canal API. Per començar, tria un dels canals següents.",
"TITLE_NEXT": "Complete the setup",
"TITLE_FINISH": "Voilà!",
"CHANNEL": {
"WEBSITE": {
"TITLE": "Lloc web",
"DESCRIPTION": "Create a live-chat widget"
},
"FACEBOOK": {
"TITLE": "Facebook",
"DESCRIPTION": "Connect your Facebook page"
},
"WHATSAPP": {
"TITLE": "WhatsApp",
"DESCRIPTION": "Support your customers on WhatsApp"
},
"EMAIL": {
"TITLE": "Correu electrònic",
"DESCRIPTION": "Connect with Gmail, Outlook, or other providers"
},
"SMS": {
"TITLE": "SMS",
"DESCRIPTION": "Integrate SMS channel with Twilio or bandwidth"
},
"API": {
"TITLE": "API",
"DESCRIPTION": "Make a custom channel using our API"
},
"TELEGRAM": {
"TITLE": "Telegram",
"DESCRIPTION": "Configure Telegram channel using Bot token"
},
"LINE": {
"TITLE": "Line",
"DESCRIPTION": "Integrate your Line channel"
},
"INSTAGRAM": {
"TITLE": "Instagram",
"DESCRIPTION": "Connect your instagram account"
},
"VOICE": {
"TITLE": "Voice",
"DESCRIPTION": "Integrate with Twilio Voice"
}
}
},
"AGENTS": {
"TITLE": "Agents",
@@ -478,7 +522,10 @@
"MESSAGE": "Ja podeu interactuar amb els vostres clients a través del vostre canal nou. Feliç suport",
"BUTTON_TEXT": "Porta'm allà",
"MORE_SETTINGS": "Més configuracions",
"WEBSITE_SUCCESS": "Heu finalitzat amb èxit la creació d'un canal web. Copieu el codi que es mostra a continuació i enganxeu-lo al lloc web. La propera vegada que un client utilitzi el xat en directe, la conversa apareixerà automàticament a la safata d'entrada."
"WEBSITE_SUCCESS": "Heu finalitzat amb èxit la creació d'un canal web. Copieu el codi que es mostra a continuació i enganxeu-lo al lloc web. La propera vegada que un client utilitzi el xat en directe, la conversa apareixerà automàticament a la safata d'entrada.",
"WHATSAPP_QR_INSTRUCTION": "Scan the QR code above to quickly test your WhatsApp inbox",
"MESSENGER_QR_INSTRUCTION": "Scan the QR code above to quickly test your Facebook Messenger inbox",
"TELEGRAM_QR_INSTRUCTION": "Scan the QR code above to quickly test your Telegram inbox"
},
"REAUTH": "Reautoritza",
"VIEW": "Veure",
@@ -868,9 +915,18 @@
"SCRIPT_SETTINGS": "\n window.chatwootSettings = {options};"
},
"EMAIL_PROVIDERS": {
"MICROSOFT": "Microsoft",
"GOOGLE": "Google",
"OTHER_PROVIDERS": "Altres proveïdors"
"MICROSOFT": {
"TITLE": "Microsoft",
"DESCRIPTION": "Connect with Microsoft"
},
"GOOGLE": {
"TITLE": "Google",
"DESCRIPTION": "Connect with Google"
},
"OTHER_PROVIDERS": {
"TITLE": "Altres proveïdors",
"DESCRIPTION": "Connect with Other Providers"
}
},
"CHANNELS": {
"MESSENGER": "Messenger",
@@ -704,11 +704,28 @@
"ERROR_MESSAGE": "There was an error creating the document, please try again."
},
"FORM": {
"TYPE": {
"LABEL": "Document Type",
"URL": "URL",
"PDF": "PDF File"
},
"URL": {
"LABEL": "URL",
"PLACEHOLDER": "Enter the URL of the document",
"ERROR": "Please provide a valid URL for the document"
},
"PDF_FILE": {
"LABEL": "PDF File",
"CHOOSE_FILE": "Choose PDF file",
"ERROR": "Please select a PDF file",
"HELP_TEXT": "Maximum file size: 10MB",
"INVALID_TYPE": "Please select a valid PDF file",
"TOO_LARGE": "File size exceeds 10MB limit"
},
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
},
"ASSISTANT": {
"LABEL": "Assistant",
"PLACEHOLDER": "Select the assistant",
@@ -610,6 +610,15 @@
"SEND_MESSAGE": "Send message"
}
},
"TWILIO_OPTIONS": {
"LABEL": "Select template",
"SEARCH_PLACEHOLDER": "Search templates",
"EMPTY_STATE": "No templates found",
"TEMPLATE_PARSER": {
"BACK": "Go back",
"SEND_MESSAGE": "Send message"
}
},
"ACTION_BUTTONS": {
"DISCARD": "Discard",
"SEND": "Send ({keyCode})"
@@ -48,7 +48,8 @@
"CREATED_AT": "Vytvořeno",
"LAST_ACTIVITY": "Poslední aktivita",
"REFERER_LINK": "Odkazující odkaz",
"BLOCKED": "Blocked"
"BLOCKED": "Blocked",
"LABELS": "Štítky"
},
"GROUPS": {
"STANDARD_FILTERS": "Standardní filtry",
@@ -0,0 +1,51 @@
{
"CONTENT_TEMPLATES": {
"MODAL": {
"TITLE": "Twilio Templates",
"SUBTITLE": "Select the Twilio template you want to send",
"TEMPLATE_SELECTED_SUBTITLE": "Configure template: {templateName}"
},
"PICKER": {
"SEARCH_PLACEHOLDER": "Search Templates",
"NO_TEMPLATES_FOUND": "No templates found for",
"NO_CONTENT": "No content",
"HEADER": "Header",
"BODY": "Body",
"FOOTER": "Footer",
"BUTTONS": "Buttons",
"CATEGORY": "Category",
"MEDIA_CONTENT": "Media Content",
"MEDIA_CONTENT_FALLBACK": "media content",
"NO_TEMPLATES_AVAILABLE": "No Twilio templates available. Click refresh to sync templates from Twilio.",
"REFRESH_BUTTON": "Refresh templates",
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
"LABELS": {
"LANGUAGE": "Language",
"TEMPLATE_BODY": "Template Body",
"CATEGORY": "Category"
},
"TYPES": {
"MEDIA": "Media",
"QUICK_REPLY": "Quick Reply",
"TEXT": "Text"
}
},
"PARSER": {
"VARIABLES_LABEL": "Variables",
"LANGUAGE": "Language",
"CATEGORY": "Category",
"VARIABLE_PLACEHOLDER": "Enter {variable} value",
"GO_BACK_LABEL": "Go Back",
"SEND_MESSAGE_LABEL": "Send Message",
"FORM_ERROR_MESSAGE": "Please fill all variables before sending",
"MEDIA_HEADER_LABEL": "{type} Header",
"MEDIA_URL_LABEL": "Enter full media URL",
"MEDIA_URL_PLACEHOLDER": "https://example.com/image.jpg"
},
"FORM": {
"BACK_BUTTON": "Zpět",
"SEND_MESSAGE_BUTTON": "Send Message"
}
}
}
@@ -35,6 +35,11 @@
"API_HOURS_WINDOW": "You can only reply to this conversation within {hours} hours",
"NOT_ASSIGNED_TO_YOU": "Tato konverzace vám není přiřazena. Chcete si přiřadit tuto konverzaci?",
"ASSIGN_TO_ME": "Přiřadit mi",
"BOT_HANDOFF_MESSAGE": "You are responding to a conversation which is currently handled by an assistant or a bot.",
"BOT_HANDOFF_ACTION": "Mark open and assign to you",
"BOT_HANDOFF_REOPEN_ACTION": "Mark conversation open",
"BOT_HANDOFF_SUCCESS": "Conversation has been handed over to you",
"BOT_HANDOFF_ERROR": "Failed to take over the conversation. Please try again.",
"TWILIO_WHATSAPP_CAN_REPLY": "Na tuto konverzaci můžete odpovědět pouze pomocí šablony zprávy z důvodu",
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "24 hodinové omezení okna",
"OLD_INSTAGRAM_INBOX_REPLY_BANNER": "This Instagram account was migrated to the new Instagram channel inbox. All new messages will show up there. You wont be able to send messages from this conversation anymore.",
@@ -807,6 +807,58 @@
"ERROR_MESSAGE": "Unable to update portal"
}
}
},
"PDF_UPLOAD": {
"TITLE": "Upload PDF Document",
"DESCRIPTION": "Upload a PDF document to automatically generate FAQs using AI",
"DRAG_DROP_TEXT": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"ADDITIONAL_CONTEXT_LABEL": "Additional Context (Optional)",
"ADDITIONAL_CONTEXT_PLACEHOLDER": "Provide any additional context or instructions for FAQ generation...",
"UPLOADING": "Nahrávání...",
"UPLOAD": "Upload & Process",
"CANCEL": "Zrušit",
"ERROR_INVALID_TYPE": "Please select a valid PDF file",
"ERROR_FILE_TOO_LARGE": "File size must be less than 512MB",
"ERROR_UPLOAD_FAILED": "Failed to upload PDF. Please try again."
},
"PDF_DOCUMENTS": {
"TITLE": "PDF Documents",
"DESCRIPTION": "Manage uploaded PDF documents and generate FAQs from them",
"UPLOAD_PDF": "Upload PDF",
"UPLOAD_FIRST_PDF": "Upload your first PDF",
"UPLOADED_BY": "Uploaded by",
"GENERATE_FAQS": "Generate FAQs",
"GENERATING": "Generating...",
"CONFIRM_DELETE": "Are you sure you want to delete {filename}?",
"EMPTY_STATE": {
"TITLE": "No PDF documents yet",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQs using AI"
},
"STATUS": {
"UPLOADED": "Ready",
"PROCESSING": "Processing",
"PROCESSED": "Completed",
"FAILED": "Failed"
}
},
"CONTENT_GENERATION": {
"TITLE": "Content Generation",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQ content using AI",
"UPLOAD_TITLE": "Upload PDF Document",
"DRAG_DROP": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"UPLOADING": "Processing document...",
"UPLOAD_SUCCESS": "Document processed successfully!",
"UPLOAD_ERROR": "Failed to upload document. Please try again.",
"INVALID_FILE_TYPE": "Please select a valid PDF file",
"FILE_TOO_LARGE": "File size must be less than 512MB",
"GENERATED_CONTENT": "Generated FAQ Content",
"PUBLISH_SELECTED": "Publish Selected",
"PUBLISHING": "Publishing...",
"FROM_DOCUMENT": "From document",
"NO_CONTENT": "No generated content available. Upload a PDF document to get started.",
"LOADING": "Loading generated content..."
}
}
}
@@ -424,7 +424,51 @@
},
"AUTH": {
"TITLE": "Choose a channel",
"DESC": "Chatwoot supports live-chat widgets, Facebook Messenger, Twitter profiles, WhatsApp, Emails, etc., as channels. If you want to build a custom channel, you can create it using the API channel. To get started, choose one of the channels below."
"DESC": "Chatwoot supports live-chat widgets, Facebook Messenger, Twitter profiles, WhatsApp, Emails, etc., as channels. If you want to build a custom channel, you can create it using the API channel. To get started, choose one of the channels below.",
"TITLE_NEXT": "Complete the setup",
"TITLE_FINISH": "Voilà!",
"CHANNEL": {
"WEBSITE": {
"TITLE": "Website",
"DESCRIPTION": "Create a live-chat widget"
},
"FACEBOOK": {
"TITLE": "Facebook",
"DESCRIPTION": "Connect your Facebook page"
},
"WHATSAPP": {
"TITLE": "WhatsApp",
"DESCRIPTION": "Support your customers on WhatsApp"
},
"EMAIL": {
"TITLE": "E-mailová adresa",
"DESCRIPTION": "Connect with Gmail, Outlook, or other providers"
},
"SMS": {
"TITLE": "SMS",
"DESCRIPTION": "Integrate SMS channel with Twilio or bandwidth"
},
"API": {
"TITLE": "API",
"DESCRIPTION": "Make a custom channel using our API"
},
"TELEGRAM": {
"TITLE": "Telegram",
"DESCRIPTION": "Configure Telegram channel using Bot token"
},
"LINE": {
"TITLE": "Line",
"DESCRIPTION": "Integrate your Line channel"
},
"INSTAGRAM": {
"TITLE": "Instagram",
"DESCRIPTION": "Connect your instagram account"
},
"VOICE": {
"TITLE": "Voice",
"DESCRIPTION": "Integrate with Twilio Voice"
}
}
},
"AGENTS": {
"TITLE": "Agenti",
@@ -478,7 +522,10 @@
"MESSAGE": "You can now engage with your customers through your new Channel. Happy supporting",
"BUTTON_TEXT": "Vezmi mě tam",
"MORE_SETTINGS": "More settings",
"WEBSITE_SUCCESS": "Úspěšně jste dokončili vytvoření webového kanálu. Zkopírujte kód zobrazený níže a vložte jej na vaše webové stránky. Když zákazník příště použije živý chat, konverzace se automaticky objeví ve vaší doručené poště."
"WEBSITE_SUCCESS": "Úspěšně jste dokončili vytvoření webového kanálu. Zkopírujte kód zobrazený níže a vložte jej na vaše webové stránky. Když zákazník příště použije živý chat, konverzace se automaticky objeví ve vaší doručené poště.",
"WHATSAPP_QR_INSTRUCTION": "Scan the QR code above to quickly test your WhatsApp inbox",
"MESSENGER_QR_INSTRUCTION": "Scan the QR code above to quickly test your Facebook Messenger inbox",
"TELEGRAM_QR_INSTRUCTION": "Scan the QR code above to quickly test your Telegram inbox"
},
"REAUTH": "Znovu autorizovat",
"VIEW": "Zobrazit",
@@ -868,9 +915,18 @@
"SCRIPT_SETTINGS": "\n window.chatwootSettings = {options};"
},
"EMAIL_PROVIDERS": {
"MICROSOFT": "Microsoft",
"GOOGLE": "Google",
"OTHER_PROVIDERS": "Other Providers"
"MICROSOFT": {
"TITLE": "Microsoft",
"DESCRIPTION": "Connect with Microsoft"
},
"GOOGLE": {
"TITLE": "Google",
"DESCRIPTION": "Connect with Google"
},
"OTHER_PROVIDERS": {
"TITLE": "Other Providers",
"DESCRIPTION": "Connect with Other Providers"
}
},
"CHANNELS": {
"MESSENGER": "Messenger",
@@ -704,11 +704,28 @@
"ERROR_MESSAGE": "There was an error creating the document, please try again."
},
"FORM": {
"TYPE": {
"LABEL": "Document Type",
"URL": "URL",
"PDF": "PDF File"
},
"URL": {
"LABEL": "URL",
"PLACEHOLDER": "Enter the URL of the document",
"ERROR": "Please provide a valid URL for the document"
},
"PDF_FILE": {
"LABEL": "PDF File",
"CHOOSE_FILE": "Choose PDF file",
"ERROR": "Please select a PDF file",
"HELP_TEXT": "Maximum file size: 10MB",
"INVALID_TYPE": "Please select a valid PDF file",
"TOO_LARGE": "File size exceeds 10MB limit"
},
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
},
"ASSISTANT": {
"LABEL": "Assistant",
"PLACEHOLDER": "Select the assistant",
@@ -610,6 +610,15 @@
"SEND_MESSAGE": "Send besked"
}
},
"TWILIO_OPTIONS": {
"LABEL": "Select template",
"SEARCH_PLACEHOLDER": "Search templates",
"EMPTY_STATE": "No templates found",
"TEMPLATE_PARSER": {
"BACK": "Gå tilbage",
"SEND_MESSAGE": "Send besked"
}
},
"ACTION_BUTTONS": {
"DISCARD": "Discard",
"SEND": "Send ({keyCode})"
@@ -48,7 +48,8 @@
"CREATED_AT": "Oprettet Den",
"LAST_ACTIVITY": "Sidste Aktivitet",
"REFERER_LINK": "Link til reference",
"BLOCKED": "Blocked"
"BLOCKED": "Blocked",
"LABELS": "Etiketter"
},
"GROUPS": {
"STANDARD_FILTERS": "Standard Filtre",
@@ -0,0 +1,51 @@
{
"CONTENT_TEMPLATES": {
"MODAL": {
"TITLE": "Twilio Templates",
"SUBTITLE": "Select the Twilio template you want to send",
"TEMPLATE_SELECTED_SUBTITLE": "Configure template: {templateName}"
},
"PICKER": {
"SEARCH_PLACEHOLDER": "Søg Skabeloner",
"NO_TEMPLATES_FOUND": "Ingen skabeloner fundet for",
"NO_CONTENT": "No content",
"HEADER": "Header",
"BODY": "Body",
"FOOTER": "Footer",
"BUTTONS": "Buttons",
"CATEGORY": "Kategori",
"MEDIA_CONTENT": "Media Content",
"MEDIA_CONTENT_FALLBACK": "media content",
"NO_TEMPLATES_AVAILABLE": "No Twilio templates available. Click refresh to sync templates from Twilio.",
"REFRESH_BUTTON": "Refresh templates",
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
"LABELS": {
"LANGUAGE": "Sprog",
"TEMPLATE_BODY": "Skabelon Krop",
"CATEGORY": "Kategori"
},
"TYPES": {
"MEDIA": "Media",
"QUICK_REPLY": "Quick Reply",
"TEXT": "Tekst"
}
},
"PARSER": {
"VARIABLES_LABEL": "Variabler",
"LANGUAGE": "Sprog",
"CATEGORY": "Kategori",
"VARIABLE_PLACEHOLDER": "Indtast {variable} værdi",
"GO_BACK_LABEL": "Gå Tilbage",
"SEND_MESSAGE_LABEL": "Send Besked",
"FORM_ERROR_MESSAGE": "Udfyld venligst alle variabler før afsendelse",
"MEDIA_HEADER_LABEL": "{type} Header",
"MEDIA_URL_LABEL": "Enter full media URL",
"MEDIA_URL_PLACEHOLDER": "https://example.com/image.jpg"
},
"FORM": {
"BACK_BUTTON": "Tilbage",
"SEND_MESSAGE_BUTTON": "Send Besked"
}
}
}
@@ -35,6 +35,11 @@
"API_HOURS_WINDOW": "You can only reply to this conversation within {hours} hours",
"NOT_ASSIGNED_TO_YOU": "Denne samtale er ikke tildelt dig. Vil du tildele denne samtale til dig selv?",
"ASSIGN_TO_ME": "Tildel til mig",
"BOT_HANDOFF_MESSAGE": "You are responding to a conversation which is currently handled by an assistant or a bot.",
"BOT_HANDOFF_ACTION": "Mark open and assign to you",
"BOT_HANDOFF_REOPEN_ACTION": "Mark conversation open",
"BOT_HANDOFF_SUCCESS": "Conversation has been handed over to you",
"BOT_HANDOFF_ERROR": "Failed to take over the conversation. Please try again.",
"TWILIO_WHATSAPP_CAN_REPLY": "Du kan kun svare på denne samtale ved hjælp af en skabelon besked på grund af",
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "24 timers beskedvindue begrænsning",
"OLD_INSTAGRAM_INBOX_REPLY_BANNER": "This Instagram account was migrated to the new Instagram channel inbox. All new messages will show up there. You wont be able to send messages from this conversation anymore.",
@@ -807,6 +807,58 @@
"ERROR_MESSAGE": "Unable to update portal"
}
}
},
"PDF_UPLOAD": {
"TITLE": "Upload PDF Document",
"DESCRIPTION": "Upload a PDF document to automatically generate FAQs using AI",
"DRAG_DROP_TEXT": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"ADDITIONAL_CONTEXT_LABEL": "Additional Context (Optional)",
"ADDITIONAL_CONTEXT_PLACEHOLDER": "Provide any additional context or instructions for FAQ generation...",
"UPLOADING": "Uploader...",
"UPLOAD": "Upload & Process",
"CANCEL": "Annuller",
"ERROR_INVALID_TYPE": "Please select a valid PDF file",
"ERROR_FILE_TOO_LARGE": "File size must be less than 512MB",
"ERROR_UPLOAD_FAILED": "Failed to upload PDF. Please try again."
},
"PDF_DOCUMENTS": {
"TITLE": "PDF Documents",
"DESCRIPTION": "Manage uploaded PDF documents and generate FAQs from them",
"UPLOAD_PDF": "Upload PDF",
"UPLOAD_FIRST_PDF": "Upload your first PDF",
"UPLOADED_BY": "Uploaded by",
"GENERATE_FAQS": "Generate FAQs",
"GENERATING": "Generating...",
"CONFIRM_DELETE": "Are you sure you want to delete {filename}?",
"EMPTY_STATE": {
"TITLE": "No PDF documents yet",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQs using AI"
},
"STATUS": {
"UPLOADED": "Ready",
"PROCESSING": "Processing",
"PROCESSED": "Afsluttet",
"FAILED": "Failed"
}
},
"CONTENT_GENERATION": {
"TITLE": "Content Generation",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQ content using AI",
"UPLOAD_TITLE": "Upload PDF Document",
"DRAG_DROP": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"UPLOADING": "Processing document...",
"UPLOAD_SUCCESS": "Document processed successfully!",
"UPLOAD_ERROR": "Failed to upload document. Please try again.",
"INVALID_FILE_TYPE": "Please select a valid PDF file",
"FILE_TOO_LARGE": "File size must be less than 512MB",
"GENERATED_CONTENT": "Generated FAQ Content",
"PUBLISH_SELECTED": "Publish Selected",
"PUBLISHING": "Publishing...",
"FROM_DOCUMENT": "From document",
"NO_CONTENT": "No generated content available. Upload a PDF document to get started.",
"LOADING": "Loading generated content..."
}
}
}
@@ -424,7 +424,51 @@
},
"AUTH": {
"TITLE": "Vælg en kanal",
"DESC": "Chatwoot understøtter live-chat-widgets, Facebook Messenger, Twitter-profiler, WhatsApp, E-mails, osv., som kanaler. Hvis du ønsker at bygge en brugerdefineret kanal, kan du oprette den ved hjælp af API-kanalen. For at komme i gang, vælg en af kanalerne nedenfor."
"DESC": "Chatwoot understøtter live-chat-widgets, Facebook Messenger, Twitter-profiler, WhatsApp, E-mails, osv., som kanaler. Hvis du ønsker at bygge en brugerdefineret kanal, kan du oprette den ved hjælp af API-kanalen. For at komme i gang, vælg en af kanalerne nedenfor.",
"TITLE_NEXT": "Complete the setup",
"TITLE_FINISH": "Voilà!",
"CHANNEL": {
"WEBSITE": {
"TITLE": "Website",
"DESCRIPTION": "Create a live-chat widget"
},
"FACEBOOK": {
"TITLE": "Facebook",
"DESCRIPTION": "Connect your Facebook page"
},
"WHATSAPP": {
"TITLE": "WhatsApp",
"DESCRIPTION": "Support your customers on WhatsApp"
},
"EMAIL": {
"TITLE": "E-mail",
"DESCRIPTION": "Connect with Gmail, Outlook, or other providers"
},
"SMS": {
"TITLE": "SMS",
"DESCRIPTION": "Integrate SMS channel with Twilio or bandwidth"
},
"API": {
"TITLE": "API",
"DESCRIPTION": "Make a custom channel using our API"
},
"TELEGRAM": {
"TITLE": "Telegram",
"DESCRIPTION": "Configure Telegram channel using Bot token"
},
"LINE": {
"TITLE": "Line",
"DESCRIPTION": "Integrate your Line channel"
},
"INSTAGRAM": {
"TITLE": "Instagram",
"DESCRIPTION": "Connect your instagram account"
},
"VOICE": {
"TITLE": "Voice",
"DESCRIPTION": "Integrate with Twilio Voice"
}
}
},
"AGENTS": {
"TITLE": "Agenter",
@@ -478,7 +522,10 @@
"MESSAGE": "Du kan nu engagere dig med dine kunder gennem din nye kanal. Glædelig supportering",
"BUTTON_TEXT": "Tag mig med dertil",
"MORE_SETTINGS": "Flere indstillinger",
"WEBSITE_SUCCESS": "Du er færdig med at oprette en hjemmeside kanal. Kopier koden vist nedenfor og indsæt den på din hjemmeside. Næste gang en kunde bruger live chat, vil samtalen automatisk vises i din indbakke."
"WEBSITE_SUCCESS": "Du er færdig med at oprette en hjemmeside kanal. Kopier koden vist nedenfor og indsæt den på din hjemmeside. Næste gang en kunde bruger live chat, vil samtalen automatisk vises i din indbakke.",
"WHATSAPP_QR_INSTRUCTION": "Scan the QR code above to quickly test your WhatsApp inbox",
"MESSENGER_QR_INSTRUCTION": "Scan the QR code above to quickly test your Facebook Messenger inbox",
"TELEGRAM_QR_INSTRUCTION": "Scan the QR code above to quickly test your Telegram inbox"
},
"REAUTH": "Genautorisér",
"VIEW": "Vis",
@@ -868,9 +915,18 @@
"SCRIPT_SETTINGS": "\n window.chatwootSettings = {options};"
},
"EMAIL_PROVIDERS": {
"MICROSOFT": "Microsoft",
"GOOGLE": "Google",
"OTHER_PROVIDERS": "Other Providers"
"MICROSOFT": {
"TITLE": "Microsoft",
"DESCRIPTION": "Connect with Microsoft"
},
"GOOGLE": {
"TITLE": "Google",
"DESCRIPTION": "Connect with Google"
},
"OTHER_PROVIDERS": {
"TITLE": "Other Providers",
"DESCRIPTION": "Connect with Other Providers"
}
},
"CHANNELS": {
"MESSENGER": "Messenger",
@@ -704,11 +704,28 @@
"ERROR_MESSAGE": "There was an error creating the document, please try again."
},
"FORM": {
"TYPE": {
"LABEL": "Document Type",
"URL": "URL",
"PDF": "PDF File"
},
"URL": {
"LABEL": "URL",
"PLACEHOLDER": "Enter the URL of the document",
"ERROR": "Please provide a valid URL for the document"
},
"PDF_FILE": {
"LABEL": "PDF File",
"CHOOSE_FILE": "Choose PDF file",
"ERROR": "Please select a PDF file",
"HELP_TEXT": "Maximum file size: 10MB",
"INVALID_TYPE": "Please select a valid PDF file",
"TOO_LARGE": "File size exceeds 10MB limit"
},
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
},
"ASSISTANT": {
"LABEL": "Assistant",
"PLACEHOLDER": "Select the assistant",
@@ -17,7 +17,7 @@
"IP_ADDRESS": "IP-Adresse",
"CREATED_AT_LABEL": "Erstellt",
"NEW_MESSAGE": "Neue Nachricht",
"CALL": "Call",
"CALL": "Anruf",
"CALL_UNDER_DEVELOPMENT": "Calling is under development",
"VOICE_INBOX_PICKER": {
"TITLE": "Choose a voice inbox"
@@ -610,6 +610,15 @@
"SEND_MESSAGE": "Nachricht senden"
}
},
"TWILIO_OPTIONS": {
"LABEL": "Vorlage auswählen",
"SEARCH_PLACEHOLDER": "Vorlagen suchen",
"EMPTY_STATE": "Keine Vorlagen gefunden",
"TEMPLATE_PARSER": {
"BACK": "Zurück",
"SEND_MESSAGE": "Nachricht senden"
}
},
"ACTION_BUTTONS": {
"DISCARD": "Verwerfen",
"SEND": "Senden ({keyCode})"
@@ -48,7 +48,8 @@
"CREATED_AT": "Erstellt am",
"LAST_ACTIVITY": "Letzte Aktivität",
"REFERER_LINK": "Verweis-Link",
"BLOCKED": "Blockiert"
"BLOCKED": "Blockiert",
"LABELS": "Labels"
},
"GROUPS": {
"STANDARD_FILTERS": "Standardfilter",
@@ -0,0 +1,51 @@
{
"CONTENT_TEMPLATES": {
"MODAL": {
"TITLE": "Twilio Templates",
"SUBTITLE": "Select the Twilio template you want to send",
"TEMPLATE_SELECTED_SUBTITLE": "Configure template: {templateName}"
},
"PICKER": {
"SEARCH_PLACEHOLDER": "Vorlagen suchen",
"NO_TEMPLATES_FOUND": "Keine Vorlagen gefunden für",
"NO_CONTENT": "Kein Inhalt",
"HEADER": "Header",
"BODY": "Body",
"FOOTER": "Footer",
"BUTTONS": "Buttons",
"CATEGORY": "Kategorie",
"MEDIA_CONTENT": "Media Content",
"MEDIA_CONTENT_FALLBACK": "media content",
"NO_TEMPLATES_AVAILABLE": "No Twilio templates available. Click refresh to sync templates from Twilio.",
"REFRESH_BUTTON": "Refresh templates",
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
"LABELS": {
"LANGUAGE": "Sprache",
"TEMPLATE_BODY": "Vorlagenbody",
"CATEGORY": "Kategorie"
},
"TYPES": {
"MEDIA": "Media",
"QUICK_REPLY": "Quick Reply",
"TEXT": "Text"
}
},
"PARSER": {
"VARIABLES_LABEL": "Variablen",
"LANGUAGE": "Sprache",
"CATEGORY": "Kategorie",
"VARIABLE_PLACEHOLDER": "Geben Sie den Wert {variable} ein",
"GO_BACK_LABEL": "Zurück",
"SEND_MESSAGE_LABEL": "Nachricht senden",
"FORM_ERROR_MESSAGE": "Bitte füllen Sie vor dem Absenden alle Variablen aus",
"MEDIA_HEADER_LABEL": "{type} Header",
"MEDIA_URL_LABEL": "Enter full media URL",
"MEDIA_URL_PLACEHOLDER": "https://example.com/image.jpg"
},
"FORM": {
"BACK_BUTTON": "Zurück",
"SEND_MESSAGE_BUTTON": "Nachricht senden"
}
}
}
@@ -35,6 +35,11 @@
"API_HOURS_WINDOW": "Sie können auf diese Unterhaltung nur innerhalb von {hours} Stunden antworten",
"NOT_ASSIGNED_TO_YOU": "Diese Konversation ist Ihnen nicht zugeordnet. Möchten Sie dieses Gespräch sich selbst zuordnen?",
"ASSIGN_TO_ME": "Mir zuweisen",
"BOT_HANDOFF_MESSAGE": "Sie antworten auf eine Unterhaltung, die derzeit von einem Assistenten oder einem Bot bearbeitet wird.",
"BOT_HANDOFF_ACTION": "Mark open and assign to you",
"BOT_HANDOFF_REOPEN_ACTION": "Mark conversation open",
"BOT_HANDOFF_SUCCESS": "Conversation has been handed over to you",
"BOT_HANDOFF_ERROR": "Failed to take over the conversation. Please try again.",
"TWILIO_WHATSAPP_CAN_REPLY": "Sie können auf diese Konversation nur mit einer Nachrichtenvorlage antworten wegen",
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "24-Stunden-Nachrichtenfenster-Beschränkung",
"OLD_INSTAGRAM_INBOX_REPLY_BANNER": "Dieser Instagram-Account wurde in den neuen Instagram-Kanal übertragen. Alle neuen Nachrichten werden dort erscheinen. Sie werden keine Nachrichten mehr von dieser Unterhaltung senden können.",
@@ -59,7 +59,7 @@
},
"MESSAGE": {
"LABEL": "Custom auto-resolution message",
"PLACEHOLDER": "Conversation was marked resolved by system due to 15 days of inactivity",
"PLACEHOLDER": "Die Unterhaltung wurde durch das System aufgrund von 15 Tagen Inaktivität geschlossen",
"HELP": "Message sent to the customer after conversation is auto-resolved"
},
"PREFERENCES": "Einstellungen",
@@ -115,7 +115,7 @@
},
"UPDATE_BUTTON": "Aktualisieren",
"MESSAGE_LABEL": "Custom resolution message",
"MESSAGE_PLACEHOLDER": "Conversation was marked resolved by system due to 15 days of inactivity",
"MESSAGE_PLACEHOLDER": "Die Unterhaltung wurde durch das System aufgrund von 15 Tagen Inaktivität geschlossen",
"MESSAGE_HELP": "This message is sent to the customer when a conversation is automatically resolved by the system due to inactivity."
},
"FEATURES": {
@@ -807,6 +807,58 @@
"ERROR_MESSAGE": "Unable to update portal"
}
}
},
"PDF_UPLOAD": {
"TITLE": "Upload PDF Document",
"DESCRIPTION": "Upload a PDF document to automatically generate FAQs using AI",
"DRAG_DROP_TEXT": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"ADDITIONAL_CONTEXT_LABEL": "Additional Context (Optional)",
"ADDITIONAL_CONTEXT_PLACEHOLDER": "Provide any additional context or instructions for FAQ generation...",
"UPLOADING": "Hochladen...",
"UPLOAD": "Upload & Process",
"CANCEL": "Stornieren",
"ERROR_INVALID_TYPE": "Please select a valid PDF file",
"ERROR_FILE_TOO_LARGE": "File size must be less than 512MB",
"ERROR_UPLOAD_FAILED": "Failed to upload PDF. Please try again."
},
"PDF_DOCUMENTS": {
"TITLE": "PDF Documents",
"DESCRIPTION": "Manage uploaded PDF documents and generate FAQs from them",
"UPLOAD_PDF": "Upload PDF",
"UPLOAD_FIRST_PDF": "Upload your first PDF",
"UPLOADED_BY": "Uploaded by",
"GENERATE_FAQS": "Generate FAQs",
"GENERATING": "Generieren...",
"CONFIRM_DELETE": "Are you sure you want to delete {filename}?",
"EMPTY_STATE": {
"TITLE": "No PDF documents yet",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQs using AI"
},
"STATUS": {
"UPLOADED": "Ready",
"PROCESSING": "Processing",
"PROCESSED": "Erledigt",
"FAILED": "Failed"
}
},
"CONTENT_GENERATION": {
"TITLE": "Content Generation",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQ content using AI",
"UPLOAD_TITLE": "Upload PDF Document",
"DRAG_DROP": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"UPLOADING": "Processing document...",
"UPLOAD_SUCCESS": "Document processed successfully!",
"UPLOAD_ERROR": "Failed to upload document. Please try again.",
"INVALID_FILE_TYPE": "Please select a valid PDF file",
"FILE_TOO_LARGE": "File size must be less than 512MB",
"GENERATED_CONTENT": "Generated FAQ Content",
"PUBLISH_SELECTED": "Publish Selected",
"PUBLISHING": "Publishing...",
"FROM_DOCUMENT": "From document",
"NO_CONTENT": "No generated content available. Upload a PDF document to get started.",
"LOADING": "Loading generated content..."
}
}
}
@@ -424,7 +424,51 @@
},
"AUTH": {
"TITLE": "Wählen Sie einen Kanal",
"DESC": "Chatwoot unterstützt Live-Chat-Widgets, Facebook Messenger, Twitter-Profile, WhatsApp, E-Mails usw. als Kanäle. Wenn Sie einen benutzerdefinierten Kanal erstellen möchten, können Sie ihn mithilfe des API-Kanals erstellen. Wählen Sie zunächst einen der folgenden Kanäle aus."
"DESC": "Chatwoot unterstützt Live-Chat-Widgets, Facebook Messenger, Twitter-Profile, WhatsApp, E-Mails usw. als Kanäle. Wenn Sie einen benutzerdefinierten Kanal erstellen möchten, können Sie ihn mithilfe des API-Kanals erstellen. Wählen Sie zunächst einen der folgenden Kanäle aus.",
"TITLE_NEXT": "Complete the setup",
"TITLE_FINISH": "Voilà!",
"CHANNEL": {
"WEBSITE": {
"TITLE": "Webseite",
"DESCRIPTION": "Create a live-chat widget"
},
"FACEBOOK": {
"TITLE": "Facebook",
"DESCRIPTION": "Connect your Facebook page"
},
"WHATSAPP": {
"TITLE": "WhatsApp",
"DESCRIPTION": "Support your customers on WhatsApp"
},
"EMAIL": {
"TITLE": "E-Mail",
"DESCRIPTION": "Connect with Gmail, Outlook, or other providers"
},
"SMS": {
"TITLE": "SMS",
"DESCRIPTION": "Integrate SMS channel with Twilio or bandwidth"
},
"API": {
"TITLE": "API",
"DESCRIPTION": "Make a custom channel using our API"
},
"TELEGRAM": {
"TITLE": "Telegramm",
"DESCRIPTION": "Configure Telegram channel using Bot token"
},
"LINE": {
"TITLE": "Line",
"DESCRIPTION": "Integrate your Line channel"
},
"INSTAGRAM": {
"TITLE": "Instagram",
"DESCRIPTION": "Connect your instagram account"
},
"VOICE": {
"TITLE": "Voice",
"DESCRIPTION": "Integrate with Twilio Voice"
}
}
},
"AGENTS": {
"TITLE": "Agenten",
@@ -478,7 +522,10 @@
"MESSAGE": "Sie können jetzt über Ihren neuen Kanal mit Ihren Kunden in Kontakt treten. Fröhliches Unterstützen",
"BUTTON_TEXT": "Bring mich dahin",
"MORE_SETTINGS": "Weitere Einstellungen",
"WEBSITE_SUCCESS": "Sie haben die Erstellung eines Website-Kanals erfolgreich abgeschlossen. Kopieren Sie den unten gezeigten Code und fügen Sie ihn in Ihre Website ein. Wenn ein Kunde das nächste Mal den Live-Chat verwendet, wird die Konversation automatisch in Ihrem Posteingang angezeigt."
"WEBSITE_SUCCESS": "Sie haben die Erstellung eines Website-Kanals erfolgreich abgeschlossen. Kopieren Sie den unten gezeigten Code und fügen Sie ihn in Ihre Website ein. Wenn ein Kunde das nächste Mal den Live-Chat verwendet, wird die Konversation automatisch in Ihrem Posteingang angezeigt.",
"WHATSAPP_QR_INSTRUCTION": "Scan the QR code above to quickly test your WhatsApp inbox",
"MESSENGER_QR_INSTRUCTION": "Scan the QR code above to quickly test your Facebook Messenger inbox",
"TELEGRAM_QR_INSTRUCTION": "Scan the QR code above to quickly test your Telegram inbox"
},
"REAUTH": "Neu autorisieren",
"VIEW": "Aussicht",
@@ -868,9 +915,18 @@
"SCRIPT_SETTINGS": "\n window.chatwootSettings = {options};"
},
"EMAIL_PROVIDERS": {
"MICROSOFT": "Microsoft",
"GOOGLE": "Google",
"OTHER_PROVIDERS": "Andere Anbieter"
"MICROSOFT": {
"TITLE": "Microsoft",
"DESCRIPTION": "Connect with Microsoft"
},
"GOOGLE": {
"TITLE": "Google",
"DESCRIPTION": "Connect with Google"
},
"OTHER_PROVIDERS": {
"TITLE": "Andere Anbieter",
"DESCRIPTION": "Connect with Other Providers"
}
},
"CHANNELS": {
"MESSENGER": "Messenger",
@@ -704,11 +704,28 @@
"ERROR_MESSAGE": "There was an error creating the document, please try again."
},
"FORM": {
"TYPE": {
"LABEL": "Document Type",
"URL": "URL",
"PDF": "PDF File"
},
"URL": {
"LABEL": "URL",
"PLACEHOLDER": "Enter the URL of the document",
"ERROR": "Please provide a valid URL for the document"
},
"PDF_FILE": {
"LABEL": "PDF File",
"CHOOSE_FILE": "Choose PDF file",
"ERROR": "Please select a PDF file",
"HELP_TEXT": "Maximum file size: 10MB",
"INVALID_TYPE": "Please select a valid PDF file",
"TOO_LARGE": "File size exceeds 10MB limit"
},
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
},
"ASSISTANT": {
"LABEL": "Assistant",
"PLACEHOLDER": "Select the assistant",
@@ -610,6 +610,15 @@
"SEND_MESSAGE": "Αποστολή μηνύματος"
}
},
"TWILIO_OPTIONS": {
"LABEL": "Select template",
"SEARCH_PLACEHOLDER": "Search templates",
"EMPTY_STATE": "No templates found",
"TEMPLATE_PARSER": {
"BACK": "Πίσω",
"SEND_MESSAGE": "Αποστολή μηνύματος"
}
},
"ACTION_BUTTONS": {
"DISCARD": "Discard",
"SEND": "Send ({keyCode})"
@@ -48,7 +48,8 @@
"CREATED_AT": "Δημιουργήθηκε στις",
"LAST_ACTIVITY": "Τελευταία Δραστηριότητα",
"REFERER_LINK": "Σύνδεσμος αναφοράς",
"BLOCKED": "Blocked"
"BLOCKED": "Blocked",
"LABELS": "Ετικέτες"
},
"GROUPS": {
"STANDARD_FILTERS": "Τυπικά Φίλτρα",
@@ -0,0 +1,51 @@
{
"CONTENT_TEMPLATES": {
"MODAL": {
"TITLE": "Twilio Templates",
"SUBTITLE": "Select the Twilio template you want to send",
"TEMPLATE_SELECTED_SUBTITLE": "Configure template: {templateName}"
},
"PICKER": {
"SEARCH_PLACEHOLDER": "Αναζήτηση Προτύπων",
"NO_TEMPLATES_FOUND": "Δεν βρέθηκαν πρότυπα για",
"NO_CONTENT": "No content",
"HEADER": "Header",
"BODY": "Body",
"FOOTER": "Footer",
"BUTTONS": "Buttons",
"CATEGORY": "Κατηγορία",
"MEDIA_CONTENT": "Media Content",
"MEDIA_CONTENT_FALLBACK": "media content",
"NO_TEMPLATES_AVAILABLE": "No Twilio templates available. Click refresh to sync templates from Twilio.",
"REFRESH_BUTTON": "Refresh templates",
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
"LABELS": {
"LANGUAGE": "Γλώσσα",
"TEMPLATE_BODY": "Σώμα Προτύπου",
"CATEGORY": "Κατηγορία"
},
"TYPES": {
"MEDIA": "Media",
"QUICK_REPLY": "Quick Reply",
"TEXT": "Κείμενο"
}
},
"PARSER": {
"VARIABLES_LABEL": "Μεταβλητές",
"LANGUAGE": "Γλώσσα",
"CATEGORY": "Κατηγορία",
"VARIABLE_PLACEHOLDER": "Εισάγετε τιμή για {variable}",
"GO_BACK_LABEL": "Πίσω",
"SEND_MESSAGE_LABEL": "Αποστολή μηνύματος",
"FORM_ERROR_MESSAGE": "Παρακαλώ συμπληρώστε όλες τις μεταβλητές πριν την αποστολή",
"MEDIA_HEADER_LABEL": "{type} Header",
"MEDIA_URL_LABEL": "Enter full media URL",
"MEDIA_URL_PLACEHOLDER": "https://example.com/image.jpg"
},
"FORM": {
"BACK_BUTTON": "Πίσω",
"SEND_MESSAGE_BUTTON": "Αποστολή μηνύματος"
}
}
}
@@ -35,6 +35,11 @@
"API_HOURS_WINDOW": "You can only reply to this conversation within {hours} hours",
"NOT_ASSIGNED_TO_YOU": "Αυτή η συνομιλία δεν έχει ανατεθεί σε εσάς. Θα θέλατε να αντιστοιχίσετε αυτή τη συνομιλία στον εαυτό σας;",
"ASSIGN_TO_ME": "Ανάθεση σε μένα",
"BOT_HANDOFF_MESSAGE": "You are responding to a conversation which is currently handled by an assistant or a bot.",
"BOT_HANDOFF_ACTION": "Mark open and assign to you",
"BOT_HANDOFF_REOPEN_ACTION": "Mark conversation open",
"BOT_HANDOFF_SUCCESS": "Conversation has been handed over to you",
"BOT_HANDOFF_ERROR": "Failed to take over the conversation. Please try again.",
"TWILIO_WHATSAPP_CAN_REPLY": "Μπορείτε να απαντήσετε μόνο σε αυτή τη συνομιλία χρησιμοποιώντας ένα πρότυπο μήνυμα επειδή",
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "του περιορισμού των 24 ωρών",
"OLD_INSTAGRAM_INBOX_REPLY_BANNER": "This Instagram account was migrated to the new Instagram channel inbox. All new messages will show up there. You wont be able to send messages from this conversation anymore.",
@@ -807,6 +807,58 @@
"ERROR_MESSAGE": "Unable to update portal"
}
}
},
"PDF_UPLOAD": {
"TITLE": "Upload PDF Document",
"DESCRIPTION": "Upload a PDF document to automatically generate FAQs using AI",
"DRAG_DROP_TEXT": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"ADDITIONAL_CONTEXT_LABEL": "Additional Context (Optional)",
"ADDITIONAL_CONTEXT_PLACEHOLDER": "Provide any additional context or instructions for FAQ generation...",
"UPLOADING": "Ανέβασμα...",
"UPLOAD": "Upload & Process",
"CANCEL": "Άκυρο",
"ERROR_INVALID_TYPE": "Please select a valid PDF file",
"ERROR_FILE_TOO_LARGE": "File size must be less than 512MB",
"ERROR_UPLOAD_FAILED": "Failed to upload PDF. Please try again."
},
"PDF_DOCUMENTS": {
"TITLE": "PDF Documents",
"DESCRIPTION": "Manage uploaded PDF documents and generate FAQs from them",
"UPLOAD_PDF": "Upload PDF",
"UPLOAD_FIRST_PDF": "Upload your first PDF",
"UPLOADED_BY": "Uploaded by",
"GENERATE_FAQS": "Generate FAQs",
"GENERATING": "Generating...",
"CONFIRM_DELETE": "Are you sure you want to delete {filename}?",
"EMPTY_STATE": {
"TITLE": "No PDF documents yet",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQs using AI"
},
"STATUS": {
"UPLOADED": "Ready",
"PROCESSING": "Processing",
"PROCESSED": "Ολοκληρώθηκε",
"FAILED": "Failed"
}
},
"CONTENT_GENERATION": {
"TITLE": "Content Generation",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQ content using AI",
"UPLOAD_TITLE": "Upload PDF Document",
"DRAG_DROP": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"UPLOADING": "Processing document...",
"UPLOAD_SUCCESS": "Document processed successfully!",
"UPLOAD_ERROR": "Failed to upload document. Please try again.",
"INVALID_FILE_TYPE": "Please select a valid PDF file",
"FILE_TOO_LARGE": "File size must be less than 512MB",
"GENERATED_CONTENT": "Generated FAQ Content",
"PUBLISH_SELECTED": "Publish Selected",
"PUBLISHING": "Publishing...",
"FROM_DOCUMENT": "From document",
"NO_CONTENT": "No generated content available. Upload a PDF document to get started.",
"LOADING": "Loading generated content..."
}
}
}
@@ -424,7 +424,51 @@
},
"AUTH": {
"TITLE": "Επιλογή Καναλιού",
"DESC": "Το Chatwoot υποστηρίζει widget live-chat, σελίδα Facebook, προφίλ Twitter, Whatsapp, Email κλπ., ως κανάλια. Αν θέλετε να δημιουργήσετε ένα προσαρμοσμένο κανάλι, μπορείτε να το δημιουργήσετε χρησιμοποιώντας το κανάλι API. Επιλέξτε ένα κανάλι από τις παρακάτω επιλογές για να συνεχίσετε."
"DESC": "Το Chatwoot υποστηρίζει widget live-chat, σελίδα Facebook, προφίλ Twitter, Whatsapp, Email κλπ., ως κανάλια. Αν θέλετε να δημιουργήσετε ένα προσαρμοσμένο κανάλι, μπορείτε να το δημιουργήσετε χρησιμοποιώντας το κανάλι API. Επιλέξτε ένα κανάλι από τις παρακάτω επιλογές για να συνεχίσετε.",
"TITLE_NEXT": "Complete the setup",
"TITLE_FINISH": "Voilà!",
"CHANNEL": {
"WEBSITE": {
"TITLE": "Website",
"DESCRIPTION": "Create a live-chat widget"
},
"FACEBOOK": {
"TITLE": "Facebook",
"DESCRIPTION": "Connect your Facebook page"
},
"WHATSAPP": {
"TITLE": "WhatsApp",
"DESCRIPTION": "Support your customers on WhatsApp"
},
"EMAIL": {
"TITLE": "Email",
"DESCRIPTION": "Connect with Gmail, Outlook, or other providers"
},
"SMS": {
"TITLE": "SMS",
"DESCRIPTION": "Integrate SMS channel with Twilio or bandwidth"
},
"API": {
"TITLE": "API",
"DESCRIPTION": "Make a custom channel using our API"
},
"TELEGRAM": {
"TITLE": "Telegram",
"DESCRIPTION": "Configure Telegram channel using Bot token"
},
"LINE": {
"TITLE": "Line",
"DESCRIPTION": "Integrate your Line channel"
},
"INSTAGRAM": {
"TITLE": "Instagram",
"DESCRIPTION": "Connect your instagram account"
},
"VOICE": {
"TITLE": "Voice",
"DESCRIPTION": "Integrate with Twilio Voice"
}
}
},
"AGENTS": {
"TITLE": "Πράκτορες",
@@ -478,7 +522,10 @@
"MESSAGE": "Μπορείτε να συνομιλείτε με τους πελάτες σας από το νέο κανάλι. Καλή υποστήριξη",
"BUTTON_TEXT": "Μετάβαση",
"MORE_SETTINGS": "Περισσότερες ρυθμίσεις",
"WEBSITE_SUCCESS": "Επιτυχής δημιουργία του καναλιού ιστοσελίδας. Αντιγράψτε τον κώδικα που παρουσιάζεται παρακάτω, και τοποθετήστε τον στην ιστοσελίδα σας. Την επόμενη φορά που κάποιος πελάτης χρησιμοποιήσει το 'live chat', η συνομιλία θα εμφανιστεί στο κιβώτιο εισερχομένων σας."
"WEBSITE_SUCCESS": "Επιτυχής δημιουργία του καναλιού ιστοσελίδας. Αντιγράψτε τον κώδικα που παρουσιάζεται παρακάτω, και τοποθετήστε τον στην ιστοσελίδα σας. Την επόμενη φορά που κάποιος πελάτης χρησιμοποιήσει το 'live chat', η συνομιλία θα εμφανιστεί στο κιβώτιο εισερχομένων σας.",
"WHATSAPP_QR_INSTRUCTION": "Scan the QR code above to quickly test your WhatsApp inbox",
"MESSENGER_QR_INSTRUCTION": "Scan the QR code above to quickly test your Facebook Messenger inbox",
"TELEGRAM_QR_INSTRUCTION": "Scan the QR code above to quickly test your Telegram inbox"
},
"REAUTH": "Εκ νέου εξουσιοδότηση",
"VIEW": "Προβολή",
@@ -868,9 +915,18 @@
"SCRIPT_SETTINGS": "\n window.chatwootSettings = {options};"
},
"EMAIL_PROVIDERS": {
"MICROSOFT": "Microsoft",
"GOOGLE": "Google",
"OTHER_PROVIDERS": "Other Providers"
"MICROSOFT": {
"TITLE": "Microsoft",
"DESCRIPTION": "Connect with Microsoft"
},
"GOOGLE": {
"TITLE": "Google",
"DESCRIPTION": "Connect with Google"
},
"OTHER_PROVIDERS": {
"TITLE": "Other Providers",
"DESCRIPTION": "Connect with Other Providers"
}
},
"CHANNELS": {
"MESSENGER": "Messenger",
@@ -704,11 +704,28 @@
"ERROR_MESSAGE": "There was an error creating the document, please try again."
},
"FORM": {
"TYPE": {
"LABEL": "Document Type",
"URL": "URL",
"PDF": "PDF File"
},
"URL": {
"LABEL": "URL",
"PLACEHOLDER": "Enter the URL of the document",
"ERROR": "Please provide a valid URL for the document"
},
"PDF_FILE": {
"LABEL": "PDF File",
"CHOOSE_FILE": "Choose PDF file",
"ERROR": "Please select a PDF file",
"HELP_TEXT": "Maximum file size: 10MB",
"INVALID_TYPE": "Please select a valid PDF file",
"TOO_LARGE": "File size exceeds 10MB limit"
},
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
},
"ASSISTANT": {
"LABEL": "Assistant",
"PLACEHOLDER": "Select the assistant",
@@ -48,7 +48,8 @@
"CREATED_AT": "Created At",
"LAST_ACTIVITY": "Last Activity",
"REFERER_LINK": "Referrer link",
"BLOCKED": "Blocked"
"BLOCKED": "Blocked",
"LABELS": "Labels"
},
"GROUPS": {
"STANDARD_FILTERS": "Standard Filters",
@@ -71,6 +71,17 @@
"SHOW_LABELS": "Show labels",
"HIDE_LABELS": "Hide labels"
},
"VOICE_CALL": {
"INCOMING_CALL": "Incoming call",
"OUTGOING_CALL": "Outgoing call",
"CALL_IN_PROGRESS": "Call in progress",
"NO_ANSWER": "No answer",
"MISSED_CALL": "Missed call",
"CALL_ENDED": "Call ended",
"NOT_ANSWERED_YET": "Not answered yet",
"THEY_ANSWERED": "They answered",
"YOU_ANSWERED": "You answered"
},
"HEADER": {
"RESOLVE_ACTION": "Resolve",
"REOPEN_ACTION": "Reopen",
@@ -807,6 +807,58 @@
"ERROR_MESSAGE": "Unable to update portal"
}
}
},
"PDF_UPLOAD": {
"TITLE": "Upload PDF Document",
"DESCRIPTION": "Upload a PDF document to automatically generate FAQs using AI",
"DRAG_DROP_TEXT": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"ADDITIONAL_CONTEXT_LABEL": "Additional Context (Optional)",
"ADDITIONAL_CONTEXT_PLACEHOLDER": "Provide any additional context or instructions for FAQ generation...",
"UPLOADING": "Uploading...",
"UPLOAD": "Upload & Process",
"CANCEL": "Cancel",
"ERROR_INVALID_TYPE": "Please select a valid PDF file",
"ERROR_FILE_TOO_LARGE": "File size must be less than 512MB",
"ERROR_UPLOAD_FAILED": "Failed to upload PDF. Please try again."
},
"PDF_DOCUMENTS": {
"TITLE": "PDF Documents",
"DESCRIPTION": "Manage uploaded PDF documents and generate FAQs from them",
"UPLOAD_PDF": "Upload PDF",
"UPLOAD_FIRST_PDF": "Upload your first PDF",
"UPLOADED_BY": "Uploaded by",
"GENERATE_FAQS": "Generate FAQs",
"GENERATING": "Generating...",
"CONFIRM_DELETE": "Are you sure you want to delete {filename}?",
"EMPTY_STATE": {
"TITLE": "No PDF documents yet",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQs using AI"
},
"STATUS": {
"UPLOADED": "Ready",
"PROCESSING": "Processing",
"PROCESSED": "Completed",
"FAILED": "Failed"
}
},
"CONTENT_GENERATION": {
"TITLE": "Content Generation",
"DESCRIPTION": "Upload PDF documents to automatically generate FAQ content using AI",
"UPLOAD_TITLE": "Upload PDF Document",
"DRAG_DROP": "Drag and drop your PDF file here, or click to select",
"SELECT_FILE": "Select PDF File",
"UPLOADING": "Processing document...",
"UPLOAD_SUCCESS": "Document processed successfully!",
"UPLOAD_ERROR": "Failed to upload document. Please try again.",
"INVALID_FILE_TYPE": "Please select a valid PDF file",
"FILE_TOO_LARGE": "File size must be less than 512MB",
"GENERATED_CONTENT": "Generated FAQ Content",
"PUBLISH_SELECTED": "Publish Selected",
"PUBLISHING": "Publishing...",
"FROM_DOCUMENT": "From document",
"NO_CONTENT": "No generated content available. Upload a PDF document to get started.",
"LOADING": "Loading generated content..."
}
}
}
@@ -424,7 +424,51 @@
},
"AUTH": {
"TITLE": "Choose a channel",
"DESC": "Chatwoot supports live-chat widgets, Facebook Messenger, WhatsApp, Emails, etc., as channels. If you want to build a custom channel, you can create it using the API channel. To get started, choose one of the channels below."
"DESC": "Chatwoot supports live-chat widgets, Facebook Messenger, WhatsApp, Emails, etc., as channels. If you want to build a custom channel, you can create it using the API channel. To get started, choose one of the channels below.",
"TITLE_NEXT": "Complete the setup",
"TITLE_FINISH": "Voilà!",
"CHANNEL": {
"WEBSITE": {
"TITLE": "Website",
"DESCRIPTION": "Create a live-chat widget"
},
"FACEBOOK": {
"TITLE": "Facebook",
"DESCRIPTION": "Connect your Facebook page"
},
"WHATSAPP": {
"TITLE": "WhatsApp",
"DESCRIPTION": "Support your customers on WhatsApp"
},
"EMAIL": {
"TITLE": "Email",
"DESCRIPTION": "Connect with Gmail, Outlook, or other providers"
},
"SMS": {
"TITLE": "SMS",
"DESCRIPTION": "Integrate SMS channel with Twilio or bandwidth"
},
"API": {
"TITLE": "API",
"DESCRIPTION": "Make a custom channel using our API"
},
"TELEGRAM": {
"TITLE": "Telegram",
"DESCRIPTION": "Configure Telegram channel using Bot token"
},
"LINE": {
"TITLE": "Line",
"DESCRIPTION": "Integrate your Line channel"
},
"INSTAGRAM": {
"TITLE": "Instagram",
"DESCRIPTION": "Connect your instagram account"
},
"VOICE": {
"TITLE": "Voice",
"DESCRIPTION": "Integrate with Twilio Voice"
}
}
},
"AGENTS": {
"TITLE": "Agents",
@@ -871,9 +915,18 @@
"SCRIPT_SETTINGS": "\n window.chatwootSettings = {options};"
},
"EMAIL_PROVIDERS": {
"MICROSOFT": "Microsoft",
"GOOGLE": "Google",
"OTHER_PROVIDERS": "Other Providers"
"MICROSOFT": {
"TITLE": "Microsoft",
"DESCRIPTION": "Connect with Microsoft"
},
"GOOGLE": {
"TITLE": "Google",
"DESCRIPTION": "Connect with Google"
},
"OTHER_PROVIDERS": {
"TITLE": "Other Providers",
"DESCRIPTION": "Connect with Other Providers"
}
},
"CHANNELS": {
"MESSENGER": "Messenger",
@@ -701,11 +701,28 @@
"ERROR_MESSAGE": "There was an error creating the document, please try again."
},
"FORM": {
"TYPE": {
"LABEL": "Document Type",
"URL": "URL",
"PDF": "PDF File"
},
"URL": {
"LABEL": "URL",
"PLACEHOLDER": "Enter the URL of the document",
"ERROR": "Please provide a valid URL for the document"
},
"PDF_FILE": {
"LABEL": "PDF File",
"CHOOSE_FILE": "Choose PDF file",
"ERROR": "Please select a PDF file",
"HELP_TEXT": "Maximum file size: 10MB",
"INVALID_TYPE": "Please select a valid PDF file",
"TOO_LARGE": "File size exceeds 10MB limit"
},
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
},
"ASSISTANT": {
"LABEL": "Assistant",
"PLACEHOLDER": "Select the assistant",
@@ -330,6 +330,7 @@
"REPORTS_LABEL": "Labels",
"REPORTS_INBOX": "Inbox",
"REPORTS_TEAM": "Team",
"AGENT_ASSIGNMENT": "Agent Assignment",
"SET_AVAILABILITY_TITLE": "Set yourself as",
"SET_YOUR_AVAILABILITY": "Set your availability",
"SLA": "SLA",
@@ -490,5 +491,31 @@
"SWITCH_TO_REPLY": "Switch to Reply",
"TOGGLE_SNOOZE_DROPDOWN": "Toggle snooze dropdown"
}
},
"ASSIGNMENT_POLICY": {
"INDEX": {
"HEADER": {
"TITLE": "Agent assignment",
"DESCRIPTION": "Define policies to effectively manage workload and route conversations based on the needs of inboxes and agents. Learn more here"
},
"ASSIGNMENT_POLICY": {
"TITLE": "Assignment policy",
"DESCRIPTION": "Manage how conversations get assigned in inboxes.",
"FEATURES": [
"Assign by conversations evenly or by available capacity",
"Add fair distribution rules to avoid overloading any agent",
"Add inboxes to a policy - one policy per inbox"
]
},
"AGENT_CAPACITY_POLICY": {
"TITLE": "Agent capacity policy",
"DESCRIPTION": "Manage workload for agents.",
"FEATURES": [
"Define maximum conversations per inbox",
"Create exceptions based on labels and time",
"Add agents to a policy - one policy per agent"
]
}
}
}
}
@@ -87,11 +87,11 @@
"ERRORS": {
"NAME": "El nombre del bot es obligatorio",
"URL": "Dirección del webhook es requerida",
"VALID_URL": "Please enter a valid URL starting with http:// or https://"
"VALID_URL": "Por favor, introduzca una URL válida comenzando con http:// o https://"
},
"CANCEL": "Cancelar",
"CREATE": "Create Bot",
"UPDATE": "Update Bot"
"CREATE": "Crear Bot",
"UPDATE": "Actualizar Bot"
},
"WEBHOOK": {
"DESCRIPTION": "Configure el webhook del bot para integrarse con sus servicios personalizados. El bot recibirá y procesará eventos de conversaciones y podrá responder a ellos."
@@ -610,6 +610,15 @@
"SEND_MESSAGE": "Enviar mensaje"
}
},
"TWILIO_OPTIONS": {
"LABEL": "Seleccionar plantilla",
"SEARCH_PLACEHOLDER": "Buscar plantillas",
"EMPTY_STATE": "No se encontraron plantillas",
"TEMPLATE_PARSER": {
"BACK": "Volver",
"SEND_MESSAGE": "Enviar mensaje"
}
},
"ACTION_BUTTONS": {
"DISCARD": "Descartar",
"SEND": "Enviar ({keyCode})"

Some files were not shown because too many files have changed in this diff Show More