Merge branch 'release/2.13.0'

This commit is contained in:
Sojan
2023-01-17 18:20:45 +05:30
517 changed files with 5314 additions and 1439 deletions

View File

@@ -35,7 +35,7 @@ REDIS_SENTINELS=
REDIS_SENTINEL_MASTER_NAME=
# By default Chatwoot will pass REDIS_PASSWORD as the password value for sentinels
# Use the following environment variable to customize passwords for sentinels.
# Use the following environment variable to customize passwords for sentinels.
# Use empty string if sentinels are configured with out passwords
# REDIS_SENTINEL_PASSWORD=
@@ -45,7 +45,7 @@ REDIS_SENTINEL_MASTER_NAME=
# REDIS_OPENSSL_VERIFY_MODE=none
# Postgres Database config variables
# You can leave POSTGRES_DATABASE blank. The default name of
# You can leave POSTGRES_DATABASE blank. The default name of
# the database in the production environment is chatwoot_production
# POSTGRES_DATABASE=
POSTGRES_HOST=postgres
@@ -213,3 +213,12 @@ STRIPE_WEBHOOK_SECRET=
# Set to true if you want to upload files to cloud storage using the signed url
# Make sure to follow https://edgeguides.rubyonrails.org/active_storage_overview.html#cross-origin-resource-sharing-cors-configuration on the cloud storage after setting this to true.
DIRECT_UPLOADS_ENABLED=
#MS OAUTH creds
AZURE_APP_ID=
AZURE_APP_SECRET=
## Advanced configurations
## Change these values to fine tune performance
# control the concurrency setting of sidekiq
# SIDEKIQ_CONCURRENCY=10

View File

@@ -37,6 +37,8 @@ gem 'json_schemer'
gem 'rack-attack'
# a utility tool for streaming, flexible and safe downloading of remote files
gem 'down', '~> 5.0'
# authentication type to fetch and send mail over oauth2.0
gem 'gmail_xoauth'
##-- for active storage --##
gem 'aws-sdk-s3', require: false
@@ -160,6 +162,8 @@ group :test do
gem 'database_cleaner'
# mock http calls
gem 'webmock'
# test profiling
gem 'test-prof'
end
group :development, :test do
@@ -186,3 +190,5 @@ group :development, :test do
gem 'spring'
gem 'spring-watcher-listen'
end
# worked with microsoft refresh token
gem 'omniauth-oauth2'

View File

@@ -249,6 +249,8 @@ GEM
gli (2.21.0)
globalid (1.0.0)
activesupport (>= 5.0)
gmail_xoauth (0.4.2)
oauth (>= 0.3.6)
google-apis-core (0.7.0)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
@@ -333,8 +335,8 @@ GEM
http-cookie (1.0.5)
domain_name (~> 0.5)
http-form_data (2.3.0)
httparty (0.20.0)
mime-types (~> 3.0)
httparty (0.21.0)
mini_mime (>= 1.0.0)
multi_xml (>= 0.5.2)
httpclient (2.8.3)
i18n (1.11.0)
@@ -437,6 +439,20 @@ GEM
nokogiri (1.13.10-x86_64-linux)
racc (~> 1.4)
oauth (0.5.10)
oauth2 (2.0.9)
faraday (>= 0.17.3, < 3.0)
jwt (>= 1.0, < 3.0)
multi_xml (~> 0.5)
rack (>= 1.2, < 4)
snaky_hash (~> 2.0)
version_gem (~> 1.1)
omniauth (2.1.0)
hashie (>= 3.4.6)
rack (>= 2.2.3)
rack-protection
omniauth-oauth2 (1.8.0)
oauth2 (>= 1.4, < 3)
omniauth (~> 2.0)
orm_adapter (0.5.0)
os (1.1.4)
parallel (1.22.1)
@@ -465,6 +481,8 @@ GEM
rack (>= 1.0, < 3)
rack-cors (1.1.1)
rack (>= 2.0.0)
rack-protection (3.0.5)
rack
rack-proxy (0.7.2)
rack
rack-test (2.0.2)
@@ -620,6 +638,9 @@ GEM
gli
hashie
websocket-driver
snaky_hash (2.0.1)
hashie
version_gem (~> 1.1, >= 1.1.1)
spring (2.1.1)
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
@@ -635,6 +656,7 @@ GEM
statsd-ruby (1.5.0)
stripe (6.5.0)
telephone_number (1.4.16)
test-prof (1.0.11)
thor (1.2.1)
tilt (2.0.10)
time_diff (0.3.0)
@@ -663,6 +685,7 @@ GEM
valid_email2 (4.0.3)
activemodel (>= 3.2)
mail (~> 2.5)
version_gem (1.1.1)
warden (1.2.9)
rack (>= 2.0.9)
web-console (4.2.0)
@@ -735,6 +758,7 @@ DEPENDENCIES
flag_shih_tzu
foreman
geocoder
gmail_xoauth
google-cloud-dialogflow
google-cloud-storage
groupdate
@@ -756,6 +780,7 @@ DEPENDENCIES
maxminddb
mock_redis
newrelic_rpm
omniauth-oauth2
pg
pg_search
procore-sift
@@ -791,6 +816,7 @@ DEPENDENCIES
squasher
stripe
telephone_number
test-prof
time_diff
twilio-ruby (~> 5.66)
twitty

View File

@@ -1,3 +1,4 @@
backend: bin/rails s -p 3000
frontend: bin/webpack-dev-server
worker: bundle exec sidekiq -C config/sidekiq.yml
# https://github.com/mperham/sidekiq/issues/3090#issuecomment-389748695
worker: dotenv bundle exec sidekiq -C config/sidekiq.yml

View File

@@ -1,3 +1,3 @@
backend: RAILS_ENV=test bin/rails s -p 5050
frontend: bin/webpack-dev-server
worker: RAILS_ENV=test bundle exec sidekiq -C config/sidekiq.yml
worker: dotenv RAILS_ENV=test bundle exec sidekiq -C config/sidekiq.yml

View File

@@ -119,4 +119,4 @@ Thanks goes to all these [wonderful people](https://www.chatwoot.com/docs/contri
<a href="https://github.com/chatwoot/chatwoot/graphs/contributors"><img src="https://opencollective.com/chatwoot/contributors.svg?width=890&button=false" /></a>
*Chatwoot* &copy; 2017-2022, Chatwoot Inc - Released under the MIT License.
*Chatwoot* &copy; 2017-2023, Chatwoot Inc - Released under the MIT License.

View File

@@ -0,0 +1,48 @@
class Api::V1::Accounts::Integrations::DyteController < Api::V1::Accounts::BaseController
before_action :fetch_conversation, only: [:create_a_meeting]
before_action :fetch_message, only: [:add_participant_to_meeting]
before_action :authorize_request
def create_a_meeting
render_response(dyte_processor_service.create_a_meeting(Current.user))
end
def add_participant_to_meeting
if @message.content_type != 'integrations'
return render json: {
error: I18n.t('errors.dyte.invalid_message_type')
}, status: :unprocessable_entity
end
render_response(
dyte_processor_service.add_participant_to_meeting(@message.content_attributes['data']['meeting_id'], Current.user)
)
end
private
def authorize_request
authorize @conversation.inbox, :show?
end
def render_response(response)
render json: response, status: response[:error].blank? ? :ok : :unprocessable_entity
end
def dyte_processor_service
Integrations::Dyte::ProcessorService.new(account: Current.account, conversation: @conversation)
end
def permitted_params
params.permit(:conversation_id, :message_id)
end
def fetch_conversation
@conversation = Current.account.conversations.find_by!(display_id: permitted_params[:conversation_id])
end
def fetch_message
@message = Current.account.messages.find(permitted_params[:message_id])
@conversation = @message.conversation
end
end

View File

@@ -0,0 +1,27 @@
class Api::V1::Accounts::Microsoft::AuthorizationsController < Api::V1::Accounts::BaseController
include MicrosoftConcern
before_action :check_authorization
def create
email = params[:authorization][:email]
redirect_url = microsoft_client.auth_code.authorize_url(
{
redirect_uri: "#{base_url}/microsoft/callback",
scope: 'offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send openid',
prompt: 'consent'
}
)
if redirect_url
::Redis::Alfred.setex(email, Current.account.id, 5.minutes)
render json: { success: true, url: redirect_url }
else
render json: { success: false }, status: :unprocessable_entity
end
end
private
def check_authorization
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
end
end

View File

@@ -0,0 +1,36 @@
class Api::V1::Widget::Integrations::DyteController < Api::V1::Widget::BaseController
before_action :set_message
def add_participant_to_meeting
if @message.content_type != 'integrations'
return render json: {
error: I18n.t('errors.dyte.invalid_message_type')
}, status: :unprocessable_entity
end
response = dyte_processor_service.add_participant_to_meeting(
@message.content_attributes['data']['meeting_id'],
@conversation.contact
)
render_response(response)
end
private
def render_response(response)
render json: response, status: response[:error].blank? ? :ok : :unprocessable_entity
end
def dyte_processor_service
Integrations::Dyte::ProcessorService.new(account: @web_widget.inbox.account, conversation: @conversation)
end
def set_message
@message = @web_widget.inbox.messages.find(permitted_params[:message_id])
@conversation = @message.conversation
end
def permitted_params
params.permit(:website_token, :message_id)
end
end

View File

@@ -0,0 +1,22 @@
module MicrosoftConcern
extend ActiveSupport::Concern
def microsoft_client
::OAuth2::Client.new(ENV.fetch('AZURE_APP_ID', nil), ENV.fetch('AZURE_APP_SECRET', nil),
{
site: 'https://login.microsoftonline.com',
authorize_url: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
token_url: 'https://login.microsoftonline.com/common/oauth2/v2.0/token'
})
end
private
def parsed_body
@parsed_body ||= Rack::Utils.parse_nested_query(@response.raw_response.body)
end
def base_url
ENV.fetch('FRONTEND_URL', 'http://localhost:3000')
end
end

View File

@@ -55,7 +55,8 @@ class DashboardController < ActionController::Base
ENABLE_ACCOUNT_SIGNUP: GlobalConfigService.load('ENABLE_ACCOUNT_SIGNUP', 'false'),
FB_APP_ID: GlobalConfigService.load('FB_APP_ID', ''),
FACEBOOK_API_VERSION: 'v14.0',
IS_ENTERPRISE: ChatwootApp.enterprise?
IS_ENTERPRISE: ChatwootApp.enterprise?,
AZURE_APP_ID: ENV.fetch('AZURE_APP_ID', '')
}
end
end

View File

@@ -0,0 +1,72 @@
class Microsoft::CallbacksController < ApplicationController
include MicrosoftConcern
def show
@response = microsoft_client.auth_code.get_token(
oauth_code,
redirect_uri: "#{base_url}/microsoft/callback"
)
inbox = find_or_create_inbox
::Redis::Alfred.delete(users_data['email'])
redirect_to app_microsoft_inbox_agents_url(account_id: account.id, inbox_id: inbox.id)
rescue StandardError => e
ChatwootExceptionTracker.new(e).capture_exception
redirect_to '/'
end
private
def oauth_code
params[:code]
end
def users_data
decoded_token = JWT.decode parsed_body[:id_token], nil, false
decoded_token[0]
end
def parsed_body
@parsed_body ||= @response.response.parsed
end
def account_id
::Redis::Alfred.get(users_data['email'])
end
def account
@account ||= Account.find(account_id)
end
def find_or_create_inbox
channel_email = Channel::Email.find_by(email: users_data['email'], account: account)
channel_email ||= create_microsoft_channel_with_inbox
update_microsoft_channel(channel_email)
channel_email.inbox
end
def create_microsoft_channel_with_inbox
ActiveRecord::Base.transaction do
channel_email = Channel::Email.create!(email: users_data['email'], account: account)
account.inboxes.create!(
account: account,
channel: channel_email,
name: users_data['name']
)
channel_email
end
end
def update_microsoft_channel(channel_email)
channel_email.update!({
imap_login: users_data['email'], imap_address: 'outlook.office365.com',
imap_port: '993', imap_enabled: true,
provider: 'microsoft',
provider_config: {
access_token: parsed_body['access_token'],
refresh_token: parsed_body['refresh_token'],
expires_on: (Time.current.utc + 1.hour).to_s
}
})
end
end

View File

@@ -11,8 +11,8 @@ class SwaggerController < ApplicationController
def derived_path
params[:path] ||= 'index.html'
path = params[:path]
path << ".#{params[:format]}" unless path.ends_with?(params[:format].to_s)
path = Rack::Utils.clean_path_info(params[:path])
path << ".#{Rack::Utils.clean_path_info(params[:format])}" unless path.ends_with?(params[:format].to_s)
path
end
end

17
app/drops/contact_drop.rb Normal file
View File

@@ -0,0 +1,17 @@
class ContactDrop < BaseDrop
def email
@obj.try(:email)
end
def phone_number
@obj.try(:phone_number)
end
def first_name
@obj.try(:name).try(:split).try(:first)
end
def last_name
@obj.try(:name).try(:split).try(:last) if @obj.try(:name).try(:split).try(:size) > 1
end
end

View File

@@ -2,4 +2,12 @@ class UserDrop < BaseDrop
def available_name
@obj.try(:available_name)
end
def first_name
@obj.try(:name).try(:split).try(:first)
end
def last_name
@obj.try(:name).try(:split).try(:last) if @obj.try(:name).try(:split).try(:size) > 1
end
end

View File

@@ -0,0 +1,14 @@
/* global axios */
import ApiClient from '../ApiClient';
class MicrosoftClient extends ApiClient {
constructor() {
super('microsoft', { accountScoped: true });
}
generateAuthorization(payload) {
return axios.post(`${this.url}/authorization`, payload);
}
}
export default new MicrosoftClient();

