Compare commits

..
Author SHA1 Message Date
MuhsinandClaude Opus 4.6 b6a3c551bc fix(agent-bot): include changed_attributes in conversation_updated webhook
Include changed_attributes in the conversation_updated payload so bots
can identify what changed — e.g. check for assignee_agent_bot_id to
distinguish bot assignment from other conversation updates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 09:34:29 +04:00
MuhsinandClaude Opus 4.6 579bce3ee4 fix(agent-bot): use consistent pattern for conversation_updated handler
Match the same pattern as conversation_opened/conversation_resolved,
using agent_bots_for to send to both inbox-level and conversation-level
bots. Update specs accordingly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:44:40 +04:00
Muhsin KelothandGitHub 0126d8c668 Merge branch 'develop' into fix/agent-bot-assignment-webhook 2026-04-02 13:11:58 +04:00
Muhsin KelothandGitHub b3d0af84c4 fix(widget): Queue SDK-set conversation attributes and labels for first message (#13912)
### Description

When integrating the web widget via the JS SDK, customers call
setConversationCustomAttributes and setLabel on chatwoot:ready — before
any conversation exists. These API calls silently fail because the
backend endpoints require an existing conversation. When the visitor
sends their first message, the conversation is created without those
attributes/labels, so the message_created webhook payload is missing the
expected metadata.

This change queues SDK-set conversation custom attributes and labels in
the widget store when no conversation exists yet, and includes them in
the API request when the first message (or attachment) creates the
conversation. The backend now permits and applies these params during
conversation creation — before the message is saved and webhooks fire.

###  How to test

  1. Configure a web widget without a pre-chat form.
2. Open the widget on a test page and run the following in the browser
console after chatwoot:ready:
`window.$chatwoot.setConversationCustomAttributes({ plan: 'enterprise'
});`
`window.$chatwoot.setLabel('vip');` // must be a label that exists in
the account
  3. Send the first message from the widget.
4. Verify in the Chatwoot dashboard that the conversation has plan:
enterprise in custom attributes and the vip label applied.
5. Set up a webhook subscriber for `message_created` confirm the first
payload includes the conversation metadata.
6. Verify that calling `setConversationCustomAttributes` / `setLabel` on
an existing conversation still works as before (direct API path, no
regression).
  7. Verify the pre-chat form flow still works as expected.
2026-04-02 12:09:24 +04:00
Muhsin KelothandGitHub 4ba3d18be0 Merge branch 'develop' into fix/agent-bot-assignment-webhook 2026-04-02 11:55:25 +04:00
MuhsinandClaude Opus 4.6 27a7e4fa0b fix(agent-bot): use conversation_updated instead of assignee_changed
CONVERSATION_UPDATED already fires when assignee_agent_bot_id changes,
so no modification to AssignmentHandler is needed. Just listen for
conversation_updated in AgentBotListener instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 11:23:37 +04:00
d83beb2148 fix: Populate extension and include content_type in attachment webhook payload (#13945)
Attachment webhook event payloads (`message_created`) were missing the
file extension and content type. The `extension` column existed but was
never populated, and `content_type` was not included in the payload at
all.

## What changed

- Added `before_save :set_extension` callback to extract file extension
from the filename when saving an attachment.
- Added `content_type` (from ActiveStorage) to the `file_metadata` used
in `push_event_data`.

### Before
```json
{
  "extension": null,
  "data_url": "...",
  "file_size": 11960
}
```

### After
```json
{
  "extension": "pdf",
  "content_type": "application/pdf",
  "data_url": "...",
  "file_size": 11960
}
```

## How to reproduce
1. Send a message with a file attachment (e.g., PDF) via any channel
2. Inspect the `message_created` webhook payload
3. Observe `extension` is `null` and `content_type` is missing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 11:13:11 +04:00
8daf6cf6cb feat: captain custom tools v1 (#13890)
# Pull Request Template

## Description

Adds custom tool support to v1

## Type of change
- [x] New feature (non-breaking change which adds functionality)


## How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration.

<img width="1816" height="958" alt="CleanShot 2026-03-24 at 11 37 33@2x"
src="https://github.com/user-attachments/assets/2777a953-8b65-4a2d-88ec-39f395b3fb47"
/>

<img width="378" height="488" alt="CleanShot 2026-03-24 at 11 38 18@2x"
src="https://github.com/user-attachments/assets/f6973c99-efd0-40e4-90fe-4472a2f63cea"
/>

<img width="1884" height="1452" alt="CleanShot 2026-03-24 at 11 38
32@2x"
src="https://github.com/user-attachments/assets/9fba4fc4-0c33-46da-888a-52ec6bad6130"
/>



## Checklist:

- [x] My code follows the style guidelines of this project
- [ ] 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
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
2026-04-02 12:40:11 +05:30
MuhsinandClaude Opus 4.6 287a75b524 fix(agent-bot): address rubocop offenses in assignee_changed handler
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 10:53:09 +04:00
MuhsinandClaude Opus 4.6 40d00d895d fix(agent-bot): dispatch webhook event on agent bot assignment
When an AgentBot is assigned to a conversation after the first message,
the bot receives no event and cannot respond. This adds ASSIGNEE_CHANGED
event dispatch for agent bot assignment changes and handles it in the
AgentBotListener to notify the bot via webhook.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 10:52:33 +04:00
Shivam MishraandGitHub 211fb1102d chore: rotate oauth password if unconfirmed (#13878)
When a user signs up with an email they don't own and sets a password,
that password remains valid even after the real owner later signs in via
OAuth. This means the original registrant — who never proved ownership
of the email — retains working credentials on the account. This change
closes that gap by rotating the password to a random value whenever an
unconfirmed user completes an OAuth sign-in.

The check (`oauth_user_needs_password_reset?`) is evaluated before
`skip_confirmation!` runs, since confirmation would flip `confirmed_at`
and mask the condition. If the user was unconfirmed, the stored password
is replaced with a secure random string that satisfies the password
policy. This applies to both the web and mobile OAuth callback paths, as
well as the sign-up path where the password is rotated before the reset
token is generated.

Users who lose access to password-based login as a side effect can
recover through the standard "Forgot password" flow at any time. Since
they've already proven email ownership via OAuth, this is a low-friction
recovery path
2026-04-02 11:26:29 +05:30
Sivin VargheseandGitHub 7b09b033ef fix: Markdown tables don't render properly in help centre (#13971)
# Pull Request Template

## Description

This PR fixes an issue where markdown tables were not rendering
correctly in the Help Center.

The issue was caused by a backslash `(\)` being appended after table row
separators `(|)`, which breaks the markdown table parsing.

The issue was introduced after recent editor changes made to preserve
new lines, which unintentionally affected how table markdown is parsed
and displayed.

### https://github.com/chatwoot/prosemirror-schema/pull/44

Fixes
https://linear.app/chatwoot/issue/CW-6714/markdown-tables-dont-render-properly-in-help-centre-preview

## Type of change

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

## How Has This Been Tested?

**Before**
```
| Type         | What you provide              |\
|--------------|-------------------------------|\
| None         | No authentication             |\
| Bearer Token | A token string                |\
| Basic Auth   | Username and password         |\
| API Key      | A custom header name and value|
```

**After**
```
| Type         | What you provide              | 
|--------------|-------------------------------| 
| None         | No authentication             | 
| Bearer Token | A token string                | 
| Basic Auth   | Username and password         | 
| API Key      | A custom header name and value|
```




## 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
2026-04-02 11:02:21 +05:30
Vishnu NarayananandGitHub 65867b8b36 fix: exclude MutexApplicationJob::LockAcquisitionError from Sentry (#13965)
## Summary
- Add `MutexApplicationJob::LockAcquisitionError` to Sentry's
`excluded_exceptions`
- This error is expected control flow (mutex lock contention during
webhook processing), not a bug
- Generated ~131K Sentry events in March 2026, 100% from
`InstagramEventsJob`

Fixes https://linear.app/chatwoot/issue/INF-58
2026-04-01 18:02:19 +05:30
4cce7f6ad8 fix(line): Use non-expiring URLs for image and video messages (#13949)
Images and videos sent from Chatwoot to LINE inboxes fail to display on
the LINE mobile app — users see expired markers, broken thumbnails, or
missing images. This happens because LINE mobile lazy-loads images
rather than downloading them immediately, and the ActiveStorage signed
URLs expire after 5 minutes.

Closes
https://linear.app/chatwoot/issue/CW-6696/line-messaging-with-image-or-video-may-not-show-when-client-inactive

## How to reproduce

1. Create a LINE inbox and start a chat from the LINE mobile app
2. Close the LINE mobile app
3. Send an image from Chatwoot to that chat
4. Wait 7-8 minutes (past the 5-minute URL expiration)
5. Open the LINE mobile app — the image is broken/expired

## What changed

- **`originalContentUrl`**: switched from `download_url` (signed, 5-min
expiry) to `file_url` (permanent redirect-based URL)
- **`previewImageUrl`**: switched to `thumb_url` (250px resized
thumbnail meeting LINE's 1MB/240x240 recommendation), with fallback to
`file_url` for non-image attachments like video

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2026-04-01 17:29:12 +05:30
f2cb23d6e9 fix: handle Socket::ResolutionError in browser push notifications (#13957)
## Linear Ticket

https://linear.app/chatwoot/issue/CW-6707/socketresolutionerror-failed-to-open-tcp-connection-to-permanently

https://linear.app/chatwoot/issue/CW-6707/socketresolutionerror-failed-to-open-tcp-connection-to-permanently#comment-14e0f9ff

## Description

Browser push notifications fail with Socket::ResolutionError when the
push subscription endpoint's domain can't be resolved via DNS (e.g.,
defunct push service, transient DNS failure). This error wasn't handled
in handle_browser_push_error, so it fell through to the catch-all else
branch and got reported to Sentry on every notification attempt — 1,637
times in the last 7 days.
The dead subscription was never cleaned up or the error suppressed, so
every subsequent notification for the affected user triggered the same
Sentry alert.
Added Socket::ResolutionError to the existing transient network error
handler alongside Errno::ECONNRESET, Net::OpenTimeout, and
Net::ReadTimeout. The error is logged but not reported to Sentry, and
the subscription is kept intact in case it's a temporary DNS blip.

## Type of change

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

## How Has This Been Tested?

- Verified that Socket::ResolutionError is a subclass of StandardError
and matches the when clause

## Checklist:

- [ ] My code follows the style guidelines of this project
- [ ] 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
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules

Co-authored-by: Vishnu Narayanan <iamwishnu@gmail.com>
2026-04-01 16:55:49 +05:30
Sivin VargheseandGitHub 8824efe0e1 fix(sentry): syntaxError: No error message (#13954) 2026-03-31 21:09:02 +05:30
Sivin VargheseandGitHub 5de7ae492c fix: html/body background not applied in appearance mode (#13955)
# Pull Request Template

## Description

This PR fixes the white background bleed visible in the widget, widget
article viewer and help center when dark mode is active.

**What was happening**

While scrolling, the `<body>` element retained a white background in
dark mode. This occurred because dark mode classes were only applied to
inner container elements, not the root.

**What changed**

* **Widget:** Updated the `useDarkMode` composable to sync the `dark`
class to `<html>` using `watchEffect`, allowing `<body>` to inherit dark
theme variables. Also added background styles to `html`, `body`, and
`#app` in `woot.scss`.
* **Help center portal:** Moved `bg-white dark:bg-slate-900` from
`<main>` to `<body>` in the portal layout so the entire page background
responds correctly to dark mode, including within the widget iframe.
* **ArticleViewer:** Replaced hardcoded `bg-white` with `bg-n-solid-1`
to ensure better theming.


Fixes
https://linear.app/chatwoot/issue/CW-6704/widget-body-colour-not-implemented

## Type of change

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

## How Has This Been Tested?

### Screencasts

### Before

**Widget**


https://github.com/user-attachments/assets/e0224ad1-81a6-440a-a824-e115fb806728

**Help center**


https://github.com/user-attachments/assets/40a8ded5-5360-474d-9ec5-fd23e037c845



### After

**Widget**


https://github.com/user-attachments/assets/dd37cc68-99fc-4d60-b2ae-cf41f9d4d38c

**Help center**


https://github.com/user-attachments/assets/bc998c4e-ef77-46fa-ac7f-4ea16d912ce3




## 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
2026-03-31 16:55:21 +05:30
Aakash BakhleandGitHub b4b5de9b46 fix: conservative hand_off prompt on auto-resolution (#13953)
# Pull Request Template

## Description

The initial version of prompt deciding to resolve or hand-off to human
agents was too conservative especially in cases where a link or an
action was told to customer. If the customer didn't respond, Captain was
told to hand it off to the agent, but customer may actually have solved
the issue. If not, they can come back and continue the conversation.

Removed two lines about the same and now we should not see needless
handoffs.

## Type of change

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

## How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration.
locally

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] 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
- [x] 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
- [x] Any dependent changes have been merged and published in downstream
modules
2026-03-31 11:10:12 +05:30
Tanmay Deep SharmaandGitHub 1987ac3d97 fix: remove bulk_auto_assignment_job cron schedule (#13877) 2026-03-31 10:56:59 +05:30
Sivin VargheseandGitHub 0012fa2c35 fix: align message trimming with configured maxLength (#13947)
# Pull Request Template

## Description

This PR fixes 
1. Messages being trimmed to the default 1024 limit in `trimContent`
method, instead of channel-specific limits for drafts and AI tasks.
2. Telegram messages are allowed up to 10,000 characters in config, but
the API supports only 4096, causing failures for oversized messages.

Fixes
https://linear.app/chatwoot/issue/CW-6694/captain-ai-rewrite-tasks-truncate-draft-to-1024-chars-trimcontent
https://github.com/chatwoot/chatwoot/issues/13919

## Type of change

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

## How Has This Been Tested?

### Loom video

**Before**
https://www.loom.com/share/00e9d6b4d19247febf35dffa99da3805

**After**
https://www.loom.com/share/c4900e9effc345c79bcd8a5aa1ee277b


## 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
2026-03-31 10:39:54 +05:30
Aakash BakhleandGitHub b4ce59eea8 feat: reclaim response_bot flag for custom_tools (#13897)
Repurpose the deprecated response_bot feature flag slot for
custom_tools.

Migration disables the flag on any accounts that had response_bot
enabled so the repurposed slot starts in its default-off state.

Pre-deploy: run the disable script on production using the old flag name
(response_bot) before deploying this migration.
2026-03-31 10:35:50 +05:30
Sivin VargheseandGitHub 42441dbd28 feat: add GuideJar embed support in HC (#13944) 2026-03-30 14:19:02 +05:30
Alok DangreandGitHub b9f824b43b fix(ui): resolve unreadable select options in dark mode (#13207) 2026-03-30 13:05:28 +05:30
Shivam MishraandGitHub 7651c18b48 feat: firecrawl branding api [UPM-15] (#13903)
Adds `WebsiteBrandingService` (OSS) with an Enterprise override using
Firecrawl v2 to extract branding and business data from a URL for
onboarding auto-fill.

OSS version uses HTTParty + Nokogiri to extract:
- Business name (og:site_name or title)
- Language (html lang)
- Favicon
- Social links from `<a>` tags

Enterprise version makes a single Firecrawl call to fetch:
- Structured JSON (name, language, industry via LLM)
- Branding (favicon, primary color)
- Page links

Falls back to OSS if Firecrawl is unavailable or fails.

Social handles (WhatsApp, Facebook, Instagram, Telegram, TikTok, LINE)
are parsed deterministically via a shared `SocialLinkParser`.

> We use links for socials, since the LLM extraction was unreliable,
mostly returned empty, and hallucinated in some rare scenarios

## How to test

```ruby
# OSS (no Firecrawl key needed)
WebsiteBrandingService.new('chatwoot.com').perform

# Enterprise (requires CAPTAIN_FIRECRAWL_API_KEY)
WebsiteBrandingService.new('notion.so').perform
WebsiteBrandingService.new('postman.com').perform
```

Verify the returned hash includes business_name, language,
industry_category, social_handles, and branding with
favicon/primary_color.

<img width="908" height="393" alt="image"
src="https://github.com/user-attachments/assets/e3696887-d366-485a-89a0-8e1a9698a788"
/>
2026-03-30 11:32:03 +05:30
Tanmay Deep SharmaandGitHub 04acc16609 fix: skip pay call if invoice already paid after finalize (#13924)
## Description

When a customer downgrades from Enterprise to Business, they may retain
unused Stripe credit balance. During an AI credits topup,
Stripe::Invoice.finalize_invoice auto-applies that credit balance to the
invoice. If the credit balance fully covers the invoice amount, Stripe
marks it as paid immediately upon finalization. Calling
Stripe::Invoice.pay on an already-paid invoice throws an error, breaking
the topup flow.
This fix retrieves the invoice status after finalization and skips the
pay call if Stripe has already settled it via credits.

## Type of change

Please delete options that are not relevant.

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

## How Has This Been Tested?

Tested against Stripe test mode with the following scenarios:

- Full credit balance payment: Customer has enough Stripe credit balance
to cover the entire invoice. Invoice is marked paid after
finalize_invoice — pay is correctly skipped. Credits are fulfilled
successfully.
- Partial credit balance payment: Customer has some Stripe credit
balance but not enough to cover the full amount. Invoice remains open
after finalization — pay is called and charges the remaining amount to
the default payment method. Credits are fulfilled successfully.
- Zero credit balance (normal payment): Customer has no Stripe credit
balance. Invoice remains open after finalization — pay charges the full
amount. Credits are fulfilled successfully.


## Checklist:

- [ ] My code follows the style guidelines of this project
- [ ] 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
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
2026-03-30 10:37:28 +05:30
44a7a13117 fix: Add Estonian to settings language options (#13936)
Adds Estonian to the settings language dropdown so accounts can select
the existing `et` translation from the UI.

Fixes: N/A
Closes: N/A

## Why
Estonian translation files already exist in the repo and in Crowdin, but
the settings dropdown is driven by `LANGUAGES_CONFIG`, where `et` was
missing.

## What this change does
- Adds `et` / `Eesti (et)` to `LANGUAGES_CONFIG`
- Makes Estonian available in the settings language selectors backed by
`enabledLanguages`

## Validation
- `ruby -c config/initializers/languages.rb`
- Opened the local UI at `/app/accounts/1/settings/general` and verified
`Eesti (et)` appears in the `Site language` dropdown

---------

Co-authored-by: Pranav <pranav@chatwoot.com>
2026-03-29 09:44:34 +05:30
Tanmay Deep SharmaandGitHub 9efd554693 fix: resolve V2 capacity bypass in team assignment (#13904)
## Description

When Assignment V2 is enabled, the V2 capacity policies
(AgentCapacityPolicy / InboxCapacityLimit) are not respected during
team-based assignment paths. The system falls back to the legacy V1
max_assignment_limit, and since V1 is deprecated and typically
unconfigured in V2 setups, agents receive unlimited assignments
regardless of their V2 capacity.

Root cause: Inbox class directly defined
member_ids_with_assignment_capacity, which shadowed the
Enterprise::InboxAgentAvailability module override in Ruby's method
resolution order (MRO). This made the V2 capacity check unreachable
(dead code) for any code path using member_ids_with_assignment_capacity.

## Type of change

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

## How Has This Been Tested?

⏺ Before the fix
1. Enable assignment_v2 + advanced_assignment on account
2. Create AgentCapacityPolicy with InboxCapacityLimit = 1 for an inbox
3. Assign the policy to an agent (e.g., John)
4. Create 1 open conversation assigned to John (now at capacity)
5. Create a new unassigned conversation in the same inbox
6. Assign a team (containing John) to that conversation
7. Result: John gets assigned despite being at capacity
⏺ After the fix
Same steps 1–6.
7. Result: John is NOT assigned — conversation stays unassigned (no
agents with capacity available)


## Checklist:

- [ ] My code follows the style guidelines of this project
- [ ] 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
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
2026-03-27 15:38:17 +05:30
Sojan JoseandGitHub 2b296c06fb chore(security): ignore CVE-2026-33658 for Chatwoot storage defaults (#13922)
This ignores `CVE-2026-33658` in `bundler-audit` after validating that
Chatwoot's default and recommended storage setups do not use Active
Storage proxy mode.

Fixes: N/A
Closes: N/A

## Why
`CVE-2026-33658` is an Active Storage proxy-mode DoS issue triggered by
multi-range requests.

For Chatwoot, the default and recommended setups do not appear to route
file downloads through Rails proxy mode:
- `config/environments/production.rb` selects the Active Storage service
but does not opt into `rails_storage_proxy`
- `.env.example` defaults to `ACTIVE_STORAGE_SERVICE=local`
- Chatwoot's storage docs recommend local/cloud storage with optional
direct uploads to the storage provider
- existing specs expect redirect/disk-style Active Storage URLs rather
than proxy-mode URLs

Given that validation, ignoring this advisory is a smaller and more
accurate response than a framework-wide Rails upgrade.

## What this change does
- adds `.bundler-audit.yml`
- preserves the existing advisory ignore entries already used by
Chatwoot
- ignores `CVE-2026-33658`
- documents why the ignore is acceptable for Chatwoot's current defaults
- notes that this should be revisited if Chatwoot enables
`rails_storage_proxy` or other app-served Active Storage proxy routes

## Validation
- reviewed `config/environments/production.rb`
- reviewed `.env.example`
- reviewed Chatwoot storage docs:
https://developers.chatwoot.com/self-hosted/deployment/storage/s3-bucket
- reviewed Active Storage URL expectations in
`spec/controllers/slack_uploads_controller_spec.rb` and
`spec/services/line/send_on_line_service_spec.rb`
- ran `bundle exec bundle-audit check --no-update`
2026-03-27 13:06:17 +05:30
4381be5f3e feat: disable helpcenter on hacker plans (#12068)
This change blocks Help Center access for default/Hacker-plan accounts
and closes the downgrade gap that could leave `help_center` enabled
after a subscription falls back to the default cloud plan.

Fixes: none
Closes: none

## Why

Default-plan accounts should not be able to access the Help Center, but
the downgrade fallback path only reset the plan name and did not
reconcile premium feature flags. That meant some accounts could keep
`help_center` enabled even after landing back on the Hacker/default
plan.

## What this change does

- blocks Help Center portal and article access for default/Hacker-plan
accounts
- reconciles premium feature flags when a subscription falls back to the
default cloud plan, so `help_center` is disabled immediately instead of
waiting for a later webhook
- preserves existing account `custom_attributes` during Stripe customer
recreation instead of overwriting them
- adds Enterprise coverage for the default-plan access checks on hosted
and custom-domain Help Center routes
- fixes the public access check to use the resolved portal object so
blocked requests return the intended response instead of raising an
error

## Validation

1. Create or use an account on the default/Hacker cloud plan with an
active portal.
2. Visit the portal home page and a published article on both the
Chatwoot-hosted URL and a configured custom domain.
3. Confirm the Help Center is blocked for that account.
4. Downgrade a paid account back to the default/Hacker plan through the
Stripe webhook flow.
5. Confirm `help_center` is disabled right after the downgrade fallback
is processed and the account can no longer access the Help Center.

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2026-03-26 23:48:46 -07:00
Shivam MishraandGitHub 127ac0a6b2 fix: show backend error message on API channel creation failure (#13855) 2026-03-27 11:42:33 +05:30
Sivin VargheseandGitHub 5d9d754961 chore(editor): Auto-linkify URLs immediately on paste (#13900)
# Pull Request Template

## Description

This PR upgrades the ProseMirror editor and enables automatic URL
linkification on paste. Previously, URLs were only linkified after a
user input event (e.g., typing a space). With this change, URLs are now
linkified instantly when pasted.

Fixes
https://linear.app/chatwoot/issue/CW-6682/email-channel-links-are-not-working

### https://github.com/chatwoot/prosemirror-schema/pull/42

## Type of change

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

## How Has This Been Tested?

**Screencast**

**Before**


https://github.com/user-attachments/assets/d38725c9-a152-4c2c-8c33-3ee717f1628f



**After**


https://github.com/user-attachments/assets/9a69a0b6-93ee-421e-896b-5a4e01a167ba


## 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
2026-03-27 11:29:54 +05:30
cac7438fff fix: Email Channel links are not working (backend) (#13898)
# Pull Request Template

## Description

This PR fixes the link formatting issue on the backend by adding
`:autolink` to `ChatwootMarkdownRenderer#render_message`, ensuring all
URLs are converted to `<a>` tags.

Fixes
https://linear.app/chatwoot/issue/CW-6682/email-channel-links-are-not-working

## 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

---------

Co-authored-by: Sojan Jose <sojan@pepalo.com>
2026-03-26 21:44:57 -07:00
Haruma HIRABAYASHIandGitHub 0b41d7f483 docs(swagger): fix operationId typo converation -> conversation (#13920)
issue: https://github.com/chatwoot/chatwoot/issues/13921

Fix a typo in the Messages API operationId where `converation` was used
instead of `conversation`. This causes cspell errors when generating
client code with tools like Orval.

## What changed

- `swagger/paths/public/inboxes/messages/index.yml`: fixed operationId
from `list-all-converation-messages` to `list-all-conversation-messages`
- `swagger/swagger.json` and `swagger/tag_groups/client_swagger.json`:
regenerated to reflect the fix


## Note

If you are using a code generator like Orval against this swagger spec,
the generated function name will change from
`listAllConverationMessages` to `listAllConversationMessages`.
2026-03-27 09:23:55 +05:30
Sivin VargheseandGitHub 4517c50227 feat: support bulk select and delete for documents (#13907) 2026-03-26 19:48:12 +05:30
Vishnu NarayananandGitHub 4c4b70da25 fix: Skip email rate limiting for self-hosted instances (#13915)
Self-hosted installations were incorrectly hitting the daily email rate
limit of 100, seeded from `installation_config`. Since self-hosted users
control their own infrastructure, email rate limiting should only apply
to Chatwoot Cloud.

Closes #13913
2026-03-26 18:06:10 +05:30
Tanmay Deep SharmaandGitHub d84ef4cfd6 fix(whatsapp): skip health check during reauthorization flow (#13911)
After a successful WhatsApp OAuth reauthorization, the health check runs
immediately and finds the phone number in a pending provisioning state
(`platform_type: NOT_APPLICABLE`). This incorrectly triggers
`prompt_reauthorization!`, re-setting the Redis disconnect flag and
sending a disconnect email — even though the reauth just succeeded.

The fix skips the health check during reauthorization flows. It still
runs for new channel creation.

Closes https://github.com/chatwoot/chatwoot/pull/12556

## Type of change

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

## How to reproduce

1. Have a WhatsApp channel with a phone number in pending provisioning
state (display name not yet approved by Meta)
2. Complete the OAuth reauthorization flow
3. Observe that the user receives a "success" response but immediately
gets a disconnect email

## What changed

- `Whatsapp::EmbeddedSignupService#perform` now skips
`check_channel_health_and_prompt_reauth` when `inbox_id` is present
(reauthorization flow)


🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-26 15:00:09 +05:30
Sivin VargheseandGitHub 23786bcb52 chore: mark conversation notifications as read on visit (#13906) 2026-03-26 14:01:26 +05:30
Shivam MishraandGitHub e4c3f0ac2f feat: fallback on phone number to update lead (#13910)
When syncing contacts to LeadSquared, the `Lead.CreateOrUpdate` API
defaults to searching by email. If a contact has no email (or a
different email) but a phone number matching an existing lead, the API
fails with `MXDuplicateEntryException` instead of finding and updating
the existing lead. This accounted for ~69% of all LeadSquared
integration errors, and cascaded into "Lead not found" failures when
posting transcript and conversation activities (~14% of errors).

## What changed

- `LeadClient#create_or_update_lead` now catches
`MXDuplicateEntryException` and retries the request once with
`SearchBy=Phone` appended to the body, telling the API to match on phone
number instead
- Once the retry succeeds, the returned lead ID is stored on the contact
(existing behavior), so all future events use the direct `update_lead`
path and never hit the duplicate error again

## How to reproduce

1. Create a lead in LeadSquared with phone number `+91-75076767676` and
email `a@example.com`
2. In Chatwoot, create a contact with the same phone number but a
different email (or no email)
3. Trigger a contact sync (via conversation creation or contact update)
4. Before fix: `MXDuplicateEntryException` error in logs, contact fails
to sync
5. After fix: retry with `SearchBy=Phone` finds and updates the existing
lead, stores the lead ID on the contact
2026-03-26 12:32:27 +05:30
742c5cc1f4 feat(dialogflow): make language_code configurable instead of hardcoded (#13221)
# Pull Request Template

## Description

Please include a summary of the change and issue(s) fixed. Also, mention
relevant motivation, context, and any dependencies that this change
requires.
- Add language_code setting to Dialogflow integration configuration
- Support 'auto' mode to detect language from contact's
additional_attributes
- Fallback to 'en-US' when no language is configured or detected
- Include comprehensive language options (22 languages)
- Add tests for language code configuration scenarios

Fixes #3071

## Type of change

Please delete options that are not relevant.

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality not to work as expected)
- [ ] This change requires a documentation update

## How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration.

<img width="815" height="506" alt="Screenshot 2026-01-10 220410"
src="https://github.com/user-attachments/assets/26d2619c-ed42-4c9a-a41d-9fb07ef91a30"
/>


## 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

---------

Co-authored-by: Sojan Jose <sojan@pepalo.com>
2026-03-25 21:30:17 -07:00
d9e732c005 chore(v5): update priority icons (#13905)
# Pull Request Template

## Description

This PR updates the priority icons with a new set and makes them
consistent across the app.


## How Has This Been Tested?

**Screenshots**
<img width="420" height="550" alt="image"
src="https://github.com/user-attachments/assets/cb392934-6c4d-46b4-9fde-244461da62ef"
/>
<img width="358" height="340" alt="image"
src="https://github.com/user-attachments/assets/cb18df47-9a17-42f8-9367-e8b7c4e3958d"
/>
<img width="344" height="468" alt="image"
src="https://github.com/user-attachments/assets/9de92374-e732-48eb-a8a9-85c5b5100931"
/>
<img width="445" height="548" alt="image"
src="https://github.com/user-attachments/assets/ecc4ce51-165c-4593-a9a2-e70b08a29006"
/>


## 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

---------

Co-authored-by: Pranav <pranav@chatwoot.com>
2026-03-26 09:20:36 +05:30
e0e321b8e2 fix: Annotaterb model annotation incomplete migration (#13132)
This pull request fixes the model annotation tooling due to previous
incomplete migration from `annotate` to `annotaterb` gem (#12600). It
also improves the handling of serialized values in the
`InstallationConfig` model by ensuring a default value is set,
simplifying the code, and removing a workaround for YAML
deserialization.

**Annotation tooling updates:**

* Added `.annotaterb.yml` to configure the `annotate_rb` gem with
project-specific options, centralizing annotation settings.
* Replaced the custom `auto_annotate_models.rake` task with the standard
rake task from `annotate_rb`, and added `lib/tasks/annotate_rb.rake` to
load annotation tasks in development environments.
[[1]](diffhunk://#diff-9450d2359e45f1db407b3871dde787a25d60bb721aed179a65ffd2692e95fb4bL1-L61)
[[2]](diffhunk://#diff-578cdfc7ad56637e42472ea891ea286dff8803d9a1750afdbfeafec164d9b8b2R1-R8)

**Model serialization improvements:**

* Updated the `InstallationConfig` model to set a default value for the
`serialized_value` attribute, ensuring it always has a hash with
indifferent access and removing the need for a deserialization
workaround in the `value` method.
[[1]](diffhunk://#diff-b4bdde42c1ad0f584073818bd43dbd865b1b3b50d4701b131979f900d7c68297L22-R22)
[[2]](diffhunk://#diff-b4bdde42c1ad0f584073818bd43dbd865b1b3b50d4701b131979f900d7c68297L36-L39)

---------

Co-authored-by: Sojan Jose <sojan@pepalo.com>
2026-03-25 17:51:06 -07:00
Sojan Jose ecc66e064d Merge branch 'release/4.12.1' into develop 2026-03-25 16:21:38 -07:00
Sojan Jose 7144d55334 Bump version to 4.12.1 2026-03-25 16:20:58 -07:00
250650dd7a feat(platform): Add email channel migration endpoint for bulk OAuth channel creation (#13902)
Adds a Platform API endpoint that allows migrating existing Google and
Microsoft email channels (with OAuth credentials) into Chatwoot without
requiring end-users to re-authenticate. This enables customers who lack
Rails console access to programmatically migrate email channels from
legacy systems.
    
 ### How to test

1. Create a Platform App and grant it permissible access to a target
account
2. `POST /platform/api/v1/accounts/:account_id/email_channel_migrations`
with a payload like:
  ```json
  {
    "migrations": [
      {
        "email": "support@example.com",
        "provider": "google",
        "provider_config": {
          "access_token": "...",
          "refresh_token": "...",
          "expires_on": "..."
        },
        "inbox_name": "Migrated Support"
      }
    ]
  }
```
  3. Verify channels are created with correct provider, provider_config, and IMAP defaults
  4. Verify partial failures (e.g. duplicate email) don't roll back other migrations in the batch
  5. Verify unauthenticated and non-permissible requests return 401

---------

Co-authored-by: Sojan Jose <sojan@pepalo.com>
2026-03-25 15:58:08 -07:00
608be1036b fix: Send raw content in webhook payloads instead of channel-rendered markdown (#13896)
Webhook payloads (`message_created`, `message_updated`) started sending
channel-rendered HTML in the `content` field instead of the original raw
message content after PR #12878. This broke downstream agent bots and
integrations that expected plain text or markdown. 
Closes https://linear.app/chatwoot/issue/PLA-109/webhook-payloads-send-channel-rendered-html-instead-of-raw-content

## How to reproduce

1. Connect an agent bot to a WebWidget inbox
2. Send a message with markdown formatting (e.g. `**bold**`) from the
widget
3. Observe the agent bot webhook payload — `content` field contains
`<p><strong>bold</strong></p>` instead of `**bold**`

## What changed

Split `MessageContentPresenter` into two public methods:
- `outgoing_content` — renders markdown for the target channel (used by
channel delivery services)
- `webhook_content` — returns raw content with CSAT survey URL when
applicable, no markdown rendering (used by `webhook_data`)

Updated `Message#webhook_data` to use `webhook_content` instead of
`outgoing_content`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2026-03-25 16:56:22 +04:00
salmonumbrellaandGitHub 6ff643b045 fix(i18n): add zh_TW snooze parser locale (#13822) 2026-03-25 16:54:18 +05:30
Vishnu NarayananandGitHub 775b73d1f9 fix: raise open file descriptor limit to prevent EMFILE errors (#13895)
## Summary
- Adds `LimitNOFILE=65536` to both web and worker systemd service units
- Fixes recurring `Errno::EMFILE` (Too many open files) errors during
peak traffic after deploys

## Context
Puma workers idle at 720-770 open FDs against the default soft limit of
1024, leaving ~250 FDs of headroom. During deploy-triggered instance
refreshes at peak traffic, concurrent requests exhaust the remaining
FDs, causing EMFILE across all web instances.

3 incidents in March 2026 with escalating event counts. The hard limit
is already 524288, so this just raises the soft limit to a standard
production value.

Self-hosted instances pick this up automatically via `cwctl --upgrade`.

Fixes
https://linear.app/chatwoot/issue/CW-6685/errnoemfile-too-many-open-files-rb-sysopen
2026-03-24 17:37:07 -07:00
14df7b3bc1 fix: ai-assist 404 on CE (#13891)
# Pull Request Template

## Description

Relocate controller from enterprise/ to app/ and add
Api::V1::Accounts::Captain::TasksController.prepend_mod_with for EE
overrides.

Fixes: Ai assist giving 404 on CE

## Type of change

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

## How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration.

before:
<img width="482" height="130" alt="image"
src="https://github.com/user-attachments/assets/f51dc28a-ac54-45c4-9015-6f956fdf5057"
/>

after:
<img width="458" height="182" alt="image"
src="https://github.com/user-attachments/assets/eb86a679-5482-4157-9f4e-f3e9953d8649"
/>


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] 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
- [x] 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
- [x] Any dependent changes have been merged and published in downstream
modules

Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
2026-03-24 16:58:11 +05:30
Sivin VargheseandGitHub 6946859ba4 fix: normalize "in less than a minute" to "now" in chat list timestamp (#13874)
# Pull Request Template

## Description

This PR fixes the conversation list showing raw "**in less than a
minute**" text instead of "**now**" for very recent conversations.

Fixes https://linear.app/chatwoot/issue/CW-6666/issue-with-timestamps

## 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
2026-03-24 16:16:35 +05:30
Sivin VargheseandGitHub c129ab00ba fix: normalize "in less than a minute" to "now" in chat list timestamp (#13874) 2026-03-24 15:40:31 +05:30
7edae93ee8 fix(agent-bot): Include payload in webhook retry failure logs (#13879)
Webhook retry failure logs for agent-bot now include the event payload,
making it easier to identify which event failed when debugging transient
upstream errors (429/500).

Previously the log only showed:
`[AgentBots::WebhookJob] attempt 1 failed
RestClient::InternalServerError`

Now it includes the payload:
`[AgentBots::WebhookJob] attempt 1 failed
RestClient::InternalServerError payload={"event":"message_created",...}`

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 10:52:37 +04:00
4b315bc2ec chore: Update translations (#13884)
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2026-03-23 20:06:17 -07:00
Sivin VargheseandGitHub 30c0479e9a fix: show agent name in unread bubble for Captain replies (#13876) 2026-03-23 20:03:31 +05:30
Aakash BakhleandGitHub 3c0d55f87a fix: handoff only if conversation pending (#13882)
# Pull Request Template

## Description

- Skip handoff when the conversation is no longer pending. 
- Fetch conversation status with Conversation.uncached to avoid stale
query cache when checking pending state.

## Type of change

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

## How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration.

Difficult to reproduce locally, but seen a couple of conversations where
bot hands off an extra time or Captain re-generates usually due to a
retry on FaradayTimeoutError but at perform time, the conversation
status is stale so it appears as if Captain responded in an open
conversation.

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] 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
- [x] 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
- [x] Any dependent changes have been merged and published in downstream
modules
2026-03-23 17:09:58 +05:30
Aakash BakhleandGitHub 4af3e830fc fix: conversation completion prompt to auto-resolve gibberish/no-intent messages after inactivity (#13875)
# Pull Request Template

## Description

For our account, the conversation completion evaluator was proving to be
too conservative. This resulted in queue noise.
This PR adds a line to handle gibberish/single worded messages with no
further context.

## Type of change

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

## How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration.

<img width="3012" height="978" alt="CleanShot 2026-03-23 at 11 44 55@2x"
src="https://github.com/user-attachments/assets/328195e8-6ea0-4c3a-9049-ee80196eecad"
/>

<img width="2202" height="866" alt="CleanShot 2026-03-23 at 11 47 15@2x"
src="https://github.com/user-attachments/assets/8d51cff4-b18f-4582-9455-8119ec7eff3a"
/>


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] 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
- [x] 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
- [x] Any dependent changes have been merged and published in downstream
modules
2026-03-23 12:18:23 +05:30
b974993886 chore: Update translations (#13845)
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2026-03-21 02:20:27 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Sojan Jose
4b849cdd11 chore(deps): bump bcrypt from 3.1.20 to 3.1.22 (#13852)
Bumps [bcrypt](https://github.com/bcrypt-ruby/bcrypt-ruby) from 3.1.20
to 3.1.22.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/bcrypt-ruby/bcrypt-ruby/releases">bcrypt's
releases</a>.</em></p>
<blockquote>
<h2>v3.1.22</h2>
<h2>What's Changed</h2>
<ul>
<li>Move compilation after bundle install by <a
href="https://github.com/tenderlove"><code>@​tenderlove</code></a> in <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/pull/291">bcrypt-ruby/bcrypt-ruby#291</a></li>
<li>Add TruffleRuby in CI by <a
href="https://github.com/tjschuck"><code>@​tjschuck</code></a> in <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/pull/293">bcrypt-ruby/bcrypt-ruby#293</a></li>
<li>fix env url by <a
href="https://github.com/tenderlove"><code>@​tenderlove</code></a> in <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/pull/294">bcrypt-ruby/bcrypt-ruby#294</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/bcrypt-ruby/bcrypt-ruby/compare/v3.1.21...v3.1.22">https://github.com/bcrypt-ruby/bcrypt-ruby/compare/v3.1.21...v3.1.22</a></p>
<h2>v3.1.21</h2>
<h2>What's Changed</h2>
<ul>
<li>Provide a 'Changelog' link on rubygems.org/gems/bcrypt by <a
href="https://github.com/mark-young-atg"><code>@​mark-young-atg</code></a>
in <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/pull/274">bcrypt-ruby/bcrypt-ruby#274</a></li>
<li>Support ruby 3.3 and 3.4.0-preview1 by <a
href="https://github.com/m-nakamura145"><code>@​m-nakamura145</code></a>
in <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/pull/276">bcrypt-ruby/bcrypt-ruby#276</a></li>
<li>Mark as ractor-safe by <a
href="https://github.com/mohamedhafez"><code>@​mohamedhafez</code></a>
in <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/pull/280">bcrypt-ruby/bcrypt-ruby#280</a></li>
<li>Add == gotcha that can be unintuitive at first by <a
href="https://github.com/federicoaldunate"><code>@​federicoaldunate</code></a>
in <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/pull/279">bcrypt-ruby/bcrypt-ruby#279</a></li>
<li>Constant compare by <a
href="https://github.com/tenderlove"><code>@​tenderlove</code></a> in <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/pull/282">bcrypt-ruby/bcrypt-ruby#282</a></li>
<li>try to modernize CI by <a
href="https://github.com/tenderlove"><code>@​tenderlove</code></a> in <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/pull/287">bcrypt-ruby/bcrypt-ruby#287</a></li>
<li>Try to deal with flaky tests by <a
href="https://github.com/tenderlove"><code>@​tenderlove</code></a> in <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/pull/288">bcrypt-ruby/bcrypt-ruby#288</a></li>
<li>Configure trusted publishing by <a
href="https://github.com/tenderlove"><code>@​tenderlove</code></a> in <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/pull/289">bcrypt-ruby/bcrypt-ruby#289</a></li>
<li>bump version by <a
href="https://github.com/tenderlove"><code>@​tenderlove</code></a> in <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/pull/290">bcrypt-ruby/bcrypt-ruby#290</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/mark-young-atg"><code>@​mark-young-atg</code></a>
made their first contribution in <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/pull/274">bcrypt-ruby/bcrypt-ruby#274</a></li>
<li><a
href="https://github.com/m-nakamura145"><code>@​m-nakamura145</code></a>
made their first contribution in <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/pull/276">bcrypt-ruby/bcrypt-ruby#276</a></li>
<li><a
href="https://github.com/mohamedhafez"><code>@​mohamedhafez</code></a>
made their first contribution in <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/pull/280">bcrypt-ruby/bcrypt-ruby#280</a></li>
<li><a
href="https://github.com/federicoaldunate"><code>@​federicoaldunate</code></a>
made their first contribution in <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/pull/279">bcrypt-ruby/bcrypt-ruby#279</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/bcrypt-ruby/bcrypt-ruby/compare/v3.1.20...v3.1.21">https://github.com/bcrypt-ruby/bcrypt-ruby/compare/v3.1.20...v3.1.21</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/bcrypt-ruby/bcrypt-ruby/blob/master/CHANGELOG">bcrypt's
changelog</a>.</em></p>
<blockquote>
<p>3.1.22 Mar 18 2026</p>
<ul>
<li>[CVE-2026-33306] Fix integer overflow in Java extension</li>
</ul>
<p>3.1.21 Dec 31 2025</p>
<ul>
<li>Use constant time comparisons</li>
<li>Mark as Ractor safe</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bcrypt-ruby/bcrypt-ruby/commit/831ce64cb0a9502130fa93a28bfd9527a5fa45c4"><code>831ce64</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/bcrypt-ruby/bcrypt-ruby/commit/32e687ec5f62baad01a62e4634e41d97f8432a61"><code>32e687e</code></a>
bump version update changelog</li>
<li><a
href="https://github.com/bcrypt-ruby/bcrypt-ruby/commit/5faa2748331d3edc661c127ef2fbb3afcb6b02a4"><code>5faa274</code></a>
Fix integer overflow in JRuby BCrypt rounds calculation</li>
<li><a
href="https://github.com/bcrypt-ruby/bcrypt-ruby/commit/aafc0332ac1aa0d774f2c864439596436f92d18d"><code>aafc033</code></a>
Merge pull request <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/issues/294">#294</a>
from bcrypt-ruby/fix-publishing</li>
<li><a
href="https://github.com/bcrypt-ruby/bcrypt-ruby/commit/01f947a66ad8c5e20d8c89d9adbc7e3bd49afb70"><code>01f947a</code></a>
fix env url</li>
<li><a
href="https://github.com/bcrypt-ruby/bcrypt-ruby/commit/92ca1d67deeb8e64dbe779396c52b177e307bc43"><code>92ca1d6</code></a>
Merge pull request <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/issues/293">#293</a>
from bcrypt-ruby/truffleruby-ci-alt-implementation</li>
<li><a
href="https://github.com/bcrypt-ruby/bcrypt-ruby/commit/4d1d95b8ec624d0cf8ed1099402a7edd2f308da2"><code>4d1d95b</code></a>
Add TruffleRuby in CI</li>
<li><a
href="https://github.com/bcrypt-ruby/bcrypt-ruby/commit/36a04a2278fae3b38100912ff489b86cd0984b8a"><code>36a04a2</code></a>
Merge pull request <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/issues/291">#291</a>
from tenderlove/fix-publishing</li>
<li><a
href="https://github.com/bcrypt-ruby/bcrypt-ruby/commit/01cc68835f0bcdd7ef16de477471c112adb417da"><code>01cc688</code></a>
Move compilation after bundle install</li>
<li><a
href="https://github.com/bcrypt-ruby/bcrypt-ruby/commit/82e6c4c6cf81912768c68d721372e78330ff2c92"><code>82e6c4c</code></a>
Merge pull request <a
href="https://redirect.github.com/bcrypt-ruby/bcrypt-ruby/issues/290">#290</a>
from tenderlove/bump</li>
<li>Additional commits viewable in <a
href="https://github.com/bcrypt-ruby/bcrypt-ruby/compare/v3.1.20...v3.1.22">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=bcrypt&package-manager=bundler&previous-version=3.1.20&new-version=3.1.22)](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 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>
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2026-03-20 16:30:50 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Sojan Jose
310590cae3 chore(deps): bump json from 2.18.1 to 2.19.2 (#13849)
Bumps [json](https://github.com/ruby/json) from 2.18.1 to 2.19.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ruby/json/releases">json's
releases</a>.</em></p>
<blockquote>
<h2>v2.19.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix a format string injection vulnerability in <code>JSON.parse(doc,
allow_duplicate_key: false)</code>. <code>CVE-2026-33210</code></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/ruby/json/compare/v2.19.1...v2.19.2">https://github.com/ruby/json/compare/v2.19.1...v2.19.2</a></p>
<h2>v2.19.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix a compiler dependent GC bug introduced in
<code>2.18.0</code>.</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/ruby/json/compare/v2.19.0...v2.19.1">https://github.com/ruby/json/compare/v2.19.0...v2.19.1</a></p>
<h2>v2.19.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix <code>allow_blank</code> parsing option to no longer allow
invalid types (e.g. <code>load([], allow_blank: true)</code> now raise a
type error).</li>
<li>Add <code>allow_invalid_escape</code> parsing option to ignore
backslashes that aren't followed by one of the valid escape
characters.</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/ruby/json/compare/v2.18.1...v2.19.0">https://github.com/ruby/json/compare/v2.18.1...v2.19.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/ruby/json/blob/master/CHANGES.md">json's
changelog</a>.</em></p>
<blockquote>
<h3>2026-03-18 (2.19.2)</h3>
<ul>
<li>Fix a format string injection vulnerability in <code>JSON.parse(doc,
allow_duplicate_key: false)</code>. <code>CVE-2026-33210</code>.</li>
</ul>
<h3>2026-03-08 (2.19.1)</h3>
<ul>
<li>Fix a compiler dependent GC bug introduced in
<code>2.18.0</code>.</li>
</ul>
<h3>2026-03-06 (2.19.0)</h3>
<ul>
<li>Fix <code>allow_blank</code> parsing option to no longer allow
invalid types (e.g. <code>load([], allow_blank: true)</code> now raise a
type error).</li>
<li>Add <code>allow_invalid_escape</code> parsing option to ignore
backslashes that aren't followed by one of the valid escape
characters.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/ruby/json/commit/54f8a878aebee090476a53c851c943128894be62"><code>54f8a87</code></a>
Release 2.19.2</li>
<li><a
href="https://github.com/ruby/json/commit/393b41c3e5f87491e1e34fa59fa78ff6fa179a74"><code>393b41c</code></a>
Fix a format string injection vulnerability</li>
<li><a
href="https://github.com/ruby/json/commit/dbf6bb12aac85db939df1180028aea06c8d3b762"><code>dbf6bb1</code></a>
Merge pull request <a
href="https://redirect.github.com/ruby/json/issues/953">#953</a> from
ruby/dependabot/github_actions/actions/create-gi...</li>
<li><a
href="https://github.com/ruby/json/commit/7187315b4571ade59d68a1fad84be2794cda744d"><code>7187315</code></a>
Bump actions/create-github-app-token from 2 to 3</li>
<li><a
href="https://github.com/ruby/json/commit/4a42a04280d96d8dd94558078c16f1c078c38e1b"><code>4a42a04</code></a>
Release 2.19.1</li>
<li><a
href="https://github.com/ruby/json/commit/13689c269970f18316952541f8544830ec2dc5c4"><code>13689c2</code></a>
Add missing GC_GUARD in <code>fbuffer_append_str</code></li>
<li><a
href="https://github.com/ruby/json/commit/a11acc1ff496627e5d72c71d6d1229e8c8ffeaa1"><code>a11acc1</code></a>
Release 2.19.0</li>
<li><a
href="https://github.com/ruby/json/commit/0a4fb79cd97f535701cc2240ac736d76b9af5025"><code>0a4fb79</code></a>
fbuffer.h: Use size_t over unsigned long</li>
<li><a
href="https://github.com/ruby/json/commit/a29fcdcb4a78164daa14f6af05812690dd3ac939"><code>a29fcdc</code></a>
Add depth validation to Jruby and TruffleRuby implementations</li>
<li><a
href="https://github.com/ruby/json/commit/de993aa76639078da891f46351a36f77d51ad3d3"><code>de993aa</code></a>
Reject negative depth; add overflow guards to prevent hang/crash</li>
<li>Additional commits viewable in <a
href="https://github.com/ruby/json/compare/v2.18.1...v2.19.2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=json&package-manager=bundler&previous-version=2.18.1&new-version=2.19.2)](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 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>
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2026-03-20 16:30:35 -07:00
446 changed files with 38674 additions and 38787 deletions
+65
View File
@@ -0,0 +1,65 @@
---
:position: before
:position_in_additional_file_patterns: before
:position_in_class: before
:position_in_factory: before
:position_in_fixture: before
:position_in_routes: before
:position_in_serializer: before
:position_in_test: before
:classified_sort: true
:exclude_controllers: true
:exclude_factories: true
:exclude_fixtures: true
:exclude_helpers: true
:exclude_scaffolds: true
:exclude_serializers: true
:exclude_sti_subclasses: false
:exclude_tests: true
:force: false
:format_markdown: false
:format_rdoc: false
:format_yard: false
:frozen: false
:grouped_polymorphic: false
:ignore_model_sub_dir: false
:ignore_unknown_models: false
:include_version: false
:show_check_constraints: false
:show_complete_foreign_keys: false
:show_foreign_keys: true
:show_indexes: true
:show_indexes_include: false
:simple_indexes: false
:sort: false
:timestamp: false
:trace: false
:with_comment: true
:with_column_comments: true
:with_table_comments: true
:position_of_column_comment: :with_name
:active_admin: false
:command:
:debug: false
:hide_default_column_types: json,jsonb,hstore
:hide_limit_column_types: integer,bigint,boolean
:timestamp_columns:
- created_at
- updated_at
:ignore_columns:
:ignore_routes:
:models: true
:routes: false
:skip_on_db_migrate: false
:target_action: :do_annotations
:wrapper:
:wrapper_close:
:wrapper_open:
:classes_default_to_s: []
:additional_file_patterns: []
:model_dir:
- app/models
- enterprise/app/models
:require: []
:root_dir:
- ''
+5
View File
@@ -2,3 +2,8 @@
ignore: ignore:
- CVE-2021-41098 # https://github.com/chatwoot/chatwoot/issues/3097 (update once azure blob storage is updated) - CVE-2021-41098 # https://github.com/chatwoot/chatwoot/issues/3097 (update once azure blob storage is updated)
- GHSA-57hq-95w6-v4fc # Devise confirmable race condition — patched locally in User model (remove once on Devise 5+) - GHSA-57hq-95w6-v4fc # Devise confirmable race condition — patched locally in User model (remove once on Devise 5+)
# Chatwoot defaults to Active Storage redirect-style URLs, and its recommended
# storage setup uses local/cloud storage with optional direct uploads to the
# storage provider rather than Rails proxy mode. Revisit if we enable
# rails_storage_proxy or other app-served Active Storage proxy routes.
- CVE-2026-33658
-4
View File
@@ -94,10 +94,6 @@ yarn-debug.log*
.vscode .vscode
.claude/settings.local.json .claude/settings.local.json
.cursor .cursor
# react component
dist
.codex/ .codex/
.claude/ .claude/
CLAUDE.local.md CLAUDE.local.md
+2 -2
View File
@@ -166,7 +166,7 @@ GEM
multi_json (~> 1) multi_json (~> 1)
statsd-ruby (~> 1.1) statsd-ruby (~> 1.1)
base64 (0.3.0) base64 (0.3.0)
bcrypt (3.1.20) bcrypt (3.1.22)
benchmark (0.4.1) benchmark (0.4.1)
bigdecimal (3.2.2) bigdecimal (3.2.2)
bindex (0.8.1) bindex (0.8.1)
@@ -465,7 +465,7 @@ GEM
rails-dom-testing (>= 1, < 3) rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0) railties (>= 4.2.0)
thor (>= 0.14, < 2.0) thor (>= 0.14, < 2.0)
json (2.18.1) json (2.19.2)
json_refs (0.1.8) json_refs (0.1.8)
hana hana
json_schemer (0.2.24) json_schemer (0.2.24)
+1 -1
View File
@@ -1 +1 @@
4.12.0 4.12.1
@@ -57,7 +57,7 @@ class Api::V1::Accounts::Captain::TasksController < Api::V1::Accounts::BaseContr
if result.nil? if result.nil?
render json: { message: nil } render json: { message: nil }
elsif result[:error] elsif result[:error]
render json: { error: result[:error] }, status: :unprocessable_entity render json: { error: result[:error] }, status: :unprocessable_content
else else
response_data = { message: result[:message] } response_data = { message: result[:message] }
response_data[:follow_up_context] = result[:follow_up_context] if result[:follow_up_context] response_data[:follow_up_context] = result[:follow_up_context] if result[:follow_up_context]
@@ -69,3 +69,5 @@ class Api::V1::Accounts::Captain::TasksController < Api::V1::Accounts::BaseContr
authorize(:'captain/tasks') authorize(:'captain/tasks')
end end
end end
Api::V1::Accounts::Captain::TasksController.prepend_mod_with('Api::V1::Accounts::Captain::TasksController')
@@ -116,6 +116,8 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
# High-traffic accounts generate excessive DB writes when agents frequently switch between conversations. # High-traffic accounts generate excessive DB writes when agents frequently switch between conversations.
# Throttle last_seen updates to once per hour when there are no unread messages to reduce DB load. # Throttle last_seen updates to once per hour when there are no unread messages to reduce DB load.
# Always update immediately if there are unread messages to maintain accurate read/unread state. # Always update immediately if there are unread messages to maintain accurate read/unread state.
# Visiting a conversation should clear any unread inbox notifications for this conversation.
Notification::MarkConversationReadService.new(user: Current.user, account: Current.account, conversation: @conversation).perform
return update_last_seen_on_conversation(DateTime.now.utc, true) if assignee? && @conversation.assignee_unread_messages.any? return update_last_seen_on_conversation(DateTime.now.utc, true) if assignee? && @conversation.assignee_unread_messages.any?
return update_last_seen_on_conversation(DateTime.now.utc, false) if !assignee? && @conversation.unread_messages.any? return update_last_seen_on_conversation(DateTime.now.utc, false) if !assignee? && @conversation.unread_messages.any?
@@ -43,7 +43,15 @@ class Api::V1::Widget::MessagesController < Api::V1::Widget::BaseController
end end
def set_conversation def set_conversation
@conversation = create_conversation if conversation.nil? return unless conversation.nil?
@conversation = create_conversation
apply_labels if permitted_params[:labels].present?
end
def apply_labels
valid_labels = inbox.account.labels.where(title: permitted_params[:labels]).pluck(:title)
@conversation.update_labels(valid_labels) if valid_labels.present?
end end
def message_finder_params def message_finder_params
@@ -64,7 +72,14 @@ class Api::V1::Widget::MessagesController < Api::V1::Widget::BaseController
def permitted_params def permitted_params
# timestamp parameter is used in create conversation method # timestamp parameter is used in create conversation method
params.permit(:id, :before, :after, :website_token, contact: [:name, :email], message: [:content, :referer_url, :timestamp, :echo_id, :reply_to]) # custom_attributes and labels are applied when a new conversation is created alongside the first message
params.permit(
:id, :before, :after, :website_token,
contact: [:name, :email],
message: [:content, :referer_url, :timestamp, :echo_id, :reply_to],
custom_attributes: {},
labels: []
)
end end
def set_message def set_message
@@ -10,7 +10,12 @@ class DeviseOverrides::OmniauthCallbacksController < DeviseTokenAuth::OmniauthCa
private private
def sign_in_user def sign_in_user
# Capture before skip_confirmation! sets confirmed_at, which would
# make oauth_user_needs_password_reset? return false and skip the
# password reset for persisted unconfirmed users.
needs_password_reset = oauth_user_needs_password_reset?
@resource.skip_confirmation! if confirmable_enabled? @resource.skip_confirmation! if confirmable_enabled?
set_random_password_if_oauth_user if needs_password_reset
# once the resource is found and verified # once the resource is found and verified
# we can just send them to the login page again with the SSO params # we can just send them to the login page again with the SSO params
@@ -20,7 +25,10 @@ class DeviseOverrides::OmniauthCallbacksController < DeviseTokenAuth::OmniauthCa
end end
def sign_in_user_on_mobile def sign_in_user_on_mobile
# See comment in sign_in_user for why this is captured before skip_confirmation!
needs_password_reset = oauth_user_needs_password_reset?
@resource.skip_confirmation! if confirmable_enabled? @resource.skip_confirmation! if confirmable_enabled?
set_random_password_if_oauth_user if needs_password_reset
# once the resource is found and verified # once the resource is found and verified
# we can just send them to the login page again with the SSO params # we can just send them to the login page again with the SSO params
@@ -37,6 +45,7 @@ class DeviseOverrides::OmniauthCallbacksController < DeviseTokenAuth::OmniauthCa
return redirect_to login_page_url(error: 'business-account-only') unless validate_signup_email_is_business_domain? return redirect_to login_page_url(error: 'business-account-only') unless validate_signup_email_is_business_domain?
create_account_for_user create_account_for_user
set_random_password_if_oauth_user
token = @resource.send(:set_reset_password_token) token = @resource.send(:set_reset_password_token)
frontend_url = ENV.fetch('FRONTEND_URL', nil) frontend_url = ENV.fetch('FRONTEND_URL', nil)
redirect_to "#{frontend_url}/app/auth/password/edit?config=default&reset_password_token=#{token}" redirect_to "#{frontend_url}/app/auth/password/edit?config=default&reset_password_token=#{token}"
@@ -81,6 +90,15 @@ class DeviseOverrides::OmniauthCallbacksController < DeviseTokenAuth::OmniauthCa
Avatar::AvatarFromUrlJob.perform_later(@resource, auth_hash['info']['image']) Avatar::AvatarFromUrlJob.perform_later(@resource, auth_hash['info']['image'])
end end
def oauth_user_needs_password_reset?
@resource.present? && (@resource.new_record? || !@resource.confirmed?)
end
def set_random_password_if_oauth_user
# Password must satisfy secure_password requirements (uppercase, lowercase, number, special char)
@resource.update(password: "#{SecureRandom.hex(16)}aA1!") if @resource.persisted?
end
def default_devise_mapping def default_devise_mapping
'user' 'user'
end end
@@ -0,0 +1,101 @@
class Platform::Api::V1::EmailChannelMigrationsController < PlatformController
before_action :set_account
before_action :validate_account_permissible
before_action :validate_feature_flag
before_action :validate_params
def create
results = migrate_email_channels
render json: { results: results }, status: :ok
end
private
def set_account
@account = Account.find(params[:account_id])
end
def validate_account_permissible
return if @platform_app.platform_app_permissibles.find_by(permissible: @account)
render json: { error: 'Non permissible resource' }, status: :unauthorized
end
def validate_feature_flag
return if ActiveModel::Type::Boolean.new.cast(ENV.fetch('EMAIL_CHANNEL_MIGRATION', false))
render json: { error: 'Email channel migration is not enabled' }, status: :forbidden
end
def validate_params
return render json: { error: 'Missing migrations parameter' }, status: :unprocessable_entity if migration_params.blank?
return unless migration_params.size > MAX_MIGRATIONS
return render json: { error: "Too many migrations (max #{MAX_MIGRATIONS})" },
status: :unprocessable_entity
end
def migrate_email_channels
migration_params.map { |entry| migrate_single(entry) }
end
MAX_MIGRATIONS = 25
SUPPORTED_PROVIDERS = %w[google microsoft].freeze
def migrate_single(entry)
validate_provider!(entry[:provider])
ActiveRecord::Base.transaction do
channel = create_channel(entry)
inbox = create_inbox(channel, entry)
{ email: entry[:email], inbox_id: inbox.id, channel_id: channel.id, status: 'success' }
end
rescue StandardError => e
{ email: entry[:email], status: 'error', message: e.message }
end
def create_channel(entry)
Channel::Email.create!(
account_id: @account.id,
email: entry[:email],
provider: entry[:provider],
provider_config: entry[:provider_config]&.to_h,
imap_enabled: entry.fetch(:imap_enabled, true),
imap_address: entry[:imap_address] || default_imap_address(entry[:provider]),
imap_port: entry[:imap_port] || 993,
imap_login: entry[:imap_login] || entry[:email],
imap_enable_ssl: entry.fetch(:imap_enable_ssl, true)
)
end
def create_inbox(channel, entry)
@account.inboxes.create!(
name: entry[:inbox_name] || "Migrated #{entry[:provider]&.capitalize}: #{entry[:email]}",
channel: channel
)
end
def validate_provider!(provider)
return if SUPPORTED_PROVIDERS.include?(provider)
raise ArgumentError, "Unsupported provider '#{provider}'. Must be one of: #{SUPPORTED_PROVIDERS.join(', ')}"
end
def default_imap_address(provider)
case provider
when 'google' then 'imap.gmail.com'
when 'microsoft' then 'outlook.office365.com'
else ''
end
end
def migration_params
params.permit(migrations: [
:email, :provider, :inbox_name,
:imap_enabled, :imap_address, :imap_port, :imap_login, :imap_enable_ssl,
{ provider_config: {} }
])[:migrations]
end
end
@@ -1,6 +1,7 @@
class Public::Api::V1::Portals::ArticlesController < Public::Api::V1::Portals::BaseController class Public::Api::V1::Portals::ArticlesController < Public::Api::V1::Portals::BaseController
before_action :ensure_custom_domain_request, only: [:show, :index] before_action :ensure_custom_domain_request, only: [:show, :index]
before_action :portal before_action :portal
before_action :ensure_portal_feature_enabled
before_action :set_category, except: [:index, :show, :tracking_pixel] before_action :set_category, except: [:index, :show, :tracking_pixel]
before_action :set_article, only: [:show] before_action :set_article, only: [:show]
layout 'portal' layout 'portal'
@@ -1,6 +1,7 @@
class Public::Api::V1::Portals::CategoriesController < Public::Api::V1::Portals::BaseController class Public::Api::V1::Portals::CategoriesController < Public::Api::V1::Portals::BaseController
before_action :ensure_custom_domain_request, only: [:show, :index] before_action :ensure_custom_domain_request, only: [:show, :index]
before_action :portal before_action :portal
before_action :ensure_portal_feature_enabled
before_action :set_category, only: [:show] before_action :set_category, only: [:show]
layout 'portal' layout 'portal'
@@ -1,7 +1,8 @@
class Public::Api::V1::PortalsController < Public::Api::V1::Portals::BaseController class Public::Api::V1::PortalsController < Public::Api::V1::Portals::BaseController
before_action :ensure_custom_domain_request, only: [:show] before_action :ensure_custom_domain_request, only: [:show]
before_action :portal
before_action :redirect_to_portal_with_locale, only: [:show] before_action :redirect_to_portal_with_locale, only: [:show]
before_action :portal
before_action :ensure_portal_feature_enabled
layout 'portal' layout 'portal'
def show def show
@@ -24,6 +25,7 @@ class Public::Api::V1::PortalsController < Public::Api::V1::Portals::BaseControl
def redirect_to_portal_with_locale def redirect_to_portal_with_locale
return if params[:locale].present? return if params[:locale].present?
portal
redirect_to "/hc/#{@portal.slug}/#{@portal.default_locale}" redirect_to "/hc/#{@portal.slug}/#{@portal.default_locale}"
end end
end end
+7
View File
@@ -18,4 +18,11 @@ class PublicController < ActionController::Base
Please send us an email at support@chatwoot.com with the custom domain name and account API key" Please send us an email at support@chatwoot.com with the custom domain name and account API key"
}, status: :unauthorized and return }, status: :unauthorized and return
end end
def ensure_portal_feature_enabled
return unless ChatwootApp.chatwoot_cloud?
return if @portal.account.feature_enabled?('help_center')
render 'public/api/v1/portals/not_active', status: :payment_required
end
end end
+3 -1
View File
@@ -98,7 +98,9 @@ export default {
mql.onchange = e => setColorTheme(e.matches); mql.onchange = e => setColorTheme(e.matches);
}, },
setLocale(locale) { setLocale(locale) {
this.$root.$i18n.locale = locale; if (locale) {
this.$root.$i18n.locale = locale;
}
}, },
async initializeAccount() { async initializeAccount() {
await this.$store.dispatch('accounts/get'); await this.$store.dispatch('accounts/get');
@@ -15,12 +15,6 @@ class ApiClient {
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
get accountIdFromRoute() { get accountIdFromRoute() {
// eslint-disable-next-line no-underscore-dangle
if (window.__WOOT_ACCOUNT_ID__) {
// eslint-disable-next-line no-underscore-dangle
return window.__WOOT_ACCOUNT_ID__;
}
const isInsideAccountScopedURLs = const isInsideAccountScopedURLs =
window.location.pathname.includes('/app/accounts'); window.location.pathname.includes('/app/accounts');
@@ -14,8 +14,7 @@ class CacheEnabledApiClient extends ApiClient {
} }
get(cache = false) { get(cache = false) {
// eslint-disable-next-line no-underscore-dangle if (cache) {
if (cache && !window.__WOOT_ISOLATED_SHELL__) {
return this.getFromCache(); return this.getFromCache();
} }
+1 -12
View File
@@ -8,14 +8,7 @@ import {
} from '../store/utils/api'; } from '../store/utils/api';
export default { export default {
async validityCheck() { validityCheck() {
if (this.hasAuthToken()) {
const urlData = endPoints('profileUpdate');
const response = await axios.get(urlData.url);
// to match the response signature of the validityCheck endpoint
return Promise.resolve({ data: { payload: response } });
}
const urlData = endPoints('validityCheck'); const urlData = endPoints('validityCheck');
return axios.get(urlData.url); return axios.get(urlData.url);
}, },
@@ -38,10 +31,6 @@ export default {
hasAuthCookie() { hasAuthCookie() {
return !!Cookies.get('cw_d_session_info'); return !!Cookies.get('cw_d_session_info');
}, },
hasAuthToken() {
// eslint-disable-next-line no-underscore-dangle
return !!window.__WOOT_ACCESS_TOKEN__;
},
getAuthData() { getAuthData() {
if (this.hasAuthCookie()) { if (this.hasAuthCookie()) {
const savedAuthInfo = Cookies.get('cw_d_session_info'); const savedAuthInfo = Cookies.get('cw_d_session_info');
@@ -31,6 +31,12 @@ class CaptainCustomTools extends ApiClient {
delete(id) { delete(id) {
return axios.delete(`${this.url}/${id}`); return axios.delete(`${this.url}/${id}`);
} }
test(data = {}) {
return axios.post(`${this.url}/test`, {
custom_tool: data,
});
}
} }
export default new CaptainCustomTools(); export default new CaptainCustomTools();
+1 -7
View File
@@ -1,13 +1,7 @@
/* global axios */ /* global axios */
import CacheEnabledApiClient from './CacheEnabledApiClient'; import CacheEnabledApiClient from './CacheEnabledApiClient';
import ApiClient from './ApiClient';
// eslint-disable-next-line no-underscore-dangle class Inboxes extends CacheEnabledApiClient {
const BaseClass = window.__WOOT_ISOLATED_SHELL__
? ApiClient
: CacheEnabledApiClient;
class Inboxes extends BaseClass {
constructor() { constructor() {
super('inboxes', { accountScoped: true }); super('inboxes', { accountScoped: true });
} }
@@ -106,6 +106,10 @@ select {
&[disabled] { &[disabled] {
@apply field-disabled; @apply field-disabled;
} }
option:not(:disabled) {
@apply bg-n-solid-2 text-n-slate-12;
}
} }
// Textarea // Textarea
@@ -1,9 +1,7 @@
// scss-lint:disable PropertySortOrder // scss-lint:disable PropertySortOrder
// NEXT COLORS START
@layer base { @layer base {
:root, // NEXT COLORS START
:host { :root {
// slate // slate
--slate-1: 252 252 253; --slate-1: 252 252 253;
--slate-2: 249 249 251; --slate-2: 249 249 251;
@@ -140,48 +138,6 @@
--label-background: 247 247 247; --label-background: 247 247 247;
--label-border: 0, 0, 0, 0.04; --label-border: 0, 0, 0, 0.04;
// Bubble-specific colors (override these for custom theming)
--bubble-agent-bg: var(--solid-blue);
--bubble-agent-text: var(--slate-12);
--bubble-user-bg: var(--slate-4);
--bubble-user-text: var(--slate-12);
--bubble-private-bg: var(--solid-amber);
--bubble-private-text: var(--amber-12);
--bubble-bot-bg: var(--solid-iris);
--bubble-bot-text: var(--slate-12);
// Bubble border customization
--bubble-border-width: 0;
--bubble-agent-border: var(--blue-6);
--bubble-user-border: var(--slate-6);
--bubble-private-border: var(--amber-6);
--bubble-bot-border: var(--iris-6);
// Bubble spacing (ratio of 1 = default, 1.5 = 50% larger, 0.5 = 50% smaller)
--bubble-spacing-ratio: 1;
--bubble-radius: calc(0.75rem * var(--bubble-spacing-ratio));
--bubble-radius-sm: calc(0.125rem * var(--bubble-spacing-ratio));
--bubble-radius-md: calc(0.375rem * var(--bubble-spacing-ratio));
--bubble-radius-lg: calc(0.5rem * var(--bubble-spacing-ratio));
--bubble-padding-x: calc(1rem * var(--bubble-spacing-ratio));
--bubble-padding-y: calc(0.75rem * var(--bubble-spacing-ratio));
// Bubble meta text colors (per variant)
--bubble-agent-meta: var(--slate-11);
--bubble-user-meta: var(--slate-11);
--bubble-private-meta: var(--amber-12);
--bubble-bot-meta: var(--slate-11);
// Message status colors (per variant)
--bubble-agent-status: var(--slate-10);
--bubble-agent-status-read: 126 182 255;
--bubble-user-status: var(--slate-10);
--bubble-user-status-read: 126 182 255;
--bubble-private-status: var(--amber-11);
--bubble-private-status-read: 126 182 255;
--bubble-bot-status: var(--slate-10);
--bubble-bot-status-read: 126 182 255;
--alpha-1: 215, 215, 215, 0.22; --alpha-1: 215, 215, 215, 0.22;
--alpha-2: 196, 197, 198, 0.22; --alpha-2: 196, 197, 198, 0.22;
--alpha-3: 255, 255, 255, 0.96; --alpha-3: 255, 255, 255, 0.96;
@@ -191,8 +147,7 @@
--white-alpha: 255, 255, 255, 0.8; --white-alpha: 255, 255, 255, 0.8;
} }
.dark, .dark {
:host(.dark) {
// slate // slate
--slate-1: 17 17 19; --slate-1: 17 17 19;
--slate-2: 24 25 27; --slate-2: 24 25 27;
@@ -328,48 +283,6 @@
--label-background: 36 38 45; --label-background: 36 38 45;
--label-border: 255, 255, 255, 0.03; --label-border: 255, 255, 255, 0.03;
// Bubble-specific colors (override these for custom theming)
--bubble-agent-bg: var(--solid-blue);
--bubble-agent-text: var(--slate-12);
--bubble-user-bg: var(--slate-4);
--bubble-user-text: var(--slate-12);
--bubble-private-bg: var(--solid-amber);
--bubble-private-text: var(--amber-12);
--bubble-bot-bg: var(--solid-iris);
--bubble-bot-text: var(--slate-12);
// Bubble border customization
--bubble-border-width: 0;
--bubble-agent-border: var(--blue-6);
--bubble-user-border: var(--slate-6);
--bubble-private-border: var(--amber-6);
--bubble-bot-border: var(--iris-6);
// Bubble spacing (inherited from light mode, can be overridden)
--bubble-spacing-ratio: 1;
--bubble-radius: calc(0.75rem * var(--bubble-spacing-ratio));
--bubble-radius-sm: calc(0.125rem * var(--bubble-spacing-ratio));
--bubble-radius-md: calc(0.375rem * var(--bubble-spacing-ratio));
--bubble-radius-lg: calc(0.5rem * var(--bubble-spacing-ratio));
--bubble-padding-x: calc(1rem * var(--bubble-spacing-ratio));
--bubble-padding-y: calc(0.75rem * var(--bubble-spacing-ratio));
// Bubble meta text colors (per variant)
--bubble-agent-meta: var(--slate-11);
--bubble-user-meta: var(--slate-11);
--bubble-private-meta: var(--amber-12);
--bubble-bot-meta: var(--slate-11);
// Message status colors (per variant)
--bubble-agent-status: var(--slate-10);
--bubble-agent-status-read: 126 182 255;
--bubble-user-status: var(--slate-10);
--bubble-user-status-read: 126 182 255;
--bubble-private-status: var(--amber-11);
--bubble-private-status-read: 126 182 255;
--bubble-bot-status: var(--slate-10);
--bubble-bot-status-read: 126 182 255;
--alpha-1: 35, 36, 42, 0.8; --alpha-1: 35, 36, 42, 0.8;
--alpha-2: 147, 153, 176, 0.12; --alpha-2: 147, 153, 176, 0.12;
--alpha-3: 33, 34, 38, 0.95; --alpha-3: 33, 34, 38, 0.95;
@@ -380,3 +293,4 @@
--white-alpha: 255, 255, 255, 0.1; --white-alpha: 255, 255, 255, 0.1;
} }
} }
// NEXT COLORS END
@@ -1,207 +1,63 @@
<script setup> <script setup>
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { CONVERSATION_PRIORITY } from 'shared/constants/messages'; import { CONVERSATION_PRIORITY } from 'shared/constants/messages';
defineProps({ import Icon from 'dashboard/components-next/icon/Icon.vue';
const props = defineProps({
priority: { priority: {
type: String, type: String,
default: '', default: '',
}, },
showEmpty: {
type: Boolean,
default: false,
},
});
const { t } = useI18n();
const icons = {
[CONVERSATION_PRIORITY.URGENT]: 'i-woot-priority-urgent',
[CONVERSATION_PRIORITY.HIGH]: 'i-woot-priority-high',
[CONVERSATION_PRIORITY.MEDIUM]: 'i-woot-priority-medium',
[CONVERSATION_PRIORITY.LOW]: 'i-woot-priority-low',
};
const priorityLabels = {
[CONVERSATION_PRIORITY.URGENT]: 'CONVERSATION.PRIORITY.OPTIONS.URGENT',
[CONVERSATION_PRIORITY.HIGH]: 'CONVERSATION.PRIORITY.OPTIONS.HIGH',
[CONVERSATION_PRIORITY.MEDIUM]: 'CONVERSATION.PRIORITY.OPTIONS.MEDIUM',
[CONVERSATION_PRIORITY.LOW]: 'CONVERSATION.PRIORITY.OPTIONS.LOW',
};
const iconName = computed(() => {
if (props.priority && icons[props.priority]) {
return icons[props.priority];
}
return props.showEmpty ? 'i-woot-priority-empty' : '';
});
const tooltipContent = computed(() => {
if (props.priority && priorityLabels[props.priority]) {
return t(priorityLabels[props.priority]);
}
if (props.showEmpty) {
return t('CONVERSATION.PRIORITY.OPTIONS.NONE');
}
return '';
}); });
</script> </script>
<!-- eslint-disable vue/no-static-inline-styles -->
<template> <template>
<div class="inline-flex items-center justify-center rounded-md"> <Icon
<!-- Low Priority --> v-tooltip.top="{
<svg content: tooltipContent,
v-if="priority === CONVERSATION_PRIORITY.LOW" delay: { show: 500, hide: 0 },
width="20" }"
height="20" :icon="iconName"
viewBox="0 0 20 20" class="size-4 text-n-slate-5"
fill="none" />
xmlns="http://www.w3.org/2000/svg"
>
<mask
id="mask0_2030_12879"
style="mask-type: alpha"
maskUnits="userSpaceOnUse"
x="0"
y="0"
width="20"
height="20"
>
<rect width="20" height="20" fill="#D9D9D9" />
</mask>
<g mask="url(#mask0_2030_12879)">
<rect
x="3.33301"
y="10"
width="3.33333"
height="6.66667"
rx="1.66667"
class="fill-n-amber-9"
/>
<rect
x="8.33301"
y="6.6665"
width="3.33333"
height="10"
rx="1.66667"
class="fill-n-slate-6"
/>
<rect
x="13.333"
y="3.3335"
width="3.33333"
height="13.3333"
rx="1.66667"
class="fill-n-slate-6"
/>
</g>
</svg>
<!-- Medium Priority -->
<svg
v-if="priority === CONVERSATION_PRIORITY.MEDIUM"
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<mask
id="mask0_2030_12879"
style="mask-type: alpha"
maskUnits="userSpaceOnUse"
x="0"
y="0"
width="20"
height="20"
>
<rect width="20" height="20" fill="#D9D9D9" />
</mask>
<g mask="url(#mask0_2030_12879)">
<rect
x="3.33301"
y="10"
width="3.33333"
height="6.66667"
rx="1.66667"
class="fill-n-amber-9"
/>
<rect
x="8.33301"
y="6.6665"
width="3.33333"
height="10"
rx="1.66667"
class="fill-n-amber-9"
/>
<rect
x="13.333"
y="3.3335"
width="3.33333"
height="13.3333"
rx="1.66667"
class="fill-n-slate-6"
/>
</g>
</svg>
<!-- High Priority -->
<svg
v-if="priority === CONVERSATION_PRIORITY.HIGH"
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<mask
id="mask0_2030_12879"
style="mask-type: alpha"
maskUnits="userSpaceOnUse"
x="0"
y="0"
width="20"
height="20"
>
<rect width="20" height="20" fill="#D9D9D9" />
</mask>
<g mask="url(#mask0_2030_12879)">
<rect
x="3.33301"
y="10"
width="3.33333"
height="6.66667"
rx="1.66667"
class="fill-n-amber-9"
/>
<rect
x="8.33301"
y="6.6665"
width="3.33333"
height="10"
rx="1.66667"
class="fill-n-amber-9"
/>
<rect
x="13.333"
y="3.3335"
width="3.33333"
height="13.3333"
rx="1.66667"
class="fill-n-amber-9"
/>
</g>
</svg>
<!-- Urgent Priority -->
<svg
v-if="priority === CONVERSATION_PRIORITY.URGENT"
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<mask
id="mask0_2030_12879"
style="mask-type: alpha"
maskUnits="userSpaceOnUse"
x="0"
y="0"
width="20"
height="20"
>
<rect width="20" height="20" fill="#D9D9D9" />
</mask>
<g mask="url(#mask0_2030_12879)">
<rect
x="3.33301"
y="10"
width="3.33333"
height="6.66667"
rx="1.66667"
class="fill-n-ruby-9"
/>
<rect
x="8.33301"
y="6.6665"
width="3.33333"
height="10"
rx="1.66667"
class="fill-n-ruby-9"
/>
<rect
x="13.333"
y="3.3335"
width="3.33333"
height="13.3333"
rx="1.66667"
class="fill-n-ruby-9"
/>
</g>
</svg>
</div>
</template> </template>
@@ -12,6 +12,7 @@ import {
import CardLayout from 'dashboard/components-next/CardLayout.vue'; import CardLayout from 'dashboard/components-next/CardLayout.vue';
import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.vue'; import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.vue';
import Button from 'dashboard/components-next/button/Button.vue'; import Button from 'dashboard/components-next/button/Button.vue';
import Checkbox from 'dashboard/components-next/checkbox/Checkbox.vue';
const props = defineProps({ const props = defineProps({
id: { id: {
@@ -34,14 +35,34 @@ const props = defineProps({
type: Number, type: Number,
required: true, required: true,
}, },
isSelected: {
type: Boolean,
default: false,
},
selectable: {
type: Boolean,
default: false,
},
showSelectionControl: {
type: Boolean,
default: false,
},
showMenu: {
type: Boolean,
default: true,
},
}); });
const emit = defineEmits(['action']); const emit = defineEmits(['action', 'select', 'hover']);
const { checkPermissions } = usePolicy(); const { checkPermissions } = usePolicy();
const { t } = useI18n(); const { t } = useI18n();
const [showActionsDropdown, toggleDropdown] = useToggle(); const [showActionsDropdown, toggleDropdown] = useToggle();
const modelValue = computed({
get: () => props.isSelected,
set: () => emit('select', props.id),
});
const menuItems = computed(() => { const menuItems = computed(() => {
const allOptions = [ const allOptions = [
@@ -79,12 +100,23 @@ const handleAction = ({ action, value }) => {
</script> </script>
<template> <template>
<CardLayout> <CardLayout
:selectable="selectable"
class="relative"
@mouseenter="emit('hover', true)"
@mouseleave="emit('hover', false)"
>
<div
v-show="showSelectionControl"
class="absolute top-7 ltr:left-3 rtl:right-3"
>
<Checkbox v-model="modelValue" />
</div>
<div class="flex gap-1 justify-between w-full"> <div class="flex gap-1 justify-between w-full">
<span class="text-base text-n-slate-12 line-clamp-1"> <span class="text-base text-n-slate-12 line-clamp-1">
{{ name }} {{ name }}
</span> </span>
<div class="flex gap-2 items-center"> <div v-if="showMenu" class="flex gap-2 items-center">
<div <div
v-on-clickaway="() => toggleDropdown(false)" v-on-clickaway="() => toggleDropdown(false)"
class="flex relative items-center group" class="flex relative items-center group"
@@ -21,16 +21,22 @@ const emit = defineEmits(['deleteSuccess']);
const { t } = useI18n(); const { t } = useI18n();
const store = useStore(); const store = useStore();
const bulkDeleteDialogRef = ref(null); const bulkDeleteDialogRef = ref(null);
const i18nKey = computed(() => props.type.toUpperCase()); const i18nKey = computed(() => {
const i18nTypeMap = {
AssistantResponse: 'RESPONSES',
AssistantDocument: 'DOCUMENTS',
};
return i18nTypeMap[props.type];
});
const handleBulkDelete = async ids => { const handleBulkDelete = async ids => {
if (!ids) return; if (!ids) return;
try { try {
await store.dispatch( await store.dispatch('captainBulkActions/handleBulkDelete', {
'captainBulkActions/handleBulkDelete', ids: Array.from(props.bulkIds),
Array.from(props.bulkIds) type: props.type,
); });
emit('deleteSuccess'); emit('deleteSuccess');
useAlert(t(`CAPTAIN.${i18nKey.value}.BULK_DELETE.SUCCESS_MESSAGE`)); useAlert(t(`CAPTAIN.${i18nKey.value}.BULK_DELETE.SUCCESS_MESSAGE`));
@@ -101,12 +101,9 @@ const authTypeLabel = computed(() => {
</Policy> </Policy>
</div> </div>
</div> </div>
<div class="flex items-center justify-between w-full gap-4"> <div class="flex items-center justify-between w-full gap-4 min-w-0">
<div class="flex items-center gap-3 flex-1"> <div class="flex items-center gap-3 flex-1 min-w-0">
<span <span v-if="description" class="text-sm truncate text-n-slate-11">
v-if="description"
class="text-sm truncate text-n-slate-11 flex-1"
>
{{ description }} {{ description }}
</span> </span>
<span <span
@@ -1,9 +1,10 @@
<script setup> <script setup>
import { reactive, computed, useTemplateRef, watch } from 'vue'; import { reactive, computed, ref, useTemplateRef, watch } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useVuelidate } from '@vuelidate/core'; import { useVuelidate } from '@vuelidate/core';
import { required } from '@vuelidate/validators'; import { required, maxLength } from '@vuelidate/validators';
import { useMapGetter } from 'dashboard/composables/store'; import { useMapGetter } from 'dashboard/composables/store';
import CustomToolsAPI from 'dashboard/api/captain/customTools';
import Input from 'dashboard/components-next/input/Input.vue'; import Input from 'dashboard/components-next/input/Input.vue';
import TextArea from 'dashboard/components-next/textarea/TextArea.vue'; import TextArea from 'dashboard/components-next/textarea/TextArea.vue';
@@ -72,8 +73,12 @@ const DEFAULT_PARAM = {
required: false, required: false,
}; };
// OpenAI enforces a 64-char limit on function names. The backend slug is
// "custom_" (7 chars) + parameterized title, so cap the title conservatively.
const MAX_TOOL_NAME_LENGTH = 55;
const validationRules = { const validationRules = {
title: { required }, title: { required, maxLength: maxLength(MAX_TOOL_NAME_LENGTH) },
endpoint_url: { required }, endpoint_url: { required },
http_method: { required }, http_method: { required },
auth_type: { required }, auth_type: { required },
@@ -103,9 +108,15 @@ const isLoading = computed(() =>
); );
const getErrorMessage = (field, errorKey) => { const getErrorMessage = (field, errorKey) => {
return v$.value[field].$error if (!v$.value[field].$error) return '';
? t(`CAPTAIN.CUSTOM_TOOLS.FORM.${errorKey}.ERROR`)
: ''; const failedRule = v$.value[field].$errors[0]?.$validator;
if (failedRule === 'maxLength') {
return t(`CAPTAIN.CUSTOM_TOOLS.FORM.${errorKey}.MAX_LENGTH_ERROR`, {
max: MAX_TOOL_NAME_LENGTH,
});
}
return t(`CAPTAIN.CUSTOM_TOOLS.FORM.${errorKey}.ERROR`);
}; };
const formErrors = computed(() => ({ const formErrors = computed(() => ({
@@ -140,6 +151,30 @@ const handleSubmit = async () => {
emit('submit', state); emit('submit', state);
}; };
const isTesting = ref(false);
const testResult = ref(null);
const isTestDisabled = computed(
() => state.endpoint_url.includes('{{') || !!state.request_template
);
const handleTest = async () => {
if (!state.endpoint_url) return;
isTesting.value = true;
testResult.value = null;
try {
const { data } = await CustomToolsAPI.test(state);
const isOk = data.status >= 200 && data.status < 300;
testResult.value = { success: isOk, status: data.status };
} catch (e) {
const message =
e.response?.data?.error || t('CAPTAIN.CUSTOM_TOOLS.TEST.ERROR');
testResult.value = { success: false, message };
} finally {
isTesting.value = false;
}
};
</script> </script>
<template> <template>
@@ -248,6 +283,45 @@ const handleSubmit = async () => {
class="[&_textarea]:font-mono" class="[&_textarea]:font-mono"
/> />
<div class="flex flex-col gap-2">
<Button
type="button"
variant="faded"
color="slate"
icon="i-lucide-play"
:label="t('CAPTAIN.CUSTOM_TOOLS.TEST.BUTTON')"
:is-loading="isTesting"
:disabled="isTesting || !state.endpoint_url || isTestDisabled"
@click="handleTest"
/>
<p v-if="isTestDisabled" class="text-xs text-n-slate-11">
{{ t('CAPTAIN.CUSTOM_TOOLS.TEST.DISABLED_HINT') }}
</p>
<div
v-if="testResult"
class="flex items-center gap-2 px-3 py-2 text-xs rounded-lg"
:class="
testResult.success
? 'bg-n-teal-2 text-n-teal-11'
: 'bg-n-ruby-2 text-n-ruby-11'
"
>
<span
:class="
testResult.success ? 'i-lucide-check-circle' : 'i-lucide-x-circle'
"
class="size-3.5 shrink-0"
/>
{{
testResult.status
? t('CAPTAIN.CUSTOM_TOOLS.TEST.SUCCESS', {
status: testResult.status,
})
: testResult.message
}}
</div>
</div>
<div class="flex gap-3 justify-between items-center w-full"> <div class="flex gap-3 justify-between items-center w-full">
<Button <Button
type="button" type="button"
@@ -1,8 +1,11 @@
<script setup> <script setup>
import { useAccount } from 'dashboard/composables/useAccount';
import EmptyStateLayout from 'dashboard/components-next/EmptyStateLayout.vue'; import EmptyStateLayout from 'dashboard/components-next/EmptyStateLayout.vue';
import FeatureSpotlight from 'dashboard/components-next/feature-spotlight/FeatureSpotlight.vue';
import Button from 'dashboard/components-next/button/Button.vue'; import Button from 'dashboard/components-next/button/Button.vue';
const emit = defineEmits(['click']); const emit = defineEmits(['click']);
const { isOnChatwootCloud } = useAccount();
const onClick = () => { const onClick = () => {
emit('click'); emit('click');
@@ -10,6 +13,15 @@ const onClick = () => {
</script> </script>
<template> <template>
<FeatureSpotlight
:title="$t('CAPTAIN.CUSTOM_TOOLS.EMPTY_STATE.FEATURE_SPOTLIGHT.TITLE')"
:note="$t('CAPTAIN.CUSTOM_TOOLS.EMPTY_STATE.FEATURE_SPOTLIGHT.NOTE')"
fallback-thumbnail="/assets/images/dashboard/captain/assistant-light.svg"
fallback-thumbnail-dark="/assets/images/dashboard/captain/assistant-dark.svg"
learn-more-url="https://chwt.app/hc/captain-tools"
class="mb-8"
:hide-actions="!isOnChatwootCloud"
/>
<EmptyStateLayout <EmptyStateLayout
:title="$t('CAPTAIN.CUSTOM_TOOLS.EMPTY_STATE.TITLE')" :title="$t('CAPTAIN.CUSTOM_TOOLS.EMPTY_STATE.TITLE')"
:subtitle="$t('CAPTAIN.CUSTOM_TOOLS.EMPTY_STATE.SUBTITLE')" :subtitle="$t('CAPTAIN.CUSTOM_TOOLS.EMPTY_STATE.SUBTITLE')"
@@ -134,11 +134,6 @@ const props = defineProps({
senderId: { type: Number, default: null }, senderId: { type: Number, default: null },
senderType: { type: String, default: null }, senderType: { type: String, default: null },
sourceId: { type: String, default: '' }, // eslint-disable-line vue/no-unused-properties sourceId: { type: String, default: '' }, // eslint-disable-line vue/no-unused-properties
forceAlignTo: {
type: String,
default: null,
validator: value => value === null || ['left', 'right'].includes(value),
},
}); });
const emit = defineEmits(['retry']); const emit = defineEmits(['retry']);
@@ -231,16 +226,12 @@ const isBotOrAgentMessage = computed(() => {
* @returns {import('vue').ComputedRef<'left'|'right'|'center'>} The computed orientation * @returns {import('vue').ComputedRef<'left'|'right'|'center'>} The computed orientation
*/ */
const orientation = computed(() => { const orientation = computed(() => {
if (props.messageType === MESSAGE_TYPES.ACTIVITY) return ORIENTATION.CENTER;
if (props.forceAlignTo) {
return props.forceAlignTo === 'left' ? ORIENTATION.LEFT : ORIENTATION.RIGHT;
}
if (isBotOrAgentMessage.value) { if (isBotOrAgentMessage.value) {
return ORIENTATION.RIGHT; return ORIENTATION.RIGHT;
} }
if (props.messageType === MESSAGE_TYPES.ACTIVITY) return ORIENTATION.CENTER;
return ORIENTATION.LEFT; return ORIENTATION.LEFT;
}); });
@@ -255,10 +246,6 @@ const flexOrientationClass = computed(() => {
}); });
const gridClass = computed(() => { const gridClass = computed(() => {
if (props.forceAlignTo) {
return 'grid gap-y-2';
}
const map = { const map = {
[ORIENTATION.LEFT]: 'grid grid-cols-1fr', [ORIENTATION.LEFT]: 'grid grid-cols-1fr',
[ORIENTATION.RIGHT]: 'grid grid-cols-[1fr_24px]', [ORIENTATION.RIGHT]: 'grid grid-cols-[1fr_24px]',
@@ -268,14 +255,6 @@ const gridClass = computed(() => {
}); });
const gridTemplate = computed(() => { const gridTemplate = computed(() => {
if (props.forceAlignTo) {
return `
"avatar"
"bubble"
"meta"
`;
}
const map = { const map = {
[ORIENTATION.LEFT]: ` [ORIENTATION.LEFT]: `
"bubble" "bubble"
@@ -298,19 +277,11 @@ const shouldGroupWithNext = computed(() => {
const shouldShowAvatar = computed(() => { const shouldShowAvatar = computed(() => {
if (props.messageType === MESSAGE_TYPES.ACTIVITY) return false; if (props.messageType === MESSAGE_TYPES.ACTIVITY) return false;
if (props.forceAlignTo) return true;
if (orientation.value === ORIENTATION.LEFT) return false; if (orientation.value === ORIENTATION.LEFT) return false;
return true; return true;
}); });
const shouldShowSenderName = computed(() => {
if (props.messageType === MESSAGE_TYPES.ACTIVITY) return false;
if (!props.forceAlignTo) return false;
return true;
});
const componentToRender = computed(() => { const componentToRender = computed(() => {
if (props.isEmailInbox && !props.private) { if (props.isEmailInbox && !props.private) {
const emailInboxTypes = [MESSAGE_TYPES.INCOMING, MESSAGE_TYPES.OUTGOING]; const emailInboxTypes = [MESSAGE_TYPES.INCOMING, MESSAGE_TYPES.OUTGOING];
@@ -373,8 +344,6 @@ const componentToRender = computed(() => {
}); });
const shouldShowContextMenu = computed(() => { const shouldShowContextMenu = computed(() => {
// eslint-disable-next-line no-underscore-dangle
if (window.__WOOT_DISABLE_CONTEXT_MENU__) return false;
return !props.contentAttributes?.isUnsupported; return !props.contentAttributes?.isUnsupported;
}); });
@@ -441,12 +410,6 @@ const shouldRenderMessage = computed(() => {
}); });
function openContextMenu(e) { function openContextMenu(e) {
// eslint-disable-next-line no-underscore-dangle
if (window.__WOOT_DISABLE_CONTEXT_MENU__) {
e.preventDefault();
return;
}
const shouldSkipContextMenu = const shouldSkipContextMenu =
e.target?.classList.contains('skip-context-menu') || e.target?.classList.contains('skip-context-menu') ||
['a', 'img'].includes(e.target?.tagName.toLowerCase()); ['a', 'img'].includes(e.target?.tagName.toLowerCase());
@@ -527,8 +490,7 @@ const avatarTooltip = computed(() => {
}); });
const setupHighlightTimer = () => { const setupHighlightTimer = () => {
// This is a defensive check, since in the ISOLATED shell mode, there might be no route.query if (Number(route.query.messageId) !== Number(props.id)) {
if (Number(route?.query?.messageId) !== Number(props.id)) {
return; return;
} }
@@ -586,23 +548,15 @@ provideMessageContext({
<div <div
v-if="!shouldGroupWithNext && shouldShowAvatar" v-if="!shouldGroupWithNext && shouldShowAvatar"
v-tooltip.left-end="avatarTooltip" v-tooltip.left-end="avatarTooltip"
class="[grid-area:avatar] flex items-end gap-2" class="[grid-area:avatar] flex items-end"
> >
<Avatar v-bind="avatarInfo" :size="24" /> <Avatar v-bind="avatarInfo" :size="24" />
<span
v-if="shouldShowSenderName"
class="text-sm font-semibold text-n-slate-12 pb-0.5"
>
{{ avatarInfo.name }}
</span>
</div> </div>
<div <div
class="[grid-area:bubble] flex" class="[grid-area:bubble] flex"
:class="{ :class="{
'ltr:ml-8 rtl:mr-8 justify-end': 'ltr:ml-8 rtl:mr-8 justify-end': orientation === ORIENTATION.RIGHT,
!props.forceAlignTo && orientation === ORIENTATION.RIGHT, 'ltr:mr-8 rtl:ml-8': orientation === ORIENTATION.LEFT,
'ltr:mr-8 rtl:ml-8':
!props.forceAlignTo && orientation === ORIENTATION.LEFT,
'min-w-0': variant === MESSAGE_VARIANTS.EMAIL, 'min-w-0': variant === MESSAGE_VARIANTS.EMAIL,
}" }"
@contextmenu="openContextMenu($event)" @contextmenu="openContextMenu($event)"
@@ -1,7 +1,7 @@
<script setup> <script setup>
import { defineProps, computed, reactive } from 'vue'; import { defineProps, computed, reactive } from 'vue';
import Message from './Message.vue'; import Message from './Message.vue';
import shouldGroupWithNext from './groupWithNext.js'; import { MESSAGE_TYPES } from './constants.js';
import { useCamelCase } from 'dashboard/composables/useTransformKeys'; import { useCamelCase } from 'dashboard/composables/useTransformKeys';
import { useMapGetter } from 'dashboard/composables/store.js'; import { useMapGetter } from 'dashboard/composables/store.js';
import MessageApi from 'dashboard/api/inbox/message.js'; import MessageApi from 'dashboard/api/inbox/message.js';
@@ -90,6 +90,39 @@ const fetchReplyMessage = async (messageId, conversationId) => {
} }
}; };
/**
* Determines if a message should be grouped with the next message
* @param {Number} index - Index of the current message
* @param {Array} searchList - Array of messages to check
* @returns {Boolean} - Whether the message should be grouped with next
*/
const shouldGroupWithNext = (index, searchList) => {
if (index === searchList.length - 1) return false;
const current = searchList[index];
const next = searchList[index + 1];
if (next.status === 'failed') return false;
const nextSenderId = next.senderId ?? next.sender?.id;
const currentSenderId = current.senderId ?? current.sender?.id;
const hasSameSender = nextSenderId === currentSenderId;
const nextMessageType = next.messageType;
const currentMessageType = current.messageType;
const areBothTemplates =
nextMessageType === MESSAGE_TYPES.TEMPLATE &&
currentMessageType === MESSAGE_TYPES.TEMPLATE;
if (!hasSameSender || areBothTemplates) return false;
if (currentMessageType !== nextMessageType) return false;
// Check if messages are in the same minute by rounding down to nearest minute
return Math.floor(next.createdAt / 60) === Math.floor(current.createdAt / 60);
};
/** /**
* Gets the message that was replied to * Gets the message that was replied to
* @param {Object} parentMessage - The message containing the reply reference * @param {Object} parentMessage - The message containing the reply reference
@@ -9,21 +9,6 @@ import { useMessageContext } from './provider.js';
import { MESSAGE_STATUS, MESSAGE_TYPES } from './constants'; import { MESSAGE_STATUS, MESSAGE_TYPES } from './constants';
const {
status,
isPrivate,
createdAt,
sourceId,
messageType,
contentAttributes,
inboxId,
} = useMessageContext();
// Resolve channel type from the message's own inbox so that the status
// indicator does not depend on `getSelectedChat` being populated. In the
// Agent SDK shell `setActiveChat` runs from a watcher in MessageList and can
// race with the first render of MessageMeta, leaving `currentChat` empty and
// every channel check returning false (the spinner stays forever).
const { const {
isAFacebookInbox, isAFacebookInbox,
isALineChannel, isALineChannel,
@@ -36,7 +21,16 @@ const {
isAnEmailChannel, isAnEmailChannel,
isAnInstagramChannel, isAnInstagramChannel,
isATiktokChannel, isATiktokChannel,
} = useInbox(inboxId.value); } = useInbox();
const {
status,
isPrivate,
createdAt,
sourceId,
messageType,
contentAttributes,
} = useMessageContext();
const readableTime = computed(() => const readableTime = computed(() =>
messageTimestamp(createdAt.value, 'LLL d, h:mm a') messageTimestamp(createdAt.value, 'LLL d, h:mm a')
@@ -2,8 +2,7 @@
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import { useIntervalFn } from '@vueuse/core'; import { useIntervalFn } from '@vueuse/core';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { MESSAGE_STATUS, MESSAGE_VARIANTS } from './constants'; import { MESSAGE_STATUS } from './constants';
import { useMessageContext } from './provider.js';
import Icon from 'next/icon/Icon.vue'; import Icon from 'next/icon/Icon.vue';
@@ -16,19 +15,6 @@ const { status } = defineProps({
}); });
const { t } = useI18n(); const { t } = useI18n();
const { variant } = useMessageContext();
const variantPrefix = computed(() => {
const prefixMap = {
[MESSAGE_VARIANTS.AGENT]: 'agent',
[MESSAGE_VARIANTS.USER]: 'user',
[MESSAGE_VARIANTS.PRIVATE]: 'private',
[MESSAGE_VARIANTS.BOT]: 'bot',
[MESSAGE_VARIANTS.TEMPLATE]: 'bot',
[MESSAGE_VARIANTS.EMAIL]: 'agent',
};
return prefixMap[variant.value] || 'agent';
});
const progresIconSequence = [ const progresIconSequence = [
'i-lucide-clock-1', 'i-lucide-clock-1',
@@ -68,44 +54,14 @@ const statusIcon = computed(() => {
return statusIconMap[status]; return statusIconMap[status];
}); });
const statusColorMap = {
agent: {
[MESSAGE_STATUS.SENT]: 'text-[rgb(var(--bubble-agent-status))]',
[MESSAGE_STATUS.DELIVERED]: 'text-[rgb(var(--bubble-agent-status))]',
[MESSAGE_STATUS.READ]: 'text-[rgb(var(--bubble-agent-status-read))]',
},
user: {
[MESSAGE_STATUS.SENT]: 'text-[rgb(var(--bubble-user-status))]',
[MESSAGE_STATUS.DELIVERED]: 'text-[rgb(var(--bubble-user-status))]',
[MESSAGE_STATUS.READ]: 'text-[rgb(var(--bubble-user-status-read))]',
},
private: {
[MESSAGE_STATUS.SENT]: 'text-[rgb(var(--bubble-private-status))]',
[MESSAGE_STATUS.DELIVERED]: 'text-[rgb(var(--bubble-private-status))]',
[MESSAGE_STATUS.READ]: 'text-[rgb(var(--bubble-private-status-read))]',
},
bot: {
[MESSAGE_STATUS.SENT]: 'text-[rgb(var(--bubble-bot-status))]',
[MESSAGE_STATUS.DELIVERED]: 'text-[rgb(var(--bubble-bot-status))]',
[MESSAGE_STATUS.READ]: 'text-[rgb(var(--bubble-bot-status-read))]',
},
};
const statusColor = computed(() => { const statusColor = computed(() => {
const variantMap = const statusIconMap = {
statusColorMap[variantPrefix.value] || statusColorMap.agent; [MESSAGE_STATUS.SENT]: 'text-n-slate-10',
return variantMap[status]; [MESSAGE_STATUS.DELIVERED]: 'text-n-slate-10',
}); [MESSAGE_STATUS.READ]: 'text-[#7EB6FF]',
};
const progressColorMap = { return statusIconMap[status];
agent: 'text-[rgb(var(--bubble-agent-status))]',
user: 'text-[rgb(var(--bubble-user-status))]',
private: 'text-[rgb(var(--bubble-private-status))]',
bot: 'text-[rgb(var(--bubble-bot-status))]',
};
const progressColor = computed(() => {
return progressColorMap[variantPrefix.value] || progressColorMap.agent;
}); });
const tooltipText = computed(() => { const tooltipText = computed(() => {
@@ -125,7 +81,7 @@ const tooltipText = computed(() => {
v-if="status === MESSAGE_STATUS.PROGRESS" v-if="status === MESSAGE_STATUS.PROGRESS"
v-tooltip.top-start="tooltipText" v-tooltip.top-start="tooltipText"
:icon="progessIcon" :icon="progessIcon"
:class="progressColor" class="text-n-slate-10"
/> />
<Icon <Icon
v-else v-else
@@ -1,45 +0,0 @@
<template>
<svg
class="w-8 h-4"
viewBox="0 0 120 30"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
>
<circle cx="15" cy="15" r="12">
<animate
attributeName="cy"
from="15"
to="5"
begin="0s"
dur="0.9s"
values="15;5;15;15;15;15"
calcMode="linear"
repeatCount="indefinite"
/>
</circle>
<circle cx="55" cy="15" r="12">
<animate
attributeName="cy"
from="15"
to="5"
begin="0.1s"
dur="0.9s"
values="15;5;15;15;15;15"
calcMode="linear"
repeatCount="indefinite"
/>
</circle>
<circle cx="95" cy="15" r="12">
<animate
attributeName="cy"
from="15"
to="5"
begin="0.2s"
dur="0.9s"
values="15;5;15;15;15;15"
calcMode="linear"
repeatCount="indefinite"
/>
</circle>
</svg>
</template>
@@ -3,31 +3,19 @@ import { computed } from 'vue';
import BaseBubble from './Base.vue'; import BaseBubble from './Base.vue';
import AudioChip from 'next/message/chips/Audio.vue'; import AudioChip from 'next/message/chips/Audio.vue';
import { useMessageContext } from '../provider.js'; import { useMessageContext } from '../provider.js';
import { MESSAGE_VARIANTS } from '../constants';
const { attachments, variant } = useMessageContext(); const { attachments } = useMessageContext();
const attachment = computed(() => { const attachment = computed(() => {
return attachments.value[0]; return attachments.value[0];
}); });
const textClass = computed(() => {
const textClassMap = {
[MESSAGE_VARIANTS.AGENT]: 'text-[rgb(var(--bubble-agent-text))]',
[MESSAGE_VARIANTS.USER]: 'text-[rgb(var(--bubble-user-text))]',
[MESSAGE_VARIANTS.PRIVATE]: 'text-[rgb(var(--bubble-private-text))]',
[MESSAGE_VARIANTS.BOT]: 'text-[rgb(var(--bubble-bot-text))]',
};
return textClassMap[variant.value] || 'text-[rgb(var(--bubble-agent-text))]';
});
</script> </script>
<template> <template>
<BaseBubble class="bg-transparent" data-bubble-name="audio"> <BaseBubble class="bg-transparent" data-bubble-name="audio">
<AudioChip <AudioChip
:attachment="attachment" :attachment="attachment"
class="p-2 skip-context-menu" class="p-2 text-n-slate-12 skip-context-menu"
:class="textClass"
/> />
</BaseBubble> </BaseBubble>
</template> </template>
@@ -20,30 +20,25 @@ const { variant, orientation, inReplyTo, shouldGroupWithNext } =
const { t } = useI18n(); const { t } = useI18n();
const varaintBaseMap = { const varaintBaseMap = {
[MESSAGE_VARIANTS.AGENT]: [MESSAGE_VARIANTS.AGENT]: 'bg-n-solid-blue text-n-slate-12',
'bg-[rgb(var(--bubble-agent-bg))] text-[rgb(var(--bubble-agent-text))] border-[length:var(--bubble-border-width)] border-[rgb(var(--bubble-agent-border))]',
[MESSAGE_VARIANTS.PRIVATE]: [MESSAGE_VARIANTS.PRIVATE]:
'bg-[rgb(var(--bubble-private-bg))] text-[rgb(var(--bubble-private-text))] border-[length:var(--bubble-border-width)] border-[rgb(var(--bubble-private-border))] [&_.prosemirror-mention-node]:font-semibold', 'bg-n-solid-amber text-n-amber-12 [&_.prosemirror-mention-node]:font-semibold',
[MESSAGE_VARIANTS.USER]: [MESSAGE_VARIANTS.USER]: 'bg-n-slate-4 text-n-slate-12',
'bg-[rgb(var(--bubble-user-bg))] text-[rgb(var(--bubble-user-text))] border-[length:var(--bubble-border-width)] border-[rgb(var(--bubble-user-border))]',
[MESSAGE_VARIANTS.ACTIVITY]: 'bg-n-alpha-1 text-n-slate-11 text-sm', [MESSAGE_VARIANTS.ACTIVITY]: 'bg-n-alpha-1 text-n-slate-11 text-sm',
[MESSAGE_VARIANTS.BOT]: [MESSAGE_VARIANTS.BOT]: 'bg-n-solid-iris text-n-slate-12',
'bg-[rgb(var(--bubble-bot-bg))] text-[rgb(var(--bubble-bot-text))] border-[length:var(--bubble-border-width)] border-[rgb(var(--bubble-bot-border))]', [MESSAGE_VARIANTS.TEMPLATE]: 'bg-n-solid-iris text-n-slate-12',
[MESSAGE_VARIANTS.TEMPLATE]: [MESSAGE_VARIANTS.ERROR]: 'bg-n-ruby-4 text-n-ruby-12',
'bg-[rgb(var(--bubble-bot-bg))] text-[rgb(var(--bubble-bot-text))] border-[length:var(--bubble-border-width)] border-[rgb(var(--bubble-bot-border))]',
[MESSAGE_VARIANTS.ERROR]:
'bg-[rgb(var(--bubble-error-bg))] text-[rgb(var(--bubble-error-text))] border-[length:var(--bubble-border-width)] border-[rgb(var(--bubble-error-border))]',
[MESSAGE_VARIANTS.EMAIL]: 'w-full', [MESSAGE_VARIANTS.EMAIL]: 'w-full',
[MESSAGE_VARIANTS.UNSUPPORTED]: [MESSAGE_VARIANTS.UNSUPPORTED]:
'bg-[rgb(var(--bubble-unsupported-bg))]/70 border border-dashed border-[rgb(var(--bubble-unsupported-border))] text-[rgb(var(--bubble-unsupported-text))]', 'bg-n-solid-amber/70 border border-dashed border-n-amber-12 text-n-amber-12',
}; };
const orientationMap = { const orientationMap = {
[ORIENTATION.LEFT]: [ORIENTATION.LEFT]:
'left-bubble rounded-[var(--bubble-radius)] ltr:rounded-bl-[var(--bubble-radius-sm)] rtl:rounded-br-[var(--bubble-radius-sm)]', 'left-bubble rounded-xl ltr:rounded-bl-sm rtl:rounded-br-sm',
[ORIENTATION.RIGHT]: [ORIENTATION.RIGHT]:
'right-bubble rounded-[var(--bubble-radius)] ltr:rounded-br-[var(--bubble-radius-sm)] rtl:rounded-bl-[var(--bubble-radius-sm)]', 'right-bubble rounded-xl ltr:rounded-br-sm rtl:rounded-bl-sm',
[ORIENTATION.CENTER]: 'rounded-[var(--bubble-radius-md)]', [ORIENTATION.CENTER]: 'rounded-md',
}; };
const flexOrientationClass = computed(() => { const flexOrientationClass = computed(() => {
@@ -62,7 +57,7 @@ const messageClass = computed(() => {
if (variant.value !== MESSAGE_VARIANTS.ACTIVITY) { if (variant.value !== MESSAGE_VARIANTS.ACTIVITY) {
classToApply.push(orientationMap[orientation.value]); classToApply.push(orientationMap[orientation.value]);
} else { } else {
classToApply.push('rounded-[var(--bubble-radius-lg)]'); classToApply.push('rounded-lg');
} }
return classToApply; return classToApply;
@@ -81,20 +76,6 @@ const shouldShowMeta = computed(
variant.value !== MESSAGE_VARIANTS.ACTIVITY variant.value !== MESSAGE_VARIANTS.ACTIVITY
); );
const metaColorClass = computed(() => {
const metaClassMap = {
[MESSAGE_VARIANTS.AGENT]: 'text-[rgb(var(--bubble-agent-meta))]',
[MESSAGE_VARIANTS.USER]: 'text-[rgb(var(--bubble-user-meta))]',
[MESSAGE_VARIANTS.PRIVATE]:
'text-[rgb(var(--bubble-private-meta))] opacity-50',
[MESSAGE_VARIANTS.BOT]: 'text-[rgb(var(--bubble-bot-meta))]',
[MESSAGE_VARIANTS.TEMPLATE]: 'text-[rgb(var(--bubble-bot-meta))]',
[MESSAGE_VARIANTS.EMAIL]: 'text-[rgb(var(--bubble-agent-meta))]',
[MESSAGE_VARIANTS.ERROR]: 'text-[rgb(var(--bubble-error-meta))]',
};
return metaClassMap[variant.value] || 'text-[rgb(var(--bubble-agent-meta))]';
});
const replyToPreview = computed(() => { const replyToPreview = computed(() => {
if (!inReplyTo) return ''; if (!inReplyTo) return '';
@@ -138,7 +119,9 @@ const replyToPreview = computed(() => {
:class="[ :class="[
flexOrientationClass, flexOrientationClass,
variant === MESSAGE_VARIANTS.EMAIL ? 'px-3 pb-3' : '', variant === MESSAGE_VARIANTS.EMAIL ? 'px-3 pb-3' : '',
metaColorClass, variant === MESSAGE_VARIANTS.PRIVATE
? 'text-n-amber-12/50'
: 'text-n-slate-11',
]" ]"
class="mt-2" class="mt-2"
/> />
@@ -4,7 +4,6 @@ import { useI18n } from 'vue-i18n';
import BaseBubble from './Base.vue'; import BaseBubble from './Base.vue';
import Icon from 'next/icon/Icon.vue'; import Icon from 'next/icon/Icon.vue';
import { useMessageContext } from '../provider.js'; import { useMessageContext } from '../provider.js';
import { MESSAGE_VARIANTS } from '../constants';
defineProps({ defineProps({
icon: { type: [String, Object], required: true }, icon: { type: [String, Object], required: true },
@@ -21,39 +20,16 @@ defineProps({
}, },
}); });
const { sender, variant } = useMessageContext(); const { sender } = useMessageContext();
const { t } = useI18n(); const { t } = useI18n();
const senderName = computed(() => { const senderName = computed(() => {
return sender?.value?.name || ''; return sender?.value?.name || '';
}); });
const primaryTextClass = computed(() => {
const classMap = {
[MESSAGE_VARIANTS.AGENT]: 'text-[rgb(var(--bubble-agent-text))]',
[MESSAGE_VARIANTS.USER]: 'text-[rgb(var(--bubble-user-text))]',
[MESSAGE_VARIANTS.PRIVATE]: 'text-[rgb(var(--bubble-private-text))]',
[MESSAGE_VARIANTS.BOT]: 'text-[rgb(var(--bubble-bot-text))]',
};
return classMap[variant.value] || 'text-[rgb(var(--bubble-agent-text))]';
});
const secondaryTextClass = computed(() => {
const classMap = {
[MESSAGE_VARIANTS.AGENT]: 'text-[rgb(var(--bubble-agent-meta))]',
[MESSAGE_VARIANTS.USER]: 'text-[rgb(var(--bubble-user-meta))]',
[MESSAGE_VARIANTS.PRIVATE]: 'text-[rgb(var(--bubble-private-meta))]',
[MESSAGE_VARIANTS.BOT]: 'text-[rgb(var(--bubble-bot-meta))]',
};
return classMap[variant.value] || 'text-[rgb(var(--bubble-agent-meta))]';
});
</script> </script>
<template> <template>
<BaseBubble <BaseBubble class="overflow-hidden p-3" data-bubble-name="attachment">
class="overflow-hidden p-[var(--bubble-padding-y)]"
data-bubble-name="attachment"
>
<div class="grid gap-4 min-w-64"> <div class="grid gap-4 min-w-64">
<div class="grid gap-3"> <div class="grid gap-3">
<div <div
@@ -65,11 +41,7 @@ const secondaryTextClass = computed(() => {
</slot> </slot>
</div> </div>
<div class="space-y-1 overflow-hidden"> <div class="space-y-1 overflow-hidden">
<div <div v-if="senderName" class="text-n-slate-12 text-sm truncate">
v-if="senderName"
class="text-sm truncate"
:class="primaryTextClass"
>
{{ {{
t(senderTranslationKey, { t(senderTranslationKey, {
sender: senderName, sender: senderName,
@@ -77,18 +49,10 @@ const secondaryTextClass = computed(() => {
}} }}
</div> </div>
<slot> <slot>
<div <div v-if="title" class="truncate text-sm text-n-slate-12">
v-if="title"
class="truncate text-sm"
:class="primaryTextClass"
>
{{ title }} {{ title }}
</div> </div>
<div <div v-if="content" class="truncate text-sm text-n-slate-11">
v-if="content"
class="truncate text-sm"
:class="secondaryTextClass"
>
{{ content }} {{ content }}
</div> </div>
</slot> </slot>
@@ -40,10 +40,7 @@ const starRatingValue = computed(() => {
</script> </script>
<template> <template>
<BaseBubble <BaseBubble class="px-4 py-3" data-bubble-name="csat">
class="px-[var(--bubble-padding-x)] py-[var(--bubble-padding-y)]"
data-bubble-name="csat"
>
<h4>{{ content || t('CONVERSATION.CSAT_REPLY_MESSAGE') }}</h4> <h4>{{ content || t('CONVERSATION.CSAT_REPLY_MESSAGE') }}</h4>
<dl v-if="isRatingSubmitted" class="mt-4"> <dl v-if="isRatingSubmitted" class="mt-4">
<dt class="text-n-slate-11 italic"> <dt class="text-n-slate-11 italic">
@@ -1,32 +1,14 @@
<script setup> <script setup>
import { computed } from 'vue'; import { computed } from 'vue';
import { MESSAGE_STATUS, MESSAGE_TYPES } from '../../constants'; import { MESSAGE_STATUS } from '../../constants';
import { useMessageContext } from '../../provider.js'; import { useMessageContext } from '../../provider.js';
const { contentAttributes, status, sender, messageType } = useMessageContext(); const { contentAttributes, status, sender } = useMessageContext();
const hasError = computed(() => { const hasError = computed(() => {
return status.value === MESSAGE_STATUS.FAILED; return status.value === MESSAGE_STATUS.FAILED;
}); });
const isIncoming = computed(() => {
return messageType.value === MESSAGE_TYPES.INCOMING;
});
const secondaryTextClass = computed(() => {
if (hasError.value) return 'text-[rgb(var(--bubble-error-meta))]';
return isIncoming.value
? 'text-[rgb(var(--bubble-user-meta))]'
: 'text-[rgb(var(--bubble-agent-meta))]';
});
const primaryTextClass = computed(() => {
if (hasError.value) return 'text-[rgb(var(--bubble-error-text))]';
return isIncoming.value
? 'text-[rgb(var(--bubble-user-text))]'
: 'text-[rgb(var(--bubble-agent-text))]';
});
const fromEmail = computed(() => { const fromEmail = computed(() => {
return contentAttributes.value?.email?.from ?? []; return contentAttributes.value?.email?.from ?? [];
}); });
@@ -86,10 +68,13 @@ const showMeta = computed(() => {
<section <section
v-show="showMeta" v-show="showMeta"
class="space-y-1 rtl:pl-9 ltr:pr-9 text-sm break-words" class="space-y-1 rtl:pl-9 ltr:pr-9 text-sm break-words"
:class="secondaryTextClass" :class="hasError ? 'text-n-ruby-11' : 'text-n-slate-11'"
> >
<template v-if="showMeta"> <template v-if="showMeta">
<div v-if="fromEmail[0]" :class="primaryTextClass"> <div
v-if="fromEmail[0]"
:class="hasError ? 'text-n-ruby-11' : 'text-n-slate-12'"
>
<template v-if="senderName"> <template v-if="senderName">
<span> <span>
{{ senderName }} {{ senderName }}
@@ -104,26 +104,21 @@ const handleSeeOriginal = () => {
<template> <template>
<BaseBubble <BaseBubble
class="w-full border-[length:var(--bubble-border-width)]" class="w-full"
:class="{ :class="{
'bg-[rgb(var(--bubble-user-bg))] text-[rgb(var(--bubble-user-text))] border-[rgb(var(--bubble-user-border))]': 'bg-n-slate-4': isIncoming,
isIncoming, 'bg-n-solid-blue': isOutgoing,
'bg-[rgb(var(--bubble-agent-bg))] text-[rgb(var(--bubble-agent-text))] border-[rgb(var(--bubble-agent-border))]':
isOutgoing,
}" }"
data-bubble-name="email" data-bubble-name="email"
> >
<EmailMeta <EmailMeta
class="px-[var(--bubble-padding-x)] py-[var(--bubble-padding-y)]" class="p-3"
:class="{ :class="{
'border-b border-[rgb(var(--bubble-user-border))]': isIncoming, 'border-b border-n-strong': isIncoming,
'border-b border-[rgb(var(--bubble-agent-border))]': isOutgoing, 'border-b border-n-slate-8/20': isOutgoing,
}" }"
/> />
<section <section ref="contentContainer" class="p-3">
ref="contentContainer"
class="px-[var(--bubble-padding-x)] py-[var(--bubble-padding-y)]"
>
<div <div
:class="{ :class="{
'max-h-[400px] overflow-hidden relative': !isExpanded && isExpandable, 'max-h-[400px] overflow-hidden relative': !isExpanded && isExpandable,
@@ -134,18 +129,14 @@ const handleSeeOriginal = () => {
v-if="isExpandable && !isExpanded" v-if="isExpandable && !isExpanded"
class="absolute left-0 right-0 bottom-0 h-40 px-8 flex items-end" class="absolute left-0 right-0 bottom-0 h-40 px-8 flex items-end"
:class="{ :class="{
'bg-gradient-to-t from-[rgb(var(--bubble-user-bg))] via-[rgb(var(--bubble-user-bg))] via-20% to-transparent': 'bg-gradient-to-t from-n-slate-4 via-n-slate-4 via-20% to-transparent':
isIncoming, isIncoming,
'bg-gradient-to-t from-[rgb(var(--bubble-agent-bg))] via-[rgb(var(--bubble-agent-bg))] via-20% to-transparent': 'bg-gradient-to-t from-n-solid-blue via-n-solid-blue via-20% to-transparent':
isOutgoing, isOutgoing,
}" }"
> >
<button <button
class="py-2 px-8 mx-auto text-center flex items-center gap-2" class="text-n-slate-12 py-2 px-8 mx-auto text-center flex items-center gap-2"
:class="{
'text-[rgb(var(--bubble-user-text))]': isIncoming,
'text-[rgb(var(--bubble-agent-text))]': isOutgoing,
}"
@click="isExpanded = true" @click="isExpanded = true"
> >
<Icon icon="i-lucide-maximize-2" /> <Icon icon="i-lucide-maximize-2" />
@@ -154,7 +145,7 @@ const handleSeeOriginal = () => {
</div> </div>
<FormattedContent <FormattedContent
v-if="isOutgoing && content && !hasEmailContent" v-if="isOutgoing && content && !hasEmailContent"
class="text-[rgb(var(--bubble-agent-text))]" class="text-n-slate-12"
:content="messageContent" :content="messageContent"
/> />
<template v-else> <template v-else>
@@ -185,11 +176,7 @@ const handleSeeOriginal = () => {
</template> </template>
<button <button
v-if="hasQuotedMessage" v-if="hasQuotedMessage"
class="px-1 leading-none text-sm bg-n-alpha-black2 text-center flex items-center gap-1 mt-2" class="text-n-slate-11 px-1 leading-none text-sm bg-n-alpha-black2 text-center flex items-center gap-1 mt-2"
:class="{
'text-[rgb(var(--bubble-user-meta))]': isIncoming,
'text-[rgb(var(--bubble-agent-meta))]': isOutgoing,
}"
@click="showQuotedMessage = !showQuotedMessage" @click="showQuotedMessage = !showQuotedMessage"
> >
<template v-if="showQuotedMessage"> <template v-if="showQuotedMessage">
@@ -48,10 +48,7 @@ const formValues = computed(() => {
</script> </script>
<template> <template>
<BaseBubble <BaseBubble class="px-4 py-3" data-bubble-name="csat">
class="px-[var(--bubble-padding-x)] py-[var(--bubble-padding-y)]"
data-bubble-name="form"
>
<span v-dompurify-html="content" :title="content" /> <span v-dompurify-html="content" :title="content" />
<dl v-if="formValues.length" class="mt-4"> <dl v-if="formValues.length" class="mt-4">
<template v-for="item in formValues" :key="item.title"> <template v-for="item in formValues" :key="item.title">
@@ -6,7 +6,6 @@ import { useLoadWithRetry } from 'dashboard/composables/loadWithRetry';
import BaseBubble from './Base.vue'; import BaseBubble from './Base.vue';
import Button from 'next/button/Button.vue'; import Button from 'next/button/Button.vue';
import Icon from 'next/icon/Icon.vue'; import Icon from 'next/icon/Icon.vue';
import { useGallery } from '../useGallery';
import { useSnakeCase } from 'dashboard/composables/useTransformKeys'; import { useSnakeCase } from 'dashboard/composables/useTransformKeys';
import { useMessageContext } from '../provider.js'; import { useMessageContext } from '../provider.js';
import { downloadFile } from '@chatwoot/utils'; import { downloadFile } from '@chatwoot/utils';
@@ -23,8 +22,8 @@ const attachment = computed(() => {
const { isLoaded, hasError, loadWithRetry } = useLoadWithRetry(); const { isLoaded, hasError, loadWithRetry } = useLoadWithRetry();
const showGallery = ref(false);
const isDownloading = ref(false); const isDownloading = ref(false);
const { showGallery, isGalleryAllowed, toggleGallery } = useGallery();
onMounted(() => { onMounted(() => {
if (attachment.value?.dataUrl) { if (attachment.value?.dataUrl) {
@@ -51,16 +50,13 @@ const handleImageError = () => {
<template> <template>
<BaseBubble <BaseBubble
class="overflow-hidden p-[var(--bubble-padding-y)]" class="overflow-hidden p-3"
data-bubble-name="image" data-bubble-name="image"
@click="toggleGallery(true)" @click="showGallery = true"
> >
<div <div v-if="hasError" class="flex items-center gap-1 text-center rounded-lg">
v-if="hasError" <Icon icon="i-lucide-circle-off" class="text-n-slate-11" />
class="flex items-center gap-1 text-center rounded-lg text-[rgb(var(--bubble-error-meta))]" <p class="mb-0 text-n-slate-11">
>
<Icon icon="i-lucide-circle-off" />
<p class="mb-0">
{{ $t('COMPONENTS.MEDIA.IMAGE_UNAVAILABLE') }} {{ $t('COMPONENTS.MEDIA.IMAGE_UNAVAILABLE') }}
</p> </p>
</div> </div>
@@ -90,7 +86,7 @@ const handleImageError = () => {
</div> </div>
</BaseBubble> </BaseBubble>
<GalleryView <GalleryView
v-if="showGallery && isGalleryAllowed" v-if="showGallery"
v-model:show="showGallery" v-model:show="showGallery"
:attachment="useSnakeCase(attachment)" :attachment="useSnakeCase(attachment)"
:all-attachments="filteredCurrentChatAttachments" :all-attachments="filteredCurrentChatAttachments"
@@ -44,10 +44,7 @@ const onVideoLoadError = () => {
</script> </script>
<template> <template>
<BaseBubble <BaseBubble class="p-3 overflow-hidden" data-bubble-name="ig-story">
class="p-[var(--bubble-padding-y)] overflow-hidden"
data-bubble-name="ig-story"
>
<p v-if="isStoryReply" class="mb-1 text-xs text-n-slate-11"> <p v-if="isStoryReply" class="mb-1 text-xs text-n-slate-11">
{{ t('COMPONENTS.FILE_BUBBLE.INSTAGRAM_STORY_REPLY') }} {{ t('COMPONENTS.FILE_BUBBLE.INSTAGRAM_STORY_REPLY') }}
</p> </p>
@@ -67,10 +64,10 @@ const onVideoLoadError = () => {
/> />
<div <div
v-else v-else
class="flex items-center gap-1 px-5 py-4 text-center rounded-lg bg-n-alpha-1 text-[rgb(var(--bubble-error-meta))]" class="flex items-center gap-1 px-5 py-4 text-center rounded-lg bg-n-alpha-1"
> >
<Icon icon="i-lucide-circle-off" /> <Icon icon="i-lucide-circle-off" class="text-n-slate-11" />
<p class="mb-0"> <p class="mb-0 text-n-slate-11">
{{ $t('COMPONENTS.FILE_BUBBLE.INSTAGRAM_STORY_UNAVAILABLE') }} {{ $t('COMPONENTS.FILE_BUBBLE.INSTAGRAM_STORY_UNAVAILABLE') }}
</p> </p>
</div> </div>
@@ -4,11 +4,11 @@ import BaseBubble from 'next/message/bubbles/Base.vue';
import FormattedContent from './FormattedContent.vue'; import FormattedContent from './FormattedContent.vue';
import AttachmentChips from 'next/message/chips/AttachmentChips.vue'; import AttachmentChips from 'next/message/chips/AttachmentChips.vue';
import TranslationToggle from 'dashboard/components-next/message/TranslationToggle.vue'; import TranslationToggle from 'dashboard/components-next/message/TranslationToggle.vue';
import { MESSAGE_TYPES, MESSAGE_VARIANTS } from '../../constants'; import { MESSAGE_TYPES } from '../../constants';
import { useMessageContext } from '../../provider.js'; import { useMessageContext } from '../../provider.js';
import { useTranslations } from 'dashboard/composables/useTranslations'; import { useTranslations } from 'dashboard/composables/useTranslations';
const { content, attachments, contentAttributes, messageType, variant } = const { content, attachments, contentAttributes, messageType } =
useMessageContext(); useMessageContext();
const { hasTranslations, translationContent } = const { hasTranslations, translationContent } =
@@ -36,29 +36,15 @@ const isEmpty = computed(() => {
return !content.value && !attachments.value?.length; return !content.value && !attachments.value?.length;
}); });
const emptyTextClass = computed(() => {
const metaClassMap = {
[MESSAGE_VARIANTS.AGENT]: 'text-[rgb(var(--bubble-agent-meta))]',
[MESSAGE_VARIANTS.USER]: 'text-[rgb(var(--bubble-user-meta))]',
[MESSAGE_VARIANTS.PRIVATE]: 'text-[rgb(var(--bubble-private-meta))]',
[MESSAGE_VARIANTS.BOT]: 'text-[rgb(var(--bubble-bot-meta))]',
[MESSAGE_VARIANTS.TEMPLATE]: 'text-[rgb(var(--bubble-bot-meta))]',
};
return metaClassMap[variant.value] || 'text-[rgb(var(--bubble-agent-meta))]';
});
const handleSeeOriginal = () => { const handleSeeOriginal = () => {
renderOriginal.value = !renderOriginal.value; renderOriginal.value = !renderOriginal.value;
}; };
</script> </script>
<template> <template>
<BaseBubble <BaseBubble class="px-4 py-3" data-bubble-name="text">
class="px-[var(--bubble-padding-x)] py-[var(--bubble-padding-y)]"
data-bubble-name="text"
>
<div class="gap-3 flex flex-col"> <div class="gap-3 flex flex-col">
<span v-if="isEmpty" :class="emptyTextClass"> <span v-if="isEmpty" class="text-n-slate-11">
{{ $t('CONVERSATION.NO_CONTENT') }} {{ $t('CONVERSATION.NO_CONTENT') }}
</span> </span>
<FormattedContent v-if="renderContent" :content="renderContent" /> <FormattedContent v-if="renderContent" :content="renderContent" />
@@ -21,10 +21,7 @@ const unsupportedMessageKey = computed(() => {
</script> </script>
<template> <template>
<BaseBubble <BaseBubble class="px-4 py-3 text-sm" data-bubble-name="unsupported">
class="px-[var(--bubble-padding-x)] py-[var(--bubble-padding-y)] text-sm"
data-bubble-name="unsupported"
>
{{ $t(unsupportedMessageKey) }} {{ $t(unsupportedMessageKey) }}
</BaseBubble> </BaseBubble>
</template> </template>
@@ -2,7 +2,6 @@
import { ref, computed } from 'vue'; import { ref, computed } from 'vue';
import BaseBubble from './Base.vue'; import BaseBubble from './Base.vue';
import Icon from 'next/icon/Icon.vue'; import Icon from 'next/icon/Icon.vue';
import { useGallery } from '../useGallery';
import { useSnakeCase } from 'dashboard/composables/useTransformKeys'; import { useSnakeCase } from 'dashboard/composables/useTransformKeys';
import { useMessageContext } from '../provider.js'; import { useMessageContext } from '../provider.js';
import GalleryView from 'dashboard/components/widgets/conversation/components/GalleryView.vue'; import GalleryView from 'dashboard/components/widgets/conversation/components/GalleryView.vue';
@@ -10,7 +9,7 @@ import { ATTACHMENT_TYPES } from '../constants';
const emit = defineEmits(['error']); const emit = defineEmits(['error']);
const hasError = ref(false); const hasError = ref(false);
const { showGallery, isGalleryAllowed, toggleGallery } = useGallery(); const showGallery = ref(false);
const { filteredCurrentChatAttachments, attachments } = useMessageContext(); const { filteredCurrentChatAttachments, attachments } = useMessageContext();
const handleError = () => { const handleError = () => {
@@ -29,9 +28,9 @@ const isReel = computed(() => {
<template> <template>
<BaseBubble <BaseBubble
class="overflow-hidden p-[var(--bubble-padding-y)]" class="overflow-hidden p-3"
data-bubble-name="video" data-bubble-name="video"
@click="toggleGallery(true)" @click="showGallery = true"
> >
<div class="relative group rounded-lg overflow-hidden"> <div class="relative group rounded-lg overflow-hidden">
<div <div
@@ -54,7 +53,7 @@ const isReel = computed(() => {
</div> </div>
</BaseBubble> </BaseBubble>
<GalleryView <GalleryView
v-if="showGallery && isGalleryAllowed" v-if="showGallery"
v-model:show="showGallery" v-model:show="showGallery"
:attachment="useSnakeCase(attachment)" :attachment="useSnakeCase(attachment)"
:all-attachments="filteredCurrentChatAttachments" :all-attachments="filteredCurrentChatAttachments"
@@ -1,7 +1,6 @@
<script setup> <script setup>
import { ref } from 'vue'; import { ref } from 'vue';
import Icon from 'next/icon/Icon.vue'; import Icon from 'next/icon/Icon.vue';
import { useGallery } from '../useGallery';
import { useSnakeCase } from 'dashboard/composables/useTransformKeys'; import { useSnakeCase } from 'dashboard/composables/useTransformKeys';
import { useMessageContext } from '../provider.js'; import { useMessageContext } from '../provider.js';
@@ -14,7 +13,7 @@ defineProps({
}, },
}); });
const hasError = ref(false); const hasError = ref(false);
const { showGallery, toggleGallery, isGalleryAllowed } = useGallery(); const showGallery = ref(false);
const { filteredCurrentChatAttachments } = useMessageContext(); const { filteredCurrentChatAttachments } = useMessageContext();
@@ -26,7 +25,7 @@ const handleError = () => {
<template> <template>
<div <div
class="size-[72px] overflow-hidden contain-content rounded-xl cursor-pointer" class="size-[72px] overflow-hidden contain-content rounded-xl cursor-pointer"
@click="toggleGallery(true)" @click="showGallery = true"
> >
<div <div
v-if="hasError" v-if="hasError"
@@ -43,7 +42,7 @@ const handleError = () => {
/> />
</div> </div>
<GalleryView <GalleryView
v-if="showGallery && isGalleryAllowed" v-if="showGallery"
v-model:show="showGallery" v-model:show="showGallery"
:attachment="useSnakeCase(attachment)" :attachment="useSnakeCase(attachment)"
:all-attachments="filteredCurrentChatAttachments" :all-attachments="filteredCurrentChatAttachments"
@@ -1,6 +1,6 @@
<script setup> <script setup>
import { ref } from 'vue';
import Icon from 'next/icon/Icon.vue'; import Icon from 'next/icon/Icon.vue';
import { useGallery } from '../useGallery';
import { useSnakeCase } from 'dashboard/composables/useTransformKeys'; import { useSnakeCase } from 'dashboard/composables/useTransformKeys';
import { useMessageContext } from '../provider.js'; import { useMessageContext } from '../provider.js';
import GalleryView from 'dashboard/components/widgets/conversation/components/GalleryView.vue'; import GalleryView from 'dashboard/components/widgets/conversation/components/GalleryView.vue';
@@ -12,7 +12,7 @@ defineProps({
}, },
}); });
const { showGallery, isGalleryAllowed, toggleGallery } = useGallery(); const showGallery = ref(false);
const { filteredCurrentChatAttachments } = useMessageContext(); const { filteredCurrentChatAttachments } = useMessageContext();
</script> </script>
@@ -20,7 +20,7 @@ const { filteredCurrentChatAttachments } = useMessageContext();
<template> <template>
<div <div
class="size-[72px] overflow-hidden contain-content rounded-xl cursor-pointer relative group" class="size-[72px] overflow-hidden contain-content rounded-xl cursor-pointer relative group"
@click="toggleGallery(true)" @click="showGallery = true"
> >
<video <video
:src="attachment.dataUrl" :src="attachment.dataUrl"
@@ -42,7 +42,7 @@ const { filteredCurrentChatAttachments } = useMessageContext();
</div> </div>
</div> </div>
<GalleryView <GalleryView
v-if="showGallery && isGalleryAllowed" v-if="showGallery"
v-model:show="showGallery" v-model:show="showGallery"
:attachment="useSnakeCase(attachment)" :attachment="useSnakeCase(attachment)"
:all-attachments="filteredCurrentChatAttachments" :all-attachments="filteredCurrentChatAttachments"
@@ -1,33 +0,0 @@
import { MESSAGE_TYPES } from './constants';
/**
* Determines if a message should be grouped with the next message
* @param {Number} index - Index of the current message
* @param {Array} searchList - Array of messages to check
* @returns {Boolean} - Whether the message should be grouped with next
*/
export default (index, searchList) => {
if (index === searchList.length - 1) return false;
const current = searchList[index];
const next = searchList[index + 1];
if (next.status === 'failed') return false;
const nextSenderId = next.senderId ?? next.sender?.id;
const currentSenderId = current.senderId ?? current.sender?.id;
const hasSameSender = nextSenderId === currentSenderId;
const nextMessageType = next.messageType;
const currentMessageType = current.messageType;
const areBothTemplates =
nextMessageType === MESSAGE_TYPES.TEMPLATE &&
currentMessageType === MESSAGE_TYPES.TEMPLATE;
if (!hasSameSender || areBothTemplates) return false;
if (currentMessageType !== nextMessageType) return false;
// Check if messages are in the same minute by rounding down to nearest minute
return Math.floor(next.createdAt / 60) === Math.floor(current.createdAt / 60);
};
@@ -1,20 +0,0 @@
import { computed } from 'vue';
import { useToggle } from '@vueuse/core';
export function useGallery() {
const [showGallery] = useToggle(false);
const isGalleryAllowed = computed(() => {
return true;
});
const toggleGallery = value => {
showGallery.value = value;
};
return {
showGallery,
isGalleryAllowed,
toggleGallery,
};
}
@@ -63,6 +63,16 @@ const hasAdvancedAssignment = computed(() => {
); );
}); });
const hasCustomTools = computed(() => {
return (
isFeatureEnabledonAccount.value(
accountId.value,
FEATURE_FLAGS.CAPTAIN_CUSTOM_TOOLS
) ||
isFeatureEnabledonAccount.value(accountId.value, FEATURE_FLAGS.CAPTAIN_V2)
);
});
const toggleShortcutModalFn = show => { const toggleShortcutModalFn = show => {
if (show) { if (show) {
emit('openKeyShortcutModal'); emit('openKeyShortcutModal');
@@ -364,14 +374,18 @@ const menuItems = computed(() => {
navigationPath: 'captain_assistants_inboxes_index', navigationPath: 'captain_assistants_inboxes_index',
}), }),
}, },
{ ...(hasCustomTools.value
name: 'Tools', ? [
label: t('SIDEBAR.CAPTAIN_TOOLS'), {
activeOn: ['captain_tools_index'], name: 'Tools',
to: accountScopedRoute('captain_assistants_index', { label: t('SIDEBAR.CAPTAIN_TOOLS'),
navigationPath: 'captain_tools_index', activeOn: ['captain_tools_index'],
}), to: accountScopedRoute('captain_assistants_index', {
}, navigationPath: 'captain_tools_index',
}),
},
]
: []),
{ {
name: 'Settings', name: 'Settings',
label: t('SIDEBAR.CAPTAIN_SETTINGS'), label: t('SIDEBAR.CAPTAIN_SETTINGS'),
+27 -49
View File
@@ -15,7 +15,6 @@ const { modalType, closeOnBackdropClick, onClose } = defineProps({
const emit = defineEmits(['close']); const emit = defineEmits(['close']);
const show = defineModel('show', { type: Boolean, default: false }); const show = defineModel('show', { type: Boolean, default: false });
const teleportTarget = ref(null);
const modalClassName = computed(() => { const modalClassName = computed(() => {
const modalClassNameMap = { const modalClassNameMap = {
@@ -26,24 +25,6 @@ const modalClassName = computed(() => {
return `modal-mask skip-context-menu ${modalClassNameMap[modalType] || ''}`; return `modal-mask skip-context-menu ${modalClassNameMap[modalType] || ''}`;
}); });
const resolveTeleportTarget = () => {
// eslint-disable-next-line no-underscore-dangle
if (window.__WOOT_ISOLATED_SHELL__) {
// Look for the specific chatwoot-message-list custom element
const messageListElement = document.querySelector('chatwoot-message-list');
if (messageListElement?.shadowRoot) {
const modalRoot =
messageListElement.shadowRoot.querySelector('#cw-modal-root');
if (modalRoot) {
teleportTarget.value = modalRoot;
return;
}
}
}
teleportTarget.value = document.body;
};
// [TODO] Revisit this logic to use outside click directive // [TODO] Revisit this logic to use outside click directive
const mousedDownOnBackdrop = ref(false); const mousedDownOnBackdrop = ref(false);
@@ -77,7 +58,6 @@ useEventListener(document.body, 'mouseup', onMouseUp);
useEventListener(document, 'keydown', onKeydown); useEventListener(document, 'keydown', onKeydown);
onMounted(() => { onMounted(() => {
resolveTeleportTarget();
if (import.meta.env.DEV && onClose && typeof onClose === 'function') { if (import.meta.env.DEV && onClose && typeof onClose === 'function') {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.warn( console.warn(
@@ -88,38 +68,36 @@ onMounted(() => {
</script> </script>
<template> <template>
<Teleport v-if="teleportTarget" :to="teleportTarget"> <transition name="modal-fade">
<transition name="modal-fade"> <div
v-if="show"
:class="modalClassName"
transition="modal"
@mousedown="handleMouseDown"
>
<div <div
v-if="show" class="relative max-h-full overflow-auto bg-n-alpha-3 shadow-md modal-container rtl:text-right skip-context-menu"
:class="modalClassName" :class="{
transition="modal" 'rounded-xl w-[37.5rem]': !fullWidth,
@mousedown="handleMouseDown" 'items-center rounded-none flex h-full justify-center w-full':
fullWidth,
[size]: true,
}"
@mouse.stop
@mousedown="event => event.stopPropagation()"
> >
<div <Button
class="relative max-h-full overflow-auto bg-n-alpha-3 shadow-md modal-container rtl:text-right skip-context-menu" v-if="showCloseButton"
:class="{ ghost
'rounded-xl w-[37.5rem]': !fullWidth, slate
'items-center rounded-none flex h-full justify-center w-full': icon="i-lucide-x"
fullWidth, class="absolute z-10 ltr:right-2 rtl:left-2 top-2"
[size]: true, @click="close"
}" />
@mouse.stop <slot />
@mousedown="event => event.stopPropagation()"
>
<Button
v-if="showCloseButton"
ghost
slate
icon="i-lucide-x"
class="absolute z-10 ltr:right-2 rtl:left-2 top-2"
@click="close"
/>
<slot />
</div>
</div> </div>
</transition> </div>
</Teleport> </transition>
</template> </template>
<style lang="scss"> <style lang="scss">
@@ -89,7 +89,6 @@ const props = defineProps({
// are triggered except when this flag is true // are triggered except when this flag is true
allowSignature: { type: Boolean, default: false }, allowSignature: { type: Boolean, default: false },
channelType: { type: String, default: '' }, channelType: { type: String, default: '' },
forceSignature: { type: Boolean, default: false },
conversationId: { type: Number, default: null }, conversationId: { type: Number, default: null },
medium: { type: String, default: '' }, medium: { type: String, default: '' },
showImageResizeToolbar: { type: Boolean, default: false }, // A kill switch to show or hide the image toolbar showImageResizeToolbar: { type: Boolean, default: false }, // A kill switch to show or hide the image toolbar
@@ -314,10 +313,6 @@ const plugins = computed(() => {
const sendWithSignature = computed(() => { const sendWithSignature = computed(() => {
// this is considered the source of truth, we watch this property // this is considered the source of truth, we watch this property
// on change, we toggle the signature in the editor // on change, we toggle the signature in the editor
if (props.forceSignature && props.allowSignature && !props.isPrivate) {
return true;
}
if (props.allowSignature && !props.isPrivate && props.channelType) { if (props.allowSignature && !props.isPrivate && props.channelType) {
return fetchSignatureFlagFromUISettings(props.channelType); return fetchSignatureFlagFromUISettings(props.channelType);
} }
@@ -569,14 +564,10 @@ function updateImgToolbarOnDelete() {
} }
function isEnterToSendEnabled() { function isEnterToSendEnabled() {
// eslint-disable-next-line no-underscore-dangle
if (window.__WOOT_ISOLATED_SHELL__) return false;
return isEditorHotKeyEnabled('enter'); return isEditorHotKeyEnabled('enter');
} }
function isCmdPlusEnterToSendEnabled() { function isCmdPlusEnterToSendEnabled() {
// eslint-disable-next-line no-underscore-dangle
if (window.__WOOT_ISOLATED_SHELL__) return true;
return isEditorHotKeyEnabled('cmd_enter'); return isEditorHotKeyEnabled('cmd_enter');
} }
@@ -820,7 +811,7 @@ watch(sendWithSignature, newValue => {
} }
}); });
onMounted(async () => { onMounted(() => {
// [VITE] state assignment was done in created before // [VITE] state assignment was done in created before
state = createState( state = createState(
props.modelValue, props.modelValue,
@@ -832,10 +823,7 @@ onMounted(async () => {
createEditorView(); createEditorView();
editorView.updateState(state); editorView.updateState(state);
// TODO: test this in the main app if (props.focusOnMount) {
if (sendWithSignature.value) {
addSignature();
} else if (props.focusOnMount) {
focusEditorInputField(); focusEditorInputField();
} }
}); });
@@ -929,10 +917,6 @@ useEmitter(BUS_EVENTS.INSERT_INTO_RICH_EDITOR, insertContentIntoEditor);
.ProseMirror-menubar-wrapper { .ProseMirror-menubar-wrapper {
@apply flex flex-col gap-3; @apply flex flex-col gap-3;
.ProseMirror-menubar:empty {
display: none;
}
.ProseMirror-menubar { .ProseMirror-menubar {
min-height: 1.25rem !important; min-height: 1.25rem !important;
@apply items-center gap-4 flex pb-0 bg-transparent text-n-slate-11 relative ltr:-left-[3px] rtl:-right-[3px]; @apply items-center gap-4 flex pb-0 bg-transparent text-n-slate-11 relative ltr:-left-[3px] rtl:-right-[3px];
@@ -2,7 +2,6 @@
import { computed, useTemplateRef } from 'vue'; import { computed, useTemplateRef } from 'vue';
import { useElementSize } from '@vueuse/core'; import { useElementSize } from '@vueuse/core';
import { REPLY_EDITOR_MODES } from './constants'; import { REPLY_EDITOR_MODES } from './constants';
import Icon from 'next/icon/Icon.vue';
const props = defineProps({ const props = defineProps({
mode: { mode: {
@@ -13,10 +12,6 @@ const props = defineProps({
type: Boolean, type: Boolean,
default: false, default: false,
}, },
iconOnly: {
type: Boolean,
default: false,
},
isReplyRestricted: { isReplyRestricted: {
type: Boolean, type: Boolean,
default: false, default: false,
@@ -74,34 +69,22 @@ const translateValue = computed(() => {
<template> <template>
<button <button
class="flex items-center w-auto p-1 transition-all border rounded-full bg-n-alpha-2 group relative duration-300 ease-in-out z-0 active:scale-[0.995] active:duration-75" class="flex items-center w-auto h-8 p-1 transition-all border rounded-full bg-n-alpha-2 group relative duration-300 ease-in-out z-0 active:scale-[0.995] active:duration-75"
:disabled="disabled || isReplyRestricted" :disabled="disabled || isReplyRestricted"
:class="{ :class="{
'h-7': iconOnly,
'h-8': !iconOnly,
'cursor-not-allowed': disabled || isReplyRestricted, 'cursor-not-allowed': disabled || isReplyRestricted,
}" }"
@click="$emit('toggleMode')" @click="$emit('toggleMode')"
> >
<div <div ref="wootEditorReplyMode" class="flex items-center gap-1 px-2 z-20">
ref="wootEditorReplyMode" {{ $t('CONVERSATION.REPLYBOX.REPLY') }}
class="flex items-center gap-1 px-2 z-20 text-n-slate-11"
>
<Icon v-if="iconOnly" icon="i-lucide-message-circle" class="size-4" />
<template v-else>{{ $t('CONVERSATION.REPLYBOX.REPLY') }}</template>
</div> </div>
<div <div ref="wootEditorPrivateMode" class="flex items-center gap-1 px-2 z-20">
ref="wootEditorPrivateMode" {{ $t('CONVERSATION.REPLYBOX.PRIVATE_NOTE') }}
class="flex items-center gap-1 px-2 z-20 text-n-slate-11"
>
<Icon v-if="iconOnly" icon="i-lucide-lock-keyhole" class="size-4" />
<template v-else>{{ $t('CONVERSATION.REPLYBOX.PRIVATE_NOTE') }}</template>
</div> </div>
<div <div
class="absolute shadow-sm rounded-full h-6 w-[var(--chip-width)] ease-in-out translate-x-[var(--translate-x)] rtl:translate-x-[var(--rtl-translate-x)] bg-n-solid-1" class="absolute shadow-sm rounded-full h-6 w-[var(--chip-width)] ease-in-out translate-x-[var(--translate-x)] rtl:translate-x-[var(--rtl-translate-x)] bg-n-solid-1"
:class="{ :class="{
'h-5': iconOnly,
'h-6': !iconOnly,
'transition-all duration-300': !disabled && !isReplyRestricted, 'transition-all duration-300': !disabled && !isReplyRestricted,
}" }"
:style="{ :style="{
@@ -114,11 +114,6 @@ export default {
type: String, type: String,
default: '', default: '',
}, },
allowSignature: { type: Boolean, default: false },
allowEmoji: { type: Boolean, default: false },
allowVideoCall: { type: Boolean, default: false },
allowFileUpload: { type: Boolean, default: false },
allowAudioRecorder: { type: Boolean, default: false },
showQuotedReplyToggle: { showQuotedReplyToggle: {
type: Boolean, type: Boolean,
default: false, default: false,
@@ -296,7 +291,7 @@ export default {
<div class="flex justify-between p-3" :class="wrapClass"> <div class="flex justify-between p-3" :class="wrapClass">
<div class="left-wrap"> <div class="left-wrap">
<NextButton <NextButton
v-if="allowEmoji && !isEditorDisabled" v-if="!isEditorDisabled"
v-tooltip.top-end="$t('CONVERSATION.REPLYBOX.TIP_EMOJI_ICON')" v-tooltip.top-end="$t('CONVERSATION.REPLYBOX.TIP_EMOJI_ICON')"
icon="i-ph-smiley-sticker" icon="i-ph-smiley-sticker"
slate slate
@@ -305,7 +300,7 @@ export default {
@click="toggleEmojiPicker" @click="toggleEmojiPicker"
/> />
<FileUpload <FileUpload
v-if="showAttachButton && allowFileUpload" v-if="showAttachButton"
ref="uploadRef" ref="uploadRef"
v-tooltip.top-end="$t('CONVERSATION.REPLYBOX.TIP_ATTACH_ICON')" v-tooltip.top-end="$t('CONVERSATION.REPLYBOX.TIP_ATTACH_ICON')"
input-id="conversationAttachment" input-id="conversationAttachment"
@@ -330,7 +325,7 @@ export default {
/> />
</FileUpload> </FileUpload>
<NextButton <NextButton
v-if="allowAudioRecorder && showAudioRecorderButton" v-if="showAudioRecorderButton"
v-tooltip.top-end="$t('CONVERSATION.REPLYBOX.TIP_AUDIORECORDER_ICON')" v-tooltip.top-end="$t('CONVERSATION.REPLYBOX.TIP_AUDIORECORDER_ICON')"
:icon="!isRecordingAudio ? 'i-ph-microphone' : 'i-ph-microphone-slash'" :icon="!isRecordingAudio ? 'i-ph-microphone' : 'i-ph-microphone-slash'"
slate slate
@@ -339,7 +334,7 @@ export default {
@click="toggleAudioRecorder" @click="toggleAudioRecorder"
/> />
<NextButton <NextButton
v-if="allowAudioRecorder && showAudioPlayStopButton" v-if="showAudioPlayStopButton"
:icon="audioRecorderPlayStopIcon" :icon="audioRecorderPlayStopIcon"
slate slate
faded faded
@@ -348,7 +343,7 @@ export default {
@click="toggleAudioRecorderPlayPause" @click="toggleAudioRecorderPlayPause"
/> />
<NextButton <NextButton
v-if="showMessageSignatureButton && allowSignature" v-if="showMessageSignatureButton"
v-tooltip.top-end="signatureToggleTooltip" v-tooltip.top-end="signatureToggleTooltip"
icon="i-ph-signature" icon="i-ph-signature"
slate slate
@@ -386,7 +381,6 @@ export default {
/> />
<VideoCallButton <VideoCallButton
v-if=" v-if="
allowVideoCall &&
(isAWebWidgetInbox || isAPIInbox) && (isAWebWidgetInbox || isAPIInbox) &&
!isOnPrivateNote && !isOnPrivateNote &&
!isEditorDisabled !isEditorDisabled
@@ -25,10 +25,6 @@ export default {
type: String, type: String,
default: REPLY_EDITOR_MODES.REPLY, default: REPLY_EDITOR_MODES.REPLY,
}, },
disablePopout: {
type: Boolean,
default: false,
},
isReplyRestricted: { isReplyRestricted: {
type: Boolean, type: Boolean,
default: false, default: false,
@@ -10,7 +10,7 @@ import InboxName from '../InboxName.vue';
import ConversationContextMenu from './contextMenu/Index.vue'; import ConversationContextMenu from './contextMenu/Index.vue';
import TimeAgo from 'dashboard/components/ui/TimeAgo.vue'; import TimeAgo from 'dashboard/components/ui/TimeAgo.vue';
import CardLabels from './conversationCardComponents/CardLabels.vue'; import CardLabels from './conversationCardComponents/CardLabels.vue';
import PriorityMark from './PriorityMark.vue'; import CardPriorityIcon from 'dashboard/components-next/Conversation/ConversationCard/CardPriorityIcon.vue';
import SLACardLabel from './components/SLACardLabel.vue'; import SLACardLabel from './components/SLACardLabel.vue';
import ContextMenu from 'dashboard/components/ui/ContextMenu.vue'; import ContextMenu from 'dashboard/components/ui/ContextMenu.vue';
import VoiceCallStatus from './VoiceCallStatus.vue'; import VoiceCallStatus from './VoiceCallStatus.vue';
@@ -305,7 +305,7 @@ const deleteConversation = () => {
> >
<InboxName v-if="showInboxName" :inbox="inbox" class="flex-1 min-w-0" /> <InboxName v-if="showInboxName" :inbox="inbox" class="flex-1 min-w-0" />
<div <div
class="flex items-center gap-2 flex-shrink-0" class="flex items-baseline gap-2 flex-shrink-0"
:class="{ :class="{
'flex-1 justify-between': !showInboxName, 'flex-1 justify-between': !showInboxName,
}" }"
@@ -317,7 +317,10 @@ const deleteConversation = () => {
<fluent-icon icon="person" size="12" class="text-n-slate-11" /> <fluent-icon icon="person" size="12" class="text-n-slate-11" />
{{ assignee.name }} {{ assignee.name }}
</span> </span>
<PriorityMark :priority="chat.priority" class="flex-shrink-0" /> <CardPriorityIcon
:priority="chat.priority"
class="flex-shrink-0 !size-3.5"
/>
</div> </div>
</div> </div>
<h4 <h4
@@ -1,53 +0,0 @@
<script>
import { CONVERSATION_PRIORITY } from '../../../../shared/constants/messages';
export default {
name: 'PriorityMark',
props: {
priority: {
type: String,
default: '',
validate: value =>
[...Object.values(CONVERSATION_PRIORITY), ''].includes(value),
},
},
data() {
return {
CONVERSATION_PRIORITY,
};
},
computed: {
tooltipText() {
return this.$t(
`CONVERSATION.PRIORITY.OPTIONS.${this.priority.toUpperCase()}`
);
},
isUrgent() {
return this.priority === CONVERSATION_PRIORITY.URGENT;
},
},
};
</script>
<!-- eslint-disable-next-line vue/no-root-v-if -->
<template>
<span
v-if="priority"
v-tooltip="{
content: tooltipText,
delay: { show: 1500, hide: 0 },
}"
class="shrink-0 rounded-sm inline-flex items-center justify-center w-3.5 h-3.5"
:class="{
'bg-n-ruby-4 text-n-ruby-10': isUrgent,
'bg-n-slate-4 text-n-slate-11': !isUrgent,
}"
>
<fluent-icon
:icon="`priority-${priority.toLowerCase()}`"
:size="isUrgent ? 12 : 14"
class="flex-shrink-0"
view-box="0 0 14 14"
/>
</span>
</template>
@@ -253,6 +253,9 @@ export default {
if (this.isAnInstagramChannel) { if (this.isAnInstagramChannel) {
return MESSAGE_MAX_LENGTH.INSTAGRAM; return MESSAGE_MAX_LENGTH.INSTAGRAM;
} }
if (this.isATelegramChannel) {
return MESSAGE_MAX_LENGTH.TELEGRAM;
}
if (this.isATiktokChannel) { if (this.isATiktokChannel) {
return MESSAGE_MAX_LENGTH.TIKTOK; return MESSAGE_MAX_LENGTH.TIKTOK;
} }
@@ -545,7 +548,10 @@ export default {
}, },
setCopilotAcceptedMessage(message, replyType = this.replyType) { setCopilotAcceptedMessage(message, replyType = this.replyType) {
const key = this.getDraftKey(this.conversationIdByRoute, replyType); const key = this.getDraftKey(this.conversationIdByRoute, replyType);
this.copilotAcceptedMessages[key] = trimContent(message || ''); this.copilotAcceptedMessages[key] = trimContent(
message || '',
this.maxLength
);
}, },
clearCopilotAcceptedMessage(replyType = this.replyType) { clearCopilotAcceptedMessage(replyType = this.replyType) {
const key = this.getDraftKey(this.conversationIdByRoute, replyType); const key = this.getDraftKey(this.conversationIdByRoute, replyType);
@@ -603,7 +609,7 @@ export default {
saveDraft(conversationId, replyType) { saveDraft(conversationId, replyType) {
if (this.message || this.message === '') { if (this.message || this.message === '') {
const key = this.getDraftKey(conversationId, replyType); const key = this.getDraftKey(conversationId, replyType);
const draftToSave = trimContent(this.message || ''); const draftToSave = trimContent(this.message || '', this.maxLength);
this.$store.dispatch('draftMessages/set', { this.$store.dispatch('draftMessages/set', {
key, key,
@@ -9,7 +9,6 @@ import { useImageZoom } from 'dashboard/composables/useImageZoom';
import { messageTimestamp } from 'shared/helpers/timeHelper'; import { messageTimestamp } from 'shared/helpers/timeHelper';
import { downloadFile } from '@chatwoot/utils'; import { downloadFile } from '@chatwoot/utils';
import WootModal from 'dashboard/components/Modal.vue';
import NextButton from 'dashboard/components-next/button/Button.vue'; import NextButton from 'dashboard/components-next/button/Button.vue';
import Avatar from 'next/avatar/Avatar.vue'; import Avatar from 'next/avatar/Avatar.vue';
import TeleportWithDirection from 'dashboard/components-next/TeleportWithDirection.vue'; import TeleportWithDirection from 'dashboard/components-next/TeleportWithDirection.vue';
@@ -169,7 +168,7 @@ onMounted(() => {
<template> <template>
<TeleportWithDirection to="body"> <TeleportWithDirection to="body">
<WootModal <woot-modal
v-model:show="show" v-model:show="show"
full-width full-width
:show-close-button="false" :show-close-button="false"
@@ -212,7 +211,7 @@ onMounted(() => {
</div> </div>
<div <div
class="flex-1 mx-2 px-2 truncate text-sm font-medium text-center text-n-slate-12 hidden sm:block" class="flex-1 mx-2 px-2 truncate text-sm font-medium text-center text-n-slate-12"
> >
<span v-dompurify-html="fileNameFromDataUrl" class="truncate" /> <span v-dompurify-html="fileNameFromDataUrl" class="truncate" />
</div> </div>
@@ -354,6 +353,6 @@ onMounted(() => {
</div> </div>
</footer> </footer>
</div> </div>
</WootModal> </woot-modal>
</TeleportWithDirection> </TeleportWithDirection>
</template> </template>
@@ -2,12 +2,6 @@ import { computed, unref } from 'vue';
import { getCurrentInstance } from 'vue'; import { getCurrentInstance } from 'vue';
export const useStore = () => { export const useStore = () => {
// eslint-disable-next-line no-underscore-dangle
if (window.__CHATWOOT_STORE__) {
// eslint-disable-next-line no-underscore-dangle
return window.__CHATWOOT_STORE__;
}
const vm = getCurrentInstance(); const vm = getCurrentInstance();
if (!vm) throw new Error('must be called in setup'); if (!vm) throw new Error('must be called in setup');
return vm.proxy.$store; return vm.proxy.$store;
@@ -11,12 +11,7 @@ export function useAccount() {
* Computed property for the current account ID. * Computed property for the current account ID.
* @type {import('vue').ComputedRef<number>} * @type {import('vue').ComputedRef<number>}
*/ */
// In the isolated shell (react-components / Web Component context), const route = useRoute();
// vue-router is not available. Fall back to the global variable.
// eslint-disable-next-line no-underscore-dangle
const isIsolatedShell = !!window.__WOOT_ISOLATED_SHELL__;
const route = isIsolatedShell ? null : useRoute();
const store = useStore(); const store = useStore();
const getAccountFn = useMapGetter('accounts/getAccount'); const getAccountFn = useMapGetter('accounts/getAccount');
const isOnChatwootCloud = useMapGetter('globalConfig/isOnChatwootCloud'); const isOnChatwootCloud = useMapGetter('globalConfig/isOnChatwootCloud');
@@ -25,10 +20,6 @@ export function useAccount() {
); );
const accountId = computed(() => { const accountId = computed(() => {
if (isIsolatedShell) {
// eslint-disable-next-line no-underscore-dangle
return Number(window.__WOOT_ACCOUNT_ID__);
}
return Number(route.params.accountId); return Number(route.params.accountId);
}); });
const currentAccount = computed(() => getAccountFn.value(accountId.value)); const currentAccount = computed(() => getAccountFn.value(accountId.value));
+1
View File
@@ -37,6 +37,7 @@ export const FEATURE_FLAGS = {
CHANNEL_INSTAGRAM: 'channel_instagram', CHANNEL_INSTAGRAM: 'channel_instagram',
CHANNEL_TIKTOK: 'channel_tiktok', CHANNEL_TIKTOK: 'channel_tiktok',
CONTACT_CHATWOOT_SUPPORT_TEAM: 'contact_chatwoot_support_team', CONTACT_CHATWOOT_SUPPORT_TEAM: 'contact_chatwoot_support_team',
CAPTAIN_CUSTOM_TOOLS: 'custom_tools',
CAPTAIN_V2: 'captain_integration_v2', CAPTAIN_V2: 'captain_integration_v2',
CAPTAIN_TASKS: 'captain_tasks', CAPTAIN_TASKS: 'captain_tasks',
SAML: 'saml', SAML: 'saml',
@@ -10,10 +10,7 @@ const { isImpersonating } = useImpersonation();
class ActionCableConnector extends BaseActionCableConnector { class ActionCableConnector extends BaseActionCableConnector {
constructor(app, pubsubToken) { constructor(app, pubsubToken) {
const { websocketURL = '' } = window.chatwootConfig || {}; const { websocketURL = '' } = window.chatwootConfig || {};
super(app, pubsubToken, websocketURL);
// eslint-disable-next-line no-underscore-dangle
const wsURL = websocketURL || window.__WEBSOCKET_URL__ || '';
super(app, pubsubToken, wsURL);
this.CancelTyping = []; this.CancelTyping = [];
this.events = { this.events = {
'message.created': this.onMessageCreated, 'message.created': this.onMessageCreated,
@@ -101,10 +98,7 @@ class ActionCableConnector extends BaseActionCableConnector {
conversation: { last_activity_at: lastActivityAt }, conversation: { last_activity_at: lastActivityAt },
conversation_id: conversationId, conversation_id: conversationId,
} = data; } = data;
// eslint-disable-next-line no-underscore-dangle DashboardAudioNotificationHelper.onNewMessage(data);
if (!window.__WOOT_ISOLATED_SHELL__) {
DashboardAudioNotificationHelper.onNewMessage(data);
}
this.app.$store.dispatch('addMessage', data); this.app.$store.dispatch('addMessage', data);
this.app.$store.dispatch('updateConversationLastActivity', { this.app.$store.dispatch('updateConversationLastActivity', {
lastActivityAt, lastActivityAt,
@@ -1,6 +1,18 @@
/* eslint no-param-reassign: 0 */
import getUuid from 'widget/helpers/uuid'; import getUuid from 'widget/helpers/uuid';
import { MESSAGE_STATUS, MESSAGE_TYPE } from 'shared/constants/messages'; import { MESSAGE_STATUS, MESSAGE_TYPE } from 'shared/constants/messages';
export default () => {
if (!Array.prototype.last) {
Object.assign(Array.prototype, {
last() {
return this[this.length - 1];
},
});
}
};
export const isEmptyObject = obj => export const isEmptyObject = obj =>
Object.keys(obj).length === 0 && obj.constructor === Object; Object.keys(obj).length === 0 && obj.constructor === Object;
@@ -166,6 +166,8 @@ const TOD_TO_MERIDIEM = {
evening: 'pm', evening: 'pm',
night: 'pm', night: 'pm',
}; };
const CJK_CHAR_RE =
/[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u;
// ─── Translation Cache ────────────────────────────────────────────────────── // ─── Translation Cache ──────────────────────────────────────────────────────
@@ -278,8 +280,13 @@ const escapeRegex = s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const substituteLocalTokens = (text, pairs) => { const substituteLocalTokens = (text, pairs) => {
let r = text; let r = text;
pairs.forEach(([local, en]) => { pairs.forEach(([local, en]) => {
const re = new RegExp(`(?<=^|\\s)${escapeRegex(local)}(?=\\s|$)`, 'g'); if (CJK_CHAR_RE.test(local)) {
r = r.replace(re, en); const re = new RegExp(escapeRegex(local), 'g');
r = r.replace(re, ` ${en} `);
} else {
const re = new RegExp(`(?<=^|\\s)${escapeRegex(local)}(?=\\s|$)`, 'g');
r = r.replace(re, en);
}
}); });
return r; return r;
}; };
@@ -82,6 +82,9 @@ const ORDINAL_RE = `(\\d{1,2}(?:st|nd|rd|th)?|${ORDINAL_WORDS})`;
const HALF_UNIT_RE = /^(?:in\s+)?half\s+(?:an?\s+)?(hour|day|week|month|year)$/; const HALF_UNIT_RE = /^(?:in\s+)?half\s+(?:an?\s+)?(hour|day|week|month|year)$/;
const RELATIVE_DURATION_RE = new RegExp(`^(?:in\\s+)?${NUM_RE}\\s+${UNIT_RE}$`); const RELATIVE_DURATION_RE = new RegExp(`^(?:in\\s+)?${NUM_RE}\\s+${UNIT_RE}$`);
const RELATIVE_DURATION_AFTER_RE = new RegExp(
`^(?:in\\s+)?${NUM_RE}\\s+${UNIT_RE}\\s+after$`
);
const DURATION_FROM_NOW_RE = new RegExp( const DURATION_FROM_NOW_RE = new RegExp(
`^${NUM_RE}\\s+${UNIT_RE}\\s+from\\s+now$` `^${NUM_RE}\\s+${UNIT_RE}\\s+from\\s+now$`
); );
@@ -89,6 +92,9 @@ const RELATIVE_DAY_ONLY_RE = new RegExp(`^(${RELATIVE_DAYS})$`);
const RELATIVE_DAY_TOD_RE = new RegExp( const RELATIVE_DAY_TOD_RE = new RegExp(
`^(${RELATIVE_DAYS})\\s+(?:at\\s+)?(${TIME_OF_DAY_NAMES})$` `^(${RELATIVE_DAYS})\\s+(?:at\\s+)?(${TIME_OF_DAY_NAMES})$`
); );
const RELATIVE_DAY_MERIDIEM_RE = new RegExp(
`^(${RELATIVE_DAYS})\\s+(?:at\\s+)?(am|pm)$`
);
const RELATIVE_DAY_TOD_TIME_RE = new RegExp( const RELATIVE_DAY_TOD_TIME_RE = new RegExp(
`^(${RELATIVE_DAYS})\\s+(?:at\\s+)?(${TIME_OF_DAY_NAMES})\\s+(\\d{1,2}(?::\\d{2})?)$` `^(${RELATIVE_DAYS})\\s+(?:at\\s+)?(${TIME_OF_DAY_NAMES})\\s+(\\d{1,2}(?::\\d{2})?)$`
); );
@@ -245,6 +251,7 @@ const matchDuration = (text, now) => {
return ( return (
parseDuration(text.match(DURATION_FROM_NOW_RE), now) || parseDuration(text.match(DURATION_FROM_NOW_RE), now) ||
parseDuration(text.match(RELATIVE_DURATION_AFTER_RE), now) ||
parseDuration(text.match(RELATIVE_DURATION_RE), now) parseDuration(text.match(RELATIVE_DURATION_RE), now)
); );
}; };
@@ -303,6 +310,13 @@ const matchRelativeDay = (text, now) => {
); );
} }
const dayMeridiemMatch = text.match(RELATIVE_DAY_MERIDIEM_RE);
if (dayMeridiemMatch) {
const [, dayKey, meridiem] = dayMeridiemMatch;
const hours = meridiem === 'am' ? 9 : 14;
return applyTimeWithRollover(RELATIVE_DAY_MAP[dayKey], hours, 0, now);
}
const dayAtTimeMatch = text.match(RELATIVE_DAY_AT_TIME_RE); const dayAtTimeMatch = text.match(RELATIVE_DAY_AT_TIME_RE);
if (dayAtTimeMatch) { if (dayAtTimeMatch) {
const [, dayKey, timeRaw] = dayAtTimeMatch; const [, dayKey, timeRaw] = dayAtTimeMatch;
@@ -1626,6 +1626,24 @@ describe('generateDateSuggestions — localized input regressions', () => {
}, },
}; };
const zhTWSnoozeTranslations = {
UNITS: {
HOUR: '小時',
HOURS: '小時',
DAY: '天',
DAYS: '天',
},
HALF: '半',
RELATIVE: {
TOMORROW: '明天',
},
MERIDIEM: {
AM: '上午',
PM: '下午',
},
AFTER: '後',
};
describe('P1: short non-English tokens must NOT produce spurious half-duration suggestions', () => { describe('P1: short non-English tokens must NOT produce spurious half-duration suggestions', () => {
it('Arabic "غد" does not produce half-duration suggestions', () => { it('Arabic "غد" does not produce half-duration suggestions', () => {
const results = generateDateSuggestions('غد', now, { const results = generateDateSuggestions('غد', now, {
@@ -1721,6 +1739,37 @@ describe('generateDateSuggestions — localized input regressions', () => {
expect(results[0].date.getHours()).toBe(6); expect(results[0].date.getHours()).toBe(6);
}); });
}); });
describe('zh_TW compact CJK inputs', () => {
const options = {
translations: zhTWSnoozeTranslations,
locale: 'zh-TW',
};
it('parses "2小時後" (2 hours from now) without spaces', () => {
const results = generateDateSuggestions('2小時後', now, options);
expect(results.length).toBeGreaterThan(0);
expect(results[0].date.getDate()).toBe(16);
expect(results[0].date.getHours()).toBe(12);
expect(results[0].date.getMinutes()).toBe(0);
});
it('parses "半天" (half day) without spaces', () => {
const results = generateDateSuggestions('半天', now, options);
expect(results.length).toBeGreaterThan(0);
expect(results[0].date.getDate()).toBe(16);
expect(results[0].date.getHours()).toBe(22);
expect(results[0].date.getMinutes()).toBe(0);
});
it('parses "明天 上午" (tomorrow AM) into tomorrow 9am', () => {
const results = generateDateSuggestions('明天 上午', now, options);
expect(results.length).toBeGreaterThan(0);
expect(results[0].date.getDate()).toBe(17);
expect(results[0].date.getHours()).toBe(9);
expect(results[0].date.getMinutes()).toBe(0);
});
});
}); });
describe('no-space duration suggestions', () => { describe('no-space duration suggestions', () => {
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,39 +1,39 @@
{ {
"REPORT": { "REPORT": {
"HEADER": "Conversations", "HEADER": "Conversations",
"LOADING_CHART": "Loading chart data...", "LOADING_CHART": "ገበታ ውሂብ በማስጫን ላይ...",
"NO_ENOUGH_DATA": "We've not received enough data points to generate report, Please try again later.", "NO_ENOUGH_DATA": "ሪፖርት ለማመንጨት በቂ ውሂብ ነጥቦች አልደረሰንም፣ እባክዎ በኋላ ደግመው ይሞክሩ።",
"DOWNLOAD_CONVERSATION_REPORTS": "Download conversation reports", "DOWNLOAD_CONVERSATION_REPORTS": "Download conversation reports",
"DATA_FETCHING_FAILED": "Failed to fetch data, please try again later.", "DATA_FETCHING_FAILED": "Failed to fetch data, please try again later.",
"SUMMARY_FETCHING_FAILED": "Failed to fetch summary, please try again later.", "SUMMARY_FETCHING_FAILED": "Failed to fetch summary, please try again later.",
"METRICS": { "METRICS": {
"CONVERSATIONS": { "CONVERSATIONS": {
"NAME": "Conversations", "NAME": "ውይይቶች",
"DESC": "( Total )" "DESC": "( ጠቅላላ )"
}, },
"INCOMING_MESSAGES": { "INCOMING_MESSAGES": {
"NAME": "Messages received", "NAME": "Messages received",
"DESC": "( Total )" "DESC": "( ጠቅላላ )"
}, },
"OUTGOING_MESSAGES": { "OUTGOING_MESSAGES": {
"NAME": "Messages sent", "NAME": "Messages sent",
"DESC": "( Total )" "DESC": "( ጠቅላላ )"
}, },
"FIRST_RESPONSE_TIME": { "FIRST_RESPONSE_TIME": {
"NAME": "First Response Time", "NAME": "First Response Time",
"DESC": "( Avg )", "DESC": "( አማካይ )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "Total number of conversations used for computation:",
"TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)"
}, },
"RESOLUTION_TIME": { "RESOLUTION_TIME": {
"NAME": "Resolution Time", "NAME": "የመፍትሄ ጊዜ",
"DESC": "( Avg )", "DESC": "( አማካይ )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "Total number of conversations used for computation:",
"TOOLTIP_TEXT": "Resolution Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "Resolution Time is {metricValue} (based on {conversationCount} conversations)"
}, },
"RESOLUTION_COUNT": { "RESOLUTION_COUNT": {
"NAME": "Resolution Count", "NAME": "የመፍትሄ ብዛት",
"DESC": "( Total )" "DESC": "( ጠቅላላ )"
}, },
"BOT_RESOLUTION_COUNT": { "BOT_RESOLUTION_COUNT": {
"NAME": "Resolution Count", "NAME": "Resolution Count",
@@ -61,8 +61,8 @@
"CUSTOM_DATE_RANGE": "Custom date range" "CUSTOM_DATE_RANGE": "Custom date range"
}, },
"CUSTOM_DATE_RANGE": { "CUSTOM_DATE_RANGE": {
"CONFIRM": "Apply", "CONFIRM": "አተግባር ላይ አውርድ",
"PLACEHOLDER": "Select date range" "PLACEHOLDER": "የቀን ክልል ይምረጡ"
}, },
"GROUP_BY_FILTER_DROPDOWN_LABEL": "Group By", "GROUP_BY_FILTER_DROPDOWN_LABEL": "Group By",
"DURATION_FILTER_LABEL": "Duration", "DURATION_FILTER_LABEL": "Duration",
@@ -127,12 +127,12 @@
} }
}, },
"AGENT_REPORTS": { "AGENT_REPORTS": {
"HEADER": "Agents Overview", "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": "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.",
"LOADING_CHART": "Loading chart data...", "LOADING_CHART": "የቅርጸ ቁምፊ ውሂብ በመጫን ላይ...",
"NO_ENOUGH_DATA": "We've not received enough data points to generate report, Please try again later.", "NO_ENOUGH_DATA": "ሪፖርት ለማቅረብ በቂ ውሂብ አልደረሰንም፣ እባክዎ በኋላ ደግመው ይሞክሩ።.",
"DOWNLOAD_AGENT_REPORTS": "Download agent reports", "DOWNLOAD_AGENT_REPORTS": "የAgent ሪፖርቶችን አውርድ",
"FILTER_DROPDOWN_LABEL": "Select Agent", "FILTER_DROPDOWN_LABEL": "Agent ይምረጡ",
"FILTERS": { "FILTERS": {
"INPUT_PLACEHOLDER": { "INPUT_PLACEHOLDER": {
"AGENTS": "Search agents" "AGENTS": "Search agents"
@@ -140,20 +140,20 @@
}, },
"METRICS": { "METRICS": {
"CONVERSATIONS": { "CONVERSATIONS": {
"NAME": "Conversations", "NAME": "ውይይቶች",
"DESC": "( Total )" "DESC": "( ጠቅላላ )"
}, },
"INCOMING_MESSAGES": { "INCOMING_MESSAGES": {
"NAME": "Incoming Messages", "NAME": "የመጣ መልእክቶች",
"DESC": "( Total )" "DESC": "( ጠቅላላ )"
}, },
"OUTGOING_MESSAGES": { "OUTGOING_MESSAGES": {
"NAME": "Outgoing Messages", "NAME": "የሚያልኩ መልእክቶች",
"DESC": "( Total )" "DESC": "( ጠቅላላ )"
}, },
"FIRST_RESPONSE_TIME": { "FIRST_RESPONSE_TIME": {
"NAME": "First Response Time", "NAME": "First Response Time",
"DESC": "( Avg )", "DESC": "( አማካይ )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "Total number of conversations used for computation:",
"TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)"
}, },
@@ -424,7 +424,7 @@
} }
}, },
"CSAT_REPORTS": { "CSAT_REPORTS": {
"HEADER": "CSAT Reports", "HEADER": "CSAT ሪፖርቶች",
"NO_RECORDS": "No responses yet", "NO_RECORDS": "No responses yet",
"NO_RECORDS_DESCRIPTION": "CSAT survey responses will appear here once customers start providing feedback.", "NO_RECORDS_DESCRIPTION": "CSAT survey responses will appear here once customers start providing feedback.",
"DOWNLOAD": "Download CSAT Reports", "DOWNLOAD": "Download CSAT Reports",
@@ -454,10 +454,10 @@
}, },
"TABLE": { "TABLE": {
"HEADER": { "HEADER": {
"CONTACT_NAME": "Contact", "CONTACT_NAME": "እውቂያ",
"AGENT_NAME": "Agent", "AGENT_NAME": "Agent",
"RATING": "Rating", "RATING": "እምነት ደረጃ",
"FEEDBACK_TEXT": "Feedback comment", "FEEDBACK_TEXT": "አስተያየት አስተያየት",
"CONVERSATION": "Conversation", "CONVERSATION": "Conversation",
"CUSTOMER": "Customer", "CUSTOMER": "Customer",
"RESPONSE": "Response", "RESPONSE": "Response",
@@ -469,16 +469,16 @@
"NO_FEEDBACK": "No feedback provided", "NO_FEEDBACK": "No feedback provided",
"METRIC": { "METRIC": {
"TOTAL_RESPONSES": { "TOTAL_RESPONSES": {
"LABEL": "Total responses", "LABEL": "ጠቅላላ ምላሾች",
"TOOLTIP": "Total number of responses collected" "TOOLTIP": "የተሰበሰበው ምላሾች ጠቅላላ ብዛት"
}, },
"SATISFACTION_SCORE": { "SATISFACTION_SCORE": {
"LABEL": "Satisfaction score", "LABEL": "የደስታ ነጥብ",
"TOOLTIP": "Total number of positive responses / Total number of responses * 100" "TOOLTIP": "አጠቃላይ የአዎንታዊ ምላሾች ብዛት / አጠቃላይ የምላሾች ብዛት * 100"
}, },
"RESPONSE_RATE": { "RESPONSE_RATE": {
"LABEL": "Response rate", "LABEL": "የምላሽ ተመን",
"TOOLTIP": "Total number of responses / Total number of CSAT survey messages sent * 100" "TOOLTIP": "አጠቃላይ የምላሾች ብዛት / አጠቃላይ የተላኩ የCSAT እቅድ መልእክቶች ብዛት * 100"
}, },
"RATING_DISTRIBUTION": "Rating distribution" "RATING_DISTRIBUTION": "Rating distribution"
}, },
File diff suppressed because it is too large Load Diff
@@ -710,9 +710,21 @@
"MESSENGER_SUB_HEAD": "ضع هذا الكود داخل وسم الـ body في موقعك", "MESSENGER_SUB_HEAD": "ضع هذا الكود داخل وسم الـ body في موقعك",
"ALLOWED_DOMAINS": { "ALLOWED_DOMAINS": {
"TITLE": "Allowed Domains", "TITLE": "Allowed Domains",
"SUBTITLE": "Add wildcard or regular domains separated by commas (leave blank to allow all), e.g. *.chatwoot.dev, chatwoot.com.", "DESCRIPTION": "Restrict which websites can embed your chat widget. For security, only add domains you own and trust. Add one or more domains separated by commas. Leave blank to allow all domains (not recommended for production).",
"PLACEHOLDER": "example.com, www.example.com, app.example.com" "PLACEHOLDER": "example.com, www.example.com, app.example.com"
}, },
"ALLOW_MOBILE_WEBVIEW": {
"LABEL": "Enable widget in mobile apps",
"SUBTITLE": "Check this if you embed the widget in iOS or Android apps. Mobile apps don't send domain information, so they would be blocked by domain restrictions unless this is enabled."
},
"IDENTITY_VALIDATION": {
"TITLE": "Identity Validation",
"DESCRIPTION": "Verify user authenticity by generating secure tokens. This prevents unauthorized users from impersonating others in your chat.",
"SECRET_KEY": "Secret Key",
"VIEW_DOCS": "View documentation",
"REQUIRE_LABEL": "Require identity validation for all conversations",
"REQUIRE_DESCRIPTION": "When enabled, users must provide a valid identity token to start conversations. Requests without valid tokens will be rejected."
},
"INBOX_AGENTS": "وكيل الدعم", "INBOX_AGENTS": "وكيل الدعم",
"INBOX_AGENTS_SUB_TEXT": "إضافة أو إزالة وكلاء من صندوق الوارد هذا", "INBOX_AGENTS_SUB_TEXT": "إضافة أو إزالة وكلاء من صندوق الوارد هذا",
"AGENT_ASSIGNMENT": "تعيين المحادثة", "AGENT_ASSIGNMENT": "تعيين المحادثة",
@@ -527,7 +527,8 @@
"TITLE": "الخصائص", "TITLE": "الخصائص",
"ALLOW_CONVERSATION_FAQS": "Generate FAQs from resolved conversations", "ALLOW_CONVERSATION_FAQS": "Generate FAQs from resolved conversations",
"ALLOW_MEMORIES": "Capture key details as memories from customer interactions.", "ALLOW_MEMORIES": "Capture key details as memories from customer interactions.",
"ALLOW_CITATIONS": "Include source citations in responses" "ALLOW_CITATIONS": "Include source citations in responses",
"ALLOW_CONTACT_ATTRIBUTES": "Allow access to contact information"
} }
}, },
"EDIT": { "EDIT": {
@@ -1,31 +1,31 @@
{ {
"CONTACT_PANEL": { "CONTACT_PANEL": {
"NOT_AVAILABLE": "Not Available", "NOT_AVAILABLE": "Mövcud deyil",
"EMAIL_ADDRESS": "Email Address", "EMAIL_ADDRESS": "Email Address",
"PHONE_NUMBER": "Phone number", "PHONE_NUMBER": "Telefon nömrəsi",
"IDENTIFIER": "Identifier", "IDENTIFIER": "Identifier",
"COPY_SUCCESSFUL": "Copied to clipboard successfully", "COPY_SUCCESSFUL": "Copied to clipboard successfully",
"COMPANY": "Company", "COMPANY": "Şirkət",
"LOCATION": "Location", "LOCATION": "Yer",
"BROWSER_LANGUAGE": "Browser Language", "BROWSER_LANGUAGE": "Browser Language",
"CONVERSATION_TITLE": "Conversation Details", "CONVERSATION_TITLE": "Conversation Details",
"VIEW_PROFILE": "View Profile", "VIEW_PROFILE": "View Profile",
"BROWSER": "Browser", "BROWSER": "Browser",
"OS": "Operating System", "OS": "Əməliyyat Sistemi",
"INITIATED_FROM": "Initiated from", "INITIATED_FROM": "Başlanğıc yeri",
"INITIATED_AT": "Initiated at", "INITIATED_AT": "Başlanğıc vaxtı",
"IP_ADDRESS": "IP Address", "IP_ADDRESS": "IP ünvanı",
"CREATED_AT_LABEL": "Created", "CREATED_AT_LABEL": "Yaradılıb",
"NEW_MESSAGE": "New message", "NEW_MESSAGE": "New message",
"CALL": "Call", "CALL": "Zəng et",
"CALL_INITIATED": "Calling the contact…", "CALL_INITIATED": "Calling the contact…",
"CALL_FAILED": "Unable to start the call. Please try again.", "CALL_FAILED": "Unable to start the call. Please try again.",
"VOICE_INBOX_PICKER": { "VOICE_INBOX_PICKER": {
"TITLE": "Choose a voice inbox" "TITLE": "Choose a voice inbox"
}, },
"CONVERSATIONS": { "CONVERSATIONS": {
"NO_RECORDS_FOUND": "There are no previous conversations associated to this contact.", "NO_RECORDS_FOUND": "Bu əlaqə ilə bağlı əvvəlki söhbətlər yoxdur.",
"TITLE": "Previous Conversations" "TITLE": "Əvvəlki Söhbətlər"
}, },
"LABELS": { "LABELS": {
"CONTACT": { "CONTACT": {
@@ -44,23 +44,23 @@
} }
}, },
"MERGE_CONTACT": "Merge contact", "MERGE_CONTACT": "Merge contact",
"CONTACT_ACTIONS": "Contact actions", "CONTACT_ACTIONS": "Əlaqə əməliyyatları",
"MUTE_CONTACT": "Block Contact", "MUTE_CONTACT": "Block Contact",
"UNMUTE_CONTACT": "Unblock Contact", "UNMUTE_CONTACT": "Unblock Contact",
"MUTED_SUCCESS": "This contact is blocked successfully. You will not be notified of any future conversations.", "MUTED_SUCCESS": "This contact is blocked successfully. You will not be notified of any future conversations.",
"UNMUTED_SUCCESS": "This contact is unblocked successfully.", "UNMUTED_SUCCESS": "Bu əlaqənin bloku uğurla açıldı.",
"SEND_TRANSCRIPT": "Send Transcript", "SEND_TRANSCRIPT": "Mətni Göndər",
"EDIT_LABEL": "Edit", "EDIT_LABEL": "Redaktə et",
"SIDEBAR_SECTIONS": { "SIDEBAR_SECTIONS": {
"CUSTOM_ATTRIBUTES": "Custom Attributes", "CUSTOM_ATTRIBUTES": "Custom Attributes",
"CONTACT_LABELS": "Contact Labels", "CONTACT_LABELS": "Contact Labels",
"PREVIOUS_CONVERSATIONS": "Previous Conversations", "PREVIOUS_CONVERSATIONS": "Əvvəlki Söhbətlər",
"NO_RECORDS_FOUND": "No attributes found" "NO_RECORDS_FOUND": "No attributes found"
} }
}, },
"EDIT_CONTACT": { "EDIT_CONTACT": {
"BUTTON_LABEL": "Edit Contact", "BUTTON_LABEL": "Əlaqəni redaktə et",
"TITLE": "Edit contact", "TITLE": "Əlaqəni redaktə et",
"DESC": "Edit contact details" "DESC": "Edit contact details"
}, },
"DELETE_CONTACT": { "DELETE_CONTACT": {
@@ -71,23 +71,23 @@
"TITLE": "Confirm Deletion", "TITLE": "Confirm Deletion",
"MESSAGE": "Are you sure to delete ", "MESSAGE": "Are you sure to delete ",
"YES": "Yes, Delete", "YES": "Yes, Delete",
"NO": "No, Keep" "NO": "Xeyr, Saxla"
}, },
"API": { "API": {
"SUCCESS_MESSAGE": "Contact deleted successfully", "SUCCESS_MESSAGE": "Contact deleted successfully",
"ERROR_MESSAGE": "Could not delete contact. Please try again later." "ERROR_MESSAGE": "Əlaqəni silmək mümkün olmadı. Zəhmət olmasa, bir az sonra yenidən cəhd edin."
} }
}, },
"CONTACT_FORM": { "CONTACT_FORM": {
"FORM": { "FORM": {
"SUBMIT": "Submit", "SUBMIT": "Submit",
"CANCEL": "Cancel", "CANCEL": "Ləğv et",
"AVATAR": { "AVATAR": {
"LABEL": "Contact Avatar" "LABEL": "Contact Avatar"
}, },
"NAME": { "NAME": {
"PLACEHOLDER": "Enter the full name of the contact", "PLACEHOLDER": "Əlaqənin tam adını daxil edin",
"LABEL": "Full Name" "LABEL": "Tam Ad"
}, },
"BIO": { "BIO": {
"PLACEHOLDER": "Enter the bio of the contact", "PLACEHOLDER": "Enter the bio of the contact",
@@ -100,30 +100,30 @@
"ERROR": "Please enter a valid email address." "ERROR": "Please enter a valid email address."
}, },
"PHONE_NUMBER": { "PHONE_NUMBER": {
"PLACEHOLDER": "Enter the phone number of the contact", "PLACEHOLDER": "Əlaqə şəxsin telefon nömrəsini daxil edin",
"LABEL": "Phone Number", "LABEL": "Telefon nömrəsi",
"HELP": "Phone number should be of E.164 format eg: +1415555555 [+][country code][area code][local phone number]. You can select the dial code from the dropdown.", "HELP": "Telefon nömrəsi E.164 formatında olmalıdır, məsələn: +1415555555. Ölkə kodunu siyahıdan seçə bilərsiniz.",
"ERROR": "Phone number should be either empty or of E.164 format", "ERROR": "Telefon nömrəsi ya boş olmalıdır, ya da E.164 formatında olmalıdır",
"DIAL_CODE_ERROR": "Please select a dial code from the list", "DIAL_CODE_ERROR": "Zəhmət olmasa siyahıdan kodu seçin",
"DUPLICATE": "This phone number is in use for another contact." "DUPLICATE": "Bu telefon nömrəsi başqa bir əlaqə üçün istifadə olunur."
}, },
"LOCATION": { "LOCATION": {
"PLACEHOLDER": "Enter the location of the contact", "PLACEHOLDER": "Əlaqə yerini daxil edin",
"LABEL": "Location" "LABEL": "Yer"
}, },
"COMPANY_NAME": { "COMPANY_NAME": {
"PLACEHOLDER": "Enter the company name", "PLACEHOLDER": "Şirkət adını daxil edin",
"LABEL": "Company Name" "LABEL": "Company Name"
}, },
"COUNTRY": { "COUNTRY": {
"PLACEHOLDER": "Enter the country name", "PLACEHOLDER": "Ölkə adını daxil edin",
"LABEL": "Country Name", "LABEL": "Country Name",
"SELECT_PLACEHOLDER": "Select", "SELECT_PLACEHOLDER": "Seçin",
"REMOVE": "Remove", "REMOVE": "Sil",
"SELECT_COUNTRY": "Select Country" "SELECT_COUNTRY": "Ölkəni seçin"
}, },
"CITY": { "CITY": {
"PLACEHOLDER": "Enter the city name", "PLACEHOLDER": "Şəhərin adını daxil edin",
"LABEL": "City Name" "LABEL": "City Name"
}, },
"SOCIAL_PROFILES": { "SOCIAL_PROFILES": {
@@ -155,23 +155,23 @@
"ERROR_MESSAGE": "There was an error, please try again" "ERROR_MESSAGE": "There was an error, please try again"
}, },
"NEW_CONVERSATION": { "NEW_CONVERSATION": {
"BUTTON_LABEL": "Start conversation", "BUTTON_LABEL": "Söhbətə başla",
"TITLE": "New conversation", "TITLE": "Yeni söhbət",
"DESC": "Start a new conversation by sending a new message.", "DESC": "Start a new conversation by sending a new message.",
"NO_INBOX": "Couldn't find an inbox to initiate a new conversation with this contact.", "NO_INBOX": "Couldn't find an inbox to initiate a new conversation with this contact.",
"FORM": { "FORM": {
"TO": { "TO": {
"LABEL": "To" "LABEL": "Kimə"
}, },
"INBOX": { "INBOX": {
"LABEL": "Via Inbox", "LABEL": "Via Inbox",
"PLACEHOLDER": "Choose source inbox", "PLACEHOLDER": "Choose source inbox",
"ERROR": "Select an inbox" "ERROR": "Bir qutu seçin"
}, },
"SUBJECT": { "SUBJECT": {
"LABEL": "Subject", "LABEL": "Mövzu",
"PLACEHOLDER": "Subject", "PLACEHOLDER": "Mövzu",
"ERROR": "Subject can't be empty" "ERROR": "Mövzu boş ola bilməz"
}, },
"MESSAGE": { "MESSAGE": {
"LABEL": "Message", "LABEL": "Message",
@@ -183,10 +183,10 @@
"HELP_TEXT": "Drag and drop files here or choose files to attach" "HELP_TEXT": "Drag and drop files here or choose files to attach"
}, },
"SUBMIT": "Send message", "SUBMIT": "Send message",
"CANCEL": "Cancel", "CANCEL": "Ləğv et",
"SUCCESS_MESSAGE": "Message sent!", "SUCCESS_MESSAGE": "Message sent!",
"GO_TO_CONVERSATION": "View", "GO_TO_CONVERSATION": "Bax",
"ERROR_MESSAGE": "Couldn't send! try again" "ERROR_MESSAGE": "Göndərmək mümkün olmadı! yenidən cəhd et"
} }
}, },
"CONTACTS_PAGE": { "CONTACTS_PAGE": {
@@ -204,7 +204,7 @@
"ACTIONS": { "ACTIONS": {
"COPY": "Copy attribute", "COPY": "Copy attribute",
"DELETE": "Delete attribute", "DELETE": "Delete attribute",
"EDIT": "Edit attribute" "EDIT": "Xüsusiyyəti redaktə et"
}, },
"ADD": { "ADD": {
"TITLE": "Create custom attribute", "TITLE": "Create custom attribute",
@@ -212,7 +212,7 @@
}, },
"FORM": { "FORM": {
"CREATE": "Add attribute", "CREATE": "Add attribute",
"CANCEL": "Cancel", "CANCEL": "Ləğv et",
"NAME": { "NAME": {
"LABEL": "Custom attribute name", "LABEL": "Custom attribute name",
"PLACEHOLDER": "Eg: shopify id", "PLACEHOLDER": "Eg: shopify id",
@@ -220,12 +220,12 @@
}, },
"VALUE": { "VALUE": {
"LABEL": "Attribute value", "LABEL": "Attribute value",
"PLACEHOLDER": "Eg: 11901 " "PLACEHOLDER": "Məsələn: 11901 "
}, },
"ADD": { "ADD": {
"TITLE": "Create new attribute ", "TITLE": "Create new attribute ",
"SUCCESS": "Attribute added successfully", "SUCCESS": "Xüsusiyyət uğurla əlavə edildi",
"ERROR": "Unable to add attribute. Please try again later" "ERROR": "Xüsusiyyəti əlavə etmək mümkün olmadı. Zəhmət olmasa, bir az sonra yenidən cəhd edin"
}, },
"UPDATE": { "UPDATE": {
"SUCCESS": "Attribute updated successfully", "SUCCESS": "Attribute updated successfully",
@@ -236,52 +236,52 @@
"ERROR": "Unable to delete attribute. Please try again later" "ERROR": "Unable to delete attribute. Please try again later"
}, },
"ATTRIBUTE_SELECT": { "ATTRIBUTE_SELECT": {
"TITLE": "Add attributes", "TITLE": "Xüsusiyyətlər əlavə et",
"PLACEHOLDER": "Search attributes", "PLACEHOLDER": "Search attributes",
"NO_RESULT": "No attributes found" "NO_RESULT": "No attributes found"
}, },
"ATTRIBUTE_TYPE": { "ATTRIBUTE_TYPE": {
"LIST": { "LIST": {
"PLACEHOLDER": "Select value", "PLACEHOLDER": "Dəyəri seçin",
"SEARCH_INPUT_PLACEHOLDER": "Search value", "SEARCH_INPUT_PLACEHOLDER": "Search value",
"NO_RESULT": "No result found" "NO_RESULT": "No result found"
} }
} }
}, },
"VALIDATIONS": { "VALIDATIONS": {
"REQUIRED": "Valid value is required", "REQUIRED": "Düzgün dəyər tələb olunur",
"INVALID_URL": "Invalid URL", "INVALID_URL": "Yanlış URL",
"INVALID_INPUT": "Invalid Input" "INVALID_INPUT": "Yanlış Giriş"
} }
}, },
"MERGE_CONTACTS": { "MERGE_CONTACTS": {
"TITLE": "Merge contacts", "TITLE": "Merge contacts",
"DESCRIPTION": "Merge contacts to combine two profiles into one, including all attributes and conversations. In case of conflict, the Primary contacts attributes will take precedence.", "DESCRIPTION": "İki profili bütün atributlar və söhbətlər daxil olmaqla birləşdirərək əlaqələri birləşdirin. Ziddiyyət olduqda, Əsas əlaqənin atributları üstünlük təşkil edəcək.",
"PRIMARY": { "PRIMARY": {
"TITLE": "Primary contact", "TITLE": "Əsas əlaqə",
"HELP_LABEL": "To be deleted" "HELP_LABEL": "To be deleted"
}, },
"PARENT": { "PARENT": {
"TITLE": "Contact to merge", "TITLE": "Contact to merge",
"PLACEHOLDER": "Search for a contact", "PLACEHOLDER": "Əlaqə axtar",
"HELP_LABEL": "To be kept" "HELP_LABEL": "To be kept"
}, },
"SUMMARY": { "SUMMARY": {
"TITLE": "Summary", "TITLE": "Yekun",
"DELETE_WARNING": "Contact of <strong>{primaryContactName}</strong> will be deleted.", "DELETE_WARNING": "Contact of <strong>{primaryContactName}</strong> will be deleted.",
"ATTRIBUTE_WARNING": "Contact details of <strong>{primaryContactName}</strong> will be copied to <strong>{parentContactName}</strong>." "ATTRIBUTE_WARNING": "Contact details of <strong>{primaryContactName}</strong> will be copied to <strong>{parentContactName}</strong>."
}, },
"SEARCH": { "SEARCH": {
"ERROR_MESSAGE": "Something went wrong. Please try again later." "ERROR_MESSAGE": "Nəsə səhv getdi. Zəhmət olmasa, bir az sonra yenidən cəhd edin."
}, },
"FORM": { "FORM": {
"SUBMIT": " Merge contacts", "SUBMIT": " Merge contacts",
"CANCEL": "Cancel", "CANCEL": "Ləğv et",
"CHILD_CONTACT": { "CHILD_CONTACT": {
"ERROR": "Select a child contact to merge" "ERROR": "Birləşdirmək üçün alt əlaqəni seçin"
}, },
"SUCCESS_MESSAGE": "Contact merged successfully", "SUCCESS_MESSAGE": "Contact merged successfully",
"ERROR_MESSAGE": "Could not merge contacts, try again!" "ERROR_MESSAGE": "Əlaqələri birləşdirmək mümkün olmadı, yenidən cəhd edin!"
}, },
"DROPDOWN_ITEM": { "DROPDOWN_ITEM": {
"ID": "(ID: {identifier})" "ID": "(ID: {identifier})"
@@ -289,68 +289,68 @@
}, },
"CONTACTS_LAYOUT": { "CONTACTS_LAYOUT": {
"HEADER": { "HEADER": {
"TITLE": "Contacts", "TITLE": "Əlaqələr",
"SEARCH_TITLE": "Search contacts", "SEARCH_TITLE": "Əlaqələrdə axtarış",
"ACTIVE_TITLE": "Active contacts", "ACTIVE_TITLE": "Aktiv əlaqələr",
"SEARCH_PLACEHOLDER": "Search...", "SEARCH_PLACEHOLDER": "Axtarış...",
"MESSAGE_BUTTON": "Message", "MESSAGE_BUTTON": "Message",
"SEND_MESSAGE": "Send message", "SEND_MESSAGE": "Send message",
"BLOCK_CONTACT": "Block contact", "BLOCK_CONTACT": "Block contact",
"UNBLOCK_CONTACT": "Unblock contact", "UNBLOCK_CONTACT": "Unblock contact",
"BREADCRUMB": { "BREADCRUMB": {
"CONTACTS": "Contacts" "CONTACTS": "Əlaqələr"
}, },
"ACTIONS": { "ACTIONS": {
"CONTACT_CREATION": { "CONTACT_CREATION": {
"ADD_CONTACT": "Add contact", "ADD_CONTACT": "Əlaqə əlavə et",
"EXPORT_CONTACT": "Export contacts", "EXPORT_CONTACT": "Əlaqələri ixrac et",
"IMPORT_CONTACT": "Import contacts", "IMPORT_CONTACT": "Əlaqələri idxal et",
"SAVE_CONTACT": "Save contact", "SAVE_CONTACT": "Əlaqəni yadda saxla",
"EMAIL_ADDRESS_DUPLICATE": "This email address is in use for another contact.", "EMAIL_ADDRESS_DUPLICATE": "This email address is in use for another contact.",
"PHONE_NUMBER_DUPLICATE": "This phone number is in use for another contact.", "PHONE_NUMBER_DUPLICATE": "Bu telefon nömrəsi başqa bir əlaqə üçün istifadə olunur.",
"SUCCESS_MESSAGE": "Contact saved successfully", "SUCCESS_MESSAGE": "Contact saved successfully",
"ERROR_MESSAGE": "Unable to save contact. Please try again later." "ERROR_MESSAGE": "Əlaqəni saxlamaq mümkün olmadı. Zəhmət olmasa sonra yenidən cəhd edin."
}, },
"BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully", "BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully",
"BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.", "BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.",
"UNBLOCK_SUCCESS_MESSAGE": "This contact is unblocked successfully", "UNBLOCK_SUCCESS_MESSAGE": "Bu əlaqənin bloku uğurla açıldı",
"UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.", "UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.",
"IMPORT_CONTACT": { "IMPORT_CONTACT": {
"TITLE": "Import contacts", "TITLE": "Əlaqələri idxal et",
"DESCRIPTION": "Import contacts through a CSV file.", "DESCRIPTION": "Əlaqələri CSV faylı vasitəsilə idxal edin.",
"DOWNLOAD_LABEL": "Download a sample csv.", "DOWNLOAD_LABEL": "Download a sample csv.",
"LABEL": "CSV File:", "LABEL": "CSV faylı:",
"CHOOSE_FILE": "Choose file", "CHOOSE_FILE": "Fayl seçin",
"CHANGE": "Change", "CHANGE": "Dəyiş",
"CANCEL": "Cancel", "CANCEL": "Ləğv et",
"IMPORT": "Import", "IMPORT": "İdxal et",
"SUCCESS_MESSAGE": "You will be notified via email when the import is complete.", "SUCCESS_MESSAGE": "İdxal bitdikdə sizə elektron bildiriş göndəriləcək.",
"ERROR_MESSAGE": "There was an error, please try again" "ERROR_MESSAGE": "There was an error, please try again"
}, },
"EXPORT_CONTACT": { "EXPORT_CONTACT": {
"TITLE": "Export contacts", "TITLE": "Əlaqələri ixrac et",
"DESCRIPTION": "Quickly export a csv file with comprehensive details of your contacts", "DESCRIPTION": "Quickly export a csv file with comprehensive details of your contacts",
"CONFIRM": "Export", "CONFIRM": "İxrac et",
"SUCCESS_MESSAGE": "Export is in progress. You will be notified on email when the export file is ready to download.", "SUCCESS_MESSAGE": "İxrac davam edir. Fayl hazır olanda sizə elektron bildiriş göndəriləcək.",
"ERROR_MESSAGE": "There was an error, please try again" "ERROR_MESSAGE": "There was an error, please try again"
}, },
"SORT_BY": { "SORT_BY": {
"LABEL": "Sort by", "LABEL": "Sırala",
"OPTIONS": { "OPTIONS": {
"NAME": "Name", "NAME": "Ad",
"EMAIL": "Email", "EMAIL": "Elektron poçt",
"PHONE_NUMBER": "Phone number", "PHONE_NUMBER": "Telefon nömrəsi",
"COMPANY": "Company", "COMPANY": "Şirkət",
"COUNTRY": "Country", "COUNTRY": "Ölkə",
"CITY": "City", "CITY": "Şəhər",
"LAST_ACTIVITY": "Last activity", "LAST_ACTIVITY": "Son fəaliyyət",
"CREATED_AT": "Created at" "CREATED_AT": "Created at"
} }
}, },
"ORDER": { "ORDER": {
"LABEL": "Ordering", "LABEL": "Ordering",
"OPTIONS": { "OPTIONS": {
"ASCENDING": "Ascending", "ASCENDING": "Artan sıra ilə",
"DESCENDING": "Descending" "DESCENDING": "Descending"
} }
}, },
@@ -358,17 +358,17 @@
"CREATE_SEGMENT": { "CREATE_SEGMENT": {
"TITLE": "Do you want to save this filter?", "TITLE": "Do you want to save this filter?",
"CONFIRM": "Save filter", "CONFIRM": "Save filter",
"LABEL": "Name", "LABEL": "Ad",
"PLACEHOLDER": "Enter the name of the filter", "PLACEHOLDER": "Enter the name of the filter",
"ERROR": "Enter a valid name", "ERROR": "Etibarlı ad daxil edin",
"SUCCESS_MESSAGE": "Filter saved successfully", "SUCCESS_MESSAGE": "Filter saved successfully",
"ERROR_MESSAGE": "Unable to save filter. Please try again later." "ERROR_MESSAGE": "Unable to save filter. Please try again later."
}, },
"DELETE_SEGMENT": { "DELETE_SEGMENT": {
"TITLE": "Confirm Deletion", "TITLE": "Confirm Deletion",
"DESCRIPTION": "Are you sure you want to delete this filter?", "DESCRIPTION": "Bu filtrin silinməsini təsdiqləyirsiniz?",
"CONFIRM": "Yes, Delete", "CONFIRM": "Yes, Delete",
"CANCEL": "No, Cancel", "CANCEL": "Xeyr, Ləğv et",
"SUCCESS_MESSAGE": "Filter deleted successfully", "SUCCESS_MESSAGE": "Filter deleted successfully",
"ERROR_MESSAGE": "Unable to delete filter. Please try again later." "ERROR_MESSAGE": "Unable to delete filter. Please try again later."
} }
@@ -379,18 +379,18 @@
"SHOWING": "Showing {startItem} - {endItem} of {totalItems} contacts" "SHOWING": "Showing {startItem} - {endItem} of {totalItems} contacts"
}, },
"FILTER": { "FILTER": {
"NAME": "Name", "NAME": "Ad",
"EMAIL": "Email", "EMAIL": "Elektron poçt",
"PHONE_NUMBER": "Phone number", "PHONE_NUMBER": "Telefon nömrəsi",
"IDENTIFIER": "Identifier", "IDENTIFIER": "Identifier",
"COUNTRY": "Country", "COUNTRY": "Ölkə",
"CITY": "City", "CITY": "Şəhər",
"CREATED_AT": "Created at", "CREATED_AT": "Created at",
"LAST_ACTIVITY": "Last activity", "LAST_ACTIVITY": "Son fəaliyyət",
"REFERER_LINK": "Referer link", "REFERER_LINK": "Referer link",
"BLOCKED": "Blocked", "BLOCKED": "Blocked",
"BLOCKED_TRUE": "True", "BLOCKED_TRUE": "Doğru",
"BLOCKED_FALSE": "False", "BLOCKED_FALSE": "Yanlış",
"BUTTONS": { "BUTTONS": {
"CLEAR_FILTERS": "Clear filters", "CLEAR_FILTERS": "Clear filters",
"UPDATE_SEGMENT": "Update segment", "UPDATE_SEGMENT": "Update segment",
@@ -409,7 +409,7 @@
} }
}, },
"CARD": { "CARD": {
"OF": "of", "OF": "",
"VIEW_DETAILS": "View details", "VIEW_DETAILS": "View details",
"EDIT_DETAILS_FORM": { "EDIT_DETAILS_FORM": {
"TITLE": "Edit contact details", "TITLE": "Edit contact details",
@@ -418,27 +418,27 @@
"PLACEHOLDER": "Enter the first name" "PLACEHOLDER": "Enter the first name"
}, },
"LAST_NAME": { "LAST_NAME": {
"PLACEHOLDER": "Enter the last name" "PLACEHOLDER": "Soyadı daxil edin"
}, },
"EMAIL_ADDRESS": { "EMAIL_ADDRESS": {
"PLACEHOLDER": "Enter the email address", "PLACEHOLDER": "Enter the email address",
"DUPLICATE": "This email address is in use for another contact." "DUPLICATE": "This email address is in use for another contact."
}, },
"PHONE_NUMBER": { "PHONE_NUMBER": {
"PLACEHOLDER": "Enter the phone number", "PLACEHOLDER": "Telefon nömrəsini daxil edin",
"DUPLICATE": "This phone number is in use for another contact." "DUPLICATE": "Bu telefon nömrəsi başqa bir əlaqə üçün istifadə olunur."
}, },
"CITY": { "CITY": {
"PLACEHOLDER": "Enter the city name" "PLACEHOLDER": "Şəhər adını daxil edin"
}, },
"COUNTRY": { "COUNTRY": {
"PLACEHOLDER": "Select country" "PLACEHOLDER": "Ölkəni seçin"
}, },
"BIO": { "BIO": {
"PLACEHOLDER": "Enter the bio" "PLACEHOLDER": "Enter the bio"
}, },
"COMPANY_NAME": { "COMPANY_NAME": {
"PLACEHOLDER": "Enter the company name" "PLACEHOLDER": "Şirkət adını daxil edin"
} }
}, },
"UPDATE_BUTTON": "Update contact", "UPDATE_BUTTON": "Update contact",
@@ -477,8 +477,8 @@
} }
}, },
"DETAILS": { "DETAILS": {
"CREATED_AT": "Created {date}", "CREATED_AT": "Yaradılıb {date}",
"LAST_ACTIVITY": "Last active {date}", "LAST_ACTIVITY": "Son fəaliyyət {date}",
"DELETE_CONTACT_DESCRIPTION": "Permanently delete this contact. This action is irreversible", "DELETE_CONTACT_DESCRIPTION": "Permanently delete this contact. This action is irreversible",
"DELETE_CONTACT": "Delete contact", "DELETE_CONTACT": "Delete contact",
"DELETE_DIALOG": { "DELETE_DIALOG": {
@@ -487,7 +487,7 @@
"CONFIRM": "Yes, Delete", "CONFIRM": "Yes, Delete",
"API": { "API": {
"SUCCESS_MESSAGE": "Contact deleted successfully", "SUCCESS_MESSAGE": "Contact deleted successfully",
"ERROR_MESSAGE": "Could not delete contact. Please try again later." "ERROR_MESSAGE": "Əlaqəni silmək mümkün olmadı. Zəhmət olmasa sonra yenidən cəhd edin."
} }
}, },
"AVATAR": { "AVATAR": {
@@ -496,86 +496,86 @@
"SUCCESS_MESSAGE": "Avatar uploaded successfully" "SUCCESS_MESSAGE": "Avatar uploaded successfully"
}, },
"DELETE": { "DELETE": {
"SUCCESS_MESSAGE": "Avatar deleted successfully", "SUCCESS_MESSAGE": "Avatar uğurla silindi",
"ERROR_MESSAGE": "Could not delete avatar. Please try again later." "ERROR_MESSAGE": "Could not delete avatar. Please try again later."
} }
} }
}, },
"SIDEBAR": { "SIDEBAR": {
"TABS": { "TABS": {
"ATTRIBUTES": "Attributes", "ATTRIBUTES": "Xüsusiyyətlər",
"HISTORY": "History", "HISTORY": "Tarix",
"NOTES": "Notes", "NOTES": "Qeydlər",
"MERGE": "Merge" "MERGE": "Merge"
}, },
"HISTORY": { "HISTORY": {
"EMPTY_STATE": "There are no previous conversations associated to this contact" "EMPTY_STATE": "Bu əlaqə ilə bağlı əvvəlki söhbətlər yoxdur"
}, },
"ATTRIBUTES": { "ATTRIBUTES": {
"SEARCH_PLACEHOLDER": "Search for attributes", "SEARCH_PLACEHOLDER": "Search for attributes",
"UNUSED_ATTRIBUTES": "{count} Used attribute | {count} Unused attributes", "UNUSED_ATTRIBUTES": "{count} Used attribute | {count} Unused attributes",
"EMPTY_STATE": "There are no contact custom attributes available in this account. You can create a custom attribute in settings.", "EMPTY_STATE": "There are no contact custom attributes available in this account. You can create a custom attribute in settings.",
"YES": "Yes", "YES": "Bəli",
"NO": "No", "NO": "Xeyr",
"TRIGGER": { "TRIGGER": {
"SELECT": "Select value", "SELECT": "Dəyəri seçin",
"INPUT": "Enter value" "INPUT": "Dəyər daxil edin"
}, },
"VALIDATIONS": { "VALIDATIONS": {
"INVALID_NUMBER": "Invalid number", "INVALID_NUMBER": "Yanlış nömrə",
"REQUIRED": "Valid value is required", "REQUIRED": "Düzgün dəyər tələb olunur",
"INVALID_INPUT": "Invalid input", "INVALID_INPUT": "Yanlış giriş",
"INVALID_URL": "Invalid URL", "INVALID_URL": "Yanlış URL",
"INVALID_DATE": "Invalid date" "INVALID_DATE": "Yanlış tarix"
}, },
"NO_ATTRIBUTES": "No attributes found", "NO_ATTRIBUTES": "No attributes found",
"API": { "API": {
"SUCCESS_MESSAGE": "Attribute updated successfully", "SUCCESS_MESSAGE": "Attribute updated successfully",
"DELETE_SUCCESS_MESSAGE": "Attribute deleted successfully", "DELETE_SUCCESS_MESSAGE": "Attribute deleted successfully",
"UPDATE_ERROR": "Unable to update attribute. Please try again later", "UPDATE_ERROR": "Unable to update attribute. Please try again later",
"DELETE_ERROR": "Unable to delete attribute. Please try again later" "DELETE_ERROR": "Xüsusiyyəti silmək mümkün olmadı. Zəhmət olmasa, bir az sonra yenidən cəhd edin"
} }
}, },
"MERGE": { "MERGE": {
"TITLE": "Merge contact", "TITLE": "Merge contact",
"DESCRIPTION": "Combine two profiles into one, including all attributes and conversations. In case of conflict, the primary contacts attributes will take precedence.", "DESCRIPTION": "İki profili bütün atributlar və söhbətlər daxil olmaqla birləşdirin. Ziddiyyət olduqda, əsas əlaqənin atributları üstünlük təşkil edəcək.",
"PRIMARY": "Primary contact", "PRIMARY": "Əsas əlaqə",
"PRIMARY_HELP_LABEL": "To be saved", "PRIMARY_HELP_LABEL": "To be saved",
"PRIMARY_REQUIRED_ERROR": "Please select a contact to merge with before proceeding", "PRIMARY_REQUIRED_ERROR": "Davam etməzdən əvvəl birləşdirmək üçün əlaqə seçin",
"PARENT": "To be merged", "PARENT": "To be merged",
"PARENT_HELP_LABEL": "To be deleted", "PARENT_HELP_LABEL": "To be deleted",
"EMPTY_STATE": "No contacts found", "EMPTY_STATE": "No contacts found",
"PLACEHOLDER": "Search for primary contact", "PLACEHOLDER": "Əsas əlaqəni axtar",
"SEARCH_PLACEHOLDER": "Search for a contact", "SEARCH_PLACEHOLDER": "Əlaqə axtar",
"SEARCH_ERROR_MESSAGE": "Could not search for contacts. Please try again later.", "SEARCH_ERROR_MESSAGE": "Could not search for contacts. Please try again later.",
"SUCCESS_MESSAGE": "Contact merged successfully", "SUCCESS_MESSAGE": "Contact merged successfully",
"ERROR_MESSAGE": "Could not merge contacts, try again!", "ERROR_MESSAGE": "Əlaqələri birləşdirmək mümkün olmadı, yenidən cəhd edin!",
"IS_SEARCHING": "Searching...", "IS_SEARCHING": "Searching...",
"BUTTONS": { "BUTTONS": {
"CANCEL": "Cancel", "CANCEL": "Ləğv et",
"CONFIRM": "Merge contact" "CONFIRM": "Merge contact"
} }
}, },
"NOTES": { "NOTES": {
"PLACEHOLDER": "Add a note", "PLACEHOLDER": "Qeyd əlavə et",
"WROTE": "wrote", "WROTE": "yazdı",
"YOU": "You", "YOU": "Siz",
"SAVE": "Save note", "SAVE": "Save note",
"ADD_NOTE": "Add contact note", "ADD_NOTE": "Add contact note",
"EXPAND": "Expand", "EXPAND": "Genişləndir",
"COLLAPSE": "Collapse", "COLLAPSE": "Collapse",
"NO_NOTES": "No notes, you can add notes from the contact details page.", "NO_NOTES": "No notes, you can add notes from the contact details page.",
"EMPTY_STATE": "There are no notes associated to this contact. You can add a note by typing in the box above.", "EMPTY_STATE": "There are no notes associated to this contact. You can add a note by typing in the box above.",
"CONVERSATION_EMPTY_STATE": "There are no notes yet. Use the Add note button to create one." "CONVERSATION_EMPTY_STATE": "Hələ qeydlər yoxdur. Yeni qeyd yaratmaq üçün Qeyd əlavə et düyməsini istifadə edin."
} }
}, },
"EMPTY_STATE": { "EMPTY_STATE": {
"TITLE": "No contacts found in this account", "TITLE": "No contacts found in this account",
"SUBTITLE": "Start adding new contacts by clicking on the button below", "SUBTITLE": "Start adding new contacts by clicking on the button below",
"BUTTON_LABEL": "Add contact", "BUTTON_LABEL": "Əlaqə əlavə et",
"SEARCH_EMPTY_STATE_TITLE": "No contacts matches your search 🔍", "SEARCH_EMPTY_STATE_TITLE": "No contacts matches your search 🔍",
"LIST_EMPTY_STATE_TITLE": "No contacts available in this view 📋", "LIST_EMPTY_STATE_TITLE": "Bu baxışda əlaqə mövcud deyil 📋",
"ACTIVE_EMPTY_STATE_TITLE": "No contacts are active at the moment 🌙" "ACTIVE_EMPTY_STATE_TITLE": "Hazırda aktiv əlaqə yoxdur 🌙"
}, },
"LOAD_MORE": "Load more" "LOAD_MORE": "Load more"
}, },
@@ -585,12 +585,12 @@
"ASSIGN_LABELS_FAILED": "Failed to assign labels", "ASSIGN_LABELS_FAILED": "Failed to assign labels",
"DESCRIPTION": "Select the labels you want to add to the selected contacts.", "DESCRIPTION": "Select the labels you want to add to the selected contacts.",
"NO_LABELS_FOUND": "No labels available yet.", "NO_LABELS_FOUND": "No labels available yet.",
"SELECTED_COUNT": "{count} selected", "SELECTED_COUNT": "{count} seçildi",
"CLEAR_SELECTION": "Clear selection", "CLEAR_SELECTION": "Clear selection",
"SELECT_ALL": "Select all ({count})", "SELECT_ALL": "Select all ({count})",
"DELETE_CONTACTS": "Delete", "DELETE_CONTACTS": "Delete",
"DELETE_SUCCESS": "Contacts deleted successfully.", "DELETE_SUCCESS": "Contacts deleted successfully.",
"DELETE_FAILED": "Failed to delete contacts.", "DELETE_FAILED": "Əlaqələri silmək mümkün olmadı.",
"DELETE_DIALOG": { "DELETE_DIALOG": {
"TITLE": "Delete selected contacts", "TITLE": "Delete selected contacts",
"SINGULAR_TITLE": "Delete selected contact", "SINGULAR_TITLE": "Delete selected contact",
@@ -605,27 +605,27 @@
"ERROR_MESSAGE": "We couldnt complete the search. Please try again." "ERROR_MESSAGE": "We couldnt complete the search. Please try again."
}, },
"FORM": { "FORM": {
"GO_TO_CONVERSATION": "View", "GO_TO_CONVERSATION": "Bax",
"SUCCESS_MESSAGE": "The message was sent successfully!", "SUCCESS_MESSAGE": "The message was sent successfully!",
"ERROR_MESSAGE": "An error occurred while creating the conversation. Please try again later.", "ERROR_MESSAGE": "An error occurred while creating the conversation. Please try again later.",
"NO_INBOX_ALERT": "There are no available inboxes to start a conversation with this contact.", "NO_INBOX_ALERT": "There are no available inboxes to start a conversation with this contact.",
"CONTACT_SELECTOR": { "CONTACT_SELECTOR": {
"LABEL": "To:", "LABEL": "Kimə:",
"TAG_INPUT_PLACEHOLDER": "Enter at least 2 characters to search by name, email, or phone number", "TAG_INPUT_PLACEHOLDER": "Enter at least 2 characters to search by name, email, or phone number",
"CONTACT_CREATING": "Creating contact..." "CONTACT_CREATING": "Əlaqə yaradılır..."
}, },
"INBOX_SELECTOR": { "INBOX_SELECTOR": {
"LABEL": "Via:", "LABEL": "Via:",
"BUTTON": "Show inboxes" "BUTTON": "Qutuları göstər"
}, },
"EMAIL_OPTIONS": { "EMAIL_OPTIONS": {
"SUBJECT_LABEL": "Subject :", "SUBJECT_LABEL": "Mövzu :",
"SUBJECT_PLACEHOLDER": "Enter your email subject here", "SUBJECT_PLACEHOLDER": "Enter your email subject here",
"CC_LABEL": "Cc:", "CC_LABEL": "Cc:",
"CC_PLACEHOLDER": "Enter at least 2 characters to search by email", "CC_PLACEHOLDER": "Enter at least 2 characters to search by email",
"BCC_LABEL": "Bcc:", "BCC_LABEL": "Bcc:",
"BCC_PLACEHOLDER": "Enter at least 2 characters to search by email", "BCC_PLACEHOLDER": "Enter at least 2 characters to search by email",
"BCC_BUTTON": "Bcc" "BCC_BUTTON": "Gizli nüsxə"
}, },
"MESSAGE_EDITOR": { "MESSAGE_EDITOR": {
"PLACEHOLDER": "Write your message here..." "PLACEHOLDER": "Write your message here..."
@@ -651,8 +651,8 @@
} }
}, },
"ACTION_BUTTONS": { "ACTION_BUTTONS": {
"DISCARD": "Discard", "DISCARD": "İmtina et",
"SEND": "Send ({keyCode})" "SEND": "Göndər ({keyCode})"
} }
} }
} }
@@ -1,452 +1,452 @@
{ {
"CONVERSATION": { "CONVERSATION": {
"SELECT_A_CONVERSATION": "Please select a conversation from left pane", "SELECT_A_CONVERSATION": "Zəhmət olmasa, soldakı paneldən bir söhbət seçin",
"CSAT_REPLY_MESSAGE": "Please rate the conversation", "CSAT_REPLY_MESSAGE": "Zəhmət olmasa söhbəti qiymətləndirin",
"404": "Sorry, we cannot find the conversation. Please try again", "404": "Bağışlayın, söhbəti tapa bilmirik. Zəhmət olmasa, yenidən cəhd edin",
"SWITCH_VIEW_LAYOUT": "Switch the layout", "SWITCH_VIEW_LAYOUT": "Düzəni dəyişdirin",
"DASHBOARD_APP_TAB_MESSAGES": "Messages", "DASHBOARD_APP_TAB_MESSAGES": "Mesajlar",
"UNVERIFIED_SESSION": "The identity of this user is not verified", "UNVERIFIED_SESSION": "Bu istifadəçinin şəxsiyyəti təsdiqlənməyib",
"NO_MESSAGE_1": "Uh oh! Looks like there are no messages from customers in your inbox.", "NO_MESSAGE_1": "Uh oh! Görünür qutunuzda müştərilərdən mesaj yoxdur.",
"NO_MESSAGE_2": " to send a message to your page!", "NO_MESSAGE_2": " səhifənizə mesaj göndərmək üçün!",
"NO_INBOX_1": "Hola! Looks like you haven't added any inboxes yet.", "NO_INBOX_1": "Hola! Görünür hələ heç bir poçt qutusu əlavə etməmisiniz.",
"NO_INBOX_2": " to get started", "NO_INBOX_2": " başlamaq üçün",
"NO_INBOX_AGENT": "Uh Oh! Looks like you are not part of any inbox. Please contact your administrator", "NO_INBOX_AGENT": "Uh Oh! Görünür heç bir poçt qutusunun üzvü deyilsiniz. Zəhmət olmasa administratorunuzla əlaqə saxlayın",
"SEARCH_MESSAGES": "Search for messages in conversations", "SEARCH_MESSAGES": "Söhbətlərdə mesajları axtarın",
"VIEW_ORIGINAL": "View original", "VIEW_ORIGINAL": "Orijinalı göstər",
"VIEW_TRANSLATED": "View translated", "VIEW_TRANSLATED": "Tərcüməni göstər",
"EMPTY_STATE": { "EMPTY_STATE": {
"CMD_BAR": "to open command menu", "CMD_BAR": "əmr menyusunu açmaq üçün",
"KEYBOARD_SHORTCUTS": "to view keyboard shortcuts" "KEYBOARD_SHORTCUTS": "klaviatura qısa yollarını görmək üçün"
}, },
"SEARCH": { "SEARCH": {
"TITLE": "Search messages", "TITLE": "Mesajları axtar",
"RESULT_TITLE": "Search Results", "RESULT_TITLE": "Axtarış Nəticələri",
"LOADING_MESSAGE": "Crunching data...", "LOADING_MESSAGE": "Məlumatlar işlənir...",
"PLACEHOLDER": "Type any text to search messages", "PLACEHOLDER": "Mesajları axtarmaq üçün istənilən mətni yazın",
"NO_MATCHING_RESULTS": "No results found." "NO_MATCHING_RESULTS": "Nəticə tapılmadı."
}, },
"UNREAD_MESSAGES": "Unread Messages", "UNREAD_MESSAGES": "Oxunmamış Mesajlar",
"UNREAD_MESSAGE": "Unread Message", "UNREAD_MESSAGE": "Oxunmamış Mesaj",
"CLICK_HERE": "Click here", "CLICK_HERE": "Buraya klik edin",
"LOADING_INBOXES": "Loading inboxes", "LOADING_INBOXES": "Qutular yüklənir",
"LOADING_CONVERSATIONS": "Loading Conversations", "LOADING_CONVERSATIONS": "Söhbətlər yüklənir",
"CANNOT_REPLY": "You cannot reply due to", "CANNOT_REPLY": "Cavab verə bilməzsiniz, çünki",
"24_HOURS_WINDOW": "24 hour message window restriction", "24_HOURS_WINDOW": "24 saatlıq mesaj pəncərəsi məhdudiyyəti",
"48_HOURS_WINDOW": "48 hour message window restriction", "48_HOURS_WINDOW": "48 saatlıq mesaj pəncərəsi məhdudiyyəti",
"API_HOURS_WINDOW": "You can only reply to this conversation within {hours} hours", "API_HOURS_WINDOW": "Bu söhbətə yalnız {hours} saat ərzində cavab verə bilərsiniz",
"NOT_ASSIGNED_TO_YOU": "This conversation is not assigned to you. Would you like to assign this conversation to yourself?", "NOT_ASSIGNED_TO_YOU": "Bu söhbət sizə təyin edilməyib. Bu söhbəti özünüzə təyin etmək istərdiniz?",
"ASSIGN_TO_ME": "Assign to me", "ASSIGN_TO_ME": "Mənə təyin et",
"BOT_HANDOFF_MESSAGE": "You are responding to a conversation which is currently handled by an assistant or a bot.", "BOT_HANDOFF_MESSAGE": "Hazırda köməkçi və ya bot tərəfindən idarə olunan söhbətə cavab verirsiniz.",
"BOT_HANDOFF_ACTION": "Mark open and assign to you", "BOT_HANDOFF_ACTION": "Açıq kimi işarələ və özünüzə təyin et",
"BOT_HANDOFF_REOPEN_ACTION": "Mark conversation open", "BOT_HANDOFF_REOPEN_ACTION": "Söhbəti açıq kimi işarələyin",
"BOT_HANDOFF_SUCCESS": "Conversation has been handed over to you", "BOT_HANDOFF_SUCCESS": "Söhbət sizə təhvil verildi",
"BOT_HANDOFF_ERROR": "Failed to take over the conversation. Please try again.", "BOT_HANDOFF_ERROR": "Söhbəti ələ keçirmək alınmadı. Zəhmət olmasa, yenidən cəhd edin.",
"TWILIO_WHATSAPP_CAN_REPLY": "You can only reply to this conversation using a template message due to", "TWILIO_WHATSAPP_CAN_REPLY": "Bu söhbətə yalnız şablon mesajı ilə cavab verə bilərsiniz, çünki",
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "24 hour message window restriction", "TWILIO_WHATSAPP_24_HOURS_WINDOW": "24 saatlıq mesaj pəncərəsi məhdudiyyəti",
"OLD_INSTAGRAM_INBOX_REPLY_BANNER": "This Instagram account was migrated to the new Instagram channel inbox. All new messages will show up there. You wont be able to send messages from this conversation anymore.", "OLD_INSTAGRAM_INBOX_REPLY_BANNER": "Bu Instagram hesabı yeni Instagram kanalının daxil olan qutusuna köçürülüb. Bütün yeni mesajlar orada görünəcək. Bu söhbətdən artıq mesaj göndərə bilməyəcəksiniz.",
"REPLYING_TO": "You are replying to:", "REPLYING_TO": "Siz cavab verirsiniz:",
"REMOVE_SELECTION": "Remove Selection", "REMOVE_SELECTION": "Seçimi sil",
"DOWNLOAD": "Download", "DOWNLOAD": "Yüklə",
"UNKNOWN_FILE_TYPE": "Unknown File", "UNKNOWN_FILE_TYPE": "Naməlum fayl",
"SAVE_CONTACT": "Save Contact", "SAVE_CONTACT": "Əlaqəni yadda saxla",
"NO_CONTENT": "No content to display", "NO_CONTENT": "Göstəriləcək məzmun yoxdur",
"SHARED_ATTACHMENT": { "SHARED_ATTACHMENT": {
"CONTACT": "{sender} has shared a contact", "CONTACT": "{sender} bir əlaqə paylaşıb",
"LOCATION": "{sender} has shared a location", "LOCATION": "{sender} bir yer paylaşıb",
"FILE": "{sender} has shared a file", "FILE": "{sender} bir fayl paylaşıb",
"MEETING": "{sender} has started a meeting" "MEETING": "{sender} bir görüş başlayıb"
}, },
"UPLOADING_ATTACHMENTS": "Uploading attachments...", "UPLOADING_ATTACHMENTS": "Əlavələr yüklənir...",
"REPLIED_TO_STORY": "Replied to your story", "REPLIED_TO_STORY": "Hekayənizə cavab verdi",
"UNSUPPORTED_MESSAGE": "This message is unsupported. You can view this message on the Facebook / Instagram app.", "UNSUPPORTED_MESSAGE": "This message is unsupported. You can view this message on the Facebook / Instagram app.",
"UNSUPPORTED_MESSAGE_FACEBOOK": "This message is unsupported. You can view this message on the Facebook Messenger app.", "UNSUPPORTED_MESSAGE_FACEBOOK": "Bu mesaj dəstəklənmir. Bu mesajı Facebook Messenger tətbiqində görə bilərsiniz.",
"UNSUPPORTED_MESSAGE_INSTAGRAM": "This message is unsupported. You can view this message on the Instagram app.", "UNSUPPORTED_MESSAGE_INSTAGRAM": "Bu mesaj dəstəklənmir. Bu mesajı Instagram tətbiqində görə bilərsiniz.",
"UNSUPPORTED_MESSAGE_TIKTOK": "This message is unsupported. You can view this message on the TikTok app.", "UNSUPPORTED_MESSAGE_TIKTOK": "Bu mesaj dəstəklənmir. Bu mesajı TikTok tətbiqində görə bilərsiniz.",
"SUCCESS_DELETE_MESSAGE": "Message deleted successfully", "SUCCESS_DELETE_MESSAGE": "Mesaj uğurla silindi",
"FAIL_DELETE_MESSSAGE": "Couldn't delete message! Try again", "FAIL_DELETE_MESSSAGE": "Mesajı silmək mümkün olmadı! Yenidən cəhd edin",
"NO_RESPONSE": "No response", "NO_RESPONSE": "Cavab yoxdur",
"RESPONSE": "Response", "RESPONSE": "Cavab",
"RATING_TITLE": "Rating", "RATING_TITLE": "Qiymətləndirmə",
"FEEDBACK_TITLE": "Feedback", "FEEDBACK_TITLE": "Rəy",
"REPLY_MESSAGE_NOT_FOUND": "Message not available", "REPLY_MESSAGE_NOT_FOUND": "Mesaj mövcud deyil",
"CARD": { "CARD": {
"SHOW_LABELS": "Show labels", "SHOW_LABELS": "Etiketləri göstər",
"HIDE_LABELS": "Hide labels" "HIDE_LABELS": "Etiketləri gizlədin"
}, },
"VOICE_CALL": { "VOICE_CALL": {
"INCOMING_CALL": "Incoming call", "INCOMING_CALL": "Gələn zəng",
"OUTGOING_CALL": "Outgoing call", "OUTGOING_CALL": "Gedən zəng",
"CALL_IN_PROGRESS": "Call in progress", "CALL_IN_PROGRESS": "Zəng davam edir",
"NO_ANSWER": "No answer", "NO_ANSWER": "Cavab yoxdur",
"MISSED_CALL": "Missed call", "MISSED_CALL": "Qeyri-işlək zəng",
"CALL_ENDED": "Call ended", "CALL_ENDED": "Zəng bitdi",
"NOT_ANSWERED_YET": "Not answered yet", "NOT_ANSWERED_YET": "Hələ cavab verilməyib",
"THEY_ANSWERED": "They answered", "THEY_ANSWERED": "Onlar cavab verdi",
"YOU_ANSWERED": "You answered" "YOU_ANSWERED": "Siz cavab verdiniz"
}, },
"HEADER": { "HEADER": {
"RESOLVE_ACTION": "Resolve", "RESOLVE_ACTION": "Həll et",
"REOPEN_ACTION": "Reopen", "REOPEN_ACTION": "Yenidən aç",
"OPEN_ACTION": "Open", "OPEN_ACTION": "",
"MORE_ACTIONS": "More actions", "MORE_ACTIONS": "Daha çox əməliyyat",
"OPEN": "More", "OPEN": "Daha çox",
"CLOSE": "Close", "CLOSE": "Bağla",
"DETAILS": "details", "DETAILS": "təfərrüatlar",
"SNOOZED_UNTIL": "Snoozed until", "SNOOZED_UNTIL": "Gecikdirilib",
"SNOOZED_UNTIL_TOMORROW": "Snoozed until tomorrow", "SNOOZED_UNTIL_TOMORROW": "Sabaha qədər təxirə salındı",
"SNOOZED_UNTIL_NEXT_WEEK": "Snoozed until next week", "SNOOZED_UNTIL_NEXT_WEEK": "Gələn həftəyə qədər təxirə salındı",
"SNOOZED_UNTIL_NEXT_REPLY": "Snoozed until next reply", "SNOOZED_UNTIL_NEXT_REPLY": "Növbəti cavaba qədər təxirə salındı",
"SLA_STATUS": { "SLA_STATUS": {
"FRT": "FRT {status}", "FRT": "FRT {status}",
"NRT": "NRT {status}", "NRT": "NRT {status}",
"RT": "RT {status}", "RT": "RT {status}",
"MISSED": "missed", "MISSED": "qaçırıldı",
"DUE": "due" "DUE": "vaxtı çatıb"
} }
}, },
"RESOLVE_DROPDOWN": { "RESOLVE_DROPDOWN": {
"MARK_PENDING": "Mark as pending", "MARK_PENDING": "Gözləmədə kimi işarələyin",
"SNOOZE_UNTIL": "Snooze", "SNOOZE_UNTIL": "Gecikdir",
"SNOOZE": { "SNOOZE": {
"TITLE": "Snooze until", "TITLE": "Gecikdirin, qədər",
"NEXT_REPLY": "Next reply", "NEXT_REPLY": "Növbəti cavab",
"TOMORROW": "Tomorrow", "TOMORROW": "Sabah",
"NEXT_WEEK": "Next week" "NEXT_WEEK": "Gələn həftə"
} }
}, },
"MENTION": { "MENTION": {
"AGENTS": "Agents", "AGENTS": "Agentlər",
"TEAMS": "Teams" "TEAMS": "Komandalar"
}, },
"CUSTOM_SNOOZE": { "CUSTOM_SNOOZE": {
"TITLE": "Snooze until", "TITLE": "Gecikdirmə müddəti",
"APPLY": "Snooze", "APPLY": "Gecikdir",
"CANCEL": "Cancel" "CANCEL": "Ləğv et"
}, },
"PRIORITY": { "PRIORITY": {
"TITLE": "Priority", "TITLE": "Prioritet",
"OPTIONS": { "OPTIONS": {
"NONE": "None", "NONE": "Heç biri",
"URGENT": "Urgent", "URGENT": "Təcili",
"HIGH": "High", "HIGH": "Yüksək",
"MEDIUM": "Medium", "MEDIUM": "Orta",
"LOW": "Low" "LOW": "Aşağı"
}, },
"CHANGE_PRIORITY": { "CHANGE_PRIORITY": {
"SELECT_PLACEHOLDER": "None", "SELECT_PLACEHOLDER": "Heç biri",
"INPUT_PLACEHOLDER": "Select priority", "INPUT_PLACEHOLDER": "Prioritet seçin",
"NO_RESULTS": "No results found", "NO_RESULTS": "Nəticə tapılmadı",
"SUCCESSFUL": "Changed priority of conversation id {conversationId} to {priority}", "SUCCESSFUL": "{conversationId} söhbətinin prioriteti {priority} olaraq dəyişdirildi",
"FAILED": "Couldn't change priority. Please try again." "FAILED": "Prioritet dəyişdirilə bilmədi. Zəhmət olmasa yenidən cəhd edin."
} }
}, },
"DELETE_CONVERSATION": { "DELETE_CONVERSATION": {
"TITLE": "Delete conversation #{conversationId}", "TITLE": "#{conversationId} nömrəli söhbəti sil",
"DESCRIPTION": "Are you sure you want to delete this conversation?", "DESCRIPTION": "Bu söhbəti silmək istədiyinizə əminsiniz?",
"CONFIRM": "Delete" "CONFIRM": "Sil"
}, },
"CARD_CONTEXT_MENU": { "CARD_CONTEXT_MENU": {
"PENDING": "Mark as pending", "PENDING": "Gözləyən kimi işarələyin",
"RESOLVED": "Mark as resolved", "RESOLVED": "Həll olundu kimi işarələyin",
"MARK_AS_UNREAD": "Mark as unread", "MARK_AS_UNREAD": "Oxunmamış kimi işarələyin",
"MARK_AS_READ": "Mark as read", "MARK_AS_READ": "Oxunmuş kimi işarələ",
"REOPEN": "Reopen conversation", "REOPEN": "Söhbəti yenidən açın",
"SNOOZE": { "SNOOZE": {
"TITLE": "Snooze", "TITLE": "Gecikdir",
"NEXT_REPLY": "Until next reply", "NEXT_REPLY": "Növbəti cavaba qədər",
"TOMORROW": "Until tomorrow", "TOMORROW": "Sabaha qədər",
"NEXT_WEEK": "Until next week" "NEXT_WEEK": "Növbəti həftəyə qədər"
}, },
"ASSIGN_AGENT": "Assign agent", "ASSIGN_AGENT": "Agent təyin et",
"ASSIGN_LABEL": "Assign label", "ASSIGN_LABEL": "Etiket təyin et",
"AGENTS_LOADING": "Loading agents...", "AGENTS_LOADING": "Agentlər yüklənir...",
"ASSIGN_TEAM": "Assign team", "ASSIGN_TEAM": "Komandaya təyin et",
"DELETE": "Delete conversation", "DELETE": "Söhbəti sil",
"OPEN_IN_NEW_TAB": "Open in new tab", "OPEN_IN_NEW_TAB": "Yeni nişanda aç",
"COPY_LINK": "Copy conversation link", "COPY_LINK": "Söhbət linkini kopyala",
"COPY_LINK_SUCCESS": "Conversation link copied to clipboard", "COPY_LINK_SUCCESS": "Söhbət linki panoya kopyalandı",
"API": { "API": {
"AGENT_ASSIGNMENT": { "AGENT_ASSIGNMENT": {
"SUCCESFUL": "Conversation id {conversationId} assigned to \"{agentName}\"", "SUCCESFUL": "{conversationId} söhbəti \"{agentName}\" agentinə təyin edildi",
"FAILED": "Couldn't assign agent. Please try again." "FAILED": "Agent təyin etmək mümkün olmadı. Zəhmət olmasa yenidən cəhd edin."
}, },
"LABEL_ASSIGNMENT": { "LABEL_ASSIGNMENT": {
"SUCCESFUL": "Assigned label #{labelName} to conversation id {conversationId}", "SUCCESFUL": "{conversationId} söhbətinə #{labelName} etiketi təyin edildi",
"FAILED": "Couldn't assign label. Please try again." "FAILED": "Etiket təyin etmək mümkün olmadı. Zəhmət olmasa yenidən cəhd edin."
}, },
"LABEL_REMOVAL": { "LABEL_REMOVAL": {
"SUCCESFUL": "Removed label #{labelName} from conversation id {conversationId}", "SUCCESFUL": "{conversationId} nömrəli söhbətdən #{labelName} etiketi silindi",
"FAILED": "Couldn't remove label. Please try again." "FAILED": "Etiketi silmək mümkün olmadı. Zəhmət olmasa yenidən cəhd edin."
}, },
"TEAM_ASSIGNMENT": { "TEAM_ASSIGNMENT": {
"SUCCESFUL": "Assigned team \"{team}\" to conversation id {conversationId}", "SUCCESFUL": "Söhbət id-si {conversationId} üçün \"{team}\" komandası təyin edildi",
"FAILED": "Couldn't assign team. Please try again." "FAILED": "Komanda təyin etmək mümkün olmadı. Zəhmət olmasa yenidən cəhd edin."
} }
} }
}, },
"FOOTER": { "FOOTER": {
"MESSAGE_SIGN_TOOLTIP": "Message signature", "MESSAGE_SIGN_TOOLTIP": "Mesaj imzası",
"ENABLE_SIGN_TOOLTIP": "Enable signature", "ENABLE_SIGN_TOOLTIP": "İmzaya icazə ver",
"DISABLE_SIGN_TOOLTIP": "Disable signature", "DISABLE_SIGN_TOOLTIP": "İmzaya icazə vermə",
"MSG_INPUT": "Shift + enter for new line. Start with '/' to select a Canned Response.", "MSG_INPUT": "Yeni sətr üçün Shift + enter. Canned Response seçmək üçün '/' ilə başlayın.",
"PRIVATE_MSG_INPUT": "Shift + enter for new line. This will be visible only to Agents", "PRIVATE_MSG_INPUT": "Yeni sətr üçün Shift + enter. Bu yalnız Agentlər üçün görünəcək",
"MESSAGING_RESTRICTED": "You cannot reply to this conversation", "MESSAGING_RESTRICTED": "Bu söhbətə cavab verə bilməzsiniz",
"MESSAGING_RESTRICTED_WHATSAPP": "You can only reply using a template message due to 24-hour message window restriction", "MESSAGING_RESTRICTED_WHATSAPP": "24 saatlıq mesaj pəncərəsi məhdudiyyəti səbəbindən yalnız şablon mesajla cavab verə bilərsiniz",
"MESSAGING_RESTRICTED_API": "You can only reply using a template message due to message window restriction", "MESSAGING_RESTRICTED_API": "Mesaj pəncərəsi məhdudiyyəti səbəbindən yalnız şablon mesajla cavab verə bilərsiniz",
"MESSAGE_SIGNATURE_NOT_CONFIGURED": "Message signature is not configured, please configure it in profile settings.", "MESSAGE_SIGNATURE_NOT_CONFIGURED": "Mesaj imzası qurulmayıb, zəhmət olmasa profil parametrlərində qurun.",
"COPILOT_MSG_INPUT": "Give copilot additional prompts, or ask anything else... Press enter to send follow-up", "COPILOT_MSG_INPUT": "Copilot üçün əlavə göstərişlər verin və ya başqa sual verin... Davam etmək üçün enter düyməsini basın",
"CLICK_HERE": "Click here to update", "CLICK_HERE": "Yeniləmək üçün buraya klikləyin",
"WHATSAPP_TEMPLATES": "Whatsapp Templates" "WHATSAPP_TEMPLATES": "Whatsapp Şablonları"
}, },
"REPLYBOX": { "REPLYBOX": {
"REPLY": "Reply", "REPLY": "Cavab ver",
"PRIVATE_NOTE": "Private Note", "PRIVATE_NOTE": "Şəxsi Qeyd",
"SEND": "Send", "SEND": "Göndər",
"CREATE": "Add Note", "CREATE": "Qeyd əlavə et",
"INSERT_READ_MORE": "Read more", "INSERT_READ_MORE": "Daha çox oxu",
"DISMISS_REPLY": "Dismiss reply", "DISMISS_REPLY": "Cavabı ləğv et",
"REPLYING_TO": "Replying to:", "REPLYING_TO": "Cavab verir:",
"TIP_EMOJI_ICON": "Show emoji selector", "TIP_EMOJI_ICON": "Emoji seçicisini göstər",
"TIP_ATTACH_ICON": "Attach files", "TIP_ATTACH_ICON": "Faylları əlavə et",
"TIP_AUDIORECORDER_ICON": "Record audio", "TIP_AUDIORECORDER_ICON": "Səs yaz",
"TIP_AUDIORECORDER_PERMISSION": "Allow access to audio", "TIP_AUDIORECORDER_PERMISSION": "Səsə girişə icazə ver",
"TIP_AUDIORECORDER_ERROR": "Could not open the audio", "TIP_AUDIORECORDER_ERROR": "Səsi açmaq mümkün olmadı",
"DRAG_DROP": "Drag and drop here to attach", "DRAG_DROP": "Qoşmaq üçün buraya sürükləyin və buraxın",
"START_AUDIO_RECORDING": "Start audio recording", "START_AUDIO_RECORDING": "Səs yazısını başla",
"STOP_AUDIO_RECORDING": "Stop audio recording", "STOP_AUDIO_RECORDING": "Səs yazısını dayandırın",
"COPILOT_THINKING": "Copilot is thinking", "COPILOT_THINKING": "Copilot düşünür",
"EMAIL_HEAD": { "EMAIL_HEAD": {
"TO": "TO", "TO": "KİMƏ",
"ADD_BCC": "Add bcc", "ADD_BCC": "Gizli nüsxə əlavə et",
"CC": { "CC": {
"LABEL": "CC", "LABEL": "CC",
"PLACEHOLDER": "Emails separated by commas", "PLACEHOLDER": "Vergüllə ayrılmış elektron poçtlar",
"ERROR": "Please enter valid email addresses" "ERROR": "Zəhmət olmasa düzgün elektron poçt ünvanları daxil edin"
}, },
"BCC": { "BCC": {
"LABEL": "BCC", "LABEL": "BCC",
"PLACEHOLDER": "Emails separated by commas", "PLACEHOLDER": "Vergüllə ayrılmış e-poçtlar",
"ERROR": "Please enter valid email addresses" "ERROR": "Zəhmət olmasa, düzgün e-poçt ünvanları daxil edin"
} }
}, },
"UNDEFINED_VARIABLES": { "UNDEFINED_VARIABLES": {
"TITLE": "Undefined variables", "TITLE": "Təyin olunmamış dəyişənlər",
"MESSAGE": "You have {undefinedVariablesCount} undefined variables in your message: {undefinedVariables}. Would you like to send the message anyway?", "MESSAGE": "Mesajınızda {undefinedVariablesCount} təyin olunmamış dəyişən var: {undefinedVariables}. Mesajı yenə də göndərmək istəyirsiniz?",
"CONFIRM": { "CONFIRM": {
"YES": "Send", "YES": "Göndər",
"CANCEL": "Cancel" "CANCEL": "Ləğv et"
} }
}, },
"QUOTED_REPLY": { "QUOTED_REPLY": {
"ENABLE_TOOLTIP": "Include quoted email thread", "ENABLE_TOOLTIP": "Sitat gətirilmiş e-poçt mövzusunu daxil et",
"DISABLE_TOOLTIP": "Don't include quoted email thread", "DISABLE_TOOLTIP": "Sitat gətirilmiş e-poçt mövzusunu daxil etmə",
"REMOVE_PREVIEW": "Remove quoted email thread", "REMOVE_PREVIEW": "Sitat gətirilmiş e-poçt mövzusunu sil",
"COLLAPSE": "Collapse preview", "COLLAPSE": "Önizləməni yığışdır",
"EXPAND": "Expand preview" "EXPAND": "Önizləməni genişləndir"
} }
}, },
"VISIBLE_TO_AGENTS": "Private Note: Only visible to you and your team", "VISIBLE_TO_AGENTS": "Şəxsi Qeyd: Yalnız siz və komandanız üçün görünür",
"CHANGE_STATUS": "Conversation status changed", "CHANGE_STATUS": "Söhbət statusu dəyişdirildi",
"CHANGE_STATUS_FAILED": "Conversation status change failed", "CHANGE_STATUS_FAILED": "Söhbətin statusunu dəyişmək mümkün olmadı",
"CHANGE_AGENT": "Conversation Assignee changed", "CHANGE_AGENT": "Söhbətin məsul şəxsi dəyişdirildi",
"CHANGE_AGENT_FAILED": "Assignee change failed", "CHANGE_AGENT_FAILED": "Təyinat dəyişdirilməsi uğursuz oldu",
"ASSIGN_LABEL_SUCCESFUL": "Label assigned successfully", "ASSIGN_LABEL_SUCCESFUL": "Etiket uğurla təyin edildi",
"ASSIGN_LABEL_FAILED": "Label assignment failed", "ASSIGN_LABEL_FAILED": "Etiket təyini uğursuz oldu",
"CHANGE_TEAM": "Conversation team changed", "CHANGE_TEAM": "Söhbət komandası dəyişdirildi",
"SUCCESS_DELETE_CONVERSATION": "Conversation deleted successfully", "SUCCESS_DELETE_CONVERSATION": "Söhbət uğurla silindi",
"FAIL_DELETE_CONVERSATION": "Couldn't delete conversation! Try again", "FAIL_DELETE_CONVERSATION": "Söhbəti silmək mümkün olmadı! Yenidən cəhd edin",
"FILE_SIZE_LIMIT": "File exceeds the {MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE} MB attachment limit", "FILE_SIZE_LIMIT": "Fayl {MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE} MB əlavə limitini aşır",
"FILE_TYPE_NOT_SUPPORTED": "This {fileName} file type is not supported in this conversation", "FILE_TYPE_NOT_SUPPORTED": "Bu {fileName} fayl növü bu söhbətdə dəstəklənmir",
"MESSAGE_ERROR": "Unable to send this message, please try again later", "MESSAGE_ERROR": "Bu mesajı göndərmək mümkün olmadı, zəhmət olmasa bir az sonra yenidən cəhd edin",
"SENT_BY": "Sent by:", "SENT_BY": "Göndərən:",
"BOT": "Bot", "BOT": "Bot",
"NATIVE_APP": "Native app", "NATIVE_APP": "Yerli tətbiq",
"NATIVE_APP_ADVISORY": "This message was sent from the native app. Reply from Chatwoot to maintain the message window.", "NATIVE_APP_ADVISORY": "Bu mesaj yerli tətbiqdən göndərilib. Mesaj pəncərəsini saxlamaq üçün Chatwoot-dan cavab verin.",
"SEND_FAILED": "Couldn't send message! Try again", "SEND_FAILED": "Mesaj göndərmək mümkün olmadı! Yenidən cəhd edin",
"TRY_AGAIN": "retry", "TRY_AGAIN": "yenidən cəhd et",
"ASSIGNMENT": { "ASSIGNMENT": {
"SELECT_AGENT": "Select Agent", "SELECT_AGENT": "Agent seçin",
"REMOVE": "Remove", "REMOVE": "Sil",
"ASSIGN": "Assign" "ASSIGN": "Təyin et"
}, },
"CONTEXT_MENU": { "CONTEXT_MENU": {
"COPY": "Copy", "COPY": "Kopyala",
"REPLY_TO": "Reply to this message", "REPLY_TO": "Bu mesaja cavab ver",
"DELETE": "Delete", "DELETE": "Sil",
"CREATE_A_CANNED_RESPONSE": "Add to canned responses", "CREATE_A_CANNED_RESPONSE": "Hazır cavablara əlavə et",
"TRANSLATE": "Translate", "TRANSLATE": "Tərcümə et",
"COPY_PERMALINK": "Copy link to the message", "COPY_PERMALINK": "Mesaja keçid linkini kopyalayın",
"LINK_COPIED": "Message URL copied to the clipboard", "LINK_COPIED": "Mesajın URL-i panoya kopyalandı",
"DELETE_CONFIRMATION": { "DELETE_CONFIRMATION": {
"TITLE": "Are you sure you want to delete this message?", "TITLE": "Bu mesajı silmək istədiyinizə əminsiniz?",
"MESSAGE": "You cannot undo this action", "MESSAGE": "Bu əməliyyatı geri qaytara bilməzsiniz",
"DELETE": "Delete", "DELETE": "Sil",
"CANCEL": "Cancel" "CANCEL": "Ləğv et"
} }
}, },
"SIDEBAR": { "SIDEBAR": {
"CONTACT": "Contact", "CONTACT": "Əlaqə",
"COPILOT": "Copilot" "COPILOT": "Copilot"
}, },
"VOICE_WIDGET": { "VOICE_WIDGET": {
"INCOMING_CALL": "Incoming call", "INCOMING_CALL": "Gələn zəng",
"OUTGOING_CALL": "Outgoing call", "OUTGOING_CALL": "Gedən zəng",
"CALL_IN_PROGRESS": "Call in progress", "CALL_IN_PROGRESS": "Zəng davam edir",
"NOT_ANSWERED_YET": "Not answered yet", "NOT_ANSWERED_YET": "Hələ cavab verilməyib",
"HANDLED_IN_ANOTHER_TAB": "Being handled in another tab", "HANDLED_IN_ANOTHER_TAB": "Başqa sekmədə işlənir",
"REJECT_CALL": "Reject", "REJECT_CALL": "İmtina et",
"JOIN_CALL": "Join call", "JOIN_CALL": "Zəngə qoşul",
"END_CALL": "End call" "END_CALL": "Zəngi bitir"
} }
}, },
"EMAIL_TRANSCRIPT": { "EMAIL_TRANSCRIPT": {
"TITLE": "Send conversation transcript", "TITLE": "Söhbət transkriptini göndər",
"DESC": "Send a copy of the conversation transcript to the specified email address", "DESC": "Söhbət transkriptinin surətini göstərilən e-poçt ünvanına göndərin",
"SUBMIT": "Submit", "SUBMIT": "Təsdiqlə",
"CANCEL": "Cancel", "CANCEL": "Ləğv et",
"SEND_EMAIL_SUCCESS": "The chat transcript was sent successfully", "SEND_EMAIL_SUCCESS": "Söhbət yazısı uğurla göndərildi",
"SEND_EMAIL_ERROR": "There was an error, please try again", "SEND_EMAIL_ERROR": "Xəta baş verdi, zəhmət olmasa yenidən cəhd edin",
"SEND_EMAIL_PAYMENT_REQUIRED": "Email transcript is not available on your current plan. Please upgrade to use this feature.", "SEND_EMAIL_PAYMENT_REQUIRED": "Cari planınızda e-poçt yazışması mövcud deyil. Bu funksiyanı istifadə etmək üçün lütfən planınızı yüksəldin.",
"FORM": { "FORM": {
"SEND_TO_CONTACT": "Send the transcript to the customer", "SEND_TO_CONTACT": "Yazını müştəriyə göndər",
"SEND_TO_AGENT": "Send the transcript to the assigned agent", "SEND_TO_AGENT": "Mətni təyin olunmuş agentə göndər",
"SEND_TO_OTHER_EMAIL_ADDRESS": "Send the transcript to another email address", "SEND_TO_OTHER_EMAIL_ADDRESS": "Yazını başqa e-poçt ünvanına göndər",
"EMAIL": { "EMAIL": {
"PLACEHOLDER": "Enter an email address", "PLACEHOLDER": "E-poçt ünvanı daxil edin",
"ERROR": "Please enter a valid email address" "ERROR": "Zəhmət olmasa, düzgün e-poçt ünvanı daxil edin"
} }
} }
}, },
"ONBOARDING": { "ONBOARDING": {
"TITLE": "Hey 👋, Welcome to {installationName}!", "TITLE": "Salam 👋, {installationName}-ə xoş gəlmisiniz!",
"DESCRIPTION": "Thanks for signing up. We want you to get the most out of {installationName}. Here are a few things you can do in {installationName} to make the experience delightful.", "DESCRIPTION": "Qeydiyyatdan keçdiyiniz üçün təşəkkür edirik. {installationName}-dən maksimum faydalanmağınızı istəyirik. Təcrübəni xoş etmək üçün {installationName}-də edə biləcəyiniz bir neçə şey var.",
"GREETING_MORNING": "👋 Good morning, {name}. Welcome to {installationName}.", "GREETING_MORNING": "👋 Sabahınız xeyir, {name}. {installationName}-ə xoş gəlmisiniz.",
"GREETING_AFTERNOON": "👋 Good afternoon, {name}. Welcome to {installationName}.", "GREETING_AFTERNOON": "👋 Günortanız xeyir, {name}. {installationName}-ə xoş gəlmisiniz.",
"GREETING_EVENING": "👋 Good evening, {name}. Welcome to {installationName}.", "GREETING_EVENING": "👋 Axşamınız xeyir, {name}. {installationName}-ə xoş gəlmisiniz.",
"READ_LATEST_UPDATES": "Read our latest updates", "READ_LATEST_UPDATES": "Ən son yeniliklərimizi oxuyun",
"ALL_CONVERSATION": { "ALL_CONVERSATION": {
"TITLE": "All your conversations in one place", "TITLE": "Bütün söhbətləriniz bir yerdə",
"DESCRIPTION": "View all the conversations from your customers in one single dashboard. You can filter the conversations by the incoming channel, label and status.", "DESCRIPTION": "Müştərilərinizdən olan bütün söhbətləri tək bir paneldə görün. Söhbətləri daxil olan kanal, etiket və vəziyyətə görə süzgəcdən keçirə bilərsiniz.",
"NEW_LINK": "Click here to create an inbox" "NEW_LINK": "Qutunu yaratmaq üçün bura klikləyin"
}, },
"TEAM_MEMBERS": { "TEAM_MEMBERS": {
"TITLE": "Invite your team members", "TITLE": "Komanda üzvlərinizi dəvət edin",
"DESCRIPTION": "Since you are getting ready to talk to your customer, bring in your teammates to assist you. You can invite your teammates by adding their email addresses to the agent list.", "DESCRIPTION": "Müştərinizlə danışmağa hazırlaşdığınız üçün, sizə kömək etmək üçün komanda üzvlərinizi dəvət edin. Komanda üzvlərinizi agent siyahısına onların e-poçt ünvanlarını əlavə etməklə dəvət edə bilərsiniz.",
"NEW_LINK": "Click here to invite a team member" "NEW_LINK": "Komanda üzvünü dəvət etmək üçün buraya klikləyin"
}, },
"LABELS": { "LABELS": {
"TITLE": "Organize conversations with labels", "TITLE": "Söhbətləri etiketlərlə təşkil edin",
"DESCRIPTION": "Labels provide an easier way to categorize your conversation. Create some labels like #support-enquiry, #billing-question etc., so that you can use them in a conversation later.", "DESCRIPTION": "Etiketlər söhbətinizi kateqoriyalara ayırmağı asanlaşdırır. Sonra söhbətdə istifadə etmək üçün #support-enquiry, #billing-question və s. kimi bəzi etiketlər yaradın.",
"NEW_LINK": "Click here to create tags" "NEW_LINK": "Etiket yaratmaq üçün buraya klikləyin"
}, },
"CANNED_RESPONSES": { "CANNED_RESPONSES": {
"TITLE": "Create canned responses", "TITLE": "Hazır cavablar yaradın",
"DESCRIPTION": "Pre-written quick reply templates help you quickly respond to a conversation. Agents can type the '/' character followed by the shortcode to insert a response.", "DESCRIPTION": "Əvvəlcədən yazılmış sürətli cavab şablonları söhbətə tez cavab verməyinizə kömək edir. Agentlər cavaba daxil etmək üçün '/' simvolunu və sonra qısa kodu yaza bilərlər.",
"NEW_LINK": "Click here to create a canned response" "NEW_LINK": "Sürətli cavab yaratmaq üçün bura klikləyin"
} }
}, },
"CONVERSATION_SIDEBAR": { "CONVERSATION_SIDEBAR": {
"ASSIGNEE_LABEL": "Assigned Agent", "ASSIGNEE_LABEL": "Təyin olunmuş agent",
"SELF_ASSIGN": "Assign to me", "SELF_ASSIGN": "Mənə təyin et",
"TEAM_LABEL": "Assigned Team", "TEAM_LABEL": "Təyin olunmuş komanda",
"SELECT": { "SELECT": {
"PLACEHOLDER": "None" "PLACEHOLDER": "Heç biri"
}, },
"ACCORDION": { "ACCORDION": {
"CONTACT_DETAILS": "Contact Details", "CONTACT_DETAILS": "Əlaqə Məlumatları",
"CONVERSATION_ACTIONS": "Conversation Actions", "CONVERSATION_ACTIONS": "Söhbət Əməliyyatları",
"CONVERSATION_LABELS": "Conversation Labels", "CONVERSATION_LABELS": "Söhbət Etiketləri",
"CONVERSATION_INFO": "Conversation Information", "CONVERSATION_INFO": "Söhbət Məlumatları",
"CONTACT_NOTES": "Contact Notes", "CONTACT_NOTES": "Əlaqə Qeydləri",
"CONTACT_ATTRIBUTES": "Contact Attributes", "CONTACT_ATTRIBUTES": "Əlaqə Xüsusiyyətləri",
"PREVIOUS_CONVERSATION": "Previous Conversations", "PREVIOUS_CONVERSATION": "Əvvəlki Söhbətlər",
"MACROS": "Macros", "MACROS": "Makrolar",
"LINEAR_ISSUES": "Linked Linear Issues", "LINEAR_ISSUES": "Əlaqəli Linear məsələlər",
"SHOPIFY_ORDERS": "Shopify Orders" "SHOPIFY_ORDERS": "Shopify Sifarişləri"
}, },
"SHOPIFY": { "SHOPIFY": {
"ORDER_ID": "Order #{id}", "ORDER_ID": "Sifariş #{id}",
"ERROR": "Error loading orders", "ERROR": "Sifarişlərin yüklənməsində xəta",
"NO_SHOPIFY_ORDERS": "No orders found", "NO_SHOPIFY_ORDERS": "Sifariş tapılmadı",
"FINANCIAL_STATUS": { "FINANCIAL_STATUS": {
"PENDING": "Pending", "PENDING": "Gözləmədə",
"AUTHORIZED": "Authorized", "AUTHORIZED": "Təsdiqlənmiş",
"PARTIALLY_PAID": "Partially Paid", "PARTIALLY_PAID": "Qismən ödənilmiş",
"PAID": "Paid", "PAID": "Ödənilib",
"PARTIALLY_REFUNDED": "Partially Refunded", "PARTIALLY_REFUNDED": "Qismən Geri Ödənilib",
"REFUNDED": "Refunded", "REFUNDED": "Geri Ödənilib",
"VOIDED": "Voided" "VOIDED": "Ləğv Edilib"
}, },
"FULFILLMENT_STATUS": { "FULFILLMENT_STATUS": {
"FULFILLED": "Fulfilled", "FULFILLED": "Yerinə Yetirilib",
"PARTIALLY_FULFILLED": "Partially Fulfilled", "PARTIALLY_FULFILLED": "Qismən Yerinə Yetirilib",
"UNFULFILLED": "Unfulfilled" "UNFULFILLED": "Yerinə Yetirilməyib"
} }
} }
}, },
"CONVERSATION_CUSTOM_ATTRIBUTES": { "CONVERSATION_CUSTOM_ATTRIBUTES": {
"ADD_BUTTON_TEXT": "Create attribute", "ADD_BUTTON_TEXT": "Xüsusiyyət yaradın",
"NO_RECORDS_FOUND": "No attributes found", "NO_RECORDS_FOUND": "Heç bir atribut tapılmadı",
"UPDATE": { "UPDATE": {
"SUCCESS": "Attribute updated successfully", "SUCCESS": "Xüsusiyyət uğurla yeniləndi",
"ERROR": "Unable to update attribute. Please try again later" "ERROR": "Xüsusiyyət yenilənə bilmədi. Zəhmət olmasa, bir az sonra yenidən cəhd edin"
}, },
"ADD": { "ADD": {
"TITLE": "Add", "TITLE": "Əlavə et",
"SUCCESS": "Attribute added successfully", "SUCCESS": "Xüsusiyyət uğurla əlavə edildi",
"ERROR": "Unable to add attribute. Please try again later" "ERROR": "Xüsusiyyət əlavə edilə bilmədi. Zəhmət olmasa, bir az sonra yenidən cəhd edin"
}, },
"DELETE": { "DELETE": {
"SUCCESS": "Attribute deleted successfully", "SUCCESS": "Xüsusiyyət uğurla silindi",
"ERROR": "Unable to delete attribute. Please try again later" "ERROR": "Atributu silmək mümkün olmadı. Zəhmət olmasa, bir az sonra yenidən cəhd edin"
}, },
"ATTRIBUTE_SELECT": { "ATTRIBUTE_SELECT": {
"TITLE": "Add attributes", "TITLE": "Atributlar əlavə et",
"PLACEHOLDER": "Search attributes", "PLACEHOLDER": "Atributlarda axtar",
"NO_RESULT": "No attributes found" "NO_RESULT": "Heç bir atribut tapılmadı"
} }
}, },
"EMAIL_HEADER": { "EMAIL_HEADER": {
"FROM": "From", "FROM": "Kimdən",
"TO": "To", "TO": "Kimə",
"BCC": "Bcc", "BCC": "Gizli nüsxə",
"CC": "Cc", "CC": "Nüsxə",
"SUBJECT": "Subject", "SUBJECT": "Mövzu",
"EXPAND": "Expand email" "EXPAND": "E-poçtu genişləndir"
}, },
"CONVERSATION_PARTICIPANTS": { "CONVERSATION_PARTICIPANTS": {
"SIDEBAR_MENU_TITLE": "Participating", "SIDEBAR_MENU_TITLE": "İştirak edənlər",
"SIDEBAR_TITLE": "Conversation participants", "SIDEBAR_TITLE": "Söhbət iştirakçıları",
"NO_RECORDS_FOUND": "No results found", "NO_RECORDS_FOUND": "Nəticə tapılmadı",
"ADD_PARTICIPANTS": "Select participants", "ADD_PARTICIPANTS": "İştirakçıları seçin",
"REMANING_PARTICIPANTS_TEXT": "+{count} others", "REMANING_PARTICIPANTS_TEXT": "+{count} digər",
"REMANING_PARTICIPANT_TEXT": "+{count} other", "REMANING_PARTICIPANT_TEXT": "+{count} digər",
"TOTAL_PARTICIPANTS_TEXT": "{count} people are participating.", "TOTAL_PARTICIPANTS_TEXT": "{count} nəfər iştirak edir.",
"TOTAL_PARTICIPANT_TEXT": "{count} person is participating.", "TOTAL_PARTICIPANT_TEXT": "{count} nəfər iştirak edir.",
"NO_PARTICIPANTS_TEXT": "No one is participating!.", "NO_PARTICIPANTS_TEXT": "No one is participating!.",
"WATCH_CONVERSATION": "Join conversation", "WATCH_CONVERSATION": "Söhbətə qoşulun",
"YOU_ARE_WATCHING": "You are participating", "YOU_ARE_WATCHING": "Siz iştirak edirsiniz",
"API": { "API": {
"ERROR_MESSAGE": "Could not update, try again!", "ERROR_MESSAGE": "Yenilənmədi, yenidən cəhd edin!",
"SUCCESS_MESSAGE": "Participants updated!" "SUCCESS_MESSAGE": "İştirakçılar yeniləndi!"
} }
}, },
"TRANSLATE_MODAL": { "TRANSLATE_MODAL": {
"TITLE": "View translated content", "TITLE": "Tərcümə edilmiş məzmunu göstər",
"DESC": "You can view the translated content in each langauge.", "DESC": "You can view the translated content in each langauge.",
"ORIGINAL_CONTENT": "Original Content", "ORIGINAL_CONTENT": "Orijinal məzmun",
"TRANSLATED_CONTENT": "Translated Content", "TRANSLATED_CONTENT": "Tərcümə edilmiş məzmun",
"NO_TRANSLATIONS_AVAILABLE": "No translations are available for this content" "NO_TRANSLATIONS_AVAILABLE": "Bu məzmun üçün tərcümə mövcud deyil"
}, },
"TYPING": { "TYPING": {
"ONE": "{user} is typing", "ONE": "{user} yazır",
"TWO": "{user} and {secondUser} are typing", "TWO": "{user} {secondUser} yazırlar",
"MULTIPLE": "{user} and {count} others are typing" "MULTIPLE": "{user} {count} başqası yazırlar"
}, },
"COPILOT": { "COPILOT": {
"TRY_THESE_PROMPTS": "Try these prompts" "TRY_THESE_PROMPTS": "Bu təklifləri sınayın"
}, },
"GALLERY_VIEW": { "GALLERY_VIEW": {
"ERROR_DOWNLOADING": "Unable to download attachment. Please try again" "ERROR_DOWNLOADING": "Əlavəni yükləmək mümkün olmadı. Zəhmət olmasa yenidən cəhd edin"
} }
} }
@@ -6,156 +6,156 @@
"CREATE_PORTAL_BUTTON": "Create Portal" "CREATE_PORTAL_BUTTON": "Create Portal"
}, },
"HEADER": { "HEADER": {
"FILTER": "Filter by", "FILTER": "Filtrlə",
"SORT": "Sort by", "SORT": "Sırala",
"LOCALE": "Locale", "LOCALE": "Dil",
"SETTINGS_BUTTON": "Settings", "SETTINGS_BUTTON": "Ayarlar",
"NEW_BUTTON": "New Article", "NEW_BUTTON": "Yeni Məqalə",
"DROPDOWN_OPTIONS": { "DROPDOWN_OPTIONS": {
"PUBLISHED": "Published", "PUBLISHED": "Yayımlanıb",
"DRAFT": "Draft", "DRAFT": "Qaralama",
"ARCHIVED": "Archived" "ARCHIVED": "Arxivlənib"
}, },
"TITLES": { "TITLES": {
"ALL_ARTICLES": "All Articles", "ALL_ARTICLES": "Bütün Məqalələr",
"MINE": "My Articles", "MINE": "Mənim Məqalələrim",
"DRAFT": "Draft Articles", "DRAFT": "Qaralama Məqalələr",
"ARCHIVED": "Archived Articles" "ARCHIVED": "Arxivləşdirilmiş Məqalələr"
}, },
"LOCALE_SELECT": { "LOCALE_SELECT": {
"TITLE": "Select locale", "TITLE": "Dili seçin",
"PLACEHOLDER": "Select locale", "PLACEHOLDER": "Dili seçin",
"NO_RESULT": "No locale found", "NO_RESULT": "Dil tapılmadı",
"SEARCH_PLACEHOLDER": "Search locale" "SEARCH_PLACEHOLDER": "Dil axtarışı"
} }
}, },
"EDIT_HEADER": { "EDIT_HEADER": {
"ALL_ARTICLES": "All Articles", "ALL_ARTICLES": "Bütün məqalələr",
"PUBLISH_BUTTON": "Publish", "PUBLISH_BUTTON": "Yayımla",
"MOVE_TO_ARCHIVE_BUTTON": "Move to archived", "MOVE_TO_ARCHIVE_BUTTON": "Arxivə köçür",
"PREVIEW": "Preview", "PREVIEW": "Önizləmə",
"ADD_TRANSLATION": "Add translation", "ADD_TRANSLATION": "Tərcümə əlavə et",
"OPEN_SIDEBAR": "Open sidebar", "OPEN_SIDEBAR": "Yan paneli aç",
"CLOSE_SIDEBAR": "Close sidebar", "CLOSE_SIDEBAR": "Yan paneli bağla",
"SAVING": "Saving...", "SAVING": "Yadda saxlanılır...",
"SAVED": "Saved" "SAVED": "Yadda saxlanıldı"
}, },
"ARTICLE_EDITOR": { "ARTICLE_EDITOR": {
"IMAGE_UPLOAD": { "IMAGE_UPLOAD": {
"TITLE": "Upload image", "TITLE": "Şəkil yüklə",
"UPLOADING": "Uploading...", "UPLOADING": "Yüklənir...",
"SUCCESS": "Image uploaded successfully", "SUCCESS": "Şəkil uğurla yükləndi",
"ERROR": "Error while uploading image", "ERROR": "Şəkil yüklənərkən xəta baş verdi",
"UN_AUTHORIZED_ERROR": "You are not authorized to upload images", "UN_AUTHORIZED_ERROR": "Şəkilləri yükləmək üçün icazəniz yoxdur",
"ERROR_FILE_SIZE": "Image size should be less than {size}MB", "ERROR_FILE_SIZE": "Şəkilin ölçüsü {size}MB-dən az olmalıdır",
"ERROR_FILE_FORMAT": "Image format should be jpg, jpeg or png", "ERROR_FILE_FORMAT": "Şəkil formatı jpg, jpeg və ya png olmalıdır",
"ERROR_FILE_DIMENSIONS": "Image dimensions should be less than 2000 x 2000" "ERROR_FILE_DIMENSIONS": "Şəkilin ölçüləri 2000 x 2000-dən az olmalıdır"
} }
}, },
"ARTICLE_SETTINGS": { "ARTICLE_SETTINGS": {
"TITLE": "Article Settings", "TITLE": "Məqalə parametrləri",
"FORM": { "FORM": {
"CATEGORY": { "CATEGORY": {
"LABEL": "Category", "LABEL": "Kateqoriya",
"TITLE": "Select category", "TITLE": "Kateqoriya seçin",
"PLACEHOLDER": "Select category", "PLACEHOLDER": "Kateqoriya seçin",
"NO_RESULT": "No category found", "NO_RESULT": "Heç bir kateqoriya tapılmadı",
"SEARCH_PLACEHOLDER": "Search category" "SEARCH_PLACEHOLDER": "Kateqoriya axtar"
}, },
"AUTHOR": { "AUTHOR": {
"LABEL": "Author", "LABEL": "Müəllif",
"TITLE": "Select author", "TITLE": "Müəllif seçin",
"PLACEHOLDER": "Select author", "PLACEHOLDER": "Müəllifi seçin",
"NO_RESULT": "No authors found", "NO_RESULT": "Müəllif tapılmadı",
"SEARCH_PLACEHOLDER": "Search author" "SEARCH_PLACEHOLDER": "Müəllifi axtar"
}, },
"META_TITLE": { "META_TITLE": {
"LABEL": "Meta title", "LABEL": "Meta başlıq",
"PLACEHOLDER": "Add a meta title" "PLACEHOLDER": "Meta başlıq əlavə edin"
}, },
"META_DESCRIPTION": { "META_DESCRIPTION": {
"LABEL": "Meta description", "LABEL": "Meta təsviri",
"PLACEHOLDER": "Add your meta description for better SEO results..." "PLACEHOLDER": "Daha yaxşı SEO nəticələri üçün meta təsvir əlavə edin..."
}, },
"META_TAGS": { "META_TAGS": {
"LABEL": "Meta tags", "LABEL": "Meta teqlər",
"PLACEHOLDER": "Add meta tags separated by comma..." "PLACEHOLDER": "Vergüllə ayrılmış meta teqlər əlavə edin..."
} }
}, },
"BUTTONS": { "BUTTONS": {
"ARCHIVE": "Archive article", "ARCHIVE": "Məqaləni arxivləşdir",
"DELETE": "Delete article" "DELETE": "Məqaləni sil"
} }
}, },
"ARTICLE_SEARCH_RESULT": { "ARTICLE_SEARCH_RESULT": {
"UNCATEGORIZED": "Uncategorized", "UNCATEGORIZED": "Kateqoriyasız",
"SEARCH_RESULTS": "Search results for {query}", "SEARCH_RESULTS": "Search results for {query}",
"EMPTY_TEXT": "Search for articles to insert into replies.", "EMPTY_TEXT": "Cavablara əlavə etmək üçün məqalələri axtarın.",
"SEARCH_LOADER": "Searching...", "SEARCH_LOADER": "Axtarılır...",
"INSERT_ARTICLE": "Insert", "INSERT_ARTICLE": "Daxil et",
"NO_RESULT": "No articles found", "NO_RESULT": "Məqalə tapılmadı",
"COPY_LINK": "Copy article link to clipboard", "COPY_LINK": "Məqalə linkini panoya kopyala",
"OPEN_LINK": "Open article in new tab", "OPEN_LINK": "Məqaləni yeni nişanda aç",
"PREVIEW_LINK": "Preview article" "PREVIEW_LINK": "Məqaləyə önizləmə baxışı"
}, },
"PORTAL": { "PORTAL": {
"HEADER": "Portals", "HEADER": "Portallar",
"DEFAULT": "Default", "DEFAULT": "Defolt",
"NEW_BUTTON": "New Portal", "NEW_BUTTON": "Yeni Portal",
"ACTIVE_BADGE": "active", "ACTIVE_BADGE": "aktiv",
"CHOOSE_LOCALE_LABEL": "Choose a locale", "CHOOSE_LOCALE_LABEL": "Bir dil seçin",
"LOADING_MESSAGE": "Loading portals...", "LOADING_MESSAGE": "Portallar yüklənir...",
"ARTICLES_LABEL": "articles", "ARTICLES_LABEL": "məqalələr",
"NO_PORTALS_MESSAGE": "There are no available portals", "NO_PORTALS_MESSAGE": "Mövcud portal yoxdur",
"ADD_NEW_LOCALE": "Add a new locale", "ADD_NEW_LOCALE": "Yeni dil əlavə et",
"POPOVER": { "POPOVER": {
"TITLE": "Portals", "TITLE": "Portallar",
"PORTAL_SETTINGS": "Portal settings", "PORTAL_SETTINGS": "Portal parametrləri",
"SUBTITLE": "You have multiple portals and can have different locales for each portal.", "SUBTITLE": "Bir neçə portalınız var və hər portal üçün fərqli dillər seçə bilərsiniz.",
"CANCEL_BUTTON_LABEL": "Cancel", "CANCEL_BUTTON_LABEL": "Ləğv et",
"CHOOSE_LOCALE_BUTTON": "Choose Locale" "CHOOSE_LOCALE_BUTTON": "Dil seçin"
}, },
"PORTAL_SETTINGS": { "PORTAL_SETTINGS": {
"LIST_ITEM": { "LIST_ITEM": {
"HEADER": { "HEADER": {
"COUNT_LABEL": "articles", "COUNT_LABEL": "məqalələr",
"ADD": "Add locale", "ADD": "Dil əlavə et",
"VISIT": "Visit site", "VISIT": "Sayta bax",
"SETTINGS": "Settings", "SETTINGS": "Parametrlər",
"DELETE": "Delete" "DELETE": "Sil"
}, },
"PORTAL_CONFIG": { "PORTAL_CONFIG": {
"TITLE": "Portal Configurations", "TITLE": "Portal Konfiqurasiyaları",
"ITEMS": { "ITEMS": {
"NAME": "Name", "NAME": "Ad",
"DOMAIN": "Custom domain", "DOMAIN": "Xüsusi domen",
"SLUG": "Slug", "SLUG": "Slug",
"TITLE": "Portal title", "TITLE": "Portal başlığı",
"THEME": "Theme color", "THEME": "Tema rəngi",
"SUB_TEXT": "Portal sub text" "SUB_TEXT": "Portal alt mətni"
} }
}, },
"AVAILABLE_LOCALES": { "AVAILABLE_LOCALES": {
"TITLE": "Available locales", "TITLE": "Mövcud dillər",
"TABLE": { "TABLE": {
"NAME": "Locale name", "NAME": "Dil adı",
"CODE": "Locale code", "CODE": "Dil kodu",
"ARTICLE_COUNT": "No. of articles", "ARTICLE_COUNT": "Məqalələrin sayı",
"CATEGORIES": "No. of categories", "CATEGORIES": "Kateqoriyaların sayı",
"SWAP": "Swap", "SWAP": "Dəyişdir",
"DELETE": "Delete", "DELETE": "Sil",
"DEFAULT_LOCALE": "Default" "DEFAULT_LOCALE": "Əsas"
} }
} }
}, },
"DELETE_PORTAL": { "DELETE_PORTAL": {
"TITLE": "Delete portal", "TITLE": "Portalı sil",
"MESSAGE": "Are you sure you want to delete this portal", "MESSAGE": "Bu portalı silmək istədiyinizə əminsiniz",
"YES": "Yes, delete portal", "YES": "Bəli, portalı sil",
"NO": "No, keep portal", "NO": "Xeyr, portalı saxla",
"API": { "API": {
"DELETE_SUCCESS": "Portal deleted successfully", "DELETE_SUCCESS": "Portal uğurla silindi",
"DELETE_ERROR": "Error while deleting portal" "DELETE_ERROR": "Portal silinərkən xəta baş verdi"
} }
}, },
"SEND_CNAME_INSTRUCTIONS": { "SEND_CNAME_INSTRUCTIONS": {
@@ -166,192 +166,192 @@
} }
}, },
"EDIT": { "EDIT": {
"HEADER_TEXT": "Edit portal", "HEADER_TEXT": "Portalı redaktə et",
"TABS": { "TABS": {
"BASIC_SETTINGS": { "BASIC_SETTINGS": {
"TITLE": "Basic information" "TITLE": "Əsas məlumat"
}, },
"CUSTOMIZATION_SETTINGS": { "CUSTOMIZATION_SETTINGS": {
"TITLE": "Portal customization" "TITLE": "Portal fərdiləşdirilməsi"
}, },
"CATEGORY_SETTINGS": { "CATEGORY_SETTINGS": {
"TITLE": "Categories" "TITLE": "Kateqoriyalar"
}, },
"LOCALE_SETTINGS": { "LOCALE_SETTINGS": {
"TITLE": "Locales" "TITLE": "Dillər"
} }
}, },
"CATEGORIES": { "CATEGORIES": {
"TITLE": "Categories in", "TITLE": "Kateqoriyalar",
"NEW_CATEGORY": "New category", "NEW_CATEGORY": "Yeni kateqoriya",
"TABLE": { "TABLE": {
"NAME": "Name", "NAME": "Ad",
"DESCRIPTION": "Description", "DESCRIPTION": "Təsvir",
"LOCALE": "Locale", "LOCALE": "Dil",
"ARTICLE_COUNT": "No. of articles", "ARTICLE_COUNT": "Məqalələrin sayı",
"ACTION_BUTTON": { "ACTION_BUTTON": {
"EDIT": "Edit category", "EDIT": "Kateqoriyanı redaktə et",
"DELETE": "Delete category" "DELETE": "Kateqoriyanı sil"
}, },
"EMPTY_TEXT": "No categories found" "EMPTY_TEXT": "Kateqoriyalar tapılmadı"
} }
}, },
"EDIT_BASIC_INFO": { "EDIT_BASIC_INFO": {
"BUTTON_TEXT": "Update basic settings" "BUTTON_TEXT": "Əsas parametrləri yenilə"
} }
}, },
"ADD": { "ADD": {
"CREATE_FLOW": { "CREATE_FLOW": {
"BASIC": { "BASIC": {
"TITLE": "Help center information", "TITLE": "Kömək mərkəzi məlumatları",
"BODY": "Basic information about portal" "BODY": "Portal haqqında əsas məlumat"
}, },
"CUSTOMIZATION": { "CUSTOMIZATION": {
"TITLE": "Help center customization", "TITLE": "Kömək mərkəzinin fərdiləşdirilməsi",
"BODY": "Customize portal" "BODY": "Portalı fərdiləşdirin"
}, },
"FINISH": { "FINISH": {
"TITLE": "Voila! 🎉", "TITLE": "Budur! 🎉",
"BODY": "You're all set!" "BODY": "You're all set!"
} }
}, },
"CREATE_FLOW_PAGE": { "CREATE_FLOW_PAGE": {
"BACK_BUTTON": "Back", "BACK_BUTTON": "Geri",
"BASIC_SETTINGS_PAGE": { "BASIC_SETTINGS_PAGE": {
"HEADER": "Create Portal", "HEADER": "Portal yarat",
"TITLE": "Help center information", "TITLE": "Kömək mərkəzi məlumatları",
"CREATE_BASIC_SETTING_BUTTON": "Create portal basic settings" "CREATE_BASIC_SETTING_BUTTON": "Portalun əsas parametrlərini yarat"
}, },
"CUSTOMIZATION_PAGE": { "CUSTOMIZATION_PAGE": {
"HEADER": "Portal customisation", "HEADER": "Portal fərdiləşdirilməsi",
"TITLE": "Help center customization", "TITLE": "Kömək mərkəzinin fərdiləşdirilməsi",
"UPDATE_PORTAL_BUTTON": "Update portal settings" "UPDATE_PORTAL_BUTTON": "Portal parametrlərini yenilə"
}, },
"FINISH_PAGE": { "FINISH_PAGE": {
"TITLE": "Voila!🎉 You're all set up!", "TITLE": "Voila!🎉 Hər şey hazırdır!",
"MESSAGE": "You can now see this created portal on your all portals page.", "MESSAGE": "İndi bu yaradılmış portala bütün portallar səhifənizdən baxa bilərsiniz.",
"FINISH": "Go to all portals page" "FINISH": "Bütün portallar səhifəsinə keç"
} }
}, },
"LOGO": { "LOGO": {
"LABEL": "Logo", "LABEL": "Logo",
"UPLOAD_BUTTON": "Upload logo", "UPLOAD_BUTTON": "Loqonu yüklə",
"HELP_TEXT": "This logo will be displayed on the portal header.", "HELP_TEXT": "Bu logo portal başlığında göstəriləcək.",
"IMAGE_UPLOAD_SUCCESS": "Logo uploaded successfully", "IMAGE_UPLOAD_SUCCESS": "Loqo uğurla yükləndi",
"IMAGE_UPLOAD_ERROR": "Logo deleted successfully", "IMAGE_UPLOAD_ERROR": "Loqo uğurla silindi",
"IMAGE_DELETE_ERROR": "Error while deleting logo" "IMAGE_DELETE_ERROR": "Loqo silinərkən xəta baş verdi"
}, },
"NAME": { "NAME": {
"LABEL": "Name", "LABEL": "Ad",
"PLACEHOLDER": "Portal name", "PLACEHOLDER": "Portal adı",
"HELP_TEXT": "The name will be used in the public facing portal internally.", "HELP_TEXT": "Ad daxili olaraq ictimai portalda istifadə olunacaq.",
"ERROR": "Name is required" "ERROR": "Ad tələb olunur"
}, },
"SLUG": { "SLUG": {
"LABEL": "Slug", "LABEL": "Slug",
"PLACEHOLDER": "Portal slug for urls", "PLACEHOLDER": "Portal slug URL-lər üçün",
"ERROR": "Slug is required" "ERROR": "Slug tələb olunur"
}, },
"DOMAIN": { "DOMAIN": {
"LABEL": "Custom Domain", "LABEL": "Xüsusi domen",
"PLACEHOLDER": "Portal custom domain", "PLACEHOLDER": "Portalun xüsusi domeni",
"HELP_TEXT": "Add only If you want to use a custom domain for your portals. Eg: {exampleURL}", "HELP_TEXT": "Add only If you want to use a custom domain for your portals. Eg: {exampleURL}",
"ERROR": "Enter a valid domain URL" "ERROR": "Etibarlı domen URL-si daxil edin"
}, },
"HOME_PAGE_LINK": { "HOME_PAGE_LINK": {
"LABEL": "Home Page Link", "LABEL": "Ana səhifə linki",
"PLACEHOLDER": "Portal home page link", "PLACEHOLDER": "Portalun ana səhifə linki",
"HELP_TEXT": "The link used to return from the portal to the home page. Eg: {exampleURL}", "HELP_TEXT": "The link used to return from the portal to the home page. Eg: {exampleURL}",
"ERROR": "Enter a valid home page URL" "ERROR": "Etibarlı ana səhifə URL-si daxil edin"
}, },
"THEME_COLOR": { "THEME_COLOR": {
"LABEL": "Portal theme color", "LABEL": "Portal tema rəngi",
"HELP_TEXT": "This color will show as the theme color for the portal." "HELP_TEXT": "Bu rəng portal üçün tema rəngi kimi göstəriləcək."
}, },
"PAGE_TITLE": { "PAGE_TITLE": {
"LABEL": "Page Title", "LABEL": "Səhifə Başlığı",
"PLACEHOLDER": "Portal page title", "PLACEHOLDER": "Portal səhifəsinin başlığı",
"HELP_TEXT": "The page title will be used in the public facing portal.", "HELP_TEXT": "Səhifənin başlığı ictimai portalda istifadə olunacaq.",
"ERROR": "Page title is required" "ERROR": "Səhifə başlığı tələb olunur"
}, },
"HEADER_TEXT": { "HEADER_TEXT": {
"LABEL": "Header Text", "LABEL": "Başlıq Mətn",
"PLACEHOLDER": "Portal header text", "PLACEHOLDER": "Portal başlıq mətni",
"HELP_TEXT": "The Portal header text will be used in the public facing portal.", "HELP_TEXT": "Portal başlıq mətni ictimai portalda istifadə olunacaq.",
"ERROR": "Portal header text is required" "ERROR": "Portal başlıq mətni tələb olunur"
}, },
"API": { "API": {
"SUCCESS_MESSAGE_FOR_BASIC": "Portal created successfully.", "SUCCESS_MESSAGE_FOR_BASIC": "Portal uğurla yaradıldı.",
"ERROR_MESSAGE_FOR_BASIC": "Couldn't create the portal. Try again.", "ERROR_MESSAGE_FOR_BASIC": "Portal yaradıla bilmədi. Yenidən cəhd edin.",
"SUCCESS_MESSAGE_FOR_UPDATE": "Portal updated successfully.", "SUCCESS_MESSAGE_FOR_UPDATE": "Portal uğurla yeniləndi.",
"ERROR_MESSAGE_FOR_UPDATE": "Couldn't update the portal. Try again." "ERROR_MESSAGE_FOR_UPDATE": "Portal yenilənə bilmədi. Yenidən cəhd edin."
} }
}, },
"ADD_LOCALE": { "ADD_LOCALE": {
"TITLE": "Add a new locale", "TITLE": "Yeni dil əlavə et",
"SUB_TITLE": "This adds a new locale to your available translation list.", "SUB_TITLE": "Bu, mövcud tərcümə siyahınıza yeni bir dil əlavə edir.",
"PORTAL": "Portal", "PORTAL": "Portal",
"LOCALE": { "LOCALE": {
"LABEL": "Locale", "LABEL": "Dil",
"PLACEHOLDER": "Choose a locale", "PLACEHOLDER": "Dil seçin",
"ERROR": "Locale is required" "ERROR": "Dil tələb olunur"
}, },
"BUTTONS": { "BUTTONS": {
"CREATE": "Create locale", "CREATE": "Dili yarat",
"CANCEL": "Cancel" "CANCEL": "Ləğv et"
}, },
"API": { "API": {
"SUCCESS_MESSAGE": "Locale added successfully", "SUCCESS_MESSAGE": "Dil uğurla əlavə edildi",
"ERROR_MESSAGE": "Unable to add locale. Try again." "ERROR_MESSAGE": "Dil əlavə etmək mümkün olmadı. Yenidən cəhd edin."
} }
}, },
"CHANGE_DEFAULT_LOCALE": { "CHANGE_DEFAULT_LOCALE": {
"API": { "API": {
"SUCCESS_MESSAGE": "Default locale updated successfully", "SUCCESS_MESSAGE": "Əsas dil uğurla yeniləndi",
"ERROR_MESSAGE": "Unable to update default locale. Try again." "ERROR_MESSAGE": "Əsas dili yeniləmək mümkün olmadı. Yenidən cəhd edin."
} }
}, },
"DELETE_LOCALE": { "DELETE_LOCALE": {
"API": { "API": {
"SUCCESS_MESSAGE": "Locale removed from portal successfully", "SUCCESS_MESSAGE": "Dil portaldan uğurla silindi",
"ERROR_MESSAGE": "Unable to remove locale from portal. Try again." "ERROR_MESSAGE": "Dili portaldan silmək mümkün olmadı. Yenidən cəhd edin."
} }
} }
}, },
"TABLE": { "TABLE": {
"LOADING_MESSAGE": "Loading articles...", "LOADING_MESSAGE": "Məqalələr yüklənir...",
"404": "No articles matches your search 🔍", "404": "Axtarışınıza uyğun məqalə tapılmadı 🔍",
"NO_ARTICLES": "There are no available articles", "NO_ARTICLES": "Mövcud məqalə yoxdur",
"HEADERS": { "HEADERS": {
"TITLE": "Title", "TITLE": "Başlıq",
"CATEGORY": "Category", "CATEGORY": "Kateqoriya",
"READ_COUNT": "Views", "READ_COUNT": "Baxışlar",
"STATUS": "Status", "STATUS": "Vəziyyət",
"LAST_EDITED": "Last edited" "LAST_EDITED": "Son redaktə"
}, },
"COLUMNS": { "COLUMNS": {
"BY": "by", "BY": "tərəfindən",
"AUTHOR_NOT_AVAILABLE": "Author is not available" "AUTHOR_NOT_AVAILABLE": "Müəllif mövcud deyil"
} }
}, },
"EDIT_ARTICLE": { "EDIT_ARTICLE": {
"LOADING": "Loading article...", "LOADING": "Məqalə yüklənir...",
"TITLE_PLACEHOLDER": "Article title goes here", "TITLE_PLACEHOLDER": "Məqalənin başlığı buraya yazılır",
"CONTENT_PLACEHOLDER": "Write your article here", "CONTENT_PLACEHOLDER": "Məqalənizi buraya yazın",
"API": { "API": {
"ERROR": "Error while saving article" "ERROR": "Məqalə yadda saxlanarkən xəta baş verdi"
} }
}, },
"PUBLISH_ARTICLE": { "PUBLISH_ARTICLE": {
"API": { "API": {
"ERROR": "Error while publishing article", "ERROR": "Məqalə yayımlanarkən xəta baş verdi",
"SUCCESS": "Article published successfully" "SUCCESS": "Məqalə uğurla dərc olundu"
} }
}, },
"ARCHIVE_ARTICLE": { "ARCHIVE_ARTICLE": {
"API": { "API": {
"ERROR": "Error while archiving article", "ERROR": "Məqalə arxivlənərkən xəta baş verdi",
"SUCCESS": "Article archived successfully" "SUCCESS": "Məqalə uğurla arxivləndi"
} }
}, },
"DRAFT_ARTICLE": { "DRAFT_ARTICLE": {
@@ -363,15 +363,15 @@
"DELETE_ARTICLE": { "DELETE_ARTICLE": {
"MODAL": { "MODAL": {
"CONFIRM": { "CONFIRM": {
"TITLE": "Confirm Deletion", "TITLE": "Silinməni təsdiqləyin",
"MESSAGE": "Are you sure to delete the article?", "MESSAGE": "Məqaləni silmək istədiyinizə əminsiniz?",
"YES": "Yes, Delete", "YES": "Bəli, sil",
"NO": "No, Keep it" "NO": "Xeyr, Saxla"
} }
}, },
"API": { "API": {
"SUCCESS_MESSAGE": "Article deleted successfully", "SUCCESS_MESSAGE": "Məqalə uğurla silindi",
"ERROR_MESSAGE": "Error while deleting article" "ERROR_MESSAGE": "Məqaləni silərkən xəta baş verdi"
} }
}, },
"REORDER_ARTICLE": { "REORDER_ARTICLE": {
@@ -385,126 +385,126 @@
} }
}, },
"CREATE_ARTICLE": { "CREATE_ARTICLE": {
"ERROR_MESSAGE": "Please add the article heading and content then only you can update the settings" "ERROR_MESSAGE": "Zəhmət olmasa məqalənin başlığını və məzmununu əlavə edin, yalnız bundan sonra parametrləri yeniləyə bilərsiniz"
}, },
"SIDEBAR": { "SIDEBAR": {
"SEARCH": { "SEARCH": {
"PLACEHOLDER": "Search for articles" "PLACEHOLDER": "Məqalələrdə axtarış"
} }
}, },
"CATEGORY": { "CATEGORY": {
"ADD": { "ADD": {
"TITLE": "Create a category", "TITLE": "Kateqoriya yaradın",
"SUB_TITLE": "The category will be used in the public facing portal to categorize articles.", "SUB_TITLE": "Kateqoriya, məqalələri kateqoriyalara ayırmaq üçün ictimai portalda istifadə olunacaq.",
"PORTAL": "Portal", "PORTAL": "Portal",
"LOCALE": "Locale", "LOCALE": "Dil",
"NAME": { "NAME": {
"LABEL": "Name", "LABEL": "Ad",
"PLACEHOLDER": "Category name", "PLACEHOLDER": "Kateqoriya adı",
"HELP_TEXT": "The category name and icon will be used in the public facing portal to categorize articles.", "HELP_TEXT": "Kateqoriya adı ikonu məqalələri kateqoriyalara ayırmaq üçün ictimai portalda istifadə olunacaq.",
"ERROR": "Name is required" "ERROR": "Ad tələb olunur"
}, },
"SLUG": { "SLUG": {
"LABEL": "Slug", "LABEL": "Slug",
"PLACEHOLDER": "Category slug for urls", "PLACEHOLDER": "URL-lər üçün kateqoriya slug-u",
"HELP_TEXT": "app.chatwoot.com/hc/my-portal/en-US/categories/my-slug", "HELP_TEXT": "app.chatwoot.com/hc/my-portal/en-US/categories/my-slug",
"ERROR": "Slug is required" "ERROR": "Slug tələb olunur"
}, },
"DESCRIPTION": { "DESCRIPTION": {
"LABEL": "Description", "LABEL": "Təsvir",
"PLACEHOLDER": "Give a short description about the category.", "PLACEHOLDER": "Kateqoriya haqqında qısa təsvir verin.",
"ERROR": "Description is required" "ERROR": "Təsvir tələb olunur"
}, },
"BUTTONS": { "BUTTONS": {
"CREATE": "Create category", "CREATE": "Kateqoriya yarat",
"CANCEL": "Cancel" "CANCEL": "Ləğv et"
}, },
"API": { "API": {
"SUCCESS_MESSAGE": "Category created successfully", "SUCCESS_MESSAGE": "Kateqoriya uğurla yaradıldı",
"ERROR_MESSAGE": "Unable to create category" "ERROR_MESSAGE": "Kateqoriya yaratmaq mümkün olmadı"
} }
}, },
"EDIT": { "EDIT": {
"TITLE": "Edit a category", "TITLE": "Kateqoriyanı redaktə et",
"SUB_TITLE": "Editing a category will update the category in the public facing portal.", "SUB_TITLE": "Kateqoriyanın redaktəsi ictimai portalda kateqoriyanı yeniləyəcək.",
"PORTAL": "Portal", "PORTAL": "Portal",
"LOCALE": "Locale", "LOCALE": "Dil",
"NAME": { "NAME": {
"LABEL": "Name", "LABEL": "Ad",
"PLACEHOLDER": "Category name", "PLACEHOLDER": "Kateqoriya adı",
"HELP_TEXT": "The category name and icon will be used in the public facing portal to categorize articles.", "HELP_TEXT": "Kateqoriya adı ikonu məqalələri kateqoriyalara ayırmaq üçün ictimai portalda istifadə olunacaq.",
"ERROR": "Name is required" "ERROR": "Ad tələb olunur"
}, },
"SLUG": { "SLUG": {
"LABEL": "Slug", "LABEL": "Slug",
"PLACEHOLDER": "Category slug for urls", "PLACEHOLDER": "URL-lər üçün kateqoriya slug-u",
"HELP_TEXT": "app.chatwoot.com/hc/my-portal/en-US/categories/my-slug", "HELP_TEXT": "app.chatwoot.com/hc/my-portal/en-US/categories/my-slug",
"ERROR": "Slug is required" "ERROR": "Slug tələb olunur"
}, },
"DESCRIPTION": { "DESCRIPTION": {
"LABEL": "Description", "LABEL": "Təsvir",
"PLACEHOLDER": "Give a short description about the category.", "PLACEHOLDER": "Kateqoriya haqqında qısa təsvir verin.",
"ERROR": "Description is required" "ERROR": "Təsvir tələb olunur"
}, },
"BUTTONS": { "BUTTONS": {
"CREATE": "Update category", "CREATE": "Kateqoriyanı yenilə",
"CANCEL": "Cancel" "CANCEL": "Ləğv et"
}, },
"API": { "API": {
"SUCCESS_MESSAGE": "Category updated successfully", "SUCCESS_MESSAGE": "Kateqoriya uğurla yeniləndi",
"ERROR_MESSAGE": "Unable to update category" "ERROR_MESSAGE": "Kateqoriyanı yeniləmək mümkün olmadı"
} }
}, },
"DELETE": { "DELETE": {
"API": { "API": {
"SUCCESS_MESSAGE": "Category deleted successfully", "SUCCESS_MESSAGE": "Kateqoriya uğurla silindi",
"ERROR_MESSAGE": "Unable to delete category" "ERROR_MESSAGE": "Kateqoriyanı silmək mümkün olmadı"
} }
} }
}, },
"ARTICLE_SEARCH": { "ARTICLE_SEARCH": {
"TITLE": "Search articles", "TITLE": "Məqalələrdə axtarış edin",
"PLACEHOLDER": "Search articles", "PLACEHOLDER": "Məqalələrdə axtarış edin",
"NO_RESULT": "No articles found", "NO_RESULT": "Məqalə tapılmadı",
"SEARCHING": "Searching...", "SEARCHING": "Axtarılır...",
"SEARCH_BUTTON": "Search", "SEARCH_BUTTON": "Axtar",
"INSERT_ARTICLE": "Insert link", "INSERT_ARTICLE": "Link əlavə et",
"IFRAME_ERROR": "URL is empty or invalid. Unable to display content.", "IFRAME_ERROR": "URL boş və ya düzgün deyil. Məzmun göstərilə bilmir.",
"OPEN_ARTICLE_SEARCH": "Insert article from Help Center", "OPEN_ARTICLE_SEARCH": "Kömək Mərkəzindən məqalə əlavə et",
"SUCCESS_ARTICLE_INSERTED": "Article inserted successfully", "SUCCESS_ARTICLE_INSERTED": "Məqalə uğurla əlavə edildi",
"PREVIEW_LINK": "Preview article", "PREVIEW_LINK": "Məqaləni önizləyin",
"CANCEL": "Close", "CANCEL": "Bağla",
"BACK": "Back", "BACK": "Geri",
"BACK_RESULTS": "Back to results" "BACK_RESULTS": "Nəticələrə qayıdın"
}, },
"UPGRADE_PAGE": { "UPGRADE_PAGE": {
"TITLE": "Help Center", "TITLE": "Kömək Mərkəzi",
"DESCRIPTION": "Create user-friendly self-service portals. Help your users to access the articles and get support 24/7. Upgrade your subscription to enable this feature.", "DESCRIPTION": "İstifadəçi dostu özünə xidmət portalları yaradın. İstifadəçilərinizə məqalələrə daxil olmaq və 24/7 dəstək almaqda kömək edin. Bu funksiyanı aktivləşdirmək üçün abunəliyinizi yüksəldin.",
"SELF_HOSTED_DESCRIPTION": "Create user-friendly self-service portals. Help your users to access the articles and get support 24/7. Please contact your administrator to enable this feature.", "SELF_HOSTED_DESCRIPTION": "İstifadəçi dostu özünə xidmət portalları yaradın. İstifadəçilərinizə məqalələrə daxil olmaq və 24/7 dəstək almaqda kömək edin. Zəhmət olmasa, bu funksiyanı aktivləşdirmək üçün administratorunuzla əlaqə saxlayın.",
"BUTTON": { "BUTTON": {
"LEARN_MORE": "Learn more", "LEARN_MORE": "Ətraflı öyrən",
"UPGRADE": "Upgrade" "UPGRADE": "Yenilə"
}, },
"FEATURES": { "FEATURES": {
"PORTALS": { "PORTALS": {
"TITLE": "Multiple portals", "TITLE": "Çoxsaylı portallar",
"DESCRIPTION": "Create multiple help center portals for different products using the same account." "DESCRIPTION": "Eyni hesabdan istifadə edərək müxtəlif məhsullar üçün çoxsaylı kömək mərkəzi portalları yaradın."
}, },
"LOCALES": { "LOCALES": {
"TITLE": "Full support for locales", "TITLE": "Dil variantlarının tam dəstəyi",
"DESCRIPTION": "Localize the portal in your language. We support all locales and allow translations for every article." "DESCRIPTION": "Portalı öz dilinizə uyğunlaşdırın. Bütün dil variantlarını dəstəkləyirik və hər məqalə üçün tərcümələrə imkan veririk."
}, },
"SEO": { "SEO": {
"TITLE": "SEO-friendly design", "TITLE": "SEO-ya uyğun dizayn",
"DESCRIPTION": "Customize your meta tags to improve your visibility on search engines with our SEO-friendly pages." "DESCRIPTION": "Meta teqlərinizi fərdiləşdirərək axtarış motorlarında görünürlüğünüzü SEO dostu səhifələrimizlə artırın."
}, },
"API": { "API": {
"TITLE": "Full API support", "TITLE": "Tam API dəstəyi",
"DESCRIPTION": "Use the portal as a headless CMS with third party front-end frameworks using our APIs." "DESCRIPTION": "Portaldan üçüncü tərəf ön çərçivələri ilə başsız CMS kimi istifadə etmək üçün API-lərimizdən yararlanın."
} }
} }
}, },
"LOADING": "Loading...", "LOADING": "Yüklənir...",
"ARTICLES_PAGE": { "ARTICLES_PAGE": {
"ARTICLE_CARD": { "ARTICLE_CARD": {
"CARD": { "CARD": {
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,138 +1,138 @@
{ {
"REPORT": { "REPORT": {
"HEADER": "Conversations", "HEADER": "Söhbətlər",
"LOADING_CHART": "Loading chart data...", "LOADING_CHART": "Loading chart data...",
"NO_ENOUGH_DATA": "We've not received enough data points to generate report, Please try again later.", "NO_ENOUGH_DATA": "Hesabat yaratmaq üçün kifayət qədər məlumat nöqtəsi alınmayıb, zəhmət olmasa bir az sonra yenidən cəhd edin.",
"DOWNLOAD_CONVERSATION_REPORTS": "Download conversation reports", "DOWNLOAD_CONVERSATION_REPORTS": "Download conversation reports",
"DATA_FETCHING_FAILED": "Failed to fetch data, please try again later.", "DATA_FETCHING_FAILED": "Məlumatları əldə etmək mümkün olmadı, zəhmət olmasa bir az sonra yenidən cəhd edin.",
"SUMMARY_FETCHING_FAILED": "Failed to fetch summary, please try again later.", "SUMMARY_FETCHING_FAILED": "Yekunu əldə etmək mümkün olmadı, zəhmət olmasa bir az sonra yenidən cəhd edin.",
"METRICS": { "METRICS": {
"CONVERSATIONS": { "CONVERSATIONS": {
"NAME": "Conversations", "NAME": "Söhbətlər",
"DESC": "( Total )" "DESC": "( Ümumi )"
}, },
"INCOMING_MESSAGES": { "INCOMING_MESSAGES": {
"NAME": "Messages received", "NAME": "Messages received",
"DESC": "( Total )" "DESC": "( Ümumi )"
}, },
"OUTGOING_MESSAGES": { "OUTGOING_MESSAGES": {
"NAME": "Messages sent", "NAME": "Messages sent",
"DESC": "( Total )" "DESC": "( Ümumi )"
}, },
"FIRST_RESPONSE_TIME": { "FIRST_RESPONSE_TIME": {
"NAME": "First Response Time", "NAME": "İlk Cavab Vaxtı",
"DESC": "( Avg )", "DESC": "( Orta )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "Hesablama üçün istifadə olunan ümumi söhbət sayı:",
"TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "İlkin cavab vaxtı {metricValue}-dir ({conversationCount} söhbət əsasında)"
}, },
"RESOLUTION_TIME": { "RESOLUTION_TIME": {
"NAME": "Resolution Time", "NAME": "Həll Vaxtı",
"DESC": "( Avg )", "DESC": "( Orta )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "Hesablama üçün istifadə olunan ümumi söhbət sayı:",
"TOOLTIP_TEXT": "Resolution Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "Həll vaxtı {metricValue}-dir ({conversationCount} söhbət əsasında)"
}, },
"RESOLUTION_COUNT": { "RESOLUTION_COUNT": {
"NAME": "Resolution Count", "NAME": "Həll Sayı",
"DESC": "( Total )" "DESC": "( Ümumi )"
}, },
"BOT_RESOLUTION_COUNT": { "BOT_RESOLUTION_COUNT": {
"NAME": "Resolution Count", "NAME": "Həll sayı",
"DESC": "( Total )" "DESC": "( Ümumi )"
}, },
"BOT_HANDOFF_COUNT": { "BOT_HANDOFF_COUNT": {
"NAME": "Handoff Count", "NAME": "Təslim Sayı",
"DESC": "( Total )" "DESC": "( Ümumi )"
}, },
"REPLY_TIME": { "REPLY_TIME": {
"NAME": "Customer waiting time", "NAME": "Customer waiting time",
"TOOLTIP_TEXT": "Waiting time is {metricValue} (based on {conversationCount} replies)", "TOOLTIP_TEXT": "Gözləmə vaxtı {metricValue}-dir ({conversationCount} cavab əsasında)",
"DESC": "" "DESC": ""
} }
}, },
"DATE_RANGE_OPTIONS": { "DATE_RANGE_OPTIONS": {
"LAST_7_DAYS": "Last 7 days", "LAST_7_DAYS": "Son 7 gün",
"LAST_14_DAYS": "Last 14 days", "LAST_14_DAYS": "Son 14 gün",
"LAST_30_DAYS": "Last 30 days", "LAST_30_DAYS": "Son 30 gün",
"THIS_MONTH": "This month", "THIS_MONTH": "Bu ay",
"LAST_MONTH": "Last month", "LAST_MONTH": "Keçən ay",
"LAST_3_MONTHS": "Last 3 months", "LAST_3_MONTHS": "Son 3 ay",
"LAST_6_MONTHS": "Last 6 months", "LAST_6_MONTHS": "Son 6 ay",
"LAST_YEAR": "Last year", "LAST_YEAR": "Keçən il",
"CUSTOM_DATE_RANGE": "Custom date range" "CUSTOM_DATE_RANGE": "Custom date range"
}, },
"CUSTOM_DATE_RANGE": { "CUSTOM_DATE_RANGE": {
"CONFIRM": "Apply", "CONFIRM": "Tətbiq et",
"PLACEHOLDER": "Select date range" "PLACEHOLDER": "Select date range"
}, },
"GROUP_BY_FILTER_DROPDOWN_LABEL": "Group By", "GROUP_BY_FILTER_DROPDOWN_LABEL": "Group By",
"DURATION_FILTER_LABEL": "Duration", "DURATION_FILTER_LABEL": "Müddət",
"GROUPING_OPTIONS": { "GROUPING_OPTIONS": {
"DAY": "Day", "DAY": "Gün",
"WEEK": "Week", "WEEK": "Həftə",
"MONTH": "Month", "MONTH": "Ay",
"YEAR": "Year" "YEAR": "İl"
}, },
"GROUP_BY_DAY_OPTIONS": [ "GROUP_BY_DAY_OPTIONS": [
{ {
"id": 1, "id": 1,
"groupBy": "Day" "groupBy": "Gün"
} }
], ],
"GROUP_BY_WEEK_OPTIONS": [ "GROUP_BY_WEEK_OPTIONS": [
{ {
"id": 1, "id": 1,
"groupBy": "Day" "groupBy": "Gün"
}, },
{ {
"id": 2, "id": 2,
"groupBy": "Week" "groupBy": "Həftə"
} }
], ],
"GROUP_BY_MONTH_OPTIONS": [ "GROUP_BY_MONTH_OPTIONS": [
{ {
"id": 1, "id": 1,
"groupBy": "Day" "groupBy": "Gün"
}, },
{ {
"id": 2, "id": 2,
"groupBy": "Week" "groupBy": "Həftə"
}, },
{ {
"id": 3, "id": 3,
"groupBy": "Month" "groupBy": "Ay"
} }
], ],
"GROUP_BY_YEAR_OPTIONS": [ "GROUP_BY_YEAR_OPTIONS": [
{ {
"id": 2, "id": 2,
"groupBy": "Week" "groupBy": "Həftə"
}, },
{ {
"id": 3, "id": 3,
"groupBy": "Month" "groupBy": "Ay"
}, },
{ {
"id": 4, "id": 4,
"groupBy": "Year" "groupBy": "İl"
} }
], ],
"BUSINESS_HOURS": "Business Hours", "BUSINESS_HOURS": "İş Saatları",
"FILTER_ACTIONS": { "FILTER_ACTIONS": {
"CLEAR_FILTER": "Clear filter", "CLEAR_FILTER": "Clear filter",
"EMPTY_LIST": "No results found" "EMPTY_LIST": "Nəticə tapılmadı"
}, },
"PAGINATION": { "PAGINATION": {
"RESULTS": "Showing {start} to {end} of {total} results", "RESULTS": "{total} nəticədən {start} - {end} göstərilir",
"PER_PAGE_TEMPLATE": "{size} / page" "PER_PAGE_TEMPLATE": "{size} / səhifə"
} }
}, },
"AGENT_REPORTS": { "AGENT_REPORTS": {
"HEADER": "Agents Overview", "HEADER": "Agents Overview",
"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": "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.",
"LOADING_CHART": "Loading chart data...", "LOADING_CHART": "Loading chart data...",
"NO_ENOUGH_DATA": "We've not received enough data points to generate report, Please try again later.", "NO_ENOUGH_DATA": "Hesabat yaratmaq üçün kifayət qədər məlumat nöqtəsi almamışıq, zəhmət olmasa sonra yenidən cəhd edin.",
"DOWNLOAD_AGENT_REPORTS": "Download agent reports", "DOWNLOAD_AGENT_REPORTS": "Download agent reports",
"FILTER_DROPDOWN_LABEL": "Select Agent", "FILTER_DROPDOWN_LABEL": "Agent seçin",
"FILTERS": { "FILTERS": {
"INPUT_PLACEHOLDER": { "INPUT_PLACEHOLDER": {
"AGENTS": "Search agents" "AGENTS": "Search agents"
@@ -140,54 +140,54 @@
}, },
"METRICS": { "METRICS": {
"CONVERSATIONS": { "CONVERSATIONS": {
"NAME": "Conversations", "NAME": "Söhbətlər",
"DESC": "( Total )" "DESC": "( Ümumi )"
}, },
"INCOMING_MESSAGES": { "INCOMING_MESSAGES": {
"NAME": "Incoming Messages", "NAME": "Incoming Messages",
"DESC": "( Total )" "DESC": "( Ümumi )"
}, },
"OUTGOING_MESSAGES": { "OUTGOING_MESSAGES": {
"NAME": "Outgoing Messages", "NAME": "Outgoing Messages",
"DESC": "( Total )" "DESC": "( Ümumi )"
}, },
"FIRST_RESPONSE_TIME": { "FIRST_RESPONSE_TIME": {
"NAME": "First Response Time", "NAME": "İlk Cavab Vaxtı",
"DESC": "( Avg )", "DESC": "( Orta )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "Hesablama üçün istifadə olunan ümumi söhbət sayı:",
"TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "İlk cavab vaxtı {metricValue}-dir ({conversationCount} söhbət əsasında)"
}, },
"RESOLUTION_TIME": { "RESOLUTION_TIME": {
"NAME": "Resolution Time", "NAME": "Həll Vaxtı",
"DESC": "( Avg )", "DESC": "( Orta )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "Hesablama üçün istifadə olunan ümumi söhbət sayı:",
"TOOLTIP_TEXT": "Resolution Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "Həll vaxtı {metricValue}-dir ({conversationCount} söhbət əsasında)"
}, },
"RESOLUTION_COUNT": { "RESOLUTION_COUNT": {
"NAME": "Resolution Count", "NAME": "Həll Sayı",
"DESC": "( Total )" "DESC": "( Cəmi )"
} }
}, },
"DATE_RANGE": [ "DATE_RANGE": [
{ {
"id": 0, "id": 0,
"name": "Last 7 days" "name": "Son 7 gün"
}, },
{ {
"id": 1, "id": 1,
"name": "Last 30 days" "name": "Son 30 gün"
}, },
{ {
"id": 2, "id": 2,
"name": "Last 3 months" "name": "Son 3 ay"
}, },
{ {
"id": 3, "id": 3,
"name": "Last 6 months" "name": "Son 6 ay"
}, },
{ {
"id": 4, "id": 4,
"name": "Last year" "name": "Keçən il"
}, },
{ {
"id": 5, "id": 5,
@@ -195,15 +195,15 @@
} }
], ],
"CUSTOM_DATE_RANGE": { "CUSTOM_DATE_RANGE": {
"CONFIRM": "Apply", "CONFIRM": "Tətbiq et",
"PLACEHOLDER": "Select date range" "PLACEHOLDER": "Select date range"
} }
}, },
"LABEL_REPORTS": { "LABEL_REPORTS": {
"HEADER": "Labels Overview", "HEADER": "Labels Overview",
"DESCRIPTION": "Track label performance with key metrics including conversations, response times, resolution times, and resolved cases. Click a label name for detailed insights.", "DESCRIPTION": "Nişan nəticələrini söhbətlər, cavab müddəti, həll müddəti və həll olunmuş hallar üzrə yoxlayın. Ətraflı məlumat üçün nişan adını açın.",
"LOADING_CHART": "Loading chart data...", "LOADING_CHART": "Loading chart data...",
"NO_ENOUGH_DATA": "We've not received enough data points to generate report, Please try again later.", "NO_ENOUGH_DATA": "Hesabat yaratmaq üçün kifayət qədər məlumat nöqtəsi almamışıq, zəhmət olmasa bir az sonra yenidən cəhd edin.",
"DOWNLOAD_LABEL_REPORTS": "Download label reports", "DOWNLOAD_LABEL_REPORTS": "Download label reports",
"FILTER_DROPDOWN_LABEL": "Select Label", "FILTER_DROPDOWN_LABEL": "Select Label",
"FILTERS": { "FILTERS": {
@@ -213,62 +213,62 @@
}, },
"METRICS": { "METRICS": {
"CONVERSATIONS": { "CONVERSATIONS": {
"NAME": "Conversations", "NAME": "Söhbətlər",
"DESC": "( Total )" "DESC": "( Ümumi )"
}, },
"INCOMING_MESSAGES": { "INCOMING_MESSAGES": {
"NAME": "Incoming Messages", "NAME": "Incoming Messages",
"DESC": "( Total )" "DESC": "( Cəmi )"
}, },
"OUTGOING_MESSAGES": { "OUTGOING_MESSAGES": {
"NAME": "Outgoing Messages", "NAME": "Outgoing Messages",
"DESC": "( Total )" "DESC": "( Cəmi )"
}, },
"FIRST_RESPONSE_TIME": { "FIRST_RESPONSE_TIME": {
"NAME": "First Response Time", "NAME": "İlk Cavab Vaxtı",
"DESC": "( Avg )", "DESC": "( Orta )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "Hesablama üçün istifadə olunan ümumi söhbət sayı:",
"TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "İlk cavab vaxtı {metricValue}-dir ({conversationCount} söhbət əsasında)"
}, },
"RESOLUTION_TIME": { "RESOLUTION_TIME": {
"NAME": "Resolution Time", "NAME": "Həll Vaxtı",
"DESC": "( Avg )", "DESC": "( Orta )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "Hesablama üçün istifadə olunan ümumi söhbət sayı:",
"TOOLTIP_TEXT": "Resolution Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "Həll vaxtı {metricValue}-dir ({conversationCount} söhbətə əsaslanır)"
}, },
"RESOLUTION_COUNT": { "RESOLUTION_COUNT": {
"NAME": "Resolution Count", "NAME": "Həll Sayı",
"DESC": "( Total )" "DESC": "( Cəmi )"
} }
}, },
"DATE_RANGE": [ "DATE_RANGE": [
{ {
"id": 0, "id": 0,
"name": "Last 7 days" "name": "Son 7 gün"
}, },
{ {
"id": 1, "id": 1,
"name": "Last 30 days" "name": "Son 30 gün"
}, },
{ {
"id": 2, "id": 2,
"name": "Last 3 months" "name": "Son 3 ay"
}, },
{ {
"id": 3, "id": 3,
"name": "Last 6 months" "name": "Son 6 ay"
}, },
{ {
"id": 4, "id": 4,
"name": "Last year" "name": "Keçən il"
}, },
{ {
"id": 5, "id": 5,
"name": "Custom date range" "name": "Xüsusi tarix aralığı"
} }
], ],
"CUSTOM_DATE_RANGE": { "CUSTOM_DATE_RANGE": {
"CONFIRM": "Apply", "CONFIRM": "Tətbiq et",
"PLACEHOLDER": "Select date range" "PLACEHOLDER": "Select date range"
} }
}, },
@@ -276,84 +276,84 @@
"HEADER": "Inbox Overview", "HEADER": "Inbox Overview",
"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": "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.",
"LOADING_CHART": "Loading chart data...", "LOADING_CHART": "Loading chart data...",
"NO_ENOUGH_DATA": "We've not received enough data points to generate report, Please try again later.", "NO_ENOUGH_DATA": "Hesabat yaratmaq üçün kifayət qədər məlumat nöqtəsi almamışıq, zəhmət olmasa bir az sonra yenidən cəhd edin.",
"DOWNLOAD_INBOX_REPORTS": "Download inbox reports", "DOWNLOAD_INBOX_REPORTS": "Download inbox reports",
"FILTER_DROPDOWN_LABEL": "Select Inbox", "FILTER_DROPDOWN_LABEL": "Qutu seçin",
"ALL_INBOXES": "All Inboxes", "ALL_INBOXES": "Bütün Qutular",
"SEARCH_INBOX": "Search Inbox", "SEARCH_INBOX": "Qutu üzrə axtarış",
"FILTERS": { "FILTERS": {
"INPUT_PLACEHOLDER": { "INPUT_PLACEHOLDER": {
"INBOXES": "Search inboxes" "INBOXES": "Qutuları axtar"
} }
}, },
"METRICS": { "METRICS": {
"CONVERSATIONS": { "CONVERSATIONS": {
"NAME": "Conversations", "NAME": "Söhbətlər",
"DESC": "( Total )" "DESC": "( Ümumi )"
}, },
"INCOMING_MESSAGES": { "INCOMING_MESSAGES": {
"NAME": "Incoming Messages", "NAME": "Incoming Messages",
"DESC": "( Total )" "DESC": "( Ümumi )"
}, },
"OUTGOING_MESSAGES": { "OUTGOING_MESSAGES": {
"NAME": "Outgoing Messages", "NAME": "Outgoing Messages",
"DESC": "( Total )" "DESC": "( Ümumi )"
}, },
"FIRST_RESPONSE_TIME": { "FIRST_RESPONSE_TIME": {
"NAME": "First Response Time", "NAME": "İlk Cavab Vaxtı",
"DESC": "( Avg )", "DESC": "( Orta )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "Hesablama üçün istifadə olunan ümumi söhbət sayı:",
"TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "İlk cavab vaxtı {metricValue}-dir ({conversationCount} söhbətə əsaslanır)"
}, },
"RESOLUTION_TIME": { "RESOLUTION_TIME": {
"NAME": "Resolution Time", "NAME": "Həll Vaxtı",
"DESC": "( Avg )", "DESC": "( Orta )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "Hesablama üçün istifadə olunan ümumi söhbət sayı:",
"TOOLTIP_TEXT": "Resolution Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "Həll vaxtı {metricValue}-dir ({conversationCount} söhbətə əsaslanır)"
}, },
"RESOLUTION_COUNT": { "RESOLUTION_COUNT": {
"NAME": "Resolution Count", "NAME": "Həll Sayı",
"DESC": "( Total )" "DESC": "( Cəmi )"
} }
}, },
"DATE_RANGE": [ "DATE_RANGE": [
{ {
"id": 0, "id": 0,
"name": "Last 7 days" "name": "Son 7 gün"
}, },
{ {
"id": 1, "id": 1,
"name": "Last 30 days" "name": "Son 30 gün"
}, },
{ {
"id": 2, "id": 2,
"name": "Last 3 months" "name": "Son 3 ay"
}, },
{ {
"id": 3, "id": 3,
"name": "Last 6 months" "name": "Son 6 ay"
}, },
{ {
"id": 4, "id": 4,
"name": "Last year" "name": "Keçən il"
}, },
{ {
"id": 5, "id": 5,
"name": "Custom date range" "name": "Xüsusi tarix aralığı"
} }
], ],
"CUSTOM_DATE_RANGE": { "CUSTOM_DATE_RANGE": {
"CONFIRM": "Apply", "CONFIRM": "Tətbiq et",
"PLACEHOLDER": "Select date range" "PLACEHOLDER": "Select date range"
} }
}, },
"TEAM_REPORTS": { "TEAM_REPORTS": {
"HEADER": "Team Overview", "HEADER": "Team Overview",
"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": "Komanda nəticələrini söhbətlər, cavab müddəti, həll müddəti və həll olunmuş hallar üzrə yoxlayın. Ətraflı məlumat üçün komanda adını açın.",
"LOADING_CHART": "Loading chart data...", "LOADING_CHART": "Loading chart data...",
"NO_ENOUGH_DATA": "We've not received enough data points to generate report, Please try again later.", "NO_ENOUGH_DATA": "Hesabat yaratmaq üçün kifayət qədər məlumat nöqtəsi almamışıq, zəhmət olmasa sonra yenidən cəhd edin.",
"DOWNLOAD_TEAM_REPORTS": "Download team reports", "DOWNLOAD_TEAM_REPORTS": "Download team reports",
"FILTER_DROPDOWN_LABEL": "Select Team", "FILTER_DROPDOWN_LABEL": "Komandanı seçin",
"FILTERS": { "FILTERS": {
"ADD_FILTER": "Add filter", "ADD_FILTER": "Add filter",
"CLEAR_ALL": "Clear all", "CLEAR_ALL": "Clear all",
@@ -364,54 +364,54 @@
}, },
"METRICS": { "METRICS": {
"CONVERSATIONS": { "CONVERSATIONS": {
"NAME": "Conversations", "NAME": "Söhbətlər",
"DESC": "( Total )" "DESC": "( Ümumi )"
}, },
"INCOMING_MESSAGES": { "INCOMING_MESSAGES": {
"NAME": "Incoming Messages", "NAME": "Incoming Messages",
"DESC": "( Total )" "DESC": "( Cəmi )"
}, },
"OUTGOING_MESSAGES": { "OUTGOING_MESSAGES": {
"NAME": "Outgoing Messages", "NAME": "Outgoing Messages",
"DESC": "( Total )" "DESC": "( Cəmi )"
}, },
"FIRST_RESPONSE_TIME": { "FIRST_RESPONSE_TIME": {
"NAME": "First Response Time", "NAME": "İlk Cavab Vaxtı",
"DESC": "( Avg )", "DESC": "( Orta )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "Hesablama üçün istifadə olunan ümumi söhbət sayı:",
"TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "İlk cavab vaxtı {metricValue}-dir ({conversationCount} söhbətə əsaslanır)"
}, },
"RESOLUTION_TIME": { "RESOLUTION_TIME": {
"NAME": "Resolution Time", "NAME": "Həll Vaxtı",
"DESC": "( Avg )", "DESC": "( Orta )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "Hesablama üçün istifadə olunan ümumi söhbət sayı:",
"TOOLTIP_TEXT": "Resolution Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "Həll vaxtı {metricValue}-dir ({conversationCount} söhbətə əsaslanır)"
}, },
"RESOLUTION_COUNT": { "RESOLUTION_COUNT": {
"NAME": "Resolution Count", "NAME": "Həll Sayı",
"DESC": "( Total )" "DESC": "( Ümumi )"
} }
}, },
"DATE_RANGE": [ "DATE_RANGE": [
{ {
"id": 0, "id": 0,
"name": "Last 7 days" "name": "Son 7 gün"
}, },
{ {
"id": 1, "id": 1,
"name": "Last 30 days" "name": "Son 30 gün"
}, },
{ {
"id": 2, "id": 2,
"name": "Last 3 months" "name": "Son 3 ay"
}, },
{ {
"id": 3, "id": 3,
"name": "Last 6 months" "name": "Son 6 ay"
}, },
{ {
"id": 4, "id": 4,
"name": "Last year" "name": "Keçən il"
}, },
{ {
"id": 5, "id": 5,
@@ -419,13 +419,13 @@
} }
], ],
"CUSTOM_DATE_RANGE": { "CUSTOM_DATE_RANGE": {
"CONFIRM": "Apply", "CONFIRM": "Tətbiq et",
"PLACEHOLDER": "Select date range" "PLACEHOLDER": "Select date range"
} }
}, },
"CSAT_REPORTS": { "CSAT_REPORTS": {
"HEADER": "CSAT Reports", "HEADER": "CSAT Hesabatları",
"NO_RECORDS": "No responses yet", "NO_RECORDS": "Hələ cavab yoxdur",
"NO_RECORDS_DESCRIPTION": "CSAT survey responses will appear here once customers start providing feedback.", "NO_RECORDS_DESCRIPTION": "CSAT survey responses will appear here once customers start providing feedback.",
"DOWNLOAD": "Download CSAT Reports", "DOWNLOAD": "Download CSAT Reports",
"DOWNLOAD_FAILED": "Failed to download CSAT Reports", "DOWNLOAD_FAILED": "Failed to download CSAT Reports",
@@ -435,7 +435,7 @@
"NO_FILTER": "No filters available", "NO_FILTER": "No filters available",
"INPUT_PLACEHOLDER": { "INPUT_PLACEHOLDER": {
"AGENTS": "Search agents", "AGENTS": "Search agents",
"INBOXES": "Search inboxes", "INBOXES": "Qutuları axtar",
"TEAMS": "Search teams", "TEAMS": "Search teams",
"RATINGS": "Search ratings" "RATINGS": "Search ratings"
}, },
@@ -443,53 +443,53 @@
"LABEL": "Agent" "LABEL": "Agent"
}, },
"INBOXES": { "INBOXES": {
"LABEL": "Inbox" "LABEL": "Gələn qutu"
}, },
"TEAMS": { "TEAMS": {
"LABEL": "Team" "LABEL": "Komanda"
}, },
"RATINGS": { "RATINGS": {
"LABEL": "Rating" "LABEL": "Qiymətləndirmə"
} }
}, },
"TABLE": { "TABLE": {
"HEADER": { "HEADER": {
"CONTACT_NAME": "Contact", "CONTACT_NAME": "Əlaqə",
"AGENT_NAME": "Agent", "AGENT_NAME": "Agent",
"RATING": "Rating", "RATING": "Qiymətləndirmə",
"FEEDBACK_TEXT": "Feedback comment", "FEEDBACK_TEXT": "Feedback comment",
"CONVERSATION": "Conversation", "CONVERSATION": "Söhbət",
"CUSTOMER": "Customer", "CUSTOMER": "Müştəri",
"RESPONSE": "Response", "RESPONSE": "Cavab",
"HANDLED_BY": "Handled by" "HANDLED_BY": "Tərəfindən idarə olunur"
}, },
"UNKNOWN_CUSTOMER": "Unknown customer" "UNKNOWN_CUSTOMER": "Naməlum müştəri"
}, },
"NO_AGENT": "No assigned agent", "NO_AGENT": "Təyin olunmuş agent yoxdur",
"NO_FEEDBACK": "No feedback provided", "NO_FEEDBACK": "Rəy verilməyib",
"METRIC": { "METRIC": {
"TOTAL_RESPONSES": { "TOTAL_RESPONSES": {
"LABEL": "Total responses", "LABEL": "Cəmi cavablar",
"TOOLTIP": "Total number of responses collected" "TOOLTIP": "Toplanmış cavabların ümumi sayı"
}, },
"SATISFACTION_SCORE": { "SATISFACTION_SCORE": {
"LABEL": "Satisfaction score", "LABEL": "Məmnunluq balı",
"TOOLTIP": "Total number of positive responses / Total number of responses * 100" "TOOLTIP": "Müsbət cavabların ümumi sayı / Cavabların ümumi sayı * 100"
}, },
"RESPONSE_RATE": { "RESPONSE_RATE": {
"LABEL": "Response rate", "LABEL": "Cavab faizi",
"TOOLTIP": "Total number of responses / Total number of CSAT survey messages sent * 100" "TOOLTIP": "Total number of responses / Total number of CSAT survey messages sent * 100"
}, },
"RATING_DISTRIBUTION": "Rating distribution" "RATING_DISTRIBUTION": "Qiymətləndirmə paylanması"
}, },
"REVIEW_NOTES": { "REVIEW_NOTES": {
"TITLE": "Review notes", "TITLE": "Rəy qeydləri",
"PLACEHOLDER": "Add review notes about this rating...", "PLACEHOLDER": "Bu qiymətləndirmə haqqında rəy qeydləri əlavə edin...",
"SAVE": "Save", "SAVE": "Yadda saxla",
"CANCEL": "Cancel", "CANCEL": "Ləğv et",
"SAVING": "Saving...", "SAVING": "Yadda saxlanılır...",
"SAVED": "Notes saved successfully", "SAVED": "Notes saved successfully",
"SAVE_ERROR": "Failed to save notes", "SAVE_ERROR": "Qeydləri yadda saxlamaq mümkün olmadı",
"UPDATED_BY": "Updated by {name} {time}", "UPDATED_BY": "Updated by {name} {time}",
"UPDATED_BY_LABEL": "Updated by", "UPDATED_BY_LABEL": "Updated by",
"PAYWALL": { "PAYWALL": {
@@ -509,42 +509,42 @@
"TOOLTIP": "Total number of conversations handled by the bot" "TOOLTIP": "Total number of conversations handled by the bot"
}, },
"TOTAL_RESPONSES": { "TOTAL_RESPONSES": {
"LABEL": "Total Responses", "LABEL": "Ümumi Cavablar",
"TOOLTIP": "Total number of responses sent by the bot" "TOOLTIP": "Total number of responses sent by the bot"
}, },
"RESOLUTION_RATE": { "RESOLUTION_RATE": {
"LABEL": "Resolution Rate", "LABEL": "Həll Faizi",
"TOOLTIP": "Total number of conversations resolved by the bot / Total number of conversations handled by the bot * 100" "TOOLTIP": "Total number of conversations resolved by the bot / Total number of conversations handled by the bot * 100"
}, },
"HANDOFF_RATE": { "HANDOFF_RATE": {
"LABEL": "Handoff Rate", "LABEL": "Təyinat Faizi",
"TOOLTIP": "Total number of conversations handed off to agents / Total number of conversations handled by the bot * 100" "TOOLTIP": "Total number of conversations handed off to agents / Total number of conversations handled by the bot * 100"
} }
} }
}, },
"OVERVIEW_REPORTS": { "OVERVIEW_REPORTS": {
"HEADER": "Overview", "HEADER": "Ümumi Baxış",
"LIVE": "Live", "LIVE": "Canlı",
"ACCOUNT_CONVERSATIONS": { "ACCOUNT_CONVERSATIONS": {
"HEADER": "Open Conversations", "HEADER": "Açıq Söhbətlər",
"LOADING_MESSAGE": "Loading conversation metrics...", "LOADING_MESSAGE": "Loading conversation metrics...",
"OPEN": "Open", "OPEN": "Açıq",
"UNATTENDED": "Unattended", "UNATTENDED": "Unattended",
"UNASSIGNED": "Unassigned", "UNASSIGNED": "Təyin olunmamış",
"PENDING": "Pending" "PENDING": "Gözləyir"
}, },
"CONVERSATION_HEATMAP": { "CONVERSATION_HEATMAP": {
"HEADER": "Conversation Traffic", "HEADER": "Conversation Traffic",
"NO_CONVERSATIONS": "No conversations", "NO_CONVERSATIONS": "Söhbət yoxdur",
"CONVERSATION": "{count} conversation", "CONVERSATION": "{count} söhbət",
"CONVERSATIONS": "{count} conversations", "CONVERSATIONS": "{count} söhbət",
"DOWNLOAD_REPORT": "Download report" "DOWNLOAD_REPORT": "Download report"
}, },
"RESOLUTION_HEATMAP": { "RESOLUTION_HEATMAP": {
"HEADER": "Resolutions", "HEADER": "Resolutions",
"NO_CONVERSATIONS": "No conversations", "NO_CONVERSATIONS": "Söhbət yoxdur",
"CONVERSATION": "{count} conversation", "CONVERSATION": "{count} söhbət",
"CONVERSATIONS": "{count} conversations", "CONVERSATIONS": "{count} söhbət",
"DOWNLOAD_REPORT": "Download report" "DOWNLOAD_REPORT": "Download report"
}, },
"AGENT_CONVERSATIONS": { "AGENT_CONVERSATIONS": {
@@ -553,42 +553,42 @@
"NO_AGENTS": "There are no conversations by agents", "NO_AGENTS": "There are no conversations by agents",
"TABLE_HEADER": { "TABLE_HEADER": {
"AGENT": "Agent", "AGENT": "Agent",
"OPEN": "Open", "OPEN": "Açıq",
"UNATTENDED": "Unattended", "UNATTENDED": "Unattended",
"STATUS": "Status" "STATUS": "Vəziyyət"
} }
}, },
"TEAM_CONVERSATIONS": { "TEAM_CONVERSATIONS": {
"ALL_TEAMS": "All Teams", "ALL_TEAMS": "All Teams",
"HEADER": "Conversations by teams", "HEADER": "Conversations by teams",
"LOADING_MESSAGE": "Loading team metrics...", "LOADING_MESSAGE": "Loading team metrics...",
"NO_TEAMS": "There is no data available", "NO_TEAMS": "Məlumat mövcud deyil",
"TABLE_HEADER": { "TABLE_HEADER": {
"TEAM": "Team", "TEAM": "Komanda",
"OPEN": "Open", "OPEN": "Açıq",
"UNATTENDED": "Unattended", "UNATTENDED": "Unattended",
"STATUS": "Status" "STATUS": "Vəziyyət"
} }
}, },
"AGENT_STATUS": { "AGENT_STATUS": {
"HEADER": "Agent status", "HEADER": "Agent vəziyyəti",
"ONLINE": "Online", "ONLINE": "Onlayn",
"BUSY": "Busy", "BUSY": "Məşğul",
"OFFLINE": "Offline" "OFFLINE": "Offline"
} }
}, },
"DAYS_OF_WEEK": { "DAYS_OF_WEEK": {
"SUNDAY": "Sunday", "SUNDAY": "Bazar günü",
"MONDAY": "Monday", "MONDAY": "Bazar ertəsi",
"TUESDAY": "Tuesday", "TUESDAY": "Çərşənbə axşamı",
"WEDNESDAY": "Wednesday", "WEDNESDAY": "Çərşənbə",
"THURSDAY": "Thursday", "THURSDAY": "Cümə axşamı",
"FRIDAY": "Friday", "FRIDAY": "Cümə",
"SATURDAY": "Saturday" "SATURDAY": "Şənbə"
}, },
"SLA_REPORTS": { "SLA_REPORTS": {
"HEADER": "SLA Reports", "HEADER": "SLA Hesabatları",
"NO_RECORDS": "SLA applied conversations are not available.", "NO_RECORDS": "Tətbiq edilmiş SLA söhbətləri mövcud deyil.",
"LOADING": "Loading SLA data...", "LOADING": "Loading SLA data...",
"DOWNLOAD_SLA_REPORTS": "Download SLA reports", "DOWNLOAD_SLA_REPORTS": "Download SLA reports",
"DOWNLOAD_FAILED": "Failed to download SLA Reports", "DOWNLOAD_FAILED": "Failed to download SLA Reports",
@@ -596,7 +596,7 @@
"ADD_FIlTER": "Add filter", "ADD_FIlTER": "Add filter",
"CLEAR_ALL": "Clear all", "CLEAR_ALL": "Clear all",
"CLEAR_FILTER": "Clear filter", "CLEAR_FILTER": "Clear filter",
"EMPTY_LIST": "No results found", "EMPTY_LIST": "Nəticə tapılmadı",
"NO_FILTER": "No filters available", "NO_FILTER": "No filters available",
"SEARCH": "Search filter", "SEARCH": "Search filter",
"INPUT_PLACEHOLDER": { "INPUT_PLACEHOLDER": {
@@ -606,16 +606,16 @@
"LABELS": "Label name", "LABELS": "Label name",
"TEAMS": "Team name" "TEAMS": "Team name"
}, },
"SLA": "SLA Policy", "SLA": "SLA Siyasəti",
"INBOXES": "Inbox", "INBOXES": "Gələn qutu",
"AGENTS": "Agent", "AGENTS": "Agent",
"LABELS": "Label", "LABELS": "Etiket",
"TEAMS": "Team" "TEAMS": "Komanda"
}, },
"WITH": "with", "WITH": "ilə",
"METRICS": { "METRICS": {
"HIT_RATE": { "HIT_RATE": {
"LABEL": "Hit Rate", "LABEL": "Uğur Faizi",
"TOOLTIP": "Percentage of SLAs created were completed successfully" "TOOLTIP": "Percentage of SLAs created were completed successfully"
}, },
"NO_OF_MISSES": { "NO_OF_MISSES": {
@@ -624,27 +624,27 @@
}, },
"NO_OF_CONVERSATIONS": { "NO_OF_CONVERSATIONS": {
"LABEL": "Number of Conversations", "LABEL": "Number of Conversations",
"TOOLTIP": "Total number of conversations with SLA" "TOOLTIP": "SLA ilə ümumi söhbət sayı"
} }
}, },
"TABLE": { "TABLE": {
"HEADER": { "HEADER": {
"POLICY": "Policy", "POLICY": "Siyasət",
"CONVERSATION": "Conversation", "CONVERSATION": "Söhbət",
"AGENT": "Agent" "AGENT": "Agent"
}, },
"VIEW_DETAILS": "View Details" "VIEW_DETAILS": "Ətraflı Bax"
} }
}, },
"SUMMARY_REPORTS": { "SUMMARY_REPORTS": {
"INBOX": "Inbox", "INBOX": "Gələnlər",
"AGENT": "Agent", "AGENT": "Agent",
"TEAM": "Team", "TEAM": "Komanda",
"LABEL": "Label", "LABEL": "Etiket",
"AVG_RESOLUTION_TIME": "Avg. Resolution Time", "AVG_RESOLUTION_TIME": "Orta Həll Vaxtı",
"AVG_FIRST_RESPONSE_TIME": "Avg. First Response Time", "AVG_FIRST_RESPONSE_TIME": "Orta İlk Cavab Vaxtı",
"AVG_REPLY_TIME": "Avg. Customer Waiting Time", "AVG_REPLY_TIME": "Orta Müştəri Gözləmə Vaxtı",
"RESOLUTION_COUNT": "Resolution Count", "RESOLUTION_COUNT": "Həll Sayı",
"CONVERSATIONS": "No. of conversations" "CONVERSATIONS": "No. of conversations"
} }
} }
File diff suppressed because it is too large Load Diff
@@ -710,9 +710,21 @@
"MESSENGER_SUB_HEAD": "Place this button inside your body tag", "MESSENGER_SUB_HEAD": "Place this button inside your body tag",
"ALLOWED_DOMAINS": { "ALLOWED_DOMAINS": {
"TITLE": "Allowed Domains", "TITLE": "Allowed Domains",
"SUBTITLE": "Add wildcard or regular domains separated by commas (leave blank to allow all), e.g. *.chatwoot.dev, chatwoot.com.", "DESCRIPTION": "Restrict which websites can embed your chat widget. For security, only add domains you own and trust. Add one or more domains separated by commas. Leave blank to allow all domains (not recommended for production).",
"PLACEHOLDER": "example.com, www.example.com, app.example.com" "PLACEHOLDER": "example.com, www.example.com, app.example.com"
}, },
"ALLOW_MOBILE_WEBVIEW": {
"LABEL": "Enable widget in mobile apps",
"SUBTITLE": "Check this if you embed the widget in iOS or Android apps. Mobile apps don't send domain information, so they would be blocked by domain restrictions unless this is enabled."
},
"IDENTITY_VALIDATION": {
"TITLE": "Identity Validation",
"DESCRIPTION": "Verify user authenticity by generating secure tokens. This prevents unauthorized users from impersonating others in your chat.",
"SECRET_KEY": "Secret Key",
"VIEW_DOCS": "View documentation",
"REQUIRE_LABEL": "Require identity validation for all conversations",
"REQUIRE_DESCRIPTION": "When enabled, users must provide a valid identity token to start conversations. Requests without valid tokens will be rejected."
},
"INBOX_AGENTS": "Агенти", "INBOX_AGENTS": "Агенти",
"INBOX_AGENTS_SUB_TEXT": "Add or remove agents from this inbox", "INBOX_AGENTS_SUB_TEXT": "Add or remove agents from this inbox",
"AGENT_ASSIGNMENT": "Conversation Assignment", "AGENT_ASSIGNMENT": "Conversation Assignment",
@@ -527,7 +527,8 @@
"TITLE": "Features", "TITLE": "Features",
"ALLOW_CONVERSATION_FAQS": "Generate FAQs from resolved conversations", "ALLOW_CONVERSATION_FAQS": "Generate FAQs from resolved conversations",
"ALLOW_MEMORIES": "Capture key details as memories from customer interactions.", "ALLOW_MEMORIES": "Capture key details as memories from customer interactions.",
"ALLOW_CITATIONS": "Include source citations in responses" "ALLOW_CITATIONS": "Include source citations in responses",
"ALLOW_CONTACT_ATTRIBUTES": "Allow access to contact information"
} }
}, },
"EDIT": { "EDIT": {
@@ -1,125 +1,125 @@
{ {
"AGENT_MGMT": { "AGENT_MGMT": {
"HEADER": "Agents", "HEADER": "এজেন্ট",
"HEADER_BTN_TXT": "Add Agent", "HEADER_BTN_TXT": "এজেন্ট যোগ করুন",
"LOADING": "Fetching Agent List", "LOADING": "এজেন্ট তালিকা আনছে",
"DESCRIPTION": "An agent is a member of your customer support team who can view and respond to user messages. The list below shows all the agents in your account.", "DESCRIPTION": "একজন এজেন্ট হলেন আপনার গ্রাহক সাপোর্ট দলের সদস্য যিনি ব্যবহারকারীর বার্তা দেখতে এবং উত্তর দিতে পারেন। নিচের তালিকায় আপনার অ্যাকাউন্টের সব এজেন্ট দেখানো হয়েছে।",
"LEARN_MORE": "Learn about user roles", "LEARN_MORE": "ব্যবহারকারীর ভূমিকা সম্পর্কে জানুন",
"AGENT_TYPES": { "AGENT_TYPES": {
"ADMINISTRATOR": "Administrator", "ADMINISTRATOR": "প্রশাসক",
"AGENT": "Agent" "AGENT": "এজেন্ট"
}, },
"COUNT": "{n} agent | {n} agents", "COUNT": "{n} এজেন্ট | {n} এজেন্ট",
"LIST": { "LIST": {
"404": "There are no agents associated to this account", "404": "এই অ্যাকাউন্টে কোনো এজেন্ট নেই",
"TITLE": "Manage agents in your team", "TITLE": "আপনার দলের এজেন্ট পরিচালনা করুন",
"DESC": "You can add/remove agents to/in your team.", "DESC": "আপনি আপনার দলে এজেন্ট যোগ/অপসারণ করতে পারেন।",
"NAME": "Name", "NAME": "নাম",
"EMAIL": "EMAIL", "EMAIL": "ইমেইল",
"STATUS": "Status", "STATUS": "অবস্থা",
"ACTIONS": "Actions", "ACTIONS": "কর্ম",
"VERIFIED": "Verified", "VERIFIED": "যাচাই করা হয়েছে",
"VERIFICATION_PENDING": "Verification Pending", "VERIFICATION_PENDING": "যাচাই প্রক্রিয়াধীন",
"AVAILABLE_CUSTOM_ROLE": "Available custom role permissions" "AVAILABLE_CUSTOM_ROLE": "উপলব্ধ কাস্টম ভূমিকার অনুমতিসমূহ"
}, },
"ADD": { "ADD": {
"TITLE": "Add agent to your team", "TITLE": "আপনার দলে এজেন্ট যোগ করুন",
"DESC": "You can add people who will be able to handle support for your inboxes.", "DESC": "আপনি এমন ব্যক্তিদের যোগ করতে পারেন যারা আপনার ইনবক্সের জন্য সাপোর্ট পরিচালনা করতে পারবেন।",
"CANCEL_BUTTON_TEXT": "Cancel", "CANCEL_BUTTON_TEXT": "বাতিল করুন",
"FORM": { "FORM": {
"NAME": { "NAME": {
"LABEL": "Agent Name", "LABEL": "এজেন্টের নাম",
"PLACEHOLDER": "Please enter a name of the agent" "PLACEHOLDER": "এজেন্টের নাম লিখুন"
}, },
"AGENT_TYPE": { "AGENT_TYPE": {
"LABEL": "Role", "LABEL": "ভূমিকা",
"PLACEHOLDER": "Please select a role", "PLACEHOLDER": "একটি ভূমিকা নির্বাচন করুন",
"ERROR": "Role is required" "ERROR": "ভূমিকা আবশ্যক"
}, },
"EMAIL": { "EMAIL": {
"LABEL": "Email Address", "LABEL": "ইমেইল ঠিকানা",
"PLACEHOLDER": "Please enter an email address of the agent" "PLACEHOLDER": "এজেন্টের ইমেইল ঠিকানা লিখুন"
}, },
"SUBMIT": "Add Agent" "SUBMIT": "এজেন্ট যোগ করুন"
}, },
"API": { "API": {
"SUCCESS_MESSAGE": "Agent added successfully", "SUCCESS_MESSAGE": "এজেন্ট সফলভাবে যোগ করা হয়েছে",
"EXIST_MESSAGE": "Agent email already in use, Please try another email address", "EXIST_MESSAGE": "এজেন্টের ইমেইল ইতিমধ্যে ব্যবহৃত, অনুগ্রহ করে অন্য ইমেইল ঠিকানা ব্যবহার করুন",
"ERROR_MESSAGE": "Could not connect to Woot Server, Please try again later" "ERROR_MESSAGE": "Woot Server-এ সংযোগ করা যায়নি, অনুগ্রহ করে পরে আবার চেষ্টা করুন"
} }
}, },
"DELETE": { "DELETE": {
"BUTTON_TEXT": "Delete", "BUTTON_TEXT": "মুছে ফেলুন",
"API": { "API": {
"SUCCESS_MESSAGE": "Agent deleted successfully", "SUCCESS_MESSAGE": "এজেন্ট সফলভাবে মুছে ফেলা হয়েছে",
"ERROR_MESSAGE": "Could not connect to Woot Server, Please try again later" "ERROR_MESSAGE": "Woot Server-এ সংযোগ করা যায়নি, অনুগ্রহ করে পরে আবার চেষ্টা করুন"
}, },
"CONFIRM": { "CONFIRM": {
"TITLE": "Confirm Deletion", "TITLE": "মুছে ফেলা নিশ্চিত করুন",
"MESSAGE": "Are you sure to delete ", "MESSAGE": "আপনি কি নিশ্চিত যে মুছে ফেলতে চান ",
"YES": "Yes, Delete ", "YES": "হ্যাঁ, মুছে ফেলুন ",
"NO": "No, Keep " "NO": "না, রাখুন "
} }
}, },
"EDIT": { "EDIT": {
"TITLE": "Edit agent", "TITLE": "এজেন্ট সম্পাদনা করুন",
"FORM": { "FORM": {
"NAME": { "NAME": {
"LABEL": "Agent Name", "LABEL": "এজেন্টের নাম",
"PLACEHOLDER": "Please enter a name of the agent" "PLACEHOLDER": "এজেন্টের নাম লিখুন"
}, },
"AGENT_TYPE": { "AGENT_TYPE": {
"LABEL": "Role", "LABEL": "ভূমিকা",
"PLACEHOLDER": "Please select a role", "PLACEHOLDER": "একটি ভূমিকা নির্বাচন করুন",
"ERROR": "Role is required" "ERROR": "ভূমিকা আবশ্যক"
}, },
"EMAIL": { "EMAIL": {
"LABEL": "Email Address", "LABEL": "ইমেইল ঠিকানা",
"PLACEHOLDER": "Please enter an email address of the agent" "PLACEHOLDER": "এজেন্টের ইমেইল ঠিকানা লিখুন"
}, },
"AGENT_AVAILABILITY": { "AGENT_AVAILABILITY": {
"LABEL": "Availability", "LABEL": "উপলব্ধতা",
"PLACEHOLDER": "Please select an availability status", "PLACEHOLDER": "একটি উপলব্ধতা অবস্থা নির্বাচন করুন",
"ERROR": "Availability is required" "ERROR": "উপলব্ধতা আবশ্যক"
}, },
"SUBMIT": "Edit Agent" "SUBMIT": "এজেন্ট সম্পাদনা করুন"
}, },
"BUTTON_TEXT": "Edit", "BUTTON_TEXT": "সম্পাদনা করুন",
"CANCEL_BUTTON_TEXT": "Cancel", "CANCEL_BUTTON_TEXT": "বাতিল করুন",
"API": { "API": {
"SUCCESS_MESSAGE": "Agent updated successfully", "SUCCESS_MESSAGE": "এজেন্ট সফলভাবে আপডেট হয়েছে",
"ERROR_MESSAGE": "Could not connect to Woot Server, Please try again later" "ERROR_MESSAGE": "Woot Server-এ সংযোগ করা যায়নি, অনুগ্রহ করে পরে আবার চেষ্টা করুন"
}, },
"PASSWORD_RESET": { "PASSWORD_RESET": {
"ADMIN_RESET_BUTTON": "Reset Password", "ADMIN_RESET_BUTTON": "পাসওয়ার্ড রিসেট করুন",
"ADMIN_SUCCESS_MESSAGE": "An email with reset password instructions has been sent to the agent", "ADMIN_SUCCESS_MESSAGE": "পাসওয়ার্ড রিসেট নির্দেশনা সহ একটি ইমেইল এজেন্টকে পাঠানো হয়েছে",
"SUCCESS_MESSAGE": "Agent password reset successfully", "SUCCESS_MESSAGE": "এজেন্টের পাসওয়ার্ড সফলভাবে রিসেট হয়েছে",
"ERROR_MESSAGE": "Could not connect to Woot Server, Please try again later" "ERROR_MESSAGE": "Woot Server-এ সংযোগ করা যায়নি, অনুগ্রহ করে পরে আবার চেষ্টা করুন"
} }
}, },
"SEARCH_PLACEHOLDER": "Search agents...", "SEARCH_PLACEHOLDER": "এজেন্ট অনুসন্ধান করুন...",
"NO_RESULTS": "No agents found matching your search", "NO_RESULTS": "আপনার অনুসন্ধানের সাথে মিলিত কোনো এজেন্ট পাওয়া যায়নি",
"SEARCH": { "SEARCH": {
"NO_RESULTS": "No results found." "NO_RESULTS": "কোনো ফলাফল পাওয়া যায়নি।"
}, },
"MULTI_SELECTOR": { "MULTI_SELECTOR": {
"PLACEHOLDER": "None", "PLACEHOLDER": "কিছুই নয়",
"TITLE": { "TITLE": {
"AGENT": "Select agent", "AGENT": "এজেন্ট নির্বাচন করুন",
"TEAM": "Select team" "TEAM": "দল নির্বাচন করুন"
}, },
"LIST": { "LIST": {
"NONE": "None" "NONE": "কিছুই নয়"
}, },
"SEARCH": { "SEARCH": {
"NO_RESULTS": { "NO_RESULTS": {
"AGENT": "No agents found", "AGENT": "কোনো এজেন্ট পাওয়া যায়নি",
"TEAM": "No teams found" "TEAM": "কোনো দল পাওয়া যায়নি"
}, },
"PLACEHOLDER": { "PLACEHOLDER": {
"AGENT": "Search agents", "AGENT": "এজেন্ট অনুসন্ধান করুন",
"TEAM": "Search teams", "TEAM": "দল অনুসন্ধান করুন",
"INPUT": "Search for agents" "INPUT": "এজেন্টদের জন্য অনুসন্ধান করুন"
} }
} }
} }
@@ -1,22 +1,22 @@
{ {
"CONTACT_PANEL": { "CONTACT_PANEL": {
"NOT_AVAILABLE": "Not Available", "NOT_AVAILABLE": "উপলব্ধ নেই",
"EMAIL_ADDRESS": "Email Address", "EMAIL_ADDRESS": "ইমেইল ঠিকানা",
"PHONE_NUMBER": "Phone number", "PHONE_NUMBER": "ফোন নম্বর",
"IDENTIFIER": "Identifier", "IDENTIFIER": "পরিচিতি নম্বর",
"COPY_SUCCESSFUL": "Copied to clipboard successfully", "COPY_SUCCESSFUL": "ক্লিপবোর্ডে সফলভাবে কপি হয়েছে",
"COMPANY": "Company", "COMPANY": "কোম্পানি",
"LOCATION": "Location", "LOCATION": "অবস্থান",
"BROWSER_LANGUAGE": "Browser Language", "BROWSER_LANGUAGE": "ব্রাউজারের ভাষা",
"CONVERSATION_TITLE": "Conversation Details", "CONVERSATION_TITLE": "কথোপকথনের বিবরণ",
"VIEW_PROFILE": "View Profile", "VIEW_PROFILE": "প্রোফাইল দেখুন",
"BROWSER": "Browser", "BROWSER": "ব্রাউজার",
"OS": "Operating System", "OS": "অপারেটিং সিস্টেম",
"INITIATED_FROM": "Initiated from", "INITIATED_FROM": "শুরু করা হয়েছে",
"INITIATED_AT": "Initiated at", "INITIATED_AT": "শুরু করার সময়",
"IP_ADDRESS": "IP Address", "IP_ADDRESS": "আইপি ঠিকানা",
"CREATED_AT_LABEL": "Created", "CREATED_AT_LABEL": "তৈরি হয়েছে",
"NEW_MESSAGE": "New message", "NEW_MESSAGE": "নতুন বার্তা",
"CALL": "Call", "CALL": "Call",
"CALL_INITIATED": "Calling the contact…", "CALL_INITIATED": "Calling the contact…",
"CALL_FAILED": "Unable to start the call. Please try again.", "CALL_FAILED": "Unable to start the call. Please try again.",
@@ -24,353 +24,353 @@
"TITLE": "Choose a voice inbox" "TITLE": "Choose a voice inbox"
}, },
"CONVERSATIONS": { "CONVERSATIONS": {
"NO_RECORDS_FOUND": "There are no previous conversations associated to this contact.", "NO_RECORDS_FOUND": "এই কন্টাক্টের সাথে পূর্বের কোনো আলাপ নেই।",
"TITLE": "Previous Conversations" "TITLE": "পূর্বের আলাপ"
}, },
"LABELS": { "LABELS": {
"CONTACT": { "CONTACT": {
"TITLE": "Contact Labels", "TITLE": "যোগাযোগ লেবেল",
"ERROR": "Couldn't update labels" "ERROR": "লেবেল আপডেট করা যায়নি"
}, },
"CONVERSATION": { "CONVERSATION": {
"TITLE": "Conversation Labels", "TITLE": "কথোপকথনের লেবেল",
"ADD_BUTTON": "Add Labels" "ADD_BUTTON": "লেবেল যোগ করুন"
}, },
"LABEL_SELECT": { "LABEL_SELECT": {
"TITLE": "Add Labels", "TITLE": "লেবেল যোগ করুন",
"PLACEHOLDER": "Search labels", "PLACEHOLDER": "লেবেল অনুসন্ধান করুন",
"NO_RESULT": "No labels found", "NO_RESULT": "কোন লেবেল পাওয়া যায়নি",
"CREATE_LABEL": "Create new label" "CREATE_LABEL": "নতুন লেবেল তৈরি করুন"
} }
}, },
"MERGE_CONTACT": "Merge contact", "MERGE_CONTACT": "যোগাযোগ একত্রিত করুন",
"CONTACT_ACTIONS": "Contact actions", "CONTACT_ACTIONS": "যোগাযোগের কার্যক্রম",
"MUTE_CONTACT": "Block Contact", "MUTE_CONTACT": "কন্টাক্ট ব্লক করুন",
"UNMUTE_CONTACT": "Unblock Contact", "UNMUTE_CONTACT": "কন্টাক্ট আনব্লক করুন",
"MUTED_SUCCESS": "This contact is blocked successfully. You will not be notified of any future conversations.", "MUTED_SUCCESS": "এই কন্টাক্ট সফলভাবে ব্লক করা হয়েছে। ভবিষ্যতে কোনো কথোপকথনের জন্য আপনাকে আর জানানো হবে না।",
"UNMUTED_SUCCESS": "This contact is unblocked successfully.", "UNMUTED_SUCCESS": "এই কন্টাক্টের ব্লক সফলভাবে সরানো হয়েছে.",
"SEND_TRANSCRIPT": "Send Transcript", "SEND_TRANSCRIPT": "ট্রান্সক্রিপ্ট পাঠান",
"EDIT_LABEL": "Edit", "EDIT_LABEL": "সম্পাদনা করুন",
"SIDEBAR_SECTIONS": { "SIDEBAR_SECTIONS": {
"CUSTOM_ATTRIBUTES": "Custom Attributes", "CUSTOM_ATTRIBUTES": "কাস্টম অ্যাট্রিবিউট",
"CONTACT_LABELS": "Contact Labels", "CONTACT_LABELS": "যোগাযোগের লেবেলসমূহ",
"PREVIOUS_CONVERSATIONS": "Previous Conversations", "PREVIOUS_CONVERSATIONS": "পূর্ববর্তী কথোপকথনসমূহ",
"NO_RECORDS_FOUND": "No attributes found" "NO_RECORDS_FOUND": "কোনো অ্যাট্রিবিউট পাওয়া যায়নি"
} }
}, },
"EDIT_CONTACT": { "EDIT_CONTACT": {
"BUTTON_LABEL": "Edit Contact", "BUTTON_LABEL": "যোগাযোগ সম্পাদনা করুন",
"TITLE": "Edit contact", "TITLE": "যোগাযোগ সম্পাদনা করুন",
"DESC": "Edit contact details" "DESC": "যোগাযোগের বিস্তারিত সম্পাদনা করুন"
}, },
"DELETE_CONTACT": { "DELETE_CONTACT": {
"BUTTON_LABEL": "Delete Contact", "BUTTON_LABEL": "যোগাযোগ মুছুন",
"TITLE": "Delete contact", "TITLE": "যোগাযোগ মুছুন",
"DESC": "Delete contact details", "DESC": "যোগাযোগের বিবরণ মুছে ফেলুন",
"CONFIRM": { "CONFIRM": {
"TITLE": "Confirm Deletion", "TITLE": "মুছে ফেলা নিশ্চিত করুন",
"MESSAGE": "Are you sure to delete ", "MESSAGE": "আপনি কি নিশ্চিত যে মুছে ফেলতে চান ",
"YES": "Yes, Delete", "YES": "হ্যাঁ, মুছে ফেলুন",
"NO": "No, Keep" "NO": "না, রাখুন"
}, },
"API": { "API": {
"SUCCESS_MESSAGE": "Contact deleted successfully", "SUCCESS_MESSAGE": "যোগাযোগ সফলভাবে মুছে ফেলা হয়েছে",
"ERROR_MESSAGE": "Could not delete contact. Please try again later." "ERROR_MESSAGE": "যোগাযোগ মুছে ফেলা যায়নি। অনুগ্রহ করে পরে আবার চেষ্টা করুন।."
} }
}, },
"CONTACT_FORM": { "CONTACT_FORM": {
"FORM": { "FORM": {
"SUBMIT": "Submit", "SUBMIT": "জমা দিন",
"CANCEL": "Cancel", "CANCEL": "বাতিল করুন",
"AVATAR": { "AVATAR": {
"LABEL": "Contact Avatar" "LABEL": "যোগাযোগের অ্যাভাটার"
}, },
"NAME": { "NAME": {
"PLACEHOLDER": "Enter the full name of the contact", "PLACEHOLDER": "যোগাযোগের পূর্ণ নাম লিখুন",
"LABEL": "Full Name" "LABEL": "পূর্ণ নাম"
}, },
"BIO": { "BIO": {
"PLACEHOLDER": "Enter the bio of the contact", "PLACEHOLDER": "যোগাযোগের জীবনী লিখুন",
"LABEL": "Bio" "LABEL": "জীবনবৃত্তান্ত"
}, },
"EMAIL_ADDRESS": { "EMAIL_ADDRESS": {
"PLACEHOLDER": "Enter the email address of the contact", "PLACEHOLDER": "যোগাযোগের ইমেইল ঠিকানা লিখুন",
"LABEL": "Email Address", "LABEL": "ইমেইল ঠিকানা",
"DUPLICATE": "This email address is in use for another contact.", "DUPLICATE": "এই ইমেল ঠিকানাটি অন্য একটি যোগাযোগের জন্য ব্যবহৃত হচ্ছে।.",
"ERROR": "Please enter a valid email address." "ERROR": "একটি বৈধ ইমেল ঠিকানা লিখুন।."
}, },
"PHONE_NUMBER": { "PHONE_NUMBER": {
"PLACEHOLDER": "Enter the phone number of the contact", "PLACEHOLDER": "যোগাযোগের ফোন নম্বর লিখুন",
"LABEL": "Phone Number", "LABEL": "ফোন নম্বর",
"HELP": "Phone number should be of E.164 format eg: +1415555555 [+][country code][area code][local phone number]. You can select the dial code from the dropdown.", "HELP": "ফোন নম্বরটি অবশ্যই E.164 ফরম্যাটে হতে হবে যেমন: +1415555555 [+][দেশের কোড][এরিয়া কোড][স্থানীয় ফোন নম্বর]. আপনি ড্রপডাউন থেকে ডায়াল কোড নির্বাচন করতে পারেন.",
"ERROR": "Phone number should be either empty or of E.164 format", "ERROR": "ফোন নম্বরটি খালি অথবা E.164 ফরম্যাটে হতে হবে",
"DIAL_CODE_ERROR": "Please select a dial code from the list", "DIAL_CODE_ERROR": "অনুগ্রহ করে তালিকা থেকে একটি ডায়াল কোড নির্বাচন করুন",
"DUPLICATE": "This phone number is in use for another contact." "DUPLICATE": "এই ফোন নম্বরটি অন্য একটি যোগাযোগের জন্য ব্যবহৃত হচ্ছে।."
}, },
"LOCATION": { "LOCATION": {
"PLACEHOLDER": "Enter the location of the contact", "PLACEHOLDER": "যোগাযোগের অবস্থান লিখুন",
"LABEL": "Location" "LABEL": "অবস্থান"
}, },
"COMPANY_NAME": { "COMPANY_NAME": {
"PLACEHOLDER": "Enter the company name", "PLACEHOLDER": "কোম্পানির নাম লিখুন",
"LABEL": "Company Name" "LABEL": "কোম্পানির নাম"
}, },
"COUNTRY": { "COUNTRY": {
"PLACEHOLDER": "Enter the country name", "PLACEHOLDER": "দেশের নাম লিখুন",
"LABEL": "Country Name", "LABEL": "দেশের নাম",
"SELECT_PLACEHOLDER": "Select", "SELECT_PLACEHOLDER": "নির্বাচন করুন",
"REMOVE": "Remove", "REMOVE": "অপসারণ করুন",
"SELECT_COUNTRY": "Select Country" "SELECT_COUNTRY": "দেশ নির্বাচন করুন"
}, },
"CITY": { "CITY": {
"PLACEHOLDER": "Enter the city name", "PLACEHOLDER": "শহরের নাম লিখুন",
"LABEL": "City Name" "LABEL": "শহরের নাম"
}, },
"SOCIAL_PROFILES": { "SOCIAL_PROFILES": {
"FACEBOOK": { "FACEBOOK": {
"PLACEHOLDER": "Enter the Facebook username", "PLACEHOLDER": "Facebook ব্যবহারকারীর নাম লিখুন",
"LABEL": "Facebook" "LABEL": "Facebook"
}, },
"TWITTER": { "TWITTER": {
"PLACEHOLDER": "Enter the Twitter username", "PLACEHOLDER": "Twitter ব্যবহারকারীর নাম লিখুন",
"LABEL": "Twitter" "LABEL": "Twitter"
}, },
"LINKEDIN": { "LINKEDIN": {
"PLACEHOLDER": "Enter the LinkedIn username", "PLACEHOLDER": "LinkedIn ব্যবহারকারীর নাম লিখুন",
"LABEL": "LinkedIn" "LABEL": "LinkedIn"
}, },
"GITHUB": { "GITHUB": {
"PLACEHOLDER": "Enter the Github username", "PLACEHOLDER": "Github ব্যবহারকারীর নাম লিখুন",
"LABEL": "Github" "LABEL": "Github"
} }
} }
}, },
"DELETE_AVATAR": { "DELETE_AVATAR": {
"API": { "API": {
"SUCCESS_MESSAGE": "Contact avatar deleted successfully", "SUCCESS_MESSAGE": "যোগাযোগের অবতার সফলভাবে মুছে ফেলা হয়েছে",
"ERROR_MESSAGE": "Could not delete the contact avatar. Please try again later." "ERROR_MESSAGE": "যোগাযোগের অবতার মুছে ফেলা যায়নি। অনুগ্রহ করে পরে আবার চেষ্টা করুন।."
} }
}, },
"SUCCESS_MESSAGE": "Contact saved successfully", "SUCCESS_MESSAGE": "যোগাযোগ সফলভাবে সংরক্ষণ করা হয়েছে",
"ERROR_MESSAGE": "There was an error, please try again" "ERROR_MESSAGE": "একটি ত্রুটি হয়েছে, অনুগ্রহ করে আবার চেষ্টা করুন"
}, },
"NEW_CONVERSATION": { "NEW_CONVERSATION": {
"BUTTON_LABEL": "Start conversation", "BUTTON_LABEL": "আলাপ শুরু করুন",
"TITLE": "New conversation", "TITLE": "নতুন আলাপ",
"DESC": "Start a new conversation by sending a new message.", "DESC": "নতুন বার্তা পাঠিয়ে একটি নতুন কথোপকথন শুরু করুন।",
"NO_INBOX": "Couldn't find an inbox to initiate a new conversation with this contact.", "NO_INBOX": "এই যোগাযোগের সাথে একটি নতুন কথোপকথন শুরু করার জন্য কোনো ইনবক্স পাওয়া যায়নি।",
"FORM": { "FORM": {
"TO": { "TO": {
"LABEL": "To" "LABEL": "প্রাপক"
}, },
"INBOX": { "INBOX": {
"LABEL": "Via Inbox", "LABEL": "ইনবক্সের মাধ্যমে",
"PLACEHOLDER": "Choose source inbox", "PLACEHOLDER": "উৎস ইনবক্স নির্বাচন করুন",
"ERROR": "Select an inbox" "ERROR": "একটি ইনবক্স নির্বাচন করুন"
}, },
"SUBJECT": { "SUBJECT": {
"LABEL": "Subject", "LABEL": "বিষয়",
"PLACEHOLDER": "Subject", "PLACEHOLDER": "বিষয়",
"ERROR": "Subject can't be empty" "ERROR": "বিষয় খালি রাখা যাবে না"
}, },
"MESSAGE": { "MESSAGE": {
"LABEL": "Message", "LABEL": "বার্তা",
"PLACEHOLDER": "Write your message here", "PLACEHOLDER": "এখানে আপনার বার্তা লিখুন",
"ERROR": "Message can't be empty" "ERROR": "বার্তাটি খালি রাখা যাবে না"
}, },
"ATTACHMENTS": { "ATTACHMENTS": {
"SELECT": "Choose files", "SELECT": "ফাইল নির্বাচন করুন",
"HELP_TEXT": "Drag and drop files here or choose files to attach" "HELP_TEXT": "এখানে ফাইল টেনে আনুন অথবা সংযুক্ত করার জন্য ফাইল নির্বাচন করুন"
}, },
"SUBMIT": "Send message", "SUBMIT": "বার্তা পাঠান",
"CANCEL": "Cancel", "CANCEL": "বাতিল করুন",
"SUCCESS_MESSAGE": "Message sent!", "SUCCESS_MESSAGE": "বার্তা পাঠানো হয়েছে!",
"GO_TO_CONVERSATION": "View", "GO_TO_CONVERSATION": "দেখুন",
"ERROR_MESSAGE": "Couldn't send! try again" "ERROR_MESSAGE": "পাঠানো যায়নি! আবার চেষ্টা করুন"
} }
}, },
"CONTACTS_PAGE": { "CONTACTS_PAGE": {
"LIST": { "LIST": {
"TABLE_HEADER": { "TABLE_HEADER": {
"SOCIAL_PROFILES": "Social Profiles" "SOCIAL_PROFILES": "সামাজিক প্রোফাইল"
} }
} }
}, },
"CUSTOM_ATTRIBUTES": { "CUSTOM_ATTRIBUTES": {
"BUTTON": "Add custom attribute", "BUTTON": "কাস্টম অ্যাট্রিবিউট যোগ করুন",
"COPY_SUCCESSFUL": "Copied to clipboard successfully", "COPY_SUCCESSFUL": "ক্লিপবোর্ডে সফলভাবে কপি হয়েছে",
"SHOW_MORE": "Show all attributes", "SHOW_MORE": "সব অ্যাট্রিবিউট দেখান",
"SHOW_LESS": "Show less attributes", "SHOW_LESS": "কম অ্যাট্রিবিউট দেখান",
"ACTIONS": { "ACTIONS": {
"COPY": "Copy attribute", "COPY": "অ্যাট্রিবিউট কপি করুন",
"DELETE": "Delete attribute", "DELETE": "অ্যাট্রিবিউট মুছুন",
"EDIT": "Edit attribute" "EDIT": "অ্যাট্রিবিউট সম্পাদনা করুন"
}, },
"ADD": { "ADD": {
"TITLE": "Create custom attribute", "TITLE": "কাস্টম অ্যাট্রিবিউট তৈরি করুন",
"DESC": "Add custom information to this contact." "DESC": "এই যোগাযোগে কাস্টম তথ্য যোগ করুন।."
}, },
"FORM": { "FORM": {
"CREATE": "Add attribute", "CREATE": "অ্যাট্রিবিউট যোগ করুন",
"CANCEL": "Cancel", "CANCEL": "বাতিল করুন",
"NAME": { "NAME": {
"LABEL": "Custom attribute name", "LABEL": "কাস্টম অ্যাট্রিবিউটের নাম",
"PLACEHOLDER": "Eg: shopify id", "PLACEHOLDER": "উদাহরণ: shopify id",
"ERROR": "Invalid custom attribute name" "ERROR": "অবৈধ কাস্টম অ্যাট্রিবিউট নাম"
}, },
"VALUE": { "VALUE": {
"LABEL": "Attribute value", "LABEL": "অ্যাট্রিবিউটের মান",
"PLACEHOLDER": "Eg: 11901 " "PLACEHOLDER": "উদাহরণ: 11901 "
}, },
"ADD": { "ADD": {
"TITLE": "Create new attribute ", "TITLE": "নতুন অ্যাট্রিবিউট তৈরি করুন ",
"SUCCESS": "Attribute added successfully", "SUCCESS": "অ্যাট্রিবিউট সফলভাবে যোগ করা হয়েছে",
"ERROR": "Unable to add attribute. Please try again later" "ERROR": "অ্যাট্রিবিউট যোগ করা সম্ভব হয়নি। অনুগ্রহ করে পরে আবার চেষ্টা করুন"
}, },
"UPDATE": { "UPDATE": {
"SUCCESS": "Attribute updated successfully", "SUCCESS": "অ্যাট্রিবিউট সফলভাবে আপডেট হয়েছে",
"ERROR": "Unable to update attribute. Please try again later" "ERROR": "অ্যাট্রিবিউট আপডেট করা সম্ভব হয়নি। অনুগ্রহ করে পরে আবার চেষ্টা করুন"
}, },
"DELETE": { "DELETE": {
"SUCCESS": "Attribute deleted successfully", "SUCCESS": "অ্যাট্রিবিউট সফলভাবে মুছে ফেলা হয়েছে",
"ERROR": "Unable to delete attribute. Please try again later" "ERROR": "অ্যাট্রিবিউট মুছে ফেলা যায়নি। অনুগ্রহ করে পরে আবার চেষ্টা করুন"
}, },
"ATTRIBUTE_SELECT": { "ATTRIBUTE_SELECT": {
"TITLE": "Add attributes", "TITLE": "অ্যাট্রিবিউট যোগ করুন",
"PLACEHOLDER": "Search attributes", "PLACEHOLDER": "অ্যাট্রিবিউট অনুসন্ধান করুন",
"NO_RESULT": "No attributes found" "NO_RESULT": "কোনো অ্যাট্রিবিউট পাওয়া যায়নি"
}, },
"ATTRIBUTE_TYPE": { "ATTRIBUTE_TYPE": {
"LIST": { "LIST": {
"PLACEHOLDER": "Select value", "PLACEHOLDER": "মান নির্বাচন করুন",
"SEARCH_INPUT_PLACEHOLDER": "Search value", "SEARCH_INPUT_PLACEHOLDER": "মান অনুসন্ধান করুন",
"NO_RESULT": "No result found" "NO_RESULT": "কোন ফলাফল পাওয়া যায়নি"
} }
} }
}, },
"VALIDATIONS": { "VALIDATIONS": {
"REQUIRED": "Valid value is required", "REQUIRED": "বৈধ মান আবশ্যক",
"INVALID_URL": "Invalid URL", "INVALID_URL": "অবৈধ URL",
"INVALID_INPUT": "Invalid Input" "INVALID_INPUT": "অবৈধ ইনপুট"
} }
}, },
"MERGE_CONTACTS": { "MERGE_CONTACTS": {
"TITLE": "Merge contacts", "TITLE": "যোগাযোগ একত্রিত করুন",
"DESCRIPTION": "Merge contacts to combine two profiles into one, including all attributes and conversations. In case of conflict, the Primary contacts attributes will take precedence.", "DESCRIPTION": "দুটি প্রোফাইল একত্রিত করতে কন্টাক্ট মার্জ করুন, এতে সব অ্যাট্রিবিউট ও কথোপকথন একত্রিত হবে। কোনো দ্বন্দ্ব হলে, প্রাইমারি কন্টাক্টের অ্যাট্রিবিউট অগ্রাধিকার পাবে।.",
"PRIMARY": { "PRIMARY": {
"TITLE": "Primary contact", "TITLE": "প্রাথমিক যোগাযোগ",
"HELP_LABEL": "To be deleted" "HELP_LABEL": "মুছে ফেলা হবে"
}, },
"PARENT": { "PARENT": {
"TITLE": "Contact to merge", "TITLE": "যে কন্টাক্ট মার্জ করা হবে",
"PLACEHOLDER": "Search for a contact", "PLACEHOLDER": "একটি যোগাযোগ খুঁজুন",
"HELP_LABEL": "To be kept" "HELP_LABEL": "রাখা হবে"
}, },
"SUMMARY": { "SUMMARY": {
"TITLE": "Summary", "TITLE": "সারাংশ",
"DELETE_WARNING": "Contact of <strong>{primaryContactName}</strong> will be deleted.", "DELETE_WARNING": "<strong>{primaryContactName}</strong> এর কন্টাক্ট মুছে ফেলা হবে.",
"ATTRIBUTE_WARNING": "Contact details of <strong>{primaryContactName}</strong> will be copied to <strong>{parentContactName}</strong>." "ATTRIBUTE_WARNING": "<strong>{primaryContactName}</strong> এর কন্টাক্টের বিস্তারিত <strong>{parentContactName}</strong> এ কপি করা হবে."
}, },
"SEARCH": { "SEARCH": {
"ERROR_MESSAGE": "Something went wrong. Please try again later." "ERROR_MESSAGE": "Something went wrong. Please try again later."
}, },
"FORM": { "FORM": {
"SUBMIT": " Merge contacts", "SUBMIT": " যোগাযোগসমূহ একত্রিত করুন",
"CANCEL": "Cancel", "CANCEL": "বাতিল করুন",
"CHILD_CONTACT": { "CHILD_CONTACT": {
"ERROR": "Select a child contact to merge" "ERROR": "একত্রিত করার জন্য একটি চাইল্ড কন্টাক্ট নির্বাচন করুন"
}, },
"SUCCESS_MESSAGE": "Contact merged successfully", "SUCCESS_MESSAGE": "যোগাযোগ সফলভাবে একত্রিত হয়েছে",
"ERROR_MESSAGE": "Could not merge contacts, try again!" "ERROR_MESSAGE": "যোগাযোগগুলো একত্রিত করা যায়নি, আবার চেষ্টা করুন!"
}, },
"DROPDOWN_ITEM": { "DROPDOWN_ITEM": {
"ID": "(ID: {identifier})" "ID": "(আইডি: {identifier})"
} }
}, },
"CONTACTS_LAYOUT": { "CONTACTS_LAYOUT": {
"HEADER": { "HEADER": {
"TITLE": "Contacts", "TITLE": "যোগাযোগসমূহ",
"SEARCH_TITLE": "Search contacts", "SEARCH_TITLE": "যোগাযোগ অনুসন্ধান করুন",
"ACTIVE_TITLE": "Active contacts", "ACTIVE_TITLE": "Active contacts",
"SEARCH_PLACEHOLDER": "Search...", "SEARCH_PLACEHOLDER": "অনুসন্ধান করুন...",
"MESSAGE_BUTTON": "Message", "MESSAGE_BUTTON": "বার্তা পাঠান",
"SEND_MESSAGE": "Send message", "SEND_MESSAGE": "Send message",
"BLOCK_CONTACT": "Block contact", "BLOCK_CONTACT": "Block contact",
"UNBLOCK_CONTACT": "Unblock contact", "UNBLOCK_CONTACT": "Unblock contact",
"BREADCRUMB": { "BREADCRUMB": {
"CONTACTS": "Contacts" "CONTACTS": "যোগাযোগসমূহ"
}, },
"ACTIONS": { "ACTIONS": {
"CONTACT_CREATION": { "CONTACT_CREATION": {
"ADD_CONTACT": "Add contact", "ADD_CONTACT": "যোগাযোগ যুক্ত করুন",
"EXPORT_CONTACT": "Export contacts", "EXPORT_CONTACT": "যোগাযোগসমূহ রপ্তানি করুন",
"IMPORT_CONTACT": "Import contacts", "IMPORT_CONTACT": "কন্টাক্ট আমদানি করুন",
"SAVE_CONTACT": "Save contact", "SAVE_CONTACT": "যোগাযোগ সংরক্ষণ করুন",
"EMAIL_ADDRESS_DUPLICATE": "This email address is in use for another contact.", "EMAIL_ADDRESS_DUPLICATE": "এই ইমেইল ঠিকানাটি অন্য একটি যোগাযোগের জন্য ব্যবহৃত হচ্ছে।",
"PHONE_NUMBER_DUPLICATE": "This phone number is in use for another contact.", "PHONE_NUMBER_DUPLICATE": "এই ফোন নম্বরটি অন্য একটি যোগাযোগের জন্য ব্যবহৃত হচ্ছে।",
"SUCCESS_MESSAGE": "Contact saved successfully", "SUCCESS_MESSAGE": "যোগাযোগ সফলভাবে সংরক্ষণ করা হয়েছে",
"ERROR_MESSAGE": "Unable to save contact. Please try again later." "ERROR_MESSAGE": "যোগাযোগ সংরক্ষণ করা যায়নি। অনুগ্রহ করে পরে আবার চেষ্টা করুন।"
}, },
"BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully", "BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully",
"BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.", "BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.",
"UNBLOCK_SUCCESS_MESSAGE": "This contact is unblocked successfully", "UNBLOCK_SUCCESS_MESSAGE": "This contact is unblocked successfully",
"UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.", "UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.",
"IMPORT_CONTACT": { "IMPORT_CONTACT": {
"TITLE": "Import contacts", "TITLE": "কন্টাক্ট আমদানি করুন",
"DESCRIPTION": "Import contacts through a CSV file.", "DESCRIPTION": "CSV ফাইলের মাধ্যমে কন্টাক্ট আমদানি করুন.",
"DOWNLOAD_LABEL": "Download a sample csv.", "DOWNLOAD_LABEL": "একটি নমুনা CSV ডাউনলোড করুন.",
"LABEL": "CSV File:", "LABEL": "CSV ফাইল:",
"CHOOSE_FILE": "Choose file", "CHOOSE_FILE": "ফাইল নির্বাচন করুন",
"CHANGE": "Change", "CHANGE": "পরিবর্তন করুন",
"CANCEL": "Cancel", "CANCEL": "বাতিল করুন",
"IMPORT": "Import", "IMPORT": "আমদানি করুন",
"SUCCESS_MESSAGE": "You will be notified via email when the import is complete.", "SUCCESS_MESSAGE": "আমদানি সম্পন্ন হলে আপনাকে ইমেইলে জানানো হবে.",
"ERROR_MESSAGE": "There was an error, please try again" "ERROR_MESSAGE": "একটি সমস্যা হয়েছে, অনুগ্রহ করে আবার চেষ্টা করুন"
}, },
"EXPORT_CONTACT": { "EXPORT_CONTACT": {
"TITLE": "Export contacts", "TITLE": "যোগাযোগসমূহ রপ্তানি করুন",
"DESCRIPTION": "Quickly export a csv file with comprehensive details of your contacts", "DESCRIPTION": "আপনার পরিচিতিগুলোর বিস্তারিত তথ্যসহ দ্রুত একটি csv ফাইল রপ্তানি করুন",
"CONFIRM": "Export", "CONFIRM": "রপ্তানি করুন",
"SUCCESS_MESSAGE": "Export is in progress. You will be notified on email when the export file is ready to download.", "SUCCESS_MESSAGE": "রপ্তানি চলছে. ডাউনলোডের জন্য ফাইল প্রস্তুত হলে আপনাকে ইমেইলে জানানো হবে.",
"ERROR_MESSAGE": "There was an error, please try again" "ERROR_MESSAGE": "একটি ত্রুটি হয়েছে, অনুগ্রহ করে আবার চেষ্টা করুন"
}, },
"SORT_BY": { "SORT_BY": {
"LABEL": "Sort by", "LABEL": "সাজান",
"OPTIONS": { "OPTIONS": {
"NAME": "Name", "NAME": "নাম",
"EMAIL": "Email", "EMAIL": "ইমেইল",
"PHONE_NUMBER": "Phone number", "PHONE_NUMBER": "ফোন নম্বর",
"COMPANY": "Company", "COMPANY": "কোম্পানি",
"COUNTRY": "Country", "COUNTRY": "দেশ",
"CITY": "City", "CITY": "শহর",
"LAST_ACTIVITY": "Last activity", "LAST_ACTIVITY": "সর্বশেষ কার্যকলাপ",
"CREATED_AT": "Created at" "CREATED_AT": "তৈরি হয়েছে"
} }
}, },
"ORDER": { "ORDER": {
"LABEL": "Ordering", "LABEL": "অর্ডারিং",
"OPTIONS": { "OPTIONS": {
"ASCENDING": "Ascending", "ASCENDING": "আরোহী",
"DESCENDING": "Descending" "DESCENDING": "নিম্নক্রমে"
} }
}, },
"FILTERS": { "FILTERS": {
"CREATE_SEGMENT": { "CREATE_SEGMENT": {
"TITLE": "Do you want to save this filter?", "TITLE": "আপনি কি এই ফিল্টারটি সংরক্ষণ করতে চান?",
"CONFIRM": "Save filter", "CONFIRM": "ফিল্টার সংরক্ষণ করুন",
"LABEL": "Name", "LABEL": "নাম",
"PLACEHOLDER": "Enter the name of the filter", "PLACEHOLDER": "ফিল্টারের নাম লিখুন",
"ERROR": "Enter a valid name", "ERROR": "একটি বৈধ নাম লিখুন",
"SUCCESS_MESSAGE": "Filter saved successfully", "SUCCESS_MESSAGE": "ফিল্টার সফলভাবে সংরক্ষণ করা হয়েছে",
"ERROR_MESSAGE": "Unable to save filter. Please try again later." "ERROR_MESSAGE": "ফিল্টার সংরক্ষণ করা যায়নি। অনুগ্রহ করে পরে আবার চেষ্টা করুন।."
}, },
"DELETE_SEGMENT": { "DELETE_SEGMENT": {
"TITLE": "Confirm Deletion", "TITLE": "মুছে ফেলার নিশ্চয়তা দিন",
"DESCRIPTION": "Are you sure you want to delete this filter?", "DESCRIPTION": "আপনি কি নিশ্চিত যে আপনি এই ফিল্টারটি মুছে ফেলতে চান?",
"CONFIRM": "Yes, Delete", "CONFIRM": "হ্যাঁ, মুছে ফেলুন",
"CANCEL": "No, Cancel", "CANCEL": "না, বাতিল করুন",
"SUCCESS_MESSAGE": "Filter deleted successfully", "SUCCESS_MESSAGE": "ফিল্টার সফলভাবে মুছে ফেলা হয়েছে",
"ERROR_MESSAGE": "Unable to delete filter. Please try again later." "ERROR_MESSAGE": "ফিল্টার মুছে ফেলা যায়নি। অনুগ্রহ করে পরে আবার চেষ্টা করুন।."
} }
} }
} }
@@ -379,83 +379,83 @@
"SHOWING": "Showing {startItem} - {endItem} of {totalItems} contacts" "SHOWING": "Showing {startItem} - {endItem} of {totalItems} contacts"
}, },
"FILTER": { "FILTER": {
"NAME": "Name", "NAME": "নাম",
"EMAIL": "Email", "EMAIL": "ইমেইল",
"PHONE_NUMBER": "Phone number", "PHONE_NUMBER": "ফোন নম্বর",
"IDENTIFIER": "Identifier", "IDENTIFIER": "আইডেন্টিফায়ার",
"COUNTRY": "Country", "COUNTRY": "দেশ",
"CITY": "City", "CITY": "শহর",
"CREATED_AT": "Created at", "CREATED_AT": "তৈরি হয়েছে",
"LAST_ACTIVITY": "Last activity", "LAST_ACTIVITY": "সর্বশেষ কার্যকলাপ",
"REFERER_LINK": "Referer link", "REFERER_LINK": "রেফারার লিঙ্ক",
"BLOCKED": "Blocked", "BLOCKED": "ব্লক করা হয়েছে",
"BLOCKED_TRUE": "True", "BLOCKED_TRUE": "সত্য",
"BLOCKED_FALSE": "False", "BLOCKED_FALSE": "ফলস",
"BUTTONS": { "BUTTONS": {
"CLEAR_FILTERS": "Clear filters", "CLEAR_FILTERS": "ফিল্টার মুছুন",
"UPDATE_SEGMENT": "Update segment", "UPDATE_SEGMENT": "সেগমেন্ট আপডেট করুন",
"APPLY_FILTERS": "Apply filters", "APPLY_FILTERS": "ফিল্টারগুলি প্রয়োগ করুন",
"ADD_FILTER": "Add filter" "ADD_FILTER": "ফিল্টার যোগ করুন"
}, },
"TITLE": "Filter contacts", "TITLE": "যোগাযোগ ফিল্টার করুন",
"EDIT_SEGMENT": "Edit segment", "EDIT_SEGMENT": "সেগমেন্ট সম্পাদনা করুন",
"SEGMENT": { "SEGMENT": {
"LABEL": "Segment name", "LABEL": "সেগমেন্টের নাম",
"INPUT_PLACEHOLDER": "Enter the name of the segment" "INPUT_PLACEHOLDER": "সেগমেন্টের নাম লিখুন"
}, },
"ACTIVE_FILTERS": { "ACTIVE_FILTERS": {
"MORE_FILTERS": "+ {count} more filters", "MORE_FILTERS": "+ {count} টি আরও ফিল্টার",
"CLEAR_FILTERS": "Clear filters" "CLEAR_FILTERS": "ফিল্টারগুলি মুছে ফেলুন"
} }
}, },
"CARD": { "CARD": {
"OF": "of", "OF": "এর",
"VIEW_DETAILS": "View details", "VIEW_DETAILS": "বিস্তারিত দেখুন",
"EDIT_DETAILS_FORM": { "EDIT_DETAILS_FORM": {
"TITLE": "Edit contact details", "TITLE": "কন্টাক্টের বিস্তারিত সম্পাদনা করুন",
"FORM": { "FORM": {
"FIRST_NAME": { "FIRST_NAME": {
"PLACEHOLDER": "Enter the first name" "PLACEHOLDER": "প্রথম নাম লিখুন"
}, },
"LAST_NAME": { "LAST_NAME": {
"PLACEHOLDER": "Enter the last name" "PLACEHOLDER": "শেষ নাম লিখুন"
}, },
"EMAIL_ADDRESS": { "EMAIL_ADDRESS": {
"PLACEHOLDER": "Enter the email address", "PLACEHOLDER": "ইমেইল ঠিকানা লিখুন",
"DUPLICATE": "This email address is in use for another contact." "DUPLICATE": "এই ইমেইল ঠিকানাটি অন্য একটি যোগাযোগের জন্য ব্যবহৃত হচ্ছে।."
}, },
"PHONE_NUMBER": { "PHONE_NUMBER": {
"PLACEHOLDER": "Enter the phone number", "PLACEHOLDER": "ফোন নম্বর লিখুন",
"DUPLICATE": "This phone number is in use for another contact." "DUPLICATE": "এই ফোন নম্বরটি অন্য একটি যোগাযোগের জন্য ব্যবহৃত হচ্ছে।."
}, },
"CITY": { "CITY": {
"PLACEHOLDER": "Enter the city name" "PLACEHOLDER": "শহরের নাম লিখুন"
}, },
"COUNTRY": { "COUNTRY": {
"PLACEHOLDER": "Select country" "PLACEHOLDER": "দেশ নির্বাচন করুন"
}, },
"BIO": { "BIO": {
"PLACEHOLDER": "Enter the bio" "PLACEHOLDER": "জীবনবৃত্তান্ত লিখুন"
}, },
"COMPANY_NAME": { "COMPANY_NAME": {
"PLACEHOLDER": "Enter the company name" "PLACEHOLDER": "কোম্পানির নাম লিখুন"
} }
}, },
"UPDATE_BUTTON": "Update contact", "UPDATE_BUTTON": "যোগাযোগ আপডেট করুন",
"SUCCESS_MESSAGE": "Contact updated successfully", "SUCCESS_MESSAGE": "যোগাযোগ সফলভাবে আপডেট হয়েছে",
"ERROR_MESSAGE": "Unable to update contact. Please try again later." "ERROR_MESSAGE": "যোগাযোগ আপডেট করা যাচ্ছে না। অনুগ্রহ করে পরে আবার চেষ্টা করুন।."
}, },
"SOCIAL_MEDIA": { "SOCIAL_MEDIA": {
"TITLE": "Edit social links", "TITLE": "সামাজিক লিঙ্ক সম্পাদনা করুন",
"FORM": { "FORM": {
"FACEBOOK": { "FACEBOOK": {
"PLACEHOLDER": "Add Facebook" "PLACEHOLDER": "Facebook যোগ করুন"
}, },
"GITHUB": { "GITHUB": {
"PLACEHOLDER": "Add Github" "PLACEHOLDER": "Github যোগ করুন"
}, },
"INSTAGRAM": { "INSTAGRAM": {
"PLACEHOLDER": "Add Instagram" "PLACEHOLDER": "Instagram যোগ করুন"
}, },
"TELEGRAM": { "TELEGRAM": {
"PLACEHOLDER": "Add Telegram" "PLACEHOLDER": "Add Telegram"
@@ -464,10 +464,10 @@
"PLACEHOLDER": "Add TikTok" "PLACEHOLDER": "Add TikTok"
}, },
"LINKEDIN": { "LINKEDIN": {
"PLACEHOLDER": "Add LinkedIn" "PLACEHOLDER": "LinkedIn যোগ করুন"
}, },
"TWITTER": { "TWITTER": {
"PLACEHOLDER": "Add Twitter" "PLACEHOLDER": "Twitter যোগ করুন"
} }
} }
}, },
@@ -477,34 +477,34 @@
} }
}, },
"DETAILS": { "DETAILS": {
"CREATED_AT": "Created {date}", "CREATED_AT": "তৈরি হয়েছে {date}",
"LAST_ACTIVITY": "Last active {date}", "LAST_ACTIVITY": "সর্বশেষ সক্রিয় {date}",
"DELETE_CONTACT_DESCRIPTION": "Permanently delete this contact. This action is irreversible", "DELETE_CONTACT_DESCRIPTION": "এই যোগাযোগ স্থায়ীভাবে মুছে ফেলুন। এই ক্রিয়াটি অপরিবর্তনীয়।",
"DELETE_CONTACT": "Delete contact", "DELETE_CONTACT": "যোগাযোগ মুছুন",
"DELETE_DIALOG": { "DELETE_DIALOG": {
"TITLE": "Confirm Deletion", "TITLE": "মুছে ফেলার নিশ্চিতকরণ",
"DESCRIPTION": "Are you sure you want to delete this contact?", "DESCRIPTION": "আপনি কি নিশ্চিত যে আপনি এই যোগাযোগটি মুছে ফেলতে চান?",
"CONFIRM": "Yes, Delete", "CONFIRM": "হ্যাঁ, মুছে ফেলুন",
"API": { "API": {
"SUCCESS_MESSAGE": "Contact deleted successfully", "SUCCESS_MESSAGE": "যোগাযোগ সফলভাবে মুছে ফেলা হয়েছে",
"ERROR_MESSAGE": "Could not delete contact. Please try again later." "ERROR_MESSAGE": "যোগাযোগ মুছে ফেলা যায়নি। অনুগ্রহ করে পরে আবার চেষ্টা করুন।"
} }
}, },
"AVATAR": { "AVATAR": {
"UPLOAD": { "UPLOAD": {
"ERROR_MESSAGE": "Could not upload avatar. Please try again later.", "ERROR_MESSAGE": "অবতার আপলোড করা যায়নি। অনুগ্রহ করে পরে আবার চেষ্টা করুন।",
"SUCCESS_MESSAGE": "Avatar uploaded successfully" "SUCCESS_MESSAGE": "অবতার সফলভাবে আপলোড হয়েছে"
}, },
"DELETE": { "DELETE": {
"SUCCESS_MESSAGE": "Avatar deleted successfully", "SUCCESS_MESSAGE": "অবতার সফলভাবে মুছে ফেলা হয়েছে",
"ERROR_MESSAGE": "Could not delete avatar. Please try again later." "ERROR_MESSAGE": "অবতার মুছে ফেলা যায়নি। অনুগ্রহ করে পরে আবার চেষ্টা করুন।"
} }
} }
}, },
"SIDEBAR": { "SIDEBAR": {
"TABS": { "TABS": {
"ATTRIBUTES": "Attributes", "ATTRIBUTES": "বৈশিষ্ট্যসমূহ",
"HISTORY": "History", "HISTORY": "ইতিহাস",
"NOTES": "Notes", "NOTES": "Notes",
"MERGE": "Merge" "MERGE": "Merge"
}, },
@@ -512,69 +512,69 @@
"EMPTY_STATE": "There are no previous conversations associated to this contact" "EMPTY_STATE": "There are no previous conversations associated to this contact"
}, },
"ATTRIBUTES": { "ATTRIBUTES": {
"SEARCH_PLACEHOLDER": "Search for attributes", "SEARCH_PLACEHOLDER": "বৈশিষ্ট্য অনুসন্ধান করুন",
"UNUSED_ATTRIBUTES": "{count} Used attribute | {count} Unused attributes", "UNUSED_ATTRIBUTES": "{count} ব্যবহৃত বৈশিষ্ট্য | {count} অব্যবহৃত বৈশিষ্ট্য",
"EMPTY_STATE": "There are no contact custom attributes available in this account. You can create a custom attribute in settings.", "EMPTY_STATE": "এই অ্যাকাউন্টে কোনো কাস্টম কন্টাক্ট অ্যাট্রিবিউট নেই। আপনি সেটিংসে একটি কাস্টম অ্যাট্রিবিউট তৈরি করতে পারেন।.",
"YES": "Yes", "YES": "হ্যাঁ",
"NO": "No", "NO": "না",
"TRIGGER": { "TRIGGER": {
"SELECT": "Select value", "SELECT": "মান নির্বাচন করুন",
"INPUT": "Enter value" "INPUT": "মান লিখুন"
}, },
"VALIDATIONS": { "VALIDATIONS": {
"INVALID_NUMBER": "Invalid number", "INVALID_NUMBER": "অবৈধ সংখ্যা",
"REQUIRED": "Valid value is required", "REQUIRED": "বৈধ মান আবশ্যক",
"INVALID_INPUT": "Invalid input", "INVALID_INPUT": "অবৈধ ইনপুট প্রদান",
"INVALID_URL": "Invalid URL", "INVALID_URL": "অবৈধ URL",
"INVALID_DATE": "Invalid date" "INVALID_DATE": "অবৈধ তারিখ"
}, },
"NO_ATTRIBUTES": "No attributes found", "NO_ATTRIBUTES": "কোনো বৈশিষ্ট্য পাওয়া যায়নি",
"API": { "API": {
"SUCCESS_MESSAGE": "Attribute updated successfully", "SUCCESS_MESSAGE": "বৈশিষ্ট্য সফলভাবে আপডেট হয়েছে",
"DELETE_SUCCESS_MESSAGE": "Attribute deleted successfully", "DELETE_SUCCESS_MESSAGE": "বৈশিষ্ট্য সফলভাবে মুছে ফেলা হয়েছে",
"UPDATE_ERROR": "Unable to update attribute. Please try again later", "UPDATE_ERROR": "বৈশিষ্ট্য আপডেট করা যায়নি। অনুগ্রহ করে পরে আবার চেষ্টা করুন",
"DELETE_ERROR": "Unable to delete attribute. Please try again later" "DELETE_ERROR": "বৈশিষ্ট্য মুছে ফেলা যায়নি। অনুগ্রহ করে পরে আবার চেষ্টা করুন"
} }
}, },
"MERGE": { "MERGE": {
"TITLE": "Merge contact", "TITLE": "কন্টাক্ট একত্রিত করুন",
"DESCRIPTION": "Combine two profiles into one, including all attributes and conversations. In case of conflict, the primary contacts attributes will take precedence.", "DESCRIPTION": "দুটি প্রোফাইলের সব বৈশিষ্ট্য ও কথোপকথন একত্র করে একটি প্রোফাইল বানান. কোনো দ্বন্দ্ব হলে, প্রধান কন্টাক্টের তথ্য আগে ধরা হবে.",
"PRIMARY": "Primary contact", "PRIMARY": "প্রধান কন্টাক্ট",
"PRIMARY_HELP_LABEL": "To be saved", "PRIMARY_HELP_LABEL": "সংরক্ষণ করা হবে",
"PRIMARY_REQUIRED_ERROR": "Please select a contact to merge with before proceeding", "PRIMARY_REQUIRED_ERROR": "অনুগ্রহ করে আগে একত্র করার জন্য একটি কন্টাক্ট বেছে নিন",
"PARENT": "To be merged", "PARENT": "একত্রিত করা হবে",
"PARENT_HELP_LABEL": "To be deleted", "PARENT_HELP_LABEL": "মুছে ফেলা হবে",
"EMPTY_STATE": "No contacts found", "EMPTY_STATE": "কোনো কন্টাক্ট পাওয়া যায়নি",
"PLACEHOLDER": "Search for primary contact", "PLACEHOLDER": "প্রধান কন্টাক্ট খুঁজুন",
"SEARCH_PLACEHOLDER": "Search for a contact", "SEARCH_PLACEHOLDER": "একটি কন্টাক্ট খুঁজুন",
"SEARCH_ERROR_MESSAGE": "Could not search for contacts. Please try again later.", "SEARCH_ERROR_MESSAGE": "কন্টাক্ট খোঁজা যায়নি. অনুগ্রহ করে পরে আবার চেষ্টা করুন.",
"SUCCESS_MESSAGE": "Contact merged successfully", "SUCCESS_MESSAGE": "যোগাযোগ সফলভাবে একত্রিত হয়েছে",
"ERROR_MESSAGE": "Could not merge contacts, try again!", "ERROR_MESSAGE": "যোগাযোগ একত্রিত করা যায়নি, আবার চেষ্টা করুন!",
"IS_SEARCHING": "Searching...", "IS_SEARCHING": "অনুসন্ধান চলছে...",
"BUTTONS": { "BUTTONS": {
"CANCEL": "Cancel", "CANCEL": "বাতিল করুন",
"CONFIRM": "Merge contact" "CONFIRM": "কন্টাক্ট একত্রিত করুন"
} }
}, },
"NOTES": { "NOTES": {
"PLACEHOLDER": "Add a note", "PLACEHOLDER": "নোট যোগ করুন",
"WROTE": "wrote", "WROTE": "লিখেছেন",
"YOU": "You", "YOU": "আপনি",
"SAVE": "Save note", "SAVE": "নোট সংরক্ষণ করুন",
"ADD_NOTE": "Add contact note", "ADD_NOTE": "Add contact note",
"EXPAND": "Expand", "EXPAND": "Expand",
"COLLAPSE": "Collapse", "COLLAPSE": "Collapse",
"NO_NOTES": "No notes, you can add notes from the contact details page.", "NO_NOTES": "No notes, you can add notes from the contact details page.",
"EMPTY_STATE": "There are no notes associated to this contact. You can add a note by typing in the box above.", "EMPTY_STATE": "এই যোগাযোগের সাথে কোনো নোট যুক্ত নেই। উপরের বাক্সে লিখে আপনি একটি নোট যোগ করতে পারেন।.",
"CONVERSATION_EMPTY_STATE": "There are no notes yet. Use the Add note button to create one." "CONVERSATION_EMPTY_STATE": "There are no notes yet. Use the Add note button to create one."
} }
}, },
"EMPTY_STATE": { "EMPTY_STATE": {
"TITLE": "No contacts found in this account", "TITLE": "এই অ্যাকাউন্টে কোনো যোগাযোগ পাওয়া যায়নি",
"SUBTITLE": "Start adding new contacts by clicking on the button below", "SUBTITLE": "নিচের বোতামে ক্লিক করে নতুন কন্টাক্ট যোগ করা শুরু করুন",
"BUTTON_LABEL": "Add contact", "BUTTON_LABEL": "কন্টাক্ট যোগ করুন",
"SEARCH_EMPTY_STATE_TITLE": "No contacts matches your search 🔍", "SEARCH_EMPTY_STATE_TITLE": "আপনার অনুসন্ধানের সাথে কোনো কন্টাক্ট মেলে নি 🔍",
"LIST_EMPTY_STATE_TITLE": "No contacts available in this view 📋", "LIST_EMPTY_STATE_TITLE": "এই ভিউতে কোনো কন্টাক্ট নেই 📋",
"ACTIVE_EMPTY_STATE_TITLE": "No contacts are active at the moment 🌙" "ACTIVE_EMPTY_STATE_TITLE": "No contacts are active at the moment 🌙"
}, },
"LOAD_MORE": "Load more" "LOAD_MORE": "Load more"
@@ -1,319 +1,319 @@
{ {
"CONVERSATION": { "CONVERSATION": {
"SELECT_A_CONVERSATION": "Please select a conversation from left pane", "SELECT_A_CONVERSATION": "বাম পাশ থেকে একটি কনভার্সেশন নির্বাচন করুন",
"CSAT_REPLY_MESSAGE": "Please rate the conversation", "CSAT_REPLY_MESSAGE": "অনুগ্রহ করে কথোপকথনের মূল্যায়ন করুন",
"404": "Sorry, we cannot find the conversation. Please try again", "404": "দুঃখিত, আমরা কনভার্সেশনটি খুঁজে পাচ্ছি না। আবার চেষ্টা করুন",
"SWITCH_VIEW_LAYOUT": "Switch the layout", "SWITCH_VIEW_LAYOUT": "লেআউট পরিবর্তন করুন",
"DASHBOARD_APP_TAB_MESSAGES": "Messages", "DASHBOARD_APP_TAB_MESSAGES": "বার্তা",
"UNVERIFIED_SESSION": "The identity of this user is not verified", "UNVERIFIED_SESSION": "এই ব্যবহারকারীর পরিচয় যাচাই করা হয়নি",
"NO_MESSAGE_1": "Uh oh! Looks like there are no messages from customers in your inbox.", "NO_MESSAGE_1": "ওহ! আপনার ইনবক্সে কোনো গ্রাহকের বার্তা নেই।",
"NO_MESSAGE_2": " to send a message to your page!", "NO_MESSAGE_2": " আপনার পেজে বার্তা পাঠাতে!",
"NO_INBOX_1": "Hola! Looks like you haven't added any inboxes yet.", "NO_INBOX_1": "হ্যালো! আপনি এখনো কোনো ইনবক্স যোগ করেননি।",
"NO_INBOX_2": " to get started", "NO_INBOX_2": " শুরু করতে",
"NO_INBOX_AGENT": "Uh Oh! Looks like you are not part of any inbox. Please contact your administrator", "NO_INBOX_AGENT": "ওহ! আপনি কোনো ইনবক্সের সদস্য নন। অনুগ্রহ করে আপনার অ্যাডমিনের সাথে যোগাযোগ করুন।",
"SEARCH_MESSAGES": "Search for messages in conversations", "SEARCH_MESSAGES": "কথোপকথনে বার্তা অনুসন্ধান করুন",
"VIEW_ORIGINAL": "View original", "VIEW_ORIGINAL": "মূল দেখুন",
"VIEW_TRANSLATED": "View translated", "VIEW_TRANSLATED": "অনুবাদ দেখুন",
"EMPTY_STATE": { "EMPTY_STATE": {
"CMD_BAR": "to open command menu", "CMD_BAR": "কমান্ড মেনু খুলতে",
"KEYBOARD_SHORTCUTS": "to view keyboard shortcuts" "KEYBOARD_SHORTCUTS": "কীবোর্ড শর্টকাট দেখতে"
}, },
"SEARCH": { "SEARCH": {
"TITLE": "Search messages", "TITLE": "বার্তা অনুসন্ধান",
"RESULT_TITLE": "Search Results", "RESULT_TITLE": "অনুসন্ধান ফলাফল",
"LOADING_MESSAGE": "Crunching data...", "LOADING_MESSAGE": "ডেটা বিশ্লেষণ হচ্ছে...",
"PLACEHOLDER": "Type any text to search messages", "PLACEHOLDER": "বার্তা খুঁজতে যেকোনো লেখা টাইপ করুন",
"NO_MATCHING_RESULTS": "No results found." "NO_MATCHING_RESULTS": "কোন ফলাফল পাওয়া যায়নি।"
}, },
"UNREAD_MESSAGES": "Unread Messages", "UNREAD_MESSAGES": "অপঠিত বার্তা",
"UNREAD_MESSAGE": "Unread Message", "UNREAD_MESSAGE": "অপঠিত বার্তা",
"CLICK_HERE": "Click here", "CLICK_HERE": "এখানে ক্লিক করুন",
"LOADING_INBOXES": "Loading inboxes", "LOADING_INBOXES": "ইনবক্স লোড হচ্ছে",
"LOADING_CONVERSATIONS": "Loading Conversations", "LOADING_CONVERSATIONS": "কথোপকথন লোড হচ্ছে",
"CANNOT_REPLY": "You cannot reply due to", "CANNOT_REPLY": "আপনি উত্তর দিতে পারবেন না কারণ",
"24_HOURS_WINDOW": "24 hour message window restriction", "24_HOURS_WINDOW": "২৪ ঘণ্টার মেসেজ সীমাবদ্ধতা",
"48_HOURS_WINDOW": "48 hour message window restriction", "48_HOURS_WINDOW": "৪৮ ঘণ্টার মেসেজ সীমাবদ্ধতা",
"API_HOURS_WINDOW": "You can only reply to this conversation within {hours} hours", "API_HOURS_WINDOW": "You can only reply to this conversation within {hours} hours",
"NOT_ASSIGNED_TO_YOU": "This conversation is not assigned to you. Would you like to assign this conversation to yourself?", "NOT_ASSIGNED_TO_YOU": "এই কথোপকথনটি আপনার কাছে বরাদ্দ নয়। আপনি কি এটি নিজের কাছে বরাদ্দ করতে চান?",
"ASSIGN_TO_ME": "Assign to me", "ASSIGN_TO_ME": "নিজের কাছে বরাদ্দ করুন",
"BOT_HANDOFF_MESSAGE": "You are responding to a conversation which is currently handled by an assistant or a bot.", "BOT_HANDOFF_MESSAGE": "আপনি এমন একটি কথোপকথনে উত্তর দিচ্ছেন যা বর্তমানে সহকারী বা বট দ্বারা পরিচালিত হচ্ছে।",
"BOT_HANDOFF_ACTION": "Mark open and assign to you", "BOT_HANDOFF_ACTION": "ওপেন করুন এবং নিজের কাছে অ্যাসাইন করুন",
"BOT_HANDOFF_REOPEN_ACTION": "Mark conversation open", "BOT_HANDOFF_REOPEN_ACTION": "কথোপকথন ওপেন করুন",
"BOT_HANDOFF_SUCCESS": "Conversation has been handed over to you", "BOT_HANDOFF_SUCCESS": "কথোপকথনটি আপনার কাছে হস্তান্তর করা হয়েছে",
"BOT_HANDOFF_ERROR": "Failed to take over the conversation. Please try again.", "BOT_HANDOFF_ERROR": "কথোপকথনটি নেওয়া যায়নি। আবার চেষ্টা করুন।",
"TWILIO_WHATSAPP_CAN_REPLY": "You can only reply to this conversation using a template message due to", "TWILIO_WHATSAPP_CAN_REPLY": "আপনি শুধুমাত্র টেমপ্লেট বার্তা ব্যবহার করে এই আলাপে উত্তর দিতে পারবেন কারণ",
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "24 hour message window restriction", "TWILIO_WHATSAPP_24_HOURS_WINDOW": "২৪ ঘণ্টার বার্তা সীমাবদ্ধতা",
"OLD_INSTAGRAM_INBOX_REPLY_BANNER": "This Instagram account was migrated to the new Instagram channel inbox. All new messages will show up there. You wont be able to send messages from this conversation anymore.", "OLD_INSTAGRAM_INBOX_REPLY_BANNER": "এই Instagram অ্যাকাউন্টটি নতুন Instagram চ্যানেল ইনবক্সে স্থানান্তরিত হয়েছে। সব নতুন বার্তা সেখানে দেখা যাবে। আপনি আর এই কথোপকথন থেকে বার্তা পাঠাতে পারবেন না।",
"REPLYING_TO": "You are replying to:", "REPLYING_TO": "আপনি যাকে উত্তর দিচ্ছেন:",
"REMOVE_SELECTION": "Remove Selection", "REMOVE_SELECTION": "নির্বাচন সরান",
"DOWNLOAD": "Download", "DOWNLOAD": "ডাউনলোড",
"UNKNOWN_FILE_TYPE": "Unknown File", "UNKNOWN_FILE_TYPE": "অজানা ফাইল",
"SAVE_CONTACT": "Save Contact", "SAVE_CONTACT": "যোগাযোগ সংরক্ষণ করুন",
"NO_CONTENT": "No content to display", "NO_CONTENT": "দেখানোর জন্য কোনো বিষয়বস্তু নেই",
"SHARED_ATTACHMENT": { "SHARED_ATTACHMENT": {
"CONTACT": "{sender} has shared a contact", "CONTACT": "{sender} has shared a contact",
"LOCATION": "{sender} has shared a location", "LOCATION": "{sender} has shared a location",
"FILE": "{sender} has shared a file", "FILE": "{sender} has shared a file",
"MEETING": "{sender} has started a meeting" "MEETING": "{sender} has started a meeting"
}, },
"UPLOADING_ATTACHMENTS": "Uploading attachments...", "UPLOADING_ATTACHMENTS": "সংযুক্তি আপলোড হচ্ছে...",
"REPLIED_TO_STORY": "Replied to your story", "REPLIED_TO_STORY": "আপনার স্টোরিতে উত্তর দিয়েছে",
"UNSUPPORTED_MESSAGE": "This message is unsupported. You can view this message on the Facebook / Instagram app.", "UNSUPPORTED_MESSAGE": "This message is unsupported. You can view this message on the Facebook / Instagram app.",
"UNSUPPORTED_MESSAGE_FACEBOOK": "This message is unsupported. You can view this message on the Facebook Messenger app.", "UNSUPPORTED_MESSAGE_FACEBOOK": "এই বার্তাটি সমর্থিত নয়। আপনি Facebook Messenger অ্যাপে এই বার্তাটি দেখতে পারেন।",
"UNSUPPORTED_MESSAGE_INSTAGRAM": "This message is unsupported. You can view this message on the Instagram app.", "UNSUPPORTED_MESSAGE_INSTAGRAM": "এই বার্তাটি সমর্থিত নয়। আপনি Instagram অ্যাপে এই বার্তাটি দেখতে পারেন।",
"UNSUPPORTED_MESSAGE_TIKTOK": "This message is unsupported. You can view this message on the TikTok app.", "UNSUPPORTED_MESSAGE_TIKTOK": "এই বার্তাটি সমর্থিত নয়। TikTok অ্যাপে এই বার্তাটি দেখতে পারেন।",
"SUCCESS_DELETE_MESSAGE": "Message deleted successfully", "SUCCESS_DELETE_MESSAGE": "বার্তা সফলভাবে মুছে ফেলা হয়েছে",
"FAIL_DELETE_MESSSAGE": "Couldn't delete message! Try again", "FAIL_DELETE_MESSSAGE": "বার্তা মুছে ফেলা যায়নি! আবার চেষ্টা করুন",
"NO_RESPONSE": "No response", "NO_RESPONSE": "কোনো উত্তর নেই",
"RESPONSE": "Response", "RESPONSE": "উত্তর",
"RATING_TITLE": "Rating", "RATING_TITLE": "রেটিং",
"FEEDBACK_TITLE": "Feedback", "FEEDBACK_TITLE": "মতামত",
"REPLY_MESSAGE_NOT_FOUND": "Message not available", "REPLY_MESSAGE_NOT_FOUND": "বার্তাটি পাওয়া যায়নি",
"CARD": { "CARD": {
"SHOW_LABELS": "Show labels", "SHOW_LABELS": "লেবেল দেখান",
"HIDE_LABELS": "Hide labels" "HIDE_LABELS": "লেবেল লুকান"
}, },
"VOICE_CALL": { "VOICE_CALL": {
"INCOMING_CALL": "Incoming call", "INCOMING_CALL": "ইনকামিং কল",
"OUTGOING_CALL": "Outgoing call", "OUTGOING_CALL": "আউটগোয়িং কল",
"CALL_IN_PROGRESS": "Call in progress", "CALL_IN_PROGRESS": "কল চলছে",
"NO_ANSWER": "No answer", "NO_ANSWER": "উত্তর নেই",
"MISSED_CALL": "Missed call", "MISSED_CALL": "মিসড কল",
"CALL_ENDED": "Call ended", "CALL_ENDED": "কল শেষ হয়েছে",
"NOT_ANSWERED_YET": "Not answered yet", "NOT_ANSWERED_YET": "এখনও উত্তর পাওয়া যায়নি",
"THEY_ANSWERED": "They answered", "THEY_ANSWERED": "তারা উত্তর দিয়েছে",
"YOU_ANSWERED": "You answered" "YOU_ANSWERED": "আপনি উত্তর দিয়েছেন"
}, },
"HEADER": { "HEADER": {
"RESOLVE_ACTION": "Resolve", "RESOLVE_ACTION": "সমাধান করুন",
"REOPEN_ACTION": "Reopen", "REOPEN_ACTION": "পুনরায় খুলুন",
"OPEN_ACTION": "Open", "OPEN_ACTION": "খুলুন",
"MORE_ACTIONS": "More actions", "MORE_ACTIONS": "আরও অপশন",
"OPEN": "More", "OPEN": "আরও",
"CLOSE": "Close", "CLOSE": "বন্ধ করুন",
"DETAILS": "details", "DETAILS": "বিস্তারিত",
"SNOOZED_UNTIL": "Snoozed until", "SNOOZED_UNTIL": "স্নুজ করা হয়েছে পর্যন্ত",
"SNOOZED_UNTIL_TOMORROW": "Snoozed until tomorrow", "SNOOZED_UNTIL_TOMORROW": "আগামীকাল পর্যন্ত স্থগিত",
"SNOOZED_UNTIL_NEXT_WEEK": "Snoozed until next week", "SNOOZED_UNTIL_NEXT_WEEK": "পরবর্তী সপ্তাহ পর্যন্ত স্থগিত",
"SNOOZED_UNTIL_NEXT_REPLY": "Snoozed until next reply", "SNOOZED_UNTIL_NEXT_REPLY": "পরবর্তী উত্তর পর্যন্ত স্থগিত",
"SLA_STATUS": { "SLA_STATUS": {
"FRT": "FRT {status}", "FRT": "FRT {status}",
"NRT": "NRT {status}", "NRT": "NRT {status}",
"RT": "RT {status}", "RT": "RT {status}",
"MISSED": "missed", "MISSED": "মিস হয়েছে",
"DUE": "due" "DUE": "বাকি"
} }
}, },
"RESOLVE_DROPDOWN": { "RESOLVE_DROPDOWN": {
"MARK_PENDING": "Mark as pending", "MARK_PENDING": "পেন্ডিং হিসেবে চিহ্নিত করুন",
"SNOOZE_UNTIL": "Snooze", "SNOOZE_UNTIL": "স্নুজ",
"SNOOZE": { "SNOOZE": {
"TITLE": "Snooze until", "TITLE": "স্নুজ করুন যতক্ষণ না",
"NEXT_REPLY": "Next reply", "NEXT_REPLY": "পরবর্তী উত্তর",
"TOMORROW": "Tomorrow", "TOMORROW": "আগামীকাল",
"NEXT_WEEK": "Next week" "NEXT_WEEK": "পরবর্তী সপ্তাহ"
} }
}, },
"MENTION": { "MENTION": {
"AGENTS": "Agents", "AGENTS": "এজেন্টরা",
"TEAMS": "Teams" "TEAMS": "টিমসমূহ"
}, },
"CUSTOM_SNOOZE": { "CUSTOM_SNOOZE": {
"TITLE": "Snooze until", "TITLE": "স্নুজ করা হবে পর্যন্ত",
"APPLY": "Snooze", "APPLY": "স্নুজ",
"CANCEL": "Cancel" "CANCEL": "বাতিল"
}, },
"PRIORITY": { "PRIORITY": {
"TITLE": "Priority", "TITLE": "অগ্রাধিকার",
"OPTIONS": { "OPTIONS": {
"NONE": "None", "NONE": "কিছুই না",
"URGENT": "Urgent", "URGENT": "জরুরি",
"HIGH": "High", "HIGH": "উচ্চ",
"MEDIUM": "Medium", "MEDIUM": "মাঝারি",
"LOW": "Low" "LOW": "নিম্ন"
}, },
"CHANGE_PRIORITY": { "CHANGE_PRIORITY": {
"SELECT_PLACEHOLDER": "None", "SELECT_PLACEHOLDER": "কিছুই না",
"INPUT_PLACEHOLDER": "Select priority", "INPUT_PLACEHOLDER": "অগ্রাধিকার নির্বাচন করুন",
"NO_RESULTS": "No results found", "NO_RESULTS": "কোন ফলাফল পাওয়া যায়নি",
"SUCCESSFUL": "Changed priority of conversation id {conversationId} to {priority}", "SUCCESSFUL": "Changed priority of conversation id {conversationId} to {priority}",
"FAILED": "Couldn't change priority. Please try again." "FAILED": "প্রাধান্য পরিবর্তন করা যায়নি। আবার চেষ্টা করুন।"
} }
}, },
"DELETE_CONVERSATION": { "DELETE_CONVERSATION": {
"TITLE": "Delete conversation #{conversationId}", "TITLE": "Delete conversation #{conversationId}",
"DESCRIPTION": "Are you sure you want to delete this conversation?", "DESCRIPTION": "আপনি কি নিশ্চিতভাবে এই কথোপকথনটি মুছে ফেলতে চান?",
"CONFIRM": "Delete" "CONFIRM": "মুছে ফেলুন"
}, },
"CARD_CONTEXT_MENU": { "CARD_CONTEXT_MENU": {
"PENDING": "Mark as pending", "PENDING": "বিচারাধীন হিসেবে চিহ্নিত করুন",
"RESOLVED": "Mark as resolved", "RESOLVED": "সমাধান হয়েছে হিসেবে চিহ্নিত করুন",
"MARK_AS_UNREAD": "Mark as unread", "MARK_AS_UNREAD": "অপঠিত হিসেবে চিহ্নিত করুন",
"MARK_AS_READ": "Mark as read", "MARK_AS_READ": "পড়া হয়েছে হিসেবে চিহ্নিত করুন",
"REOPEN": "Reopen conversation", "REOPEN": "আলোচনা পুনরায় খুলুন",
"SNOOZE": { "SNOOZE": {
"TITLE": "Snooze", "TITLE": "স্নুজ",
"NEXT_REPLY": "Until next reply", "NEXT_REPLY": "পরবর্তী উত্তর পর্যন্ত",
"TOMORROW": "Until tomorrow", "TOMORROW": "আগামীকাল পর্যন্ত",
"NEXT_WEEK": "Until next week" "NEXT_WEEK": "পরবর্তী সপ্তাহ পর্যন্ত"
}, },
"ASSIGN_AGENT": "Assign agent", "ASSIGN_AGENT": "এজেন্ট নির্ধারণ করুন",
"ASSIGN_LABEL": "Assign label", "ASSIGN_LABEL": "লেবেল নির্ধারণ করুন",
"AGENTS_LOADING": "Loading agents...", "AGENTS_LOADING": "এজেন্ট লোড হচ্ছে...",
"ASSIGN_TEAM": "Assign team", "ASSIGN_TEAM": "টিম নির্ধারণ করুন",
"DELETE": "Delete conversation", "DELETE": "কথোপকথন মুছে ফেলুন",
"OPEN_IN_NEW_TAB": "Open in new tab", "OPEN_IN_NEW_TAB": "নতুন ট্যাবে খুলুন",
"COPY_LINK": "Copy conversation link", "COPY_LINK": "কথোপকথনের লিংক কপি করুন",
"COPY_LINK_SUCCESS": "Conversation link copied to clipboard", "COPY_LINK_SUCCESS": "কথোপকথনের লিংক ক্লিপবোর্ডে কপি হয়েছে",
"API": { "API": {
"AGENT_ASSIGNMENT": { "AGENT_ASSIGNMENT": {
"SUCCESFUL": "Conversation id {conversationId} assigned to \"{agentName}\"", "SUCCESFUL": "Conversation id {conversationId} assigned to \"{agentName}\"",
"FAILED": "Couldn't assign agent. Please try again." "FAILED": "এজেন্ট নির্ধারণ করা যায়নি। আবার চেষ্টা করুন।"
}, },
"LABEL_ASSIGNMENT": { "LABEL_ASSIGNMENT": {
"SUCCESFUL": "Assigned label #{labelName} to conversation id {conversationId}", "SUCCESFUL": "Assigned label #{labelName} to conversation id {conversationId}",
"FAILED": "Couldn't assign label. Please try again." "FAILED": "লেবেল নির্ধারণ করা যায়নি। আবার চেষ্টা করুন।"
}, },
"LABEL_REMOVAL": { "LABEL_REMOVAL": {
"SUCCESFUL": "Removed label #{labelName} from conversation id {conversationId}", "SUCCESFUL": "Removed label #{labelName} from conversation id {conversationId}",
"FAILED": "Couldn't remove label. Please try again." "FAILED": "লেবেল সরানো যায়নি। অনুগ্রহ করে আবার চেষ্টা করুন।"
}, },
"TEAM_ASSIGNMENT": { "TEAM_ASSIGNMENT": {
"SUCCESFUL": "Assigned team \"{team}\" to conversation id {conversationId}", "SUCCESFUL": "Assigned team \"{team}\" to conversation id {conversationId}",
"FAILED": "Couldn't assign team. Please try again." "FAILED": "টিম নির্ধারণ করা যায়নি। আবার চেষ্টা করুন।"
} }
} }
}, },
"FOOTER": { "FOOTER": {
"MESSAGE_SIGN_TOOLTIP": "Message signature", "MESSAGE_SIGN_TOOLTIP": "বার্তার স্বাক্ষর",
"ENABLE_SIGN_TOOLTIP": "Enable signature", "ENABLE_SIGN_TOOLTIP": "স্বাক্ষর চালু করুন",
"DISABLE_SIGN_TOOLTIP": "Disable signature", "DISABLE_SIGN_TOOLTIP": "স্বাক্ষর বন্ধ করুন",
"MSG_INPUT": "Shift + enter for new line. Start with '/' to select a Canned Response.", "MSG_INPUT": "নতুন লাইনের জন্য Shift + Enter চাপুন। Canned Response বাছাই করতে '/' দিয়ে শুরু করুন।",
"PRIVATE_MSG_INPUT": "Shift + enter for new line. This will be visible only to Agents", "PRIVATE_MSG_INPUT": "নতুন লাইনের জন্য Shift + Enter চাপুন। এটি শুধু এজেন্টদের জন্য দৃশ্যমান হবে",
"MESSAGING_RESTRICTED": "You cannot reply to this conversation", "MESSAGING_RESTRICTED": "আপনি এই কথোপকথনে উত্তর দিতে পারবেন না",
"MESSAGING_RESTRICTED_WHATSAPP": "You can only reply using a template message due to 24-hour message window restriction", "MESSAGING_RESTRICTED_WHATSAPP": "২৪ ঘণ্টার বার্তা সীমাবদ্ধতার কারণে শুধু টেমপ্লেট বার্তা দিয়ে উত্তর দিতে পারবেন",
"MESSAGING_RESTRICTED_API": "You can only reply using a template message due to message window restriction", "MESSAGING_RESTRICTED_API": "বার্তা উইন্ডো সীমাবদ্ধতার কারণে শুধু টেমপ্লেট বার্তা দিয়ে উত্তর দিতে পারবেন",
"MESSAGE_SIGNATURE_NOT_CONFIGURED": "Message signature is not configured, please configure it in profile settings.", "MESSAGE_SIGNATURE_NOT_CONFIGURED": "বার্তার স্বাক্ষর কনফিগার করা হয়নি, প্রোফাইল সেটিংসে কনফিগার করুন।",
"COPILOT_MSG_INPUT": "Give copilot additional prompts, or ask anything else... Press enter to send follow-up", "COPILOT_MSG_INPUT": "Copilot-কে আরও নির্দেশ দিন বা অন্য কিছু জিজ্ঞাসা করুন... ফলো-আপ পাঠাতে এন্টার চাপুন",
"CLICK_HERE": "Click here to update", "CLICK_HERE": "আপডেট করতে এখানে ক্লিক করুন",
"WHATSAPP_TEMPLATES": "Whatsapp Templates" "WHATSAPP_TEMPLATES": "Whatsapp টেমপ্লেট"
}, },
"REPLYBOX": { "REPLYBOX": {
"REPLY": "Reply", "REPLY": "উত্তর দিন",
"PRIVATE_NOTE": "Private Note", "PRIVATE_NOTE": "ব্যক্তিগত নোট",
"SEND": "Send", "SEND": "পাঠান",
"CREATE": "Add Note", "CREATE": "নোট যোগ করুন",
"INSERT_READ_MORE": "Read more", "INSERT_READ_MORE": "আরও পড়ুন",
"DISMISS_REPLY": "Dismiss reply", "DISMISS_REPLY": "উত্তর বাতিল করুন",
"REPLYING_TO": "Replying to:", "REPLYING_TO": "উত্তর দিচ্ছেন:",
"TIP_EMOJI_ICON": "Show emoji selector", "TIP_EMOJI_ICON": "ইমোজি সিলেক্টর দেখান",
"TIP_ATTACH_ICON": "Attach files", "TIP_ATTACH_ICON": "ফাইল সংযুক্ত করুন",
"TIP_AUDIORECORDER_ICON": "Record audio", "TIP_AUDIORECORDER_ICON": "অডিও রেকর্ড করুন",
"TIP_AUDIORECORDER_PERMISSION": "Allow access to audio", "TIP_AUDIORECORDER_PERMISSION": "অডিও অ্যাক্সেসের অনুমতি দিন",
"TIP_AUDIORECORDER_ERROR": "Could not open the audio", "TIP_AUDIORECORDER_ERROR": "অডিও খোলা যায়নি",
"DRAG_DROP": "Drag and drop here to attach", "DRAG_DROP": "সংযুক্ত করতে এখানে ড্র্যাগ ও ড্রপ করুন",
"START_AUDIO_RECORDING": "Start audio recording", "START_AUDIO_RECORDING": "অডিও রেকর্ডিং শুরু করুন",
"STOP_AUDIO_RECORDING": "Stop audio recording", "STOP_AUDIO_RECORDING": "অডিও রেকর্ডিং বন্ধ করুন",
"COPILOT_THINKING": "Copilot is thinking", "COPILOT_THINKING": "Copilot ভাবছে",
"EMAIL_HEAD": { "EMAIL_HEAD": {
"TO": "TO", "TO": "TO",
"ADD_BCC": "Add bcc", "ADD_BCC": "বিসিসি যোগ করুন",
"CC": { "CC": {
"LABEL": "CC", "LABEL": "CC",
"PLACEHOLDER": "Emails separated by commas", "PLACEHOLDER": "কমা দিয়ে আলাদা ইমেইল",
"ERROR": "Please enter valid email addresses" "ERROR": "সঠিক ইমেইল ঠিকানা দিন"
}, },
"BCC": { "BCC": {
"LABEL": "BCC", "LABEL": "BCC",
"PLACEHOLDER": "Emails separated by commas", "PLACEHOLDER": "কমা দিয়ে আলাদা ইমেইল",
"ERROR": "Please enter valid email addresses" "ERROR": "বৈধ ইমেইল ঠিকানা দিন"
} }
}, },
"UNDEFINED_VARIABLES": { "UNDEFINED_VARIABLES": {
"TITLE": "Undefined variables", "TITLE": "অনির্ধারিত ভেরিয়েবল",
"MESSAGE": "You have {undefinedVariablesCount} undefined variables in your message: {undefinedVariables}. Would you like to send the message anyway?", "MESSAGE": "You have {undefinedVariablesCount} undefined variables in your message: {undefinedVariables}. Would you like to send the message anyway?",
"CONFIRM": { "CONFIRM": {
"YES": "Send", "YES": "পাঠান",
"CANCEL": "Cancel" "CANCEL": "বাতিল"
} }
}, },
"QUOTED_REPLY": { "QUOTED_REPLY": {
"ENABLE_TOOLTIP": "Include quoted email thread", "ENABLE_TOOLTIP": "উদ্ধৃত ইমেইল থ্রেড যুক্ত করুন",
"DISABLE_TOOLTIP": "Don't include quoted email thread", "DISABLE_TOOLTIP": "উদ্ধৃত ইমেইল থ্রেড যুক্ত করবেন না",
"REMOVE_PREVIEW": "Remove quoted email thread", "REMOVE_PREVIEW": "উদ্ধৃত ইমেইল থ্রেড সরান",
"COLLAPSE": "Collapse preview", "COLLAPSE": "প্রিভিউ সংকুচিত করুন",
"EXPAND": "Expand preview" "EXPAND": "প্রিভিউ বড় করুন"
} }
}, },
"VISIBLE_TO_AGENTS": "Private Note: Only visible to you and your team", "VISIBLE_TO_AGENTS": "ব্যক্তিগত নোট: শুধু আপনি ও আপনার টিম দেখতে পারবেন",
"CHANGE_STATUS": "Conversation status changed", "CHANGE_STATUS": "কথোপকথনের অবস্থা পরিবর্তিত হয়েছে",
"CHANGE_STATUS_FAILED": "Conversation status change failed", "CHANGE_STATUS_FAILED": "কনভার্সেশনের স্ট্যাটাস পরিবর্তন ব্যর্থ হয়েছে",
"CHANGE_AGENT": "Conversation Assignee changed", "CHANGE_AGENT": "কথোপকথনের দায়িত্বপ্রাপ্ত ব্যক্তি পরিবর্তিত হয়েছে",
"CHANGE_AGENT_FAILED": "Assignee change failed", "CHANGE_AGENT_FAILED": "অ্যাসাইনি পরিবর্তন ব্যর্থ হয়েছে",
"ASSIGN_LABEL_SUCCESFUL": "Label assigned successfully", "ASSIGN_LABEL_SUCCESFUL": "লেবেল সফলভাবে নির্ধারণ হয়েছে",
"ASSIGN_LABEL_FAILED": "Label assignment failed", "ASSIGN_LABEL_FAILED": "লেবেল নির্ধারণ ব্যর্থ হয়েছে",
"CHANGE_TEAM": "Conversation team changed", "CHANGE_TEAM": "আলাপের টিম পরিবর্তন হয়েছে",
"SUCCESS_DELETE_CONVERSATION": "Conversation deleted successfully", "SUCCESS_DELETE_CONVERSATION": "কথোপকথন সফলভাবে মুছে ফেলা হয়েছে",
"FAIL_DELETE_CONVERSATION": "Couldn't delete conversation! Try again", "FAIL_DELETE_CONVERSATION": "কথোপকথন মুছে ফেলা যায়নি! আবার চেষ্টা করুন",
"FILE_SIZE_LIMIT": "File exceeds the {MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE} MB attachment limit", "FILE_SIZE_LIMIT": "File exceeds the {MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE} MB attachment limit",
"FILE_TYPE_NOT_SUPPORTED": "This {fileName} file type is not supported in this conversation", "FILE_TYPE_NOT_SUPPORTED": "This {fileName} file type is not supported in this conversation",
"MESSAGE_ERROR": "Unable to send this message, please try again later", "MESSAGE_ERROR": "বার্তাটি পাঠানো যায়নি, পরে আবার চেষ্টা করুন",
"SENT_BY": "Sent by:", "SENT_BY": "প্রেরক:",
"BOT": "Bot", "BOT": "Bot",
"NATIVE_APP": "Native app", "NATIVE_APP": "নেটিভ অ্যাপ",
"NATIVE_APP_ADVISORY": "This message was sent from the native app. Reply from Chatwoot to maintain the message window.", "NATIVE_APP_ADVISORY": "এই বার্তাটি নেটিভ অ্যাপ থেকে পাঠানো হয়েছে। বার্তা উইন্ডো বজায় রাখতে Chatwoot থেকে উত্তর দিন।",
"SEND_FAILED": "Couldn't send message! Try again", "SEND_FAILED": "বার্তা পাঠানো যায়নি! আবার চেষ্টা করুন",
"TRY_AGAIN": "retry", "TRY_AGAIN": "পুনরায় চেষ্টা করুন",
"ASSIGNMENT": { "ASSIGNMENT": {
"SELECT_AGENT": "Select Agent", "SELECT_AGENT": "এজেন্ট নির্বাচন করুন",
"REMOVE": "Remove", "REMOVE": "সরান",
"ASSIGN": "Assign" "ASSIGN": "নিয়োগ করুন"
}, },
"CONTEXT_MENU": { "CONTEXT_MENU": {
"COPY": "Copy", "COPY": "কপি করুন",
"REPLY_TO": "Reply to this message", "REPLY_TO": "এই বার্তায় উত্তর দিন",
"DELETE": "Delete", "DELETE": "মুছুন",
"CREATE_A_CANNED_RESPONSE": "Add to canned responses", "CREATE_A_CANNED_RESPONSE": "ক্যানড রেসপন্সে যোগ করুন",
"TRANSLATE": "Translate", "TRANSLATE": "অনুবাদ করুন",
"COPY_PERMALINK": "Copy link to the message", "COPY_PERMALINK": "বার্তার লিঙ্ক কপি করুন",
"LINK_COPIED": "Message URL copied to the clipboard", "LINK_COPIED": "বার্তার URL ক্লিপবোর্ডে কপি হয়েছে",
"DELETE_CONFIRMATION": { "DELETE_CONFIRMATION": {
"TITLE": "Are you sure you want to delete this message?", "TITLE": "আপনি কি নিশ্চিত এই বার্তাটি মুছে ফেলতে চান?",
"MESSAGE": "You cannot undo this action", "MESSAGE": "এই কাজটি পূর্বাবস্থায় ফেরানো যাবে না",
"DELETE": "Delete", "DELETE": "মুছে ফেলুন",
"CANCEL": "Cancel" "CANCEL": "বাতিল করুন"
} }
}, },
"SIDEBAR": { "SIDEBAR": {
"CONTACT": "Contact", "CONTACT": "যোগাযোগ",
"COPILOT": "Copilot" "COPILOT": "Copilot"
}, },
"VOICE_WIDGET": { "VOICE_WIDGET": {
"INCOMING_CALL": "Incoming call", "INCOMING_CALL": "আসন্ন কল",
"OUTGOING_CALL": "Outgoing call", "OUTGOING_CALL": "প্রেরিত কল",
"CALL_IN_PROGRESS": "Call in progress", "CALL_IN_PROGRESS": "কল চলছে",
"NOT_ANSWERED_YET": "Not answered yet", "NOT_ANSWERED_YET": "এখনও উত্তর পাওয়া যায়নি",
"HANDLED_IN_ANOTHER_TAB": "Being handled in another tab", "HANDLED_IN_ANOTHER_TAB": "অন্য ট্যাবে পরিচালিত হচ্ছে",
"REJECT_CALL": "Reject", "REJECT_CALL": "প্রত্যাখ্যান করুন",
"JOIN_CALL": "Join call", "JOIN_CALL": "কলে যোগ দিন",
"END_CALL": "End call" "END_CALL": "কল শেষ করুন"
} }
}, },
"EMAIL_TRANSCRIPT": { "EMAIL_TRANSCRIPT": {
"TITLE": "Send conversation transcript", "TITLE": "কথোপকথনের ট্রান্সক্রিপ্ট পাঠান",
"DESC": "Send a copy of the conversation transcript to the specified email address", "DESC": "নির্দিষ্ট ইমেইল ঠিকানায় কথোপকথনের ট্রান্সক্রিপ্ট পাঠান",
"SUBMIT": "Submit", "SUBMIT": "জমা দিন",
"CANCEL": "Cancel", "CANCEL": "বাতিল করুন",
"SEND_EMAIL_SUCCESS": "The chat transcript was sent successfully", "SEND_EMAIL_SUCCESS": "চ্যাট ট্রান্সক্রিপ্ট সফলভাবে পাঠানো হয়েছে",
"SEND_EMAIL_ERROR": "There was an error, please try again", "SEND_EMAIL_ERROR": "একটি ত্রুটি হয়েছে, অনুগ্রহ করে আবার চেষ্টা করুন",
"SEND_EMAIL_PAYMENT_REQUIRED": "Email transcript is not available on your current plan. Please upgrade to use this feature.", "SEND_EMAIL_PAYMENT_REQUIRED": "আপনার বর্তমান প্ল্যানে ইমেইল ট্রান্সক্রিপ্ট সুবিধা নেই। এই ফিচারটি ব্যবহার করতে প্ল্যান আপগ্রেড করুন।",
"FORM": { "FORM": {
"SEND_TO_CONTACT": "Send the transcript to the customer", "SEND_TO_CONTACT": "গ্রাহককে ট্রান্সক্রিপ্ট পাঠান",
"SEND_TO_AGENT": "Send the transcript to the assigned agent", "SEND_TO_AGENT": "নিয়োজিত এজেন্টকে ট্রান্সক্রিপ্ট পাঠান",
"SEND_TO_OTHER_EMAIL_ADDRESS": "Send the transcript to another email address", "SEND_TO_OTHER_EMAIL_ADDRESS": "অন্য ইমেইল ঠিকানায় ট্রান্সক্রিপ্ট পাঠান",
"EMAIL": { "EMAIL": {
"PLACEHOLDER": "Enter an email address", "PLACEHOLDER": "ইমেইল ঠিকানা লিখুন",
"ERROR": "Please enter a valid email address" "ERROR": "একটি বৈধ ইমেইল ঠিকানা লিখুন"
} }
} }
}, },
@@ -323,120 +323,120 @@
"GREETING_MORNING": "👋 Good morning, {name}. Welcome to {installationName}.", "GREETING_MORNING": "👋 Good morning, {name}. Welcome to {installationName}.",
"GREETING_AFTERNOON": "👋 Good afternoon, {name}. Welcome to {installationName}.", "GREETING_AFTERNOON": "👋 Good afternoon, {name}. Welcome to {installationName}.",
"GREETING_EVENING": "👋 Good evening, {name}. Welcome to {installationName}.", "GREETING_EVENING": "👋 Good evening, {name}. Welcome to {installationName}.",
"READ_LATEST_UPDATES": "Read our latest updates", "READ_LATEST_UPDATES": "আমাদের সর্বশেষ আপডেট পড়ুন",
"ALL_CONVERSATION": { "ALL_CONVERSATION": {
"TITLE": "All your conversations in one place", "TITLE": "আপনার সব কথোপকথন এক জায়গায়",
"DESCRIPTION": "View all the conversations from your customers in one single dashboard. You can filter the conversations by the incoming channel, label and status.", "DESCRIPTION": "একটি ড্যাশবোর্ডে আপনার গ্রাহকদের সব কথোপকথন দেখুন। আপনি চ্যানেল, লেবেল ও স্ট্যাটাস অনুযায়ী ফিল্টার করতে পারবেন।",
"NEW_LINK": "Click here to create an inbox" "NEW_LINK": "ইনবক্স তৈরি করতে এখানে ক্লিক করুন"
}, },
"TEAM_MEMBERS": { "TEAM_MEMBERS": {
"TITLE": "Invite your team members", "TITLE": "আপনার টিম সদস্যদের আমন্ত্রণ জানান",
"DESCRIPTION": "Since you are getting ready to talk to your customer, bring in your teammates to assist you. You can invite your teammates by adding their email addresses to the agent list.", "DESCRIPTION": "আপনি যখন গ্রাহকের সাথে কথা বলার জন্য প্রস্তুতি নিচ্ছেন, তখন সহায়তার জন্য আপনার টিমমেটদের যুক্ত করুন। এজেন্ট তালিকায় তাদের ইমেইল ঠিকানা যোগ করে আমন্ত্রণ জানাতে পারেন।",
"NEW_LINK": "Click here to invite a team member" "NEW_LINK": "টিম সদস্য আমন্ত্রণ জানাতে এখানে ক্লিক করুন"
}, },
"LABELS": { "LABELS": {
"TITLE": "Organize conversations with labels", "TITLE": "লেবেল দিয়ে কথোপকথন সাজান",
"DESCRIPTION": "Labels provide an easier way to categorize your conversation. Create some labels like #support-enquiry, #billing-question etc., so that you can use them in a conversation later.", "DESCRIPTION": "লেবেল ব্যবহার করে সহজেই কথোপকথন শ্রেণিবদ্ধ করুন। যেমন #support-enquiry, #billing-question ইত্যাদি লেবেল তৈরি করুন, পরে কথোপকথনে ব্যবহার করতে পারবেন।",
"NEW_LINK": "Click here to create tags" "NEW_LINK": "ট্যাগ তৈরি করতে এখানে ক্লিক করুন"
}, },
"CANNED_RESPONSES": { "CANNED_RESPONSES": {
"TITLE": "Create canned responses", "TITLE": "ক্যানড রেসপন্স তৈরি করুন",
"DESCRIPTION": "Pre-written quick reply templates help you quickly respond to a conversation. Agents can type the '/' character followed by the shortcode to insert a response.", "DESCRIPTION": "আগে থেকে লেখা দ্রুত উত্তর টেমপ্লেট দিয়ে সহজেই কথোপকথনে উত্তর দিন। এজেন্টরা '/' চিহ্ন ও শর্টকোড লিখে দ্রুত উত্তর যোগ করতে পারেন।",
"NEW_LINK": "Click here to create a canned response" "NEW_LINK": "ক্যানড রেসপন্স তৈরি করতে এখানে ক্লিক করুন"
} }
}, },
"CONVERSATION_SIDEBAR": { "CONVERSATION_SIDEBAR": {
"ASSIGNEE_LABEL": "Assigned Agent", "ASSIGNEE_LABEL": "নিযুক্ত এজেন্ট",
"SELF_ASSIGN": "Assign to me", "SELF_ASSIGN": "নিজেকে নির্ধারণ করুন",
"TEAM_LABEL": "Assigned Team", "TEAM_LABEL": "নিযুক্ত টিম",
"SELECT": { "SELECT": {
"PLACEHOLDER": "None" "PLACEHOLDER": "কিছুই না"
}, },
"ACCORDION": { "ACCORDION": {
"CONTACT_DETAILS": "Contact Details", "CONTACT_DETAILS": "যোগাযোগের বিবরণ",
"CONVERSATION_ACTIONS": "Conversation Actions", "CONVERSATION_ACTIONS": "আলোচনার কার্যক্রম",
"CONVERSATION_LABELS": "Conversation Labels", "CONVERSATION_LABELS": "আলোচনার লেবেল",
"CONVERSATION_INFO": "Conversation Information", "CONVERSATION_INFO": "আলোচনার তথ্য",
"CONTACT_NOTES": "Contact Notes", "CONTACT_NOTES": "যোগাযোগ নোট",
"CONTACT_ATTRIBUTES": "Contact Attributes", "CONTACT_ATTRIBUTES": "যোগাযোগের বৈশিষ্ট্য",
"PREVIOUS_CONVERSATION": "Previous Conversations", "PREVIOUS_CONVERSATION": "পূর্বের আলোচনা",
"MACROS": "Macros", "MACROS": "ম্যাক্রো",
"LINEAR_ISSUES": "Linked Linear Issues", "LINEAR_ISSUES": "সংযুক্ত Linear সমস্যা",
"SHOPIFY_ORDERS": "Shopify Orders" "SHOPIFY_ORDERS": "Shopify অর্ডার"
}, },
"SHOPIFY": { "SHOPIFY": {
"ORDER_ID": "Order #{id}", "ORDER_ID": "Order #{id}",
"ERROR": "Error loading orders", "ERROR": "অর্ডার লোড করতে সমস্যা হয়েছে",
"NO_SHOPIFY_ORDERS": "No orders found", "NO_SHOPIFY_ORDERS": "কোনো অর্ডার পাওয়া যায়নি",
"FINANCIAL_STATUS": { "FINANCIAL_STATUS": {
"PENDING": "Pending", "PENDING": "অপেক্ষমাণ",
"AUTHORIZED": "Authorized", "AUTHORIZED": "অনুমোদিত",
"PARTIALLY_PAID": "Partially Paid", "PARTIALLY_PAID": "আংশিক পরিশোধিত",
"PAID": "Paid", "PAID": "পরিশোধিত",
"PARTIALLY_REFUNDED": "Partially Refunded", "PARTIALLY_REFUNDED": "আংশিক ফেরত",
"REFUNDED": "Refunded", "REFUNDED": "ফেরত",
"VOIDED": "Voided" "VOIDED": "বাতিল"
}, },
"FULFILLMENT_STATUS": { "FULFILLMENT_STATUS": {
"FULFILLED": "Fulfilled", "FULFILLED": "সম্পন্ন",
"PARTIALLY_FULFILLED": "Partially Fulfilled", "PARTIALLY_FULFILLED": "আংশিক সম্পন্ন",
"UNFULFILLED": "Unfulfilled" "UNFULFILLED": "অসম্পন্ন"
} }
} }
}, },
"CONVERSATION_CUSTOM_ATTRIBUTES": { "CONVERSATION_CUSTOM_ATTRIBUTES": {
"ADD_BUTTON_TEXT": "Create attribute", "ADD_BUTTON_TEXT": "অ্যাট্রিবিউট তৈরি করুন",
"NO_RECORDS_FOUND": "No attributes found", "NO_RECORDS_FOUND": "কোনো অ্যাট্রিবিউট পাওয়া যায়নি",
"UPDATE": { "UPDATE": {
"SUCCESS": "Attribute updated successfully", "SUCCESS": "অ্যাট্রিবিউট সফলভাবে আপডেট হয়েছে",
"ERROR": "Unable to update attribute. Please try again later" "ERROR": "অ্যাট্রিবিউট আপডেট করা যায়নি। পরে আবার চেষ্টা করুন"
}, },
"ADD": { "ADD": {
"TITLE": "Add", "TITLE": "যোগ করুন",
"SUCCESS": "Attribute added successfully", "SUCCESS": "অ্যাট্রিবিউট সফলভাবে যোগ হয়েছে",
"ERROR": "Unable to add attribute. Please try again later" "ERROR": "অ্যাট্রিবিউট যোগ করা যায়নি। পরে আবার চেষ্টা করুন"
}, },
"DELETE": { "DELETE": {
"SUCCESS": "Attribute deleted successfully", "SUCCESS": "অ্যাট্রিবিউট সফলভাবে মুছে ফেলা হয়েছে",
"ERROR": "Unable to delete attribute. Please try again later" "ERROR": "অ্যাট্রিবিউট মুছে ফেলা যায়নি। পরে আবার চেষ্টা করুন"
}, },
"ATTRIBUTE_SELECT": { "ATTRIBUTE_SELECT": {
"TITLE": "Add attributes", "TITLE": "অ্যাট্রিবিউট যোগ করুন",
"PLACEHOLDER": "Search attributes", "PLACEHOLDER": "অ্যাট্রিবিউট অনুসন্ধান করুন",
"NO_RESULT": "No attributes found" "NO_RESULT": "কোনো অ্যাট্রিবিউট পাওয়া যায়নি"
} }
}, },
"EMAIL_HEADER": { "EMAIL_HEADER": {
"FROM": "From", "FROM": "প্রেরক",
"TO": "To", "TO": "প্রাপক",
"BCC": "Bcc", "BCC": "বিসিসি",
"CC": "Cc", "CC": "সিসি",
"SUBJECT": "Subject", "SUBJECT": "বিষয়",
"EXPAND": "Expand email" "EXPAND": "ইমেইল প্রসারিত করুন"
}, },
"CONVERSATION_PARTICIPANTS": { "CONVERSATION_PARTICIPANTS": {
"SIDEBAR_MENU_TITLE": "Participating", "SIDEBAR_MENU_TITLE": "অংশগ্রহণকারী",
"SIDEBAR_TITLE": "Conversation participants", "SIDEBAR_TITLE": "আলোচনার অংশগ্রহণকারীরা",
"NO_RECORDS_FOUND": "No results found", "NO_RECORDS_FOUND": "কোনো ফলাফল পাওয়া যায়নি",
"ADD_PARTICIPANTS": "Select participants", "ADD_PARTICIPANTS": "অংশগ্রহণকারী নির্বাচন করুন",
"REMANING_PARTICIPANTS_TEXT": "+{count} others", "REMANING_PARTICIPANTS_TEXT": "+{count} others",
"REMANING_PARTICIPANT_TEXT": "+{count} other", "REMANING_PARTICIPANT_TEXT": "+{count} other",
"TOTAL_PARTICIPANTS_TEXT": "{count} people are participating.", "TOTAL_PARTICIPANTS_TEXT": "{count} people are participating.",
"TOTAL_PARTICIPANT_TEXT": "{count} person is participating.", "TOTAL_PARTICIPANT_TEXT": "{count} person is participating.",
"NO_PARTICIPANTS_TEXT": "No one is participating!.", "NO_PARTICIPANTS_TEXT": "No one is participating!.",
"WATCH_CONVERSATION": "Join conversation", "WATCH_CONVERSATION": "আলাপচারিতায় যোগ দিন",
"YOU_ARE_WATCHING": "You are participating", "YOU_ARE_WATCHING": "আপনি অংশগ্রহণ করছেন",
"API": { "API": {
"ERROR_MESSAGE": "Could not update, try again!", "ERROR_MESSAGE": "আপডেট করা যায়নি, আবার চেষ্টা করুন!",
"SUCCESS_MESSAGE": "Participants updated!" "SUCCESS_MESSAGE": "অংশগ্রহণকারীরা আপডেট হয়েছে!"
} }
}, },
"TRANSLATE_MODAL": { "TRANSLATE_MODAL": {
"TITLE": "View translated content", "TITLE": "অনুবাদিত বিষয়বস্তু দেখুন",
"DESC": "You can view the translated content in each langauge.", "DESC": "You can view the translated content in each langauge.",
"ORIGINAL_CONTENT": "Original Content", "ORIGINAL_CONTENT": "মূল বিষয়বস্তু",
"TRANSLATED_CONTENT": "Translated Content", "TRANSLATED_CONTENT": "অনুবাদিত বিষয়বস্তু",
"NO_TRANSLATIONS_AVAILABLE": "No translations are available for this content" "NO_TRANSLATIONS_AVAILABLE": "এই বিষয়বস্তুর জন্য কোনো অনুবাদ নেই"
}, },
"TYPING": { "TYPING": {
"ONE": "{user} is typing", "ONE": "{user} is typing",
@@ -444,9 +444,9 @@
"MULTIPLE": "{user} and {count} others are typing" "MULTIPLE": "{user} and {count} others are typing"
}, },
"COPILOT": { "COPILOT": {
"TRY_THESE_PROMPTS": "Try these prompts" "TRY_THESE_PROMPTS": "এই পরামর্শগুলো চেষ্টা করুন"
}, },
"GALLERY_VIEW": { "GALLERY_VIEW": {
"ERROR_DOWNLOADING": "Unable to download attachment. Please try again" "ERROR_DOWNLOADING": "সংযুক্তি ডাউনলোড করা যাচ্ছে না। আবার চেষ্টা করুন"
} }
} }
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,106 +1,106 @@
{ {
"MFA_SETTINGS": { "MFA_SETTINGS": {
"TITLE": "Two-Factor Authentication", "TITLE": "দ্বি-স্তরীয় প্রমাণীকরণ",
"SUBTITLE": "Protect your account from unauthorized access with TOTP-based authentication. This adds an extra layer of security to your account.", "SUBTITLE": "TOTP-ভিত্তিক প্রমাণীকরণের মাধ্যমে আপনার অ্যাকাউন্টকে অননুমোদিত প্রবেশ থেকে সুরক্ষিত করুন। এটি আপনার অ্যাকাউন্টে অতিরিক্ত নিরাপত্তা যোগ করে.",
"DESCRIPTION": "Add an extra layer of security to your account using a time-based one-time password (TOTP)", "DESCRIPTION": "সময়-ভিত্তিক একবারের পাসওয়ার্ড (TOTP) ব্যবহার করে আপনার অ্যাকাউন্টে অতিরিক্ত নিরাপত্তা যোগ করুন",
"STATUS_TITLE": "Authentication Status", "STATUS_TITLE": "প্রমাণীকরণের অবস্থা",
"STATUS_DESCRIPTION": "Manage your two-factor authentication settings and backup recovery codes", "STATUS_DESCRIPTION": "আপনার দ্বি-স্তরীয় প্রমাণীকরণ সেটিংস এবং ব্যাকআপ পুনরুদ্ধার কোডগুলি পরিচালনা করুন",
"ENABLED": "Enabled", "ENABLED": "সক্রিয়",
"DISABLED": "Disabled", "DISABLED": "নিষ্ক্রিয়",
"STATUS_ENABLED": "Two-factor authentication is active", "STATUS_ENABLED": "দ্বি-স্তরীয় প্রমাণীকরণ সক্রিয় আছে",
"STATUS_ENABLED_DESC": "Your account is protected with an additional layer of security", "STATUS_ENABLED_DESC": "আপনার অ্যাকাউন্ট অতিরিক্ত নিরাপত্তা স্তর দ্বারা সুরক্ষিত",
"ENABLE_BUTTON": "Enable Two-Factor Authentication", "ENABLE_BUTTON": "দ্বি-স্তরীয় প্রমাণীকরণ চালু করুন",
"ENHANCE_SECURITY": "Enhance Your Account Security", "ENHANCE_SECURITY": "আপনার অ্যাকাউন্টের নিরাপত্তা বৃদ্ধি করুন",
"ENHANCE_SECURITY_DESC": "Two-factor authentication adds an extra layer of security by requiring a verification code from your authenticator app in addition to your password.", "ENHANCE_SECURITY_DESC": "দ্বি-স্তরীয় প্রমাণীকরণ আপনার নিরাপত্তা আরও বাড়ায়, কারণ এটি আপনার পাসওয়ার্ডের পাশাপাশি আপনার authenticator অ্যাপ থেকে একটি যাচাইকরণ কোড চায়.",
"SETUP": { "SETUP": {
"STEP_NUMBER_1": "1", "STEP_NUMBER_1": "",
"STEP_NUMBER_2": "2", "STEP_NUMBER_2": "",
"STEP1_TITLE": "Scan QR Code with Your Authenticator App", "STEP1_TITLE": "আপনার Authenticator অ্যাপ দিয়ে QR কোড স্ক্যান করুন",
"STEP1_DESCRIPTION": "Use Google Authenticator, Authy, or any TOTP-compatible app", "STEP1_DESCRIPTION": "Google Authenticator, Authy, অথবা যেকোনো TOTP-সামঞ্জস্যপূর্ণ অ্যাপ ব্যবহার করুন",
"LOADING_QR": "Loading...", "LOADING_QR": "লোড হচ্ছে...",
"MANUAL_ENTRY": "Can't scan? Enter code manually", "MANUAL_ENTRY": "স্ক্যান করতে পারছেন না? কোডটি ম্যানুয়ালি লিখুন",
"SECRET_KEY": "Secret Key", "SECRET_KEY": "সিক্রেট কী",
"COPY": "Copy", "COPY": "কপি করুন",
"ENTER_CODE": "Enter the 6-digit code from your authenticator app", "ENTER_CODE": "আপনার অথেন্টিকেটর অ্যাপ থেকে ৬-সংখ্যার কোডটি লিখুন",
"ENTER_CODE_PLACEHOLDER": "000000", "ENTER_CODE_PLACEHOLDER": "০০০০০০",
"VERIFY_BUTTON": "Verify & Continue", "VERIFY_BUTTON": "যাচাই করুন ও চালিয়ে যান",
"CANCEL": "Cancel", "CANCEL": "বাতিল করুন",
"ERROR_STARTING": "MFA not enabled. Please contact administrator.", "ERROR_STARTING": "MFA সক্রিয় নয়। অনুগ্রহ করে প্রশাসকের সাথে যোগাযোগ করুন.",
"INVALID_CODE": "Invalid verification code", "INVALID_CODE": "ভুল যাচাইকরণ কোড",
"SECRET_COPIED": "Secret key copied to clipboard", "SECRET_COPIED": "সিক্রেট কী ক্লিপবোর্ডে কপি করা হয়েছে",
"SUCCESS": "Two-factor authentication has been enabled successfully" "SUCCESS": "দ্বৈত-ধাপ যাচাইকরণ সফলভাবে সক্রিয় করা হয়েছে"
}, },
"BACKUP": { "BACKUP": {
"TITLE": "Save Your Backup Codes", "TITLE": "আপনার ব্যাকআপ কোড সংরক্ষণ করুন",
"DESCRIPTION": "Keep these codes safe. Each can be used once if you lose access to your authenticator", "DESCRIPTION": "এই কোডগুলো নিরাপদে রাখুন। আপনার অথেন্টিকেটরে প্রবেশ হারালে প্রতিটি কোড একবার করে ব্যবহার করা যাবে",
"IMPORTANT": "Important:", "IMPORTANT": "গুরুত্বপূর্ণ:",
"IMPORTANT_NOTE": " Save these codes in a secure location. You won't be able to see them again.", "IMPORTANT_NOTE": " এই কোডগুলো নিরাপদ স্থানে সংরক্ষণ করুন। আপনি এগুলো আর দেখতে পারবেন না.",
"DOWNLOAD": "Download", "DOWNLOAD": "ডাউনলোড করুন",
"COPY_ALL": "Copy All", "COPY_ALL": "সব কপি করুন",
"CONFIRM": "I have saved my backup codes in a secure location and understand that I won't be able to see them again", "CONFIRM": "আমি আমার ব্যাকআপ কোডগুলো নিরাপদ স্থানে সংরক্ষণ করেছি এবং বুঝতে পেরেছি যে এগুলো আমি আর দেখতে পারব না",
"COMPLETE_SETUP": "Complete Setup", "COMPLETE_SETUP": "সেটআপ সম্পন্ন করুন",
"CODES_COPIED": "Backup codes copied to clipboard" "CODES_COPIED": "ব্যাকআপ কোডগুলো ক্লিপবোর্ডে কপি করা হয়েছে"
}, },
"MANAGEMENT": { "MANAGEMENT": {
"BACKUP_CODES": "Backup Codes", "BACKUP_CODES": "ব্যাকআপ কোড",
"BACKUP_CODES_DESC": "Generate new codes if you've lost or used your existing ones", "BACKUP_CODES_DESC": "আপনার বিদ্যমান কোডগুলো হারিয়ে গেলে বা ব্যবহার হয়ে গেলে নতুন কোড তৈরি করুন",
"REGENERATE": "Regenerate Backup Codes", "REGENERATE": "ব্যাকআপ কোড পুনরায় তৈরি করুন",
"DISABLE_MFA": "Disable 2FA", "DISABLE_MFA": "২এফএ নিষ্ক্রিয় করুন",
"DISABLE_MFA_DESC": "Remove two-factor authentication from your account", "DISABLE_MFA_DESC": "আপনার অ্যাকাউন্ট থেকে দুই-ধাপ যাচাইকরণ সরান",
"DISABLE_BUTTON": "Disable Two-Factor Authentication" "DISABLE_BUTTON": "দুই-ধাপ যাচাইকরণ নিষ্ক্রিয় করুন"
}, },
"DISABLE": { "DISABLE": {
"TITLE": "Disable Two-Factor Authentication", "TITLE": "দুই-ধাপ যাচাইকরণ নিষ্ক্রিয় করুন",
"DESCRIPTION": "You'll need to enter your password and a verification code to disable two-factor authentication.", "DESCRIPTION": "দুই-ধাপ যাচাইকরণ নিষ্ক্রিয় করতে আপনাকে আপনার পাসওয়ার্ড এবং একটি যাচাইকরণ কোড প্রবেশ করতে হবে.",
"PASSWORD": "Password", "PASSWORD": "পাসওয়ার্ড",
"OTP_CODE": "Verification Code", "OTP_CODE": "ভেরিফিকেশন কোড",
"OTP_CODE_PLACEHOLDER": "000000", "OTP_CODE_PLACEHOLDER": "০০০০০০",
"CONFIRM": "Disable 2FA", "CONFIRM": "2FA নিষ্ক্রিয় করুন",
"CANCEL": "Cancel", "CANCEL": "বাতিল করুন",
"SUCCESS": "Two-factor authentication has been disabled", "SUCCESS": "টু-ফ্যাক্টর অথেন্টিকেশন নিষ্ক্রিয় করা হয়েছে",
"ERROR": "Failed to disable MFA. Please check your credentials." "ERROR": "MFA নিষ্ক্রিয় করতে ব্যর্থ হয়েছে। অনুগ্রহ করে আপনার শংসাপত্র যাচাই করুন."
}, },
"REGENERATE": { "REGENERATE": {
"TITLE": "Regenerate Backup Codes", "TITLE": "ব্যাকআপ কোড পুনরায় তৈরি করুন",
"DESCRIPTION": "This will invalidate your existing backup codes and generate new ones. Enter your verification code to continue.", "DESCRIPTION": "এটি আপনার বর্তমান ব্যাকআপ কোডসমূহ বাতিল করবে এবং নতুন কোড তৈরি করবে। চালিয়ে যেতে আপনার যাচাইকরণ কোড দিন.",
"OTP_CODE": "Verification Code", "OTP_CODE": "যাচাইকরণ কোড",
"OTP_CODE_PLACEHOLDER": "000000", "OTP_CODE_PLACEHOLDER": "০০০০০০",
"CONFIRM": "Generate New Codes", "CONFIRM": "নতুন কোড তৈরি করুন",
"CANCEL": "Cancel", "CANCEL": "বাতিল করুন",
"NEW_CODES_TITLE": "New Backup Codes Generated", "NEW_CODES_TITLE": "নতুন ব্যাকআপ কোড তৈরি হয়েছে",
"NEW_CODES_DESC": "Your old backup codes have been invalidated. Save these new codes in a secure location.", "NEW_CODES_DESC": "আপনার পুরোনো ব্যাকআপ কোডগুলো বাতিল করা হয়েছে। এই নতুন কোডগুলো নিরাপদ স্থানে সংরক্ষণ করুন.",
"CODES_IMPORTANT": "Important:", "CODES_IMPORTANT": "গুরুত্বপূর্ণ:",
"CODES_IMPORTANT_NOTE": " Each code can only be used once. Save them before closing this window.", "CODES_IMPORTANT_NOTE": " প্রতিটি কোড শুধুমাত্র একবার ব্যবহার করা যাবে। এই উইন্ডো বন্ধ করার আগে কোডগুলো সংরক্ষণ করুন.",
"DOWNLOAD_CODES": "Download Codes", "DOWNLOAD_CODES": "কোড ডাউনলোড করুন",
"COPY_ALL_CODES": "Copy All Codes", "COPY_ALL_CODES": "সব কোড কপি করুন",
"CODES_SAVED": "I've Saved My Codes", "CODES_SAVED": "আমি আমার কোডগুলো সংরক্ষণ করেছি",
"SUCCESS": "New backup codes have been generated", "SUCCESS": "নতুন ব্যাকআপ কোড তৈরি হয়েছে",
"ERROR": "Failed to regenerate backup codes" "ERROR": "ব্যাকআপ কোড পুনরায় তৈরি করতে ব্যর্থ হয়েছে"
} }
}, },
"MFA_VERIFICATION": { "MFA_VERIFICATION": {
"TITLE": "Two-Factor Authentication", "TITLE": "দ্বি-স্তরীয় প্রমাণীকরণ",
"DESCRIPTION": "Enter your verification code to continue", "DESCRIPTION": "চালিয়ে যেতে আপনার যাচাইকরণ কোড দিন",
"AUTHENTICATOR_APP": "Authenticator App", "AUTHENTICATOR_APP": "অথেন্টিকেটর অ্যাপ",
"BACKUP_CODE": "Backup Code", "BACKUP_CODE": "ব্যাকআপ কোড",
"ENTER_OTP_CODE": "Enter 6-digit code from your authenticator app", "ENTER_OTP_CODE": "আপনার authenticator অ্যাপ থেকে ৬-সংখ্যার কোডটি লিখুন",
"ENTER_BACKUP_CODE": "Enter one of your backup codes", "ENTER_BACKUP_CODE": "আপনার ব্যাকআপ কোডগুলোর মধ্যে একটি লিখুন",
"BACKUP_CODE_PLACEHOLDER": "000000", "BACKUP_CODE_PLACEHOLDER": "০০০০০০",
"VERIFY_BUTTON": "Verify", "VERIFY_BUTTON": "যাচাই করুন",
"TRY_ANOTHER_METHOD": "Try another verification method", "TRY_ANOTHER_METHOD": "অন্য একটি যাচাইকরণ পদ্ধতি চেষ্টা করুন",
"CANCEL_LOGIN": "Cancel and return to login", "CANCEL_LOGIN": "বাতিল করুন এবং লগইন পৃষ্ঠায় ফিরে যান",
"HELP_TEXT": "Having trouble signing in?", "HELP_TEXT": "সাইন ইন করতে সমস্যা হচ্ছে?",
"LEARN_MORE": "Learn more about 2FA", "LEARN_MORE": "2FA সম্পর্কে আরও জানুন",
"HELP_MODAL": { "HELP_MODAL": {
"TITLE": "Two-Factor Authentication Help", "TITLE": "টু-ফ্যাক্টর অথেন্টিকেশন সহায়তা",
"AUTHENTICATOR_TITLE": "Using an Authenticator App", "AUTHENTICATOR_TITLE": "অথেন্টিকেটর অ্যাপ ব্যবহার করা হচ্ছে",
"AUTHENTICATOR_DESC": "Open your authenticator app (Google Authenticator, Authy, etc.) and enter the 6-digit code shown for your account.", "AUTHENTICATOR_DESC": "আপনার authenticator অ্যাপ (Google Authenticator, Authy, ইত্যাদি) খুলুন এবং আপনার অ্যাকাউন্টের জন্য দেখানো ৬-সংখ্যার কোডটি লিখুন.",
"BACKUP_TITLE": "Using a Backup Code", "BACKUP_TITLE": "ব্যাকআপ কোড ব্যবহার করুন",
"BACKUP_DESC": "If you don't have access to your authenticator app, you can use one of the backup codes you saved when setting up 2FA. Each code can only be used once.", "BACKUP_DESC": "যদি আপনার authenticator অ্যাপে প্রবেশাধিকার না থাকে, তাহলে 2FA সেটআপ করার সময় সংরক্ষণ করা ব্যাকআপ কোডগুলোর যেকোনো একটি ব্যবহার করতে পারেন। প্রতিটি কোড কেবল একবারই ব্যবহার করা যাবে.",
"CONTACT_TITLE": "Need More Help?", "CONTACT_TITLE": "আরও সাহায্য দরকার?",
"CONTACT_DESC_CLOUD": "If you've lost access to both your authenticator app and backup codes, please reach out to Chatwoot support for assistance.", "CONTACT_DESC_CLOUD": "আপনি যদি আপনার authenticator অ্যাপ এবং ব্যাকআপ কোড দুটোই হারিয়ে ফেলেন, তাহলে সহায়তার জন্য অনুগ্রহ করে Chatwoot সাপোর্ট টিমের সাথে যোগাযোগ করুন.",
"CONTACT_DESC_SELF_HOSTED": "If you've lost access to both your authenticator app and backup codes, please contact your administrator for assistance." "CONTACT_DESC_SELF_HOSTED": "আপনি যদি আপনার authenticator অ্যাপ এবং ব্যাকআপ কোড দুটোই হারিয়ে ফেলেন, সহায়তার জন্য অনুগ্রহ করে আপনার অ্যাডমিনিস্ট্রেটরের সাথে যোগাযোগ করুন."
}, },
"VERIFICATION_FAILED": "Verification failed. Please try again." "VERIFICATION_FAILED": "ভেরিফিকেশন ব্যর্থ হয়েছে। অনুগ্রহ করে আবার চেষ্টা করুন."
} }
} }
@@ -1,125 +1,125 @@
{ {
"REPORT": { "REPORT": {
"HEADER": "Conversations", "HEADER": "কথোপকথন",
"LOADING_CHART": "Loading chart data...", "LOADING_CHART": "চার্ট ডেটা লোড হচ্ছে...",
"NO_ENOUGH_DATA": "We've not received enough data points to generate report, Please try again later.", "NO_ENOUGH_DATA": "রিপোর্ট তৈরি করার জন্য যথেষ্ট ডেটা নেই, পরে আবার চেষ্টা করুন।",
"DOWNLOAD_CONVERSATION_REPORTS": "Download conversation reports", "DOWNLOAD_CONVERSATION_REPORTS": "কথোপকথনের রিপোর্ট ডাউনলোড করুন",
"DATA_FETCHING_FAILED": "Failed to fetch data, please try again later.", "DATA_FETCHING_FAILED": "তথ্য আনতে ব্যর্থ হয়েছে, পরে আবার চেষ্টা করুন।",
"SUMMARY_FETCHING_FAILED": "Failed to fetch summary, please try again later.", "SUMMARY_FETCHING_FAILED": "সারাংশ আনতে ব্যর্থ হয়েছে, পরে আবার চেষ্টা করুন।",
"METRICS": { "METRICS": {
"CONVERSATIONS": { "CONVERSATIONS": {
"NAME": "Conversations", "NAME": "কনভার্সেশন",
"DESC": "( Total )" "DESC": "( মোট )"
}, },
"INCOMING_MESSAGES": { "INCOMING_MESSAGES": {
"NAME": "Messages received", "NAME": "প্রাপ্ত বার্তা",
"DESC": "( Total )" "DESC": "( মোট )"
}, },
"OUTGOING_MESSAGES": { "OUTGOING_MESSAGES": {
"NAME": "Messages sent", "NAME": "প্রেরিত বার্তা",
"DESC": "( Total )" "DESC": "( মোট )"
}, },
"FIRST_RESPONSE_TIME": { "FIRST_RESPONSE_TIME": {
"NAME": "First Response Time", "NAME": "প্রথম সাড়া দেওয়ার সময়",
"DESC": "( Avg )", "DESC": "( গড় )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "গণনার জন্য ব্যবহৃত মোট কথোপকথনের সংখ্যা:",
"TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)"
}, },
"RESOLUTION_TIME": { "RESOLUTION_TIME": {
"NAME": "Resolution Time", "NAME": "সমাধানের সময়",
"DESC": "( Avg )", "DESC": "( গড় )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "গণনার জন্য ব্যবহৃত মোট কথোপকথনের সংখ্যা:",
"TOOLTIP_TEXT": "Resolution Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "Resolution Time is {metricValue} (based on {conversationCount} conversations)"
}, },
"RESOLUTION_COUNT": { "RESOLUTION_COUNT": {
"NAME": "Resolution Count", "NAME": "সমাধানের সংখ্যা",
"DESC": "( Total )" "DESC": "( মোট )"
}, },
"BOT_RESOLUTION_COUNT": { "BOT_RESOLUTION_COUNT": {
"NAME": "Resolution Count", "NAME": "সমাধানের সংখ্যা",
"DESC": "( Total )" "DESC": "( মোট )"
}, },
"BOT_HANDOFF_COUNT": { "BOT_HANDOFF_COUNT": {
"NAME": "Handoff Count", "NAME": "হস্তান্তরের সংখ্যা",
"DESC": "( Total )" "DESC": "( মোট )"
}, },
"REPLY_TIME": { "REPLY_TIME": {
"NAME": "Customer waiting time", "NAME": "গ্রাহকের অপেক্ষার সময়",
"TOOLTIP_TEXT": "Waiting time is {metricValue} (based on {conversationCount} replies)", "TOOLTIP_TEXT": "Waiting time is {metricValue} (based on {conversationCount} replies)",
"DESC": "" "DESC": ""
} }
}, },
"DATE_RANGE_OPTIONS": { "DATE_RANGE_OPTIONS": {
"LAST_7_DAYS": "Last 7 days", "LAST_7_DAYS": "গত দিন",
"LAST_14_DAYS": "Last 14 days", "LAST_14_DAYS": "গত ১৪ দিন",
"LAST_30_DAYS": "Last 30 days", "LAST_30_DAYS": "গত ৩০ দিন",
"THIS_MONTH": "This month", "THIS_MONTH": "এই মাস",
"LAST_MONTH": "Last month", "LAST_MONTH": "গত মাস",
"LAST_3_MONTHS": "Last 3 months", "LAST_3_MONTHS": "গত ৩ মাস",
"LAST_6_MONTHS": "Last 6 months", "LAST_6_MONTHS": "গত ৬ মাস",
"LAST_YEAR": "Last year", "LAST_YEAR": "গত বছর",
"CUSTOM_DATE_RANGE": "Custom date range" "CUSTOM_DATE_RANGE": "কাস্টম তারিখ পরিসর"
}, },
"CUSTOM_DATE_RANGE": { "CUSTOM_DATE_RANGE": {
"CONFIRM": "Apply", "CONFIRM": "প্রয়োগ করুন",
"PLACEHOLDER": "Select date range" "PLACEHOLDER": "তারিখ নির্বাচন করুন"
}, },
"GROUP_BY_FILTER_DROPDOWN_LABEL": "Group By", "GROUP_BY_FILTER_DROPDOWN_LABEL": "গ্রুপ করুন",
"DURATION_FILTER_LABEL": "Duration", "DURATION_FILTER_LABEL": "সময়কাল",
"GROUPING_OPTIONS": { "GROUPING_OPTIONS": {
"DAY": "Day", "DAY": "দিন",
"WEEK": "Week", "WEEK": "সপ্তাহ",
"MONTH": "Month", "MONTH": "মাস",
"YEAR": "Year" "YEAR": "বছর"
}, },
"GROUP_BY_DAY_OPTIONS": [ "GROUP_BY_DAY_OPTIONS": [
{ {
"id": 1, "id": 1,
"groupBy": "Day" "groupBy": "দিন"
} }
], ],
"GROUP_BY_WEEK_OPTIONS": [ "GROUP_BY_WEEK_OPTIONS": [
{ {
"id": 1, "id": 1,
"groupBy": "Day" "groupBy": "দিন"
}, },
{ {
"id": 2, "id": 2,
"groupBy": "Week" "groupBy": "সপ্তাহ"
} }
], ],
"GROUP_BY_MONTH_OPTIONS": [ "GROUP_BY_MONTH_OPTIONS": [
{ {
"id": 1, "id": 1,
"groupBy": "Day" "groupBy": "দিন"
}, },
{ {
"id": 2, "id": 2,
"groupBy": "Week" "groupBy": "সপ্তাহ"
}, },
{ {
"id": 3, "id": 3,
"groupBy": "Month" "groupBy": "মাস"
} }
], ],
"GROUP_BY_YEAR_OPTIONS": [ "GROUP_BY_YEAR_OPTIONS": [
{ {
"id": 2, "id": 2,
"groupBy": "Week" "groupBy": "সপ্তাহ"
}, },
{ {
"id": 3, "id": 3,
"groupBy": "Month" "groupBy": "মাস"
}, },
{ {
"id": 4, "id": 4,
"groupBy": "Year" "groupBy": "বছর"
} }
], ],
"BUSINESS_HOURS": "Business Hours", "BUSINESS_HOURS": "ব্যবসায়িক সময়",
"FILTER_ACTIONS": { "FILTER_ACTIONS": {
"CLEAR_FILTER": "Clear filter", "CLEAR_FILTER": "ফিল্টার পরিষ্কার করুন",
"EMPTY_LIST": "No results found" "EMPTY_LIST": "কোনও ফলাফল পাওয়া যায়নি"
}, },
"PAGINATION": { "PAGINATION": {
"RESULTS": "Showing {start} to {end} of {total} results", "RESULTS": "Showing {start} to {end} of {total} results",
@@ -127,524 +127,524 @@
} }
}, },
"AGENT_REPORTS": { "AGENT_REPORTS": {
"HEADER": "Agents Overview", "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 data...", "LOADING_CHART": "চার্ট ডেটা লোড হচ্ছে...",
"NO_ENOUGH_DATA": "We've not received enough data points to generate report, Please try again later.", "NO_ENOUGH_DATA": "রিপোর্ট তৈরি করার জন্য যথেষ্ট ডেটা নেই, পরে আবার চেষ্টা করুন।",
"DOWNLOAD_AGENT_REPORTS": "Download agent reports", "DOWNLOAD_AGENT_REPORTS": "এজেন্ট রিপোর্ট ডাউনলোড করুন",
"FILTER_DROPDOWN_LABEL": "Select Agent", "FILTER_DROPDOWN_LABEL": "এজেন্ট নির্বাচন করুন",
"FILTERS": { "FILTERS": {
"INPUT_PLACEHOLDER": { "INPUT_PLACEHOLDER": {
"AGENTS": "Search agents" "AGENTS": "এজেন্ট খুঁজুন"
} }
}, },
"METRICS": { "METRICS": {
"CONVERSATIONS": { "CONVERSATIONS": {
"NAME": "Conversations", "NAME": "কনভার্সেশন",
"DESC": "( Total )" "DESC": "( মোট )"
}, },
"INCOMING_MESSAGES": { "INCOMING_MESSAGES": {
"NAME": "Incoming Messages", "NAME": "আসা বার্তা",
"DESC": "( Total )" "DESC": "( মোট )"
}, },
"OUTGOING_MESSAGES": { "OUTGOING_MESSAGES": {
"NAME": "Outgoing Messages", "NAME": "প্রেরিত বার্তা",
"DESC": "( Total )" "DESC": "( মোট )"
}, },
"FIRST_RESPONSE_TIME": { "FIRST_RESPONSE_TIME": {
"NAME": "First Response Time", "NAME": "প্রথম সাড়া দেওয়ার সময়",
"DESC": "( Avg )", "DESC": "( গড় )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "গণনার জন্য ব্যবহৃত মোট কথোপকথনের সংখ্যা:",
"TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)"
}, },
"RESOLUTION_TIME": { "RESOLUTION_TIME": {
"NAME": "Resolution Time", "NAME": "সমাধান সময়",
"DESC": "( Avg )", "DESC": "( গড় )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "গণনার জন্য ব্যবহৃত মোট কথোপকথনের সংখ্যা:",
"TOOLTIP_TEXT": "Resolution Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "Resolution Time is {metricValue} (based on {conversationCount} conversations)"
}, },
"RESOLUTION_COUNT": { "RESOLUTION_COUNT": {
"NAME": "Resolution Count", "NAME": "সমাধান সংখ্যা",
"DESC": "( Total )" "DESC": "( মোট )"
} }
}, },
"DATE_RANGE": [ "DATE_RANGE": [
{ {
"id": 0, "id": 0,
"name": "Last 7 days" "name": "গত দিন"
}, },
{ {
"id": 1, "id": 1,
"name": "Last 30 days" "name": "গত ৩০ দিন"
}, },
{ {
"id": 2, "id": 2,
"name": "Last 3 months" "name": "গত ৩ মাস"
}, },
{ {
"id": 3, "id": 3,
"name": "Last 6 months" "name": "গত ৬ মাস"
}, },
{ {
"id": 4, "id": 4,
"name": "Last year" "name": "গত বছর"
}, },
{ {
"id": 5, "id": 5,
"name": "Custom date range" "name": "কাস্টম তারিখ পরিসর"
} }
], ],
"CUSTOM_DATE_RANGE": { "CUSTOM_DATE_RANGE": {
"CONFIRM": "Apply", "CONFIRM": "প্রয়োগ করুন",
"PLACEHOLDER": "Select date range" "PLACEHOLDER": "তারিখ পরিসর নির্বাচন করুন"
} }
}, },
"LABEL_REPORTS": { "LABEL_REPORTS": {
"HEADER": "Labels Overview", "HEADER": "লেবেল সংক্ষিপ্তসার",
"DESCRIPTION": "Track label performance with key metrics including conversations, response times, resolution times, and resolved cases. Click a label name for detailed insights.", "DESCRIPTION": "কথোপকথন, সাড়া দেওয়ার সময়, সমাধানের সময় ও সমাধানকৃত কেসসহ মূল পরিসংখ্যান দিয়ে লেবেলের কার্যকারিতা ট্র্যাক করুন। বিস্তারিত জানতে লেবেলের নাম ক্লিক করুন।",
"LOADING_CHART": "Loading chart data...", "LOADING_CHART": "চার্ট ডেটা লোড হচ্ছে...",
"NO_ENOUGH_DATA": "We've not received enough data points to generate report, Please try again later.", "NO_ENOUGH_DATA": "রিপোর্ট তৈরি করার জন্য যথেষ্ট ডেটা নেই, পরে আবার চেষ্টা করুন।",
"DOWNLOAD_LABEL_REPORTS": "Download label reports", "DOWNLOAD_LABEL_REPORTS": "লেবেল রিপোর্ট ডাউনলোড করুন",
"FILTER_DROPDOWN_LABEL": "Select Label", "FILTER_DROPDOWN_LABEL": "লেবেল নির্বাচন করুন",
"FILTERS": { "FILTERS": {
"INPUT_PLACEHOLDER": { "INPUT_PLACEHOLDER": {
"LABELS": "Search labels" "LABELS": "লেবেল খুঁজুন"
} }
}, },
"METRICS": { "METRICS": {
"CONVERSATIONS": { "CONVERSATIONS": {
"NAME": "Conversations", "NAME": "কনভার্সেশন",
"DESC": "( Total )" "DESC": "( মোট )"
}, },
"INCOMING_MESSAGES": { "INCOMING_MESSAGES": {
"NAME": "Incoming Messages", "NAME": "ইনকামিং মেসেজ",
"DESC": "( Total )" "DESC": "( মোট )"
}, },
"OUTGOING_MESSAGES": { "OUTGOING_MESSAGES": {
"NAME": "Outgoing Messages", "NAME": "আউটগোয়িং মেসেজ",
"DESC": "( Total )" "DESC": "( মোট )"
}, },
"FIRST_RESPONSE_TIME": { "FIRST_RESPONSE_TIME": {
"NAME": "First Response Time", "NAME": "প্রথম সাড়া সময়",
"DESC": "( Avg )", "DESC": "( গড় )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "গণনার জন্য ব্যবহৃত মোট কথোপকথনের সংখ্যা:",
"TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)"
}, },
"RESOLUTION_TIME": { "RESOLUTION_TIME": {
"NAME": "Resolution Time", "NAME": "সমাধানের সময়",
"DESC": "( Avg )", "DESC": "( গড় )",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "গণনার জন্য ব্যবহৃত মোট কথোপকথনের সংখ্যা:",
"TOOLTIP_TEXT": "Resolution Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "Resolution Time is {metricValue} (based on {conversationCount} conversations)"
}, },
"RESOLUTION_COUNT": { "RESOLUTION_COUNT": {
"NAME": "Resolution Count", "NAME": "সমাধান সংখ্যা",
"DESC": "( Total )" "DESC": "( মোট )"
} }
}, },
"DATE_RANGE": [ "DATE_RANGE": [
{ {
"id": 0, "id": 0,
"name": "Last 7 days" "name": "গত দিন"
}, },
{ {
"id": 1, "id": 1,
"name": "Last 30 days" "name": "গত ৩০ দিন"
}, },
{ {
"id": 2, "id": 2,
"name": "Last 3 months" "name": "গত ৩ মাস"
}, },
{ {
"id": 3, "id": 3,
"name": "Last 6 months" "name": "গত ৬ মাস"
}, },
{ {
"id": 4, "id": 4,
"name": "Last year" "name": "গত বছর"
}, },
{ {
"id": 5, "id": 5,
"name": "Custom date range" "name": "কাস্টম তারিখ পরিসর"
} }
], ],
"CUSTOM_DATE_RANGE": { "CUSTOM_DATE_RANGE": {
"CONFIRM": "Apply", "CONFIRM": "প্রয়োগ করুন",
"PLACEHOLDER": "Select date range" "PLACEHOLDER": "তারিখের পরিসর নির্বাচন করুন"
} }
}, },
"INBOX_REPORTS": { "INBOX_REPORTS": {
"HEADER": "Inbox Overview", "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 data...", "LOADING_CHART": "চার্ট ডেটা লোড হচ্ছে...",
"NO_ENOUGH_DATA": "We've not received enough data points to generate report, Please try again later.", "NO_ENOUGH_DATA": "রিপোর্ট তৈরির জন্য যথেষ্ট ডেটা নেই, পরে আবার চেষ্টা করুন।",
"DOWNLOAD_INBOX_REPORTS": "Download inbox reports", "DOWNLOAD_INBOX_REPORTS": "ইনবক্স রিপোর্ট ডাউনলোড করুন",
"FILTER_DROPDOWN_LABEL": "Select Inbox", "FILTER_DROPDOWN_LABEL": "ইনবক্স নির্বাচন করুন",
"ALL_INBOXES": "All Inboxes", "ALL_INBOXES": "সব ইনবক্স",
"SEARCH_INBOX": "Search Inbox", "SEARCH_INBOX": "ইনবক্সে খুঁজুন",
"FILTERS": { "FILTERS": {
"INPUT_PLACEHOLDER": { "INPUT_PLACEHOLDER": {
"INBOXES": "Search inboxes" "INBOXES": "ইনবক্স খুঁজুন"
} }
}, },
"METRICS": { "METRICS": {
"CONVERSATIONS": { "CONVERSATIONS": {
"NAME": "Conversations", "NAME": "কনভার্সেশন",
"DESC": "( Total )" "DESC": "( মোট )"
}, },
"INCOMING_MESSAGES": { "INCOMING_MESSAGES": {
"NAME": "Incoming Messages", "NAME": "ইনকামিং মেসেজ",
"DESC": "( Total )" "DESC": "( মোট )"
}, },
"OUTGOING_MESSAGES": { "OUTGOING_MESSAGES": {
"NAME": "Outgoing Messages", "NAME": "প্রেরিত বার্তা",
"DESC": "( Total )" "DESC": "(মোট)"
}, },
"FIRST_RESPONSE_TIME": { "FIRST_RESPONSE_TIME": {
"NAME": "First Response Time", "NAME": "প্রথম সাড়া সময়",
"DESC": "( Avg )", "DESC": "(গড়)",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "গণনার জন্য ব্যবহৃত মোট কথোপকথনের সংখ্যা:",
"TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)"
}, },
"RESOLUTION_TIME": { "RESOLUTION_TIME": {
"NAME": "Resolution Time", "NAME": "সমাধানের সময়",
"DESC": "( Avg )", "DESC": "(গড়)",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "গণনার জন্য ব্যবহৃত মোট কথোপকথনের সংখ্যা:",
"TOOLTIP_TEXT": "Resolution Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "Resolution Time is {metricValue} (based on {conversationCount} conversations)"
}, },
"RESOLUTION_COUNT": { "RESOLUTION_COUNT": {
"NAME": "Resolution Count", "NAME": "সমাধানের সংখ্যা",
"DESC": "( Total )" "DESC": "(মোট)"
} }
}, },
"DATE_RANGE": [ "DATE_RANGE": [
{ {
"id": 0, "id": 0,
"name": "Last 7 days" "name": "গত দিন"
}, },
{ {
"id": 1, "id": 1,
"name": "Last 30 days" "name": "গত ৩০ দিন"
}, },
{ {
"id": 2, "id": 2,
"name": "Last 3 months" "name": "গত ৩ মাস"
}, },
{ {
"id": 3, "id": 3,
"name": "Last 6 months" "name": "গত ৬ মাস"
}, },
{ {
"id": 4, "id": 4,
"name": "Last year" "name": "গত বছর"
}, },
{ {
"id": 5, "id": 5,
"name": "Custom date range" "name": "কাস্টম তারিখ পরিসর"
} }
], ],
"CUSTOM_DATE_RANGE": { "CUSTOM_DATE_RANGE": {
"CONFIRM": "Apply", "CONFIRM": "প্রয়োগ করুন",
"PLACEHOLDER": "Select date range" "PLACEHOLDER": "তারিখ পরিসর নির্বাচন করুন"
} }
}, },
"TEAM_REPORTS": { "TEAM_REPORTS": {
"HEADER": "Team Overview", "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 data...", "LOADING_CHART": "চার্ট ডেটা লোড হচ্ছে...",
"NO_ENOUGH_DATA": "We've not received enough data points to generate report, Please try again later.", "NO_ENOUGH_DATA": "রিপোর্ট তৈরির জন্য যথেষ্ট ডেটা নেই, পরে আবার চেষ্টা করুন।",
"DOWNLOAD_TEAM_REPORTS": "Download team reports", "DOWNLOAD_TEAM_REPORTS": "টিম রিপোর্ট ডাউনলোড করুন",
"FILTER_DROPDOWN_LABEL": "Select Team", "FILTER_DROPDOWN_LABEL": "টিম নির্বাচন করুন",
"FILTERS": { "FILTERS": {
"ADD_FILTER": "Add filter", "ADD_FILTER": "ফিল্টার যোগ করুন",
"CLEAR_ALL": "Clear all", "CLEAR_ALL": "সব মুছুন",
"NO_FILTER": "No filters available", "NO_FILTER": "কোনো ফিল্টার নেই",
"INPUT_PLACEHOLDER": { "INPUT_PLACEHOLDER": {
"TEAMS": "Search teams" "TEAMS": "টিম খুঁজুন"
} }
}, },
"METRICS": { "METRICS": {
"CONVERSATIONS": { "CONVERSATIONS": {
"NAME": "Conversations", "NAME": "আলোচনা",
"DESC": "( Total )" "DESC": "(মোট)"
}, },
"INCOMING_MESSAGES": { "INCOMING_MESSAGES": {
"NAME": "Incoming Messages", "NAME": "প্রাপ্ত বার্তা",
"DESC": "( Total )" "DESC": "(মোট)"
}, },
"OUTGOING_MESSAGES": { "OUTGOING_MESSAGES": {
"NAME": "Outgoing Messages", "NAME": "প্রেরিত বার্তা",
"DESC": "( Total )" "DESC": "(মোট)"
}, },
"FIRST_RESPONSE_TIME": { "FIRST_RESPONSE_TIME": {
"NAME": "First Response Time", "NAME": "প্রথম সাড়া সময়",
"DESC": "( Avg )", "DESC": "(গড়)",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "গণনার জন্য ব্যবহৃত মোট কথোপকথনের সংখ্যা:",
"TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "First Response Time is {metricValue} (based on {conversationCount} conversations)"
}, },
"RESOLUTION_TIME": { "RESOLUTION_TIME": {
"NAME": "Resolution Time", "NAME": "সমাধানের সময়",
"DESC": "( Avg )", "DESC": "(গড়)",
"INFO_TEXT": "Total number of conversations used for computation:", "INFO_TEXT": "গণনার জন্য ব্যবহৃত মোট কথোপকথনের সংখ্যা:",
"TOOLTIP_TEXT": "Resolution Time is {metricValue} (based on {conversationCount} conversations)" "TOOLTIP_TEXT": "Resolution Time is {metricValue} (based on {conversationCount} conversations)"
}, },
"RESOLUTION_COUNT": { "RESOLUTION_COUNT": {
"NAME": "Resolution Count", "NAME": "সমাধানের সংখ্যা",
"DESC": "( Total )" "DESC": "( Total )"
} }
}, },
"DATE_RANGE": [ "DATE_RANGE": [
{ {
"id": 0, "id": 0,
"name": "Last 7 days" "name": "গত দিন"
}, },
{ {
"id": 1, "id": 1,
"name": "Last 30 days" "name": "গত ৩০ দিন"
}, },
{ {
"id": 2, "id": 2,
"name": "Last 3 months" "name": "গত ৩ মাস"
}, },
{ {
"id": 3, "id": 3,
"name": "Last 6 months" "name": "গত ৬ মাস"
}, },
{ {
"id": 4, "id": 4,
"name": "Last year" "name": "গত বছর"
}, },
{ {
"id": 5, "id": 5,
"name": "Custom date range" "name": "কাস্টম তারিখ পরিসর"
} }
], ],
"CUSTOM_DATE_RANGE": { "CUSTOM_DATE_RANGE": {
"CONFIRM": "Apply", "CONFIRM": "প্রয়োগ করুন",
"PLACEHOLDER": "Select date range" "PLACEHOLDER": "তারিখ পরিসর নির্বাচন করুন"
} }
}, },
"CSAT_REPORTS": { "CSAT_REPORTS": {
"HEADER": "CSAT Reports", "HEADER": "CSAT রিপোর্ট",
"NO_RECORDS": "No responses yet", "NO_RECORDS": "এখনও কোনো উত্তর নেই",
"NO_RECORDS_DESCRIPTION": "CSAT survey responses will appear here once customers start providing feedback.", "NO_RECORDS_DESCRIPTION": "গ্রাহকরা ফিডব্যাক দিলে এখানে CSAT জরিপের উত্তর দেখা যাবে।",
"DOWNLOAD": "Download CSAT Reports", "DOWNLOAD": "CSAT রিপোর্ট ডাউনলোড করুন",
"DOWNLOAD_FAILED": "Failed to download CSAT Reports", "DOWNLOAD_FAILED": "CSAT রিপোর্ট ডাউনলোড ব্যর্থ হয়েছে",
"FILTERS": { "FILTERS": {
"ADD_FILTER": "Add filter", "ADD_FILTER": "ফিল্টার যোগ করুন",
"CLEAR_ALL": "Clear all", "CLEAR_ALL": "সব মুছুন",
"NO_FILTER": "No filters available", "NO_FILTER": "কোনো ফিল্টার নেই",
"INPUT_PLACEHOLDER": { "INPUT_PLACEHOLDER": {
"AGENTS": "Search agents", "AGENTS": "এজেন্ট খুঁজুন",
"INBOXES": "Search inboxes", "INBOXES": "ইনবক্স খুঁজুন",
"TEAMS": "Search teams", "TEAMS": "টিম খুঁজুন",
"RATINGS": "Search ratings" "RATINGS": "রেটিং খুঁজুন"
}, },
"AGENTS": { "AGENTS": {
"LABEL": "Agent" "LABEL": "এজেন্ট"
}, },
"INBOXES": { "INBOXES": {
"LABEL": "Inbox" "LABEL": "ইনবক্স"
}, },
"TEAMS": { "TEAMS": {
"LABEL": "Team" "LABEL": "টিম"
}, },
"RATINGS": { "RATINGS": {
"LABEL": "Rating" "LABEL": "রেটিং"
} }
}, },
"TABLE": { "TABLE": {
"HEADER": { "HEADER": {
"CONTACT_NAME": "Contact", "CONTACT_NAME": "যোগাযোগ",
"AGENT_NAME": "Agent", "AGENT_NAME": "এজেন্ট",
"RATING": "Rating", "RATING": "রেটিং",
"FEEDBACK_TEXT": "Feedback comment", "FEEDBACK_TEXT": "মতামত",
"CONVERSATION": "Conversation", "CONVERSATION": "কথোপকথন",
"CUSTOMER": "Customer", "CUSTOMER": "গ্রাহক",
"RESPONSE": "Response", "RESPONSE": "প্রতিক্রিয়া",
"HANDLED_BY": "Handled by" "HANDLED_BY": "যিনি পরিচালনা করেছেন"
}, },
"UNKNOWN_CUSTOMER": "Unknown customer" "UNKNOWN_CUSTOMER": "অজানা গ্রাহক"
}, },
"NO_AGENT": "No assigned agent", "NO_AGENT": "কোনো এজেন্ট নির্ধারিত নেই",
"NO_FEEDBACK": "No feedback provided", "NO_FEEDBACK": "কোনো মতামত দেওয়া হয়নি",
"METRIC": { "METRIC": {
"TOTAL_RESPONSES": { "TOTAL_RESPONSES": {
"LABEL": "Total responses", "LABEL": "মোট উত্তর",
"TOOLTIP": "Total number of responses collected" "TOOLTIP": "মোট সংগৃহীত উত্তর"
}, },
"SATISFACTION_SCORE": { "SATISFACTION_SCORE": {
"LABEL": "Satisfaction score", "LABEL": "সন্তুষ্টি স্কোর",
"TOOLTIP": "Total number of positive responses / Total number of responses * 100" "TOOLTIP": "মোট ইতিবাচক প্রতিক্রিয়া / মোট প্রতিক্রিয়া * ১০০"
}, },
"RESPONSE_RATE": { "RESPONSE_RATE": {
"LABEL": "Response rate", "LABEL": "প্রতিক্রিয়া হার",
"TOOLTIP": "Total number of responses / Total number of CSAT survey messages sent * 100" "TOOLTIP": "মোট প্রতিক্রিয়া / মোট CSAT জরিপ বার্তা * ১০০"
}, },
"RATING_DISTRIBUTION": "Rating distribution" "RATING_DISTRIBUTION": "রেটিং বণ্টন"
}, },
"REVIEW_NOTES": { "REVIEW_NOTES": {
"TITLE": "Review notes", "TITLE": "নোটসমূহ পর্যালোচনা করুন",
"PLACEHOLDER": "Add review notes about this rating...", "PLACEHOLDER": "এই রেটিং সম্পর্কে পর্যালোচনার নোট যোগ করুন...",
"SAVE": "Save", "SAVE": "সংরক্ষণ করুন",
"CANCEL": "Cancel", "CANCEL": "বাতিল করুন",
"SAVING": "Saving...", "SAVING": "সংরক্ষণ করা হচ্ছে...",
"SAVED": "Notes saved successfully", "SAVED": "নোট সফলভাবে সংরক্ষিত হয়েছে",
"SAVE_ERROR": "Failed to save notes", "SAVE_ERROR": "নোট সংরক্ষণে ব্যর্থ হয়েছে",
"UPDATED_BY": "Updated by {name} {time}", "UPDATED_BY": "Updated by {name} {time}",
"UPDATED_BY_LABEL": "Updated by", "UPDATED_BY_LABEL": "আপডেট করেছেন",
"PAYWALL": { "PAYWALL": {
"TITLE": "Upgrade to add review notes", "TITLE": "পর্যালোচনার নোট যোগ করতে আপগ্রেড করুন",
"AVAILABLE_ON": "The review notes feature is only available in the Business and Enterprise plans.", "AVAILABLE_ON": "পর্যালোচনার নোট ফিচারটি শুধুমাত্র Business এবং Enterprise প্ল্যানে উপলব্ধ।",
"UPGRADE_PROMPT": "Add internal context to every CSAT response with review notes. Capture what really happened, spot patterns faster, and make better decisions from your feedback.", "UPGRADE_PROMPT": "প্রতি CSAT প্রতিক্রিয়ায় রিভিউ নোট যোগ করে অভ্যন্তরীণ তথ্য যুক্ত করুন। কী ঘটেছিল তা ধরুন, দ্রুত প্যাটার্ন চিনুন এবং আপনার ফিডব্যাক থেকে আরও ভালো সিদ্ধান্ত নিন।",
"UPGRADE_NOW": "Upgrade now", "UPGRADE_NOW": "এখনই আপগ্রেড করুন",
"CANCEL_ANYTIME": "You can change or cancel your plan anytime" "CANCEL_ANYTIME": "আপনি যেকোনো সময় আপনার প্ল্যান পরিবর্তন বা বাতিল করতে পারেন"
} }
} }
}, },
"BOT_REPORTS": { "BOT_REPORTS": {
"HEADER": "Bot Reports", "HEADER": "বট রিপোর্ট",
"METRIC": { "METRIC": {
"TOTAL_CONVERSATIONS": { "TOTAL_CONVERSATIONS": {
"LABEL": "No. of Conversations", "LABEL": "কথোপকথনের সংখ্যা",
"TOOLTIP": "Total number of conversations handled by the bot" "TOOLTIP": "বট দ্বারা পরিচালিত মোট কথোপকথন"
}, },
"TOTAL_RESPONSES": { "TOTAL_RESPONSES": {
"LABEL": "Total Responses", "LABEL": "মোট উত্তর",
"TOOLTIP": "Total number of responses sent by the bot" "TOOLTIP": "বট দ্বারা পাঠানো মোট উত্তর"
}, },
"RESOLUTION_RATE": { "RESOLUTION_RATE": {
"LABEL": "Resolution Rate", "LABEL": "সমাধান হার",
"TOOLTIP": "Total number of conversations resolved by the bot / Total number of conversations handled by the bot * 100" "TOOLTIP": "বট দ্বারা সমাধানকৃত মোট কথোপকথন / বট দ্বারা পরিচালিত মোট কথোপকথন * ১০০"
}, },
"HANDOFF_RATE": { "HANDOFF_RATE": {
"LABEL": "Handoff Rate", "LABEL": "হ্যান্ডঅফ হার",
"TOOLTIP": "Total number of conversations handed off to agents / Total number of conversations handled by the bot * 100" "TOOLTIP": "এজেন্টদের কাছে হ্যান্ডঅফ করা মোট কথোপকথন / বট দ্বারা পরিচালিত মোট কথোপকথন * ১০০"
} }
} }
}, },
"OVERVIEW_REPORTS": { "OVERVIEW_REPORTS": {
"HEADER": "Overview", "HEADER": "সংক্ষিপ্ত বিবরণ",
"LIVE": "Live", "LIVE": "লাইভ",
"ACCOUNT_CONVERSATIONS": { "ACCOUNT_CONVERSATIONS": {
"HEADER": "Open Conversations", "HEADER": "খোলা কথোপকথন",
"LOADING_MESSAGE": "Loading conversation metrics...", "LOADING_MESSAGE": "কথোপকথনের পরিসংখ্যান লোড হচ্ছে...",
"OPEN": "Open", "OPEN": "খোলা",
"UNATTENDED": "Unattended", "UNATTENDED": "অবহেলিত",
"UNASSIGNED": "Unassigned", "UNASSIGNED": "অবরোধহীন",
"PENDING": "Pending" "PENDING": "অপেক্ষমাণ"
}, },
"CONVERSATION_HEATMAP": { "CONVERSATION_HEATMAP": {
"HEADER": "Conversation Traffic", "HEADER": "কথোপকথনের ট্রাফিক",
"NO_CONVERSATIONS": "No conversations", "NO_CONVERSATIONS": "কোনো কথোপকথন নেই",
"CONVERSATION": "{count} conversation", "CONVERSATION": "{count} conversation",
"CONVERSATIONS": "{count} conversations", "CONVERSATIONS": "{count} conversations",
"DOWNLOAD_REPORT": "Download report" "DOWNLOAD_REPORT": "রিপোর্ট ডাউনলোড করুন"
}, },
"RESOLUTION_HEATMAP": { "RESOLUTION_HEATMAP": {
"HEADER": "Resolutions", "HEADER": "সমাধানসমূহ",
"NO_CONVERSATIONS": "No conversations", "NO_CONVERSATIONS": "কোনো কথোপকথন নেই",
"CONVERSATION": "{count} conversation", "CONVERSATION": "{count} conversation",
"CONVERSATIONS": "{count} conversations", "CONVERSATIONS": "{count} conversations",
"DOWNLOAD_REPORT": "Download report" "DOWNLOAD_REPORT": "রিপোর্ট ডাউনলোড করুন"
}, },
"AGENT_CONVERSATIONS": { "AGENT_CONVERSATIONS": {
"HEADER": "Conversations by agents", "HEADER": "এজেন্ট অনুযায়ী কথোপকথন",
"LOADING_MESSAGE": "Loading agent metrics...", "LOADING_MESSAGE": "এজেন্টের পরিসংখ্যান লোড হচ্ছে...",
"NO_AGENTS": "There are no conversations by agents", "NO_AGENTS": "এজেন্টদের কোনো কথোপকথন নেই",
"TABLE_HEADER": { "TABLE_HEADER": {
"AGENT": "Agent", "AGENT": "এজেন্ট",
"OPEN": "Open", "OPEN": "খোলা",
"UNATTENDED": "Unattended", "UNATTENDED": "অযত্নে",
"STATUS": "Status" "STATUS": "অবস্থা"
} }
}, },
"TEAM_CONVERSATIONS": { "TEAM_CONVERSATIONS": {
"ALL_TEAMS": "All Teams", "ALL_TEAMS": "সব টিম",
"HEADER": "Conversations by teams", "HEADER": "দলের ভিত্তিতে কথোপকথন",
"LOADING_MESSAGE": "Loading team metrics...", "LOADING_MESSAGE": "দলের পরিসংখ্যান লোড হচ্ছে...",
"NO_TEAMS": "There is no data available", "NO_TEAMS": "কোনো তথ্য নেই",
"TABLE_HEADER": { "TABLE_HEADER": {
"TEAM": "Team", "TEAM": "দল",
"OPEN": "Open", "OPEN": "খোলা",
"UNATTENDED": "Unattended", "UNATTENDED": "অবহেলিত",
"STATUS": "Status" "STATUS": "অবস্থা"
} }
}, },
"AGENT_STATUS": { "AGENT_STATUS": {
"HEADER": "Agent status", "HEADER": "এজেন্টের অবস্থা",
"ONLINE": "Online", "ONLINE": "অনলাইন",
"BUSY": "Busy", "BUSY": "ব্যস্ত",
"OFFLINE": "Offline" "OFFLINE": "অফলাইন"
} }
}, },
"DAYS_OF_WEEK": { "DAYS_OF_WEEK": {
"SUNDAY": "Sunday", "SUNDAY": "রবিবার",
"MONDAY": "Monday", "MONDAY": "সোমবার",
"TUESDAY": "Tuesday", "TUESDAY": "মঙ্গলবার",
"WEDNESDAY": "Wednesday", "WEDNESDAY": "বুধবার",
"THURSDAY": "Thursday", "THURSDAY": "বৃহস্পতিবার",
"FRIDAY": "Friday", "FRIDAY": "শুক্রবার",
"SATURDAY": "Saturday" "SATURDAY": "শনিবার"
}, },
"SLA_REPORTS": { "SLA_REPORTS": {
"HEADER": "SLA Reports", "HEADER": "SLA রিপোর্ট",
"NO_RECORDS": "SLA applied conversations are not available.", "NO_RECORDS": "SLA প্রয়োগকৃত কোনো কথোপকথন নেই।",
"LOADING": "Loading SLA data...", "LOADING": "SLA ডেটা লোড হচ্ছে...",
"DOWNLOAD_SLA_REPORTS": "Download SLA reports", "DOWNLOAD_SLA_REPORTS": "SLA রিপোর্ট ডাউনলোড করুন",
"DOWNLOAD_FAILED": "Failed to download SLA Reports", "DOWNLOAD_FAILED": "SLA রিপোর্ট ডাউনলোড ব্যর্থ হয়েছে",
"DROPDOWN": { "DROPDOWN": {
"ADD_FIlTER": "Add filter", "ADD_FIlTER": "ফিল্টার যোগ করুন",
"CLEAR_ALL": "Clear all", "CLEAR_ALL": "সব মুছুন",
"CLEAR_FILTER": "Clear filter", "CLEAR_FILTER": "ফিল্টার মুছুন",
"EMPTY_LIST": "No results found", "EMPTY_LIST": "কোনও ফলাফল পাওয়া যায়নি",
"NO_FILTER": "No filters available", "NO_FILTER": "কোনও ফিল্টার নেই",
"SEARCH": "Search filter", "SEARCH": "ফিল্টার অনুসন্ধান করুন",
"INPUT_PLACEHOLDER": { "INPUT_PLACEHOLDER": {
"SLA": "SLA name", "SLA": "SLA নাম",
"AGENTS": "Agent name", "AGENTS": "এজেন্টের নাম",
"INBOXES": "Inbox name", "INBOXES": "ইনবক্সের নাম",
"LABELS": "Label name", "LABELS": "লেবেল নাম",
"TEAMS": "Team name" "TEAMS": "টিমের নাম"
}, },
"SLA": "SLA Policy", "SLA": "SLA নীতি",
"INBOXES": "Inbox", "INBOXES": "ইনবক্স",
"AGENTS": "Agent", "AGENTS": "এজেন্ট",
"LABELS": "Label", "LABELS": "লেবেল",
"TEAMS": "Team" "TEAMS": "টিম"
}, },
"WITH": "with", "WITH": "সহ",
"METRICS": { "METRICS": {
"HIT_RATE": { "HIT_RATE": {
"LABEL": "Hit Rate", "LABEL": "হিট হার",
"TOOLTIP": "Percentage of SLAs created were completed successfully" "TOOLTIP": "তৈরি হওয়া SLA-র শতকরা কত সফলভাবে সম্পন্ন হয়েছে"
}, },
"NO_OF_MISSES": { "NO_OF_MISSES": {
"LABEL": "Number of Misses", "LABEL": "মিসের সংখ্যা",
"TOOLTIP": "Total SLA misses in a certain period" "TOOLTIP": "নির্দিষ্ট সময়ে মোট SLA মিস"
}, },
"NO_OF_CONVERSATIONS": { "NO_OF_CONVERSATIONS": {
"LABEL": "Number of Conversations", "LABEL": "কথোপকথনের সংখ্যা",
"TOOLTIP": "Total number of conversations with SLA" "TOOLTIP": "SLA সহ মোট কথোপকথনের সংখ্যা"
} }
}, },
"TABLE": { "TABLE": {
"HEADER": { "HEADER": {
"POLICY": "Policy", "POLICY": "নীতি",
"CONVERSATION": "Conversation", "CONVERSATION": "কথোপকথন",
"AGENT": "Agent" "AGENT": "এজেন্ট"
}, },
"VIEW_DETAILS": "View Details" "VIEW_DETAILS": "বিস্তারিত দেখুন"
} }
}, },
"SUMMARY_REPORTS": { "SUMMARY_REPORTS": {
"INBOX": "Inbox", "INBOX": "ইনবক্স",
"AGENT": "Agent", "AGENT": "এজেন্ট",
"TEAM": "Team", "TEAM": "টিম",
"LABEL": "Label", "LABEL": "লেবেল",
"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", "RESOLUTION_COUNT": "সমাধান সংখ্যা",
"CONVERSATIONS": "No. of conversations" "CONVERSATIONS": "কথোপকথনের সংখ্যা"
} }
} }
File diff suppressed because it is too large Load Diff
@@ -710,9 +710,21 @@
"MESSENGER_SUB_HEAD": "Col·loca aquest botó dins de l'etiqueta body", "MESSENGER_SUB_HEAD": "Col·loca aquest botó dins de l'etiqueta body",
"ALLOWED_DOMAINS": { "ALLOWED_DOMAINS": {
"TITLE": "Allowed Domains", "TITLE": "Allowed Domains",
"SUBTITLE": "Add wildcard or regular domains separated by commas (leave blank to allow all), e.g. *.chatwoot.dev, chatwoot.com.", "DESCRIPTION": "Restrict which websites can embed your chat widget. For security, only add domains you own and trust. Add one or more domains separated by commas. Leave blank to allow all domains (not recommended for production).",
"PLACEHOLDER": "example.com, www.example.com, app.example.com" "PLACEHOLDER": "example.com, www.example.com, app.example.com"
}, },
"ALLOW_MOBILE_WEBVIEW": {
"LABEL": "Enable widget in mobile apps",
"SUBTITLE": "Check this if you embed the widget in iOS or Android apps. Mobile apps don't send domain information, so they would be blocked by domain restrictions unless this is enabled."
},
"IDENTITY_VALIDATION": {
"TITLE": "Identity Validation",
"DESCRIPTION": "Verify user authenticity by generating secure tokens. This prevents unauthorized users from impersonating others in your chat.",
"SECRET_KEY": "Secret Key",
"VIEW_DOCS": "View documentation",
"REQUIRE_LABEL": "Require identity validation for all conversations",
"REQUIRE_DESCRIPTION": "When enabled, users must provide a valid identity token to start conversations. Requests without valid tokens will be rejected."
},
"INBOX_AGENTS": "Agents", "INBOX_AGENTS": "Agents",
"INBOX_AGENTS_SUB_TEXT": "Afegir o eliminar agents d'aquesta safata d'entrada", "INBOX_AGENTS_SUB_TEXT": "Afegir o eliminar agents d'aquesta safata d'entrada",
"AGENT_ASSIGNMENT": "Conversació Assignada", "AGENT_ASSIGNMENT": "Conversació Assignada",
@@ -527,7 +527,8 @@
"TITLE": "Característiques", "TITLE": "Característiques",
"ALLOW_CONVERSATION_FAQS": "Generate FAQs from resolved conversations", "ALLOW_CONVERSATION_FAQS": "Generate FAQs from resolved conversations",
"ALLOW_MEMORIES": "Capture key details as memories from customer interactions.", "ALLOW_MEMORIES": "Capture key details as memories from customer interactions.",
"ALLOW_CITATIONS": "Include source citations in responses" "ALLOW_CITATIONS": "Include source citations in responses",
"ALLOW_CONTACT_ATTRIBUTES": "Allow access to contact information"
} }
}, },
"EDIT": { "EDIT": {
@@ -710,9 +710,21 @@
"MESSENGER_SUB_HEAD": "Umístěte toto tlačítko dovnitř vašeho tělesného štítku", "MESSENGER_SUB_HEAD": "Umístěte toto tlačítko dovnitř vašeho tělesného štítku",
"ALLOWED_DOMAINS": { "ALLOWED_DOMAINS": {
"TITLE": "Allowed Domains", "TITLE": "Allowed Domains",
"SUBTITLE": "Add wildcard or regular domains separated by commas (leave blank to allow all), e.g. *.chatwoot.dev, chatwoot.com.", "DESCRIPTION": "Restrict which websites can embed your chat widget. For security, only add domains you own and trust. Add one or more domains separated by commas. Leave blank to allow all domains (not recommended for production).",
"PLACEHOLDER": "example.com, www.example.com, app.example.com" "PLACEHOLDER": "example.com, www.example.com, app.example.com"
}, },
"ALLOW_MOBILE_WEBVIEW": {
"LABEL": "Enable widget in mobile apps",
"SUBTITLE": "Check this if you embed the widget in iOS or Android apps. Mobile apps don't send domain information, so they would be blocked by domain restrictions unless this is enabled."
},
"IDENTITY_VALIDATION": {
"TITLE": "Identity Validation",
"DESCRIPTION": "Verify user authenticity by generating secure tokens. This prevents unauthorized users from impersonating others in your chat.",
"SECRET_KEY": "Secret Key",
"VIEW_DOCS": "View documentation",
"REQUIRE_LABEL": "Require identity validation for all conversations",
"REQUIRE_DESCRIPTION": "When enabled, users must provide a valid identity token to start conversations. Requests without valid tokens will be rejected."
},
"INBOX_AGENTS": "Agenti", "INBOX_AGENTS": "Agenti",
"INBOX_AGENTS_SUB_TEXT": "Přidat nebo odebrat agenty z této složky doručené pošty", "INBOX_AGENTS_SUB_TEXT": "Přidat nebo odebrat agenty z této složky doručené pošty",
"AGENT_ASSIGNMENT": "Conversation Assignment", "AGENT_ASSIGNMENT": "Conversation Assignment",
@@ -527,7 +527,8 @@
"TITLE": "Funkce", "TITLE": "Funkce",
"ALLOW_CONVERSATION_FAQS": "Generate FAQs from resolved conversations", "ALLOW_CONVERSATION_FAQS": "Generate FAQs from resolved conversations",
"ALLOW_MEMORIES": "Capture key details as memories from customer interactions.", "ALLOW_MEMORIES": "Capture key details as memories from customer interactions.",
"ALLOW_CITATIONS": "Include source citations in responses" "ALLOW_CITATIONS": "Include source citations in responses",
"ALLOW_CONTACT_ATTRIBUTES": "Allow access to contact information"
} }
}, },
"EDIT": { "EDIT": {
@@ -710,9 +710,21 @@
"MESSENGER_SUB_HEAD": "Placer denne knap inde i din body tag", "MESSENGER_SUB_HEAD": "Placer denne knap inde i din body tag",
"ALLOWED_DOMAINS": { "ALLOWED_DOMAINS": {
"TITLE": "Allowed Domains", "TITLE": "Allowed Domains",
"SUBTITLE": "Add wildcard or regular domains separated by commas (leave blank to allow all), e.g. *.chatwoot.dev, chatwoot.com.", "DESCRIPTION": "Restrict which websites can embed your chat widget. For security, only add domains you own and trust. Add one or more domains separated by commas. Leave blank to allow all domains (not recommended for production).",
"PLACEHOLDER": "example.com, www.example.com, app.example.com" "PLACEHOLDER": "example.com, www.example.com, app.example.com"
}, },
"ALLOW_MOBILE_WEBVIEW": {
"LABEL": "Enable widget in mobile apps",
"SUBTITLE": "Check this if you embed the widget in iOS or Android apps. Mobile apps don't send domain information, so they would be blocked by domain restrictions unless this is enabled."
},
"IDENTITY_VALIDATION": {
"TITLE": "Identity Validation",
"DESCRIPTION": "Verify user authenticity by generating secure tokens. This prevents unauthorized users from impersonating others in your chat.",
"SECRET_KEY": "Secret Key",
"VIEW_DOCS": "View documentation",
"REQUIRE_LABEL": "Require identity validation for all conversations",
"REQUIRE_DESCRIPTION": "When enabled, users must provide a valid identity token to start conversations. Requests without valid tokens will be rejected."
},
"INBOX_AGENTS": "Agenter", "INBOX_AGENTS": "Agenter",
"INBOX_AGENTS_SUB_TEXT": "Tilføj eller fjern agenter fra denne indbakke", "INBOX_AGENTS_SUB_TEXT": "Tilføj eller fjern agenter fra denne indbakke",
"AGENT_ASSIGNMENT": "Samtale Tildeling", "AGENT_ASSIGNMENT": "Samtale Tildeling",
@@ -527,7 +527,8 @@
"TITLE": "Funktioner", "TITLE": "Funktioner",
"ALLOW_CONVERSATION_FAQS": "Generate FAQs from resolved conversations", "ALLOW_CONVERSATION_FAQS": "Generate FAQs from resolved conversations",
"ALLOW_MEMORIES": "Capture key details as memories from customer interactions.", "ALLOW_MEMORIES": "Capture key details as memories from customer interactions.",
"ALLOW_CITATIONS": "Include source citations in responses" "ALLOW_CITATIONS": "Include source citations in responses",
"ALLOW_CONTACT_ATTRIBUTES": "Allow access to contact information"
} }
}, },
"EDIT": { "EDIT": {
@@ -710,9 +710,21 @@
"MESSENGER_SUB_HEAD": "Platzieren Sie diese Schaltfläche in Ihrem Body-Tag", "MESSENGER_SUB_HEAD": "Platzieren Sie diese Schaltfläche in Ihrem Body-Tag",
"ALLOWED_DOMAINS": { "ALLOWED_DOMAINS": {
"TITLE": "Allowed Domains", "TITLE": "Allowed Domains",
"SUBTITLE": "Add wildcard or regular domains separated by commas (leave blank to allow all), e.g. *.chatwoot.dev, chatwoot.com.", "DESCRIPTION": "Restrict which websites can embed your chat widget. For security, only add domains you own and trust. Add one or more domains separated by commas. Leave blank to allow all domains (not recommended for production).",
"PLACEHOLDER": "example.com, www.example.com, app.example.com" "PLACEHOLDER": "example.com, www.example.com, app.example.com"
}, },
"ALLOW_MOBILE_WEBVIEW": {
"LABEL": "Enable widget in mobile apps",
"SUBTITLE": "Check this if you embed the widget in iOS or Android apps. Mobile apps don't send domain information, so they would be blocked by domain restrictions unless this is enabled."
},
"IDENTITY_VALIDATION": {
"TITLE": "Identity Validation",
"DESCRIPTION": "Verify user authenticity by generating secure tokens. This prevents unauthorized users from impersonating others in your chat.",
"SECRET_KEY": "Secret Key",
"VIEW_DOCS": "View documentation",
"REQUIRE_LABEL": "Require identity validation for all conversations",
"REQUIRE_DESCRIPTION": "When enabled, users must provide a valid identity token to start conversations. Requests without valid tokens will be rejected."
},
"INBOX_AGENTS": "Agenten", "INBOX_AGENTS": "Agenten",
"INBOX_AGENTS_SUB_TEXT": "Hinzufügen oder Entfernen von Agenten zu diesem Posteingang", "INBOX_AGENTS_SUB_TEXT": "Hinzufügen oder Entfernen von Agenten zu diesem Posteingang",
"AGENT_ASSIGNMENT": "Konversationssauftrag", "AGENT_ASSIGNMENT": "Konversationssauftrag",

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