Compare commits

..
Author SHA1 Message Date
Shivam Mishra 8fe2be5e1a test: action cable broadcast job 2025-03-10 14:53:31 +05:30
Shivam Mishra 2edd7c569f test: ensure event timestamp is sent across 2025-03-10 14:50:00 +05:30
Shivam Mishra 13ed6c1336 feat: ignore out of sequence events 2025-03-10 14:32:28 +05:30
Shivam Mishra 72326788fb feat: include event timestamp in the payload 2025-03-10 14:12:40 +05:30
PranavandGitHub 66fbe1bde7 fix: Hide Configuration page for Microsoft & Gmail channels (#11045)
The Microsoft and Gmail channels don’t function with custom SMTP or IMAP
configurations or forwarding option. Displaying the configuration tab
creates confusion among users.

This PR would eliminate the option for these channels.
2025-03-07 16:02:40 -08:00
a543cc92df chore: Update translations (#11043)
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2025-03-07 14:07:28 -08:00
PranavandGitHub 22331fb626 fix: Paginate attachments API (#11044)
There are attachments with over 1000 attachments (unusual) in
production, and some of them timeout. This PR would limit the number of
attachments to 100 (which is sufficient for viewing the files in the
gallery, pagination on the UI can be added later).
2025-03-07 13:56:10 -08:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
08f0ea2c98 chore(deps): Bump vue-i18n from 9.14.2 to 9.14.3 (#11041)
Bumps
[vue-i18n](https://github.com/intlify/vue-i18n/tree/HEAD/packages/vue-i18n)
from 9.14.2 to 9.14.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/intlify/vue-i18n/releases">vue-i18n's
releases</a>.</em></p>
<blockquote>
<h2>v9.14.3</h2>
<!-- raw HTML omitted -->
<h2>What's Changed</h2>
<h3>🔒 Security Fixes</h3>
<ul>
<li>fix: prototype pollution in <code>handleFlatJson</code>, about
details see <a
href="https://github.com/intlify/vue-i18n/security/advisories/GHSA-p2ph-7g93-hw3m">https://github.com/intlify/vue-i18n/security/advisories/GHSA-p2ph-7g93-hw3m</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/intlify/vue-i18n/compare/v9.14.2...v9.14.3">https://github.com/intlify/vue-i18n/compare/v9.14.2...v9.14.3</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/intlify/vue-i18n/blob/v9.14.3/CHANGELOG.md">vue-i18n's
changelog</a>.</em></p>
<blockquote>
<h1>v9.14.3 (2025-03-07T03:21:38Z)</h1>
<p>This changelog is generated by <a
href="https://github.com/intlify/vue-i18n/releases/tag/v9.14.3">GitHub
Releases</a></p>
<!-- raw HTML omitted -->
<p><strong>Full Changelog</strong>: <a
href="https://github.com/intlify/vue-i18n/compare/v9.14.2...v9.14.3">https://github.com/intlify/vue-i18n/compare/v9.14.2...v9.14.3</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/intlify/vue-i18n/commit/2e255c59ded7caf7c35f67190a336ce4cec82816"><code>2e255c5</code></a>
release: v9.14.3</li>
<li><a
href="https://github.com/intlify/vue-i18n/commit/6695eec30737265032dca70690df00ad8d3aa713"><code>6695eec</code></a>
fix: update package name for npm provenance</li>
<li><a
href="https://github.com/intlify/vue-i18n/commit/2b5149d42afe9b00a514e6b1ee2021212e47edf5"><code>2b5149d</code></a>
Revert &quot;release: v9.14.3&quot;</li>
<li><a
href="https://github.com/intlify/vue-i18n/commit/26449f9d74165736cd1d5ff768ff3c7d12d8a8d5"><code>26449f9</code></a>
release: v9.14.3</li>
<li>See full diff in <a
href="https://github.com/intlify/vue-i18n/commits/v9.14.3/packages/vue-i18n">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=vue-i18n&package-manager=npm_and_yarn&previous-version=9.14.2&new-version=9.14.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/chatwoot/chatwoot/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-07 11:49:36 -08:00
PranavandGitHub 8fefdea4e8 chore: Dynamically load OldSidebar if needed (#11038)
Move old sidebar loading to async
2025-03-06 19:12:54 -08:00
PranavandGitHub a513f152ed fix: Extend the locale without variant check for article locales as well (#11021)
We allow users to select locale variants when creating the help center
(e.g., pt_BR or en_UK). However, the selected variant may not always be
available for translation in the app. In such cases, we need to fall
back to either the base language or the default locale.

While this fallback logic was implemented for the portal locale, it was
missing for article locales.

This PR fixes that issue.
2025-03-06 18:24:46 -08:00
a0cf25ccde chore: Rescue slack link unfurling errors. (#11033)
Fixes
https://linear.app/chatwoot/issue/CW-4122/slackwebapierrorsmissingscope-missing-scope

This PR adds the ability to handle errors when scopes are missing during
link unfurling. Since link unfurling is just a nice-to-have feature that
doesn't affect core functionality, we will silently ignore these errors.

---------

Co-authored-by: Sojan <sojan@pepalo.com>
2025-03-06 15:57:16 -08:00
8d85a02ca9 feat: handle Channel errors (#11015)
This PR adds missing error handlers for the following channels and cases

1. WhatsApp - Generic Handlers for both Cloud and 360Dialog (Deprecated)
2. Instagram - Handler for a case where there is an HTTP error instead
of an `:error` in the 200 response
3. Facebook - Errors from the two sentry issues
([Net::OpenTimeout](https://chatwoot-p3.sentry.io/issues/6164805227) &
[JSON::ParserError](https://chatwoot-p3.sentry.io/issues/5903200786))
4. SMS: Generic handlers for Bandwidth SMS

#### Checklist

- [x] Bandwidth SMS
- [x] Whatsapp Cloud + 360 Dialog
- [x] Twilio SMS
- [x] Line
- [x] Telegram
- [x] Instagram
- [x] Facebook
- [x] GMail
- [x] 365 Mail
- [x] SMTP Mail

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2025-03-06 20:09:47 +05:30
Sivin VargheseandGitHub 7e1458fd32 fix: Issue when saving hotkeys (#11026)
# Pull Request Template

## Description

This PR fixes an issue when saving send message button hotkeys, where a
TypeError occurs: `this.updateUISettings is not a function`.

This issue arises after merging this PR
https://github.com/chatwoot/chatwoot/pull/10974

Fixes
https://chatwoot-p3.sentry.io/issues/6339976939/events/ca9946f92cb74428a72f1f74976a56a3/

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
2025-03-06 10:53:02 +05:30
PranavandGitHub d017156f32 fix: Disable syncing IMAP if the account is suspended (#11031)
This PR disables the IMAP syncing if the account is suspended.
2025-03-05 17:10:24 -08:00
111 changed files with 1107 additions and 477 deletions
+1 -1
View File
@@ -561,7 +561,7 @@ GEM
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
raabro (1.4.0) raabro (1.4.0)
racc (1.8.1) racc (1.8.1)
rack (2.2.11) rack (2.2.12)
rack-attack (6.7.0) rack-attack (6.7.0)
rack (>= 1.0, < 4) rack (>= 1.0, < 4)
rack-contrib (2.5.0) rack-contrib (2.5.0)
@@ -6,6 +6,8 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
before_action :conversation, except: [:index, :meta, :search, :create, :filter] before_action :conversation, except: [:index, :meta, :search, :create, :filter]
before_action :inbox, :contact, :contact_inbox, only: [:create] before_action :inbox, :contact, :contact_inbox, only: [:create]
ATTACHMENT_RESULTS_PER_PAGE = 100
def index def index
result = conversation_finder.perform result = conversation_finder.perform
@conversations = result[:conversations] @conversations = result[:conversations]
@@ -24,7 +26,12 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
end end
def attachments def attachments
@attachments_count = @conversation.attachments.count
@attachments = @conversation.attachments @attachments = @conversation.attachments
.includes(:message)
.order(created_at: :desc)
.page(attachment_params[:page])
.per(ATTACHMENT_RESULTS_PER_PAGE)
end end
def show; end def show; end
@@ -124,6 +131,10 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
params.permit(:priority) params.permit(:priority)
end end
def attachment_params
params.permit(:page)
end
def update_last_seen_on_conversation(last_seen_at, update_assignee) def update_last_seen_on_conversation(last_seen_at, update_assignee)
# rubocop:disable Rails/SkipsModelValidations # rubocop:disable Rails/SkipsModelValidations
@conversation.update_column(:agent_last_seen_at, last_seen_at) @conversation.update_column(:agent_last_seen_at, last_seen_at)
+19 -14
View File
@@ -5,10 +5,11 @@ module SwitchLocale
def switch_locale(&) def switch_locale(&)
# priority is for locale set in query string (mostly for widget/from js sdk) # priority is for locale set in query string (mostly for widget/from js sdk)
locale ||= locale_from_params locale ||= params[:locale]
locale ||= locale_from_custom_domain locale ||= locale_from_custom_domain
# if locale is not set in account, let's use DEFAULT_LOCALE env variable # if locale is not set in account, let's use DEFAULT_LOCALE env variable
locale ||= locale_from_env_variable locale ||= ENV.fetch('DEFAULT_LOCALE', nil)
set_locale(locale, &) set_locale(locale, &)
end end
@@ -32,26 +33,30 @@ module SwitchLocale
end end
def set_locale(locale, &) def set_locale(locale, &)
# if locale is empty, use default_locale safe_locale = validate_and_get_locale(locale)
locale ||= I18n.default_locale
# Ensure locale won't bleed into other requests # Ensure locale won't bleed into other requests
# https://guides.rubyonrails.org/i18n.html#managing-the-locale-across-requests # https://guides.rubyonrails.org/i18n.html#managing-the-locale-across-requests
I18n.with_locale(locale, &) I18n.with_locale(safe_locale, &)
end end
def locale_from_params def validate_and_get_locale(locale)
I18n.available_locales.map(&:to_s).include?(params[:locale]) ? params[:locale] : nil return I18n.default_locale.to_s if locale.blank?
available_locales = I18n.available_locales.map(&:to_s)
locale_without_variant = locale.split('_')[0]
if available_locales.include?(locale)
locale
elsif available_locales.include?(locale_without_variant)
locale_without_variant
else
I18n.default_locale.to_s
end
end end
def locale_from_account(account) def locale_from_account(account)
return unless account return unless account
I18n.available_locales.map(&:to_s).include?(account.locale) ? account.locale : nil account.locale
end
def locale_from_env_variable
return unless ENV.fetch('DEFAULT_LOCALE', nil)
I18n.available_locales.map(&:to_s).include?(ENV.fetch('DEFAULT_LOCALE')) ? ENV.fetch('DEFAULT_LOCALE') : nil
end end
end end
@@ -1,4 +1,6 @@
class Public::Api::V1::Portals::BaseController < PublicController class Public::Api::V1::Portals::BaseController < PublicController
include SwitchLocale
before_action :show_plain_layout before_action :show_plain_layout
before_action :set_color_scheme before_action :set_color_scheme
before_action :set_global_config before_action :set_global_config
@@ -27,14 +29,7 @@ class Public::Api::V1::Portals::BaseController < PublicController
end end
def switch_locale_with_portal(&) def switch_locale_with_portal(&)
locale_without_variant = params[:locale].split('_')[0] @locale = validate_and_get_locale(params[:locale])
is_locale_available = I18n.available_locales.map(&:to_s).include?(params[:locale])
is_locale_variant_available = I18n.available_locales.map(&:to_s).include?(locale_without_variant)
if is_locale_available
@locale = params[:locale]
elsif is_locale_variant_available
@locale = locale_without_variant
end
I18n.with_locale(@locale, &) I18n.with_locale(@locale, &)
end end
@@ -44,12 +39,12 @@ class Public::Api::V1::Portals::BaseController < PublicController
Rails.logger.info "Article: not found for slug: #{params[:article_slug]}" Rails.logger.info "Article: not found for slug: #{params[:article_slug]}"
render_404 && return if article.blank? render_404 && return if article.blank?
@locale = if article.category.present? article_locale = if article.category.present?
article.category.locale article.category.locale
else else
article.portal.default_locale article.portal.default_locale
end end
@locale = validate_and_get_locale(article_locale)
I18n.with_locale(@locale, &) I18n.with_locale(@locale, &)
end end
+3
View File
@@ -4,6 +4,7 @@ import AddAccountModal from '../dashboard/components/layout/sidebarComponents/Ad
import LoadingState from './components/widgets/LoadingState.vue'; import LoadingState from './components/widgets/LoadingState.vue';
import NetworkNotification from './components/NetworkNotification.vue'; import NetworkNotification from './components/NetworkNotification.vue';
import UpdateBanner from './components/app/UpdateBanner.vue'; import UpdateBanner from './components/app/UpdateBanner.vue';
import UpgradeBanner from './components/app/UpgradeBanner.vue';
import PaymentPendingBanner from './components/app/PaymentPendingBanner.vue'; import PaymentPendingBanner from './components/app/PaymentPendingBanner.vue';
import PendingEmailVerificationBanner from './components/app/PendingEmailVerificationBanner.vue'; import PendingEmailVerificationBanner from './components/app/PendingEmailVerificationBanner.vue';
import vueActionCable from './helper/actionCable'; import vueActionCable from './helper/actionCable';
@@ -30,6 +31,7 @@ export default {
UpdateBanner, UpdateBanner,
PaymentPendingBanner, PaymentPendingBanner,
WootSnackbarBox, WootSnackbarBox,
UpgradeBanner,
PendingEmailVerificationBanner, PendingEmailVerificationBanner,
}, },
setup() { setup() {
@@ -144,6 +146,7 @@ export default {
<template v-if="currentAccountId"> <template v-if="currentAccountId">
<PendingEmailVerificationBanner v-if="hideOnOnboardingView" /> <PendingEmailVerificationBanner v-if="hideOnOnboardingView" />
<PaymentPendingBanner v-if="hideOnOnboardingView" /> <PaymentPendingBanner v-if="hideOnOnboardingView" />
<UpgradeBanner />
</template> </template>
<router-view v-slot="{ Component }"> <router-view v-slot="{ Component }">
<transition name="fade" mode="out-in"> <transition name="fade" mode="out-in">
@@ -26,7 +26,7 @@ const { t } = useI18n();
/> />
</div> </div>
<div <div
class="absolute bg-n-alpha-3 px-4 py-3 border rounded-xl border-n-strong text-n-slate-12 bottom-6 w-52 text-xs backdrop-blur-[100px] shadow-[0px_0px_24px_0px_rgba(0,0,0,0.12)] opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all" class="absolute bg-n-alpha-3 px-4 py-3 border rounded-xl border-n-strong text-n-slate-12 bottom-6 w-52 text-xs backdrop-blur-[100px] shadow-[0px_0px_24px_0px_rgba(0,0,0,0.12)] opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all break-all"
:class="{ :class="{
'ltr:left-0 rtl:right-0': orientation === ORIENTATION.LEFT, 'ltr:left-0 rtl:right-0': orientation === ORIENTATION.LEFT,
'ltr:right-0 rtl:left-0': orientation === ORIENTATION.RIGHT, 'ltr:right-0 rtl:left-0': orientation === ORIENTATION.RIGHT,
@@ -102,6 +102,7 @@ const statusToShow = computed(() => {
if (isRead.value) return MESSAGE_STATUS.READ; if (isRead.value) return MESSAGE_STATUS.READ;
if (isDelivered.value) return MESSAGE_STATUS.DELIVERED; if (isDelivered.value) return MESSAGE_STATUS.DELIVERED;
if (isSent.value) return MESSAGE_STATUS.SENT; if (isSent.value) return MESSAGE_STATUS.SENT;
if (status.value === MESSAGE_STATUS.FAILED) return MESSAGE_STATUS.FAILED;
return MESSAGE_STATUS.PROGRESS; return MESSAGE_STATUS.PROGRESS;
}); });
@@ -1,79 +0,0 @@
<script setup>
import { computed, onMounted } from 'vue';
import { useStore } from 'vuex';
import { useAccount } from 'dashboard/composables/useAccount';
import { differenceInDays } from 'date-fns';
import { useRoute } from 'vue-router';
const ALWAYS_ON_ROUTES = [
'agent_list',
'settings_inbox_list',
'billing_settings_index',
];
const { accountId } = useAccount();
const store = useStore();
const route = useRoute();
const routeName = computed(() => {
return route.name || '';
});
const isOnChatwootCloud = computed(
() => store.getters['globalConfig/isOnChatwootCloud']
);
const account = computed(() =>
store.getters['accounts/getAccount'](accountId.value)
);
const isTrialAccount = computed(() => {
if (!account.value) return false;
const createdAt = new Date(account.value.created_at);
const diffDays = differenceInDays(new Date(), createdAt);
return diffDays <= 15;
});
const testLimit = ({ allowed, consumed }) => {
return consumed > allowed;
};
const isLimitExceeded = computed(() => {
if (ALWAYS_ON_ROUTES.includes(routeName.value)) {
return false;
}
if (!account.value) return false;
const { limits } = account.value;
if (!limits) return false;
const { conversation, non_web_inboxes: nonWebInboxes } = limits;
return testLimit(conversation) || testLimit(nonWebInboxes);
});
const shouldShowBanner = computed(() => {
if (!isOnChatwootCloud.value) {
return false;
}
if (isTrialAccount.value) {
return false;
}
return isLimitExceeded.value;
});
const fetchLimits = () => store.dispatch('accounts/limits');
onMounted(() => {
if (isOnChatwootCloud.value) {
fetchLimits();
}
});
</script>
<template>
<div v-if="shouldShowBanner">Limits exceeded</div>
<slot v-else />
</template>
+27 -4
View File
@@ -9,6 +9,7 @@ class ActionCableConnector extends BaseActionCableConnector {
const { websocketURL = '' } = window.chatwootConfig || {}; const { websocketURL = '' } = window.chatwootConfig || {};
super(app, pubsubToken, websocketURL); super(app, pubsubToken, websocketURL);
this.CancelTyping = []; this.CancelTyping = [];
this.conversationEventTimestamps = new Map();
this.events = { this.events = {
'message.created': this.onMessageCreated, 'message.created': this.onMessageCreated,
'message.updated': this.onMessageUpdated, 'message.updated': this.onMessageUpdated,
@@ -33,6 +34,23 @@ class ActionCableConnector extends BaseActionCableConnector {
}; };
} }
/**
* Checks if a conversation event is out of sequence by comparing timestamps
* @param {number} conversationId - The ID of the conversation to check
* @param {number} eventTimestamp - The timestamp of the current event
* @returns {boolean} Returns true if event is out of sequence, false otherwise
*/
eventOutOfSequence(conversationId, eventTimestamp) {
if (!eventTimestamp) return false;
const lastTimestamp = this.conversationEventTimestamps.get(conversationId);
if (!lastTimestamp || eventTimestamp > lastTimestamp) {
this.conversationEventTimestamps.set(conversationId, eventTimestamp);
return false;
}
return true;
}
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
onReconnect = () => { onReconnect = () => {
emitter.emit(BUS_EVENTS.WEBSOCKET_RECONNECT); emitter.emit(BUS_EVENTS.WEBSOCKET_RECONNECT);
@@ -68,8 +86,10 @@ class ActionCableConnector extends BaseActionCableConnector {
} }
}; };
onAssigneeChanged = payload => { onAssigneeChanged = (payload, eventTimestamp) => {
const { id } = payload; const { id } = payload;
if (this.eventOutOfSequence(id, eventTimestamp)) return;
if (id) { if (id) {
this.app.$store.dispatch('updateConversation', payload); this.app.$store.dispatch('updateConversation', payload);
} }
@@ -81,7 +101,8 @@ class ActionCableConnector extends BaseActionCableConnector {
this.fetchConversationStats(); this.fetchConversationStats();
}; };
onConversationRead = data => { onConversationRead = (data, eventTimestamp) => {
if (this.eventOutOfSequence(data.id, eventTimestamp)) return;
this.app.$store.dispatch('updateConversation', data); this.app.$store.dispatch('updateConversation', data);
}; };
@@ -104,12 +125,14 @@ class ActionCableConnector extends BaseActionCableConnector {
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
onReload = () => window.location.reload(); onReload = () => window.location.reload();
onStatusChange = data => { onStatusChange = (data, eventTimestamp) => {
if (this.eventOutOfSequence(data.id, eventTimestamp)) return;
this.app.$store.dispatch('updateConversation', data); this.app.$store.dispatch('updateConversation', data);
this.fetchConversationStats(); this.fetchConversationStats();
}; };
onConversationUpdated = data => { onConversationUpdated = (data, eventTimestamp) => {
if (this.eventOutOfSequence(data.id, eventTimestamp)) return;
this.app.$store.dispatch('updateConversation', data); this.app.$store.dispatch('updateConversation', data);
this.fetchConversationStats(); this.fetchConversationStats();
}; };
@@ -560,7 +560,7 @@
"ERROR_MESSAGE": "Wir konnten die Suche nicht abschließen. Bitte versuch es erneut." "ERROR_MESSAGE": "Wir konnten die Suche nicht abschließen. Bitte versuch es erneut."
}, },
"FORM": { "FORM": {
"GO_TO_CONVERSATION": "Aussicht", "GO_TO_CONVERSATION": "Anzeigen",
"SUCCESS_MESSAGE": "Die Nachricht wurde erfolgreich versendet!", "SUCCESS_MESSAGE": "Die Nachricht wurde erfolgreich versendet!",
"ERROR_MESSAGE": "Beim Erstellen der Unterhaltung ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.", "ERROR_MESSAGE": "Beim Erstellen der Unterhaltung ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.",
"NO_INBOX_ALERT": "Es sind keine Posteingänge vorhanden, um eine Unterhaltung mit diesem Kontakt zu starten.", "NO_INBOX_ALERT": "Es sind keine Posteingänge vorhanden, um eine Unterhaltung mit diesem Kontakt zu starten.",
@@ -751,7 +751,7 @@
"WHATSAPP": "WhatsApp", "WHATSAPP": "WhatsApp",
"SMS": "SMS", "SMS": "SMS",
"EMAIL": "E-Mail", "EMAIL": "E-Mail",
"TELEGRAM": "Telegram", "TELEGRAM": "Telegramm",
"LINE": "Line", "LINE": "Line",
"API": "API-Kanal" "API": "API-Kanal"
} }
@@ -12,7 +12,7 @@
}, },
"WEBHOOK": { "WEBHOOK": {
"SUBSCRIBED_EVENTS": "Abonnierte Events", "SUBSCRIBED_EVENTS": "Abonnierte Events",
"LEARN_MORE": "Learn more about webhooks", "LEARN_MORE": "Mehr über Webhooks erfahren",
"FORM": { "FORM": {
"CANCEL": "Stornieren", "CANCEL": "Stornieren",
"DESC": "Webhook-Ereignisse bieten Ihnen Echtzeitinformationen darüber, was in Ihrem Chatwoot-Konto passiert. Bitte geben Sie eine gültige URL ein, um einen Rückruf zu konfigurieren.", "DESC": "Webhook-Ereignisse bieten Ihnen Echtzeitinformationen darüber, was in Ihrem Chatwoot-Konto passiert. Bitte geben Sie eine gültige URL ein, um einen Rückruf zu konfigurieren.",
@@ -31,7 +31,7 @@
}, },
"END_POINT": { "END_POINT": {
"LABEL": "Webhook-URL", "LABEL": "Webhook-URL",
"PLACEHOLDER": "Example: {webhookExampleURL}", "PLACEHOLDER": "Beispiel: {webhookExampleURL}",
"ERROR": "Bitte geben Sie eine gültige URL ein" "ERROR": "Bitte geben Sie eine gültige URL ein"
}, },
"EDIT_SUBMIT": "Webhook aktualisieren", "EDIT_SUBMIT": "Webhook aktualisieren",
@@ -114,7 +114,7 @@
}, },
"OPEN_AI": { "OPEN_AI": {
"AI_ASSIST": "AI-Assistent", "AI_ASSIST": "AI-Assistent",
"WITH_AI": " {option} with AI ", "WITH_AI": " {option} mit KI ",
"OPTIONS": { "OPTIONS": {
"REPLY_SUGGESTION": "Antwortvorschlag", "REPLY_SUGGESTION": "Antwortvorschlag",
"SUMMARIZE": "Zusammenfassen", "SUMMARIZE": "Zusammenfassen",
@@ -235,7 +235,7 @@
"ERROR": "Beim Abrufen der linearen Probleme ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut", "ERROR": "Beim Abrufen der linearen Probleme ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut",
"LINK_SUCCESS": "Problem erfolgreich verknüpft", "LINK_SUCCESS": "Problem erfolgreich verknüpft",
"LINK_ERROR": "Beim Verknüpfen des Problems ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut", "LINK_ERROR": "Beim Verknüpfen des Problems ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut",
"LINK_TITLE": "Conversation (#{conversationId}) with {name}" "LINK_TITLE": "Unterhaltung (#{conversationId}) mit {name}"
}, },
"ADD_OR_LINK": { "ADD_OR_LINK": {
"TITLE": "Lineares Problem erstellen/verknüpfen", "TITLE": "Lineares Problem erstellen/verknüpfen",
@@ -294,7 +294,7 @@
"PRIORITY": "Priorität", "PRIORITY": "Priorität",
"ASSIGNEE": "Zugewiesener", "ASSIGNEE": "Zugewiesener",
"LABELS": "Labels", "LABELS": "Labels",
"CREATED_AT": "Created at {createdAt}" "CREATED_AT": "Erstellt am {createdAt}"
}, },
"UNLINK": { "UNLINK": {
"TITLE": "Verknüpfung aufheben", "TITLE": "Verknüpfung aufheben",
@@ -302,8 +302,8 @@
"ERROR": "Beim Aufheben der Verknüpfung des Problems ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut" "ERROR": "Beim Aufheben der Verknüpfung des Problems ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut"
}, },
"DELETE": { "DELETE": {
"TITLE": "Are you sure you want to delete the integration?", "TITLE": "Sind Sie sicher, dass Sie die Integration löschen möchten?",
"MESSAGE": "Are you sure you want to delete the integration?", "MESSAGE": "Sind Sie sicher, dass Sie die Integration löschen möchten?",
"CONFIRM": "Ja, löschen", "CONFIRM": "Ja, löschen",
"CANCEL": "Stornieren" "CANCEL": "Stornieren"
} }
@@ -313,27 +313,27 @@
"NAME": "Kapitän", "NAME": "Kapitän",
"COPILOT": { "COPILOT": {
"SEND_MESSAGE": "Nachricht senden...", "SEND_MESSAGE": "Nachricht senden...",
"LOADER": "Captain is thinking", "LOADER": "Captain denkt nach",
"YOU": "Sie", "YOU": "Sie",
"USE": "Use this", "USE": "Verwenden",
"RESET": "Reset", "RESET": "Zurücksetzen",
"SELECT_ASSISTANT": "Select Assistant" "SELECT_ASSISTANT": "Assistent auswählen"
}, },
"PAYWALL": { "PAYWALL": {
"TITLE": "Upgrade to use Captain AI", "TITLE": "Upgrade auf Captain AI",
"AVAILABLE_ON": "Captain is not available on the free plan.", "AVAILABLE_ON": "Captain is not available on the free plan.",
"UPGRADE_PROMPT": "Upgrade your plan to get access to our assistants, copilot and more.", "UPGRADE_PROMPT": "Tarif upgraden, um Zugang zu unseren Assistenten, Copilot und mehr zu erhalten.",
"UPGRADE_NOW": "Upgrade now", "UPGRADE_NOW": "Jetzt upgraden",
"CANCEL_ANYTIME": "You can change or cancel your plan anytime" "CANCEL_ANYTIME": "Sie können Ihr Paket jederzeit ändern oder kündigen"
}, },
"ENTERPRISE_PAYWALL": { "ENTERPRISE_PAYWALL": {
"AVAILABLE_ON": "Captain AI feature is only available in a paid plan.", "AVAILABLE_ON": "Captain AI Funktion ist nur mit einem kostenpflichtigen Tarif verfügbar.",
"UPGRADE_PROMPT": "Upgrade your plan to get access to our assistants, copilot and more.", "UPGRADE_PROMPT": "Tarif upgraden, um Zugang zu unseren Assistenten, Copilot und mehr zu erhalten.",
"ASK_ADMIN": "Please reach out to your administrator for the upgrade." "ASK_ADMIN": "Bitte kontaktieren Sie Ihren Administrator für das Upgrade."
}, },
"BANNER": { "BANNER": {
"RESPONSES": "You've used over 80% of your response limit. To continue using Captain AI, please upgrade.", "RESPONSES": "You've used over 80% of your response limit. To continue using Captain AI, please upgrade.",
"DOCUMENTS": "Document limit reached. Upgrade to continue using Captain AI." "DOCUMENTS": "Dokumentenlimit erreicht. Upgraden um Cpatain AI weiter zu verwenden."
}, },
"FORM": { "FORM": {
"CANCEL": "Stornieren", "CANCEL": "Stornieren",
@@ -100,7 +100,7 @@
"NO_RESULTS": "Nenhum resultado encontrado." "NO_RESULTS": "Nenhum resultado encontrado."
}, },
"MULTI_SELECTOR": { "MULTI_SELECTOR": {
"PLACEHOLDER": "Nenhuma", "PLACEHOLDER": "Nenhum",
"TITLE": { "TITLE": {
"AGENT": "Selecionar agente", "AGENT": "Selecionar agente",
"TEAM": "Selecionar time" "TEAM": "Selecionar time"
@@ -1,16 +1,16 @@
{ {
"AUDIT_LOGS": { "AUDIT_LOGS": {
"HEADER": "Registros de Auditoria", "HEADER": "Auditoria",
"HEADER_BTN_TXT": "Adicionar Registros de Auditoria", "HEADER_BTN_TXT": "Adicionar Logs de Auditoria",
"LOADING": "Buscando Logs de Auditoria", "LOADING": "Buscando Logs de Auditoria",
"DESCRIPTION": "Logs de Auditoria mantêm um registro de atividades em sua conta, permitindo que você acompanhe e auditoria de sua conta, equipe ou serviços.", "DESCRIPTION": "Logs de Auditoria mantêm um registro de atividades em sua conta, permitindo que você acompanhe e auditoria de sua conta, equipe ou serviços.",
"LEARN_MORE": "Saiba mais sobre os logs de auditoria", "LEARN_MORE": "Saiba mais sobre os logs de auditoria",
"SEARCH_404": "Não existem itens correspondentes a esta consulta", "SEARCH_404": "Não existem itens correspondentes a esta consulta",
"SIDEBAR_TXT": "<p><b>Registros de Auditoria</b> </p><p> Registros de Auditoria são trilhas para eventos e ações em um Sistema Chatwoot. </p>", "SIDEBAR_TXT": "<p><b>Logs de Auditoria</b> </p><p> Os Logs de Auditoria são rastros para eventos e ações em um Sistema Chatwoot. </p>",
"LIST": { "LIST": {
"404": "Não há Registros de Auditoria disponíveis nesta conta.", "404": "Não há Logs de Auditoria disponíveis nesta conta.",
"TITLE": "Gerenciar Registros de Auditoria", "TITLE": "Gerenciar Logs de Auditoria",
"DESC": "Registros de Auditoria são trilhas para eventos e ações em um Sistema Chatwoot.", "DESC": "Logs de auditoria são rastros para eventos e ações em um Sistema de Chatwoot.",
"TABLE_HEADER": { "TABLE_HEADER": {
"ACTIVITY": "Usuário", "ACTIVITY": "Usuário",
"TIME": "Ação", "TIME": "Ação",
@@ -27,12 +27,12 @@
"ERROR": "Falha ao atualizar etiquetas" "ERROR": "Falha ao atualizar etiquetas"
}, },
"CONVERSATION": { "CONVERSATION": {
"TITLE": "Marcador da conversa", "TITLE": "Etiquetas da conversa",
"ADD_BUTTON": "Adicionar marcador" "ADD_BUTTON": "Adicionar etiquetas"
}, },
"LABEL_SELECT": { "LABEL_SELECT": {
"TITLE": "Adicionar marcador", "TITLE": "Adicionar etiquetas",
"PLACEHOLDER": "Pesquisar marcador ", "PLACEHOLDER": "Pesquisar etiquetas",
"NO_RESULT": "Nenhuma etiqueta encontrada", "NO_RESULT": "Nenhuma etiqueta encontrada",
"CREATE_LABEL": "Criar etiqueta" "CREATE_LABEL": "Criar etiqueta"
} }
@@ -65,7 +65,7 @@
"HEADER": { "HEADER": {
"RESOLVE_ACTION": "Resolver", "RESOLVE_ACTION": "Resolver",
"REOPEN_ACTION": "Reabrir", "REOPEN_ACTION": "Reabrir",
"OPEN_ACTION": "Abertas", "OPEN_ACTION": "Abrir",
"OPEN": "Mais", "OPEN": "Mais",
"CLOSE": "Fechar", "CLOSE": "Fechar",
"DETAILS": "detalhes", "DETAILS": "detalhes",
@@ -148,7 +148,7 @@
"MESSAGE_SIGN_TOOLTIP": "Assinatura de mensagem", "MESSAGE_SIGN_TOOLTIP": "Assinatura de mensagem",
"ENABLE_SIGN_TOOLTIP": "Ativar assinatura", "ENABLE_SIGN_TOOLTIP": "Ativar assinatura",
"DISABLE_SIGN_TOOLTIP": "Desativar assinatura", "DISABLE_SIGN_TOOLTIP": "Desativar assinatura",
"MSG_INPUT": "Shift + enter para nova linha. Digite '/' para atalhos.", "MSG_INPUT": "Shift + enter para nova linha. Digite '/' para selecionar uma Resposta Pronta.",
"PRIVATE_MSG_INPUT": "A mensagem será visível apenas para agentes", "PRIVATE_MSG_INPUT": "A mensagem será visível apenas para agentes",
"MESSAGE_SIGNATURE_NOT_CONFIGURED": "A assinatura da mensagem não está configurada. Por favor, configure-a nas configurações do perfil.", "MESSAGE_SIGNATURE_NOT_CONFIGURED": "A assinatura da mensagem não está configurada. Por favor, configure-a nas configurações do perfil.",
"CLICK_HERE": "Clique aqui para atualizar", "CLICK_HERE": "Clique aqui para atualizar",
@@ -15,7 +15,7 @@
}, },
"ENTERPRISE_PAYWALL": { "ENTERPRISE_PAYWALL": {
"AVAILABLE_ON": "O recurso de função personalizada está disponível apenas nos planos pagos.", "AVAILABLE_ON": "O recurso de função personalizada está disponível apenas nos planos pagos.",
"UPGRADE_PROMPT": "Atualize para um plano pago para acessar recursos avançados como registros de auditoria, capacidade do agente e muito mais.", "UPGRADE_PROMPT": "Atualize para um plano pago para acessar recursos avançados como logs de auditoria, capacidade do agente e muito mais.",
"ASK_ADMIN": "Entre em contato com seu administrador para fazer a atualização." "ASK_ADMIN": "Entre em contato com seu administrador para fazer a atualização."
}, },
"LIST": { "LIST": {
@@ -1,6 +1,6 @@
{ {
"GENERAL_SETTINGS": { "GENERAL_SETTINGS": {
"TITLE": "Configurações da conta", "TITLE": "Conta",
"SUBMIT": "Atualizar configurações", "SUBMIT": "Atualizar configurações",
"BACK": "Anterior", "BACK": "Anterior",
"DISMISS": "Recusar", "DISMISS": "Recusar",
@@ -131,10 +131,10 @@
"GO_TO_INBOX_REPORTS": "Ir para Relatórios da Caixa de Entrada", "GO_TO_INBOX_REPORTS": "Ir para Relatórios da Caixa de Entrada",
"GO_TO_TEAM_REPORTS": "Ir para Relatórios da Equipe", "GO_TO_TEAM_REPORTS": "Ir para Relatórios da Equipe",
"GO_TO_SETTINGS_AGENTS": "Ir para Configurações de Agente", "GO_TO_SETTINGS_AGENTS": "Ir para Configurações de Agente",
"GO_TO_SETTINGS_TEAMS": "Ir para as configurações de equipe", "GO_TO_SETTINGS_TEAMS": "Ir para as Configurações de Equipe",
"GO_TO_SETTINGS_INBOXES": "Ir para as configurações da Caixa de Entrada", "GO_TO_SETTINGS_INBOXES": "Ir para as Configurações da Caixa de Entrada",
"GO_TO_SETTINGS_LABELS": "Ir para as Configurações de Etiqueta", "GO_TO_SETTINGS_LABELS": "Ir para as Configurações de Etiqueta",
"GO_TO_SETTINGS_CANNED_RESPONSES": "Ir para as configurações de respostas prontas", "GO_TO_SETTINGS_CANNED_RESPONSES": "Ir para as Configurações de Respostas Prontas",
"GO_TO_SETTINGS_APPLICATIONS": "Vá para Configurações do Aplicativo", "GO_TO_SETTINGS_APPLICATIONS": "Vá para Configurações do Aplicativo",
"GO_TO_SETTINGS_ACCOUNT": "Ir para as Configurações da Conta", "GO_TO_SETTINGS_ACCOUNT": "Ir para as Configurações da Conta",
"GO_TO_SETTINGS_PROFILE": "Ir para as Configurações do Perfil", "GO_TO_SETTINGS_PROFILE": "Ir para as Configurações do Perfil",
@@ -500,7 +500,7 @@
"ENABLE_CONTINUITY_VIA_EMAIL_SUB_TEXT": "As conversas continuarão sobre o e-mail se o endereço de e-mail de contato estiver disponível.", "ENABLE_CONTINUITY_VIA_EMAIL_SUB_TEXT": "As conversas continuarão sobre o e-mail se o endereço de e-mail de contato estiver disponível.",
"LOCK_TO_SINGLE_CONVERSATION": "Bloquear para conversa única", "LOCK_TO_SINGLE_CONVERSATION": "Bloquear para conversa única",
"LOCK_TO_SINGLE_CONVERSATION_SUB_TEXT": "Ativar ou desativar várias conversas para o mesmo contato nesta caixa de entrada", "LOCK_TO_SINGLE_CONVERSATION_SUB_TEXT": "Ativar ou desativar várias conversas para o mesmo contato nesta caixa de entrada",
"INBOX_UPDATE_TITLE": "Configurações da Caixa de entrada", "INBOX_UPDATE_TITLE": "Configurações da Caixa de Entrada",
"INBOX_UPDATE_SUB_TEXT": "Atualize suas configurações de caixa de entrada", "INBOX_UPDATE_SUB_TEXT": "Atualize suas configurações de caixa de entrada",
"AUTO_ASSIGNMENT_SUB_TEXT": "Ativar ou desativar a atribuição automática de novas conversas aos agentes adicionados a essa caixa de entrada.", "AUTO_ASSIGNMENT_SUB_TEXT": "Ativar ou desativar a atribuição automática de novas conversas aos agentes adicionados a essa caixa de entrada.",
"HMAC_VERIFICATION": "Validação de Identidade do Usuário", "HMAC_VERIFICATION": "Validação de Identidade do Usuário",
@@ -695,7 +695,7 @@
"PLACE_HOLDER": "Fale conosco no chat" "PLACE_HOLDER": "Fale conosco no chat"
}, },
"UPDATE": { "UPDATE": {
"BUTTON_TEXT": "Atualizar configurações do widget", "BUTTON_TEXT": "Atualizar Configurações do Widget",
"API": { "API": {
"SUCCESS_MESSAGE": "Configurações do widget atualizadas com sucesso", "SUCCESS_MESSAGE": "Configurações do widget atualizadas com sucesso",
"ERROR_MESSAGE": "Não é possível atualizar as configurações do widget" "ERROR_MESSAGE": "Não é possível atualizar as configurações do widget"
@@ -302,8 +302,8 @@
"ERROR": "Houve um erro ao desvincular o atributo, por favor, tente novamente" "ERROR": "Houve um erro ao desvincular o atributo, por favor, tente novamente"
}, },
"DELETE": { "DELETE": {
"TITLE": "Are you sure you want to delete the integration?", "TITLE": "Tem certeza que deseja excluir esta integração?",
"MESSAGE": "Are you sure you want to delete the integration?", "MESSAGE": "Tem certeza que deseja excluir esta integração?",
"CONFIRM": "Sim, excluir", "CONFIRM": "Sim, excluir",
"CANCEL": "Cancelar" "CANCEL": "Cancelar"
} }
@@ -317,7 +317,7 @@
"YOU": "Você", "YOU": "Você",
"USE": "Use isto", "USE": "Use isto",
"RESET": "Reiniciar", "RESET": "Reiniciar",
"SELECT_ASSISTANT": "Select Assistant" "SELECT_ASSISTANT": "Selecione o Assistente"
}, },
"PAYWALL": { "PAYWALL": {
"TITLE": "Atualize para usar o Capitão IA", "TITLE": "Atualize para usar o Capitão IA",
@@ -440,19 +440,19 @@
"DOCUMENTABLE": { "DOCUMENTABLE": {
"CONVERSATION": "Conversação #{id}" "CONVERSATION": "Conversação #{id}"
}, },
"SELECTED": "{count} selected", "SELECTED": "{count} selecionado",
"BULK_APPROVE_BUTTON": "Approve", "BULK_APPROVE_BUTTON": "Aprovar",
"BULK_DELETE_BUTTON": "Excluir", "BULK_DELETE_BUTTON": "Excluir",
"BULK_APPROVE": { "BULK_APPROVE": {
"SUCCESS_MESSAGE": "FAQs approved successfully", "SUCCESS_MESSAGE": "Perguntas Frequentes aprovadas com sucesso",
"ERROR_MESSAGE": "There was an error approving the FAQs, please try again." "ERROR_MESSAGE": "Ocorreu um erro ao aprovar as Perguntas Frequentes. Tente novamente."
}, },
"BULK_DELETE": { "BULK_DELETE": {
"TITLE": "Delete FAQs?", "TITLE": "Excluir as Perguntas Frequentes?",
"DESCRIPTION": "Are you sure you want to delete the selected FAQs? This action cannot be undone.", "DESCRIPTION": "Tem certeza que deseja excluir as Perguntas Frequentes selecionadas? Esta ação não pode ser desfeita.",
"CONFIRM": "Yes, delete all", "CONFIRM": "Sim, excluir todas",
"SUCCESS_MESSAGE": "FAQs deleted successfully", "SUCCESS_MESSAGE": "Perguntas Frequentes excluídas com sucesso/",
"ERROR_MESSAGE": "There was an error deleting the FAQs, please try again." "ERROR_MESSAGE": "Ocorreu um erro ao excluir as Perguntas Frequentes, por favor tente novamente."
}, },
"DELETE": { "DELETE": {
"TITLE": "Tem certeza que deseja excluir o FAQ?", "TITLE": "Tem certeza que deseja excluir o FAQ?",
@@ -1,7 +1,7 @@
{ {
"LABEL_MGMT": { "LABEL_MGMT": {
"HEADER": "Etiquetas", "HEADER": "Etiquetas",
"HEADER_BTN_TXT": "Adicionar marcador", "HEADER_BTN_TXT": "Adicionar etiqueta",
"LOADING": "Buscando etiquetas", "LOADING": "Buscando etiquetas",
"DESCRIPTION": "As etiquetas ajudam você a categorizar e priorizar conversas e leads. Você pode atribuir uma etiqueta a uma conversa ou contato usando o painel lateral.", "DESCRIPTION": "As etiquetas ajudam você a categorizar e priorizar conversas e leads. Você pode atribuir uma etiqueta a uma conversa ou contato usando o painel lateral.",
"LEARN_MORE": "Aprenda mais sobre etiquetas", "LEARN_MORE": "Aprenda mais sobre etiquetas",
@@ -18,21 +18,21 @@
}, },
"FORM": { "FORM": {
"NAME": { "NAME": {
"LABEL": "Nome do marcador", "LABEL": "Nome da Etiqueta",
"PLACEHOLDER": "Nome do marcador", "PLACEHOLDER": "Nome da etiqueta",
"REQUIRED_ERROR": "O nome do marcador é obrigatório", "REQUIRED_ERROR": "O nome da etiqueta é obrigatório",
"MINIMUM_LENGTH_ERROR": "Tamanho mínimo 2 é necessário", "MINIMUM_LENGTH_ERROR": "Tamanho mínimo 2 é necessário",
"VALID_ERROR": "Somente Letras, Números, Hífen e Sublinhado são permitidos" "VALID_ERROR": "Somente Letras, Números, Hífen e Sublinhado são permitidos"
}, },
"DESCRIPTION": { "DESCRIPTION": {
"LABEL": "Descrição", "LABEL": "Descrição",
"PLACEHOLDER": "Descrição do marcador" "PLACEHOLDER": "Descrição da etiqueta"
}, },
"COLOR": { "COLOR": {
"LABEL": "Cor" "LABEL": "Cor"
}, },
"SHOW_ON_SIDEBAR": { "SHOW_ON_SIDEBAR": {
"LABEL": "Exibir marcador na barra lateral" "LABEL": "Exibir etiqueta na barra lateral"
}, },
"EDIT": "Alterar", "EDIT": "Alterar",
"CREATE": "Criar", "CREATE": "Criar",
@@ -54,10 +54,10 @@
"SUGGESTED_LABELS": "Etiquetas sugeridos" "SUGGESTED_LABELS": "Etiquetas sugeridos"
}, },
"ADD": { "ADD": {
"TITLE": "Adicionar marcador", "TITLE": "Adicionar etiqueta",
"DESC": "Etiquetas permitem agrupar as conversas.", "DESC": "Etiquetas permitem agrupar as conversas.",
"API": { "API": {
"SUCCESS_MESSAGE": "Marcador adicionado com sucesso", "SUCCESS_MESSAGE": "Etiqueta adicionada com sucesso",
"ERROR_MESSAGE": "Ocorreu um erro, por favor tente novamente" "ERROR_MESSAGE": "Ocorreu um erro, por favor tente novamente"
} }
}, },
@@ -71,7 +71,7 @@
"DELETE": { "DELETE": {
"BUTTON_TEXT": "Excluir", "BUTTON_TEXT": "Excluir",
"API": { "API": {
"SUCCESS_MESSAGE": "Marcador excluído com sucesso", "SUCCESS_MESSAGE": "Etiqueta excluída com sucesso",
"ERROR_MESSAGE": "Ocorreu um erro, por favor tente novamente" "ERROR_MESSAGE": "Ocorreu um erro, por favor tente novamente"
}, },
"CONFIRM": { "CONFIRM": {
@@ -471,7 +471,7 @@
"NO_AGENTS": "Não há conversas por agentes", "NO_AGENTS": "Não há conversas por agentes",
"TABLE_HEADER": { "TABLE_HEADER": {
"AGENT": "Agente", "AGENT": "Agente",
"OPEN": "Abertas", "OPEN": "Abrir",
"UNATTENDED": "Não atendidas", "UNATTENDED": "Não atendidas",
"STATUS": "Situação" "STATUS": "Situação"
} }
@@ -509,7 +509,7 @@
"SLA": "Nome do SLA", "SLA": "Nome do SLA",
"AGENTS": "Nome do Agente", "AGENTS": "Nome do Agente",
"INBOXES": "Nome da Caixa de Entrada", "INBOXES": "Nome da Caixa de Entrada",
"LABELS": "Nome do marcador", "LABELS": "Nome da etiqueta",
"TEAMS": "Nome da equipe" "TEAMS": "Nome da equipe"
}, },
"SLA": "Política SLA", "SLA": "Política SLA",
@@ -26,7 +26,7 @@
"UPDATE_SUCCESS": "Suas configurações foram atualizadas com sucesso", "UPDATE_SUCCESS": "Suas configurações foram atualizadas com sucesso",
"CARD": { "CARD": {
"ENTER_KEY": { "ENTER_KEY": {
"HEADING": "Inserir (↵)", "HEADING": "Enter (↵)",
"CONTENT": "Enviar mensagens pressionando a tecla Enter em vez de clicar no botão de enviar." "CONTENT": "Enviar mensagens pressionando a tecla Enter em vez de clicar no botão de enviar."
}, },
"CMD_ENTER_KEY": { "CMD_ENTER_KEY": {
@@ -37,19 +37,19 @@
}, },
"INTERFACE_SECTION": { "INTERFACE_SECTION": {
"TITLE": "Interface", "TITLE": "Interface",
"NOTE": "Customize the look and feel of your Chatwoot dashboard.", "NOTE": "Personalize a aparência do seu painel do Chatwoot.",
"FONT_SIZE": { "FONT_SIZE": {
"TITLE": "Font size", "TITLE": "Tamanho da fonte",
"NOTE": "Adjust the text size across the dashboard based on your preference.", "NOTE": "Ajuste o tamanho do texto do painel com base na sua preferência.",
"UPDATE_SUCCESS": "Your font settings have been updated successfully", "UPDATE_SUCCESS": "As configurações de sua fonte foram atualizadas com sucesso",
"UPDATE_ERROR": "There is an error while updating the font settings, please try again", "UPDATE_ERROR": "Ocorreu um erro ao atualizar as configurações de fonte, por favor, tente novamente",
"OPTIONS": { "OPTIONS": {
"SMALLER": "Smaller", "SMALLER": "Menor",
"SMALL": "Small", "SMALL": "Pequeno",
"DEFAULT": "Padrão", "DEFAULT": "Padrão",
"LARGE": "Large", "LARGE": "Grande",
"LARGER": "Larger", "LARGER": "Maior",
"EXTRA_LARGE": "Extra Large" "EXTRA_LARGE": "Muito Grande"
} }
} }
}, },
@@ -287,13 +287,13 @@
"HOME": "Principal", "HOME": "Principal",
"AGENTS": "Agentes", "AGENTS": "Agentes",
"AGENT_BOTS": "Robôs", "AGENT_BOTS": "Robôs",
"AUDIT_LOGS": "Registros de Auditoria", "AUDIT_LOGS": "Auditoria",
"INBOXES": "Caixas de Entrada", "INBOXES": "Caixas de Entrada",
"NOTIFICATIONS": "Notificações", "NOTIFICATIONS": "Notificações",
"CANNED_RESPONSES": "Respostas Prontas", "CANNED_RESPONSES": "Respostas Prontas",
"INTEGRATIONS": "Integrações", "INTEGRATIONS": "Integrações",
"PROFILE_SETTINGS": "Configurações do Perfil", "PROFILE_SETTINGS": "Configurações do Perfil",
"ACCOUNT_SETTINGS": "Configurações da conta", "ACCOUNT_SETTINGS": "Conta",
"APPLICATIONS": "Aplicações", "APPLICATIONS": "Aplicações",
"LABELS": "Etiquetas", "LABELS": "Etiquetas",
"CUSTOM_ATTRIBUTES": "Atributos Personalizados", "CUSTOM_ATTRIBUTES": "Atributos Personalizados",
@@ -322,7 +322,7 @@
"REPORTS_INBOX": "Caixa de Entrada", "REPORTS_INBOX": "Caixa de Entrada",
"REPORTS_TEAM": "Equipe", "REPORTS_TEAM": "Equipe",
"SET_AVAILABILITY_TITLE": "Defina como", "SET_AVAILABILITY_TITLE": "Defina como",
"SET_YOUR_AVAILABILITY": "Definir a sua disponibilidade", "SET_YOUR_AVAILABILITY": "Disponibilidade",
"SLA": "SLA", "SLA": "SLA",
"CUSTOM_ROLES": "Regras Personalizadas", "CUSTOM_ROLES": "Regras Personalizadas",
"BETA": "Beta", "BETA": "Beta",
@@ -1,9 +1,9 @@
{ {
"SLA": { "SLA": {
"HEADER": "Termos do Serviço", "HEADER": "Acordo de Nível de Serviço",
"ADD_ACTION": "Adicionar SLA", "ADD_ACTION": "Adicionar SLA",
"ADD_ACTION_LONG": "Criar uma nova Política de SLA", "ADD_ACTION_LONG": "Criar uma nova Política de SLA",
"DESCRIPTION": "Contratos de Nível de Serviço (SLAs em inglês) são contratos que definem expectativas claras entre sua equipe e os clientes. Estabelecem normas para tempos de resposta e de resolução, criando um quadro de responsabilização e garantindo uma experiência coerente e de qualidade.", "DESCRIPTION": "Acordo de Nível de Serviço (SLAs em inglês) são acordos que definem expectativas claras entre sua equipe e os clientes. Estabelecem normas para tempos de resposta e de resolução, criando um quadro de responsabilização e garantindo uma experiência coerente e de qualidade.",
"LEARN_MORE": "Saiba mais sobre SLA", "LEARN_MORE": "Saiba mais sobre SLA",
"LOADING": "Buscando SLAs", "LOADING": "Buscando SLAs",
"PAYWALL": { "PAYWALL": {
@@ -15,7 +15,7 @@
}, },
"ENTERPRISE_PAYWALL": { "ENTERPRISE_PAYWALL": {
"AVAILABLE_ON": "O recurso SLA está disponível apenas nos planos pagos.", "AVAILABLE_ON": "O recurso SLA está disponível apenas nos planos pagos.",
"UPGRADE_PROMPT": "Atualize para um plano pago para acessar recursos avançados como registros de auditoria, capacidade do agente e muito mais.", "UPGRADE_PROMPT": "Atualize para um plano pago para acessar recursos avançados como logs de auditoria, capacidade do agente e muito mais.",
"ASK_ADMIN": "Entre em contato com seu administrador para fazer a atualização." "ASK_ADMIN": "Entre em contato com seu administrador para fazer a atualização."
}, },
"LIST": { "LIST": {
@@ -266,7 +266,7 @@
"ATTRIBUTE_WARNING": "Контактная информация <strong>{primaryContactName}</strong> будет скопирована в <strong>{parentContactName}</strong>." "ATTRIBUTE_WARNING": "Контактная информация <strong>{primaryContactName}</strong> будет скопирована в <strong>{parentContactName}</strong>."
}, },
"SEARCH": { "SEARCH": {
"ERROR_MESSAGE": "Something went wrong. Please try again later." "ERROR_MESSAGE": "Что-то пошло не так. Пожалуйста, попробуйте позже."
}, },
"FORM": { "FORM": {
"SUBMIT": " Объединить контакты", "SUBMIT": " Объединить контакты",
@@ -563,7 +563,7 @@
"GO_TO_CONVERSATION": "Просмотр", "GO_TO_CONVERSATION": "Просмотр",
"SUCCESS_MESSAGE": "Сообщение успешно отправлено!", "SUCCESS_MESSAGE": "Сообщение успешно отправлено!",
"ERROR_MESSAGE": "Произошла ошибка при создании диалога. Пожалуйста, повторите попытку позже.", "ERROR_MESSAGE": "Произошла ошибка при создании диалога. Пожалуйста, повторите попытку позже.",
"NO_INBOX_ALERT": "Нет доступных \"входящих\" для начала разговора с этим контактом.", "NO_INBOX_ALERT": "Нет доступных входящих для начала разговора с этим контактом.",
"CONTACT_SELECTOR": { "CONTACT_SELECTOR": {
"LABEL": "Кому:", "LABEL": "Кому:",
"TAG_INPUT_PLACEHOLDER": "Поиск контакта с именем, email или номером телефона", "TAG_INPUT_PLACEHOLDER": "Поиск контакта с именем, email или номером телефона",
@@ -31,7 +31,7 @@
}, },
"PERMISSIONS": { "PERMISSIONS": {
"CONVERSATION_MANAGE": "Управление всеми диалогами", "CONVERSATION_MANAGE": "Управление всеми диалогами",
"CONVERSATION_UNASSIGNED_MANAGE": "Управление неназначенными беседами и теми, которые назначены им", "CONVERSATION_UNASSIGNED_MANAGE": "Управление неназначенными беседами и теми, которые им назначены",
"CONVERSATION_PARTICIPATING_MANAGE": "Управление текущими беседами и теми, которые им назначены", "CONVERSATION_PARTICIPATING_MANAGE": "Управление текущими беседами и теми, которые им назначены",
"CONTACT_MANAGE": "Управление контактами", "CONTACT_MANAGE": "Управление контактами",
"REPORT_MANAGE": "Управление отчетами", "REPORT_MANAGE": "Управление отчетами",
@@ -114,7 +114,7 @@
"CHANGE_PRIORITY": "Изменить приоритет", "CHANGE_PRIORITY": "Изменить приоритет",
"CHANGE_TEAM": "Изменить команду", "CHANGE_TEAM": "Изменить команду",
"SNOOZE_CONVERSATION": "Включить звук диалога", "SNOOZE_CONVERSATION": "Включить звук диалога",
"ADD_LABEL": "Добавить метку в разговор", "ADD_LABEL": "Добавить метку в диалог",
"REMOVE_LABEL": "Удалить метку из диалога", "REMOVE_LABEL": "Удалить метку из диалога",
"SETTINGS": "Настройки", "SETTINGS": "Настройки",
"AI_ASSIST": "Помощь ИИ", "AI_ASSIST": "Помощь ИИ",
@@ -128,11 +128,11 @@
"GO_TO_CONVERSATION_REPORTS": "Перейти к отчетам по диалогам", "GO_TO_CONVERSATION_REPORTS": "Перейти к отчетам по диалогам",
"GO_TO_AGENT_REPORTS": "Перейти к отчетам по сотрудникам", "GO_TO_AGENT_REPORTS": "Перейти к отчетам по сотрудникам",
"GO_TO_LABEL_REPORTS": "Перейти к отчетам по меткам", "GO_TO_LABEL_REPORTS": "Перейти к отчетам по меткам",
"GO_TO_INBOX_REPORTS": "Перейти к отчётам по \"Входящим\"", "GO_TO_INBOX_REPORTS": "Перейти к отчётам по «Входящим»",
"GO_TO_TEAM_REPORTS": "Перейти к отчетам по командам", "GO_TO_TEAM_REPORTS": "Перейти к отчетам по командам",
"GO_TO_SETTINGS_AGENTS": "Перейти к настройкам сотрудников", "GO_TO_SETTINGS_AGENTS": "Перейти к настройкам сотрудников",
"GO_TO_SETTINGS_TEAMS": "Перейти к настройкам команд", "GO_TO_SETTINGS_TEAMS": "Перейти к настройкам команд",
"GO_TO_SETTINGS_INBOXES": "Перейти к настройкам \"Входящих\"", "GO_TO_SETTINGS_INBOXES": "Перейти к настройкам «Входящих»",
"GO_TO_SETTINGS_LABELS": "Перейти к настройкам меток", "GO_TO_SETTINGS_LABELS": "Перейти к настройкам меток",
"GO_TO_SETTINGS_CANNED_RESPONSES": "Перейти к настройкам шаблонных ответов", "GO_TO_SETTINGS_CANNED_RESPONSES": "Перейти к настройкам шаблонных ответов",
"GO_TO_SETTINGS_APPLICATIONS": "Перейти в настройки приложения", "GO_TO_SETTINGS_APPLICATIONS": "Перейти в настройки приложения",
@@ -2,7 +2,7 @@
"INBOX_MGMT": { "INBOX_MGMT": {
"HEADER": "Источники", "HEADER": "Источники",
"DESCRIPTION": "Канал — это способ коммуникации, который ваш клиент выбирает для связи с вами. Входящие — это место, где вы управляете диалогами для определенного канала. Он может включать диалоги из различных источников, таких как электронная почта, онлайн чат или социальные сети.", "DESCRIPTION": "Канал — это способ коммуникации, который ваш клиент выбирает для связи с вами. Входящие — это место, где вы управляете диалогами для определенного канала. Он может включать диалоги из различных источников, таких как электронная почта, онлайн чат или социальные сети.",
"LEARN_MORE": "Узнать больше о \"Входящих\"", "LEARN_MORE": "Узнать больше о «Входящих»",
"RECONNECTION_REQUIRED": "Входящие сообщения отключены. Вы не будете получать новые сообщения пока не пройдете авторизацию повторно.", "RECONNECTION_REQUIRED": "Входящие сообщения отключены. Вы не будете получать новые сообщения пока не пройдете авторизацию повторно.",
"CLICK_TO_RECONNECT": "Нажмите здесь для повторного подключения.", "CLICK_TO_RECONNECT": "Нажмите здесь для повторного подключения.",
"LIST": { "LIST": {
@@ -208,8 +208,8 @@
} }
}, },
"WHATSAPP": { "WHATSAPP": {
"TITLE": "WhatsApp канал", "TITLE": "Канал WhatsApp",
"DESC": "Начните поддерживать ваших клиентов через WhatsApp.", "DESC": "Начните поддерживать своих клиентов через WhatsApp.",
"PROVIDERS": { "PROVIDERS": {
"LABEL": "Поставщик API", "LABEL": "Поставщик API",
"TWILIO": "Twilio", "TWILIO": "Twilio",
@@ -302,8 +302,8 @@
"ERROR": "Произошла ошибка при отвязке задачи, пожалуйста, попробуйте ещё раз" "ERROR": "Произошла ошибка при отвязке задачи, пожалуйста, попробуйте ещё раз"
}, },
"DELETE": { "DELETE": {
"TITLE": "Are you sure you want to delete the integration?", "TITLE": "Вы уверены, что хотите удалить интеграцию?",
"MESSAGE": "Are you sure you want to delete the integration?", "MESSAGE": "Вы уверены, что хотите удалить интеграцию?",
"CONFIRM": "Да, удалить", "CONFIRM": "Да, удалить",
"CANCEL": "Отменить" "CANCEL": "Отменить"
} }
@@ -317,18 +317,18 @@
"YOU": "Вы", "YOU": "Вы",
"USE": "Использовать это", "USE": "Использовать это",
"RESET": "Сброс", "RESET": "Сброс",
"SELECT_ASSISTANT": "Select Assistant" "SELECT_ASSISTANT": "Выбрать ассистента"
}, },
"PAYWALL": { "PAYWALL": {
"TITLE": "Обновите тарифный план, чтобы использовать Captain AI", "TITLE": "Обновите тарифный план, чтобы использовать Captain AI",
"AVAILABLE_ON": "Капитан недоступен на бесплатном тарифном плане.", "AVAILABLE_ON": "Капитан недоступен на бесплатном тарифном плане.",
"UPGRADE_PROMPT": "Обновите тарифный план, чтобы получить доступ к помощникам, Captain AI и другому.", "UPGRADE_PROMPT": "Обновите тарифный план, чтобы получить доступ к нашим ассистентам, copilot и другим функциям.",
"UPGRADE_NOW": "Обновить сейчас", "UPGRADE_NOW": "Обновить сейчас",
"CANCEL_ANYTIME": "Вы можете изменить или отменить ваш тарифный план в любое время" "CANCEL_ANYTIME": "Вы можете изменить или отменить ваш тарифный план в любое время"
}, },
"ENTERPRISE_PAYWALL": { "ENTERPRISE_PAYWALL": {
"AVAILABLE_ON": "Функция Captain AI доступна только в платном плане.", "AVAILABLE_ON": "Функция Captain AI доступна только в платном плане.",
"UPGRADE_PROMPT": "Обновите тарифный план, чтобы получить доступ к помощникам, Captain AI и другому.", "UPGRADE_PROMPT": "Обновите тарифный план, чтобы получить доступ к нашим ассистентам, copilot и другим функциям.",
"ASK_ADMIN": "Пожалуйста, обратитесь к вашему администратору для обновления." "ASK_ADMIN": "Пожалуйста, обратитесь к вашему администратору для обновления."
}, },
"BANNER": { "BANNER": {
@@ -341,35 +341,35 @@
"EDIT": "Обновить" "EDIT": "Обновить"
}, },
"ASSISTANTS": { "ASSISTANTS": {
"HEADER": "Помощники", "HEADER": "Ассистенты",
"ADD_NEW": "Создать нового помощника", "ADD_NEW": "Создать нового ассистента",
"DELETE": { "DELETE": {
"TITLE": "Вы уверены, что хотите удалить помощника?", "TITLE": "Вы уверены, что хотите удалить ассистента?",
"DESCRIPTION": "Это действие необратимо. Удаление этого помощника удалит его из всех подключенных источников и навсегда удалит все сгенерированные знания.", "DESCRIPTION": "Это действие необратимо. Удаление этого ассистента удалит его из всех подключенных источников и навсегда удалит все сгенерированные знания.",
"CONFIRM": "Да, удалить", "CONFIRM": "Да, удалить",
"SUCCESS_MESSAGE": "Помощник успешно удален", "SUCCESS_MESSAGE": "Ассистент успешно удален",
"ERROR_MESSAGE": "При удалении помощника произошла ошибка. Пожалуйста, попробуйте еще раз." "ERROR_MESSAGE": "При удалении ассистента произошла ошибка. Пожалуйста, попробуйте еще раз."
}, },
"FORM_DESCRIPTION": "Заполните приведенные ниже сведения, чтобы назвать своего помощника, описать его цель и указать поддерживаемый продукт.", "FORM_DESCRIPTION": "Заполните приведенные ниже сведения, чтобы назвать своего ассистента, описать его цель и указать поддерживаемый продукт.",
"CREATE": { "CREATE": {
"TITLE": "Создать помощника", "TITLE": "Создать ассистента",
"SUCCESS_MESSAGE": "Помощник успешно создан", "SUCCESS_MESSAGE": "Ассистент успешно создан",
"ERROR_MESSAGE": "При создании помощника произошла ошибка, пожалуйста, попробуйте еще раз." "ERROR_MESSAGE": "При создании ассистента произошла ошибка, пожалуйста, попробуйте еще раз."
}, },
"FORM": { "FORM": {
"NAME": { "NAME": {
"LABEL": "Имя помощника", "LABEL": "Имя ассистента",
"PLACEHOLDER": "Введите имя помощника", "PLACEHOLDER": "Введите имя ассистента",
"ERROR": "Пожалуйста, укажите имя помощника" "ERROR": "Пожалуйста, укажите имя ассистента"
}, },
"DESCRIPTION": { "DESCRIPTION": {
"LABEL": "Описание помощника", "LABEL": "Описание ассистента",
"PLACEHOLDER": "Опишите, как и где будет использоваться этот помощник", "PLACEHOLDER": "Опишите, как и где будет использоваться этот ассистент",
"ERROR": "Необходимо описание" "ERROR": "Необходимо описание"
}, },
"PRODUCT_NAME": { "PRODUCT_NAME": {
"LABEL": "Название продукта", "LABEL": "Название продукта",
"PLACEHOLDER": "Введите название продукта, для которого предназначен этот помощник", "PLACEHOLDER": "Введите название продукта, для которого предназначен этот ассистент",
"ERROR": "Требуется название продукта" "ERROR": "Требуется название продукта"
}, },
"FEATURES": { "FEATURES": {
@@ -379,18 +379,18 @@
} }
}, },
"EDIT": { "EDIT": {
"TITLE": "Обновить помощника", "TITLE": "Обновить ассистента",
"SUCCESS_MESSAGE": "Помощник успешно обновлен", "SUCCESS_MESSAGE": "Ассистент успешно обновлен",
"ERROR_MESSAGE": "При обновлении помощника произошла ошибка, пожалуйста, попробуйте еще раз." "ERROR_MESSAGE": "При обновлении ассистента произошла ошибка, пожалуйста, попробуйте еще раз."
}, },
"OPTIONS": { "OPTIONS": {
"EDIT_ASSISTANT": "Редактировать помощника", "EDIT_ASSISTANT": "Редактировать ассистента",
"DELETE_ASSISTANT": "Удалить помощника", "DELETE_ASSISTANT": "Удалить ассистента",
"VIEW_CONNECTED_INBOXES": "Просмотр подключенных источников" "VIEW_CONNECTED_INBOXES": "Просмотр подключенных источников"
}, },
"EMPTY_STATE": { "EMPTY_STATE": {
"TITLE": "Нет доступных помощников", "TITLE": "Нет доступных ассистентов",
"SUBTITLE": "Создайте помощника, чтобы дать быстрые и точные ответы пользователям. Он может учиться на ваших статьях из центра поддержки и прошлых диалогах." "SUBTITLE": "Создайте ассистента, чтобы дать быстрые и точные ответы пользователям. Он может учиться на ваших статьях из центра поддержки и прошлых диалогах."
} }
}, },
"DOCUMENTS": { "DOCUMENTS": {
@@ -413,9 +413,9 @@
"ERROR": "Пожалуйста, укажите корректный URL для документа" "ERROR": "Пожалуйста, укажите корректный URL для документа"
}, },
"ASSISTANT": { "ASSISTANT": {
"LABEL": "Помощник", "LABEL": "Ассистент",
"PLACEHOLDER": "Выберите помощника", "PLACEHOLDER": "Выберите ассистента",
"ERROR": "Необходимо заполнить поле помощника" "ERROR": "Необходимо заполнить поле ассистента"
} }
}, },
"DELETE": { "DELETE": {
@@ -440,19 +440,19 @@
"DOCUMENTABLE": { "DOCUMENTABLE": {
"CONVERSATION": "Диалог #{id}" "CONVERSATION": "Диалог #{id}"
}, },
"SELECTED": "{count} selected", "SELECTED": "Выбрано {count}",
"BULK_APPROVE_BUTTON": "Approve", "BULK_APPROVE_BUTTON": "Одобрить",
"BULK_DELETE_BUTTON": "Удалить", "BULK_DELETE_BUTTON": "Удалить",
"BULK_APPROVE": { "BULK_APPROVE": {
"SUCCESS_MESSAGE": "FAQs approved successfully", "SUCCESS_MESSAGE": "FAQ успешно одобрены",
"ERROR_MESSAGE": "There was an error approving the FAQs, please try again." "ERROR_MESSAGE": "Произошла ошибка при одобрении FAQ, пожалуйста, попробуйте ещё раз."
}, },
"BULK_DELETE": { "BULK_DELETE": {
"TITLE": "Delete FAQs?", "TITLE": "Удалить FAQ?",
"DESCRIPTION": "Are you sure you want to delete the selected FAQs? This action cannot be undone.", "DESCRIPTION": "Вы уверены, что хотите удалить выбранные FAQ? Это действие невозможно отменить.",
"CONFIRM": "Yes, delete all", "CONFIRM": "Да, удалить всё",
"SUCCESS_MESSAGE": "FAQs deleted successfully", "SUCCESS_MESSAGE": "FAQ успешно удалены",
"ERROR_MESSAGE": "There was an error deleting the FAQs, please try again." "ERROR_MESSAGE": "Произошла ошибка при удалении FAQ, пожалуйста, попробуйте ещё раз."
}, },
"DELETE": { "DELETE": {
"TITLE": "Вы действительно хотите удалить FAQ?", "TITLE": "Вы действительно хотите удалить FAQ?",
@@ -462,7 +462,7 @@
"ERROR_MESSAGE": "Произошла ошибка при удалении FAQ, попробуйте еще раз." "ERROR_MESSAGE": "Произошла ошибка при удалении FAQ, попробуйте еще раз."
}, },
"FILTER": { "FILTER": {
"ASSISTANT": "Помощник: {selected}", "ASSISTANT": "Ассистент: {selected}",
"STATUS": "Статус: {selected}", "STATUS": "Статус: {selected}",
"ALL_ASSISTANTS": "Все" "ALL_ASSISTANTS": "Все"
}, },
@@ -472,7 +472,7 @@
"APPROVED": "Одобрено", "APPROVED": "Одобрено",
"ALL": "Все" "ALL": "Все"
}, },
"FORM_DESCRIPTION": "Добавьте вопрос и соответствующий ему ответ в базу знаний и выберите помощника, с которым он должен связаться.", "FORM_DESCRIPTION": "Добавьте вопрос и соответствующий ему ответ в базу знаний и выберите ассистента, с которым он должен связаться.",
"CREATE": { "CREATE": {
"TITLE": "Добавить FAQ", "TITLE": "Добавить FAQ",
"SUCCESS_MESSAGE": "Ответ успешно добавлен.", "SUCCESS_MESSAGE": "Ответ успешно добавлен.",
@@ -487,59 +487,59 @@
"ANSWER": { "ANSWER": {
"LABEL": "Ответ", "LABEL": "Ответ",
"PLACEHOLDER": "Введите ответ", "PLACEHOLDER": "Введите ответ",
"ERROR": "Please provide a valid answer." "ERROR": "Пожалуйста, введите корректный ответ."
}, },
"ASSISTANT": { "ASSISTANT": {
"LABEL": "Помощник", "LABEL": "Ассистент",
"PLACEHOLDER": "Select an assistant", "PLACEHOLDER": "Выбрать ассистента",
"ERROR": "Please select an assistant." "ERROR": "Выбрать ассистента"
} }
}, },
"EDIT": { "EDIT": {
"TITLE": "Update the FAQ", "TITLE": "Обновить FAQ",
"SUCCESS_MESSAGE": "The FAQ has been successfully updated", "SUCCESS_MESSAGE": "FAQ успешно обновлён",
"ERROR_MESSAGE": "There was an error updating the FAQ, please try again", "ERROR_MESSAGE": "Произошла ошибка при обновлении FAQ, пожалуйста, попробуйте ещё раз",
"APPROVE_SUCCESS_MESSAGE": "The FAQ was marked as approved" "APPROVE_SUCCESS_MESSAGE": "FAQ был отмечен как одобренный"
}, },
"OPTIONS": { "OPTIONS": {
"APPROVE": "Mark as approved", "APPROVE": "Отметить как одобренный",
"EDIT_RESPONSE": "Edit FAQ", "EDIT_RESPONSE": "FAQ отмечен как одобренный",
"DELETE_RESPONSE": "Delete FAQ" "DELETE_RESPONSE": "Удалить FAQ"
}, },
"EMPTY_STATE": { "EMPTY_STATE": {
"TITLE": "No FAQs Found", "TITLE": "FAQ не найдены",
"SUBTITLE": "FAQs help your assistant provide quick and accurate answers to questions from your customers. They can be generated automatically from your content or can be added manually." "SUBTITLE": "FAQ помогают вашему ассистенту быстро и точно отвечать на вопросы клиентов. Их можно генерировать автоматически из вашего контента или добавлять вручную."
} }
}, },
"INBOXES": { "INBOXES": {
"HEADER": "Connected Inboxes", "HEADER": "Подключённые источники входящих",
"ADD_NEW": "Connect a new inbox", "ADD_NEW": "Подключить новый источник входящих",
"OPTIONS": { "OPTIONS": {
"DISCONNECT": "Отключиться" "DISCONNECT": "Отключиться"
}, },
"DELETE": { "DELETE": {
"TITLE": "Are you sure to disconnect the inbox?", "TITLE": "Вы уверены, что хотите отключить этот источник входящих?",
"DESCRIPTION": "", "DESCRIPTION": "",
"CONFIRM": "Да, удалить", "CONFIRM": "Да, удалить",
"SUCCESS_MESSAGE": "The inbox was successfully disconnected.", "SUCCESS_MESSAGE": "Источник входящих успешно отключён.",
"ERROR_MESSAGE": "There was an error disconnecting the inbox, please try again." "ERROR_MESSAGE": "Произошла ошибка при отключении источника входящих, пожалуйста, попробуйте ещё раз."
}, },
"FORM_DESCRIPTION": "Choose an inbox to connect with the assistant.", "FORM_DESCRIPTION": "Выберите источник входящих для подключения к ассистенту.",
"CREATE": { "CREATE": {
"TITLE": "Connect an Inbox", "TITLE": "Подключить источник входящих",
"SUCCESS_MESSAGE": "The inbox was successfully connected.", "SUCCESS_MESSAGE": "Источник входящих успешно подключён.",
"ERROR_MESSAGE": "An error occurred while connecting the inbox. Please try again." "ERROR_MESSAGE": "Произошла ошибка при подключении источника входящих. Пожалуйста, попробуйте ещё раз."
}, },
"FORM": { "FORM": {
"INBOX": { "INBOX": {
"LABEL": "Электронная почта", "LABEL": "Электронная почта",
"PLACEHOLDER": "Choose the inbox to deploy the assistant.", "PLACEHOLDER": "Выберите источник входящих для развертывания ассистента.",
"ERROR": "An inbox selection is required." "ERROR": "Необходимо выбрать источник входящих."
} }
}, },
"EMPTY_STATE": { "EMPTY_STATE": {
"TITLE": "No Connected Inboxes", "TITLE": "Нет подключённых источников входящих",
"SUBTITLE": "Connecting an inbox allows the assistant to handle initial questions from your customers before transferring them to you." "SUBTITLE": "Подключение источника входящих позволяет ассистенту обрабатывать первые вопросы ваших клиентов до их передачи вам."
} }
} }
} }
@@ -124,7 +124,7 @@
}, },
"AGENT_REPORTS": { "AGENT_REPORTS": {
"HEADER": "Обзор агентов", "HEADER": "Обзор агентов",
"DESCRIPTION": "Easily track agent performance with key metrics such as conversations, response times, resolution times, and resolved cases. Click an agent’s name to learn more.", "DESCRIPTION": "Легко отслеживайте эффективность работы агентов с помощью ключевых метрик, таких как количество бесед, время ответа, время решения проблем и количество решённых случаев. Нажмите на имя агента, чтобы узнать подробности.",
"LOADING_CHART": "Загрузка данных графика...", "LOADING_CHART": "Загрузка данных графика...",
"NO_ENOUGH_DATA": "Недостаточно данных для создания отчета, пожалуйста, повторите попытку позже.", "NO_ENOUGH_DATA": "Недостаточно данных для создания отчета, пожалуйста, повторите попытку позже.",
"DOWNLOAD_AGENT_REPORTS": "Сказать отчёт по агентам", "DOWNLOAD_AGENT_REPORTS": "Сказать отчёт по агентам",
@@ -259,7 +259,7 @@
}, },
"INBOX_REPORTS": { "INBOX_REPORTS": {
"HEADER": "Обзор входящих", "HEADER": "Обзор входящих",
"DESCRIPTION": "Quickly view your inbox performance with key metrics like conversations, response times, resolution times, and resolved cases—all in one place. Click an inbox name for more details.", "DESCRIPTION": "Быстро просматривайте эффективность источника входящих с основными метриками — количеством бесед, временем ответа, временем решения проблем и количеством решённых случаев — всё в одном месте. Нажмите на имя источника для получения подробной информации.",
"LOADING_CHART": "Загрузка данных графика...", "LOADING_CHART": "Загрузка данных графика...",
"NO_ENOUGH_DATA": "Недостаточно данных для создания отчета, пожалуйста, повторите попытку позже.", "NO_ENOUGH_DATA": "Недостаточно данных для создания отчета, пожалуйста, повторите попытку позже.",
"DOWNLOAD_INBOX_REPORTS": "Скачать отчет по входящим", "DOWNLOAD_INBOX_REPORTS": "Скачать отчет по входящим",
@@ -327,7 +327,7 @@
}, },
"TEAM_REPORTS": { "TEAM_REPORTS": {
"HEADER": "Обзор команды", "HEADER": "Обзор команды",
"DESCRIPTION": "Get a snapshot of your team’s performance with essential metrics, including conversations, response times, resolution times, and resolved cases. Click a team name for more details.", "DESCRIPTION": "Получите обзор работы вашей команды с основными метриками, такими как количество бесед, время ответа, время решения проблем и количество решённых случаев. Нажмите на имя команды для подробностей.",
"LOADING_CHART": "Загрузка данных графика...", "LOADING_CHART": "Загрузка данных графика...",
"NO_ENOUGH_DATA": "Недостаточно данных для создания отчета, пожалуйста, повторите попытку позже.", "NO_ENOUGH_DATA": "Недостаточно данных для создания отчета, пожалуйста, повторите попытку позже.",
"DOWNLOAD_TEAM_REPORTS": "Скачать отчет по команде", "DOWNLOAD_TEAM_REPORTS": "Скачать отчет по команде",
@@ -546,9 +546,9 @@
"INBOX": "Электронная почта", "INBOX": "Электронная почта",
"AGENT": "Оператор", "AGENT": "Оператор",
"TEAM": "Команда", "TEAM": "Команда",
"AVG_RESOLUTION_TIME": "Avg. Resolution Time", "AVG_RESOLUTION_TIME": "Среднее время решения",
"AVG_FIRST_RESPONSE_TIME": "Avg. First Response Time", "AVG_FIRST_RESPONSE_TIME": "Среднее время первого ответа",
"AVG_REPLY_TIME": "Avg. Customer Waiting Time", "AVG_REPLY_TIME": "Среднее время ожидания клиента",
"RESOLUTION_COUNT": "Количество завершенных", "RESOLUTION_COUNT": "Количество завершенных",
"CONVERSATIONS": "Количество диалогов" "CONVERSATIONS": "Количество диалогов"
} }
@@ -11,8 +11,8 @@
"CONVERSATIONS": "Диалоги", "CONVERSATIONS": "Диалоги",
"MESSAGES": "Сообщения" "MESSAGES": "Сообщения"
}, },
"VIEW_MORE": "View more", "VIEW_MORE": "Посмотреть больше",
"LOAD_MORE": "Load more", "LOAD_MORE": "Загрузить ещё",
"SEARCHING_DATA": "Идёт поиск", "SEARCHING_DATA": "Идёт поиск",
"LOADING_DATA": "Загрузка", "LOADING_DATA": "Загрузка",
"EMPTY_STATE": "Не найдено {item} для запроса '{query}'", "EMPTY_STATE": "Не найдено {item} для запроса '{query}'",
@@ -36,20 +36,20 @@
} }
}, },
"INTERFACE_SECTION": { "INTERFACE_SECTION": {
"TITLE": "Interface", "TITLE": "Интерфейс",
"NOTE": "Customize the look and feel of your Chatwoot dashboard.", "NOTE": "Настройте внешний вид и оформление вашей панели Chatwoot.",
"FONT_SIZE": { "FONT_SIZE": {
"TITLE": "Font size", "TITLE": "Размер шрифта",
"NOTE": "Adjust the text size across the dashboard based on your preference.", "NOTE": "Измените размер текста на всей панели в соответствии с вашими предпочтениями.",
"UPDATE_SUCCESS": "Your font settings have been updated successfully", "UPDATE_SUCCESS": "Настройки шрифта успешно обновлены",
"UPDATE_ERROR": "There is an error while updating the font settings, please try again", "UPDATE_ERROR": "Произошла ошибка при обновлении настроек шрифта, пожалуйста, попробуйте ещё раз",
"OPTIONS": { "OPTIONS": {
"SMALLER": "Smaller", "SMALLER": "Меньше",
"SMALL": "Small", "SMALL": "Маленький",
"DEFAULT": "По умолчанию", "DEFAULT": "По умолчанию",
"LARGE": "Large", "LARGE": "Большой",
"LARGER": "Larger", "LARGER": "Крупнее",
"EXTRA_LARGE": "Extra Large" "EXTRA_LARGE": "Очень большой"
} }
} }
}, },
@@ -162,7 +162,7 @@
"REQUEST_PUSH": "Включить push-уведомления", "REQUEST_PUSH": "Включить push-уведомления",
"SLA_MISSED_FIRST_RESPONSE": "Отправить push-уведомление, если диалог не соответствует SLA первого ответа", "SLA_MISSED_FIRST_RESPONSE": "Отправить push-уведомление, если диалог не соответствует SLA первого ответа",
"SLA_MISSED_NEXT_RESPONSE": "Отправить push-уведомление, если диалог не успел получить следующий ответ SLA", "SLA_MISSED_NEXT_RESPONSE": "Отправить push-уведомление, если диалог не успел получить следующий ответ SLA",
"SLA_MISSED_RESOLUTION": "Отправить push-уведомление, если диалог не соответствует уровню разрешения SLA" "SLA_MISSED_RESOLUTION": "Отправить push-уведомление, если диалог не соответствует SLA"
}, },
"PROFILE_IMAGE": { "PROFILE_IMAGE": {
"LABEL": "Изображение профиля" "LABEL": "Изображение профиля"
@@ -281,9 +281,9 @@
"SETTINGS": "Настройки", "SETTINGS": "Настройки",
"CONTACTS": "Контакты", "CONTACTS": "Контакты",
"CAPTAIN": "Капитан", "CAPTAIN": "Капитан",
"CAPTAIN_ASSISTANTS": "Помощники", "CAPTAIN_ASSISTANTS": "Ассистенты",
"CAPTAIN_DOCUMENTS": "Документы", "CAPTAIN_DOCUMENTS": "Документы",
"CAPTAIN_RESPONSES": "FAQs", "CAPTAIN_RESPONSES": "FAQ",
"HOME": "Главная", "HOME": "Главная",
"AGENTS": "Операторы", "AGENTS": "Операторы",
"AGENT_BOTS": "Боты", "AGENT_BOTS": "Боты",
@@ -345,14 +345,14 @@
}, },
"BILLING_SETTINGS": { "BILLING_SETTINGS": {
"TITLE": "Платёж", "TITLE": "Платёж",
"DESCRIPTION": "Manage your subscription here, upgrade your plan and get more for your team.", "DESCRIPTION": "Управляйте подпиской здесь, обновите тарифный план и получите больше возможностей для вашей команды.",
"CURRENT_PLAN": { "CURRENT_PLAN": {
"TITLE": "Текущий план", "TITLE": "Текущий план",
"PLAN_NOTE": "На данный момент вы подписаны на ** план{plan}** с **{quantity}** лицензиями", "PLAN_NOTE": "На данный момент вы подписаны на ** план{plan}** с **{quantity}** лицензиями",
"SEAT_COUNT": "Number of seats", "SEAT_COUNT": "Количество мест",
"RENEWS_ON": "Renews on" "RENEWS_ON": "Продление"
}, },
"VIEW_PRICING": "View Pricing", "VIEW_PRICING": "Посмотреть цены",
"MANAGE_SUBSCRIPTION": { "MANAGE_SUBSCRIPTION": {
"TITLE": "Управление подпиской", "TITLE": "Управление подпиской",
"DESCRIPTION": "Просматривайте ваши предыдущие счета, редактируйте платежные реквизиты или отмените подписку.", "DESCRIPTION": "Просматривайте ваши предыдущие счета, редактируйте платежные реквизиты или отмените подписку.",
@@ -360,11 +360,11 @@
}, },
"CAPTAIN": { "CAPTAIN": {
"TITLE": "Капитан", "TITLE": "Капитан",
"DESCRIPTION": "Manage usage and credits for Captain AI.", "DESCRIPTION": "Управляйте использованием и кредитами для Captain AI.",
"BUTTON_TXT": "Buy more credits", "BUTTON_TXT": "Купить дополнительные кредиты",
"DOCUMENTS": "Документы", "DOCUMENTS": "Документы",
"RESPONSES": "Responses", "RESPONSES": "Ответы",
"UPGRADE": "Captain is not available on the free plan, upgrade now to get access to assistants, copilot and more." "UPGRADE": "Captain недоступен в бесплатном тарифном плане, обновите его, чтобы получить доступ к ассистентам, copilot и другим функциям."
}, },
"CHAT_WITH_US": { "CHAT_WITH_US": {
"TITLE": "Нужна помощь?", "TITLE": "Нужна помощь?",
@@ -3,13 +3,12 @@ import { mapGetters } from 'vuex';
import { defineAsyncComponent } from 'vue'; import { defineAsyncComponent } from 'vue';
import NextSidebar from 'next/sidebar/Sidebar.vue'; import NextSidebar from 'next/sidebar/Sidebar.vue';
import Sidebar from '../../components/layout/Sidebar.vue';
import WootKeyShortcutModal from 'dashboard/components/widgets/modal/WootKeyShortcutModal.vue'; import WootKeyShortcutModal from 'dashboard/components/widgets/modal/WootKeyShortcutModal.vue';
import AddAccountModal from 'dashboard/components/layout/sidebarComponents/AddAccountModal.vue'; import AddAccountModal from 'dashboard/components/layout/sidebarComponents/AddAccountModal.vue';
import AccountSelector from 'dashboard/components/layout/sidebarComponents/AccountSelector.vue'; import AccountSelector from 'dashboard/components/layout/sidebarComponents/AccountSelector.vue';
import AddLabelModal from 'dashboard/routes/dashboard/settings/labels/AddLabel.vue'; import AddLabelModal from 'dashboard/routes/dashboard/settings/labels/AddLabel.vue';
import NotificationPanel from 'dashboard/routes/dashboard/notifications/components/NotificationPanel.vue'; import NotificationPanel from 'dashboard/routes/dashboard/notifications/components/NotificationPanel.vue';
import PaymentPaywall from 'dashboard/components/app/PaymentPaywall.vue';
import { useUISettings } from 'dashboard/composables/useUISettings'; import { useUISettings } from 'dashboard/composables/useUISettings';
import { useAccount } from 'dashboard/composables/useAccount'; import { useAccount } from 'dashboard/composables/useAccount';
@@ -20,6 +19,10 @@ import { FEATURE_FLAGS } from 'dashboard/featureFlags';
const CommandBar = defineAsyncComponent( const CommandBar = defineAsyncComponent(
() => import('./commands/commandbar.vue') () => import('./commands/commandbar.vue')
); );
const Sidebar = defineAsyncComponent(
() => import('../../components/layout/Sidebar.vue')
);
import { emitter } from 'shared/helpers/mitt'; import { emitter } from 'shared/helpers/mitt';
export default { export default {
@@ -29,7 +32,6 @@ export default {
CommandBar, CommandBar,
WootKeyShortcutModal, WootKeyShortcutModal,
AddAccountModal, AddAccountModal,
PaymentPaywall,
AccountSelector, AccountSelector,
AddLabelModal, AddLabelModal,
NotificationPanel, NotificationPanel,
@@ -195,9 +197,7 @@ export default {
@show-add-label-popup="showAddLabelPopup" @show-add-label-popup="showAddLabelPopup"
/> />
<main class="flex flex-1 h-full min-h-0 px-0 overflow-hidden"> <main class="flex flex-1 h-full min-h-0 px-0 overflow-hidden">
<PaymentPaywall> <router-view />
<router-view />
</PaymentPaywall>
<CommandBar /> <CommandBar />
<AccountSelector <AccountSelector
:show-account-modal="showAccountModal" :show-account-modal="showAccountModal"
@@ -121,8 +121,6 @@ export default {
this.isALineChannel || this.isALineChannel ||
this.isAPIInbox || this.isAPIInbox ||
(this.isAnEmailChannel && !this.inbox.provider) || (this.isAnEmailChannel && !this.inbox.provider) ||
this.isAMicrosoftInbox ||
this.isAGoogleInbox ||
this.isAWhatsAppChannel || this.isAWhatsAppChannel ||
this.isAWebWidgetInbox this.isAWebWidgetInbox
) { ) {
@@ -39,13 +39,14 @@ export default {
}, },
mixins: [globalConfigMixin], mixins: [globalConfigMixin],
setup() { setup() {
const { isEditorHotKeyEnabled } = useUISettings(); const { isEditorHotKeyEnabled, updateUISettings } = useUISettings();
const { currentFontSize, updateFontSize } = useFontSize(); const { currentFontSize, updateFontSize } = useFontSize();
return { return {
currentFontSize, currentFontSize,
updateFontSize, updateFontSize,
isEditorHotKeyEnabled, isEditorHotKeyEnabled,
updateUISettings,
}; };
}, },
data() { data() {
@@ -23,7 +23,6 @@ const state = {
export const getters = { export const getters = {
getAccount: $state => id => { getAccount: $state => id => {
console.log('account', id);
return findRecordById($state, id); return findRecordById($state, id);
}, },
getUIFlags($state) { getUIFlags($state) {
@@ -79,10 +79,10 @@ class BaseActionCableConnector {
this.consumer.disconnect(); this.consumer.disconnect();
} }
onReceived = ({ event, data } = {}) => { onReceived = ({ event, data, event_timestamp } = {}) => {
if (this.isAValidEvent(data)) { if (this.isAValidEvent(data)) {
if (this.events[event] && typeof this.events[event] === 'function') { if (this.events[event] && typeof this.events[event] === 'function') {
this.events[event](data); this.events[event](data, event_timestamp);
} }
} }
}; };
+8 -4
View File
@@ -10,11 +10,11 @@ class ActionCableBroadcastJob < ApplicationJob
CONVERSATION_STATUS_CHANGED CONVERSATION_STATUS_CHANGED
].freeze ].freeze
def perform(members, event_name, data) def perform(members, event_name, data, event_timestamp)
return if members.blank? return if members.blank?
broadcast_data = prepare_broadcast_data(event_name, data) broadcast_data = prepare_broadcast_data(event_name, data)
broadcast_to_members(members, event_name, broadcast_data) broadcast_to_members(members, event_name, broadcast_data, event_timestamp)
end end
private private
@@ -30,13 +30,17 @@ class ActionCableBroadcastJob < ApplicationJob
conversation.push_event_data.merge(account_id: data[:account_id]) conversation.push_event_data.merge(account_id: data[:account_id])
end end
def broadcast_to_members(members, event_name, broadcast_data) # A timestamp is added to the broadcast data, this timestamp is
# generated in the main app thread when the job is enqueued.
# This is used as a "sequence number" to ensure we ignore out of order events
def broadcast_to_members(members, event_name, broadcast_data, event_timestamp)
members.each do |member| members.each do |member|
ActionCable.server.broadcast( ActionCable.server.broadcast(
member, member,
{ {
event: event_name, event: event_name,
data: broadcast_data data: broadcast_data,
event_timestamp: event_timestamp
} }
) )
end end
@@ -2,8 +2,15 @@ class Inboxes::FetchImapEmailInboxesJob < ApplicationJob
queue_as :scheduled_jobs queue_as :scheduled_jobs
def perform def perform
Inbox.where(channel_type: 'Channel::Email').all.find_each(batch_size: 100) do |inbox| email_inboxes = Inbox.where(channel_type: 'Channel::Email')
::Inboxes::FetchImapEmailsJob.perform_later(inbox.channel) if inbox.channel.imap_enabled email_inboxes.find_each(batch_size: 100) do |inbox|
::Inboxes::FetchImapEmailsJob.perform_later(inbox.channel) if should_fetch_emails?(inbox)
end end
end end
private
def should_fetch_emails?(inbox)
inbox.channel.imap_enabled && !inbox.account.suspended?
end
end end
+12 -7
View File
@@ -58,7 +58,8 @@ class ActionCableListener < BaseListener
conversation, account = extract_conversation_and_account(event) conversation, account = extract_conversation_and_account(event)
tokens = user_tokens(account, conversation.inbox.members) + contact_inbox_tokens(conversation.contact_inbox) tokens = user_tokens(account, conversation.inbox.members) + contact_inbox_tokens(conversation.contact_inbox)
broadcast(account, tokens, CONVERSATION_CREATED, conversation.push_event_data) # Include the original event timestamp to ensure correct ordering on frontend
broadcast(account, tokens, CONVERSATION_CREATED, conversation.push_event_data, event.timestamp.to_f)
end end
def conversation_read(event) def conversation_read(event)
@@ -72,14 +73,16 @@ class ActionCableListener < BaseListener
conversation, account = extract_conversation_and_account(event) conversation, account = extract_conversation_and_account(event)
tokens = user_tokens(account, conversation.inbox.members) + contact_inbox_tokens(conversation.contact_inbox) tokens = user_tokens(account, conversation.inbox.members) + contact_inbox_tokens(conversation.contact_inbox)
broadcast(account, tokens, CONVERSATION_STATUS_CHANGED, conversation.push_event_data) # Include the original event timestamp to ensure correct ordering on frontend
broadcast(account, tokens, CONVERSATION_STATUS_CHANGED, conversation.push_event_data, event.timestamp.to_f)
end end
def conversation_updated(event) def conversation_updated(event)
conversation, account = extract_conversation_and_account(event) conversation, account = extract_conversation_and_account(event)
tokens = user_tokens(account, conversation.inbox.members) + contact_inbox_tokens(conversation.contact_inbox) tokens = user_tokens(account, conversation.inbox.members) + contact_inbox_tokens(conversation.contact_inbox)
broadcast(account, tokens, CONVERSATION_UPDATED, conversation.push_event_data) # Include the original event timestamp to ensure correct ordering on frontend
broadcast(account, tokens, CONVERSATION_UPDATED, conversation.push_event_data, event.timestamp.to_f)
end end
def conversation_typing_on(event) def conversation_typing_on(event)
@@ -118,14 +121,16 @@ class ActionCableListener < BaseListener
conversation, account = extract_conversation_and_account(event) conversation, account = extract_conversation_and_account(event)
tokens = user_tokens(account, conversation.inbox.members) tokens = user_tokens(account, conversation.inbox.members)
broadcast(account, tokens, ASSIGNEE_CHANGED, conversation.push_event_data) # Include the original event timestamp to ensure correct ordering on frontend
broadcast(account, tokens, ASSIGNEE_CHANGED, conversation.push_event_data, event.timestamp.to_f)
end end
def team_changed(event) def team_changed(event)
conversation, account = extract_conversation_and_account(event) conversation, account = extract_conversation_and_account(event)
tokens = user_tokens(account, conversation.inbox.members) tokens = user_tokens(account, conversation.inbox.members)
broadcast(account, tokens, TEAM_CHANGED, conversation.push_event_data) # Include the original event timestamp to ensure correct ordering on frontend
broadcast(account, tokens, TEAM_CHANGED, conversation.push_event_data, event.timestamp.to_f)
end end
def conversation_contact_changed(event) def conversation_contact_changed(event)
@@ -197,7 +202,7 @@ class ActionCableListener < BaseListener
contact_inbox.hmac_verified? ? contact.contact_inboxes.where(hmac_verified: true).filter_map(&:pubsub_token) : [contact_inbox.pubsub_token] contact_inbox.hmac_verified? ? contact.contact_inboxes.where(hmac_verified: true).filter_map(&:pubsub_token) : [contact_inbox.pubsub_token]
end end
def broadcast(account, tokens, event_name, data) def broadcast(account, tokens, event_name, data, event_timestamp = nil)
return if tokens.blank? return if tokens.blank?
payload = data.merge(account_id: account.id) payload = data.merge(account_id: account.id)
@@ -205,6 +210,6 @@ class ActionCableListener < BaseListener
# Useful in cases like conversation assignment for generating a notification with assigner name. # Useful in cases like conversation assignment for generating a notification with assigner name.
payload[:performer] = Current.user&.push_event_data if Current.user.present? payload[:performer] = Current.user&.push_event_data if Current.user.present?
::ActionCableBroadcastJob.perform_later(tokens.uniq, event_name, payload) ::ActionCableBroadcastJob.perform_later(tokens.uniq, event_name, payload, event_timestamp)
end end
end end
+18 -3
View File
@@ -37,7 +37,7 @@ class Channel::Sms < ApplicationRecord
body = message_body(contact_number, message.content) body = message_body(contact_number, message.content)
body['media'] = message.attachments.map(&:download_url) if message.attachments.present? body['media'] = message.attachments.map(&:download_url) if message.attachments.present?
send_to_bandwidth(body) send_to_bandwidth(body, message)
end end
def send_text_message(contact_number, message_content) def send_text_message(contact_number, message_content)
@@ -56,7 +56,7 @@ class Channel::Sms < ApplicationRecord
} }
end end
def send_to_bandwidth(body) def send_to_bandwidth(body, message = nil)
response = HTTParty.post( response = HTTParty.post(
"#{api_base_path}/users/#{provider_config['account_id']}/messages", "#{api_base_path}/users/#{provider_config['account_id']}/messages",
basic_auth: bandwidth_auth, basic_auth: bandwidth_auth,
@@ -64,7 +64,22 @@ class Channel::Sms < ApplicationRecord
body: body.to_json body: body.to_json
) )
response.success? ? response.parsed_response['id'] : nil if response.success?
response.parsed_response['id']
else
handle_error(response, message)
nil
end
end
def handle_error(response, message)
Rails.logger.error("[#{account_id}] Error sending SMS: #{response.parsed_response['description']}")
return if message.blank?
# https://dev.bandwidth.com/apis/messaging-apis/messaging/#tag/Messages/operation/createMessage
message.external_error = response.parsed_response['description']
message.status = :failed
message.save!
end end
def bandwidth_auth def bandwidth_auth
@@ -20,15 +20,30 @@ class Facebook::SendOnFacebookService < Base::SendOnChannelService
end end
def send_message_to_facebook(delivery_params) def send_message_to_facebook(delivery_params)
result = Facebook::Messenger::Bot.deliver(delivery_params, page_id: channel.page_id) parsed_result = deliver_message(delivery_params)
parsed_result = JSON.parse(result) return if parsed_result.nil?
if parsed_result['error'].present? if parsed_result['error'].present?
message.update!(status: :failed, external_error: external_error(parsed_result)) message.update!(status: :failed, external_error: external_error(parsed_result))
Rails.logger.info "Facebook::SendOnFacebookService: Error sending message to Facebook : Page - #{channel.page_id} : #{result}" Rails.logger.info "Facebook::SendOnFacebookService: Error sending message to Facebook : Page - #{channel.page_id} : #{parsed_result}"
end end
message.update!(source_id: parsed_result['message_id']) if parsed_result['message_id'].present? message.update!(source_id: parsed_result['message_id']) if parsed_result['message_id'].present?
end end
def deliver_message(delivery_params)
result = Facebook::Messenger::Bot.deliver(delivery_params, page_id: channel.page_id)
JSON.parse(result)
rescue JSON::ParserError
message.update!(status: :failed, external_error: 'Facebook was unable to process this request')
Rails.logger.error "Facebook::SendOnFacebookService: Error parsing JSON response from Facebook : Page - #{channel.page_id} : #{result}"
nil
rescue Net::OpenTimeout
message.update!(status: :failed, external_error: 'Request timed out, please try again later')
Rails.logger.error "Facebook::SendOnFacebookService: Timeout error sending message to Facebook : Page - #{channel.page_id}"
nil
end
def fb_text_message_params def fb_text_message_params
{ {
recipient: { id: contact.get_source_id(inbox.id) }, recipient: { id: contact.get_source_id(inbox.id) },
@@ -70,22 +70,28 @@ class Instagram::SendOnInstagramService < Base::SendOnChannelService
query: query query: query
) )
if response[:error].present? handle_response(response, message_content)
Rails.logger.error("Instagram response: #{response['error']} : #{message_content}") end
message.status = :failed
message.external_error = external_error(response) def handle_response(response, message_content)
parsed_response = response.parsed_response
if response.success? && parsed_response['error'].blank?
message.update!(source_id: parsed_response['message_id'])
parsed_response
else
external_error = external_error(parsed_response)
Rails.logger.error("Instagram response: #{external_error} : #{message_content}")
message.update!(status: :failed, external_error: external_error)
nil
end end
message.source_id = response['message_id'] if response['message_id'].present?
message.save!
response
end end
def external_error(response) def external_error(response)
# https://developers.facebook.com/docs/instagram-api/reference/error-codes/ # https://developers.facebook.com/docs/instagram-api/reference/error-codes/
error_message = response[:error][:message] error_message = response.dig('error', 'message')
error_code = response[:error][:code] error_code = response.dig('error', 'code')
"#{error_code} - #{error_message}" "#{error_code} - #{error_message}"
end end
@@ -27,6 +27,33 @@ class Whatsapp::Providers::BaseService
raise 'Overwrite this method in child class' raise 'Overwrite this method in child class'
end end
def error_message
raise 'Overwrite this method in child class'
end
def process_response(response)
parsed_response = response.parsed_response
if response.success? && parsed_response['error'].blank?
parsed_response['messages'].first['id']
else
handle_error(response)
nil
end
end
def handle_error(response)
Rails.logger.error response.body
return if @message.blank?
# https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes/#sample-response
error_message = error_message(response)
return if error_message.blank?
@message.external_error = error_message
@message.status = :failed
@message.save!
end
def create_buttons(items) def create_buttons(items)
buttons = [] buttons = []
items.each do |item| items.each do |item|
@@ -1,5 +1,6 @@
class Whatsapp::Providers::Whatsapp360DialogService < Whatsapp::Providers::BaseService class Whatsapp::Providers::Whatsapp360DialogService < Whatsapp::Providers::BaseService
def send_message(phone_number, message) def send_message(phone_number, message)
@message = message
if message.attachments.present? if message.attachments.present?
send_attachment_message(phone_number, message) send_attachment_message(phone_number, message)
elsif message.content_type == 'input_select' elsif message.content_type == 'input_select'
@@ -78,6 +79,7 @@ class Whatsapp::Providers::Whatsapp360DialogService < Whatsapp::Providers::BaseS
} }
type_content['caption'] = message.content unless %w[audio sticker].include?(type) type_content['caption'] = message.content unless %w[audio sticker].include?(type)
type_content['filename'] = attachment.file.filename if type == 'document' type_content['filename'] = attachment.file.filename if type == 'document'
response = HTTParty.post( response = HTTParty.post(
"#{api_base_path}/messages", "#{api_base_path}/messages",
headers: api_headers, headers: api_headers,
@@ -91,13 +93,9 @@ class Whatsapp::Providers::Whatsapp360DialogService < Whatsapp::Providers::BaseS
process_response(response) process_response(response)
end end
def process_response(response) def error_message(response)
if response.success? # {"meta": {"success": false, "http_code": 400, "developer_message": "errro-message", "360dialog_trace_id": "someid"}}
response['messages'].first['id'] response.parsed_response.dig('meta', 'developer_message')
else
Rails.logger.error response.body
nil
end
end end
def template_body_parameters(template_info) def template_body_parameters(template_info)
@@ -1,5 +1,7 @@
class Whatsapp::Providers::WhatsappCloudService < Whatsapp::Providers::BaseService class Whatsapp::Providers::WhatsappCloudService < Whatsapp::Providers::BaseService
def send_message(phone_number, message) def send_message(phone_number, message)
@message = message
if message.attachments.present? if message.attachments.present?
send_attachment_message(phone_number, message) send_attachment_message(phone_number, message)
elsif message.content_type == 'input_select' elsif message.content_type == 'input_select'
@@ -111,13 +113,9 @@ class Whatsapp::Providers::WhatsappCloudService < Whatsapp::Providers::BaseServi
process_response(response) process_response(response)
end end
def process_response(response) def error_message(response)
if response.success? # https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes/#sample-response
response['messages'].first['id'] response.parsed_response&.dig('error', 'message')
else
Rails.logger.error response.body
nil
end
end end
def template_body_parameters(template_info) def template_body_parameters(template_info)
@@ -1,3 +1,7 @@
json.meta do
json.total_count @attachments_count
end
json.payload @attachments do |attachment| json.payload @attachments do |attachment|
json.message_id attachment.push_event_data[:message_id] json.message_id attachment.push_event_data[:message_id]
json.thumb_url attachment.push_event_data[:thumb_url] json.thumb_url attachment.push_event_data[:thumb_url]
+2
View File
@@ -68,6 +68,8 @@ am:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ ar:
invalid_operator: مشغل غير صالح. المشغل المسموح به لـ %{attribute_name} هو [%{allowed_keys}]. invalid_operator: مشغل غير صالح. المشغل المسموح به لـ %{attribute_name} هو [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: قيمة غير صالحة. القيم المقدمة ل %{attribute_name} غير صالحة invalid_value: قيمة غير صالحة. القيم المقدمة ل %{attribute_name} غير صالحة
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: فترة التبليغ %{since} إلى %{until} period: فترة التبليغ %{since} إلى %{until}
utc_warning: التقرير الذي تم إنشاؤه في التوقيت العالمي الموحّد utc_warning: التقرير الذي تم إنشاؤه في التوقيت العالمي الموحّد
+2
View File
@@ -68,6 +68,8 @@ az:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ bg:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ ca:
invalid_operator: Operador no vàlid. Els operadors permesos per a %{attribute_name} son [%{allowed_keys}]. invalid_operator: Operador no vàlid. Els operadors permesos per a %{attribute_name} son [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Valor no vàlid. Els valors proporcionats per a %{attribute_name} no són vàlids invalid_value: Valor no vàlid. Els valors proporcionats per a %{attribute_name} no són vàlids
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Període d'informes %{since} a %{until} period: Període d'informes %{since} a %{until}
utc_warning: L'informe generat es troba a la zona horària UTC utc_warning: L'informe generat es troba a la zona horària UTC
+2
View File
@@ -68,6 +68,8 @@ cs:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ da:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Rapporteringsperiode %{since} til %{until} period: Rapporteringsperiode %{since} til %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ de:
invalid_operator: Ungültiger Operator. Die erlaubten Operatoren für %{attribute_name} sind [%{allowed_keys}]. invalid_operator: Ungültiger Operator. Die erlaubten Operatoren für %{attribute_name} sind [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Ungültiger Wert. Die Werte für %{attribute_name} sind ungültig invalid_value: Ungültiger Wert. Die Werte für %{attribute_name} sind ungültig
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Berichtszeitraum von %{since} bis %{until} period: Berichtszeitraum von %{since} bis %{until}
utc_warning: Der generierte Bericht ist in UTC-Zeitzone utc_warning: Der generierte Bericht ist in UTC-Zeitzone
+2
View File
@@ -68,6 +68,8 @@ el:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Περίοδος αναφοράς %{since} έως %{until} period: Περίοδος αναφοράς %{since} έως %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ es:
invalid_operator: Operador no válido. Los operadores permitidos para %{attribute_name} son [%{allowed_keys}]. invalid_operator: Operador no válido. Los operadores permitidos para %{attribute_name} son [%{allowed_keys}].
invalid_query_operator: El operador de consulta debe ser "Y" o "O". invalid_query_operator: El operador de consulta debe ser "Y" o "O".
invalid_value: Valor no válido. Los valores proporcionados para %{attribute_name} no son válidos invalid_value: Valor no válido. Los valores proporcionados para %{attribute_name} no son válidos
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reportando el periodo desde %{since} hasta %{until} period: Reportando el periodo desde %{since} hasta %{until}
utc_warning: El informe generado está en zona horaria UTC utc_warning: El informe generado está en zona horaria UTC
+2
View File
@@ -68,6 +68,8 @@ fa:
invalid_operator: این عملیات مجاز نیست. عملیات های مجاز برای %{attribute_name} شامل %{allowed_keys} می باشد. invalid_operator: این عملیات مجاز نیست. عملیات های مجاز برای %{attribute_name} شامل %{allowed_keys} می باشد.
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: مقدار معتبر نیست. مقادیر ارائه شده برای %{attribute_name} معتبر نیست invalid_value: مقدار معتبر نیست. مقادیر ارائه شده برای %{attribute_name} معتبر نیست
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: زمان گزارش از %{since} تا %{until} period: زمان گزارش از %{since} تا %{until}
utc_warning: گزارش تولید شده در منطقه زمانی UTC است utc_warning: گزارش تولید شده در منطقه زمانی UTC است
+2
View File
@@ -68,6 +68,8 @@ fi:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Raportointijakso %{since} – %{until} period: Raportointijakso %{since} – %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ fr:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Période de rapport %{since} à %{until} period: Période de rapport %{since} à %{until}
utc_warning: Le rapport généré est dans le fuseau horaire UTC utc_warning: Le rapport généré est dans le fuseau horaire UTC
+2
View File
@@ -68,6 +68,8 @@ he:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ hi:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ hr:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ hu:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Jelentési időszak %{since}-tól %{until}-ig period: Jelentési időszak %{since}-tól %{until}-ig
utc_warning: A generált riport UTC időzónát használ utc_warning: A generált riport UTC időzónát használ
+2
View File
@@ -68,6 +68,8 @@ hy:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ id:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Periode pelaporan %{since} hingga %{until} period: Periode pelaporan %{since} hingga %{until}
utc_warning: Laporan yang dihasilkan berada dalam zona waktu UTC utc_warning: Laporan yang dihasilkan berada dalam zona waktu UTC
+2
View File
@@ -68,6 +68,8 @@ is:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ it:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Periodo di segnalazione da %{since} a %{until} period: Periodo di segnalazione da %{since} a %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ ja:
invalid_operator: 無効な演算子です。%{attribute_name} に許可されている演算子は [%{allowed_keys}] です。 invalid_operator: 無効な演算子です。%{attribute_name} に許可されている演算子は [%{allowed_keys}] です。
invalid_query_operator: クエリ演算子は "AND" または "OR" でなければなりません。 invalid_query_operator: クエリ演算子は "AND" または "OR" でなければなりません。
invalid_value: 無効な値です。%{attribute_name} に提供された値は無効です。 invalid_value: 無効な値です。%{attribute_name} に提供された値は無効です。
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: レポート期間 %{since} から %{until} まで period: レポート期間 %{since} から %{until} まで
utc_warning: 生成されたレポートはUTCタイムゾーンです utc_warning: 生成されたレポートはUTCタイムゾーンです
+2
View File
@@ -68,6 +68,8 @@ ka:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ ko:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: 보고 기간 %{since} - %{until} period: 보고 기간 %{since} - %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ lt:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Ataskaitinis laikotarpis nuo %{since} iki %{until} period: Ataskaitinis laikotarpis nuo %{since} iki %{until}
utc_warning: Sugeneruota ataskaita yra UTC laiko juostoje utc_warning: Sugeneruota ataskaita yra UTC laiko juostoje
+2
View File
@@ -68,6 +68,8 @@ lv:
invalid_operator: Nederīgs operators. Atļautie operatori priekš %{attribute_name} ir [%{allowed_keys}]. invalid_operator: Nederīgs operators. Atļautie operatori priekš %{attribute_name} ir [%{allowed_keys}].
invalid_query_operator: Vaicājuma operatoram ir jābūt "UN" vai "VAI". invalid_query_operator: Vaicājuma operatoram ir jābūt "UN" vai "VAI".
invalid_value: Nederīga vērtība. Norādītās vērtības priekš %{attribute_name} nav derīgas invalid_value: Nederīga vērtība. Norādītās vērtības priekš %{attribute_name} nav derīgas
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Ziņošanas periods %{since} līdz %{until} period: Ziņošanas periods %{since} līdz %{until}
utc_warning: Izveidotais pārskats atbilst UTC laika joslai utc_warning: Izveidotais pārskats atbilst UTC laika joslai
+2
View File
@@ -68,6 +68,8 @@ ml:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ ms:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ ne:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ nl:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Rapportering van %{since} tot %{until} period: Rapportering van %{since} tot %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@
invalid_operator: Ugyldig operatør. De tillatte operatørene for %{attribute_name} er [%{allowed_keys}]. invalid_operator: Ugyldig operatør. De tillatte operatørene for %{attribute_name} er [%{allowed_keys}].
invalid_query_operator: Spørrings-operatør må være enten "AND" eller "OR". invalid_query_operator: Spørrings-operatør må være enten "AND" eller "OR".
invalid_value: Ugyldig verdi. Verdiene angitt for %{attribute_name} er ugyldige invalid_value: Ugyldig verdi. Verdiene angitt for %{attribute_name} er ugyldige
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Rapporteringsperiode %{since} til %{until} period: Rapporteringsperiode %{since} til %{until}
utc_warning: Rapporten generert er i UTC tidssone utc_warning: Rapporten generert er i UTC tidssone
+2
View File
@@ -68,6 +68,8 @@ pl:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Okres raportowania od %{since} do %{until} period: Okres raportowania od %{since} do %{until}
utc_warning: Generowany raport jest w strefie czasowej UTC utc_warning: Generowany raport jest w strefie czasowej UTC
+2
View File
@@ -68,6 +68,8 @@ pt:
invalid_operator: Operador inválido. Os operadores permitidos para %{attribute_name} são [%{allowed_keys}]. invalid_operator: Operador inválido. Os operadores permitidos para %{attribute_name} são [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Valor inválido. Os valores fornecidos para %{attribute_name} são inválidos invalid_value: Valor inválido. Os valores fornecidos para %{attribute_name} são inválidos
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Período do relatório de %{since} a %{until} period: Período do relatório de %{since} a %{until}
utc_warning: O relatório gerado está no fuso horário UTC utc_warning: O relatório gerado está no fuso horário UTC
+3 -1
View File
@@ -68,6 +68,8 @@ pt_BR:
invalid_operator: Operador inválido. Os operadores permitidos para %{attribute_name} são [%{allowed_keys}]. invalid_operator: Operador inválido. Os operadores permitidos para %{attribute_name} são [%{allowed_keys}].
invalid_query_operator: Operador de consulta deve ser "E" ou "OU". invalid_query_operator: Operador de consulta deve ser "E" ou "OU".
invalid_value: Valor inválido. Os valores fornecidos para %{attribute_name} são inválidos invalid_value: Valor inválido. Os valores fornecidos para %{attribute_name} são inválidos
custom_attribute_definition:
key_conflict: A chave fornecida não é permitida pois pode entrar em conflito com os atributos padrão.
reports: reports:
period: Reportando o período %{since} a %{until} period: Reportando o período %{since} a %{until}
utc_warning: O relatório gerado está em fuso horário UTC utc_warning: O relatório gerado está em fuso horário UTC
@@ -133,7 +135,7 @@ pt_BR:
messages: messages:
instagram_story_content: '%{story_sender} mencionou você na conversa: ' instagram_story_content: '%{story_sender} mencionou você na conversa: '
instagram_deleted_story_content: Este Story não está mais disponível. instagram_deleted_story_content: Este Story não está mais disponível.
deleted: Esta mensagem foi apagada deleted: Esta mensagem foi excluída
delivery_status: delivery_status:
error_code: 'Código de erro: %{error_code}' error_code: 'Código de erro: %{error_code}'
activity: activity:
+2
View File
@@ -68,6 +68,8 @@ ro:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Perioada de raportare %{since}-%{until} period: Perioada de raportare %{since}-%{until}
utc_warning: Raportul generat este în fusul orar UTC utc_warning: Raportul generat este în fusul orar UTC
+5 -3
View File
@@ -68,6 +68,8 @@ ru:
invalid_operator: Неверный оператор. Допустимыми операторами для %{attribute_name} являются [%{allowed_keys}]. invalid_operator: Неверный оператор. Допустимыми операторами для %{attribute_name} являются [%{allowed_keys}].
invalid_query_operator: Оператор запроса должен быть "AND" или "OR". invalid_query_operator: Оператор запроса должен быть "AND" или "OR".
invalid_value: Недопустимое значение. Значения, предоставленные для %{attribute_name} являются недопустимыми invalid_value: Недопустимое значение. Значения, предоставленные для %{attribute_name} являются недопустимыми
custom_attribute_definition:
key_conflict: Предоставленный ключ не разрешён, так как он может конфликтовать со стандартными атрибутами.
reports: reports:
period: Отчётный период с %{since} по %{until} period: Отчётный период с %{since} по %{until}
utc_warning: Отчёт создан в часовом поясе UTC utc_warning: Отчёт создан в часовом поясе UTC
@@ -165,7 +167,7 @@ ru:
removed: '%{user_name} удалил политику SLA %{sla_name}' removed: '%{user_name} удалил политику SLA %{sla_name}'
muted: '%{user_name} заглушил(а) этот разговор' muted: '%{user_name} заглушил(а) этот разговор'
unmuted: '%{user_name} включил(а) уведомления для разговора' unmuted: '%{user_name} включил(а) уведомления для разговора'
auto_resolution_message: 'Resolving the conversation as it has been inactive for a while. Please start a new conversation if you need further assistance.' auto_resolution_message: 'Разговор закрывается, поскольку он был неактивен в течение длительного времени. Пожалуйста, начните новый разговор, если потребуется дополнительная помощь.'
templates: templates:
greeting_message_body: '%{account_name} как правило отвечает в течении несколько часов.' greeting_message_body: '%{account_name} как правило отвечает в течении несколько часов.'
ways_to_reach_you_message_body: 'Оставьте ваш email для связи' ways_to_reach_you_message_body: 'Оставьте ваш email для связи'
@@ -216,8 +218,8 @@ ru:
name: 'Linear' name: 'Linear'
description: 'Создавайте или прикрепляйте уже существующие задачи в Linear непосредственно из окна диалога для более упорядоченного и эффективного процесса отслеживания проблем.' description: 'Создавайте или прикрепляйте уже существующие задачи в Linear непосредственно из окна диалога для более упорядоченного и эффективного процесса отслеживания проблем.'
captain: captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot' copilot_error: 'Пожалуйста, подключите ассистента к этому источнику входящих для использования Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.' copilot_limit: 'У вас закончились кредиты для Copilot. Вы можете купить дополнительные кредиты в разделе биллинга.'
public_portal: public_portal:
search: search:
search_placeholder: Поиск статьи по названию или содержанию... search_placeholder: Поиск статьи по названию или содержанию...
+2
View File
@@ -68,6 +68,8 @@ sh:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ sk:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ sl:
invalid_operator: Neveljaven operater. Dovoljeni operaterji za %{attribute_name} so [%{allowed_keys}]. invalid_operator: Neveljaven operater. Dovoljeni operaterji za %{attribute_name} so [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Neveljavna vrednost. Podane vrednosti za %{attribute_name} so neveljavne invalid_value: Neveljavna vrednost. Podane vrednosti za %{attribute_name} so neveljavne
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Obdobje poročanja %{since} do %{until} period: Obdobje poročanja %{since} do %{until}
utc_warning: Ustvarjeno poročilo je v časovnem pasu UTC utc_warning: Ustvarjeno poročilo je v časovnem pasu UTC
+2
View File
@@ -68,6 +68,8 @@ sq:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ sr-Latn:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Period izveštaja %{since} do %{until} period: Period izveštaja %{since} do %{until}
utc_warning: Generisani izveštaj je u UTC vremenskoj zoni utc_warning: Generisani izveštaj je u UTC vremenskoj zoni
+2
View File
@@ -68,6 +68,8 @@ sv:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Rapporteringsperiod %{since} till %{until} period: Rapporteringsperiod %{since} till %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ ta:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ th:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ tl:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ tr:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Raporlama aralığı %{since}'dan %{until}'a period: Raporlama aralığı %{since}'dan %{until}'a
utc_warning: Oluşturulan rapor UTC zaman dilimindedir. utc_warning: Oluşturulan rapor UTC zaman dilimindedir.
+2
View File
@@ -68,6 +68,8 @@ uk:
invalid_operator: Некоректний оператор. Дозволені оператори для %{attribute_name} є [%{allowed_keys}]. invalid_operator: Некоректний оператор. Дозволені оператори для %{attribute_name} є [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Невірне значення. Надані значення для %{attribute_name} є неприпустимі invalid_value: Невірне значення. Надані значення для %{attribute_name} є неприпустимі
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Період звіту %{since} до %{until} period: Період звіту %{since} до %{until}
utc_warning: Звіт створено в часовій зоні UTC utc_warning: Звіт створено в часовій зоні UTC
+2
View File
@@ -68,6 +68,8 @@ ur:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ ur:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
+2
View File
@@ -68,6 +68,8 @@ vi:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Thời gian báo cáo từ %{since} đến %{until} period: Thời gian báo cáo từ %{since} đến %{until}
utc_warning: Báo cáo đã được tạo với múi giờ UTC utc_warning: Báo cáo đã được tạo với múi giờ UTC
+2
View File
@@ -68,6 +68,8 @@ zh_CN:
invalid_operator: 无效的操作符。%{attribute_name} 允许的操作符为 [%{allowed_keys}]。 invalid_operator: 无效的操作符。%{attribute_name} 允许的操作符为 [%{allowed_keys}]。
invalid_query_operator: 查询操作符必须为 "AND" 或 "OR"。 invalid_query_operator: 查询操作符必须为 "AND" 或 "OR"。
invalid_value: 无效的值。为 %{attribute_name} 提供的值无效 invalid_value: 无效的值。为 %{attribute_name} 提供的值无效
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: 报告周期 %{since} 至 %{until} period: 报告周期 %{since} 至 %{until}
utc_warning: 生成的报表在 UTC 时区 utc_warning: 生成的报表在 UTC 时区
+2
View File
@@ -68,6 +68,8 @@ zh_TW:
invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}]. invalid_operator: Invalid operator. The allowed operators for %{attribute_name} are [%{allowed_keys}].
invalid_query_operator: Query operator must be either "AND" or "OR". invalid_query_operator: Query operator must be either "AND" or "OR".
invalid_value: Invalid value. The values provided for %{attribute_name} are invalid invalid_value: Invalid value. The values provided for %{attribute_name} are invalid
custom_attribute_definition:
key_conflict: The provided key is not allowed as it might conflict with default attributes.
reports: reports:
period: Reporting period %{since} to %{until} period: Reporting period %{since} to %{until}
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
@@ -18,6 +18,10 @@ class Integrations::Slack::SendOnSlackService < Base::SendOnChannelService
slack_client.chat_unfurl( slack_client.chat_unfurl(
event event
) )
# You may wonder why we're not requesting reauthorization and disabling hooks when scope errors occur.
# Since link unfurling is just a nice-to-have feature that doesn't affect core functionality, we will silently ignore these errors.
rescue Slack::Web::Api::Errors::MissingScope => e
Rails.logger.warn "Slack: Missing scope error: #{e.message}"
end end
private private

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