View File

@@ -0,0 +1,23 @@
/* global axios */
import ApiClient from '../ApiClient';
class DyteAPI extends ApiClient {
constructor() {
super('integrations/dyte', { accountScoped: true });
}
createAMeeting(conversationId) {
return axios.post(`${this.url}/create_a_meeting`, {
conversation_id: conversationId,
});
}
addParticipantToMeeting(messageId) {
return axios.post(`${this.url}/add_participant_to_meeting`, {
message_id: messageId,
});
}
}
export default new DyteAPI();

View File

@@ -0,0 +1,35 @@
import DyteAPIClient from '../../integrations/dyte';
import ApiClient from '../../ApiClient';
import describeWithAPIMock from '../apiSpecHelper';
describe('#accountAPI', () => {
it('creates correct instance', () => {
expect(DyteAPIClient).toBeInstanceOf(ApiClient);
expect(DyteAPIClient).toHaveProperty('createAMeeting');
expect(DyteAPIClient).toHaveProperty('addParticipantToMeeting');
});
describeWithAPIMock('createAMeeting', context => {
it('creates a valid request', () => {
DyteAPIClient.createAMeeting(1);
expect(context.axiosMock.post).toHaveBeenCalledWith(
'/api/v1/integrations/dyte/create_a_meeting',
{
conversation_id: 1,
}
);
});
});
describeWithAPIMock('addParticipantToMeeting', context => {
it('creates a valid request', () => {
DyteAPIClient.addParticipantToMeeting(1);
expect(context.axiosMock.post).toHaveBeenCalledWith(
'/api/v1/integrations/dyte/add_participant_to_meeting',
{
message_id: 1,
}
);
});
});
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -75,7 +75,7 @@ Arial,
sans-serif;
$body-antialiased: true;
$global-margin: $space-small;
$global-padding: $space-micro;
$global-padding: $space-small;
$global-weight-normal: normal;
$global-weight-bold: bold;
$global-radius: 0;

View File

@@ -37,7 +37,6 @@
@include foundation-prototype-sizing;
@include foundation-prototype-spacing;
@import 'typography';
@import 'layout';
@import 'animations';
@@ -61,7 +60,6 @@
@import 'widgets/woot-tables';
@import 'views/settings/inbox';
@import 'views/settings/channel';
@import 'views/settings/integrations';
@import 'plugins/multiselect';

View File

@@ -1,52 +0,0 @@
$channel-hover-color: rgba(0, 0, 0, 0.1);
.channels {
margin-top: $space-medium;
.inactive {
filter: grayscale(100%);
}
.channel {
@include flex;
@include background-white;
@include border-light;
cursor: pointer;
flex-direction: column;
margin: -1px;
padding: $space-normal $zero;
transition: all 0.2s ease-in;
&:last-child {
@include border-light;
}
&:hover {
border: 1px solid $primary-color;
box-shadow: 0 2px 8px $channel-hover-color;
z-index: 999;
}
&.disabled {
opacity: 0.6;
}
img {
margin: $space-normal auto;
width: 50%;
}
.channel__title {
color: $color-body;
font-size: var(--font-size-default);
text-align: center;
text-transform: capitalize;
}
p {
color: $medium-gray;
width: 100%;
}
}
}

View File

@@ -42,7 +42,6 @@ $resolve-button-width: 13.2rem;
margin-right: var(--space-normal);
min-width: 0;
.user--profile__meta {
align-items: flex-start;
display: flex;
@@ -54,13 +53,17 @@ $resolve-button-width: 13.2rem;
}
}
.header-actions-wrap {
align-items: center;
display: flex;
flex-direction: row;
flex-grow: 1;
justify-content: flex-end;
margin-top: var(--space-small);
@include breakpoint(medium up) {
margin-top: 0;
}
&.has-open-sidebar {
justify-content: flex-end;

View File

@@ -81,8 +81,12 @@
}
.conversations-list {
@include scroll-on-hover;
overflow-y: auto;
flex: 1 1;
@include breakpoint(large up) {
@include scroll-on-hover;
}
}
.chat-list__top {
@@ -324,6 +328,7 @@
var(--space-one);
.is-text {
align-items: center;
display: inline-flex;
text-align: start;

View File

@@ -82,8 +82,8 @@
@include flex-align($x: flex-end, $y: middle);
padding: $space-small $zero;
button {
font-size: $font-size-small;
.button {
margin-left: var(--space-small);
}
&.justify-content-end {

View File

@@ -0,0 +1,67 @@
<template>
<button class="small-6 medium-4 large-3 channel" @click="$emit('click')">
<img :src="src" :alt="title" />
<h3 class="channel__title">
{{ title }}
</h3>
</button>
</template>
<script>
export default {
props: {
title: {
type: String,
required: true,
},
src: {
type: String,
required: true,
},
},
};
</script>
<style scoped lang="scss">
.inactive {
filter: grayscale(100%);
}
.channel {
background: var(--white);
border: 1px solid var(--color-border-light);
cursor: pointer;
display: flex;
flex-direction: column;
margin: -1px;
padding: var(--space-normal) 0;
transition: all 0.2s ease-in;
align-items: center;
&:hover {
border: 1px solid var(--w-500);
box-shadow: var(--shadow-medium);
z-index: var(--z-index-high);
}
&.disabled {
opacity: 0.6;
}
img {
margin: var(--space-normal) auto;
width: 50%;
}
.channel__title {
color: var(--color-body);
font-size: var(--font-size-default);
text-align: center;
text-transform: capitalize;
}
p {
color: var(--b-500);
width: 100%;
}
}
</style>

View File

@@ -794,30 +794,15 @@ export default {
.conversations-list-wrap {
flex-shrink: 0;
width: 34rem;
flex-basis: clamp(32rem, 4vw + 34rem, 44rem);
overflow: hidden;
@include breakpoint(large up) {
width: 36rem;
}
@include breakpoint(xlarge up) {
width: 35rem;
}
@include breakpoint(xxlarge up) {
width: 38rem;
}
@include breakpoint(xxxlarge up) {
flex-basis: 46rem;
}
&.hide {
display: none;
}
&.list--full-width {
width: 100%;
@include breakpoint(xxxlarge up) {
flex-basis: 100%;
}
flex-basis: 100%;
}
}
.filter--actions {

View File

@@ -39,6 +39,8 @@ export default {
<style scoped lang="scss">
.wrap-content {
word-wrap: break-word;
margin-top: var(--space-small);
.content-value {
font-weight: var(--font-weight-bold);
}

View File

@@ -233,9 +233,6 @@ export default {
width: 40rem;
}
}
.off-canvas-content.is-open-left {
transform: translateX(18.8rem);
}
.secondary-sidebar {
overflow-y: auto;

View File

@@ -88,9 +88,9 @@
v-model="action_params"
:teams="dropdownValues"
/>
<textarea
<woot-message-editor
v-if="inputType === 'textarea'"
v-model="action_params"
v-model="castMessageVmodel"
rows="4"
:placeholder="$t('AUTOMATION.ACTION.TEAM_MESSAGE_INPUT_PLACEHOLDER')"
class="action-message"
@@ -107,10 +107,12 @@
<script>
import AutomationActionTeamMessageInput from './AutomationActionTeamMessageInput.vue';
import AutomationActionFileInput from './AutomationFileInput.vue';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor';
export default {
components: {
AutomationActionTeamMessageInput,
AutomationActionFileInput,
WootMessageEditor,
},
props: {
value: {
@@ -173,6 +175,17 @@ export default {
'is-a-macro': this.isMacro,
};
},
castMessageVmodel: {
get() {
if (Array.isArray(this.action_params)) {
return this.action_params[0];
}
return this.action_params;
},
set(value) {
this.action_params = value;
},
},
},
methods: {
removeAction() {
@@ -281,4 +294,8 @@ export default {
.action-message {
margin: var(--space-small) var(--space-zero) var(--space-zero);
}
// Prosemirror does not have a native way of hiding the menu bar, hence
::v-deep .ProseMirror-menubar {
display: none;
}
</style>

View File

@@ -1,56 +1,15 @@
<template>
<div
class="small-6 medium-4 large-3 columns channel"
<channel-selector
:class="{ inactive: !isActive }"
:title="channel.name"
:src="getChannelThumbnail()"
@click="onItemClick"
>
<img
v-if="channel.key === 'facebook'"
src="~dashboard/assets/images/channels/messenger.png"
/>
<img
v-if="channel.key === 'twitter'"
src="~dashboard/assets/images/channels/twitter.png"
/>
<img
v-if="channel.key === 'telegram'"
src="~dashboard/assets/images/channels/telegram.png"
/>
<img
v-if="channel.key === 'api' && !channel.thumbnail"
src="~dashboard/assets/images/channels/api.png"
/>
<img
v-if="channel.key === 'api' && channel.thumbnail"
:src="channel.thumbnail"
/>
<img
v-if="channel.key === 'email'"
src="~dashboard/assets/images/channels/email.png"
/>
<img
v-if="channel.key === 'line'"
src="~dashboard/assets/images/channels/line.png"
/>
<img
v-if="channel.key === 'website'"
src="~dashboard/assets/images/channels/website.png"
/>
<img
v-if="channel.key === 'sms'"
src="~dashboard/assets/images/channels/sms.png"
/>
<img
v-if="channel.key === 'whatsapp'"
src="~dashboard/assets/images/channels/whatsapp.png"
/>
<h3 class="channel__title">
{{ channel.name }}
</h3>
</div>
/>
</template>
<script>
import ChannelSelector from '../ChannelSelector';
export default {
components: { ChannelSelector },
props: {
channel: {
type: Object,
@@ -92,6 +51,12 @@ export default {
},
},
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('channel-item-click', this.channel.key);

View File

@@ -0,0 +1,57 @@
<template>
<woot-button
v-if="isVideoIntegrationEnabled"
v-tooltip.top-end="
$t('INTEGRATION_SETTINGS.DYTE.START_VIDEO_CALL_HELP_TEXT')
"
icon="video"
:is-loading="isLoading"
color-scheme="secondary"
variant="smooth"
size="small"
@click="onClick"
/>
</template>
<script>
import { mapGetters } from 'vuex';
import DyteAPI from 'dashboard/api/integrations/dyte';
import alertMixin from 'shared/mixins/alertMixin';
export default {
mixins: [alertMixin],
props: {
conversationId: {
type: Number,
default: 0,
},
},
data() {
return { isLoading: false };
},
computed: {
...mapGetters({ appIntegrations: 'integrations/getAppIntegrations' }),
isVideoIntegrationEnabled() {
return this.appIntegrations.find(
integration => integration.id === 'dyte' && !!integration.hooks.length
);
},
},
mounted() {
if (!this.appIntegrations.length) {
this.$store.dispatch('integrations/get');
}
},
methods: {
async onClick() {
this.isLoading = true;
try {
await DyteAPI.createAMeeting(this.conversationId);
} catch (error) {
this.showAlert(this.$t('INTEGRATION_SETTINGS.DYTE.CREATE_ERROR'));
} finally {
this.isLoading = false;
}
},
},
};
</script>

View File

@@ -15,29 +15,25 @@
</template>
<script>
import { EditorView } from 'prosemirror-view';
import { defaultMarkdownSerializer } from 'prosemirror-markdown';
import {
addMentionsToMarkdownSerializer,
addMentionsToMarkdownParser,
schemaWithMentions,
} from '@chatwoot/prosemirror-schema/src/mentions/schema';
messageSchema,
wootMessageWriterSetup,
EditorView,
MessageMarkdownTransformer,
MessageMarkdownSerializer,
EditorState,
Selection,
} from '@chatwoot/prosemirror-schema';
import {
suggestionsPlugin,
triggerCharacters,
} from '@chatwoot/prosemirror-schema/src/mentions/plugin';
import { EditorState, Selection } from 'prosemirror-state';
import { defaultMarkdownParser } from 'prosemirror-markdown';
import { wootWriterSetup } from '@chatwoot/prosemirror-schema';
import TagAgents from '../conversation/TagAgents';
import CannedResponse from '../conversation/CannedResponse';
const TYPING_INDICATOR_IDLE_TIME = 4000;
import '@chatwoot/prosemirror-schema/src/woot-editor.css';
import {
hasPressedEnterAndNotCmdOrShift,
hasPressedCommandAndEnter,
@@ -53,9 +49,9 @@ import AnalyticsHelper, {
const createState = (content, placeholder, plugins = []) => {
return EditorState.create({
doc: addMentionsToMarkdownParser(defaultMarkdownParser).parse(content),
plugins: wootWriterSetup({
schema: schemaWithMentions,
doc: new MessageMarkdownTransformer(messageSchema).parse(content),
plugins: wootMessageWriterSetup({
schema: messageSchema,
placeholder,
plugins,
}),
@@ -88,9 +84,7 @@ export default {
},
computed: {
contentFromEditor() {
return addMentionsToMarkdownSerializer(
defaultMarkdownSerializer
).serialize(this.editorView.state.doc);
return MessageMarkdownSerializer.serialize(this.editorView.state.doc);
},
plugins() {
if (!this.enableSuggestions) {
@@ -282,11 +276,11 @@ export default {
}
let from = this.range.from - 1;
let node = addMentionsToMarkdownParser(defaultMarkdownParser).parse(
let node = new MessageMarkdownTransformer(messageSchema).parse(
cannedItem
);
if (node.childCount === 1) {
if (node.textContent === cannedItem) {
node = this.editorView.state.schema.text(cannedItem);
from = this.range.from;
}
@@ -372,10 +366,18 @@ export default {
</script>
<style lang="scss">
@import '~@chatwoot/prosemirror-schema/src/styles/base.scss';
.ProseMirror-menubar-wrapper {
display: flex;
flex-direction: column;
.ProseMirror-menubar {
min-height: var(--space-two) !important;
margin-left: var(--space-minus-one);
padding-bottom: 0;
}
> .ProseMirror {
padding: 0;
word-break: break-word;
@@ -384,6 +386,7 @@ export default {
.editor-root {
width: 100%;
position: relative;
}
.ProseMirror-woot-style {
@@ -406,6 +409,9 @@ export default {
color: var(--s-900);
padding: 0 var(--space-smaller);
}
.ProseMirror-menubar {
background: var(--y-50);
}
}
.editor-wrap {

View File

@@ -0,0 +1,167 @@
<template>
<div>
<div class="editor-root editor--article">
<div ref="editor" />
</div>
</div>
</template>
<script>
import {
fullSchema,
wootArticleWriterSetup,
EditorView,
ArticleMarkdownSerializer,
ArticleMarkdownTransformer,
EditorState,
Selection,
} from '@chatwoot/prosemirror-schema';
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
const createState = (content, placeholder, plugins = []) => {
return EditorState.create({
doc: new ArticleMarkdownTransformer(fullSchema).parse(content),
plugins: wootArticleWriterSetup({
schema: fullSchema,
placeholder,
plugins,
}),
});
};
export default {
mixins: [eventListenerMixins, uiSettingsMixin],
props: {
value: { type: String, default: '' },
editorId: { type: String, default: '' },
placeholder: { type: String, default: '' },
},
data() {
return {
editorView: null,
state: undefined,
plugins: [],
};
},
computed: {
contentFromEditor() {
if (this.editorView) {
return ArticleMarkdownSerializer.serialize(this.editorView.state.doc);
}
return '';
},
},
watch: {
value(newValue = '') {
if (newValue !== this.contentFromEditor) {
this.reloadState();
}
},
editorId() {
this.reloadState();
},
},
created() {
this.state = createState(this.value, this.placeholder, this.plugins);
},
mounted() {
this.createEditorView();
this.editorView.updateState(this.state);
this.focusEditorInputField();
},
methods: {
reloadState() {
this.state = createState(this.value, this.placeholder, this.plugins);
this.editorView.updateState(this.state);
this.focusEditorInputField();
},
createEditorView() {
this.editorView = new EditorView(this.$refs.editor, {
state: this.state,
dispatchTransaction: tx => {
this.state = this.state.apply(tx);
this.emitOnChange();
},
handleDOMEvents: {
keyup: () => {
this.onKeyup();
},
keydown: (view, event) => {
this.onKeydown(event);
},
focus: () => {
this.onFocus();
},
blur: () => {
this.onBlur();
},
},
});
},
handleKeyEvents() {},
focusEditorInputField() {
const { tr } = this.editorView.state;
const selection = Selection.atEnd(tr.doc);
this.editorView.dispatch(tr.setSelection(selection));
this.editorView.focus();
},
emitOnChange() {
this.editorView.updateState(this.state);
this.$emit('input', this.contentFromEditor);
},
onKeyup() {
this.$emit('keyup');
},
onKeydown() {
this.$emit('keydown');
},
onBlur() {
this.$emit('blur');
},
onFocus() {
this.$emit('focus');
},
},
};
</script>
<style lang="scss">
@import '~@chatwoot/prosemirror-schema/src/styles/article.scss';
.ProseMirror-menubar-wrapper {
display: flex;
flex-direction: column;
> .ProseMirror {
padding: 0;
word-break: break-word;
}
}
.editor-root {
width: 100%;
}
.ProseMirror-woot-style {
min-height: 8rem;
max-height: 12rem;
overflow: auto;
}
.ProseMirror-prompt {
z-index: var(--z-index-highest);
background: var(--white);
box-shadow: var(--shadow-large);
border-radius: var(--border-radius-normal);
border: 1px solid var(--color-border);
min-width: 40rem;
}
</style>

View File

@@ -87,6 +87,10 @@
:title="'Whatsapp Templates'"
@click="$emit('selectWhatsappTemplate')"
/>
<video-call-button
v-if="(isAWebWidgetInbox || isAPIInbox) && !isOnPrivateNote"
:conversation-id="conversationId"
/>
<transition name="modal-fade">
<div
v-show="$refs.upload && $refs.upload.dropActive"
@@ -124,13 +128,13 @@ import {
ALLOWED_FILE_TYPES,
ALLOWED_FILE_TYPES_FOR_TWILIO_WHATSAPP,
} from 'shared/constants/messages';
import VideoCallButton from '../VideoCallButton';
import { REPLY_EDITOR_MODES } from './constants';
import { mapGetters } from 'vuex';
export default {
name: 'ReplyBottomPanel',
components: { FileUpload },
components: { FileUpload, VideoCallButton },
mixins: [eventListenerMixins, uiSettingsMixin, inboxMixin],
props: {
mode: {
@@ -209,6 +213,10 @@ export default {
type: Boolean,
default: false,
},
conversationId: {
type: Number,
required: true,
},
},
computed: {
...mapGetters({
@@ -269,7 +277,7 @@ export default {
}
},
showMessageSignatureButton() {
return !this.isPrivate && this.isAnEmailChannel;
return !this.isOnPrivateNote && this.isAnEmailChannel;
},
sendWithSignature() {
const { send_with_signature: isEnabled } = this.uiSettings;

View File

@@ -166,10 +166,14 @@ export default {
.conversation-sidebar-wrap {
height: auto;
flex: 0 0;
overflow: hidden;
z-index: var(--z-index-low);
overflow: auto;
background: white;
flex-basis: 28rem;
flex-basis: 100%;
@include breakpoint(medium up) {
flex-basis: 28rem;
}
@include breakpoint(large up) {
flex-basis: 30em;

View File

@@ -1,53 +1,54 @@
<template>
<div class="conv-header">
<div class="user">
<back-button v-if="showBackButton" :back-url="backButtonUrl" />
<Thumbnail
:src="currentContact.thumbnail"
size="40px"
:badge="inboxBadge"
:username="currentContact.name"
:status="currentContact.availability_status"
/>
<div class="user--profile__meta">
<h3 class="user--name text-truncate">
<span class="margin-right-smaller">{{ currentContact.name }}</span>
<fluent-icon
v-if="!isHMACVerified"
v-tooltip="$t('CONVERSATION.UNVERIFIED_SESSION')"
size="14"
class="hmac-warning__icon"
icon="warning"
/>
</h3>
<div class="conversation--header--actions">
<inbox-name
v-if="hasMultipleInboxes"
:inbox="inbox"
class="margin-right-small"
/>
<span
v-if="isSnoozed"
class="snoozed--display-text margin-right-small"
>
{{ snoozedDisplayText }}
</span>
<woot-button
class="user--profile__button margin-right-small"
size="small"
variant="link"
@click="$emit('contact-panel-toggle')"
>
{{ contactPanelToggleText }}
</woot-button>
<div class="conversation-header--details">
<div class="user">
<back-button v-if="showBackButton" :back-url="backButtonUrl" />
<Thumbnail
:src="currentContact.thumbnail"
:badge="inboxBadge"
:username="currentContact.name"
:status="currentContact.availability_status"
/>
<div class="user--profile__meta">
<h3 class="user--name text-truncate">
<span class="margin-right-smaller">{{ currentContact.name }}</span>
<fluent-icon
v-if="!isHMACVerified"
v-tooltip="$t('CONVERSATION.UNVERIFIED_SESSION')"
size="14"
class="hmac-warning__icon"
icon="warning"
/>
</h3>
<div class="conversation--header--actions text-truncate">
<inbox-name
v-if="hasMultipleInboxes"
:inbox="inbox"
class="margin-right-small"
/>
<span
v-if="isSnoozed"
class="snoozed--display-text margin-right-small"
>
{{ snoozedDisplayText }}
</span>
<woot-button
class="user--profile__button margin-right-small"
size="small"
variant="link"
@click="$emit('contact-panel-toggle')"
>
{{ contactPanelToggleText }}
</woot-button>
</div>
</div>
</div>
</div>
<div
class="header-actions-wrap"
:class="{ 'has-open-sidebar': isContactPanelOpen }"
>
<more-actions :conversation-id="currentChat.id" />
<div
class="header-actions-wrap"
:class="{ 'has-open-sidebar': isContactPanelOpen }"
>
<more-actions :conversation-id="currentChat.id" />
</div>
</div>
</div>
</template>
@@ -165,14 +166,27 @@ export default {
</script>
<style lang="scss" scoped>
.text-truncate {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
@import '~dashboard/assets/scss/woot';
.conv-header {
flex: 0 0 var(--space-jumbo);
flex-direction: row;
@include breakpoint(medium up) {
flex-direction: column;
}
}
.conversation-header--details {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
width: 100%;
@include breakpoint(medium up) {
flex-direction: row;
}
}
.option__desc {

View File

@@ -1,8 +1,5 @@
<template>
<li
v-if="hasAttachments || data.content || isEmailContentType"
:class="alignBubble"
>
<li v-if="shouldRenderMessage" :class="alignBubble">
<div :class="wrapClass">
<div v-tooltip.top-start="messageToolTip" :class="bubbleClass">
<bubble-mail-head
@@ -17,6 +14,11 @@
:is-email="isEmailContentType"
:display-quoted-button="displayQuotedButton"
/>
<bubble-integration
:message-id="data.id"
:content-attributes="contentAttributes"
:inbox-id="data.inbox_id"
/>
<span
v-if="isPending && hasAttachments"
class="chat-bubble has-attachment agent"
@@ -111,14 +113,14 @@
</template>
<script>
import messageFormatterMixin from 'shared/mixins/messageFormatterMixin';
import BubbleActions from './bubble/Actions';
import BubbleFile from './bubble/File';
import BubbleImage from './bubble/Image';
import BubbleIntegration from './bubble/Integration.vue';
import BubbleLocation from './bubble/Location';
import BubbleMailHead from './bubble/MailHead';
import BubbleText from './bubble/Text';
import BubbleImage from './bubble/Image';
import BubbleFile from './bubble/File';
import BubbleVideo from './bubble/Video.vue';
import BubbleActions from './bubble/Actions';
import BubbleLocation from './bubble/Location';
import Spinner from 'shared/components/Spinner';
import ContextMenu from 'dashboard/modules/conversations/components/MessageContextMenu';
@@ -130,12 +132,13 @@ import { generateBotMessageContent } from './helpers/botMessageContentHelper';
export default {
components: {
BubbleActions,
BubbleText,
BubbleImage,
BubbleFile,
BubbleVideo,
BubbleMailHead,
BubbleImage,
BubbleIntegration,
BubbleLocation,
BubbleMailHead,
BubbleText,
BubbleVideo,
ContextMenu,
Spinner,
},
@@ -169,6 +172,14 @@ export default {
};
},
computed: {
shouldRenderMessage() {
return (
this.hasAttachments ||
this.data.content ||
this.isEmailContentType ||
this.isAnIntegrationMessage
);
},
emailMessageContent() {
const {
html_content: { full: fullHTMLContent } = {},
@@ -274,6 +285,9 @@ export default {
isTemplate() {
return this.data.message_type === MESSAGE_TYPE.TEMPLATE;
},
isAnIntegrationMessage() {
return this.contentType === 'integrations';
},
emailHeadAttributes() {
return {
email: this.contentAttributes.email,

View File

@@ -96,25 +96,26 @@
</p>
</div>
<reply-bottom-panel
:mode="replyType"
:inbox="inbox"
:send-button-text="replyButtonLabel"
:on-file-upload="onFileUpload"
:show-file-upload="showFileUpload"
:show-audio-recorder="showAudioRecorder"
:toggle-emoji-picker="toggleEmojiPicker"
:toggle-audio-recorder="toggleAudioRecorder"
:toggle-audio-recorder-play-pause="toggleAudioRecorderPlayPause"
:show-emoji-picker="showEmojiPicker"
:on-send="onSendReply"
:is-send-disabled="isReplyButtonDisabled"
:recording-audio-duration-text="recordingAudioDurationText"
:recording-audio-state="recordingAudioState"
:is-recording-audio="isRecordingAudio"
:is-on-private-note="isOnPrivateNote"
:show-editor-toggle="isAPIInbox && !isOnPrivateNote"
:conversation-id="conversationId"
:enable-multiple-file-upload="enableMultipleFileUpload"
:has-whatsapp-templates="hasWhatsappTemplates"
:inbox="inbox"
:is-on-private-note="isOnPrivateNote"
:is-recording-audio="isRecordingAudio"
:is-send-disabled="isReplyButtonDisabled"
:mode="replyType"
:on-file-upload="onFileUpload"
:on-send="onSendReply"
:recording-audio-duration-text="recordingAudioDurationText"
:recording-audio-state="recordingAudioState"
:send-button-text="replyButtonLabel"
:show-audio-recorder="showAudioRecorder"
:show-editor-toggle="isAPIInbox && !isOnPrivateNote"
:show-emoji-picker="showEmojiPicker"
:show-file-upload="showFileUpload"
:toggle-audio-recorder-play-pause="toggleAudioRecorderPlayPause"
:toggle-audio-recorder="toggleAudioRecorder"
:toggle-emoji-picker="toggleEmojiPicker"
@selectWhatsappTemplate="openWhatsappTemplateModal"
@toggle-editor="toggleRichContentEditor"
/>

View File

@@ -96,7 +96,9 @@ export default {
<style scoped lang="scss">
.mention--box {
background: var(--white);
border-radius: var(--border-radius-normal);
border-top: 1px solid var(--color-border);
box-shadow: var(--shadow-medium);
font-size: var(--font-size-small);
left: 0;
line-height: 1.2;

View File

@@ -0,0 +1,39 @@
<template>
<dyte-video-call
v-if="showDyteIntegration"
:message-id="messageId"
:meeting-data="contentAttributes.data"
/>
</template>
<script>
import DyteVideoCall from './integrations/Dyte.vue';
import inboxMixin from 'shared/mixins/inboxMixin';
export default {
components: { DyteVideoCall },
mixins: [inboxMixin],
props: {
messageId: {
type: [String, Number],
default: 0,
},
contentAttributes: {
type: Object,
default: () => ({}),
},
inboxId: {
type: [String, Number],
default: 0,
},
},
computed: {
showDyteIntegration() {
const isEnabledOnTheInbox = this.isAPIInbox || this.isAWebWidgetInbox;
return isEnabledOnTheInbox && this.contentAttributes.type === 'dyte';
},
inbox() {
return this.$store.getters['inboxes/getInbox'](this.inboxId);
},
},
};
</script>

View File

@@ -0,0 +1,103 @@
<template>
<div>
<woot-button
size="small"
variant="smooth"
color-scheme="secondary"
icon="video-add"
class="join-call-button"
:is-loading="isLoading"
@click="joinTheCall"
>
{{ $t('INTEGRATION_SETTINGS.DYTE.CLICK_HERE_TO_JOIN') }}
</woot-button>
<div v-if="dyteAuthToken" class="video-call--container">
<iframe
:src="meetingLink"
allow="camera;microphone;fullscreen;display-capture;picture-in-picture;clipboard-write;"
/>
<woot-button
size="small"
variant="smooth"
color-scheme="secondary"
class="join-call-button"
@click="leaveTheRoom"
>
{{ $t('INTEGRATION_SETTINGS.DYTE.LEAVE_THE_ROOM') }}
</woot-button>
</div>
</div>
</template>
<script>
import DyteAPI from 'dashboard/api/integrations/dyte';
import { buildDyteURL } from 'shared/helpers/IntegrationHelper';
import alertMixin from 'shared/mixins/alertMixin';
export default {
mixins: [alertMixin],
props: {
messageId: {
type: Number,
required: true,
},
meetingData: {
type: Object,
default: () => ({}),
},
},
data() {
return { isLoading: false, dyteAuthToken: '', isSDKMounted: false };
},
computed: {
meetingLink() {
return buildDyteURL(this.meetingData.room_name, this.dyteAuthToken);
},
},
methods: {
async joinTheCall() {
this.isLoading = true;
try {
const {
data: { authResponse: { authToken } = {} } = {},
} = await DyteAPI.addParticipantToMeeting(this.messageId);
this.dyteAuthToken = authToken;
} catch (err) {
this.showAlert(this.$t('INTEGRATION_SETTINGS.DYTE.JOIN_ERROR'));
} finally {
this.isLoading = false;
}
},
leaveTheRoom() {
this.dyteAuthToken = '';
},
},
};
</script>
<style lang="scss">
.join-call-button {
margin: var(--space-small) 0;
}
.video-call--container {
position: fixed;
bottom: 0;
right: 0;
width: 100%;
height: 100%;
z-index: var(--z-index-high);
padding: var(--space-smaller);
background: var(--b-800);
iframe {
width: 100%;
height: 100%;
border: 0;
}
button {
position: absolute;
top: var(--space-smaller);
right: 16rem;
}
}
</style>

View File

@@ -70,7 +70,9 @@ export default {
.mention--box {
background: var(--white);
border-bottom: var(--space-small) solid var(--white);
border-radius: var(--border-radius-normal);
border-top: 1px solid var(--color-border);
box-shadow: var(--shadow-medium);
left: 0;
max-height: 14rem;
overflow: auto;

View File

@@ -1,23 +1,14 @@
<template>
<modal :show.sync="show" :on-close="cancel">
<div class="column content-box">
<woot-modal-header :header-title="title" />
<div class="row modal-content">
<div class="medium-12 columns">
<p>
{{ description }}
</p>
</div>
<div class="modal-footer">
<div class="medium-12 columns">
<woot-button @click="confirm">
{{ confirmLabel }}
</woot-button>
<button class="button clear" @click="cancel">
{{ cancelLabel }}
</button>
</div>
</div>
<woot-modal-header :header-title="title" :header-content="description" />
<div class="modal-footer">
<woot-button variant="clear" @click="cancel">
{{ cancelLabel }}
</woot-button>
<woot-button @click="confirm">
{{ confirmLabel }}
</woot-button>
</div>
</div>
</modal>
@@ -73,3 +64,8 @@ export default {
},
};
</script>
<style lang="scss" scoped>
.modal-container .modal-footer {
padding: var(--space-normal) var(--space-medium);
}
</style>

View File

@@ -23,5 +23,6 @@ export default {
},
DOCS_URL: '//www.chatwoot.com/docs/product/',
TESTIMONIAL_URL: 'https://testimonials.cdn.chatwoot.com/content.json',
SMALL_SCREEN_BREAKPOINT: 1024,
};
export const DEFAULT_REDIRECT_URL = '/app/';

View File

@@ -97,8 +97,9 @@ export const generateConditionOptions = (options, key = 'id') => {
});
};
export const getActionOptions = ({ teams, labels, type }) => {
export const getActionOptions = ({ agents, teams, labels, type }) => {
const actionsMap = {
assign_agent: agents,
assign_team: teams,
send_email_to_team: teams,
add_label: generateConditionOptions(labels, 'title'),
@@ -178,7 +179,7 @@ export const getDefaultConditions = eventName => {
export const getDefaultActions = () => {
return [
{
action_name: 'assign_team',
action_name: 'assign_agent',
action_params: [],
},
];
@@ -213,7 +214,7 @@ export const isCustomAttribute = (attrs, key) => {
export const generateCustomAttributes = (
conversationAttributes = [],
contactAttribtues = [],
contactAttributes = [],
conversationlabel,
contactlabel
) => {
@@ -228,14 +229,14 @@ export const generateCustomAttributes = (
...conversationAttributes
);
}
if (contactAttribtues.length) {
if (contactAttributes.length) {
customAttributes.push(
{
key: `contact_custom_attribute`,
name: contactlabel,
disabled: true,
},
...contactAttribtues
...contactAttributes
);
}
return customAttributes;

View File

@@ -24,8 +24,11 @@
"TITLE": "Select an agent bot",
"DESC": "You can set an agent bot from the list to this inbox. The bot can initially handle the conversation and transfer it to an agent when needed.",
"SUBMIT": "تحديث",
"DISCONNECT": "Disconnect Bot",
"SUCCESS_MESSAGE": "Successfully updated the agent bot",
"DISCONNECTED_SUCCESS_MESSAGE": "Successfully disconnected the agent bot",
"ERROR_MESSAGE": "Could not update the agent bot, please try again later",
"DISCONNECTED_ERROR_MESSAGE": "Could not disconnect the agent bot, please try again later",
"SELECT_PLACEHOLDER": "Select Bot"
},
"ADD": {

View File

@@ -42,8 +42,8 @@
}
},
"API": {
"SUCCESS_MESSAGE": "تم إضافة سمة مخصصة بنجاح",
"ERROR_MESSAGE": "تعذر إنشاء سمة مخصصة، الرجاء المحاولة مرة أخرى لاحقاً"
"SUCCESS_MESSAGE": "تم إضافة سمة مخصصة بنجاح!",
"ERROR_MESSAGE": "تعذر إنشاء سمة مخصصة، الرجاء المحاولة مرة أخرى لاحقاً."
}
},
"DELETE": {

View File

@@ -2,8 +2,8 @@
"BULK_ACTION": {
"CONVERSATIONS_SELECTED": "%{conversationCount} المحادثات المحددة",
"AGENT_SELECT_LABEL": "اختر وكيل",
"ASSIGN_CONFIRMATION_LABEL": "Are you sure to assign %{conversationCount} %{conversationLabel} to",
"UNASSIGN_CONFIRMATION_LABEL": "Are you sure to unassign %{conversationCount} %{conversationLabel}?",
"ASSIGN_CONFIRMATION_LABEL": "هل أنت متأكد من أنك تريد تعيين %{conversationCount} %{conversationLabel} إلى",
"UNASSIGN_CONFIRMATION_LABEL": "هل أنت متأكد من إلغاء تعيين %{conversationCount} %{conversationLabel}؟",
"GO_BACK_LABEL": "العودة للخلف",
"ASSIGN_LABEL": "تكليف",
"YES": "نعم",
@@ -31,10 +31,10 @@
"TEAMS": {
"TEAM_SELECT_LABEL": "اختيار فريق",
"NONE": "لا شيء",
"NO_TEAMS_AVAILABLE": "There are no teams added to this account yet.",
"ASSIGN_SELECTED_TEAMS": "Assign selected team",
"ASSIGN_SUCCESFUL": "Teams assiged successfully",
"ASSIGN_FAILED": "Failed to assign team, please try again"
"NO_TEAMS_AVAILABLE": "لا توجد فرق مضافة إلى هذا الحساب حتى الآن.",
"ASSIGN_SELECTED_TEAMS": "تعيين فريق محدد",
"ASSIGN_SUCCESFUL": "تم تعيين الفرق بنجاح",
"ASSIGN_FAILED": "فشل تعيين الفريق، الرجاء المحاولة مرة أخرى"
}
}
}

View File

@@ -57,8 +57,8 @@
"REPLY_TO_TWEET": "الرد على هذه التغريدة",
"LINK_TO_STORY": "الذهاب إلى قصة الإنستقرام",
"SENT": "Sent successfully",
"READ": "Read successfully",
"DELIVERED": "Delivered successfully",
"READ": "تمت القراءة بنجاح",
"DELIVERED": "تم الإرسال بنجاح",
"NO_MESSAGES": "لا توجد رسائل",
"NO_CONTENT": "لم يتم العثور على محتوى",
"HIDE_QUOTED_TEXT": "Hide Quoted Text",

View File

@@ -214,7 +214,7 @@
"CONVERSATION_INFO": "معلومات المحادثة",
"CONTACT_ATTRIBUTES": "سمات جهة الاتصال",
"PREVIOUS_CONVERSATION": "المحادثات السابقة",
"MACROS": "Macros"
"MACROS": "ماكروس"
}
},
"CONVERSATION_CUSTOM_ATTRIBUTES": {

View File

@@ -1,6 +1,6 @@
{
"EMOJI": {
"PLACEHOLDER": "Search emojis",
"NOT_FOUND": "No emoji match your search"
"PLACEHOLDER": "ابحث في الايموجي",
"NOT_FOUND": "لا يوجد إيموجي يطابق بحثك"
}
}

View File

@@ -23,7 +23,7 @@
"ERROR": "الرجاء إدخال اسم حساب صحيح"
},
"LANGUAGE": {
"LABEL": "Site language",
"LABEL": "لغة الموقع",
"PLACEHOLDER": "اسم الحساب الخاص بك",
"ERROR": ""
},
@@ -55,7 +55,7 @@
"ENTER_TO_SELECT": "اضغط على زر الإدخال للاختيار",
"ENTER_TO_REMOVE": "اضغط على زر الإدخال للحذف",
"SELECT_ONE": "اختر واحدا",
"SELECT": "Select"
"SELECT": "اختر"
}
},
"NOTIFICATIONS_PAGE": {
@@ -139,6 +139,6 @@
}
},
"DASHBOARD_APPS": {
"LOADING_MESSAGE": "Loading Dashboard App..."
"LOADING_MESSAGE": "تحميل تطبيق لوحة التحكم..."
}
}

View File

@@ -53,6 +53,10 @@
"ENABLE": "إنشاء محادثات من التغريدات المشار إليها"
}
},
"MICROSOFT": {
"HELP": "To add your Microsoft account as a channel, you need to authenticate your Microsoft account by clicking on 'Sign in with Microsoft' ",
"ERROR_MESSAGE": "There was an error connecting to Microsoft, please try again"
},
"WEBSITE_CHANNEL": {
"TITLE": "قناة الموقع",
"DESC": "قم بإنشاء قناة تواصل لموقع الويب الخاص بك وابدأ في استقبال الرسائل من عملائك عبر صندوق الدردشة المباشرة.",
@@ -134,7 +138,7 @@
"PHONE_NUMBER": {
"LABEL": "رقم الهاتف",
"PLACEHOLDER": "الرجاء إدخال رقم الهاتف الذي سيتم إرسال الرسائل منه.",
"ERROR": "Please provide a valid phone number that starts with a `+` sign and does not contain any spaces."
"ERROR": "الرجاء تقديم رقم هاتف صالح يبدأ بإشارة '+' ولا يحتوي على أي مسافات."
},
"API_CALLBACK": {
"TITLE": "عنوان Callback URL",
@@ -185,7 +189,7 @@
"PHONE_NUMBER": {
"LABEL": "رقم الهاتف",
"PLACEHOLDER": "الرجاء إدخال رقم الهاتف الذي سيتم إرسال الرسائل منه.",
"ERROR": "Please provide a valid phone number that starts with a `+` sign and does not contain any spaces."
"ERROR": "الرجاء تقديم رقم هاتف صالح يبدأ بإشارة '+' ولا يحتوي على أي مسافات."
},
"SUBMIT_BUTTON": "إنشاء قناة عرض التردد",
"API": {
@@ -214,7 +218,7 @@
"PHONE_NUMBER": {
"LABEL": "رقم الهاتف",
"PLACEHOLDER": "الرجاء إدخال رقم الهاتف الذي سيتم إرسال الرسائل منه.",
"ERROR": "Please provide a valid phone number that starts with a `+` sign and does not contain any spaces."
"ERROR": "الرجاء تقديم رقم هاتف صالح يبدأ بإشارة '+' ولا يحتوي على أي مسافات."
},
"PHONE_NUMBER_ID": {
"LABEL": "رقم الهاتف",
@@ -239,9 +243,9 @@
},
"API_CALLBACK": {
"TITLE": "عنوان Callback URL",
"SUBTITLE": "You have to configure the webhook URL and the verification token in the Facebook Developer portal with the values shown below.",
"SUBTITLE": "يجب عليك تكوين رابط الويب هوك و رمز التحقق في بوابة مطور الفيسبوك مع القيم الموضحة أدناه.",
"WEBHOOK_URL": "رابط Webhook",
"WEBHOOK_VERIFICATION_TOKEN": "Webhook Verification Token"
"WEBHOOK_VERIFICATION_TOKEN": "رمز التحقق من Webhook"
},
"SUBMIT_BUTTON": "إنشاء قناة واتساب",
"API": {
@@ -421,7 +425,7 @@
"PRE_CHAT_FORM": "نموذج ما قبل الدردشة",
"BUSINESS_HOURS": "ساعات العمل",
"WIDGET_BUILDER": "منشئ اللايف شات",
"BOT_CONFIGURATION": "Bot Configuration"
"BOT_CONFIGURATION": "اعدادات البوت"
},
"SETTINGS": "الإعدادات",
"FEATURES": {
@@ -445,8 +449,8 @@
"ENABLE_CSAT_SUB_TEXT": "تمكين/تعطيل تقييم خدمة العملاء بعد إنتهاء المحادثة",
"ENABLE_CONTINUITY_VIA_EMAIL": "تمكين استمرارية المحادثة عبر البريد الإلكتروني",
"ENABLE_CONTINUITY_VIA_EMAIL_SUB_TEXT": "المحادثات ستستمر عبر البريد الإلكتروني إذا كان عنوان البريد الإلكتروني لجهة الاتصال متاحاً.",
"LOCK_TO_SINGLE_CONVERSATION": "Lock to single conversation",
"LOCK_TO_SINGLE_CONVERSATION_SUB_TEXT": "Enable or disable multiple conversations for the same contact in this inbox",
"LOCK_TO_SINGLE_CONVERSATION": "قفل إلى محادثة واحدة",
"LOCK_TO_SINGLE_CONVERSATION_SUB_TEXT": "تمكين أو تعطيل محادثات متعددة لنفس جهة الاتصال في هذا البريد الوارد",
"INBOX_UPDATE_TITLE": "إعدادات قناة التواصل",
"INBOX_UPDATE_SUB_TEXT": "تحديث إعدادات قناة التواصل",
"AUTO_ASSIGNMENT_SUB_TEXT": "تمكين أو تعطيل الإسناد التلقائي للمحادثات الجديدة إلى الموظفين المضافين إلى قناة التواصل هذه.",
@@ -548,6 +552,10 @@
},
"ENABLE_SSL": "تمكين SSL"
},
"MICROSOFT": {
"TITLE": "Microsoft",
"SUBTITLE": "Reauthorize your MICROSOFT account"
},
"SMTP": {
"TITLE": "SMTP",
"SUBTITLE": "تعيين تفاصيل IMAP الخاصة بك",

View File

@@ -76,6 +76,13 @@
"BODY": "<br/><p>ستتم الآن مزامنة جميع المحادثات الواردة إلى <b><i>محادثة الزبائن</i></b> داخل مكان العمل الخاص بك.</p><p>الرد على موضوع محادثة في <b><i>محادثة العملاء</i></b> قناة الركود سوف تقوم بإنشاء رد على العميل من خلال المحادثة.</p><p>ابدأ الردود ب <b><i>ملاحظة:</i></b> لإنشاء ملاحظات خاصة بدلاً من الردود.</p><p>إذا كان للرد على slack ملف تعريف الوكيل في الدردشة تحت نفس البريد الإلكتروني، فسيتم ربط الردود وفقا لذلك.</p><p>عندما لا يكون للرد ملف شخصي للوكيل المرتبط، ستتم الردود من ملف بوت الشخصي.</p>"
}
},
"DYTE": {
"CLICK_HERE_TO_JOIN": "Click here to join",
"LEAVE_THE_ROOM": "Leave the room",
"START_VIDEO_CALL_HELP_TEXT": "Start a new video call with the customer",
"JOIN_ERROR": "There was an error joining the call, please try again",
"CREATE_ERROR": "There was an error creating a meeting link, please try again"
},
"DELETE": {
"BUTTON_TEXT": "حذف",
"API": {

View File

@@ -1,78 +1,78 @@
{
"MACROS": {
"HEADER": "Macros",
"HEADER_BTN_TXT": "Add a new macro",
"HEADER_BTN_TXT_SAVE": "Save macro",
"LOADING": "Fetching macros",
"SIDEBAR_TXT": "<p><b>Macros</b><p>A macro is a set of saved actions that help customer service agents easily complete tasks. The agents can define a set of actions like tagging a conversation with a label, sending an email transcript, updating a custom attribute, etc., and they can run these actions in a single click. When the agents run the macro, the actions would be performed sequentially in the order they are defined. Macros improve productivity and increase consistency in actions. </p><p>A macro can be helpful in 2 ways. </p><p><b>As an agent assist:</b> If an agent performs a set of actions multiple times, they can save it as a macro and execute all the actions together using a single click.</p><p><b>As an option to onboard a team member:</b> Every agent has to perform many different checks/actions during each conversation. Onboarding a new support team member will be easy if pre-defined macros are available on the account. Instead of describing each step in detail, the manager/team lead can point to the macros used in different scenarios.</p>",
"ERROR": "Something went wrong. Please try again",
"ORDER_INFO": "Macros will run in the order you add your actions. You can rearrange them by dragging them by the handle beside each node.",
"HEADER": "ماكروس",
"HEADER_BTN_TXT": "إضافة ماكرو جديد",
"HEADER_BTN_TXT_SAVE": "حفظ الماكرو",
"LOADING": "جاري جلب الماكروس",
"SIDEBAR_TXT": "<p><b>الماكروس</b><p>الماكرو هو مجموعة من الإجراءات المحفوظة التي تساعد وكلاء خدمة العملاء على إكمال المهام بسهولة. يمكن للوكلاء تحديد مجموعة من الإجراءات مثل وضع علامة على محادثة مع تسمية، وإرسال نص بريد إلكتروني، وتحديث سمة مخصصة، إلخ. ويمكنهم تنفيذ هذه الإجراءات بنقرة واحدة. وعندما يدير الوكلاء الكلية، يتم تنفيذ الإجراءات بالتسلسل حسب الترتيب الذي تحدده. يحسن الماكرو الإنتاجية ويزيد الاتساق في الإجراءات. </p><p>يمكن أن يكون الماكرو مفيداً بطريقتين. </p><p><b>كوكيل يساعد:</b> إذا قام وكيل بمجموعة من الإجراءات عدة مرات، يمكنهم حفظه كماكلي وتنفيذ جميع الإجراءات معاً باستخدام نقرة واحدة.</p><p><b>كخيار للدخول إلى عضوية الفريق:</b> يجب على كل وكيل إجراء العديد من الشيكات والإجراءات المختلفة خلال كل محادثة. سيكون عضو فريق الدعم الجديد من أونبواردينغ سهلا إذا كان الماكرو المحدد مسبقا متاحا على الحساب. وبدلا من وصف كل خطوة بالتفصيل، يمكن للمدير/الفريق أن يشير إلى الكتلة الكلية المستخدمة في سيناريوهات مختلفة.</p>",
"ERROR": "حدث خطأ ما. الرجاء المحاولة مرة أخرى",
"ORDER_INFO": "سيتم تشغيل الماكرو بالترتيب الذي تضيفه إجراءاتك. يمكنك إعادة ترتيبهم بسحبهم بواسطة المعالج بجانب كل عقدة.",
"ADD": {
"FORM": {
"NAME": {
"LABEL": "Macro name",
"PLACEHOLDER": "Enter a name for your macro",
"ERROR": "Name is required for creating a macro"
"LABEL": "اسم الماكرو",
"PLACEHOLDER": "أدخل اسم الماكرو الخاص بك",
"ERROR": "الاسم مطلوب لإنشاء الماكرو"
},
"ACTIONS": {
"LABEL": "الإجراءات"
}
},
"API": {
"SUCCESS_MESSAGE": "Macro added successfully",
"ERROR_MESSAGE": "Unable to create macro, Please try again later"
"SUCCESS_MESSAGE": "تمت إضافة الماكرو بنجاح",
"ERROR_MESSAGE": "غير قادر على إنشاء الماكرو ، الرجاء المحاولة مرة أخرى لاحقاً"
}
},
"LIST": {
"TABLE_HEADER": [
"الاسم",
"Created by",
"Last updated by",
"Visibility"
"تم إنشاؤها بواسطة",
"آخر تحديث بواسطة",
"الظهور"
],
"404": "No macros found"
"404": "لم يتم العثور على الماكروس"
},
"DELETE": {
"TOOLTIP": "Delete macro",
"TOOLTIP": "حذف الماكرو",
"CONFIRM": {
"MESSAGE": "هل أنت متأكد من الحذف ",
"YES": "نعم، احذف",
"NO": "لا"
},
"API": {
"SUCCESS_MESSAGE": "Macro deleted successfully",
"ERROR_MESSAGE": "There was an error deleting the macro. Please try again later"
"SUCCESS_MESSAGE": "تم حذف الماكرو بنجاح",
"ERROR_MESSAGE": "حدث خطأ أثناء حذف الماكرو. الرجاء المحاولة مرة أخرى في وقت لاحق"
}
},
"EDIT": {
"TOOLTIP": "Edit macro",
"TOOLTIP": "تعديل الماكرو",
"API": {
"SUCCESS_MESSAGE": "Macro updated successfully",
"ERROR_MESSAGE": "Could not update Macro, Please try again later"
"SUCCESS_MESSAGE": "تم تحديث الماكرو بنجاح",
"ERROR_MESSAGE": "تعذر تحديث الماكرو ، الرجاء المحاولة مرة أخرى لاحقاً"
}
},
"EDITOR": {
"START_FLOW": "Start Flow",
"END_FLOW": "End Flow",
"LOADING": "Fetching macro",
"ADD_BTN_TOOLTIP": "Add new action",
"DELETE_BTN_TOOLTIP": "Delete Action",
"START_FLOW": "بداية الإجرائات",
"END_FLOW": "نهاية الإجرائات",
"LOADING": "جاري جلب الماكروس",
"ADD_BTN_TOOLTIP": "إضافة إجراء جديد",
"DELETE_BTN_TOOLTIP": "حذف الإجراء",
"VISIBILITY": {
"LABEL": "Macro Visibility",
"LABEL": "الرؤية الخاصة بالماكرو",
"GLOBAL": {
"LABEL": "Public",
"DESCRIPTION": "This macro is available publicly for all agents in this account."
"LABEL": "عامة",
"DESCRIPTION": "هذا الماكرو متاح بشكل عام لجميع الوكلاء في هذا الحساب."
},
"PERSONAL": {
"LABEL": "Private",
"DESCRIPTION": "This macro will be private to you and not be available to others."
"LABEL": "خاص",
"DESCRIPTION": "هذا الماكرو سيكون خاصا لك ولن يكون متاحا للآخرين."
}
}
},
"EXECUTE": {
"BUTTON_TOOLTIP": "Execute",
"PREVIEW": "Preview Macro",
"EXECUTED_SUCCESSFULLY": "Macro executed successfully"
"BUTTON_TOOLTIP": "تنفيذ",
"PREVIEW": "معاينة الماكرو",
"EXECUTED_SUCCESSFULLY": "تم تنفيذ الماكرو بنجاح"
}
}
}

View File

@@ -59,18 +59,18 @@
"TITLE": "الإشعارات الصوتية",
"NOTE": "تمكين التنبيهات الصوتية في لوحة التحكم للرسائل والمحادثات الجديدة.",
"ALERT_TYPE": {
"TITLE": "Alert events:",
"TITLE": "أحداث التنبيه:",
"NONE": "لا شيء",
"ASSIGNED": "المحادثات المسندة",
"ALL_CONVERSATIONS": "كل المحادثات"
},
"DEFAULT_TONE": {
"TITLE": "Alert tone:"
"TITLE": "نغمة التنبيه:"
},
"CONDITIONS": {
"TITLE": "Alert conditions:",
"CONDITION_ONE": "Send audio alerts only if the browser window is not active",
"CONDITION_TWO": "Send alerts every 30s until all the assigned conversations are read"
"TITLE": "شروط التنبيه:",
"CONDITION_ONE": "إرسال تنبيهات صوتية فقط إذا كانت نافذة المتصفح غير نشطة",
"CONDITION_TWO": "إرسال تنبيهات كل 30 ثانية حتى يتم قراءة جميع المحادثات المعينة"
}
},
"EMAIL_NOTIFICATIONS_SECTION": {
@@ -115,8 +115,8 @@
"مشغول",
"غير متصل"
],
"SET_AVAILABILITY_SUCCESS": "Availability has been set successfully",
"SET_AVAILABILITY_ERROR": "Couldn't set availability, please try again"
"SET_AVAILABILITY_SUCCESS": "تم تعيين التوافر بنجاح",
"SET_AVAILABILITY_ERROR": "تعذر تعيين التوافر، الرجاء المحاولة مرة أخرى"
},
"EMAIL": {
"LABEL": "عنوان البريد الإلكتروني الخاص بك",
@@ -147,7 +147,7 @@
"SELECTOR_SUBTITLE": "اختر حساباً من القائمة التالية",
"PROFILE_SETTINGS": "إعدادات الملف الشخصي",
"KEYBOARD_SHORTCUTS": "اختصارات لوحة المفاتيح",
"SUPER_ADMIN_CONSOLE": "Super Admin Console",
"SUPER_ADMIN_CONSOLE": "وحدة تحكم المدير المتميز",
"LOGOUT": "تسجيل الخروج"
},
"APP_GLOBAL": {
@@ -173,7 +173,7 @@
"UPLOADING": "جاري الرفع..."
},
"LOCATION_BUBBLE": {
"SEE_ON_MAP": "See on map"
"SEE_ON_MAP": "مشاهدة على الخريطة"
},
"FORM_BUBBLE": {
"SUBMIT": "إرسال"
@@ -197,7 +197,7 @@
"CONTACTS": "جهات الاتصال",
"HOME": "الرئيسية",
"AGENTS": "موظف الدعم",
"AGENT_BOTS": "Bots",
"AGENT_BOTS": "البوتات",
"INBOXES": "قنوات التواصل",
"NOTIFICATIONS": "الإشعارات",
"CANNED_RESPONSES": "الردود السريعة",
@@ -208,7 +208,7 @@
"LABELS": "الوسوم",
"CUSTOM_ATTRIBUTES": "سمات مخصصة",
"AUTOMATION": "الأتمتة",
"MACROS": "Macros",
"MACROS": "ماكروس",
"TEAMS": "الفرق",
"BILLING": "الفواتير",
"CUSTOM_VIEWS_FOLDER": "المجلدات",
@@ -241,8 +241,8 @@
"CATEGORY_EMPTY_MESSAGE": "لم يتم العثور على فئات"
},
"SET_AUTO_OFFLINE": {
"TEXT": "Mark offline automatically",
"INFO_TEXT": "Let the system automatically mark you offline when you aren't using the app or dashboard."
"TEXT": "وضع علامة غير متصل تلقائيا",
"INFO_TEXT": "السماح للنظام بوضع علامة غير متصل أوتوماتيكياً عندما لا تستخدم التطبيق أو لوحة التحكم."
},
"DOCS": "قراءة المستندات"
},
@@ -282,6 +282,7 @@
}
},
"KEYBOARD_SHORTCUTS": {
"TOGGLE_MODAL": "عرض جميع الاختصارات",
"TITLE": {
"OPEN_CONVERSATION": "فتح المحادثة",
"RESOLVE_AND_NEXT": "حل وانتقل إلى التالي",

View File

@@ -2,7 +2,7 @@
"REGISTER": {
"TRY_WOOT": "تسجيل حساب",
"TITLE": "تسجيل",
"TESTIMONIAL_HEADER": "All it takes is one step to move forward",
"TESTIMONIAL_HEADER": "إن كل ما يلزم هو خطوة واحدة للمضي قدما",
"TESTIMONIAL_CONTENT": "You're one step away from engaging your customers, retaining them and finding new ones.",
"TERMS_ACCEPT": "من خلال التسجيل، فإنك توافق على <a href=\"https://www.chatwoot.com/terms\">شروط الخدمة</a> و <a href=\"https://www.chatwoot.com/privacy-policy\">سياسة الخصوصية</a>",
"COMPANY_NAME": {

View File

@@ -24,8 +24,11 @@
"TITLE": "Select an agent bot",
"DESC": "You can set an agent bot from the list to this inbox. The bot can initially handle the conversation and transfer it to an agent when needed.",
"SUBMIT": "Обновяване",
"DISCONNECT": "Disconnect Bot",
"SUCCESS_MESSAGE": "Successfully updated the agent bot",
"DISCONNECTED_SUCCESS_MESSAGE": "Successfully disconnected the agent bot",
"ERROR_MESSAGE": "Could not update the agent bot, please try again later",
"DISCONNECTED_ERROR_MESSAGE": "Could not disconnect the agent bot, please try again later",
"SELECT_PLACEHOLDER": "Select Bot"
},
"ADD": {

View File

@@ -42,8 +42,8 @@
}
},
"API": {
"SUCCESS_MESSAGE": "Custom Attribute added successfully",
"ERROR_MESSAGE": "Could not able to create a custom attribute, Please try again later"
"SUCCESS_MESSAGE": "Custom Attribute added successfully!",
"ERROR_MESSAGE": "Could not create a Custom Attribute. Please try again later."
}
},
"DELETE": {

View File

@@ -53,6 +53,10 @@
"ENABLE": "Create conversations from mentioned Tweets"
}
},
"MICROSOFT": {
"HELP": "To add your Microsoft account as a channel, you need to authenticate your Microsoft account by clicking on 'Sign in with Microsoft' ",
"ERROR_MESSAGE": "There was an error connecting to Microsoft, please try again"
},
"WEBSITE_CHANNEL": {
"TITLE": "Website channel",
"DESC": "Create a channel for your website and start supporting your customers via our website widget.",
@@ -548,6 +552,10 @@
},
"ENABLE_SSL": "Enable SSL"
},
"MICROSOFT": {
"TITLE": "Microsoft",
"SUBTITLE": "Reauthorize your MICROSOFT account"
},
"SMTP": {
"TITLE": "SMTP",
"SUBTITLE": "Set your SMTP details",

View File

@@ -76,6 +76,13 @@
"BODY": "<br/><p>Chatwoot will now sync all the incoming conversations into the <b><i>customer-conversations</i></b> channel inside your slack workplace.</p><p>Replying to a conversation thread in <b><i>customer-conversations</i></b> slack channel will create a response back to the customer through chatwoot.</p><p>Start the replies with <b><i>note:</i></b> to create private notes instead of replies.</p><p>If the replier on slack has an agent profile in chatwoot under the same email, the replies will be associated accordingly.</p><p>When the replier doesn't have an associated agent profile, the replies will be made from the bot profile.</p>"
}
},
"DYTE": {
"CLICK_HERE_TO_JOIN": "Click here to join",
"LEAVE_THE_ROOM": "Leave the room",
"START_VIDEO_CALL_HELP_TEXT": "Start a new video call with the customer",
"JOIN_ERROR": "There was an error joining the call, please try again",
"CREATE_ERROR": "There was an error creating a meeting link, please try again"
},
"DELETE": {
"BUTTON_TEXT": "Изтрий",
"API": {

View File

@@ -282,6 +282,7 @@
}
},
"KEYBOARD_SHORTCUTS": {
"TOGGLE_MODAL": "View all shortcuts",
"TITLE": {
"OPEN_CONVERSATION": "Open conversation",
"RESOLVE_AND_NEXT": "Resolve and move to next",

View File

@@ -24,8 +24,11 @@
"TITLE": "Select an agent bot",
"DESC": "You can set an agent bot from the list to this inbox. The bot can initially handle the conversation and transfer it to an agent when needed.",
"SUBMIT": "Actualitza",
"DISCONNECT": "Disconnect Bot",
"SUCCESS_MESSAGE": "Successfully updated the agent bot",
"DISCONNECTED_SUCCESS_MESSAGE": "Successfully disconnected the agent bot",
"ERROR_MESSAGE": "Could not update the agent bot, please try again later",
"DISCONNECTED_ERROR_MESSAGE": "Could not disconnect the agent bot, please try again later",
"SELECT_PLACEHOLDER": "Select Bot"
},
"ADD": {

View File

@@ -42,8 +42,8 @@
}
},
"API": {
"SUCCESS_MESSAGE": "Custom Attribute added successfully",
"ERROR_MESSAGE": "Could not able to create a custom attribute, Please try again later"
"SUCCESS_MESSAGE": "Custom Attribute added successfully!",
"ERROR_MESSAGE": "Could not create a Custom Attribute. Please try again later."
}
},
"DELETE": {

View File

@@ -53,6 +53,10 @@
"ENABLE": "Create conversations from mentioned Tweets"
}
},
"MICROSOFT": {
"HELP": "To add your Microsoft account as a channel, you need to authenticate your Microsoft account by clicking on 'Sign in with Microsoft' ",
"ERROR_MESSAGE": "There was an error connecting to Microsoft, please try again"
},
"WEBSITE_CHANNEL": {
"TITLE": "Canal Web",
"DESC": "Crea un canal per al vostre lloc web i comença a donar suport als vostres clients mitjançant el teu widget del lloc web.",
@@ -548,6 +552,10 @@
},
"ENABLE_SSL": "Enable SSL"
},
"MICROSOFT": {
"TITLE": "Microsoft",
"SUBTITLE": "Reauthorize your MICROSOFT account"
},
"SMTP": {
"TITLE": "SMTP",
"SUBTITLE": "Set your SMTP details",

View File

@@ -76,6 +76,13 @@
"BODY": "<br/><p>Chatwoot will now sync all the incoming conversations into the <b><i>customer-conversations</i></b> channel inside your slack workplace.</p><p>Replying to a conversation thread in <b><i>customer-conversations</i></b> slack channel will create a response back to the customer through chatwoot.</p><p>Start the replies with <b><i>note:</i></b> to create private notes instead of replies.</p><p>If the replier on slack has an agent profile in chatwoot under the same email, the replies will be associated accordingly.</p><p>When the replier doesn't have an associated agent profile, the replies will be made from the bot profile.</p>"
}
},
"DYTE": {
"CLICK_HERE_TO_JOIN": "Click here to join",
"LEAVE_THE_ROOM": "Leave the room",
"START_VIDEO_CALL_HELP_TEXT": "Start a new video call with the customer",
"JOIN_ERROR": "There was an error joining the call, please try again",
"CREATE_ERROR": "There was an error creating a meeting link, please try again"
},
"DELETE": {
"BUTTON_TEXT": "Suprimeix",
"API": {

View File

@@ -282,6 +282,7 @@
}
},
"KEYBOARD_SHORTCUTS": {
"TOGGLE_MODAL": "View all shortcuts",
"TITLE": {
"OPEN_CONVERSATION": "Open conversation",
"RESOLVE_AND_NEXT": "Resolve and move to next",

View File

@@ -24,8 +24,11 @@
"TITLE": "Select an agent bot",
"DESC": "You can set an agent bot from the list to this inbox. The bot can initially handle the conversation and transfer it to an agent when needed.",
"SUBMIT": "Aktualizovat",
"DISCONNECT": "Disconnect Bot",
"SUCCESS_MESSAGE": "Successfully updated the agent bot",
"DISCONNECTED_SUCCESS_MESSAGE": "Successfully disconnected the agent bot",
"ERROR_MESSAGE": "Could not update the agent bot, please try again later",
"DISCONNECTED_ERROR_MESSAGE": "Could not disconnect the agent bot, please try again later",
"SELECT_PLACEHOLDER": "Select Bot"
},
"ADD": {

View File

@@ -42,8 +42,8 @@
}
},
"API": {
"SUCCESS_MESSAGE": "Custom Attribute added successfully",
"ERROR_MESSAGE": "Could not able to create a custom attribute, Please try again later"
"SUCCESS_MESSAGE": "Custom Attribute added successfully!",
"ERROR_MESSAGE": "Could not create a Custom Attribute. Please try again later."
}
},
"DELETE": {

View File

@@ -53,6 +53,10 @@
"ENABLE": "Create conversations from mentioned Tweets"
}
},
"MICROSOFT": {
"HELP": "To add your Microsoft account as a channel, you need to authenticate your Microsoft account by clicking on 'Sign in with Microsoft' ",
"ERROR_MESSAGE": "There was an error connecting to Microsoft, please try again"
},
"WEBSITE_CHANNEL": {
"TITLE": "Kanál webové stránky",
"DESC": "Vytvořte si kanál pro vaše webové stránky a začněte podporovat své zákazníky prostřednictvím našeho widgetu.",
@@ -548,6 +552,10 @@
},
"ENABLE_SSL": "Enable SSL"
},
"MICROSOFT": {
"TITLE": "Microsoft",
"SUBTITLE": "Reauthorize your MICROSOFT account"
},
"SMTP": {
"TITLE": "SMTP",
"SUBTITLE": "Set your SMTP details",

View File

@@ -76,6 +76,13 @@
"BODY": "<br/><p>Chatwoot will now sync all the incoming conversations into the <b><i>customer-conversations</i></b> channel inside your slack workplace.</p><p>Replying to a conversation thread in <b><i>customer-conversations</i></b> slack channel will create a response back to the customer through chatwoot.</p><p>Start the replies with <b><i>note:</i></b> to create private notes instead of replies.</p><p>If the replier on slack has an agent profile in chatwoot under the same email, the replies will be associated accordingly.</p><p>When the replier doesn't have an associated agent profile, the replies will be made from the bot profile.</p>"
}
},
"DYTE": {
"CLICK_HERE_TO_JOIN": "Click here to join",
"LEAVE_THE_ROOM": "Leave the room",
"START_VIDEO_CALL_HELP_TEXT": "Start a new video call with the customer",
"JOIN_ERROR": "There was an error joining the call, please try again",
"CREATE_ERROR": "There was an error creating a meeting link, please try again"
},
"DELETE": {
"BUTTON_TEXT": "Vymazat",
"API": {

View File

@@ -282,6 +282,7 @@
}
},
"KEYBOARD_SHORTCUTS": {
"TOGGLE_MODAL": "View all shortcuts",
"TITLE": {
"OPEN_CONVERSATION": "Open conversation",
"RESOLVE_AND_NEXT": "Resolve and move to next",

View File

@@ -24,8 +24,11 @@
"TITLE": "Select an agent bot",
"DESC": "You can set an agent bot from the list to this inbox. The bot can initially handle the conversation and transfer it to an agent when needed.",
"SUBMIT": "Opdater",
"DISCONNECT": "Disconnect Bot",
"SUCCESS_MESSAGE": "Successfully updated the agent bot",
"DISCONNECTED_SUCCESS_MESSAGE": "Successfully disconnected the agent bot",
"ERROR_MESSAGE": "Could not update the agent bot, please try again later",
"DISCONNECTED_ERROR_MESSAGE": "Could not disconnect the agent bot, please try again later",
"SELECT_PLACEHOLDER": "Vælg bot"
},
"ADD": {

View File

@@ -42,8 +42,8 @@
}
},
"API": {
"SUCCESS_MESSAGE": "Brugerdefineret attribut blev tilføjet",
"ERROR_MESSAGE": "Kunne ikke oprette en brugerdefineret attribut. Prøv igen senere"
"SUCCESS_MESSAGE": "Brugerdefineret attribut blev tilføjet!",
"ERROR_MESSAGE": "Could not create a Custom Attribute. Please try again later."
}
},
"DELETE": {

View File

@@ -217,14 +217,14 @@
"DOMAIN": {
"LABEL": "Tilpasset Domæne",
"PLACEHOLDER": "Portal brugerdefineret domæne",
"HELP_TEXT": "Add only If you want to use a custom domain for your portals. Eg: https://example.com",
"HELP_TEXT": "Tilføj kun hvis du vil bruge et brugerdefineret domæne, til dine portaler. Eksempelvis https://example.com",
"ERROR": "Indtast et gyldigt domæne URL"
},
"HOME_PAGE_LINK": {
"LABEL": "Link Til Hjemmeside",
"PLACEHOLDER": "Link til portalens hjemmeside",
"HELP_TEXT": "The link used to return from the portal to the home page. Eg: https://example.com",
"ERROR": "Enter a valid home page URL"
"ERROR": "Indtast en gyldig URL til startsiden"
},
"THEME_COLOR": {
"LABEL": "Portal tema farve",

View File

@@ -53,6 +53,10 @@
"ENABLE": "Opret samtaler fra nævnte Tweets"
}
},
"MICROSOFT": {
"HELP": "To add your Microsoft account as a channel, you need to authenticate your Microsoft account by clicking on 'Sign in with Microsoft' ",
"ERROR_MESSAGE": "There was an error connecting to Microsoft, please try again"
},
"WEBSITE_CHANNEL": {
"TITLE": "Hjemmesidekanal",
"DESC": "Opret en kanal til din hjemmeside og begynde at supporte dine kunder via vores hjemmeside widget.",
@@ -548,6 +552,10 @@
},
"ENABLE_SSL": "Aktiver SSL"
},
"MICROSOFT": {
"TITLE": "Microsoft",
"SUBTITLE": "Reauthorize your MICROSOFT account"
},
"SMTP": {
"TITLE": "Smtp",
"SUBTITLE": "Indstil dine IMAP-oplysninger",

View File

@@ -76,6 +76,13 @@
"BODY": "<br/><p>Chatwoot vil nu synkronisere alle indgående samtaler ind i <b><i>kundesamtaler</i></b> kanalen i din slack arbejdsplads.</p><p>Svar på en samtaletråd i <b><i>kunde-samtaler</i></b> slack kanal vil skabe et svar tilbage til kunden gennem chatwoot.</p><p>Start svarene med <b><i>note:</i></b> for at oprette private noter i stedet for svar.</p><p>Hvis replikatoren på slack har en agentprofil i chatwoot under samme e-mail, vil svarene blive tilknyttet i overensstemmelse hermed.</p><p>Når replikatoren ikke har en tilknyttet agentprofil, vil svarene blive fremsat fra bot-profilen.</p>"
}
},
"DYTE": {
"CLICK_HERE_TO_JOIN": "Click here to join",
"LEAVE_THE_ROOM": "Leave the room",
"START_VIDEO_CALL_HELP_TEXT": "Start a new video call with the customer",
"JOIN_ERROR": "There was an error joining the call, please try again",
"CREATE_ERROR": "There was an error creating a meeting link, please try again"
},
"DELETE": {
"BUTTON_TEXT": "Slet",
"API": {

View File

@@ -282,6 +282,7 @@
}
},
"KEYBOARD_SHORTCUTS": {
"TOGGLE_MODAL": "View all shortcuts",
"TITLE": {
"OPEN_CONVERSATION": "Åbn samtale",
"RESOLVE_AND_NEXT": "Løs og flyt til næste",

View File

@@ -24,8 +24,11 @@
"TITLE": "Agenten-Bot auswählen",
"DESC": "Sie können einen Agenten-Bot aus der Liste in diesen Posteingang setzen. Der Bot kann die Unterhaltung anfangs bearbeiten und bei Bedarf an einen Agenten übertragen.",
"SUBMIT": "Aktualisieren",
"DISCONNECT": "Disconnect Bot",
"SUCCESS_MESSAGE": "Agenten-Bot erfolgreich aktualisiert",
"DISCONNECTED_SUCCESS_MESSAGE": "Successfully disconnected the agent bot",
"ERROR_MESSAGE": "Konnte den Agenten-Bot nicht aktualisieren, bitte versuchen Sie es später erneut",
"DISCONNECTED_ERROR_MESSAGE": "Could not disconnect the agent bot, please try again later",
"SELECT_PLACEHOLDER": "Bot auswählen"
},
"ADD": {
@@ -37,29 +40,29 @@
}
},
"LIST": {
"404": "No Bots found, you can create a bot by clicking the 'Configure new bot' Button ↗",
"LOADING": "Fetching Bots...",
"TYPE": "Bot Type"
"404": "Keine Bots gefunden, Sie können einen Bot erstellen, indem Sie auf den 'Neuen Bot konfigurieren' Button klicken ↗",
"LOADING": "Bots werden geladen...",
"TYPE": "Bot-Typ"
},
"DELETE": {
"BUTTON_TEXT": "Löschen",
"TITLE": "Delete Bot",
"TITLE": "Bot löschen",
"SUBMIT": "Löschen",
"CANCEL_BUTTON_TEXT": "Stornieren",
"DESCRIPTION": "Are you sure you want to delete this bot? This action is irreversible",
"DESCRIPTION": "Sind Sie sicher, dass Sie diesen Bot löschen wollen? Diese Aktion kann nicht rückgängig gemacht werden",
"API": {
"SUCCESS_MESSAGE": "Bot deleted successfully",
"SUCCESS_MESSAGE": "Bot erfolgreich gelöscht",
"ERROR_MESSAGE": "Could not able to delete bot, Please try again later"
}
},
"EDIT": {
"BUTTON_TEXT": "Bearbeiten",
"LOADING": "Fetching Bots...",
"TITLE": "Edit Bot",
"LOADING": "Bots werden geladen...",
"TITLE": "Bot bearbeiten",
"CANCEL_BUTTON_TEXT": "Stornieren",
"API": {
"SUCCESS_MESSAGE": "Bot updated successfully",
"ERROR_MESSAGE": "Could not update bot, Please try again later"
"SUCCESS_MESSAGE": "Bot erfolgreich aktualisiert",
"ERROR_MESSAGE": "Bot konnte nicht aktualisiert werden, bitte versuchen Sie es später erneut"
}
},
"TYPES": {

View File

@@ -42,8 +42,8 @@
}
},
"API": {
"SUCCESS_MESSAGE": "Benutzerdefiniertes Attribut erfolgreich hinzugefügt",
"ERROR_MESSAGE": "Konnte kein benutzerdefiniertes Attribut erstellen. Bitte versuchen Sie es später erneut"
"SUCCESS_MESSAGE": "Benutzerdefiniertes Attribut erfolgreich hinzugefügt!",
"ERROR_MESSAGE": "Could not create a Custom Attribute. Please try again later."
}
},
"DELETE": {

View File

@@ -23,7 +23,7 @@
"ERROR": "Bitte geben Sie einen gültigen Kontonamen ein"
},
"LANGUAGE": {
"LABEL": "Site language",
"LABEL": "Sprache",
"PLACEHOLDER": "Ihr Kontoname",
"ERROR": ""
},
@@ -55,7 +55,7 @@
"ENTER_TO_SELECT": "Drücken Sie zur Auswahl die Eingabetaste",
"ENTER_TO_REMOVE": "Drücken Sie zum Entfernen die Eingabetaste",
"SELECT_ONE": "Eines wählen",
"SELECT": "Select"
"SELECT": "Auswählen"
}
},
"NOTIFICATIONS_PAGE": {
@@ -139,6 +139,6 @@
}
},
"DASHBOARD_APPS": {
"LOADING_MESSAGE": "Loading Dashboard App..."
"LOADING_MESSAGE": "Dashboard-App wird geladen..."
}
}

View File

@@ -53,6 +53,10 @@
"ENABLE": "Konversationen aus erwähnten Tweets erstellen"
}
},
"MICROSOFT": {
"HELP": "To add your Microsoft account as a channel, you need to authenticate your Microsoft account by clicking on 'Sign in with Microsoft' ",
"ERROR_MESSAGE": "There was an error connecting to Microsoft, please try again"
},
"WEBSITE_CHANNEL": {
"TITLE": "Website-Kanal",
"DESC": "Erstellen Sie einen Kanal für Ihre Website und unterstützen Sie Ihre Kunden über unser Website-Widget.",
@@ -134,7 +138,7 @@
"PHONE_NUMBER": {
"LABEL": "Telefonnummer",
"PLACEHOLDER": "Bitte geben Sie die Telefonnummer ein, von der die Nachricht gesendet wird.",
"ERROR": "Please provide a valid phone number that starts with a `+` sign and does not contain any spaces."
"ERROR": "Bitte geben Sie eine gültige Telefonnummer an, die mit einem `+` Zeichen beginnt und keine Leerzeichen enthält."
},
"API_CALLBACK": {
"TITLE": "Callback URL",
@@ -185,7 +189,7 @@
"PHONE_NUMBER": {
"LABEL": "Telefonnummer",
"PLACEHOLDER": "Bitte geben Sie die Telefonnummer ein, von der die Nachricht gesendet wird.",
"ERROR": "Please provide a valid phone number that starts with a `+` sign and does not contain any spaces."
"ERROR": "Bitte geben Sie eine gültige Telefonnummer an, die mit einem `+` Zeichen beginnt und keine Leerzeichen enthält."
},
"SUBMIT_BUTTON": "Bitte geben Sie Ihre Bandbreitenanwendungs-ID ein",
"API": {
@@ -214,7 +218,7 @@
"PHONE_NUMBER": {
"LABEL": "Telefonnummer",
"PLACEHOLDER": "Bitte geben Sie die Telefonnummer ein, von der die Nachricht gesendet wird.",
"ERROR": "Please provide a valid phone number that starts with a `+` sign and does not contain any spaces."
"ERROR": "Bitte geben Sie eine gültige Telefonnummer an, die mit einem `+` Zeichen beginnt und keine Leerzeichen enthält."
},
"PHONE_NUMBER_ID": {
"LABEL": "Telefonnummer-ID",
@@ -548,6 +552,10 @@
},
"ENABLE_SSL": "SSL aktivieren"
},
"MICROSOFT": {
"TITLE": "Microsoft",
"SUBTITLE": "Reauthorize your MICROSOFT account"
},
"SMTP": {
"TITLE": "SMTP",
"SUBTITLE": "Setzen Sie Ihre SMTP-Details",

View File

@@ -76,6 +76,13 @@
"BODY": "<br/><p>Chatwoot wird nun alle eingehenden Konversationen in den <b><i>Kundengespräche</i></b> Channel innerhalb Ihres Slack Arbeitsplatzes synchronisieren.</p><p>Wenn Sie in <b><i>Kunden-Konversationen</i></b> antworten, wird der Slack Kanal eine Antwort an den Kunden durch Chat erzeugen.</p><p>Starten Sie die Antworten mit <b><i>Notiz:</i></b> um private Notizen anstatt Antworten zu erstellen.</p><p>Wenn der Replier auf Slack ein Agentenprofil im Chatwoot unter der gleichen E-Mail hat, werden die Antworten entsprechend assoziiert.</p><p>Wenn der Replier kein Agentenprofil hat, werden die Antworten aus dem Bot-Profil getätigt.</p>"
}
},
"DYTE": {
"CLICK_HERE_TO_JOIN": "Click here to join",
"LEAVE_THE_ROOM": "Leave the room",
"START_VIDEO_CALL_HELP_TEXT": "Start a new video call with the customer",
"JOIN_ERROR": "There was an error joining the call, please try again",
"CREATE_ERROR": "There was an error creating a meeting link, please try again"
},
"DELETE": {
"BUTTON_TEXT": "Löschen",
"API": {

View File

@@ -282,6 +282,7 @@
}
},
"KEYBOARD_SHORTCUTS": {
"TOGGLE_MODAL": "View all shortcuts",
"TITLE": {
"OPEN_CONVERSATION": "Unterhaltung öffnen",
"RESOLVE_AND_NEXT": "Lösen und zum Nächsten gehen",

View File

@@ -24,8 +24,11 @@
"TITLE": "Επιλέξτε ενός Agent Bot",
"DESC": "Μπορείτε να ορίσετε ένα agent bot από τη λίστα σε αυτά τα εισερχόμενα. Το bot μπορεί αρχικά να χειριστεί τη συνομιλία και να την μεταφέρει σε έναν πράκτορα όταν χρειάζεται.",
"SUBMIT": "Ενημέρωση",
"DISCONNECT": "Disconnect Bot",
"SUCCESS_MESSAGE": "Επιτυχής ενημέρωση του agent bot",
"DISCONNECTED_SUCCESS_MESSAGE": "Successfully disconnected the agent bot",
"ERROR_MESSAGE": "Δεν ήταν δυνατή η ενημέρωση του agent bot, δοκιμάστε ξανά αργότερα",
"DISCONNECTED_ERROR_MESSAGE": "Could not disconnect the agent bot, please try again later",
"SELECT_PLACEHOLDER": "Επιλογή Bot"
},
"ADD": {

View File

@@ -42,8 +42,8 @@
}
},
"API": {
"SUCCESS_MESSAGE": "Η ιδιότητα προστέθηκε με επιτυχία",
"ERROR_MESSAGE": "Δεν ήταν δυνατή η δημιουργία Ιδιότητας, Παρακαλώ δοκιμάστε ξανά αργότερα"
"SUCCESS_MESSAGE": "Η ιδιότητα προστέθηκε με επιτυχία!",
"ERROR_MESSAGE": "Δεν ήταν δυνατή η δημιουργία Ιδιότητας, Παρακαλώ δοκιμάστε ξανά αργότερα."
}
},
"DELETE": {

View File

@@ -53,6 +53,10 @@
"ENABLE": "Δημιουργία συνομιλιών από τα αναφερόμενα Tweets"
}
},
"MICROSOFT": {
"HELP": "To add your Microsoft account as a channel, you need to authenticate your Microsoft account by clicking on 'Sign in with Microsoft' ",
"ERROR_MESSAGE": "There was an error connecting to Microsoft, please try again"
},
"WEBSITE_CHANNEL": {
"TITLE": "Κανάλι Ιστοσελίδας",
"DESC": "Δημιουργήστε ένα κανάλι Ιστοσελίδα για να υποστηρίξετε τους πελάτες σας μέσω του πρόσθετου επικοινωνίας (widget) που θα εγκαταστήσετε στην ιστοσελίδα σας.",
@@ -548,6 +552,10 @@
},
"ENABLE_SSL": "Ενεργοποίηση SSL"
},
"MICROSOFT": {
"TITLE": "Microsoft",
"SUBTITLE": "Reauthorize your MICROSOFT account"
},
"SMTP": {
"TITLE": "SMTP",
"SUBTITLE": "Ορισμός λεπτομερειών SMTP",

View File

@@ -76,6 +76,13 @@
"BODY": "<br/><p>Το Chatwoot θα συγχρονίσει τώρα όλες τις εισερχόμενες συνομιλίες στο κανάλι <b><i>πελατών-συνομιλιών</i></b> μέσα στο slack χώρο εργασίας σας.</p><p>Απάντηση σε μια συνομιλία από <b><i>συνομιλίες πελατών</i></b> το κανάλι slack θα δημιουργήσει μια απάντηση για στον πελάτη μέσω chatwoot.</p><p>Ξεκινήστε τις απαντήσεις με το <b><i>note:</i></b> για να δημιουργήσετε ιδιωτικές σημειώσεις αντί για απαντήσεις.</p><p>Αν ο χρήστης στο slack έχει προφίλ πράκτορα στο chatwoot με το ίδιο email, οι απαντήσεις θα συσχετιστούν ανάλογα.</p><p>Εφόσον δεν έχει προφίλ συνδεδεμένου πράκτορα, οι απαντήσεις θα γίνουν από το προφίλ bot.</p>"
}
},
"DYTE": {
"CLICK_HERE_TO_JOIN": "Κάντε κλικ εδώ για να συμμετάσχετε",
"LEAVE_THE_ROOM": "Αποχώρηση",
"START_VIDEO_CALL_HELP_TEXT": "Ξεκινήστε μια νέα βιντεοκλήση με τον πελάτη",
"JOIN_ERROR": "Παρουσιάστηκε σφάλμα κατά τη σύνδεση της κλήσης, παρακαλώ προσπαθήστε ξανά",
"CREATE_ERROR": "Παρουσιάστηκε σφάλμα κατά τη δημιουργία ενός συνδέσμου συνάντησης, παρακαλώ προσπαθήστε ξανά"
},
"DELETE": {
"BUTTON_TEXT": "Διαγραφή",
"API": {

View File

@@ -282,6 +282,7 @@
}
},
"KEYBOARD_SHORTCUTS": {
"TOGGLE_MODAL": "Εμφάνιση όλων των συντομεύσεων",
"TITLE": {
"OPEN_CONVERSATION": "Άνοιγμα συνομιλίας",
"RESOLVE_AND_NEXT": "Επίλυση και μετακίνηση στην επόμενη",

View File

@@ -24,8 +24,11 @@
"TITLE": "Select an agent bot",
"DESC": "You can set an agent bot from the list to this inbox. The bot can initially handle the conversation and transfer it to an agent when needed.",
"SUBMIT": "Update",
"DISCONNECT": "Disconnect Bot",
"SUCCESS_MESSAGE": "Successfully updated the agent bot",
"DISCONNECTED_SUCCESS_MESSAGE": "Successfully disconnected the agent bot",
"ERROR_MESSAGE": "Could not update the agent bot, please try again later",
"DISCONNECTED_ERROR_MESSAGE": "Could not disconnect the agent bot, please try again later",
"SELECT_PLACEHOLDER": "Select Bot"
},
"ADD": {

View File

@@ -42,8 +42,8 @@
}
},
"API": {
"SUCCESS_MESSAGE": "Custom Attribute added successfully",
"ERROR_MESSAGE": "Could not able to create a custom attribute, Please try again later"
"SUCCESS_MESSAGE": "Custom Attribute added successfully!",
"ERROR_MESSAGE": "Could not create a Custom Attribute. Please try again later."
}
},
"DELETE": {

View File

@@ -214,7 +214,7 @@
"PHONE_NUMBER": {
"LABEL": "Phone number",
"PLACEHOLDER": "Please enter the phone number from which message will be sent.",
"ERROR": "Please provide a valid phone number that starts with a `+` sign and does not contain any spaces."
"ERROR": "Please provide a valid phone number that starts with a `+` sign and does not contain any spaces."
},
"PHONE_NUMBER_ID": {
"LABEL": "Phone number ID",
@@ -344,6 +344,17 @@
"FINISH": {
"TITLE": "Nailed It!",
"DESC": "You have successfully finished integrating your Facebook Page with Chatwoot. Next time a customer messages your Page, the conversation will automatically appear on your inbox.<br>We are also providing you with a widget script that you can easily add to your website. Once this is live on your website, customers can message you right from your website without the help of any external tool and the conversation will appear right here, on Chatwoot.<br>Cool, huh? Well, we sure try to be :)"
},
"EMAIL_PROVIDER": {
"TITLE": "Select your email provider",
"DESCRIPTION": "Select an email provider from the list below. If you don't see your email provider in the list, you can select the other provider option and provide the IMAP and SMTP Credentials."
},
"MICROSOFT": {
"TITLE": "Microsoft Email",
"DESCRIPTION": "Click on the Sign in with Microsoft button to get started. You will redirected to the email sign in page. Once you accept the requested permissions, you would be redirected back to the inbox creation step.",
"EMAIL_PLACEHOLDER": "Enter email address",
"HELP": "To add your Microsoft account as a channel, you need to authenticate your Microsoft account by clicking on 'Sign in with Microsoft' ",
"ERROR_MESSAGE": "There was an error connecting to Microsoft, please try again"
}
},
"DETAILS": {
@@ -548,6 +559,10 @@
},
"ENABLE_SSL": "Enable SSL"
},
"MICROSOFT": {
"TITLE": "Microsoft",
"SUBTITLE": "Reauthorize your MICROSOFT account"
},
"SMTP": {
"TITLE": "SMTP",
"SUBTITLE": "Set your SMTP details",
@@ -666,6 +681,10 @@
},
"BRANDING_TEXT": "Powered by Chatwoot",
"SCRIPT_SETTINGS": "\n window.chatwootSettings = {options};"
},
"EMAIL_PROVIDERS": {
"MICROSOFT": "Microsoft",
"OTHER_PROVIDERS": "Other Providers"
}
}
}

View File

@@ -35,10 +35,7 @@
"LIST": {
"404": "There are no webhooks configured for this account.",
"TITLE": "Manage webhooks",
"TABLE_HEADER": [
"Webhook endpoint",
"Actions"
]
"TABLE_HEADER": ["Webhook endpoint", "Actions"]
},
"EDIT": {
"BUTTON_TEXT": "Edit",
@@ -76,6 +73,13 @@
"BODY": "<br/><p>Chatwoot will now sync all the incoming conversations into the <b><i>customer-conversations</i></b> channel inside your slack workplace.</p><p>Replying to a conversation thread in <b><i>customer-conversations</i></b> slack channel will create a response back to the customer through chatwoot.</p><p>Start the replies with <b><i>note:</i></b> to create private notes instead of replies.</p><p>If the replier on slack has an agent profile in chatwoot under the same email, the replies will be associated accordingly.</p><p>When the replier doesn't have an associated agent profile, the replies will be made from the bot profile.</p>"
}
},
"DYTE": {
"CLICK_HERE_TO_JOIN": "Click here to join",
"LEAVE_THE_ROOM": "Leave the room",
"START_VIDEO_CALL_HELP_TEXT": "Start a new video call with the customer",
"JOIN_ERROR": "There was an error joining the call, please try again",
"CREATE_ERROR": "There was an error creating a meeting link, please try again"
},
"DELETE": {
"BUTTON_TEXT": "Delete",
"API": {
@@ -93,10 +97,7 @@
"LIST": {
"404": "There are no dashboard apps configured on this account yet",
"LOADING": "Fetching dashboard apps...",
"TABLE_HEADER": [
"Name",
"Endpoint"
],
"TABLE_HEADER": ["Name", "Endpoint"],
"EDIT_TOOLTIP": "Edit app",
"DELETE_TOOLTIP": "Delete app"
},

View File

@@ -158,7 +158,7 @@
"COMPONENTS": {
"CODE": {
"BUTTON_TEXT": "Copy",
"COPY_SUCCESSFUL": "Code copied to clipboard successfully"
"COPY_SUCCESSFUL": "Copied to clipboard"
},
"SHOW_MORE_BLOCK": {
"SHOW_MORE": "Show More",

View File

@@ -24,8 +24,11 @@
"TITLE": "Seleccione un bot de agente",
"DESC": "Puedes establecer un bot de agente desde la lista a esta bandeja de entrada. El bot puede inicialmente manejar la conversación y transferirla a un agente cuando sea necesario.",
"SUBMIT": "Actualizar",
"DISCONNECT": "Desconectar Bot",
"SUCCESS_MESSAGE": "El bot del agente se ha actualizado con éxito",
"DISCONNECTED_SUCCESS_MESSAGE": "Desconectado correctamente el bot agente",
"ERROR_MESSAGE": "No se pudo actualizar el bot de agente, por favor inténtalo de nuevo más tarde",
"DISCONNECTED_ERROR_MESSAGE": "No se pudo desconectar el bot de agente, por favor inténtalo de nuevo más tarde",
"SELECT_PLACEHOLDER": "Seleccionar bot"
},
"ADD": {

View File

@@ -42,8 +42,8 @@
}
},
"API": {
"SUCCESS_MESSAGE": "Atributo personalizado añadido correctamente",
"ERROR_MESSAGE": "No se pudo crear un atributo personalizado, por favor inténtalo de nuevo"
"SUCCESS_MESSAGE": "Atributo personalizado añadido correctamente!",
"ERROR_MESSAGE": "Could not create a Custom Attribute. Please try again later."
}
},
"DELETE": {

View File

@@ -53,6 +53,10 @@
"ENABLE": "Crear conversaciones de los Tweets mencionados"
}
},
"MICROSOFT": {
"HELP": "To add your Microsoft account as a channel, you need to authenticate your Microsoft account by clicking on 'Sign in with Microsoft' ",
"ERROR_MESSAGE": "There was an error connecting to Microsoft, please try again"
},
"WEBSITE_CHANNEL": {
"TITLE": "Canal del sitio web",
"DESC": "Cree un canal para su sitio web y comience a apoyar a sus clientes a través de nuestro widget de sitio web.",
@@ -548,6 +552,10 @@
},
"ENABLE_SSL": "Activar SSL"
},
"MICROSOFT": {
"TITLE": "Microsoft",
"SUBTITLE": "Reauthorize your MICROSOFT account"
},
"SMTP": {
"TITLE": "SMTP",
"SUBTITLE": "Configura tus detalles de SMTP",

View File

@@ -76,6 +76,13 @@
"BODY": "<br/><p>Chatwoot ahora sincronizará todas las conversaciones entrantes en el canal <b><i>de conversaciones del cliente</i></b> dentro de tu lugar de trabajo slack.</p><p>Respondiendo a un tema de conversación en <b><i>conversaciones de clientes</i></b> canal de slack creará una respuesta al cliente a través de chatwoot.</p><p>Inicie las respuestas con <b><i>nota:</i></b> para crear notas privadas en lugar de respuestas.</p><p>Si el respondente de slack tiene un perfil de agente en el chatwoot bajo el mismo correo electrónico, las respuestas se asociarán en consecuencia.</p><p>Cuando el replicador no tiene un perfil de agente asociado, las respuestas se harán con el perfil del bot.</p>"
}
},
"DYTE": {
"CLICK_HERE_TO_JOIN": "Click here to join",
"LEAVE_THE_ROOM": "Leave the room",
"START_VIDEO_CALL_HELP_TEXT": "Start a new video call with the customer",
"JOIN_ERROR": "There was an error joining the call, please try again",
"CREATE_ERROR": "There was an error creating a meeting link, please try again"
},
"DELETE": {
"BUTTON_TEXT": "Eliminar",
"API": {

View File

@@ -282,6 +282,7 @@
}
},
"KEYBOARD_SHORTCUTS": {
"TOGGLE_MODAL": "View all shortcuts",
"TITLE": {
"OPEN_CONVERSATION": "Abrir conversación",
"RESOLVE_AND_NEXT": "Resolver y pasar al siguiente",

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