diff --git a/.circleci/config.yml b/.circleci/config.yml
index f8ffdf076..c5a6430a3 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -7,7 +7,7 @@ defaults: &defaults
working_directory: ~/build
docker:
# specify the version you desire here
- - image: circleci/ruby:3.0.2-node-browsers
+ - image: cimg/ruby:3.0.2-node
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
@@ -40,20 +40,20 @@ jobs:
- restore_cache:
keys:
- - chatwoot-bundle-{{ checksum "Gemfile.lock" }}
+ - chatwoot-bundle-{{ .Environment.CACHE_VERSION }}-{{ checksum "Gemfile.lock" }}
- chatwoot-bundle
- run: bundle install --frozen --path ~/.bundle
- save_cache:
paths:
- ~/.bundle
- key: chatwoot-bundle-{{ checksum "Gemfile.lock" }}
+ key: chatwoot-bundle-{{ .Environment.CACHE_VERSION }}-{{ checksum "Gemfile.lock" }}
# Only necessary if app uses webpacker or yarn in some other way
- restore_cache:
keys:
- - chatwoot-yarn-{{ checksum "yarn.lock" }}
+ - chatwoot-yarn-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }}
- chatwoot-yarn-
- run:
@@ -62,7 +62,7 @@ jobs:
# Store yarn / webpacker cache
- save_cache:
- key: chatwoot-yarn-{{ checksum "yarn.lock" }}
+ key: chatwoot-yarn-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }}
paths:
- ~/.cache/yarn
diff --git a/.env.example b/.env.example
index eb41a88f5..39a533355 100644
--- a/.env.example
+++ b/.env.example
@@ -85,8 +85,6 @@ AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=
-# Sentry
-SENTRY_DSN=
# Log settings
# Disable if you want to write logs to a file
@@ -139,6 +137,25 @@ ANDROID_SHA256_CERT_FINGERPRINT=AC:73:8E:DE:EB:56:EA:CC:10:87:02:A7:65:37:7B:38:
USE_INBOX_AVATAR_FOR_BOT=true
+### APM and Error Monitoring configurations
+## Sentry
+# SENTRY_DSN=
+
+## Scout
+## https://scoutapm.com/docs/ruby/configuration
+# SCOUT_KEY=YOURKEY
+# SCOUT_NAME=YOURAPPNAME (Production)
+# SCOUT_MONITOR=true
+
+## NewRelic
+# https://docs.newrelic.com/docs/agents/ruby-agent/configuration/ruby-agent-configuration/
+# NEW_RELIC_LICENSE_KEY=
+
+## Datadog
+## https://github.com/DataDog/dd-trace-rb/blob/master/docs/GettingStarted.md#environment-variables
+# DD_TRACE_AGENT_URL=
+
+
## IP look up configuration
## ref https://github.com/alexreisner/geocoder/blob/master/README_API_GUIDE.md
diff --git a/.rubocop.yml b/.rubocop.yml
index c05cbb9bf..76ef5fcfc 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -100,6 +100,7 @@ Metrics/AbcSize:
- 'app/controllers/concerns/auth_helper.rb'
- 'db/migrate/20190819005836_add_missing_indexes_on_taggings.acts_as_taggable_on_engine.rb'
- 'db/migrate/20161123131628_devise_token_auth_create_users.rb'
+ - 'app/controllers/api/v1/accounts/inboxes_controller.rb'
Metrics/CyclomaticComplexity:
Max: 7
Exclude:
diff --git a/Gemfile b/Gemfile
index c172b7d08..1dddb482c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -63,7 +63,7 @@ gem 'barnes'
##--- gems for authentication & authorization ---##
gem 'devise'
-gem 'devise-secure_password', '~> 2.0'
+gem 'devise-secure_password', '~> 2.0', git: 'https://github.com/chatwoot/devise-secure_password'
gem 'devise_token_auth'
# authorization
gem 'jwt'
@@ -78,7 +78,7 @@ gem 'wisper', '2.0.0'
##--- gems for channels ---##
# TODO: bump up gem to 2.0
gem 'facebook-messenger'
-gem 'telegram-bot-ruby'
+gem 'line-bot-api'
gem 'twilio-ruby', '~> 5.32.0'
# twitty will handle subscription of twitter account events
# gem 'twitty', git: 'https://github.com/chatwoot/twitty'
@@ -93,7 +93,10 @@ gem 'google-cloud-dialogflow'
##--- gems for debugging and error reporting ---##
# static analysis
gem 'brakeman'
+
+##-- apm and error monitoring ---#
gem 'ddtrace'
+gem 'newrelic_rpm'
gem 'scout_apm'
gem 'sentry-rails'
gem 'sentry-ruby'
diff --git a/Gemfile.lock b/Gemfile.lock
index 30c6c022a..45a7b9133 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,63 +1,71 @@
+GIT
+ remote: https://github.com/chatwoot/devise-secure_password
+ revision: de11e8765654b8242d42101ee9c8ffc8126f7975
+ specs:
+ devise-secure_password (2.0.1)
+ devise (>= 4.0.0, < 5.0.0)
+ railties (>= 5.0.0, < 7.0.0)
+
GEM
remote: https://rubygems.org/
specs:
- actioncable (6.1.4)
- actionpack (= 6.1.4)
- activesupport (= 6.1.4)
+ actioncable (6.1.4.1)
+ actionpack (= 6.1.4.1)
+ activesupport (= 6.1.4.1)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
- actionmailbox (6.1.4)
- actionpack (= 6.1.4)
- activejob (= 6.1.4)
- activerecord (= 6.1.4)
- activestorage (= 6.1.4)
- activesupport (= 6.1.4)
+ actionmailbox (6.1.4.1)
+ actionpack (= 6.1.4.1)
+ activejob (= 6.1.4.1)
+ activerecord (= 6.1.4.1)
+ activestorage (= 6.1.4.1)
+ activesupport (= 6.1.4.1)
mail (>= 2.7.1)
- actionmailer (6.1.4)
- actionpack (= 6.1.4)
- actionview (= 6.1.4)
- activejob (= 6.1.4)
- activesupport (= 6.1.4)
+ actionmailer (6.1.4.1)
+ actionpack (= 6.1.4.1)
+ actionview (= 6.1.4.1)
+ activejob (= 6.1.4.1)
+ activesupport (= 6.1.4.1)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
- actionpack (6.1.4)
- actionview (= 6.1.4)
- activesupport (= 6.1.4)
+ actionpack (6.1.4.1)
+ actionview (= 6.1.4.1)
+ activesupport (= 6.1.4.1)
rack (~> 2.0, >= 2.0.9)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
- actiontext (6.1.4)
- actionpack (= 6.1.4)
- activerecord (= 6.1.4)
- activestorage (= 6.1.4)
- activesupport (= 6.1.4)
+ actiontext (6.1.4.1)
+ actionpack (= 6.1.4.1)
+ activerecord (= 6.1.4.1)
+ activestorage (= 6.1.4.1)
+ activesupport (= 6.1.4.1)
nokogiri (>= 1.8.5)
- actionview (6.1.4)
- activesupport (= 6.1.4)
+ actionview (6.1.4.1)
+ activesupport (= 6.1.4.1)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0)
active_record_query_trace (1.8)
- activejob (6.1.4)
- activesupport (= 6.1.4)
+ activejob (6.1.4.1)
+ activesupport (= 6.1.4.1)
globalid (>= 0.3.6)
- activemodel (6.1.4)
- activesupport (= 6.1.4)
- activerecord (6.1.4)
- activemodel (= 6.1.4)
- activesupport (= 6.1.4)
+ activemodel (6.1.4.1)
+ activesupport (= 6.1.4.1)
+ activerecord (6.1.4.1)
+ activemodel (= 6.1.4.1)
+ activesupport (= 6.1.4.1)
activerecord-import (1.2.0)
activerecord (>= 3.2)
- activestorage (6.1.4)
- actionpack (= 6.1.4)
- activejob (= 6.1.4)
- activerecord (= 6.1.4)
- activesupport (= 6.1.4)
+ activestorage (6.1.4.1)
+ actionpack (= 6.1.4.1)
+ activejob (= 6.1.4.1)
+ activerecord (= 6.1.4.1)
+ activesupport (= 6.1.4.1)
marcel (~> 1.0.0)
mini_mime (>= 1.1.0)
- activesupport (6.1.4)
+ activesupport (6.1.4.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
@@ -98,10 +106,6 @@ GEM
aws-sigv4 (~> 1.1)
aws-sigv4 (1.2.4)
aws-eventstream (~> 1, >= 1.0.2)
- axiom-types (0.1.1)
- descendants_tracker (~> 0.0.4)
- ice_nine (~> 0.11.0)
- thread_safe (~> 0.3, >= 0.3.1)
azure-storage-blob (2.0.1)
azure-storage-common (~> 2.0)
nokogiri (~> 1.11.0.rc2)
@@ -115,7 +119,7 @@ GEM
statsd-ruby (~> 1.1)
bcrypt (3.1.16)
bindex (0.8.1)
- bootsnap (1.7.6)
+ bootsnap (1.7.7)
msgpack (~> 1.0)
brakeman (5.1.1)
browser (5.3.1)
@@ -130,8 +134,6 @@ GEM
thor (~> 1.0)
byebug (11.1.3)
coderay (1.1.3)
- coercible (1.0.0)
- descendants_tracker (~> 0.0.1)
commonmarker (0.22.0)
concurrent-ruby (1.1.9)
connection_pool (2.2.5)
@@ -152,17 +154,12 @@ GEM
ffi (~> 1.0)
msgpack
declarative (0.0.20)
- descendants_tracker (0.0.4)
- thread_safe (~> 0.3, >= 0.3.1)
devise (4.8.0)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
- devise-secure_password (2.0.1)
- devise (>= 4.0.0, < 5.0.0)
- railties (>= 5.0.0, < 7.0.0)
devise_token_auth (1.2.0)
bcrypt (~> 3.0)
devise (> 3.5.2, < 5)
@@ -179,7 +176,6 @@ GEM
railties (>= 3.2)
down (5.2.3)
addressable (~> 2.8)
- dry-inflector (0.2.1)
ecma-re-validator (0.3.0)
regexp_parser (~> 2.0)
erubi (1.10.0)
@@ -216,7 +212,7 @@ GEM
grpc (~> 1.25)
geocoder (1.6.7)
gli (2.20.1)
- globalid (0.5.1)
+ globalid (0.5.2)
activesupport (>= 5.0)
google-apis-core (0.4.1)
addressable (~> 2.5, >= 2.5.1)
@@ -292,7 +288,6 @@ GEM
httpclient (2.8.3)
i18n (1.8.10)
concurrent-ruby (~> 1.0)
- ice_nine (0.11.2)
image_processing (1.12.1)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
@@ -332,11 +327,12 @@ GEM
addressable (~> 2.7)
letter_opener (1.7.0)
launchy (~> 2.2)
+ line-bot-api (1.21.0)
liquid (5.0.1)
listen (3.6.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
- loofah (2.11.0)
+ loofah (2.12.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
@@ -349,7 +345,7 @@ GEM
mime-types-data (~> 3.2015)
mime-types-data (3.2021.0704)
mini_magick (4.11.0)
- mini_mime (1.1.0)
+ mini_mime (1.1.1)
minitest (5.14.4)
mock_redis (0.28.0)
ruby2_keywords
@@ -362,7 +358,8 @@ GEM
net-http-persistent (4.0.1)
connection_pool (~> 2.2)
netrc (0.11.0)
- nio4r (2.5.7)
+ newrelic_rpm (7.2.0)
+ nio4r (2.5.8)
nokogiri (1.11.7-arm64-darwin)
racc (~> 1.4)
nokogiri (1.11.7-x86_64-darwin)
@@ -400,29 +397,29 @@ GEM
rack-test (1.1.0)
rack (>= 1.0, < 3)
rack-timeout (0.6.0)
- rails (6.1.4)
- actioncable (= 6.1.4)
- actionmailbox (= 6.1.4)
- actionmailer (= 6.1.4)
- actionpack (= 6.1.4)
- actiontext (= 6.1.4)
- actionview (= 6.1.4)
- activejob (= 6.1.4)
- activemodel (= 6.1.4)
- activerecord (= 6.1.4)
- activestorage (= 6.1.4)
- activesupport (= 6.1.4)
+ rails (6.1.4.1)
+ actioncable (= 6.1.4.1)
+ actionmailbox (= 6.1.4.1)
+ actionmailer (= 6.1.4.1)
+ actionpack (= 6.1.4.1)
+ actiontext (= 6.1.4.1)
+ actionview (= 6.1.4.1)
+ activejob (= 6.1.4.1)
+ activemodel (= 6.1.4.1)
+ activerecord (= 6.1.4.1)
+ activestorage (= 6.1.4.1)
+ activesupport (= 6.1.4.1)
bundler (>= 1.15.0)
- railties (= 6.1.4)
+ railties (= 6.1.4.1)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
- rails-html-sanitizer (1.3.0)
+ rails-html-sanitizer (1.4.1)
loofah (~> 2.3)
- railties (6.1.4)
- actionpack (= 6.1.4)
- activesupport (= 6.1.4)
+ railties (6.1.4.1)
+ actionpack (= 6.1.4.1)
+ activesupport (= 6.1.4.1)
method_source
rake (>= 0.13)
thor (~> 1.0)
@@ -563,13 +560,8 @@ GEM
sprockets (>= 3.0.0)
squasher (0.6.2)
statsd-ruby (1.5.0)
- telegram-bot-ruby (0.16.0)
- dry-inflector
- faraday
- virtus (~> 2.0)
telephone_number (1.4.12)
thor (1.1.0)
- thread_safe (0.3.6)
tilt (2.0.10)
time_diff (0.3.0)
activesupport
@@ -597,10 +589,6 @@ GEM
valid_email2 (4.0.0)
activemodel (>= 3.2)
mail (~> 2.5)
- virtus (2.0.0)
- axiom-types (~> 0.1)
- coercible (~> 1.0)
- descendants_tracker (~> 0.0, >= 0.0.3)
warden (1.2.9)
rack (>= 2.0.9)
web-console (4.1.0)
@@ -629,6 +617,8 @@ GEM
PLATFORMS
arm64-darwin-20
+ x86_64-darwin-18
+ x86_64-darwin-20
x86_64-darwin-21
x86_64-linux
@@ -653,7 +643,7 @@ DEPENDENCIES
database_cleaner
ddtrace
devise
- devise-secure_password (~> 2.0)
+ devise-secure_password (~> 2.0)!
devise_token_auth
dotenv-rails
down (~> 5.0)
@@ -678,10 +668,12 @@ DEPENDENCIES
kaminari
koala
letter_opener
+ line-bot-api
liquid
listen
maxminddb
mock_redis
+ newrelic_rpm
pg
procore-sift
pry-rails
@@ -713,7 +705,6 @@ DEPENDENCIES
spring
spring-watcher-listen
squasher
- telegram-bot-ruby
telephone_number
time_diff
twilio-ruby (~> 5.32.0)
diff --git a/README.md b/README.md
index 2720de61e..41f15553d 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,8 @@ ___
+
+
diff --git a/app/actions/contact_merge_action.rb b/app/actions/contact_merge_action.rb
index 3a3ef11ed..f20e2ffb4 100644
--- a/app/actions/contact_merge_action.rb
+++ b/app/actions/contact_merge_action.rb
@@ -1,4 +1,5 @@
class ContactMergeAction
+ include Events::Types
pattr_initialize [:account!, :base_contact!, :mergee_contact!]
def perform
@@ -11,7 +12,7 @@ class ContactMergeAction
merge_conversations
merge_messages
merge_contact_inboxes
- remove_mergee_contact
+ merge_and_remove_mergee_contact
end
@base_contact
end
@@ -40,7 +41,18 @@ class ContactMergeAction
ContactInbox.where(contact_id: @mergee_contact.id).update(contact_id: @base_contact.id)
end
- def remove_mergee_contact
+ def merge_and_remove_mergee_contact
+ mergable_attribute_keys = %w[identifier name email phone_number custom_attributes]
+ base_contact_attributes = base_contact.attributes.slice(*mergable_attribute_keys).compact_blank
+ mergee_contact_attributes = mergee_contact.attributes.slice(*mergable_attribute_keys).compact_blank
+
+ # attributes in base contact are given preference
+ merged_attributes = mergee_contact_attributes.deep_merge(base_contact_attributes)
+ # retaining old pubsub token to notify the contacts that are listening
+ mergee_pubsub_token = mergee_contact.pubsub_token
+
@mergee_contact.destroy!
+ Rails.configuration.dispatcher.dispatch(CONTACT_MERGED, Time.zone.now, contact: @base_contact, tokens: [mergee_pubsub_token])
+ @base_contact.update!(merged_attributes)
end
end
diff --git a/app/assets/stylesheets/administrate/utilities/_variables.scss b/app/assets/stylesheets/administrate/utilities/_variables.scss
index c46326612..db8d1a302 100644
--- a/app/assets/stylesheets/administrate/utilities/_variables.scss
+++ b/app/assets/stylesheets/administrate/utilities/_variables.scss
@@ -43,7 +43,7 @@ $woot-logo-padding: $space-large $space-two;
// Colors
$color-woot: #1f93ff;
$color-gray: #6e6f73;
-$color-light-gray: #999a9b;
+$color-light-gray: #747677;
$color-border: #e0e6ed;
$color-border-light: #f0f4f5;
$color-background: #f4f6fb;
diff --git a/app/builders/messages/facebook/message_builder.rb b/app/builders/messages/facebook/message_builder.rb
index 23c9d92b4..4ffb4b101 100644
--- a/app/builders/messages/facebook/message_builder.rb
+++ b/app/builders/messages/facebook/message_builder.rb
@@ -148,6 +148,14 @@ class Messages::Facebook::MessageBuilder
}
end
+ def process_contact_params_result(result)
+ {
+ name: "#{result['first_name'] || 'John'} #{result['last_name'] || 'Doe'}",
+ account_id: @inbox.account_id,
+ remote_avatar_url: result['profile_pic'] || ''
+ }
+ end
+
def contact_params
begin
k = Koala::Facebook::API.new(@inbox.channel.page_access_token) if @inbox.facebook?
@@ -155,14 +163,15 @@ class Messages::Facebook::MessageBuilder
rescue Koala::Facebook::AuthenticationError
@inbox.channel.authorization_error!
raise
+ rescue Koala::Facebook::ClientError => e
+ result = {}
+ # OAuthException, code: 100, error_subcode: 2018218, message: (#100) No profile available for this user
+ # We don't need to capture this error as we don't care about contact params in case of echo messages
+ Sentry.capture_exception(e) unless outgoing_echo?
rescue StandardError => e
result = {}
Sentry.capture_exception(e)
end
- {
- name: "#{result['first_name'] || 'John'} #{result['last_name'] || 'Doe'}",
- account_id: @inbox.account_id,
- remote_avatar_url: result['profile_pic'] || ''
- }
+ process_contact_params_result(result)
end
end
diff --git a/app/builders/messages/message_builder.rb b/app/builders/messages/message_builder.rb
index ba78d76d7..b6ae5409d 100644
--- a/app/builders/messages/message_builder.rb
+++ b/app/builders/messages/message_builder.rb
@@ -15,21 +15,25 @@ class Messages::MessageBuilder
def perform
@message = @conversation.messages.build(message_params)
- if @attachments.present?
- @attachments.each do |uploaded_attachment|
- attachment = @message.attachments.new(
- account_id: @message.account_id,
- file_type: file_type(uploaded_attachment&.content_type)
- )
- attachment.file.attach(uploaded_attachment)
- end
- end
- @message.save
+ process_attachments
+ @message.save!
@message
end
private
+ def process_attachments
+ return if @attachments.blank?
+
+ @attachments.each do |uploaded_attachment|
+ @message.attachments.build(
+ account_id: @message.account_id,
+ file_type: file_type(uploaded_attachment&.content_type),
+ file: uploaded_attachment
+ )
+ end
+ end
+
def message_type
if @conversation.inbox.channel_type != 'Channel::Api' && @message_type == 'incoming'
raise StandardError, 'Incoming messages are only allowed in Api inboxes'
diff --git a/app/builders/notification_subscription_builder.rb b/app/builders/notification_subscription_builder.rb
index c1574bfc1..af75ef2fd 100644
--- a/app/builders/notification_subscription_builder.rb
+++ b/app/builders/notification_subscription_builder.rb
@@ -4,7 +4,7 @@ class NotificationSubscriptionBuilder
def perform
# if multiple accounts were used to login in same browser
move_subscription_to_user if identifier_subscription && identifier_subscription.user_id != user.id
- build_identifier_subscription if identifier_subscription.blank?
+ identifier_subscription.blank? ? build_identifier_subscription : update_identifier_subscription
identifier_subscription
end
@@ -25,6 +25,10 @@ class NotificationSubscriptionBuilder
end
def build_identifier_subscription
- user.notification_subscriptions.create(params.merge(identifier: identifier))
+ @identifier_subscription = user.notification_subscriptions.create(params.merge(identifier: identifier))
+ end
+
+ def update_identifier_subscription
+ identifier_subscription.update(params.merge(identifier: identifier))
end
end
diff --git a/app/builders/v2/report_builder.rb b/app/builders/v2/report_builder.rb
index 2a7a55a8a..30804b8e8 100644
--- a/app/builders/v2/report_builder.rb
+++ b/app/builders/v2/report_builder.rb
@@ -32,9 +32,16 @@ class V2::ReportBuilder
private
def scope
- return account if params[:type].match?('account')
- return inbox if params[:type].match?('inbox')
- return user if params[:type].match?('agent')
+ case params[:type]
+ when :account
+ account
+ when :inbox
+ inbox
+ when :agent
+ user
+ when :label
+ label
+ end
end
def inbox
@@ -45,6 +52,10 @@ class V2::ReportBuilder
@user ||= account.users.where(id: params[:id]).first
end
+ def label
+ @label ||= account.labels.where(id: params[:id]).first
+ end
+
def conversations_count
scope.conversations
.group_by_day(:created_at, range: range, default_value: 0)
diff --git a/app/controllers/api/v1/accounts/contacts_controller.rb b/app/controllers/api/v1/accounts/contacts_controller.rb
index b9b9ffafe..444f0c918 100644
--- a/app/controllers/api/v1/accounts/contacts_controller.rb
+++ b/app/controllers/api/v1/accounts/contacts_controller.rb
@@ -79,6 +79,7 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
@resolved_contacts = Current.account.contacts
.where.not(email: [nil, ''])
.or(Current.account.contacts.where.not(phone_number: [nil, '']))
+ .or(Current.account.contacts.where.not(identifier: [nil, '']))
@resolved_contacts = @resolved_contacts.tagged_with(params[:labels], any: true) if params[:labels].present?
@resolved_contacts
end
diff --git a/app/controllers/api/v1/accounts/conversations/assignments_controller.rb b/app/controllers/api/v1/accounts/conversations/assignments_controller.rb
index 670abf37a..68ff2e67d 100644
--- a/app/controllers/api/v1/accounts/conversations/assignments_controller.rb
+++ b/app/controllers/api/v1/accounts/conversations/assignments_controller.rb
@@ -1,20 +1,34 @@
class Api::V1::Accounts::Conversations::AssignmentsController < Api::V1::Accounts::Conversations::BaseController
# assigns agent/team to a conversation
def create
- set_assignee
- render json: @assignee
+ if params.key?(:assignee_id)
+ set_agent
+ elsif params.key?(:team_id)
+ set_team
+ else
+ render json: nil
+ end
end
private
- def set_assignee
- # if params[:assignee_id] is not a valid id, it will set to nil, hence unassigning the conversation
- if params.key?(:assignee_id)
- @assignee = Current.account.users.find_by(id: params[:assignee_id])
- @conversation.update_assignee(@assignee)
- elsif params.key?(:team_id)
- @assignee = Current.account.teams.find_by(id: params[:team_id])
- @conversation.update!(team: @assignee)
+ def set_agent
+ @agent = Current.account.users.find_by(id: params[:assignee_id])
+ @conversation.update_assignee(@agent)
+ render_agent
+ end
+
+ def render_agent
+ if @agent.nil?
+ render json: nil
+ else
+ render partial: 'api/v1/models/agent', formats: [:json], locals: { resource: @agent }
end
end
+
+ def set_team
+ @team = Current.account.teams.find_by(id: params[:team_id])
+ @conversation.update!(team: @team)
+ render json: @team
+ end
end
diff --git a/app/controllers/api/v1/accounts/custom_attribute_definitions_controller.rb b/app/controllers/api/v1/accounts/custom_attribute_definitions_controller.rb
index 687da55bd..e02c090db 100644
--- a/app/controllers/api/v1/accounts/custom_attribute_definitions_controller.rb
+++ b/app/controllers/api/v1/accounts/custom_attribute_definitions_controller.rb
@@ -31,12 +31,13 @@ class Api::V1::Accounts::CustomAttributeDefinitionsController < Api::V1::Account
end
def fetch_custom_attribute_definition
- @custom_attribute_definition = @custom_attribute_definitions.find(permitted_params[:id])
+ @custom_attribute_definition = Current.account.custom_attribute_definitions.find(permitted_params[:id])
end
def permitted_payload
params.require(:custom_attribute_definition).permit(
:attribute_display_name,
+ :attribute_description,
:attribute_display_type,
:attribute_key,
:attribute_model,
@@ -45,6 +46,6 @@ class Api::V1::Accounts::CustomAttributeDefinitionsController < Api::V1::Account
end
def permitted_params
- params.permit(:id, :filter_type)
+ params.permit(:id, :filter_type, :attribute_model)
end
end
diff --git a/app/controllers/api/v1/accounts/inbox_members_controller.rb b/app/controllers/api/v1/accounts/inbox_members_controller.rb
index c5fb3486b..591aa5637 100644
--- a/app/controllers/api/v1/accounts/inbox_members_controller.rb
+++ b/app/controllers/api/v1/accounts/inbox_members_controller.rb
@@ -1,26 +1,40 @@
class Api::V1::Accounts::InboxMembersController < Api::V1::Accounts::BaseController
- before_action :fetch_inbox, only: [:create, :show]
- before_action :current_agents_ids, only: [:create]
+ before_action :fetch_inbox
+ before_action :current_agents_ids, only: [:update]
def create
authorize @inbox, :create?
- begin
- # update also done via same action
- update_agents_list
- head :ok
- rescue StandardError => e
- Rails.logger.debug { "Rescued: #{e.inspect}" }
- render_could_not_create_error('Could not add agents to inbox')
+ ActiveRecord::Base.transaction do
+ params[:user_ids].map { |user_id| @inbox.add_member(user_id) }
end
+ fetch_updated_agents
end
def show
authorize @inbox, :show?
- @agents = Current.account.users.where(id: @inbox.members.select(:user_id))
+ fetch_updated_agents
+ end
+
+ def update
+ authorize @inbox, :update?
+ update_agents_list
+ fetch_updated_agents
+ end
+
+ def destroy
+ authorize @inbox, :destroy?
+ ActiveRecord::Base.transaction do
+ params[:user_ids].map { |user_id| @inbox.remove_member(user_id) }
+ end
+ head :ok
end
private
+ def fetch_updated_agents
+ @agents = Current.account.users.where(id: @inbox.members.select(:user_id))
+ end
+
def update_agents_list
# get all the user_ids which the inbox currently has as members.
# get the list of user_ids from params
diff --git a/app/controllers/api/v1/accounts/inboxes_controller.rb b/app/controllers/api/v1/accounts/inboxes_controller.rb
index 2621a4a33..df055923c 100644
--- a/app/controllers/api/v1/accounts/inboxes_controller.rb
+++ b/app/controllers/api/v1/accounts/inboxes_controller.rb
@@ -1,12 +1,15 @@
class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
before_action :fetch_inbox, except: [:index, :create]
before_action :fetch_agent_bot, only: [:set_agent_bot]
- before_action :check_authorization
+ # we are already handling the authorization in fetch inbox
+ before_action :check_authorization, except: [:show]
def index
@inboxes = policy_scope(Current.account.inboxes.order_by_name.includes(:channel, { avatar_attachment: [:blob] }))
end
+ def show; end
+
def assignable_agents
@assignable_agents = (Current.account.users.where(id: @inbox.members.select(:user_id)) + Current.account.administrators).uniq
end
@@ -15,26 +18,32 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
@campaigns = @inbox.campaigns
end
+ def avatar
+ @inbox.avatar.attachment.destroy! if @inbox.avatar.attached?
+ head :ok
+ end
+
def create
ActiveRecord::Base.transaction do
channel = create_channel
@inbox = Current.account.inboxes.build(
- name: permitted_params[:name],
- greeting_message: permitted_params[:greeting_message],
- greeting_enabled: permitted_params[:greeting_enabled],
- channel: channel
+ {
+ name: inbox_name(channel),
+ channel: channel
+ }.merge(
+ permitted_params.except(:channel)
+ )
)
- @inbox.avatar.attach(permitted_params[:avatar])
@inbox.save!
end
end
def update
- @inbox.update(inbox_update_params.except(:channel))
+ @inbox.update(permitted_params.except(:channel))
@inbox.update_working_hours(params.permit(working_hours: Inbox::OFFISABLE_ATTRS)[:working_hours]) if params[:working_hours]
- return unless @inbox.channel.is_a?(Channel::WebWidget) && inbox_update_params[:channel].present?
- @inbox.channel.update!(inbox_update_params[:channel])
+ channel_attributes = get_channel_attributes(@inbox.channel_type)
+ @inbox.channel.update!(permitted_params(channel_attributes)[:channel]) if permitted_params(channel_attributes)[:channel].present?
update_channel_feature_flags
end
@@ -69,43 +78,57 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
@agent_bot = AgentBot.find(params[:agent_bot]) if params[:agent_bot]
end
+ def inbox_name(channel)
+ return channel.try(:bot_name) if channel.is_a?(Channel::Telegram)
+
+ permitted_params[:name]
+ end
+
def create_channel
case permitted_params[:channel][:type]
when 'web_widget'
- Current.account.web_widgets.create!(permitted_params[:channel].except(:type))
+ Current.account.web_widgets.create!(permitted_params(Channel::WebWidget::EDITABLE_ATTRS)[:channel].except(:type))
when 'api'
- Current.account.api_channels.create!(permitted_params[:channel].except(:type))
+ Current.account.api_channels.create!(permitted_params(Channel::Api::EDITABLE_ATTRS)[:channel].except(:type))
when 'email'
- Current.account.email_channels.create!(permitted_params[:channel].except(:type))
+ Current.account.email_channels.create!(permitted_params(Channel::Email::EDITABLE_ATTRS)[:channel].except(:type))
+ when 'line'
+ Current.account.line_channels.create!(permitted_params(Channel::Line::EDITABLE_ATTRS)[:channel].except(:type))
+ when 'telegram'
+ Current.account.telegram_channels.create!(permitted_params(Channel::Telegram::EDITABLE_ATTRS)[:channel].except(:type))
end
end
def update_channel_feature_flags
- return unless inbox_update_params[:channel].key? :selected_feature_flags
+ return unless @inbox.web_widget?
+ return unless permitted_params(Channel::WebWidget::EDITABLE_ATTRS)[:channel].key? :selected_feature_flags
- @inbox.channel.selected_feature_flags = inbox_update_params[:channel][:selected_feature_flags]
+ @inbox.channel.selected_feature_flags = permitted_params(Channel::WebWidget::EDITABLE_ATTRS)[:channel][:selected_feature_flags]
@inbox.channel.save!
end
- def permitted_params
- params.permit(:id, :avatar, :name, :greeting_message, :greeting_enabled, :enable_email_collect, :csat_survey_enabled, channel:
- [:type, :website_url, :widget_color, :welcome_title, :welcome_tagline, :webhook_url, :email, :reply_time])
+ def permitted_params(channel_attributes = [])
+ params.permit(
+ :name, :avatar, :greeting_enabled, :greeting_message, :enable_email_collect, :csat_survey_enabled,
+ :enable_auto_assignment, :working_hours_enabled, :out_of_office_message, :timezone,
+ channel: [:type, *channel_attributes]
+ )
end
- def inbox_update_params
- params.permit(:enable_auto_assignment, :enable_email_collect, :name, :avatar, :greeting_message, :greeting_enabled, :csat_survey_enabled,
- :working_hours_enabled, :out_of_office_message, :timezone,
- channel: [
- :website_url,
- :widget_color,
- :welcome_title,
- :welcome_tagline,
- :webhook_url,
- :email,
- :reply_time,
- :pre_chat_form_enabled,
- { pre_chat_form_options: [:pre_chat_message, :require_email] },
- { selected_feature_flags: [] }
- ])
+ def get_channel_attributes(channel_type)
+ case channel_type
+ when 'Channel::WebWidget'
+ Channel::WebWidget::EDITABLE_ATTRS
+ when 'Channel::Api'
+ Channel::Api::EDITABLE_ATTRS
+ when 'Channel::Email'
+ Channel::Email::EDITABLE_ATTRS
+ when 'Channel::Telegram'
+ Channel::Telegram::EDITABLE_ATTRS
+ when 'Channel::Line'
+ Channel::Line::EDITABLE_ATTRS
+ else
+ []
+ end
end
end
diff --git a/app/controllers/api/v1/widget/messages_controller.rb b/app/controllers/api/v1/widget/messages_controller.rb
index 9e6f770ad..0d9ab6323 100644
--- a/app/controllers/api/v1/widget/messages_controller.rb
+++ b/app/controllers/api/v1/widget/messages_controller.rb
@@ -8,8 +8,8 @@ class Api::V1::Widget::MessagesController < Api::V1::Widget::BaseController
def create
@message = conversation.messages.new(message_params)
- @message.save
build_attachment
+ @message.save!
end
def update
@@ -29,13 +29,12 @@ class Api::V1::Widget::MessagesController < Api::V1::Widget::BaseController
return if params[:message][:attachments].blank?
params[:message][:attachments].each do |uploaded_attachment|
- attachment = @message.attachments.new(
+ @message.attachments.new(
account_id: @message.account_id,
- file_type: helpers.file_type(uploaded_attachment&.content_type)
+ file_type: helpers.file_type(uploaded_attachment&.content_type),
+ file: uploaded_attachment
)
- attachment.file.attach(uploaded_attachment)
end
- @message.save!
end
def set_conversation
diff --git a/app/controllers/api/v2/accounts/reports_controller.rb b/app/controllers/api/v2/accounts/reports_controller.rb
index 8fc980255..af28fe544 100644
--- a/app/controllers/api/v2/accounts/reports_controller.rb
+++ b/app/controllers/api/v2/accounts/reports_controller.rb
@@ -1,14 +1,14 @@
class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController
before_action :check_authorization
- def account
- builder = V2::ReportBuilder.new(Current.account, account_report_params)
+ def index
+ builder = V2::ReportBuilder.new(Current.account, report_params)
data = builder.build
render json: data
end
- def account_summary
- render json: account_summary_metrics
+ def summary
+ render json: summary_metrics
end
def agents
@@ -23,31 +23,39 @@ class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController
render layout: false, template: 'api/v2/accounts/reports/inboxes.csv.erb', format: 'csv'
end
+ def labels
+ response.headers['Content-Type'] = 'text/csv'
+ response.headers['Content-Disposition'] = 'attachment; filename=labels_report.csv'
+ render layout: false, template: 'api/v2/accounts/reports/labels.csv.erb', format: 'csv'
+ end
+
private
def check_authorization
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
end
- def account_summary_params
+ def summary_params
{
- type: :account,
+ type: params[:type].to_sym,
since: params[:since],
- until: params[:until]
+ until: params[:until],
+ id: params[:id]
}
end
- def account_report_params
+ def report_params
{
metric: params[:metric],
- type: :account,
+ type: params[:type].to_sym,
since: params[:since],
- until: params[:until]
+ until: params[:until],
+ id: params[:id]
}
end
- def account_summary_metrics
- builder = V2::ReportBuilder.new(Current.account, account_summary_params)
+ def summary_metrics
+ builder = V2::ReportBuilder.new(Current.account, summary_params)
builder.summary
end
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index d25f88269..0a1c672ec 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,5 +1,6 @@
class ApplicationController < ActionController::Base
include DeviseTokenAuth::Concerns::SetUserByToken
+ include RequestExceptionHandler
include Pundit
include SwitchLocale
@@ -9,22 +10,8 @@ class ApplicationController < ActionController::Base
around_action :switch_locale
around_action :handle_with_exception, unless: :devise_controller?
- rescue_from ActiveRecord::RecordInvalid, with: :render_record_invalid
-
private
- def handle_with_exception
- yield
- rescue ActiveRecord::RecordNotFound => e
- Sentry.capture_exception(e)
- render_not_found_error('Resource could not be found')
- rescue Pundit::NotAuthorizedError
- render_unauthorized('You are not authorized to do this action')
- ensure
- # to address the thread variable leak issues in Puma/Thin webserver
- Current.reset
- end
-
def set_current_user
@user ||= current_user
Current.user = @user
@@ -34,32 +21,6 @@ class ApplicationController < ActionController::Base
@subscription ||= Current.account.subscription
end
- def render_unauthorized(message)
- render json: { error: message }, status: :unauthorized
- end
-
- def render_not_found_error(message)
- render json: { error: message }, status: :not_found
- end
-
- def render_could_not_create_error(message)
- render json: { error: message }, status: :unprocessable_entity
- end
-
- def render_internal_server_error(message)
- render json: { error: message }, status: :internal_server_error
- end
-
- def render_record_invalid(exception)
- render json: {
- message: exception.record.errors.full_messages.join(', ')
- }, status: :unprocessable_entity
- end
-
- def render_error_response(exception)
- render json: exception.to_hash, status: exception.http_status
- end
-
def pundit_user
{
user: Current.user,
diff --git a/app/controllers/concerns/request_exception_handler.rb b/app/controllers/concerns/request_exception_handler.rb
new file mode 100644
index 000000000..3ce486012
--- /dev/null
+++ b/app/controllers/concerns/request_exception_handler.rb
@@ -0,0 +1,47 @@
+module RequestExceptionHandler
+ extend ActiveSupport::Concern
+
+ included do
+ rescue_from ActiveRecord::RecordInvalid, with: :render_record_invalid
+ end
+
+ private
+
+ def handle_with_exception
+ yield
+ rescue ActiveRecord::RecordNotFound => e
+ Sentry.capture_exception(e)
+ render_not_found_error('Resource could not be found')
+ rescue Pundit::NotAuthorizedError
+ render_unauthorized('You are not authorized to do this action')
+ ensure
+ # to address the thread variable leak issues in Puma/Thin webserver
+ Current.reset
+ end
+
+ def render_unauthorized(message)
+ render json: { error: message }, status: :unauthorized
+ end
+
+ def render_not_found_error(message)
+ render json: { error: message }, status: :not_found
+ end
+
+ def render_could_not_create_error(message)
+ render json: { error: message }, status: :unprocessable_entity
+ end
+
+ def render_internal_server_error(message)
+ render json: { error: message }, status: :internal_server_error
+ end
+
+ def render_record_invalid(exception)
+ render json: {
+ message: exception.record.errors.full_messages.join(', ')
+ }, status: :unprocessable_entity
+ end
+
+ def render_error_response(exception)
+ render json: exception.to_hash, status: exception.http_status
+ end
+end
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index 53c0abb02..d00aafc18 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -23,7 +23,9 @@ class DashboardController < ActionController::Base
'CREATE_NEW_ACCOUNT_FROM_DASHBOARD',
'CHATWOOT_INBOX_TOKEN',
'API_CHANNEL_NAME',
- 'API_CHANNEL_THUMBNAIL'
+ 'API_CHANNEL_THUMBNAIL',
+ 'ANALYTICS_TOKEN',
+ 'ANALYTICS_HOST'
).merge(
APP_VERSION: Chatwoot.config[:version]
)
diff --git a/app/controllers/platform/api/v1/accounts_controller.rb b/app/controllers/platform/api/v1/accounts_controller.rb
index 24b39aa3e..a037f4e2f 100644
--- a/app/controllers/platform/api/v1/accounts_controller.rb
+++ b/app/controllers/platform/api/v1/accounts_controller.rb
@@ -16,7 +16,7 @@ class Platform::Api::V1::AccountsController < PlatformController
end
def destroy
- # TODO: obfusicate account
+ DeleteObjectJob.perform_later(@resource)
head :ok
end
diff --git a/app/controllers/platform/api/v1/users_controller.rb b/app/controllers/platform/api/v1/users_controller.rb
index b6e9237b9..4ee14d0b6 100644
--- a/app/controllers/platform/api/v1/users_controller.rb
+++ b/app/controllers/platform/api/v1/users_controller.rb
@@ -7,8 +7,8 @@ class Platform::Api::V1::UsersController < PlatformController
def create
@resource = (User.find_by(email: user_params[:email]) || User.new(user_params))
- @resource.confirm
@resource.save!
+ @resource.confirm
@platform_app.platform_app_permissibles.find_or_create_by(permissible: @resource)
end
@@ -19,21 +19,33 @@ class Platform::Api::V1::UsersController < PlatformController
def show; end
def update
- @resource.update!(user_params)
+ @resource.assign_attributes(user_update_params)
+ @resource.save!
end
def destroy
- # TODO: obfusicate user
+ DeleteObjectJob.perform_later(@resource)
head :ok
end
private
+ def user_custom_attributes
+ return @resource.custom_attributes.merge(user_params[:custom_attributes]) if user_params[:custom_attributes]
+
+ @resource.custom_attributes
+ end
+
+ def user_update_params
+ # we want the merged custom attributes not the original one
+ user_params.except(:custom_attributes).merge({ custom_attributes: user_custom_attributes })
+ end
+
def set_resource
@resource = User.find(params[:id])
end
def user_params
- params.permit(:name, :email, :password)
+ params.permit(:name, :email, :password, custom_attributes: {})
end
end
diff --git a/app/controllers/platform_controller.rb b/app/controllers/platform_controller.rb
index c1ecfc500..335f92483 100644
--- a/app/controllers/platform_controller.rb
+++ b/app/controllers/platform_controller.rb
@@ -1,4 +1,6 @@
class PlatformController < ActionController::API
+ include RequestExceptionHandler
+
before_action :ensure_access_token
before_action :set_platform_app
before_action :set_resource, only: [:update, :show, :destroy]
diff --git a/app/controllers/public/api/v1/inboxes/messages_controller.rb b/app/controllers/public/api/v1/inboxes/messages_controller.rb
index 68c0f5223..925c16d38 100644
--- a/app/controllers/public/api/v1/inboxes/messages_controller.rb
+++ b/app/controllers/public/api/v1/inboxes/messages_controller.rb
@@ -7,8 +7,8 @@ class Public::Api::V1::Inboxes::MessagesController < Public::Api::V1::InboxesCon
def create
@message = @conversation.messages.new(message_params)
- @message.save
build_attachment
+ @message.save!
end
def update
@@ -23,13 +23,12 @@ class Public::Api::V1::Inboxes::MessagesController < Public::Api::V1::InboxesCon
return if params[:attachments].blank?
params[:attachments].each do |uploaded_attachment|
- attachment = @message.attachments.new(
+ @message.attachments.new(
account_id: @message.account_id,
- file_type: helpers.file_type(uploaded_attachment&.content_type)
+ file_type: helpers.file_type(uploaded_attachment&.content_type),
+ file: uploaded_attachment
)
- attachment.file.attach(uploaded_attachment)
end
- @message.save!
end
def message_finder_params
diff --git a/app/controllers/public_controller.rb b/app/controllers/public_controller.rb
index 9e5a7e6ba..b59a4296e 100644
--- a/app/controllers/public_controller.rb
+++ b/app/controllers/public_controller.rb
@@ -1,5 +1,6 @@
# TODO: we should switch to ActionController::API for the base classes
# One of the specs is failing when I tried doing that, lets revisit in future
class PublicController < ActionController::Base
+ include RequestExceptionHandler
skip_before_action :verify_authenticity_token
end
diff --git a/app/controllers/super_admin/dashboard_controller.rb b/app/controllers/super_admin/dashboard_controller.rb
index b5f3d34eb..56d19d563 100644
--- a/app/controllers/super_admin/dashboard_controller.rb
+++ b/app/controllers/super_admin/dashboard_controller.rb
@@ -3,10 +3,9 @@ class SuperAdmin::DashboardController < SuperAdmin::ApplicationController
def index
@data = Conversation.unscoped.group_by_day(:created_at, range: 30.days.ago..2.seconds.ago).count.to_a
- @accounts_count = number_with_delimiter(Account.all.length)
- @users_count = number_with_delimiter(User.all.length)
- @inboxes_count = number_with_delimiter(Inbox.all.length)
- @conversations_count = number_with_delimiter(Conversation.all.length)
- @messages_count = number_with_delimiter(Message.all.length)
+ @accounts_count = number_with_delimiter(Account.count)
+ @users_count = number_with_delimiter(User.count)
+ @inboxes_count = number_with_delimiter(Inbox.count)
+ @conversations_count = number_with_delimiter(Conversation.count)
end
end
diff --git a/app/controllers/webhooks/line_controller.rb b/app/controllers/webhooks/line_controller.rb
new file mode 100644
index 000000000..74e22f119
--- /dev/null
+++ b/app/controllers/webhooks/line_controller.rb
@@ -0,0 +1,6 @@
+class Webhooks::LineController < ActionController::API
+ def process_payload
+ Webhooks::LineEventsJob.perform_later(params: params.to_unsafe_hash, signature: request.headers['x-line-signature'], post_body: request.raw_post)
+ head :ok
+ end
+end
diff --git a/app/controllers/webhooks/telegram_controller.rb b/app/controllers/webhooks/telegram_controller.rb
new file mode 100644
index 000000000..bc65061e7
--- /dev/null
+++ b/app/controllers/webhooks/telegram_controller.rb
@@ -0,0 +1,6 @@
+class Webhooks::TelegramController < ActionController::API
+ def process_payload
+ Webhooks::TelegramEventsJob.perform_later(params.to_unsafe_hash)
+ head :ok
+ end
+end
diff --git a/app/drops/message_drop.rb b/app/drops/message_drop.rb
new file mode 100644
index 000000000..cbb3f1782
--- /dev/null
+++ b/app/drops/message_drop.rb
@@ -0,0 +1,12 @@
+class MessageDrop < BaseDrop
+ include MessageFormatHelper
+
+ def sender_display_name
+ @obj.sender.try(:available_name)
+ end
+
+ def text_content
+ content = @obj.try(:content)
+ transform_user_mention_content content
+ end
+end
diff --git a/app/helpers/file_type_helper.rb b/app/helpers/file_type_helper.rb
index 4936fa155..64d67701a 100644
--- a/app/helpers/file_type_helper.rb
+++ b/app/helpers/file_type_helper.rb
@@ -3,12 +3,12 @@ module FileTypeHelper
return :image if [
'image/jpeg',
'image/png',
- 'image/svg+xml',
'image/gif',
'image/tiff',
'image/bmp'
].include?(content_type)
+ return :video if content_type.include?('video/')
return :audio if content_type.include?('audio/')
:file
diff --git a/app/javascript/dashboard/api/attributes.js b/app/javascript/dashboard/api/attributes.js
new file mode 100644
index 000000000..56eb5da76
--- /dev/null
+++ b/app/javascript/dashboard/api/attributes.js
@@ -0,0 +1,14 @@
+/* global axios */
+import ApiClient from './ApiClient';
+
+class AttributeAPI extends ApiClient {
+ constructor() {
+ super('custom_attribute_definitions', { accountScoped: true });
+ }
+
+ getAttributesByModel(modelId) {
+ return axios.get(`${this.url}?attribute_model=${modelId}`);
+ }
+}
+
+export default new AttributeAPI();
diff --git a/app/javascript/dashboard/api/inboxMembers.js b/app/javascript/dashboard/api/inboxMembers.js
index 3716f89ab..64f78845f 100644
--- a/app/javascript/dashboard/api/inboxMembers.js
+++ b/app/javascript/dashboard/api/inboxMembers.js
@@ -6,8 +6,8 @@ class InboxMembers extends ApiClient {
super('inbox_members', { accountScoped: true });
}
- create({ inboxId, agentList }) {
- return axios.post(this.url, {
+ update({ inboxId, agentList }) {
+ return axios.patch(this.url, {
inbox_id: inboxId,
user_ids: agentList,
});
diff --git a/app/javascript/dashboard/api/inboxes.js b/app/javascript/dashboard/api/inboxes.js
index b6d8ab860..1cf6ba113 100644
--- a/app/javascript/dashboard/api/inboxes.js
+++ b/app/javascript/dashboard/api/inboxes.js
@@ -13,6 +13,10 @@ class Inboxes extends ApiClient {
getCampaigns(inboxId) {
return axios.get(`${this.url}/${inboxId}/campaigns`);
}
+
+ deleteInboxAvatar(inboxId) {
+ return axios.delete(`${this.url}/${inboxId}/avatar`);
+ }
}
export default new Inboxes();
diff --git a/app/javascript/dashboard/api/reports.js b/app/javascript/dashboard/api/reports.js
index 9b7eeaf45..9f7875c79 100644
--- a/app/javascript/dashboard/api/reports.js
+++ b/app/javascript/dashboard/api/reports.js
@@ -7,14 +7,14 @@ class ReportsAPI extends ApiClient {
}
getAccountReports(metric, since, until) {
- return axios.get(`${this.url}/account`, {
- params: { metric, since, until },
+ return axios.get(`${this.url}`, {
+ params: { metric, since, until, type: 'account' },
});
}
getAccountSummary(since, until) {
- return axios.get(`${this.url}/account_summary`, {
- params: { since, until },
+ return axios.get(`${this.url}/summary`, {
+ params: { since, until, type: 'account' },
});
}
diff --git a/app/javascript/dashboard/api/specs/inboxes.spec.js b/app/javascript/dashboard/api/specs/inboxes.spec.js
index 6c5cf38ea..b261bb930 100644
--- a/app/javascript/dashboard/api/specs/inboxes.spec.js
+++ b/app/javascript/dashboard/api/specs/inboxes.spec.js
@@ -27,5 +27,12 @@ describe('#InboxesAPI', () => {
'/api/v1/inboxes/2/campaigns'
);
});
+
+ it('#deleteInboxAvatar', () => {
+ inboxesAPI.deleteInboxAvatar(2);
+ expect(context.axiosMock.delete).toHaveBeenCalledWith(
+ '/api/v1/inboxes/2/avatar'
+ );
+ });
});
});
diff --git a/app/javascript/dashboard/api/specs/reports.spec.js b/app/javascript/dashboard/api/specs/reports.spec.js
index 0ca5f4be7..72d5b7a90 100644
--- a/app/javascript/dashboard/api/specs/reports.spec.js
+++ b/app/javascript/dashboard/api/specs/reports.spec.js
@@ -23,12 +23,13 @@ describe('#Reports API', () => {
1621621800
);
expect(context.axiosMock.get).toHaveBeenCalledWith(
- '/api/v2/reports/account',
+ '/api/v2/reports',
{
params: {
metric: 'conversations_count',
since: 1621103400,
until: 1621621800,
+ type: 'account'
},
}
);
@@ -37,11 +38,12 @@ describe('#Reports API', () => {
it('#getAccountSummary', () => {
reportsAPI.getAccountSummary(1621103400, 1621621800);
expect(context.axiosMock.get).toHaveBeenCalledWith(
- '/api/v2/reports/account_summary',
+ '/api/v2/reports/summary',
{
params: {
since: 1621103400,
until: 1621621800,
+ type: 'account'
},
}
);
diff --git a/app/javascript/dashboard/assets/scss/_woot.scss b/app/javascript/dashboard/assets/scss/_woot.scss
index e3ad32e2e..908daa315 100644
--- a/app/javascript/dashboard/assets/scss/_woot.scss
+++ b/app/javascript/dashboard/assets/scss/_woot.scss
@@ -5,6 +5,7 @@
@import 'shared/assets/stylesheets/font-weights';
@import 'shared/assets/stylesheets/shadows';
@import 'shared/assets/stylesheets/border-radius';
+@import 'shared/assets/stylesheets/z-index';
@import 'variables';
diff --git a/app/javascript/dashboard/assets/scss/views/settings/inbox.scss b/app/javascript/dashboard/assets/scss/views/settings/inbox.scss
index cc2abcf9b..e3b45726f 100644
--- a/app/javascript/dashboard/assets/scss/views/settings/inbox.scss
+++ b/app/javascript/dashboard/assets/scss/views/settings/inbox.scss
@@ -71,7 +71,6 @@
}
&.over {
-
&::after {
background: $color-woot;
}
@@ -80,7 +79,7 @@
background: $color-woot;
}
- &+.item {
+ & + .item {
&::before {
background: $color-woot;
}
@@ -132,10 +131,13 @@
@include padding($space-medium);
@include border-light;
@include full-height();
+
+ &.height-auto {
+ height: auto;
+ }
}
.inoboxes-list {
-
.inbox-item {
@include margin($space-normal);
@include flex;
@@ -189,9 +191,9 @@
align-self: center;
color: $medium-gray;
font-size: $font-size-small;
- opacity: .7;
+ opacity: 0.7;
transform: translateX(0);
- transition: opacity 0.100s ease-in 0s, transform 0.200s ease-in 0.030s;
+ transition: opacity 0.1s ease-in 0s, transform 0.2s ease-in 0.03s;
}
}
}
@@ -226,7 +228,7 @@
@include padding($space-medium);
}
- >a>img {
+ > a > img {
width: $space-larger * 5;
}
}
diff --git a/app/javascript/dashboard/assets/scss/widgets/_conversation-card.scss b/app/javascript/dashboard/assets/scss/widgets/_conversation-card.scss
index f7b96381e..a7a256b4d 100644
--- a/app/javascript/dashboard/assets/scss/widgets/_conversation-card.scss
+++ b/app/javascript/dashboard/assets/scss/widgets/_conversation-card.scss
@@ -144,7 +144,10 @@
padding-left: 0;
.conversation--details {
+ border-radius: var(--border-radius-small);
margin-left: 0;
+ padding-left: var(--space-two);
+ padding-right: var(--space-small);
}
}
}
diff --git a/app/javascript/dashboard/assets/scss/widgets/_conversation-view.scss b/app/javascript/dashboard/assets/scss/widgets/_conversation-view.scss
index d79cfe80d..f2c156542 100644
--- a/app/javascript/dashboard/assets/scss/widgets/_conversation-view.scss
+++ b/app/javascript/dashboard/assets/scss/widgets/_conversation-view.scss
@@ -113,10 +113,18 @@
}
&:last-child {
- margin-bottom: $space-small;
+ margin-bottom: 0;
}
&.unread--toast {
+ +.right {
+ margin-bottom: 0;
+ }
+
+ +.left {
+ margin-bottom: 0;
+ }
+
span {
@include elegant-card;
@include round-corner;
@@ -140,6 +148,7 @@
}
}
+
&.left {
.bubble {
@@ -183,6 +192,19 @@
}
}
+ +.unread--toast {
+ +.right {
+ margin-top: $space-one;
+
+ .bubble {
+ border-top-right-radius: $space-one;
+ }
+ }
+
+ +.left {
+ margin-top: 0;
+ }
+ }
}
&.right {
@@ -226,6 +248,21 @@
border-top-left-radius: $space-one;
}
}
+
+ +.unread--toast {
+ +.left {
+ margin-top: $space-one;
+
+ .bubble {
+ border-top-left-radius: $space-one;
+ }
+ }
+
+ +.right {
+ margin-top: 0;
+ }
+ }
+
}
&.center {
@@ -259,11 +296,11 @@
display: flex;
font-size: var(--font-size-small);
justify-content: center;
- margin: var(--space-small) var(--space-normal);
- padding: var(--space-small) var(--space-normal);
+ margin: var(--space-smaller) 0;
+ padding: var(--space-smaller) var(--space-micro) var(--space-smaller) var(--space-one);
.is-text {
- display: inline-block;
+ display: inline-flex;
text-align: start;
@include breakpoint(xxxlarge up) {
diff --git a/app/javascript/dashboard/components/Accordion/AccordionItem.stories.js b/app/javascript/dashboard/components/Accordion/AccordionItem.stories.js
new file mode 100644
index 000000000..5ff6af8cf
--- /dev/null
+++ b/app/javascript/dashboard/components/Accordion/AccordionItem.stories.js
@@ -0,0 +1,30 @@
+import { action } from '@storybook/addon-actions';
+import AccordionItemComponent from './AccordionItem';
+
+export default {
+ title: 'Components/Generic/Accordion',
+ component: AccordionItemComponent,
+ argTypes: {
+ title: {
+ control: {
+ type: 'string',
+ },
+ },
+ },
+};
+
+const Template = (args, { argTypes }) => ({
+ props: Object.keys(argTypes),
+ components: { AccordionItem: AccordionItemComponent },
+ template: `
+
+
- {{ $t('KEYBOARD_SHORTCUTS.KEYS.COMMAND_KEY') }} + {{ $t('KEYBOARD_SHORTCUTS.KEYS.WINDOWS_KEY_AND_COMMAND_KEY') }}
{{ $t('KEYBOARD_SHORTCUTS.KEYS.FORWARD_SLASH_KEY') }} @@ -51,7 +51,7 @@
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Agents
An Agent is a member of your Customer Support team.
Agents will be able to view and reply to messages from your users. The list shows all agents currently in your account.
Click on Add Agent to add a new agent. Agent you add will receive an email with a confirmation link to activate their account, after which they can access Chatwoot and respond to messages.
Access to Chatwoot's features are based on following roles.
Agent - Agents with this role can only access inboxes, reports and conversations. They can assign conversations to other agents or themselves and resolve conversations.
Administrator - Administrator will have access to all Chatwoot features enabled for your account, including settings, along with all of a normal agents' privileges.
", + "SIDEBAR_TXT": "Agenti
Agent je členem vašeho týmu zákaznické podpory.
Agenti budou moci prohlížet a odpovídat na zprávy od uživatelů. Seznam zobrazuje všechny agenty aktuálně na vašem účtu.
Pro přidání nového agenta klikněte na Přidat agenta. Přidaný agent obdrží e-mail s potvrzovacím odkazem pro aktivaci jejich účtu, poté bude mít přístup k Chatwoot a bude reagovat na zprávy.
Přístup k funkcím Chatwootu je založen na následujících rolích.
Agent - Agent s touto rolí může přistupovat pouze k doručeným zprávám, zprávám a konverzacím. Mohou přiřadit konverzace jiným agentům nebo sobě a řešit konverzace.
Administrátor - Správce bude mít přístup ke všem funkcím Chatwoot povoleným pro váš účet, včetně nastavení spolu se všemi obvyklými právy agenta.
", "AGENT_TYPES": { "ADMINISTRATOR": "Administrátor", "AGENT": "Agent" @@ -91,6 +91,23 @@ }, "SEARCH": { "NO_RESULTS": "Žádné výsledky." + }, + "MULTI_SELECTOR": { + "PLACEHOLDER": "Nic", + "TITLE": { + "AGENT": "Vybrat agenta", + "TEAM": "Vybrat tým" + }, + "SEARCH": { + "NO_RESULTS": { + "AGENT": "Nenalezeni žádní agenti", + "TEAM": "Nenalezeny žádné týmy" + }, + "PLACEHOLDER": { + "AGENT": "Hledat agenty", + "TEAM": "Hledat týmy" + } + } } } } diff --git a/app/javascript/dashboard/i18n/locale/cs/attributesMgmt.json b/app/javascript/dashboard/i18n/locale/cs/attributesMgmt.json new file mode 100644 index 000000000..ea9001dcb --- /dev/null +++ b/app/javascript/dashboard/i18n/locale/cs/attributesMgmt.json @@ -0,0 +1,85 @@ +{ + "ATTRIBUTES_MGMT": { + "HEADER": "Attributes", + "HEADER_BTN_TXT": "Add Attribute", + "LOADING": "Fetching attributes", + "SIDEBAR_TXT": "Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Ιδιότητες
Μια προσαρμοσμένη ιδιότητα παρακολουθεί γεγονότα σχετικά με τις επαφές σας/συνομιλίες σας — όπως για παράδειγμα συνδρομή, ή όταν γίνεται η πρώτη παραγγελία κ. λπ.
Για τη δημιουργία ιδιοτήτων απλά κάντε κλικ στοΠροσθήκη Ιδιότητας. Μπορείτε επίσης να επεξεργαστείτε ή να διαγράψετε μια υπάρχουσα Ιδιότητα κάνοντας κλικ στο κουμπί Επεξεργασία ή διαγραφή.
Chatwoot will now sync all the incoming conversations into the customer-conversations channel inside your slack workplace.
Replying to a conversation thread in customer-conversations slack channel will create a response back to the customer through chatwoot.
Start the replies with note: to create private notes instead of replies.
If the replier on slack has an agent profile in chatwoot under the same email, the replies will be associated accordingly.
When the replier doesn't have an associated agent profile, the replies will be made from the bot profile.
" + "TITLE": "Χρήση Slack Integration", + "BODY": "Το Chatwoot θα συγχρονίσει τώρα όλες τις εισερχόμενες συνομιλίες στο κανάλι πελατών-συνομιλιών μέσα στο slack χώρο εργασίας σας.
Απάντηση σε μια συνομιλία από συνομιλίες πελατών το κανάλι slack θα δημιουργήσει μια απάντηση για στον πελάτη μέσω chatwoot.
Ξεκινήστε τις απαντήσεις με το note: για να δημιουργήσετε ιδιωτικές σημειώσεις αντί για απαντήσεις.
Αν ο χρήστης στο slack έχει προφίλ πράκτορα στο chatwoot με το ίδιο email, οι απαντήσεις θα συσχετιστούν ανάλογα.
Εφόσον δεν έχει προφίλ συνδεδεμένου πράκτορα, οι απαντήσεις θα γίνουν από το προφίλ bot.
" } }, "DELETE": { diff --git a/app/javascript/dashboard/i18n/locale/el/report.json b/app/javascript/dashboard/i18n/locale/el/report.json index d5b87e4d6..2fbd0017b 100644 --- a/app/javascript/dashboard/i18n/locale/el/report.json +++ b/app/javascript/dashboard/i18n/locale/el/report.json @@ -1,6 +1,6 @@ { "REPORT": { - "HEADER": "Overview", + "HEADER": "Επισκόπηση", "LOADING_CHART": "Φόρτωση δεδομένων γραφήματος...", "NO_ENOUGH_DATA": "Δεν έχουν ληφθεί αρκετά σημεία δεδομένων για την δημιουργία της αναφοράς, Παρακαλώ προσπαθήστε αργότερα.", "DOWNLOAD_AGENT_REPORTS": "Κατέβασμα αναφορών πράκτορα", @@ -53,37 +53,37 @@ }, { "id": 5, - "name": "Custom date range" + "name": "Προσαρμοσμένο εύρος ημερομηνιών" } ], "CUSTOM_DATE_RANGE": { - "CONFIRM": "Apply", - "PLACEHOLDER": "Select date range" + "CONFIRM": "Εφαρμογή", + "PLACEHOLDER": "Επιλέξτε εύρος ημερομηνιών" } }, "CSAT_REPORTS": { - "HEADER": "CSAT Reports", - "NO_RECORDS": "There are no CSAT survey responses available.", + "HEADER": "Αναφορές CSAT", + "NO_RECORDS": "Δεν υπάρχουν διαθέσιμες απαντήσεις ερευνών CSAT.", "TABLE": { "HEADER": { - "CONTACT_NAME": "Contact", - "AGENT_NAME": "Assigned agent", - "RATING": "Rating", - "FEEDBACK_TEXT": "Feedback comment" + "CONTACT_NAME": "Επαφές", + "AGENT_NAME": "Αντιστοιχισμένος πράκτορας", + "RATING": "Αξιολόγηση", + "FEEDBACK_TEXT": "Σχόλιο ανατροφοδότησης" } }, "METRIC": { "TOTAL_RESPONSES": { - "LABEL": "Total responses", - "TOOLTIP": "Total number of responses collected" + "LABEL": "Συνολικές απαντήσεις", + "TOOLTIP": "Συνολικός αριθμός απαντήσεων" }, "SATISFACTION_SCORE": { - "LABEL": "Satisfaction score", - "TOOLTIP": "Total number of positive responses / Total number of responses * 100" + "LABEL": "Βαθμός ικανοποίησης", + "TOOLTIP": "Συνολικός αριθμός θετικών αποκρίσεων / Συνολικός αριθμός ανταποκρίσεων * 100" }, "RESPONSE_RATE": { - "LABEL": "Response rate", - "TOOLTIP": "Total number of responses / Total number of CSAT survey messages sent * 100" + "LABEL": "Ποσοστό ανταπόκρισης", + "TOOLTIP": "Συνολικός αριθμός απαντήσεων / Συνολικός αριθμός μηνυμάτων έρευνας CSAT * 100" } } } diff --git a/app/javascript/dashboard/i18n/locale/el/settings.json b/app/javascript/dashboard/i18n/locale/el/settings.json index 46e650abb..7b76a7f14 100644 --- a/app/javascript/dashboard/i18n/locale/el/settings.json +++ b/app/javascript/dashboard/i18n/locale/el/settings.json @@ -29,8 +29,8 @@ "TITLE": "Ειδοποιήσεις Ήχου", "NOTE": "Ενεργοποίηση ηχητικών ειδοποιήσεων για νέα μηνύματα και συνομιλίες.", "NONE": "Κανένα", - "ASSIGNED": "Assigned Conversations", - "ALL_CONVERSATIONS": "All Conversations" + "ASSIGNED": "Ανατεθειμένες Συνομιλίες", + "ALL_CONVERSATIONS": "Όλες Οι Συνομιλίες" }, "EMAIL_NOTIFICATIONS_SECTION": { "TITLE": "Ειδοποιήσεις Email", @@ -102,6 +102,7 @@ "CHANGE_ACCOUNTS": "Αλλαγή Λογαριασμού", "SELECTOR_SUBTITLE": "Επιλέξτε ένα λογαριασμό από την Λίστα", "PROFILE_SETTINGS": "Ρυθμίσεις Προφίλ", + "KEYBOARD_SHORTCUTS": "Συντομεύσεις Πληκτρολογίου", "LOGOUT": "Έξοδος (Logout)" }, "APP_GLOBAL": { @@ -130,8 +131,8 @@ "SIDEBAR": { "CONVERSATIONS": "Συζητήσεις", "REPORTS": "Αναφορές", - "CONTACTS": "Επαφές", "SETTINGS": "Ρυθμίσεις", + "CONTACTS": "Επαφές", "HOME": "Αρχική", "AGENTS": "Πράκτορες", "INBOXES": "Κιβώτια Εισερχομένων", @@ -141,13 +142,18 @@ "ACCOUNT_SETTINGS": "Ρυθμίσεις Λογαριασμού", "APPLICATIONS": "Εφαρμογές", "LABELS": "Ετικέτες", + "ATTRIBUTES": "Ιδιότητες", "TEAMS": "Ομάδες", - "ALL_CONTACTS": "All Contacts", - "TAGGED_WITH": "Tagged with", - "REPORTS_OVERVIEW": "Overview", - "CSAT": "CSAT" + "ALL_CONTACTS": "Όλες Οι Επαφές", + "TAGGED_WITH": "Ετικέτα με", + "REPORTS_OVERVIEW": "Επισκόπηση", + "CSAT": "CSAT", + "CAMPAIGNS": "Καμπάνιες", + "ONGOING": "Σε Εξέλιξη", + "ONE_OFF": "Ένα/μία από" }, "CREATE_ACCOUNT": { + "NO_ACCOUNT_WARNING": "Ωχ! Δεν μπορέσαμε να βρούμε κανένα λογαριασμό Chatwoot. Παρακαλούμε δημιουργήστε ένα νέο λογαριασμό για να συνεχίσετε.", "NEW_ACCOUNT": "Νέος Λογαριασμός", "SELECTOR_SUBTITLE": "Δημιουργία νέου Λογαριασμού", "API": { @@ -162,5 +168,30 @@ }, "SUBMIT": "Καταχώρηση" } + }, + "KEYBOARD_SHORTCUTS": { + "TITLE": { + "OPEN_CONVERSATION": "Άνοιγμα συνομιλίας", + "RESOLVE_AND_NEXT": "Επίλυση και μετακίνηση στην επόμενη", + "NAVIGATE_DROPDOWN": "Πλοηγηθείτε στα αναπτυσσόμενα στοιχεία", + "RESOLVE_CONVERSATION": "Επίλυση Συνομιλίας", + "GO_TO_CONVERSATION_DASHBOARD": "Μεταβείτε στον Πίνακα Συνομιλίων", + "ADD_ATTACHMENT": "Προσθήκη Συνημμένου", + "GO_TO_CONTACTS_DASHBOARD": "Μετάβαση στον Πίνακα Επαφών", + "TOGGLE_SIDEBAR": "Εναλλαγή πλευρικής μπάρας", + "GO_TO_REPORTS_SIDEBAR": "Πλευρική μπάρα αναφορών", + "MOVE_TO_NEXT_TAB": "Μετακίνηση στην επόμενη καρτέλα στη λίστα συνομιλιών", + "GO_TO_SETTINGS": "Μετάβαση στις ρυθμίσεις", + "SWITCH_CONVERSATION_STATUS": "Εναλλαγή στην επόμενη κατάσταση συνομιλίας", + "SWITCH_TO_PRIVATE_NOTE": "Αλλαγή σε Ιδιωτική Σημείωση", + "TOGGLE_RICH_CONTENT_EDITOR": "Εναλλαγή επεξεργαστή εμπλουτισμένου περιεχομένου", + "SWITCH_TO_REPLY": "Εναλλαγή σε απάντηση", + "TOGGLE_SNOOZE_DROPDOWN": "Εναλλαγή αναβολής dropdown" + }, + "KEYS": { + "WINDOWS_KEY_AND_COMMAND_KEY": "Win / ⌘", + "ALT_OR_OPTION_KEY": "Alt / °C.", + "FORWARD_SLASH_KEY": "/" + } } } diff --git a/app/javascript/dashboard/i18n/locale/en/attributesMgmt.json b/app/javascript/dashboard/i18n/locale/en/attributesMgmt.json new file mode 100644 index 000000000..d7bcb597a --- /dev/null +++ b/app/javascript/dashboard/i18n/locale/en/attributesMgmt.json @@ -0,0 +1,80 @@ +{ + "ATTRIBUTES_MGMT": { + "HEADER": "Attributes", + "HEADER_BTN_TXT": "Add Attribute", + "LOADING": "Fetching attributes", + "SIDEBAR_TXT": "Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
اپراتورها
یک اپراتور یکی از اعضای تیم پشتیبانی است.
اپراتورها میتوانند پیامهای کاربران را ببینند و به آنها پاسخ بدهند. این لیست حاوی تمام اپراتورهایی است که در حساب شما تعریف شده اند.
با زدن روی دکمه اضافه کردن اپراتور میتوانید یک اپراتور جدید معرفی کنید. به ایمیل اپراتوری که معرفی میکنید یک دعوتنامه ارسال میشود که بعد از پذیرفتن آن اپراتور میتواند به پیامهای کاربران پاسخ بدهد.
بسته به سطح دسترسی تعیین شده یک اپراتور میتواند به بخشهای مشخصی از اکانت دسترسی پیدا کند
اپراتور - اپراتورهایی که این نقش را داشته باشند تنها میتوانند به صندوقهای ورودی، گزارشات و گفتگوها دسترسی داشته باشند. آنها میتوانند یک مکالمه را به اپراتور دیگر یا خودشان تخصیص دهند و یا یک مکالمه را حل شده اعلام کنند.
مدیر - مدیران میتوانند علاوه بر تمام بخشهایی که یک اپراتور دسترسی دارد، به تمام بخشهایی که در حساب کاربری شما وجود دارد دسترسی داشته باشند.
", + "HEADER": "ایجنت ها", + "HEADER_BTN_TXT": "اضافه کردن ایجنت", + "LOADING": "دریافت لیست ایجنت ها", + "SIDEBAR_TXT": "ایجنت ها
\nیک ایجنت یکی از اعضای تیم پشتیبانی است.
ایجنت ها میتوانند پیامهای کاربران را ببینند و به آنها پاسخ بدهند. این لیست حاوی تمام اپراتورهایی است که در حساب شما تعریف شده اند.
با زدن روی دکمه اضافه کردن اپراتور میتوانید یک اپراتور جدید معرفی کنید. به ایمیل اپراتوری که معرفی میکنید یک دعوتنامه ارسال میشود که بعد از پذیرفتن آن ایجنت میتواند به پیامهای کاربران پاسخ بدهد.
بسته به سطح دسترسی تعیین شده یک اپراتور میتواند به بخشهای مشخصی از اکانت دسترسی پیدا کند
اپراتور - اپراتورهایی که این نقش را داشته باشند تنها میتوانند به صندوقهای ورودی، گزارشات و گفتگوها دسترسی داشته باشند. آنها میتوانند یک مکالمه را به اپراتور دیگر یا خودشان تخصیص دهند و یا یک مکالمه را حل شده اعلام کنند.
مدیر - مدیران میتوانند علاوه بر تمام بخشهایی که یک اپراتور دسترسی دارد، به تمام بخشهایی که در حساب کاربری شما وجود دارد دسترسی داشته باشند.
", "AGENT_TYPES": { "ADMINISTRATOR": "مدیر", - "AGENT": "اپراتور" + "AGENT": "ایجنت" }, "LIST": { - "404": "در حال حاضر هیچ اپراتوری برای این حساب معرفی نشده است.", - "TITLE": "مدیریت اپراتورها", - "DESC": "میتوانید به تیمتان اپراتور اضافه کرده یا اپراتورهای فعلی را حذف کنید", + "404": "در حال حاضر هیچ ایجنتی برای این حساب معرفی نشده است", + "TITLE": "مدیریت ایجنت ها", + "DESC": "میتوانید به تیمتان ایجنت اضافه کرده یا ایجنت های فعلی را حذف کنید.", "NAME": "نام", "EMAIL": "ایمیل", "STATUS": "وضعیت", @@ -20,35 +20,35 @@ "VERIFICATION_PENDING": "در انتظار تایید" }, "ADD": { - "TITLE": "اضافه کردن اپراتور به تیم", + "TITLE": "اضافه کردن ایجنت به تیم", "DESC": "میتوانید افرادی را معرفی کنید که مسئول پشتیبانی آنلاین صندوقهای ورودی باشند", "CANCEL_BUTTON_TEXT": "انصراف", "FORM": { "NAME": { - "LABEL": "اسم اپراتور", - "PLACEHOLDER": "لطفا اسم اپراتور را وارد نمایید" + "LABEL": "اسم ایجنت", + "PLACEHOLDER": "لطفا اسم ایجنت را وارد نمایید" }, "AGENT_TYPE": { - "LABEL": "نوع اپراتور", - "PLACEHOLDER": "لطفا نوع دسترسی اپراتور را مشخص کنید", - "ERROR": "تعیین کردن نوع اپراتور الزامی است" + "LABEL": "نوع ایجنت", + "PLACEHOLDER": "لطفا نوع دسترسی ایجنت را مشخص کنید", + "ERROR": "تعیین کردن نوع ایجنت الزامی است" }, "EMAIL": { "LABEL": "ایمیل", - "PLACEHOLDER": "لطفا آدرس ایمیل اپراتور را وارد نمایید" + "PLACEHOLDER": "لطفا آدرس ایمیل ایجنت را وارد نمایید" }, - "SUBMIT": "اضافه کردن اپراتور" + "SUBMIT": "اضافه کردن ایجنت" }, "API": { - "SUCCESS_MESSAGE": "اپراتور معرفی شد", - "EXIST_MESSAGE": "این اپراتور قبلا معرفی شده، لطفا ایمیل دیگری را امتحان کنید", + "SUCCESS_MESSAGE": "ایجنت اضافه شد", + "EXIST_MESSAGE": "این ایجنت قبلا اضافه شده است، لطفا ایمیل دیگری را امتحان کنید", "ERROR_MESSAGE": "متاسفانه ارتباط با سرور برقرار نشد، مجددا امتحان کنید" } }, "DELETE": { "BUTTON_TEXT": "حذف", "API": { - "SUCCESS_MESSAGE": "اپراتور حذف شد", + "SUCCESS_MESSAGE": "ایجنت حذف شد", "ERROR_MESSAGE": "متاسفانه ارتباط با سرور برقرار نشد، مجددا امتحان کنید" }, "CONFIRM": { @@ -59,38 +59,55 @@ } }, "EDIT": { - "TITLE": "تغییر مشخصات اپراتور", + "TITLE": "تغییر مشخصات ایجنت", "FORM": { "NAME": { - "LABEL": "اسم اپراتور", - "PLACEHOLDER": "لطفا اسم اپراتور را وارد کنید" + "LABEL": "اسم ایجنت", + "PLACEHOLDER": "لطفا اسم ایجنت را وارد کنید" }, "AGENT_TYPE": { - "LABEL": "نوع اپراتور", - "PLACEHOLDER": "لطفا نوع اپراتور را انتخاب کنید", - "ERROR": "تعیین کردن نوع اپراتور الزامی است" + "LABEL": "نوع ایجنت", + "PLACEHOLDER": "لطفا نوع ایجنت را انتخاب کنید", + "ERROR": "تعیین کردن نوع ایجنت الزامی است" }, "EMAIL": { "LABEL": "ایمیل", "PLACEHOLDER": "لطفا ایمیل اپراتور را وارد کنید" }, - "SUBMIT": "تغییر اپراتور" + "SUBMIT": "تغییر ایجنت" }, "BUTTON_TEXT": "ویرایش", "CANCEL_BUTTON_TEXT": "انصراف", "API": { - "SUCCESS_MESSAGE": "اطلاعات اپراتور تغییر یافت", + "SUCCESS_MESSAGE": "اطلاعات ایجنت تغییر یافت", "ERROR_MESSAGE": "متاسفانه ارتباط با سرور برقرار نشد، مجددا امتحان کنید" }, "PASSWORD_RESET": { "ADMIN_RESET_BUTTON": "تغییر رمز عبور", - "ADMIN_SUCCESS_MESSAGE": "یک ایمیل حاوی روش تغییر دادن رمز عبور برای اپراتور ارسال شد", - "SUCCESS_MESSAGE": "تغییر رمز عبور اپراتور با موفقیت انجام شد", + "ADMIN_SUCCESS_MESSAGE": "یک ایمیل حاوی روش تغییر دادن رمز عبور برای ایجنت ارسال شد", + "SUCCESS_MESSAGE": "تغییر رمز عبور ایجنت با موفقیت انجام شد", "ERROR_MESSAGE": "متاسفانه ارتباط با سرور برقرار نشد، مجددا امتحان کنید" } }, "SEARCH": { "NO_RESULTS": "نتیجهای یافت نشد." + }, + "MULTI_SELECTOR": { + "PLACEHOLDER": "هیچکدام", + "TITLE": { + "AGENT": "انتخاب ایجنت", + "TEAM": "انتخاب تیم" + }, + "SEARCH": { + "NO_RESULTS": { + "AGENT": "اپراتوری یافت نشد", + "TEAM": "ایجنتی یافت نشد" + }, + "PLACEHOLDER": { + "AGENT": "جستجوی اپراتور", + "TEAM": "جستجوی تیم" + } + } } } } diff --git a/app/javascript/dashboard/i18n/locale/fa/attributesMgmt.json b/app/javascript/dashboard/i18n/locale/fa/attributesMgmt.json new file mode 100644 index 000000000..b20537f25 --- /dev/null +++ b/app/javascript/dashboard/i18n/locale/fa/attributesMgmt.json @@ -0,0 +1,85 @@ +{ + "ATTRIBUTES_MGMT": { + "HEADER": "ویژگی ها", + "HEADER_BTN_TXT": "افزودن ویژگی", + "LOADING": "Fetching attributes", + "SIDEBAR_TXT": "Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
پاسخهای آماده
پاسخهای آماده قالبهایی متنی هستند که برای جواب دادن سریع به یک گفتگو به کار میآیند.
برای ساختن یک جواب آماده، روی دکمه اضافه کردن جواب آماده کلیک کنید. همچنین با زدن روی دکمه «تغییر» یا «حذف» میتوانید یک پاسخ آماده را تغییر داده یا حذف کنید.
پاسخهای آماده با استفاده و با کمک کدهای کوتاه ساخته شدهاند. اپراتورها با زدن کلید '/' از صفحه کلید میتوانند به لیست پاسخهای آماده دسترسی پیدا کنند.
", + "SIDEBAR_TXT": "پاسخهای آماده
\nپاسخهای آماده قالبهایی متنی هستند که برای جواب دادن سریع به یک گفتگو به کار میآیند.
برای ساختن یک جواب آماده، روی دکمه اضافه کردن جواب آماده کلیک کنید. همچنین با زدن روی دکمه «تغییر» یا «حذف» میتوانید یک پاسخ آماده را تغییر داده یا حذف کنید.
پاسخهای آماده با استفاده و با کمک کدهای کوتاه ساخته شدهاند. ایجنت ها با زدن کلید '/' از صفحه کلید میتوانند به لیست پاسخهای آماده دسترسی پیدا کنند.
", "LIST": { "404": "هیچ پاسخ آمادهای برای این حساب تعریف نشده است", "TITLE": "مدیریت پاسخهای آماده", diff --git a/app/javascript/dashboard/i18n/locale/fa/chatlist.json b/app/javascript/dashboard/i18n/locale/fa/chatlist.json index 03fdf41d7..a83ff6b08 100644 --- a/app/javascript/dashboard/i18n/locale/fa/chatlist.json +++ b/app/javascript/dashboard/i18n/locale/fa/chatlist.json @@ -47,8 +47,12 @@ "VALUE": "resolved" }, { - "TEXT": "ربات", - "VALUE": "ربات" + "TEXT": "در انتظار", + "VALUE": "pending" + }, + { + "TEXT": "به تعویق افتاد", + "VALUE": "snoozed" } ], "ATTACHMENTS": { diff --git a/app/javascript/dashboard/i18n/locale/fa/contact.json b/app/javascript/dashboard/i18n/locale/fa/contact.json index 4d03d9feb..dde0b739e 100644 --- a/app/javascript/dashboard/i18n/locale/fa/contact.json +++ b/app/javascript/dashboard/i18n/locale/fa/contact.json @@ -19,8 +19,8 @@ }, "LABELS": { "CONTACT": { - "TITLE": "Contact Labels", - "ERROR": "Couldn't update labels" + "TITLE": "تماس با برچسب ها", + "ERROR": "به روزرسانی برچسب ها امکان پذیر نیست" }, "CONVERSATION": { "TITLE": "برچسبهای گفتگو", @@ -37,7 +37,12 @@ "MUTED_SUCCESS": "این گفتگو به مدت ۶ ساعت بیصدا است", "UNMUTED_SUCCESS": "این گفتگو از حالت بی صدا خارج شده است", "SEND_TRANSCRIPT": "ارسال متن", - "EDIT_LABEL": "ویرایش" + "EDIT_LABEL": "ویرایش", + "SIDEBAR_SECTIONS": { + "CUSTOM_ATTRIBUTES": "ویژگیهای سفارشی", + "CONTACT_LABELS": "تماس با برچسب ها", + "PREVIOUS_CONVERSATIONS": "گفتگوهای قبلی" + } }, "EDIT_CONTACT": { "BUTTON_LABEL": "ویرایش مخاطب", @@ -45,9 +50,9 @@ "DESC": "ویرایش اطلاعات مخاطب" }, "CREATE_CONTACT": { - "BUTTON_LABEL": "New Contact", - "TITLE": "Create new contact", - "DESC": "Add basic information details about the contact." + "BUTTON_LABEL": "تماس جدید", + "TITLE": "ایجاد مخاطب جدید", + "DESC": "اطلاعات اولیه درباره مخاطب را اضافه کنید." }, "CONTACT_FORM": { "FORM": { @@ -71,8 +76,8 @@ "PHONE_NUMBER": { "PLACEHOLDER": "شماره تلفن مخاطب را وارد کنید", "LABEL": "شماره تلفن", - "HELP": "Phone number should be of E.164 format eg: +1415555555 [+][country code][area code][local phone number]", - "ERROR": "Phone number should be either empty or of E.164 format" + "HELP": "شماره تلفن باید با فرمت E.164 باشد به عنوان مثال: +98415555555 [+] [کد کشور] [کد منطقه] [شماره تلفن محلی]", + "ERROR": "شماره تلفن باید یا خالی باشد و یا با فرمت E.164" }, "LOCATION": { "PLACEHOLDER": "مکان مخاطب را وارد کنید", @@ -101,7 +106,7 @@ } } }, - "SUCCESS_MESSAGE": "Contact saved successfully", + "SUCCESS_MESSAGE": "مخاطب با موفقیت ذخیره شد", "CONTACT_ALREADY_EXIST": "این آدرس ایمیل برای مخاطب دیگری در حال استفاده است.", "ERROR_MESSAGE": "خطایی پیش آمد. لطفا دوباره امتحان کنید" }, @@ -109,7 +114,7 @@ "BUTTON_LABEL": "شروع گفتگو", "TITLE": "گفتگوی جدید", "DESC": "با ارسال پیام جدید، گفتگوی جدیدی را شروع کنید.", - "NO_INBOX": "Couldn't find an inbox to initiate a new conversation with this contact.", + "NO_INBOX": "صندوق ورودی برای شروع مکالمه جدید با این مخاطب یافت نشد.", "FORM": { "TO": { "LABEL": "به" @@ -131,13 +136,13 @@ }, "CONTACTS_PAGE": { "HEADER": "مخاطبین", - "FIELDS": "Contact fields", + "FIELDS": "برچسب های تماس", "SEARCH_BUTTON": "جستجو", "SEARCH_INPUT_PLACEHOLDER": "جستجوی مخاطبین", "LIST": { "LOADING_MESSAGE": "در حال بارگذاری مخاطبین...", "404": "هیچ مخاطبی با جستجوی شما مطابقت ندارد 🔍", - "NO_CONTACTS": "There are no available contacts", + "NO_CONTACTS": "هیچ مخاطبی در دسترس نیست", "TABLE_HEADER": { "NAME": "نام", "PHONE_NUMBER": "شماره تلفن", @@ -155,16 +160,16 @@ "REMINDER": { "ADD_BUTTON": { "BUTTON": "افزودن", - "TITLE": "Shift + Enter to create a task" + "TITLE": "برای ایجاد کار Shift + Enter را فشار دهید" }, "FOOTER": { - "DUE_DATE": "Due date", - "LABEL_TITLE": "Set type" + "DUE_DATE": "تاریخ سررسید", + "LABEL_TITLE": "تنظیم نوع" } }, "NOTES": { "HEADER": { - "TITLE": "Notes" + "TITLE": "یادداشت" }, "ADD": { "BUTTON": "افزودن", @@ -172,66 +177,66 @@ "TITLE": "برای ایجاد یادداشت Shift + Enter را فشار دهید" }, "FOOTER": { - "BUTTON": "View all notes" + "BUTTON": "مشاهده همه یادداشت ها" } }, "EVENTS": { "HEADER": { - "TITLE": "Activities" + "TITLE": "فعالیت ها" }, "BUTTON": { - "PILL_BUTTON_NOTES": "notes", - "PILL_BUTTON_EVENTS": "events", + "PILL_BUTTON_NOTES": "یادداشت", + "PILL_BUTTON_EVENTS": "رویدادها", "PILL_BUTTON_CONVO": "گفتگوها" } }, "CUSTOM_ATTRIBUTES": { - "TITLE": "ویژگیهای سفارشی", - "BUTTON": "Add custom attribute", + "BUTTON": "اضافه کردن ویژگی سفارشی", + "NOT_AVAILABLE": "There are no custom attributes available for this contact.", "ADD": { - "TITLE": "Create custom attribute", - "DESC": "Add custom information to this contact." + "TITLE": "ساخت ویژگی سفارشی", + "DESC": "اطلاعات سفارشی مخاطب را اضافه کنید." }, "FORM": { - "CREATE": "Add attribute", + "CREATE": "افزودن ویژگی", "CANCEL": "انصراف", "NAME": { - "LABEL": "Custom attribute name", - "PLACEHOLDER": "Eg: shopify id", - "ERROR": "Invalid custom attribute name" + "LABEL": "نام ویژگی سفارشی", + "PLACEHOLDER": "به عنوان مثال: شناسه shopify", + "ERROR": "نام ویژگی سفارشی نامعتبر است" }, "VALUE": { - "LABEL": "Attribute value", - "PLACEHOLDER": "Eg: 11901 " + "LABEL": "مقدار ویژگی", + "PLACEHOLDER": "مثال: 11901 " } } }, "MERGE_CONTACTS": { - "TITLE": "Merge contacts", - "DESCRIPTION": "Merge contact is helpful when you have duplicated entries of the same contact. Merging action takes a primary contact and a child contact. After merging, all details in the primary contact will remain the same. If the primary contact doesn't have a field, then the value from the child contact will be used after merging. If a conflict happens, fields in primary contact will remain unaffected, but fields from secondary will be copied to the custom attributes in the primary contact.", + "TITLE": "ادغام مخاطبین", + "DESCRIPTION": "ادغام مخاطب زمانی مفید است که نوشته های یک مخاطب تکراری داشته باشید. ادغام مستلزم یک تماس اولیه و یک تماس ثانویه است. پس از ادغام ، تمام جزئیات در مخاطب اصلی یکسان می مانند. اگر مخاطب اصلی فیلدی ندارد ، پس از ادغام از مقدار مخاطب ثانویه استفاده می شود، در صورت بروز ناسازگاری فیلدهای موجود در مخاطب اصلی بدون تغییر باقی می مانند ، اما زمینه های ثانویه در ویژگی های سفارشی در مخاطب اصلی کپی می شوند.", "PRIMARY": { - "TITLE": "Primary contact" + "TITLE": "مخاطب اصلی" }, "CHILD": { - "TITLE": "Contact to merge", - "PLACEHOLDER": "Choose a contact" + "TITLE": "ادغام مخاطب", + "PLACEHOLDER": "انتخاب مخاطب" }, "SUMMARY": { - "TITLE": "Summary", - "DELETE_WARNING": "Contact of %{childContactName}will be deleted.", - "ATTRIBUTE_WARNING": "Contact details of %{childContactName} will be copied to %{primaryContactName}." + "TITLE": "خلاصه", + "DELETE_WARNING": "مخاطب %{childContactName} پاک خواهد شد.", + "ATTRIBUTE_WARNING": "اطلاعات مخاطب %{childContactName} کپی شود به %{primaryContactName}." }, "SEARCH": { "ERROR": "ERROR_MESSAGE" }, "FORM": { - "SUBMIT": " Merge contacts", + "SUBMIT": " ادغام مخاطبین", "CANCEL": "انصراف", "CHILD_CONTACT": { - "ERROR": "Select a child contact to merge" + "ERROR": "برای ادغام مخاطب ثانویه را انتخاب کنید" }, - "SUCCESS_MESSAGE": "Contact merged successfully", - "ERROR_MESSAGE": "Could not merge contcts, try again!" + "SUCCESS_MESSAGE": "مخاطب با موفقیت ادغام شد", + "ERROR_MESSAGE": "مخاطب ادغام نشد، دوباره امتحان کنید!" } } } diff --git a/app/javascript/dashboard/i18n/locale/fa/conversation.json b/app/javascript/dashboard/i18n/locale/fa/conversation.json index cc8e261f5..30f2c9d00 100644 --- a/app/javascript/dashboard/i18n/locale/fa/conversation.json +++ b/app/javascript/dashboard/i18n/locale/fa/conversation.json @@ -6,12 +6,13 @@ "NO_INBOX_1": "سلام! به نظر میرسد هنوز صندوق ورودی اضافه نکردهاید.", "NO_INBOX_2": " برای شروع", "NO_INBOX_AGENT": "اوه اوه! به نظر میرسد شما عضو هیچ صندوق ورودی نیستید. لطفا با مدیر خود تماس بگیرید", - "SEARCH_MESSAGES": "پیامها را در گفتگوها جستجو کنید", + "SEARCH_MESSAGES": "پیامها را در مکالمات جستجو کنید", "SEARCH": { "TITLE": "جستجو پیامها", + "RESULT_TITLE": "نتایج جستجو", "LOADING_MESSAGE": "درحال پردازش داده...", "PLACEHOLDER": "متنی برای جستجو پیام تایپ کنید", - "NO_MATCHING_RESULTS": "No results found." + "NO_MATCHING_RESULTS": "نتیجهای یافت نشد." }, "UNREAD_MESSAGES": "پیامهای خوانده نشده", "UNREAD_MESSAGE": "پیام خوانده نشده", @@ -20,15 +21,15 @@ "LOADING_CONVERSATIONS": "در حال بارگیری گفتگوها", "CANNOT_REPLY": "شما نمیتوانید پاسخ بدهید به دلیل", "24_HOURS_WINDOW": "محدودیت ۲۴ ساعته پنجره پیام", - "TWILIO_WHATSAPP_CAN_REPLY": "You can only reply to this conversation using a template message due to", + "TWILIO_WHATSAPP_CAN_REPLY": "شما فقط می توانید با استفاده از یک پیام الگو به این مکالمه پاسخ دهید", "TWILIO_WHATSAPP_24_HOURS_WINDOW": "محدودیت ۲۴ ساعته پنجره پیام", - "LAST_INCOMING_TWEET": "شما در حال پاسخ به آخرین توییت ورودی هستید", + "SELECT_A_TWEET_TO_REPLY": "لطفاً برای پاسخ دادن ، یک توییت را انتخاب کنید.", "REPLYING_TO": "شما در حال پاسخ دادن به:", "REMOVE_SELECTION": "حذف انتخابشدهها", "DOWNLOAD": "دانلود", "UPLOADING_ATTACHMENTS": "در حال بارگذاری پیوستها...", - "SUCCESS_DELETE_MESSAGE": "Message deleted successfully", - "FAIL_DELETE_MESSSAGE": "Couldn't delete message! Try again", + "SUCCESS_DELETE_MESSAGE": "پیام با موفقیت حذف شد", + "FAIL_DELETE_MESSSAGE": "پیام حذف نشد! دوباره امتحان کنید", "NO_RESPONSE": "بدون پاسخ", "RATING_TITLE": "رتبه", "FEEDBACK_TITLE": "بازخورد", @@ -41,7 +42,13 @@ "DETAILS": "جزئیات" }, "RESOLVE_DROPDOWN": { - "OPEN_BOT": "با ربات باز کنید" + "MARK_PENDING": "علامت گذاری به عنوان در انتظار", + "SNOOZE": { + "TITLE": "به تعویق انداختن تا", + "NEXT_REPLY": "پاسخ بعدی", + "TOMORROW": "فردا", + "NEXT_WEEK": "هفته بعد" + } }, "FOOTER": { "MSG_INPUT": "برای رفتن به سرخط shift+enter و برای استفاده از پیام های ذخیره شده / را بزنید.", @@ -57,13 +64,26 @@ "TIP_EMOJI_ICON": "انتخاب ایموجی", "TIP_ATTACH_ICON": "ضمیمه فایل", "ENTER_TO_SEND": "برای ارسال Enter را بزنید", - "DRAG_DROP": "Drag and drop here to attach" + "DRAG_DROP": "برای ضمیمه کردن درگ و درآپ کنید", + "EMAIL_HEAD": { + "ADD_BCC": "افزودن bcc", + "CC": { + "LABEL": "CC", + "PLACEHOLDER": "ایمیلها با کاما از هم جدا میشوند", + "ERROR": "لطفا آدرس ایمیل معتبر وارد کنید" + }, + "BCC": { + "LABEL": "BCC", + "PLACEHOLDER": "ایمیلها با کاما از هم جدا میشوند", + "ERROR": "لطفا آدرس ایمیل معتبر وارد کنید" + } + } }, "VISIBLE_TO_AGENTS": "یادداشت خصوصی: فقط برای شما و تیم شما قابل مشاهده است", "CHANGE_STATUS": "وضعیت گفتگو تغییر کرد", "CHANGE_AGENT": "مسول گفتگو تغییر کرد", - "CHANGE_TEAM": "Conversation team changed", - "FILE_SIZE_LIMIT": "File exceeds the {MAXIMUM_FILE_UPLOAD_SIZE} attachment limit", + "CHANGE_TEAM": "تیم مکالمه تغییر کرد", + "FILE_SIZE_LIMIT": "فایل ضمیمه شده بیشتر از {MAXIMUM_FILE_UPLOAD_SIZE} است", "SENT_BY": "ارسال شده توسط:", "ASSIGNMENT": { "SELECT_AGENT": "انتخاب ایجنت", @@ -93,35 +113,49 @@ } }, "ONBOARDING": { - "TITLE": "Hey 👋, Welcome to %{installationName}!", - "DESCRIPTION": "Thanks for signing up. We want you to get the most out of %{installationName}. Here are a few things you can do in %{installationName} to make the experience delightful.", - "READ_LATEST_UPDATES": "Read our latest updates", + "TITLE": "سلام 👋، خوش آمدی به %{installationName}!", + "DESCRIPTION": "از این که ثبت نام کرده اید سپاسگذاریم. ما ماخواهیم بهترین تجربه را از %{installationName} داشته باشید. در اینجا چند کار وجود دارد که می توانید در %{installationName} انجام دهید تا تجربه بهتری داشته باشید.", + "READ_LATEST_UPDATES": "آخرین به روزرسانی های ما را بخوانید", "ALL_CONVERSATION": { - "TITLE": "All your conversations in one place", - "DESCRIPTION": "View all the conversations from your customers in one single dashboard. You can filter the conversations by the incoming channel, label and status." + "TITLE": "همه مکالمات شما در یک مکان", + "DESCRIPTION": "همه مکالمات مشتریان خود را در یک داشبورد واحد مشاهده کنید. می توانید مکالمات را بر اساس کانال ، برچسب و وضعیت ورودی فیلتر کنید." }, "TEAM_MEMBERS": { - "TITLE": "Invite your team members", - "DESCRIPTION": "Since you are getting ready to talk to your customer, bring in your teammates to assist you. You can invite your teammates by adding their email address to the agent list.", - "NEW_LINK": "Click here to invite a team member" + "TITLE": "اعضای تیم خود را دعوت کنید", + "DESCRIPTION": "از آنجا که در حال آماده شدن برای صحبت با مشتری هستید ، می توانید از هم تیمی های خود نیز کمک بگیرید. با افزودن آدرس ایمیل آنها به لیست ایجنت ها، می توانید از هم تیمی های خود دعوت کنید.", + "NEW_LINK": "برای دعوت از یکی از اعضای تیم اینجا را کلیک کنید" }, "INBOXES": { - "TITLE": "Connect Inboxes", - "DESCRIPTION": "Connect various channels through which your customers would be talking to you. It can be a website live-chat, your Facebook or Twitter page or even your WhatsApp number.", - "NEW_LINK": "Click here to create an inbox" + "TITLE": "صندوق ورودی را وصل کنید", + "DESCRIPTION": "شما می توانید کانال های مختلفی را برای ارتباط با مشتری ایجاد نمایید، شما میتوانید از طریق چت داخل سایت یا فیس بوک یا توییتر و حتی واتس آپ استفاده نمایید.", + "NEW_LINK": "برای ایجاد صندوق ورودی اینجا را کلیک کنید" }, "LABELS": { - "TITLE": "Organize conversations with labels", - "DESCRIPTION": "Labels provide an easier way to categorize your conversation. Create some labels like #support-enquiry, #billing-question etc., so that you can use them in a conversation later.", - "NEW_LINK": "Click here to create tags" + "TITLE": "سازماندهی مکالمات با برچسب ها", + "DESCRIPTION": "برچسب ها روش ساده تری برای دسته بندی مکالمه شما فراهم می کنند. برخی از برچسب ها مانند #پشتیبانی-درخواست ، #صورتحساب و غیره را ایجاد کنید تا بعداً بتوانید از آنها در مکالمه استفاده کنید.", + "NEW_LINK": "برای ایجاد برچسب ها اینجا را کلیک کنید" } }, "CONVERSATION_SIDEBAR": { - "ASSIGNEE_LABEL": "Assigned Agent", - "SELF_ASSIGN": "Assign to me", - "TEAM_LABEL": "Assigned Team", + "ASSIGNEE_LABEL": "اختصاص به ایجنت", + "SELF_ASSIGN": "اختصاص به من", + "TEAM_LABEL": "اختصاص به تیم", "SELECT": { - "PLACEHOLDER": "None" + "PLACEHOLDER": "هیچکدام" + }, + "ACCORDION": { + "CONTACT_DETAILS": "Contact Details", + "CONVERSATION_ACTIONS": "Conversation Actions", + "CONVERSATION_LABELS": "برچسبهای گفتگو", + "CONVERSATION_INFO": "Conversation Information", + "CONTACT_ATTRIBUTES": "Contact Attributes", + "PREVIOUS_CONVERSATION": "گفتگوهای قبلی" } + }, + "EMAIL_HEADER": { + "TO": "به", + "BCC": "Bcc", + "CC": "Cc", + "SUBJECT": "موضوع" } } diff --git a/app/javascript/dashboard/i18n/locale/fa/csatMgmt.json b/app/javascript/dashboard/i18n/locale/fa/csatMgmt.json index d7d2efc2a..57afc6744 100644 --- a/app/javascript/dashboard/i18n/locale/fa/csatMgmt.json +++ b/app/javascript/dashboard/i18n/locale/fa/csatMgmt.json @@ -1,6 +1,6 @@ { "CSAT": { - "TITLE": "Rate your conversation", - "PLACEHOLDER": "Tell us more..." + "TITLE": "به مکالمه خود امتیاز دهید", + "PLACEHOLDER": "توضیحات بیشتر بدهید..." } } diff --git a/app/javascript/dashboard/i18n/locale/fa/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/fa/inboxMgmt.json index 30c7a438c..b08ae3d5d 100644 --- a/app/javascript/dashboard/i18n/locale/fa/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/fa/inboxMgmt.json @@ -1,7 +1,7 @@ { "INBOX_MGMT": { "HEADER": "صندوقهای ورودی", - "SIDEBAR_TXT": "صندوق ورودی
وقتی چت ووت به یک وب سایت یا یک صفحه فیس بوک متصل شود به آن صندوق ورودی میگوید. شما در حساب چت ووت خود میتوانید بینهایت صندوق ورودی داشته باشید.
روی دکمه اضافه کردن صندوق ورودی کلیک کنید تا به یک وب سایت یا یک صفحه فیس بوک وصل شوید.
در داشبورد، میتوانید گفتگوهای همه صندوقهای ورودی را یکجا ببینید و در تب «گفتگوها» به آنها پاسخ بدهید.
همچنین میتوانید با کلیک کردن روی اسم صندوق ورودی از قسمت سمت چپ، فقط گفتگوهای همان صندوق را ببینید.
", + "SIDEBAR_TXT": "صندوق ورودی
\nوقتی چت ووت به یک وب سایت یا یک صفحه فیس بوک متصل شود به آن صندوق ورودی میگوید. شما در حساب چت ووت خود میتوانید بینهایت صندوق ورودی داشته باشید.
روی دکمه اضافه کردن صندوق ورودی کلیک کنید تا به یک وب سایت یا یک صفحه فیس بوک وصل شوید.
در داشبورد، میتوانید گفتگوهای همه صندوقهای ورودی را یکجا ببینید و در تب «گفتگوها» به آنها پاسخ بدهید.
همچنین میتوانید با کلیک کردن روی اسم صندوق ورودی از قسمت سمت چپ، فقط گفتگوهای همان صندوق را ببینید.
", "LIST": { "404": "برای این حساب هیچ صندوق ورودی معرفی نشده است." }, @@ -17,9 +17,9 @@ "body": "به حساب کاربری وارد شوید و صندوق ورودی بسازید." }, { - "title": "معرفی اپراتور", + "title": "معرفی ایجنت", "route": "settings_inboxes_add_agents", - "body": "اپراتورها را به صندوق ورودی ساخته شده تخصیص میدهد" + "body": "ایجنت ها را به صندوق ورودی ساخته شده تخصیص میدهد." }, { "title": "ماشالله!", @@ -30,7 +30,7 @@ "ADD": { "CHANNEL_NAME": { "LABEL": "عنوان صندوق ورودی", - "PLACEHOLDER": "Enter your inbox name (eg: Acme Inc)" + "PLACEHOLDER": "نام صندوق ورودی خود را وارد کنید (به عنوان مثال: Acme Inc)" }, "WEBSITE_NAME": { "LABEL": "عنوان سایت", @@ -47,7 +47,7 @@ }, "TWITTER": { "HELP": "برای اضافه کردن امکان گفتگو از صفحه پروفایل توییترتان، لازم است با زدن دکمه `ورود با توییتر` پروفایل توییتر خود را شناسایی کنید' ", - "ERROR_MESSAGE": "There was an error connecting to Twitter, please try again" + "ERROR_MESSAGE": "هنگام اتصال به توییتر خطایی روی داد ، لطفاً دوباره امتحان کنید" }, "WEBSITE_CHANNEL": { "TITLE": "کانال وب سایت", @@ -128,12 +128,12 @@ } }, "SMS": { - "TITLE": "SMS Channel via Twilio", - "DESC": "Start supporting your customers via SMS with Twilio integration." + "TITLE": "کانال پیامک از طریق Twilio", + "DESC": "با ادغام Twilio از طریق SMS از مشتریان خود پشتیبانی کنید." }, "WHATSAPP": { - "TITLE": "Whatsapp Channel via Twilio", - "DESC": "Start supporting your customers via Whatsapp with Twilio integration." + "TITLE": "کانال واتساپ از طریق Twilio", + "DESC": "با ادغام Twilio از مشتریان خود از طریق Whatsapp پشتیبانی کنید." }, "API_CHANNEL": { "TITLE": "کانال API", @@ -172,13 +172,51 @@ }, "FINISH_MESSAGE": "ایمیل های خود را به این آدرس ها فوروارد کنید." }, + "LINE_CHANNEL": { + "TITLE": "LINE Channel", + "DESC": "Integrate with LINE channel and start supporting your customers.", + "CHANNEL_NAME": { + "LABEL": "عنوان کانال", + "PLACEHOLDER": "لطفا اسم یک کانال را وارد کنید", + "ERROR": "پر کردن این فیلد ضروری است" + }, + "LINE_CHANNEL_ID": { + "LABEL": "LINE Channel ID", + "PLACEHOLDER": "LINE Channel ID" + }, + "LINE_CHANNEL_SECRET": { + "LABEL": "LINE Channel Secret", + "PLACEHOLDER": "LINE Channel Secret" + }, + "LINE_CHANNEL_TOKEN": { + "LABEL": "LINE Channel Token", + "PLACEHOLDER": "LINE Channel Token" + }, + "SUBMIT_BUTTON": "Create LINE Channel", + "API": { + "ERROR_MESSAGE": "We were not able to save the LINE channel" + } + }, + "TELEGRAM_CHANNEL": { + "TITLE": "Telegram Channel", + "DESC": "Integrate with Telegram channel and start supporting your customers.", + "BOT_TOKEN": { + "LABEL": "Bot Token", + "SUBTITLE": "Configure the bot token you have obtained from Telegram BotFather.", + "PLACEHOLDER": "Bot Token" + }, + "SUBMIT_BUTTON": "Create Telegram Channel", + "API": { + "ERROR_MESSAGE": "We were not able to save the telegram channel" + } + }, "AUTH": { - "TITLE": "Choose a channel", - "DESC": "Chatwoot supports live-chat widget, Facebook page, Twitter profile, Whatsapp, Email etc., as channels. If you want to build a custom channel, you can create it using the API channel. Select one channel from the options below to proceed." + "TITLE": "کانالی را انتخاب کنید", + "DESC": "ما از چت زنده روی سایت، فیسبوک، توییتر، واتس آپ و ایمیل پشتیبانی می کنیم. در صورتی که نیاز به ارتباط از طریق کانال اختصاصی دیگیر دارید می توانید آن را به کمک API ایجاد نمایید." }, "AGENTS": { - "TITLE": "اپراتورها", - "DESC": "در اینجا میتوانید اپراتورها را به صندوق ورودی خود اختصاص دهید. توجه داشته باشید که فقط اپراتورهایی که در اینجا معرفی شده باشند میتوانند به پیامهای این صندوق پاسخ بدهند.دیگر اپراتورها نخواهند توانست پیامهای این صندوق را ببینید یا به آنها پاسخی بدهند.وب هوکها
وب هوکها اجرا کنندهی درخواستهای HTTP هستند که برای هر حسابی قابل تنظیم شدن هستند. به عنوان مثال میتوان وقتی گفتگوی جدیدی ایجاد شد یک وب سرویس صدا زده شود. برای هر حساب میتوان چند وب هوک ایجاد کرد.
برای ساختن یک وب هوک, روی دکمه اضافه کردن وب هوک جدید کلیک کنید. همچنین با زدن دکمه «حذف» میتوانید وب هوک ساخته شده را حذف کنید.
وب هوکها
\nوب هوکها اجرا کنندهی درخواستهای HTTP هستند که برای هر حسابی قابل تنظیم شدن هستند. به عنوان مثال میتوان وقتی گفتگوی جدیدی ایجاد شد یک وب سرویس صدا زده شود. برای هر حساب میتوان چند وب هوک ایجاد کرد.
برای ساختن یک وب هوک, روی دکمه اضافه کردن وب هوک جدید کلیک کنید. همچنین با زدن دکمه «حذف» میتوانید وب هوک ساخته شده را حذف کنید.
Chatwoot will now sync all the incoming conversations into the customer-conversations channel inside your slack workplace.
Replying to a conversation thread in customer-conversations slack channel will create a response back to the customer through chatwoot.
Start the replies with note: to create private notes instead of replies.
If the replier on slack has an agent profile in chatwoot under the same email, the replies will be associated accordingly.
When the replier doesn't have an associated agent profile, the replies will be made from the bot profile.
" + "TITLE": "استفاده از اسلک", + "BODY": "ما اکنون تمام مکالمات ورودی را در کانال گفتگوهای مشتری داخل محل کار شما همگام سازی می کنیم.
پاسخ به یک رشته مکالمه در کانال مکالمه مشتری- مکالمات i> از طریق برنامه پاسخی به مشتری ایجاد می کند. p>
پاسخ ها را با شروع کنید توجه: برای ایجاد یادداشت های خصوصی به جای پاسخ ها.
اگر پاسخ دهنده در slack نمایه نماینده ای در برنامه تحت همان ایمیل داشته باشد ، پاسخ ها به همین ترتیب مرتبط می شوند. p>
وقتی ارسال کننده نمایه نماینده مرتبطی ندارد ، پاسخها از نمایه ربات انجام می شود.
" } }, "DELETE": { diff --git a/app/javascript/dashboard/i18n/locale/fa/labelsMgmt.json b/app/javascript/dashboard/i18n/locale/fa/labelsMgmt.json index 9dae44f4b..09b436f2a 100644 --- a/app/javascript/dashboard/i18n/locale/fa/labelsMgmt.json +++ b/app/javascript/dashboard/i18n/locale/fa/labelsMgmt.json @@ -19,9 +19,9 @@ "NAME": { "LABEL": "نام برچسب", "PLACEHOLDER": "نام برچسب", - "REQUIRED_ERROR": "Label name is required", - "MINIMUM_LENGTH_ERROR": "Minimum length 2 is required", - "VALID_ERROR": "Only Alphabets, Numbers, Hyphen and Underscore are allowed" + "REQUIRED_ERROR": "نام برچسب لازم است", + "MINIMUM_LENGTH_ERROR": "باید بیشتر از 2 کاراکتر باشد", + "VALID_ERROR": "فقط حروف ، اعداد ، خط تیره و زیر خط مجاز است" }, "DESCRIPTION": { "LABEL": "توضیحات", diff --git a/app/javascript/dashboard/i18n/locale/fa/report.json b/app/javascript/dashboard/i18n/locale/fa/report.json index d73aa3216..bf013e3f4 100644 --- a/app/javascript/dashboard/i18n/locale/fa/report.json +++ b/app/javascript/dashboard/i18n/locale/fa/report.json @@ -1,6 +1,6 @@ { "REPORT": { - "HEADER": "Overview", + "HEADER": "بررسی اجمالی", "LOADING_CHART": "در حال دریافت اطلاعات...", "NO_ENOUGH_DATA": "متاسفانه اطلاعات کافی دریافت نشد، لطفا بعدا دوباره امتحان کنید", "DOWNLOAD_AGENT_REPORTS": "دانلود گزارش ایجنت", @@ -53,37 +53,37 @@ }, { "id": 5, - "name": "Custom date range" + "name": "محدوده تاریخ سفارشی" } ], "CUSTOM_DATE_RANGE": { - "CONFIRM": "Apply", - "PLACEHOLDER": "Select date range" + "CONFIRM": "درخواست دادن", + "PLACEHOLDER": "محدوده تاریخ را انتخاب کنید" } }, "CSAT_REPORTS": { - "HEADER": "CSAT Reports", - "NO_RECORDS": "There are no CSAT survey responses available.", + "HEADER": "گزارشات رضایت مشتری", + "NO_RECORDS": "هیچ پاسخ برای نظرسنجی رضایت مشتری در دسترس نیست.", "TABLE": { "HEADER": { - "CONTACT_NAME": "Contact", - "AGENT_NAME": "Assigned agent", + "CONTACT_NAME": "مخاطب", + "AGENT_NAME": "ایجنت تعیین شده", "RATING": "رتبه", - "FEEDBACK_TEXT": "Feedback comment" + "FEEDBACK_TEXT": "نظر ثبت شده" } }, "METRIC": { "TOTAL_RESPONSES": { - "LABEL": "Total responses", - "TOOLTIP": "Total number of responses collected" + "LABEL": "مجموع پاسخ ها", + "TOOLTIP": "تعداد کل پاسخهای جمع آوری شده" }, "SATISFACTION_SCORE": { - "LABEL": "Satisfaction score", - "TOOLTIP": "Total number of positive responses / Total number of responses * 100" + "LABEL": "نمره رضایت", + "TOOLTIP": "تعداد کل پاسخ های مثبت / تعداد کل پاسخ ها از 100" }, "RESPONSE_RATE": { - "LABEL": "Response rate", - "TOOLTIP": "Total number of responses / Total number of CSAT survey messages sent * 100" + "LABEL": "نرخ پاسخ", + "TOOLTIP": "تعداد کل پاسخ ها / تعداد کل پیام های نظرسنجی رضایت مشتری ارسال شده از 100" } } } diff --git a/app/javascript/dashboard/i18n/locale/fa/settings.json b/app/javascript/dashboard/i18n/locale/fa/settings.json index a6e078a7d..fca673a13 100644 --- a/app/javascript/dashboard/i18n/locale/fa/settings.json +++ b/app/javascript/dashboard/i18n/locale/fa/settings.json @@ -14,7 +14,7 @@ "UPDATE_IMAGE": "تغییر عکس", "PROFILE_SECTION": { "TITLE": "پروفایل", - "NOTE": "ایمیل عامل شناسایی شما برای ورود به سیستم است" + "NOTE": "آدرس ایمیل شما هویت شماست و برای ورود به سیستم استفاده می شود." }, "PASSWORD_SECTION": { "TITLE": "رمز عبور", @@ -26,11 +26,11 @@ "NOTE": "از این توکن برای دسترسی از طریق API استفاده میشود" }, "AUDIO_NOTIFICATIONS_SECTION": { - "TITLE": "Audio Notifications", - "NOTE": "Enable audio notifications in dashboard for new messages and conversations.", - "NONE": "None", - "ASSIGNED": "Assigned Conversations", - "ALL_CONVERSATIONS": "All Conversations" + "TITLE": "اعلان های صوتی", + "NOTE": "اعلان های صوتی را در داشبورد برای پیام ها و مکالمات جدید فعال کنید.", + "NONE": "هیچکدام", + "ASSIGNED": "مکالمات اختصاص داده شده", + "ALL_CONVERSATIONS": "همه مکالمات" }, "EMAIL_NOTIFICATIONS_SECTION": { "TITLE": "اعلامیه به ایمیل", @@ -81,9 +81,9 @@ "PLACEHOLDER": "لطفا ایمیل خود را وارد کنید، این ایمیل در گفتگوها دیده میشود" }, "CURRENT_PASSWORD": { - "LABEL": "Current password", - "ERROR": "Please enter the current password", - "PLACEHOLDER": "Please enter the current password" + "LABEL": "رمز عبور فعلی", + "ERROR": "لطفاً رمز عبور فعلی را وارد کنید", + "PLACEHOLDER": "لطفاً رمز عبور فعلی را وارد کنید" }, "PASSWORD": { "LABEL": "رمز عبور", @@ -102,6 +102,7 @@ "CHANGE_ACCOUNTS": "سوییچ به یک حساب دیگر", "SELECTOR_SUBTITLE": "از لیست یکی از حسابها را انتخاب کنید", "PROFILE_SETTINGS": "تنظیمات پروفایل", + "KEYBOARD_SHORTCUTS": "میانبرهای صفحهکلید", "LOGOUT": "خروج از حساب" }, "APP_GLOBAL": { @@ -130,24 +131,29 @@ "SIDEBAR": { "CONVERSATIONS": "گفتگوها", "REPORTS": "گزارشات", - "CONTACTS": "مخاطبین", "SETTINGS": "تنظیمات", + "CONTACTS": "مخاطبین", "HOME": "صفحه اصلی", - "AGENTS": "اپراتورها", + "AGENTS": "ایجنت ها", "INBOXES": "صندوقهای ورودی", "NOTIFICATIONS": "اعلان ها", "CANNED_RESPONSES": "پاسخهای آماده", "INTEGRATIONS": "برنامههای تلفیق شده", "ACCOUNT_SETTINGS": "تنظیمات حساب", - "APPLICATIONS": "Applications", + "APPLICATIONS": "برنامه های کاربردی", "LABELS": "برچسبها", + "ATTRIBUTES": "ویژگی ها", "TEAMS": "تیمها", - "ALL_CONTACTS": "All Contacts", - "TAGGED_WITH": "Tagged with", - "REPORTS_OVERVIEW": "Overview", - "CSAT": "CSAT" + "ALL_CONTACTS": "تمام مخاطبین", + "TAGGED_WITH": "برچسب گذاری شده با", + "REPORTS_OVERVIEW": "بررسی اجمالی", + "CSAT": "رضایت مشتری", + "CAMPAIGNS": "کمپین ها", + "ONGOING": "درحال انجام", + "ONE_OFF": "یکبار مصرف" }, "CREATE_ACCOUNT": { + "NO_ACCOUNT_WARNING": "اوه اوه! ما هیچ حسابی روی Chatwoot پاز شما پیدا نکردیم. لطفاً برای ادامه یک حساب جدید ایجاد کنید.", "NEW_ACCOUNT": "حسابکاربری جدید", "SELECTOR_SUBTITLE": "ایجاد حسابکاربری جدید", "API": { @@ -162,5 +168,30 @@ }, "SUBMIT": "ثبت" } + }, + "KEYBOARD_SHORTCUTS": { + "TITLE": { + "OPEN_CONVERSATION": "باز کردن مکالمه", + "RESOLVE_AND_NEXT": "حل کنید و به مرحله بعدی بروید", + "NAVIGATE_DROPDOWN": "به موارد کشویی بروید", + "RESOLVE_CONVERSATION": "حل مکالمه", + "GO_TO_CONVERSATION_DASHBOARD": "به داشبورد مکالمه بروید", + "ADD_ATTACHMENT": "افزودن پیوست", + "GO_TO_CONTACTS_DASHBOARD": "به داشبورد مخاطبین بروید", + "TOGGLE_SIDEBAR": "نوار کناری", + "GO_TO_REPORTS_SIDEBAR": "به نوار کناری گزارش ها بروید", + "MOVE_TO_NEXT_TAB": "به برگه بعدی در فهرست مکالمه بروید", + "GO_TO_SETTINGS": "برو به تنظیمات", + "SWITCH_CONVERSATION_STATUS": "به وضعیت مکالمه بعدی بروید", + "SWITCH_TO_PRIVATE_NOTE": "رفتن به یادداشت خصوصی", + "TOGGLE_RICH_CONTENT_EDITOR": "تغییر وضعیت ویرایشگر محتوا", + "SWITCH_TO_REPLY": "رفتن به پاسخ", + "TOGGLE_SNOOZE_DROPDOWN": "تغییر حالت بازکردن تعویق" + }, + "KEYS": { + "WINDOWS_KEY_AND_COMMAND_KEY": "Win / ⌘", + "ALT_OR_OPTION_KEY": "Alt / ⌥", + "FORWARD_SLASH_KEY": "/" + } } } diff --git a/app/javascript/dashboard/i18n/locale/fa/teamsSettings.json b/app/javascript/dashboard/i18n/locale/fa/teamsSettings.json index fdf867295..94fa5cd32 100644 --- a/app/javascript/dashboard/i18n/locale/fa/teamsSettings.json +++ b/app/javascript/dashboard/i18n/locale/fa/teamsSettings.json @@ -2,9 +2,9 @@ "TEAMS_SETTINGS": { "NEW_TEAM": "ایجاد تیم جدید", "HEADER": "تیمها", - "SIDEBAR_TXT": "Teams
Teams let you organize your agents into groups based on their responsibilities.
A user can be part of multiple teams. You can assign conversations to a team when you are working collaboratively.
تیمها
تیمها به شما امکان می دهند ایجنت ها خود را بر اساس مسئولیت های آنها در گروه ها سازماندهی کنید.
یک کاربر می تواند بخشی از چندین تیم باشد. هنگامی که به طور مشترک کار می کنید ، می توانید مکالمات را به یک تیم اختصاص دهید.
Edustajat
Edustaja on jäsenenä asiakastukitiimissäsi.
Edustajat voivat katsella ja vastata viesteihin asiakkailtasi. Luettelo näyttää kaikki edustajat, jotka ovat tällä hetkellä tililläsi.
Klikkaa Lisää edustaja lisätäksesi uuden edustajan. Edustaja, jonka lisäät, saa sähköpostiviestin, jossa on vahvistuslinkki tilin aktivointiin, jonka jälkeen he voivat käyttää Chatwoot -sovellusta ja vastata viesteihin.
Pääsy Chatwoot'n ominaisuuksiin perustuu seuraaviin rooleihin.
Edustaja - Tällä roolilla toimivat edustajat voivat käyttää vain saapuneita, raportteja ja keskusteluja. He voivat määrittää keskusteluja muille edustajille tai itse ratkaista keskusteluja.
Ylläpitäjä - Ylläpitäjällä on pääsy kaikkiin Chatwoot ominaisuuksiin, jotka ovat käytössä tililläsi, mukaan lukien asetukset sekä kaikki normaalien asiamiesten oikeudet.
", + "SIDEBAR_TXT": "Edustajat
An Edustaja on jäsenenä asiakastukitiimissäsi.
Edustajat voivat katsella ja vastata viesteihin asiakkailtasi. Luettelo näyttää kaikki edustajat, jotka ovat tällä hetkellä tililläsi.
Klikkaa Lisää edustaja lisätäksesi uuden edustajan. Edustaja, jonka lisäät, saa sähköpostiviestin, jossa on vahvistuslinkki tilin aktivointiin, jonka jälkeen he voivat käyttää Chatwoot -sovellusta ja vastata viesteihin.
Pääsy Chatwoot'n ominaisuuksiin perustuu seuraaviin rooleihin.
Edustaja - Tällä roolilla toimivat edustajat voivat käyttää vain saapuneita, raportteja ja keskusteluja. He voivat määrittää keskusteluja muille edustajille tai itse ratkaista keskusteluja.
Ylläpitäjä - Ylläpitäjällä on pääsy kaikkiin Chatwoot ominaisuuksiin, jotka ovat käytössä tililläsi, mukaan lukien asetukset sekä kaikki normaalien asiamiesten oikeudet.
", "AGENT_TYPES": { "ADMINISTRATOR": "Ylläpitäjä", "AGENT": "Edustajat" @@ -29,9 +29,9 @@ "PLACEHOLDER": "Ole hyvä ja kirjoita edustajan nimi" }, "AGENT_TYPE": { - "LABEL": "Edustajan tyyppi", - "PLACEHOLDER": "Valitse tyyppi", - "ERROR": "Edustajan tyyppi on pakollinen" + "LABEL": "Agent Type", + "PLACEHOLDER": "Please select a type", + "ERROR": "Agent type is required" }, "EMAIL": { "LABEL": "Sähköpostiosoite", @@ -66,9 +66,9 @@ "PLACEHOLDER": "Ole hyvä ja kirjoita edustajan nimi" }, "AGENT_TYPE": { - "LABEL": "Edustajan tyyppi", - "PLACEHOLDER": "Valitse edustajan tyyppi", - "ERROR": "Edustajan tyyppi on pakollinen" + "LABEL": "Agent Type", + "PLACEHOLDER": "Please select a type", + "ERROR": "Agent type is required" }, "EMAIL": { "LABEL": "Sähköpostiosoite", @@ -90,7 +90,24 @@ } }, "SEARCH": { - "NO_RESULTS": "Ei hakutuloksia." + "NO_RESULTS": "No results found." + }, + "MULTI_SELECTOR": { + "PLACEHOLDER": "None", + "TITLE": { + "AGENT": "Select agent", + "TEAM": "Select team" + }, + "SEARCH": { + "NO_RESULTS": { + "AGENT": "Edustajia ei löytynyt", + "TEAM": "No teams found" + }, + "PLACEHOLDER": { + "AGENT": "Search agents", + "TEAM": "Search teams" + } + } } } } diff --git a/app/javascript/dashboard/i18n/locale/fi/attributesMgmt.json b/app/javascript/dashboard/i18n/locale/fi/attributesMgmt.json new file mode 100644 index 000000000..1062a3b73 --- /dev/null +++ b/app/javascript/dashboard/i18n/locale/fi/attributesMgmt.json @@ -0,0 +1,85 @@ +{ + "ATTRIBUTES_MGMT": { + "HEADER": "Attributes", + "HEADER_BTN_TXT": "Add Attribute", + "LOADING": "Fetching attributes", + "SIDEBAR_TXT": "Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Postilaatikko
Kun yhdistät sivuston tai Facebook-sivun Chatwotiin, sitä kutsutaan postilaatikoksi. Sinulla voi olla rajoittamaton määrä postilaatikoita Chatwoot tililläsi.
Klikkaa Lisää postilaatikko yhdistääksesi verkkosivuston tai Facebook-sivun.
Kojelaudalla näet kaikki keskustelut kaikista saapuneet-kansiostasi yhdessä paikassa ja vastaat niihin `Keskustelut`-välilehdessä.
Voit myös nähdä postilaatikkoon liittyviä keskusteluja klikkaamalla postilaatikon nimeä kojelaudan vasemmassa paneelissa.
", + "SIDEBAR_TXT": "Postilaatikko
Kun yhdistät sivuston tai facebook-sivun Chatwotiin, sitä kutsutaan postilaatikoksi. Sinulla voi olla rajoittamaton määrä postilaatikoita Chatwoot tililläsi.
Klikkaa Lisää postilaatikko yhdistääksesi verkkosivuston tai Facebook-sivun.
Kojelaudalla näet kaikki keskustelut kaikista saapuneet-kansiostasi yhdessä paikassa ja vastaat niihin `Keskustelut`-välilehdessä.
Voit myös nähdä postilaatikkoon liittyviä keskusteluja klikkaamalla postilaatikon nimeä kojelaudan vasemmassa paneelissa.
", "LIST": { "404": "Tähän tiliin ei ole liitetty saapuneet-kansiota." }, @@ -30,7 +30,7 @@ "ADD": { "CHANNEL_NAME": { "LABEL": "Kansion nimi", - "PLACEHOLDER": "Valitse kansion nimi (esim: Acme Oy)" + "PLACEHOLDER": "Enter your inbox name (eg: Acme Inc)" }, "WEBSITE_NAME": { "LABEL": "Sivuston nimi", @@ -47,7 +47,7 @@ }, "TWITTER": { "HELP": "Lisätäksesi twitter-profiilin kanavaksesi, sinun tulee autentikoida twitter-tilisi klikkaamalla \"Kirjaudu sisään Twitterillä\" ", - "ERROR_MESSAGE": "Twitteriin yhdistäessä tapahtui virhe" + "ERROR_MESSAGE": "There was an error connecting to Twitter, please try again" }, "WEBSITE_CHANNEL": { "TITLE": "Sivuston chat", @@ -83,7 +83,7 @@ "IN_A_FEW_MINUTES": "Muutamassa minuutissa", "IN_A_FEW_HOURS": "Muutamassa tunnissa", "IN_A_DAY": "Päivän kuluessa", - "HELP_TEXT": "Vastausaika näytetään chat-widgetissä" + "HELP_TEXT": "Vastausaika näytetään chat -widgetissä" }, "WIDGET_COLOR": { "LABEL": "Widgetin väri", @@ -128,12 +128,12 @@ } }, "SMS": { - "TITLE": "SMS Twilio:n kautta", - "DESC": "Ala palvelemaan asiakkaitasi tekstiviestien avulla käyttäen Twilio-alustaa" + "TITLE": "SMS Channel via Twilio", + "DESC": "Start supporting your customers via SMS with Twilio integration." }, "WHATSAPP": { - "TITLE": "Whatsapp Twilio:n kautta", - "DESC": "Ala palvelemaan asiakkaitasi Whatsapp-viestien avulla käyttäen Twilio-alustaa" + "TITLE": "Whatsapp Channel via Twilio", + "DESC": "Start supporting your customers via Whatsapp with Twilio integration." }, "API_CHANNEL": { "TITLE": "API-rajapinta", @@ -172,9 +172,47 @@ }, "FINISH_MESSAGE": "Aloita välittämällä sähköpostit seuraavaan osoitteeseen." }, + "LINE_CHANNEL": { + "TITLE": "LINE Channel", + "DESC": "Integrate with LINE channel and start supporting your customers.", + "CHANNEL_NAME": { + "LABEL": "Kanavan nimi", + "PLACEHOLDER": "Ole hyvä ja anna kanavan nimi", + "ERROR": "Tämä kenttä on pakollinen" + }, + "LINE_CHANNEL_ID": { + "LABEL": "LINE Channel ID", + "PLACEHOLDER": "LINE Channel ID" + }, + "LINE_CHANNEL_SECRET": { + "LABEL": "LINE Channel Secret", + "PLACEHOLDER": "LINE Channel Secret" + }, + "LINE_CHANNEL_TOKEN": { + "LABEL": "LINE Channel Token", + "PLACEHOLDER": "LINE Channel Token" + }, + "SUBMIT_BUTTON": "Create LINE Channel", + "API": { + "ERROR_MESSAGE": "We were not able to save the LINE channel" + } + }, + "TELEGRAM_CHANNEL": { + "TITLE": "Telegram Channel", + "DESC": "Integrate with Telegram channel and start supporting your customers.", + "BOT_TOKEN": { + "LABEL": "Bot Token", + "SUBTITLE": "Configure the bot token you have obtained from Telegram BotFather.", + "PLACEHOLDER": "Bot Token" + }, + "SUBMIT_BUTTON": "Create Telegram Channel", + "API": { + "ERROR_MESSAGE": "We were not able to save the telegram channel" + } + }, "AUTH": { - "TITLE": "Valitse kanava", - "DESC": "Chatwoot tukee live-chat widgettiä, Facebook-sivua, Twitter-profiilia, Whatsappia, Sähköpostia jne., as channels. Voit luoda oman kanavan API-rajapinnalla." + "TITLE": "Choose a channel", + "DESC": "Chatwoot supports live-chat widget, Facebook page, Twitter profile, Whatsapp, Email etc., as channels. If you want to build a custom channel, you can create it using the API channel. Select one channel from the options below to proceed." }, "AGENTS": { "TITLE": "Edustajat", @@ -232,6 +270,7 @@ }, "DELETE": { "BUTTON_TEXT": "Poista", + "AVATAR_DELETE_BUTTON_TEXT": "Delete Avatar", "CONFIRM": { "TITLE": "Vahvista poistaminen", "MESSAGE": "Oletko varma että haluat poistaa ", @@ -241,7 +280,9 @@ }, "API": { "SUCCESS_MESSAGE": "Postilaatikko poistettu onnistuneesti", - "ERROR_MESSAGE": "Postilaatikkoa ei voitu poistaa. Yritä myöhemmin uudelleen." + "ERROR_MESSAGE": "Postilaatikkoa ei voitu poistaa. Yritä myöhemmin uudelleen.", + "AVATAR_SUCCESS_MESSAGE": "Inbox avatar deleted successfully", + "AVATAR_ERROR_MESSAGE": "Could not delete the inbox avatar. Please try again later." } }, "TABS": { @@ -264,16 +305,20 @@ "INBOX_AGENTS": "Edustajat", "INBOX_AGENTS_SUB_TEXT": "Lisää tai poista edustajia tästä saapuneet-kansiosta", "UPDATE": "Päivitä", - "ENABLE_EMAIL_COLLECT_BOX": "Aktivoi sähköpostilaatikko", - "ENABLE_EMAIL_COLLECT_BOX_SUB_TEXT": "Aktivoi tai disabloi sähköpostilaatikko uusissa keskusteluissa", + "ENABLE_EMAIL_COLLECT_BOX": "Enable email collect box", + "ENABLE_EMAIL_COLLECT_BOX_SUB_TEXT": "Enable or disable email collect box on new conversation", "AUTO_ASSIGNMENT": "Ota automaattinen delegointi käyttöön", - "ENABLE_CSAT": "Aktivoi ASTK", - "ENABLE_CSAT_SUB_TEXT": "Aktivoi/Disabloi ASTK(ASiakasTyytyväisyysKysely) keskustelun ratkaisun jälkeen", + "ENABLE_CSAT": "Enable CSAT", + "ENABLE_CSAT_SUB_TEXT": "Enable/Disable CSAT(Customer satisfaction) survey after resolving a conversation", "INBOX_UPDATE_TITLE": "Postilaatikon tiedot", "INBOX_UPDATE_SUB_TEXT": "Päivitä postilaatikon asetukset", "AUTO_ASSIGNMENT_SUB_TEXT": "Ota käyttöön tai poista käytöstä automaattinen keskusteluiden delegointi edustajille.", - "HMAC_VERIFICATION": "Käyttäjän identiteettivarmistus", - "HMAC_DESCRIPTION": "Varmistaaksemme käyttäjän identiteetin, SDK sallii sinun antaa `identifier_hash` jokaiselle käyttäjälle. Voit generoida HMAC käyttäen 'sha256' avaimella joka on alla." + "HMAC_VERIFICATION": "User Identity Validation", + "HMAC_DESCRIPTION": "Inorder to validate the user's identity, the SDK allows you to pass an `identifier_hash` for each user. You can generate HMAC using 'sha256' with the key shown here.", + "INBOX_IDENTIFIER": "Inbox Identifier", + "INBOX_IDENTIFIER_SUB_TEXT": "Use the `inbox_identifier` token shown here to authentication your API clients.", + "FORWARD_EMAIL_TITLE": "Forward to Email", + "FORWARD_EMAIL_SUB_TEXT": "Aloita välittämällä sähköpostit seuraavaan osoitteeseen." }, "FACEBOOK_REAUTHORIZE": { "TITLE": "Uudelleenvaltuuta", @@ -282,38 +327,38 @@ "MESSAGE_ERROR": "Tapahtui virhe, yritä uudelleen" }, "PRE_CHAT_FORM": { - "DESCRIPTION": "Pikakysely kysyy käyttäjän sähköpostin ja nimen ennen keskustelua", + "DESCRIPTION": "Pre chat forms enable you to capture user information before they start conversation with you.", "ENABLE": { - "LABEL": "Aktivoi pikakysely", + "LABEL": "Enable pre chat form", "OPTIONS": { - "ENABLED": "Kyllä", - "DISABLED": "Ei" + "ENABLED": "Yes", + "DISABLED": "No" } }, "PRE_CHAT_MESSAGE": { - "LABEL": "Pikakyselyviesti", - "PLACEHOLDER": "Tämä viesti näytetään käyttäjille joille pikakysely näytetään" + "LABEL": "Pre Chat Message", + "PLACEHOLDER": "This message would be visible to the users along with the form" }, "REQUIRE_EMAIL": { - "LABEL": "Käyttäjien tulee antaa sähköpostiosoite ja nimi ennen keskustelun aloitusta" + "LABEL": "Visitors should provide their name and email address before starting the chat" } }, "BUSINESS_HOURS": { - "TITLE": "Aseta tilasi", - "SUBTITLE": "Aseta tilasi livechat widgetissä", - "WEEKLY_TITLE": "Aseta viikkotyöaikasi", - "TIMEZONE_LABEL": "Aseta aikavyöhyke", - "UPDATE": "Aseta työaika", - "TOGGLE_AVAILABILITY": "Aktivoi työaikasaatavuus tälle kansiolle", - "UNAVAILABLE_MESSAGE_LABEL": "Ei saatavilla-viesti käyttäjille", - "UNAVAILABLE_MESSAGE_DEFAULT": "Emme ole saatavilla juuri nyt. Jätä viesti ja vastaamme heti kun pystymme.", - "TOGGLE_HELP": "Aktivoimalla työaikasaatavuus livechat widgetissä näytetään olevanne saatavilla, vaikka kukaan edustaja ei olisi paikalla. Näiden aikojen ulkopuolella käyttäjille näytetään varoitus ja pikakysely.", + "TITLE": "Set your availability", + "SUBTITLE": "Set your availability on your livechat widget", + "WEEKLY_TITLE": "Set your weekly hours", + "TIMEZONE_LABEL": "Select timezone", + "UPDATE": "Update business hours settings", + "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", + "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { - "ENABLE": "Aktivoi saatavuus tälle päivälle", - "UNAVAILABLE": "Ei saatavilla", - "HOURS": "tuntia", - "VALIDATION_ERROR": "Avaamisajan tulisi olla ennen sulkemisaikaa.", - "CHOOSE": "Valitse" + "ENABLE": "Enable availability for this day", + "UNAVAILABLE": "Unavailable", + "HOURS": "hours", + "VALIDATION_ERROR": "Starting time should be before closing time.", + "CHOOSE": "Choose" } } } diff --git a/app/javascript/dashboard/i18n/locale/fi/index.js b/app/javascript/dashboard/i18n/locale/fi/index.js index cf1dda7fe..bfcef683a 100644 --- a/app/javascript/dashboard/i18n/locale/fi/index.js +++ b/app/javascript/dashboard/i18n/locale/fi/index.js @@ -1,11 +1,14 @@ import { default as _agentMgmt } from './agentMgmt.json'; +import { default as _attributesMgmt } from './attributesMgmt.json'; import { default as _campaign } from './campaign.json'; import { default as _cannedMgmt } from './cannedMgmt.json'; import { default as _chatlist } from './chatlist.json'; import { default as _contact } from './contact.json'; import { default as _conversation } from './conversation.json'; +import { default as _csatMgmtMgmt } from './csatMgmt.json'; import { default as _generalSettings } from './generalSettings.json'; import { default as _inboxMgmt } from './inboxMgmt.json'; +import { default as _integrationApps } from './integrationApps.json'; import { default as _integrations } from './integrations.json'; import { default as _labelsMgmt } from './labelsMgmt.json'; import { default as _login } from './login.json'; @@ -18,13 +21,16 @@ import { default as _teamsSettings } from './teamsSettings.json'; export default { ..._agentMgmt, + ..._attributesMgmt, ..._campaign, ..._cannedMgmt, ..._chatlist, ..._contact, ..._conversation, + ..._csatMgmtMgmt, ..._generalSettings, ..._inboxMgmt, + ..._integrationApps, ..._integrations, ..._labelsMgmt, ..._login, diff --git a/app/javascript/dashboard/i18n/locale/fi/integrationApps.json b/app/javascript/dashboard/i18n/locale/fi/integrationApps.json index 3bdbf7a6a..ac9f76d68 100644 --- a/app/javascript/dashboard/i18n/locale/fi/integrationApps.json +++ b/app/javascript/dashboard/i18n/locale/fi/integrationApps.json @@ -1,36 +1,36 @@ { "INTEGRATION_APPS": { - "FETCHING": "Haetaan integraatioita", - "NO_HOOK_CONFIGURED": "Integraatiota IDllä %{integrationId} ei löytynyt tai ei ole konfiguroitu.", - "HEADER": "Applikaatiot", + "FETCHING": "Fetching Integrations", + "NO_HOOK_CONFIGURED": "There are no %{integrationId} integrations configured in this account.", + "HEADER": "Applications", "STATUS": { "ENABLED": "Käytössä", "DISABLED": "Pois käytöstä" }, "CONFIGURE": "Määrittele", - "ADD_BUTTON": "Lisää uusi webhook", + "ADD_BUTTON": "Add a new hook", "DELETE": { "TITLE": { - "INBOX": "Varmista poisto", - "ACCOUNT": "Katkaise" + "INBOX": "Confirm deletion", + "ACCOUNT": "Disconnect" }, "MESSAGE": { "INBOX": "Oletko varma että haluat poistaa?", - "ACCOUNT": "Oletko varma että haluat katkaista?" + "ACCOUNT": "Are you sure to disconnect?" }, "CONFIRM_BUTTON_TEXT": { "INBOX": "Kyllä, poista", - "ACCOUNT": "Kyllä, katkaise" + "ACCOUNT": "Yes, Disconnect" }, "CANCEL_BUTTON_TEXT": "Peruuta", "API": { - "SUCCESS_MESSAGE": "Webhook poistettu onnistuneesti", + "SUCCESS_MESSAGE": "Hook deleted successfully", "ERROR_MESSAGE": "Yhteyden muodostaminen Woot-palvelimelle ei onnistunut, yritä myöhemmin uudelleen" } }, "LIST": { - "FETCHING": "Haetaan integraatiowebhookkeja", - "INBOX": "Kansio", + "FETCHING": "Fetching integration hooks", + "INBOX": "Inbox", "DELETE": { "BUTTON_TEXT": "Poista" } @@ -38,14 +38,14 @@ "ADD": { "FORM": { "INBOX": { - "LABEL": "Valitse kansio", - "PLACEHOLDER": "Valitse kansio" + "LABEL": "Select Inbox", + "PLACEHOLDER": "Select Inbox" }, "SUBMIT": "Luo", "CANCEL": "Peruuta" }, "API": { - "SUCCESS_MESSAGE": "Integraatio webhook lisätty", + "SUCCESS_MESSAGE": "Integration hook added successfully", "ERROR_MESSAGE": "Yhteyden muodostaminen Woot-palvelimelle ei onnistunut, yritä myöhemmin uudelleen" } }, @@ -53,7 +53,7 @@ "BUTTON_TEXT": "Yhdistä" }, "DISCONNECT": { - "BUTTON_TEXT": "Katkaise" + "BUTTON_TEXT": "Disconnect" }, "SIDEBAR_DESCRIPTION": { "DIALOGFLOW": "Dialogflow is a natural language understanding platform that makes it easy to design and integrate a conversational user interface into your mobile app, web application, device, bot, interactive voice response system, and so on.Tiimit
Tiimit antavat tavan jakaa edustajat eri osa-alueisiin.
Yksi edustaja voi olla monessa ryhmässä. Keskustelun voi määrätä ryhmälle.
Teams
Teams let you organize your agents into groups based on their responsibilities.
A user can be part of multiple teams. You can assign conversations to a team when you are working collaboratively.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Agents
An Agent is a member of your Customer Support team.
Agents will be able to view and reply to messages from your users. The list shows all agents currently in your account.
Click on Add Agent to add a new agent. Agent you add will receive an email with a confirmation link to activate their account, after which they can access Chatwoot and respond to messages.
Access to Chatwoot's features are based on following roles.
Agent - Agents with this role can only access inboxes, reports and conversations. They can assign conversations to other agents or themselves and resolve conversations.
Administrator - Administrator will have access to all Chatwoot features enabled for your account, including settings, along with all of a normal agents' privileges.
", + "SIDEBAR_TXT": "Agentes
Um Agente é um membro da sua equipa de Suporte ao Cliente.
Os agentes podem ver e responder às mensagens dos seus utilizadores. A lista mostra todos os agentes atualmente na sua conta.
Clique em Adicionar Agente para adicionar um novo agente. O agente que adicionar receberá um e-mail com um link de confirmação para ativar a sua conta, de forma a poderem aceder ao Chatwoot e responder às mensagens.
Os acessos aos recursos do Chatwoot têm como base as seguintes funções.
Agentes - Só podem aceder às caixas de entrada, relatórios e conversas. Podem atribuir conversas a outros agentes ou a eles próprios e responder a pedidos.
Administrador - Têm acesso a todos os recursos do Chatwoot ativados na sua conta, incluindo configurações e todos os privilégios que os Agentes normais têm.
", "AGENT_TYPES": { "ADMINISTRATOR": "Administrador", "AGENT": "Representante" @@ -90,7 +90,24 @@ } }, "SEARCH": { - "NO_RESULTS": "No results found." + "NO_RESULTS": "Nenhum resultado encontrado." + }, + "MULTI_SELECTOR": { + "PLACEHOLDER": "nenhum", + "TITLE": { + "AGENT": "Escolher Agente", + "TEAM": "Escolher Equipa" + }, + "SEARCH": { + "NO_RESULTS": { + "AGENT": "Nenhum agente encontrado", + "TEAM": "Nenhuma Equipa encontrada" + }, + "PLACEHOLDER": { + "AGENT": "Procurar Agentes", + "TEAM": "Procurar Equipas" + } + } } } } diff --git a/app/javascript/dashboard/i18n/locale/pt/attributesMgmt.json b/app/javascript/dashboard/i18n/locale/pt/attributesMgmt.json new file mode 100644 index 000000000..09b60f014 --- /dev/null +++ b/app/javascript/dashboard/i18n/locale/pt/attributesMgmt.json @@ -0,0 +1,85 @@ +{ + "ATTRIBUTES_MGMT": { + "HEADER": "Attributes", + "HEADER_BTN_TXT": "Add Attribute", + "LOADING": "Fetching attributes", + "SIDEBAR_TXT": "Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Inbox
When you connect a website or a facebook Page to Chatwoot, it is called an Inbox. You can have unlimited inboxes in your Chatwoot account.
Click on Add Inbox to connect a website or a Facebook Page.
In the Dashboard, you can see all the conversations from all your inboxes in a single place and respond to them under the `Conversations` tab.
You can also see conversations specific to an inbox by clicking on the inbox name on the left pane of the dashboard.
", + "SIDEBAR_TXT": "Caixa de entrada
Ao ligar um site ou uma página do Facebook ao Chatwoot, ela passa a ser chamada de caixa de entrada. Pode ter caixas de entrada ilimitadas na sua conta de Chatwoot.
Clique em Adicionar caixa de entrada para ligar um site ou uma página do Facebook.
No Painel, pode ver todas as conversas de todas as suas caixas de entrada num único lugar e responder a elas utilizando o separado `Conversas`.
Também pode ver conversas específicas de uma determinada caixa de entrada clicando no nome dessa caixa no lado esquerdo do painel lateral.
", "LIST": { "404": "Não há caixas de entrada anexadas a esta conta." }, @@ -29,8 +29,8 @@ ], "ADD": { "CHANNEL_NAME": { - "LABEL": "Inbox Name", - "PLACEHOLDER": "Enter your inbox name (eg: Acme Inc)" + "LABEL": "Nome da Caixa de Entrada", + "PLACEHOLDER": "Digite o nome da caixa de entrada (ex: Informatico. pt)" }, "WEBSITE_NAME": { "LABEL": "Nome do site", @@ -38,23 +38,23 @@ }, "FB": { "HELP": "PS: ao fazer login, só teremos acesso às mensagens da sua página. Suas mensagens privadas nunca poderão ser acessadas pelo Chatwoot.", - "CHOOSE_PAGE": "Choose Page", - "CHOOSE_PLACEHOLDER": "Select a page from the list", - "INBOX_NAME": "Inbox Name", - "ADD_NAME": "Add a name for your inbox", - "PICK_NAME": "Pick A Name Your Inbox", - "PICK_A_VALUE": "Pick a value" + "CHOOSE_PAGE": "Escolher página", + "CHOOSE_PLACEHOLDER": "Escolher uma página da lista", + "INBOX_NAME": "Nome Caixa de Entrada", + "ADD_NAME": "Escolha um nome para a sua caixa de entrada", + "PICK_NAME": "Escolha um nome a sua caixa de entrada", + "PICK_A_VALUE": "Escolha um valor" }, "TWITTER": { "HELP": "Para adicionar seu perfil do Twitter como um canal, você precisa autenticar seu perfil do Twitter clicando em 'Entrar com o Twitter' ", - "ERROR_MESSAGE": "There was an error connecting to Twitter, please try again" + "ERROR_MESSAGE": "Houve um de ligação com o Twitter, por favor, tente novamente" }, "WEBSITE_CHANNEL": { "TITLE": "Canal do site", "DESC": "Crie um canal para seu site e comece a oferecer suporte a seus clientes através do nosso widget do site.", "LOADING_MESSAGE": "Criando canal de suporte ao site", "CHANNEL_AVATAR": { - "LABEL": "Channel Avatar" + "LABEL": "Avatar do canal" }, "CHANNEL_DOMAIN": { "LABEL": "Domínio do site", @@ -69,21 +69,21 @@ "PLACEHOLDER": "Nós simplificamos nos conectar com a gente. Pergunte a nós qualquer coisa ou compartilhe seus comentários." }, "CHANNEL_GREETING_MESSAGE": { - "LABEL": "Channel greeting message", + "LABEL": "Mensagem de Boas-vindas do canal", "PLACEHOLDER": "Acme Inc normalmente responde em algumas horas." }, "CHANNEL_GREETING_TOGGLE": { - "LABEL": "Enable channel greeting", - "HELP_TEXT": "Send a greeting message to the user when he starts the conversation.", + "LABEL": "Ativar mensagem de Boas-vindas do canal", + "HELP_TEXT": "Enviar uma mensagem de boas-vindas ao utilizador quando ele iniciar uma conversa.", "ENABLED": "Ativado", "DISABLED": "Desabilitado" }, "REPLY_TIME": { - "TITLE": "Set Reply time", - "IN_A_FEW_MINUTES": "In a few minutes", - "IN_A_FEW_HOURS": "In a few hours", - "IN_A_DAY": "In a day", - "HELP_TEXT": "This reply time will be displayed on the live chat widget" + "TITLE": "Definir tempo de resposta", + "IN_A_FEW_MINUTES": "Em poucos minutos", + "IN_A_FEW_HOURS": "Em poucas horas", + "IN_A_DAY": "Dentro de um dia", + "HELP_TEXT": "Este tempo de resposta será mostrado no widget de chat" }, "WIDGET_COLOR": { "LABEL": "Cor do widget", @@ -119,8 +119,8 @@ "ERROR": "Por favor, insira um valor válido. O número de telefone deve começar com o sinal `+`." }, "API_CALLBACK": { - "TITLE": "Callback URL", - "SUBTITLE": "You have to configure the message callback URL in Twilio with the URL mentioned here." + "TITLE": "Link de retorno de ligação", + "SUBTITLE": "Tem de configurar aqui, o link de retorno de mensagem no Twilio, através de um URL." }, "SUBMIT_BUTTON": "Criar canal Twilio", "API": { @@ -128,16 +128,16 @@ } }, "SMS": { - "TITLE": "SMS Channel via Twilio", - "DESC": "Start supporting your customers via SMS with Twilio integration." + "TITLE": "Canal SMS através do Twilio", + "DESC": "Comece a dar apoio aos seus clientes por SMS com a integração Twilio." }, "WHATSAPP": { - "TITLE": "Whatsapp Channel via Twilio", - "DESC": "Start supporting your customers via Whatsapp with Twilio integration." + "TITLE": "Canal do Whatsapp através do Twilio", + "DESC": "Comece a dar apoio aos seus clientes através do Whatsapp com a integração do Twilio." }, "API_CHANNEL": { - "TITLE": "API Channel", - "DESC": "Integrate with API channel and start supporting your customers.", + "TITLE": "Canal de API", + "DESC": "Integrar com o canal API para dar apoio aos seus clientes.", "CHANNEL_NAME": { "LABEL": "Nome do Canal", "PLACEHOLDER": "Por favor, insira um nome de canal", @@ -145,17 +145,17 @@ }, "WEBHOOK_URL": { "LABEL": "URL do Webhook", - "SUBTITLE": "Configure the URL where you want to recieve callbacks on events.", + "SUBTITLE": "Configurar a URL onde quer receber mensagens de retorno.", "PLACEHOLDER": "URL do Webhook" }, - "SUBMIT_BUTTON": "Create API Channel", + "SUBMIT_BUTTON": "Criar canal API", "API": { - "ERROR_MESSAGE": "We were not able to save the api channel" + "ERROR_MESSAGE": "Não foi possível guardar o canal API" } }, "EMAIL_CHANNEL": { - "TITLE": "Email Channel", - "DESC": "Integrate you email inbox.", + "TITLE": "Canal de e-mail", + "DESC": "Integrar a caixa de entrada.", "CHANNEL_NAME": { "LABEL": "Nome do Canal", "PLACEHOLDER": "Por favor, insira um nome de canal", @@ -163,24 +163,62 @@ }, "EMAIL": { "LABEL": "e-mail", - "SUBTITLE": "Email where your customers sends you support tickets", + "SUBTITLE": "Email para onde os seus clientes lhe enviam os tickets de suporte", "PLACEHOLDER": "e-mail" }, - "SUBMIT_BUTTON": "Create Email Channel", + "SUBMIT_BUTTON": "Criar canal de email", "API": { - "ERROR_MESSAGE": "We were not able to save the email channel" + "ERROR_MESSAGE": "Não foi possível guardar o canal de email" }, - "FINISH_MESSAGE": "Start forwarding your emails to the following email address." + "FINISH_MESSAGE": "Comece a encaminhar as suas mensagens de email para o seguinte endereço." + }, + "LINE_CHANNEL": { + "TITLE": "LINE Channel", + "DESC": "Integrate with LINE channel and start supporting your customers.", + "CHANNEL_NAME": { + "LABEL": "Nome do Canal", + "PLACEHOLDER": "Por favor, insira um nome de canal", + "ERROR": "Este campo é obrigatório" + }, + "LINE_CHANNEL_ID": { + "LABEL": "LINE Channel ID", + "PLACEHOLDER": "LINE Channel ID" + }, + "LINE_CHANNEL_SECRET": { + "LABEL": "LINE Channel Secret", + "PLACEHOLDER": "LINE Channel Secret" + }, + "LINE_CHANNEL_TOKEN": { + "LABEL": "LINE Channel Token", + "PLACEHOLDER": "LINE Channel Token" + }, + "SUBMIT_BUTTON": "Create LINE Channel", + "API": { + "ERROR_MESSAGE": "We were not able to save the LINE channel" + } + }, + "TELEGRAM_CHANNEL": { + "TITLE": "Telegram Channel", + "DESC": "Integrate with Telegram channel and start supporting your customers.", + "BOT_TOKEN": { + "LABEL": "Bot Token", + "SUBTITLE": "Configure the bot token you have obtained from Telegram BotFather.", + "PLACEHOLDER": "Bot Token" + }, + "SUBMIT_BUTTON": "Create Telegram Channel", + "API": { + "ERROR_MESSAGE": "We were not able to save the telegram channel" + } }, "AUTH": { - "TITLE": "Choose a channel", - "DESC": "Chatwoot supports live-chat widget, Facebook page, Twitter profile, Whatsapp, Email etc., as channels. If you want to build a custom channel, you can create it using the API channel. Select one channel from the options below to proceed." + "TITLE": "Escolher um canal", + "DESC": "O Chatwoot pode ter vários canais como widget, páginas do Facebook, perfis do Twitter, Whatsapp, E-mail, etc. Se quiser criar um canal personalizado pode utilizar uma API. Escolha um canal entre as opções a seguir para prosseguir." }, "AGENTS": { "TITLE": "agentes", "DESC": "Aqui você pode adicionar agentes para gerenciar a sua caixa de entrada recém-criada. Apenas esses agentes selecionados terão acesso à sua caixa de entrada. Agentes que não fazem parte desta caixa de entrada não serão capazes de ver ou responder a mensagens nesta caixa de entrada quando eles acessarem.Chatwoot will now sync all the incoming conversations into the customer-conversations channel inside your slack workplace.
Replying to a conversation thread in customer-conversations slack channel will create a response back to the customer through chatwoot.
Start the replies with note: to create private notes instead of replies.
If the replier on slack has an agent profile in chatwoot under the same email, the replies will be associated accordingly.
When the replier doesn't have an associated agent profile, the replies will be made from the bot profile.
" + "TITLE": "Utilizar a integração Slack", + "BODY": "Chatwoot irá agora sincronizar todas as mensagens recebidas através do canal de conversas com clientes dentro do seu local de trabalho do Slack.
A resposta a uma mensagem nas conversas com o cliente no seu canal de slack irá criar uma resposta para o cliente através do Chatwoot.
Comece as respostas com nota: para criar notas privadas em vez de respostas.
Se o remetente do slack tiver um perfil de agente no Chatwoot com o mesmo e-mail, as respostas serão associadas de acordo com isso.
Quando a pessoa que responde não tiver um perfil de agente associado, as respostas serão dadas a partir do perfil do bot.
" } }, "DELETE": { "BUTTON_TEXT": "excluir", "API": { - "SUCCESS_MESSAGE": "Integration deleted successfully" + "SUCCESS_MESSAGE": "Integração removida com sucesso" } }, "CONNECT": { - "BUTTON_TEXT": "Connect" + "BUTTON_TEXT": "Ligar" } } } diff --git a/app/javascript/dashboard/i18n/locale/pt/labelsMgmt.json b/app/javascript/dashboard/i18n/locale/pt/labelsMgmt.json index 742f0d71f..79d8164a0 100644 --- a/app/javascript/dashboard/i18n/locale/pt/labelsMgmt.json +++ b/app/javascript/dashboard/i18n/locale/pt/labelsMgmt.json @@ -19,9 +19,9 @@ "NAME": { "LABEL": "Nome da etiqueta", "PLACEHOLDER": "Nome da etiqueta", - "REQUIRED_ERROR": "Label name is required", - "MINIMUM_LENGTH_ERROR": "Minimum length 2 is required", - "VALID_ERROR": "Only Alphabets, Numbers, Hyphen and Underscore are allowed" + "REQUIRED_ERROR": "O nome da etiqueta é obrigatório", + "MINIMUM_LENGTH_ERROR": "O tamanho mínimo obrigatório é 2", + "VALID_ERROR": "Apenas são permitidos Alfabetos, Números, Hífen e Underscores" }, "DESCRIPTION": { "LABEL": "Descrição", diff --git a/app/javascript/dashboard/i18n/locale/pt/report.json b/app/javascript/dashboard/i18n/locale/pt/report.json index 5b5834d67..56257b62f 100644 --- a/app/javascript/dashboard/i18n/locale/pt/report.json +++ b/app/javascript/dashboard/i18n/locale/pt/report.json @@ -1,9 +1,9 @@ { "REPORT": { - "HEADER": "Overview", + "HEADER": "Visão geral", "LOADING_CHART": "Carregando dados da carta...", "NO_ENOUGH_DATA": "Não recebemos pontos de dados suficientes para gerar o relatório. Por favor, tente novamente mais tarde.", - "DOWNLOAD_AGENT_REPORTS": "Download agent reports", + "DOWNLOAD_AGENT_REPORTS": "Descarregar relatórios de agentes", "METRICS": { "CONVERSATIONS": { "NAME": "Conversas", @@ -41,49 +41,49 @@ }, { "id": 2, - "name": "Last 3 months" + "name": "Últimos 3 meses" }, { "id": 3, - "name": "Last 6 months" + "name": "Últimos 6 meses" }, { "id": 4, - "name": "Last year" + "name": "Último ano" }, { "id": 5, - "name": "Custom date range" + "name": "Intervalo de tempo personalizado" } ], "CUSTOM_DATE_RANGE": { - "CONFIRM": "Apply", - "PLACEHOLDER": "Select date range" + "CONFIRM": "Confirmar", + "PLACEHOLDER": "Escolher intervalo de tempo" } }, "CSAT_REPORTS": { - "HEADER": "CSAT Reports", - "NO_RECORDS": "There are no CSAT survey responses available.", + "HEADER": "Relatórios CSAT", + "NO_RECORDS": "Sem dados CSAT disponíveis para reposta.", "TABLE": { "HEADER": { - "CONTACT_NAME": "Contact", - "AGENT_NAME": "Assigned agent", - "RATING": "Rating", - "FEEDBACK_TEXT": "Feedback comment" + "CONTACT_NAME": "Contato", + "AGENT_NAME": "Agente atribuído", + "RATING": "Avaliar", + "FEEDBACK_TEXT": "Comentário de feedback" } }, "METRIC": { "TOTAL_RESPONSES": { - "LABEL": "Total responses", - "TOOLTIP": "Total number of responses collected" + "LABEL": "Total de respostas", + "TOOLTIP": "Número total de respostas recolhidas" }, "SATISFACTION_SCORE": { - "LABEL": "Satisfaction score", - "TOOLTIP": "Total number of positive responses / Total number of responses * 100" + "LABEL": "Pontuação de satisfação", + "TOOLTIP": "Número total de respostas positivas / Número total de respostas * 100" }, "RESPONSE_RATE": { - "LABEL": "Response rate", - "TOOLTIP": "Total number of responses / Total number of CSAT survey messages sent * 100" + "LABEL": "Taxa de resposta", + "TOOLTIP": "Número total de respostas / Número total de mensagens CSAT enviadas * 100" } } } diff --git a/app/javascript/dashboard/i18n/locale/pt/settings.json b/app/javascript/dashboard/i18n/locale/pt/settings.json index 6f414e8f8..47a21819b 100644 --- a/app/javascript/dashboard/i18n/locale/pt/settings.json +++ b/app/javascript/dashboard/i18n/locale/pt/settings.json @@ -3,7 +3,7 @@ "LINK": "Configurações do perfil", "TITLE": "Configurações do perfil", "BTN_TEXT": "Atualizar o perfil", - "UPDATE_SUCCESS": "Your profile has been updated successfully", + "UPDATE_SUCCESS": "O seu perfil foi atualizado com sucesso", "PASSWORD_UPDATE_SUCCESS": "Sua senha foi alterada com sucesso", "AFTER_EMAIL_CHANGED": "Seu perfil foi atualizado com sucesso, faça o login novamente pois suas credenciais foram alteradas", "FORM": { @@ -19,60 +19,60 @@ "PASSWORD_SECTION": { "TITLE": "Palavra-passe", "NOTE": "Atualizar sua senha irá redefinir seus logins em vários dispositivos.", - "BTN_TEXT": "Change password" + "BTN_TEXT": "Alterar password" }, "ACCESS_TOKEN": { "TITLE": "Token de acesso", "NOTE": "Este token pode ser usado se você estiver construindo uma integração baseada em API" }, "AUDIO_NOTIFICATIONS_SECTION": { - "TITLE": "Audio Notifications", - "NOTE": "Enable audio notifications in dashboard for new messages and conversations.", - "NONE": "None", - "ASSIGNED": "Assigned Conversations", - "ALL_CONVERSATIONS": "All Conversations" + "TITLE": "Notificações de som", + "NOTE": "Ativar notificações de som no painel quando surgirem novas mensagens e conversas.", + "NONE": "Nenhuma", + "ASSIGNED": "Conversas atribuídas", + "ALL_CONVERSATIONS": "Todas as conversas" }, "EMAIL_NOTIFICATIONS_SECTION": { "TITLE": "Notificações por e-mail", "NOTE": "Atualize suas preferências de notificação por e-mail aqui", "CONVERSATION_ASSIGNMENT": "Enviar notificações por email quando uma conversa é atribuída a mim", "CONVERSATION_CREATION": "Enviar notificações por email quando uma nova conversa é criada", - "CONVERSATION_MENTION": "Send email notifications when you are mentioned in a conversation", - "ASSIGNED_CONVERSATION_NEW_MESSAGE": "Send email notifications when a new message is created in an assigned conversation" + "CONVERSATION_MENTION": "Enviar notificações por email quando for mencionado numa conversa", + "ASSIGNED_CONVERSATION_NEW_MESSAGE": "Enviar mensagem de email quando criada uma mensagem ou atribuída uma conversa" }, "API": { - "UPDATE_SUCCESS": "Your notification preferences are updated successfully", - "UPDATE_ERROR": "There is an error while updating the preferences, please try again" + "UPDATE_SUCCESS": "As suas preferências de notificação foram atualizadas com sucesso", + "UPDATE_ERROR": "Ocorreu um erro ao atualizar as suas preferências, por favor, tente de novo" }, "PUSH_NOTIFICATIONS_SECTION": { - "TITLE": "Push Notifications", - "NOTE": "Update your push notification preferences here", - "CONVERSATION_ASSIGNMENT": "Send push notifications when a conversation is assigned to me", - "CONVERSATION_CREATION": "Send push notifications when a new conversation is created", - "CONVERSATION_MENTION": "Send push notifications when you are mentioned in a conversation", - "ASSIGNED_CONVERSATION_NEW_MESSAGE": "Send push notifications when a new message is created in an assigned conversation", - "HAS_ENABLED_PUSH": "You have enabled push for this browser.", - "REQUEST_PUSH": "Enable push notifications" + "TITLE": "Notificações Push", + "NOTE": "Atualize aqui as suas preferências de notificação Push", + "CONVERSATION_ASSIGNMENT": "Enviar uma notificação Push quando uma conversa me for atribuída", + "CONVERSATION_CREATION": "Enviar uma notificação Push quando uma conversa é criada", + "CONVERSATION_MENTION": "Enviar uma notificação Push quando for mencionado numa conversa", + "ASSIGNED_CONVERSATION_NEW_MESSAGE": "Enviar uma notificação Push quando uma mensagem é criada numa conversa atribuída", + "HAS_ENABLED_PUSH": "Ativou notificações Push neste navegador.", + "REQUEST_PUSH": "Ativar notificações Push" }, "PROFILE_IMAGE": { "LABEL": "Imagem do perfil" }, "NAME": { - "LABEL": "Your full name", - "ERROR": "Please enter a valid full name", - "PLACEHOLDER": "Please enter your full name" + "LABEL": "O seu nome completo", + "ERROR": "Por favor, digite um nome completo válido", + "PLACEHOLDER": "Por favor, digite o seu nome completo" }, "DISPLAY_NAME": { - "LABEL": "Display name", - "ERROR": "Please enter a valid display name", - "PLACEHOLDER": "Please enter a display name, this would be displayed in conversations" + "LABEL": "Mostrar nome", + "ERROR": "Por favor, digite uma alcunha válida", + "PLACEHOLDER": "Por favor, escolha uma alcunha que será mostrada nas conversas" }, "AVAILABILITY": { - "LABEL": "Availability", + "LABEL": "Disponibilidade", "STATUSES_LIST": [ - "Online", - "Busy", - "Offline" + "Disponível", + "Ocupado", + "Ausente" ] }, "EMAIL": { @@ -81,9 +81,9 @@ "PLACEHOLDER": "Por favor, insira seu endereço de e-mail, que será exibido em conversas" }, "CURRENT_PASSWORD": { - "LABEL": "Current password", - "ERROR": "Please enter the current password", - "PLACEHOLDER": "Please enter the current password" + "LABEL": "Password atual", + "ERROR": "Por favor, digite a password atual", + "PLACEHOLDER": "Por favor, digite a password atual" }, "PASSWORD": { "LABEL": "Palavra-passe", @@ -99,60 +99,66 @@ }, "SIDEBAR_ITEMS": { "CHANGE_AVAILABILITY_STATUS": "Trocar", - "CHANGE_ACCOUNTS": "Switch Account", - "SELECTOR_SUBTITLE": "Select an account from the following list", + "CHANGE_ACCOUNTS": "Trocar de conta", + "SELECTOR_SUBTITLE": "Escolha uma conta da lista a seguir", "PROFILE_SETTINGS": "Configurações do perfil", + "KEYBOARD_SHORTCUTS": "Atalhos do teclado", "LOGOUT": "Desconectar" }, "APP_GLOBAL": { - "TRIAL_MESSAGE": "days trial remaining.", - "TRAIL_BUTTON": "Buy Now" + "TRIAL_MESSAGE": "dias de teste restantes.", + "TRAIL_BUTTON": "Comprar agora" }, "COMPONENTS": { "CODE": { - "BUTTON_TEXT": "Copy", - "COPY_SUCCESSFUL": "Code copied to clipboard successfully" + "BUTTON_TEXT": "Copiar", + "COPY_SUCCESSFUL": "Código copiado com sucesso para área de transferência" }, "FILE_BUBBLE": { "DOWNLOAD": "BAIXAR", - "UPLOADING": "Uploading..." + "UPLOADING": "A carregar..." }, "FORM_BUBBLE": { "SUBMIT": "submeter" } }, - "CONFIRM_EMAIL": "Verifying...", + "CONFIRM_EMAIL": "A verificar...", "SETTINGS": { "INBOXES": { - "NEW_INBOX": "Add Inbox" + "NEW_INBOX": "Adicionar caixa de entrada" } }, "SIDEBAR": { "CONVERSATIONS": "Conversas", "REPORTS": "relatórios", - "CONTACTS": "Contacts", "SETTINGS": "Confirgurações", - "HOME": "Home", + "CONTACTS": "Contatos", + "HOME": "Principal", "AGENTS": "agentes", "INBOXES": "Caixas de Entrada", - "NOTIFICATIONS": "Notifications", + "NOTIFICATIONS": "Notificaçoes", "CANNED_RESPONSES": "Respostas Prontas", "INTEGRATIONS": "Integrações", - "ACCOUNT_SETTINGS": "Account Settings", - "APPLICATIONS": "Applications", + "ACCOUNT_SETTINGS": "Configurações da conta", + "APPLICATIONS": "Aplicações", "LABELS": "Etiquetas", - "TEAMS": "Teams", - "ALL_CONTACTS": "All Contacts", - "TAGGED_WITH": "Tagged with", - "REPORTS_OVERVIEW": "Overview", - "CSAT": "CSAT" + "ATTRIBUTES": "Attributes", + "TEAMS": "Equipas", + "ALL_CONTACTS": "Todos os contatos", + "TAGGED_WITH": "Etiquetada com", + "REPORTS_OVERVIEW": "Visão geral", + "CSAT": "CSAT", + "CAMPAIGNS": "Campanhas", + "ONGOING": "Em curso", + "ONE_OFF": "Pontual" }, "CREATE_ACCOUNT": { - "NEW_ACCOUNT": "New Account", - "SELECTOR_SUBTITLE": "Create a new account", + "NO_ACCOUNT_WARNING": "Não conseguimos encontrar nenhuma conta do Chatwoot. Por favor, crie uma nova conta para continuar.", + "NEW_ACCOUNT": "Nova conta", + "SELECTOR_SUBTITLE": "Criar uma nova conta", "API": { - "SUCCESS_MESSAGE": "Account created successfully", - "EXIST_MESSAGE": "Account already exists", + "SUCCESS_MESSAGE": "Conta criada com sucesso", + "EXIST_MESSAGE": "Esta conta já existe", "ERROR_MESSAGE": "Não foi possível conectar ao servidor Woot, por favor tente novamente mais tarde" }, "FORM": { @@ -162,5 +168,30 @@ }, "SUBMIT": "submeter" } + }, + "KEYBOARD_SHORTCUTS": { + "TITLE": { + "OPEN_CONVERSATION": "Abrir conversa", + "RESOLVE_AND_NEXT": "Resolver e passar para a próxima", + "NAVIGATE_DROPDOWN": "Navegar pelos itens a seguir", + "RESOLVE_CONVERSATION": "Resolver conversa", + "GO_TO_CONVERSATION_DASHBOARD": "Ir para o painel de conversação", + "ADD_ATTACHMENT": "Adicionar anexo", + "GO_TO_CONTACTS_DASHBOARD": "Ir para o painel de contatos", + "TOGGLE_SIDEBAR": "Ativar/Desativar barra lateral", + "GO_TO_REPORTS_SIDEBAR": "Ir para barra lateral de Relatórios", + "MOVE_TO_NEXT_TAB": "Mover para próximo separador da lista de conversas", + "GO_TO_SETTINGS": "Ir para as configurações", + "SWITCH_CONVERSATION_STATUS": "Switch to the next conversation status", + "SWITCH_TO_PRIVATE_NOTE": "Alterar para nota privada", + "TOGGLE_RICH_CONTENT_EDITOR": "Ativar/desativar editor de conteúdo", + "SWITCH_TO_REPLY": "Mudar para resposta", + "TOGGLE_SNOOZE_DROPDOWN": "Ativar/desativar suspensos" + }, + "KEYS": { + "WINDOWS_KEY_AND_COMMAND_KEY": "Win / ⌘", + "ALT_OR_OPTION_KEY": "Alt / ⌥", + "FORWARD_SLASH_KEY": "/" + } } } diff --git a/app/javascript/dashboard/i18n/locale/pt/signup.json b/app/javascript/dashboard/i18n/locale/pt/signup.json index a6a63a244..b9a33c407 100644 --- a/app/javascript/dashboard/i18n/locale/pt/signup.json +++ b/app/javascript/dashboard/i18n/locale/pt/signup.json @@ -5,18 +5,18 @@ "TERMS_ACCEPT": "Ao se inscrever, você concorda com nossa T & C e Política de privacidade", "ACCOUNT_NAME": { "LABEL": "Nome da Conta", - "PLACEHOLDER": "Enter an account name. eg: Wayne Enterprises", - "ERROR": "Account name is too short" + "PLACEHOLDER": "Escolha o nome da conta, por exemplo: Informatico. pt", + "ERROR": "O nome da conta é muito pequeno" }, "FULL_NAME": { - "LABEL": "Full name", - "PLACEHOLDER": "Enter your full name. eg: Bruce Wayne", - "ERROR": "Full name is too short" + "LABEL": "Nome completo", + "PLACEHOLDER": "Digite o seu nome completo, por exemplo: António Almeida", + "ERROR": "O nome completo é muito pequeno" }, "EMAIL": { - "LABEL": "Work email", - "PLACEHOLDER": "Enter your work email address. eg: bruce@wayne.enterprises", - "ERROR": "Email address is invalid" + "LABEL": "E-mail de trabalho", + "PLACEHOLDER": "Digite o seu endereço de e-mail profissional. Por exemplo: geral@informatico.pt", + "ERROR": "Endereço de e-mail inválido" }, "PASSWORD": { "LABEL": "Palavra-passe", @@ -33,6 +33,6 @@ "ERROR_MESSAGE": "Não foi possível conectar ao servidor Woot, por favor tente novamente mais tarde" }, "SUBMIT": "submeter", - "HAVE_AN_ACCOUNT": "Already have an account?" + "HAVE_AN_ACCOUNT": "Já tem uma conta?" } } diff --git a/app/javascript/dashboard/i18n/locale/pt/teamsSettings.json b/app/javascript/dashboard/i18n/locale/pt/teamsSettings.json index ae5211f76..e229bd44e 100644 --- a/app/javascript/dashboard/i18n/locale/pt/teamsSettings.json +++ b/app/javascript/dashboard/i18n/locale/pt/teamsSettings.json @@ -1,125 +1,125 @@ { "TEAMS_SETTINGS": { - "NEW_TEAM": "Create new team", - "HEADER": "Teams", - "SIDEBAR_TXT": "Teams
Teams let you organize your agents into groups based on their responsibilities.
A user can be part of multiple teams. You can assign conversations to a team when you are working collaboratively.
Equipas
As equipas permitem-lhe organizar os seus agentes em grupos com base nas suas responsabilidades.
Um utilizador pode fazer parte de várias equipas. Pode atribuir conversas a uma equipa quando estiver a trabalhar online.
Atributos
Um atributo personalizado faixa fatos sobre seus contatos/conversa — como o plano de assinatura. ou quando eles compraram o primeiro item, etc.
Para criar um Atributo, basta clicar noAdicionar Atributo. Pode também editar ou apagar um atributo existente clicando em Editar ou Apagar botão.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Атрибуты
Пользовательский атрибут отслеживает факты о ваших контактах/диалогах — как план подписки, или когда они сделали первый заказ и т. д.
Для создания атрибутов, просто нажмите кнопкуДобавить атрибут. Вы также можете редактировать или удалять существующие атрибуты, нажав на кнопку Правка или Удалить.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
客服
客服 是您的客戶支持團隊成員。
客服將能夠查看和回覆您使用者的訊息。 列表顯示目前帳戶中的所有客服。
點擊 建立客服 建立新客服。 您建立的客服將收到一封包含確認連結的電子信箱來啟動他們的帳戶,然後他們可以訪問Chatwoot 並回覆訊息。
聊天視窗的功能基於以下角色。
客服 - 具有此角色的客服只能訪問收件匣、報表和對話。 他們可以將對話分配給其他客服或自己,並封存會話。
管理員 - 管理員將可以訪問您帳戶中所有已啟用的聊天功能。 包括設定,以及所有正常客服的權限。
", + "SIDEBAR_TXT": "客服
客服 是您的客戶支持團隊成員。
客服將能夠查看和回覆您使用者的訊息。 列表顯示目前帳戶中的所有客服。
點擊 新增客服 以新增新客服。 您新增的客服將收到一封包含確認連結的電子信箱來啟動他們的帳戶,然後他們可以訪問Chatwoot 並回覆訊息。
聊天視窗的功能基於以下角色。
客服 - 具有此角色的客服只能訪問收件匣、報表和對話。 他們可以將對話分配給其他客服或自己,並封存會話。
管理員 - 管理員將可以訪問您帳戶中所有已啟用的聊天功能。 包括設定,以及所有正常客服的權限。
", "AGENT_TYPES": { "ADMINISTRATOR": "管理員", "AGENT": "客服" @@ -11,7 +11,7 @@ "LIST": { "404": "沒有與此帳號關聯的客服", "TITLE": "管理您團隊中的客服", - "DESC": "你可以建立 / 移除客服到你的團隊。", + "DESC": "你可以新增 / 移除客服到你的團隊。", "NAME": "姓名", "EMAIL": "電子信箱", "STATUS": "狀態", @@ -21,7 +21,7 @@ }, "ADD": { "TITLE": "新增客服到你的團隊", - "DESC": "您可以建立能夠处理支持您的收件匣的人。", + "DESC": "您可以新增能夠支援您的收件匣的人。", "CANCEL_BUTTON_TEXT": "取消", "FORM": { "NAME": { @@ -91,6 +91,23 @@ }, "SEARCH": { "NO_RESULTS": "查無結果。" + }, + "MULTI_SELECTOR": { + "PLACEHOLDER": "無", + "TITLE": { + "AGENT": "選擇客服", + "TEAM": "選擇團隊" + }, + "SEARCH": { + "NO_RESULTS": { + "AGENT": "查無客服", + "TEAM": "查無團隊" + }, + "PLACEHOLDER": { + "AGENT": "搜尋客服", + "TEAM": "搜尋團隊" + } + } } } } diff --git a/app/javascript/dashboard/i18n/locale/zh_TW/attributesMgmt.json b/app/javascript/dashboard/i18n/locale/zh_TW/attributesMgmt.json new file mode 100644 index 000000000..2def6266f --- /dev/null +++ b/app/javascript/dashboard/i18n/locale/zh_TW/attributesMgmt.json @@ -0,0 +1,85 @@ +{ + "ATTRIBUTES_MGMT": { + "HEADER": "屬性", + "HEADER_BTN_TXT": "新增屬性", + "LOADING": "取得屬性", + "SIDEBAR_TXT": "Attributes
A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.
For creating a Attributes, just click on the Add Attribute. You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.
Webhooks
Webhooks 是 HTTP 回呼,可以為每個帳戶定義的。 他們是由諸如在 Chatwoot 中建立消息等事件所觸發的。您可以為此帳戶建立多個 webhook。
建立一個 webhook, 點擊 建立新的 webhook 按鈕。 您也可以通過點擊刪除按鈕刪除任何現有的 webhook。
標籤
可以幫助您對對話進行分類和排序。 您可以從側面板給對話指定標籤。
標籤被綁定到帳戶,可以用於建立您組織中的自定義工作流。 您可以將自定義顏色分配給標籤,使它更容易識別標籤。 您將能夠在側邊欄上顯示標籤,方便地過濾對話。
+ {{ $t('ATTRIBUTES_MGMT.LIST.EMPTY_RESULT.404') }} +
+| + {{ tableHeader }} + | + + +||||
|---|---|---|---|---|
| + {{ attribute.attribute_display_name }} + | ++ {{ attribute.attribute_description }} + | ++ {{ attribute.attribute_display_type }} + | ++ {{ attribute.attribute_key }} + | +
+ |
+
- {{ $t('SURVEY.DESCRIPTION') }}
+
+ {{ $t('SURVEY.DESCRIPTION', { inboxName }) }}
-