Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76307dec12 | ||
|
|
0b441054ae | ||
|
|
2e8b78aebc | ||
|
|
d01b221a24 | ||
|
|
61bb111768 | ||
|
|
de47d6e445 | ||
|
|
59fe4b30f0 | ||
|
|
166dae8e27 | ||
|
|
5ce64fd30d | ||
|
|
1a4513f437 | ||
|
|
59be4a780f | ||
|
|
74001c2b49 | ||
|
|
a9ce0fb2d9 | ||
|
|
4c3fd1c214 | ||
|
|
a9459fe746 | ||
|
|
5a3228f05b | ||
|
|
befc238db9 | ||
|
|
ae75a1f8d4 | ||
|
|
d1c50bfd73 | ||
|
|
6f540366f4 | ||
|
|
151fc760fe | ||
|
|
be4391a4b6 | ||
|
|
76ae3e0f6b | ||
|
|
f37b6edaa6 | ||
|
|
7095f77f93 | ||
|
|
5853b778f2 | ||
|
|
6405725ce6 | ||
|
|
111d6141aa | ||
|
|
5560b3c8e6 | ||
|
|
d528d541ea | ||
|
|
ab6b51cc1f | ||
|
|
35aa4f2658 | ||
|
|
36db3c37e8 | ||
|
|
b0c9232153 | ||
|
|
0070fb9e5c | ||
|
|
aa33ac4b1d | ||
|
|
1c2bc5b395 | ||
|
|
f2fe18a4c5 | ||
|
|
87fdcbebf6 | ||
|
|
68a4f651ea | ||
|
|
243caa9626 | ||
|
|
863684b916 | ||
|
|
2d543f3728 | ||
|
|
47088cfbee | ||
|
|
66c75cbf79 | ||
|
|
b2c68d88ae | ||
|
|
675e998cba | ||
|
|
db1d20ae36 | ||
|
|
59b40dda4e | ||
|
|
317fab4dfe | ||
|
|
6c83ab68b4 | ||
|
|
2194465757 | ||
|
|
a0e70f88ad | ||
|
|
9102a3d852 | ||
|
|
b05cba896e | ||
|
|
6716a31b6c | ||
|
|
2e42d0e7eb | ||
|
|
dee9864157 | ||
|
|
0293fc8c6f | ||
|
|
725fdc03a6 | ||
|
|
4557cb695f | ||
|
|
172403a061 | ||
|
|
d03c3c185e | ||
|
|
50a111343c | ||
|
|
f01693adc3 | ||
|
|
d2bbbb4448 | ||
|
|
38c0aadff2 | ||
|
|
79d593b155 | ||
|
|
ddc84cfecc | ||
|
|
b620383d94 | ||
|
|
2319dba68d | ||
|
|
0c388ee3a7 | ||
|
|
fb5b3e2964 | ||
|
|
d44eaa5b41 | ||
|
|
2eaf05df27 | ||
|
|
9e5431e205 | ||
|
|
26c3102af8 | ||
|
|
104f06ef2b | ||
|
|
93c8654e84 | ||
|
|
a7261790bd | ||
|
|
d8d6e521f6 | ||
|
|
02497bcd40 | ||
|
|
b498e15620 | ||
|
|
1288d312c0 | ||
|
|
84cd350c42 | ||
|
|
100bf89074 | ||
|
|
d66c80f95a | ||
|
|
26f04bbd94 | ||
|
|
6582c03823 | ||
|
|
abacaf2e02 | ||
|
|
c65d8b9856 | ||
|
|
8f94cf06de | ||
|
|
94c1c16de8 | ||
|
|
e69d992725 | ||
|
|
e6c5dd6e22 | ||
|
|
5486d4874a | ||
|
|
9d9d8e03fe | ||
|
|
6ee50243a2 | ||
|
|
3ec078f9c1 | ||
|
|
4c3209be6d | ||
|
|
7fe8f9a8dc | ||
|
|
7fa2b29418 | ||
|
|
dd4edd5a85 | ||
|
|
b85df5a0d3 | ||
|
|
1a7bec3d4e | ||
|
|
727c4b454f | ||
|
|
4ba86b34a9 | ||
|
|
277a35aed9 | ||
|
|
28c1ffa09f | ||
|
|
10595680a9 | ||
|
|
577298dbc5 | ||
|
|
49ca4dfbf7 | ||
|
|
89ec47deec | ||
|
|
a043a46457 | ||
|
|
eb8e3a0fd1 | ||
|
|
fc25df8104 | ||
|
|
d8ffd3e543 | ||
|
|
ea4ec9310d | ||
|
|
479ec85e0d | ||
|
|
3e4b450260 | ||
|
|
f6a81949d0 | ||
|
|
6896962606 | ||
|
|
9b6d6ab4b0 | ||
|
|
d5f399f7d5 | ||
|
|
dbd3bd024c | ||
|
|
9ba7e19da3 | ||
|
|
5f6d1412cf | ||
|
|
0b5af3145e | ||
|
|
ad10ea4e96 | ||
|
|
9de53a972a | ||
|
|
4043efbb9a | ||
|
|
42019644f0 | ||
|
|
bcc25ef42f | ||
|
|
602bbf3b60 | ||
|
|
585ac6074f |
No files matched your search
@@ -8,6 +8,7 @@
|
||||
# ==================
|
||||
# Base URL for the API (used for webhooks, file URLs, etc.)
|
||||
WAHA_BASE_URL=http://localhost:3000
|
||||
# WAHA_PUBLIC_URL=http://localhost:3000
|
||||
|
||||
# Server configuration (if you need to customize hostname/port)
|
||||
# WHATSAPP_API_SCHEMA=http
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
src/core/engines/gows/grpc/*
|
||||
src/core/engines/gows/proto/*
|
||||
src/core/engines/webjs/_lodash.js
|
||||
@@ -1,36 +0,0 @@
|
||||
module.exports = {
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
project: 'tsconfig.json',
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['@typescript-eslint/eslint-plugin', 'simple-import-sort'],
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/eslint-recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'prettier',
|
||||
'prettier/@typescript-eslint',
|
||||
],
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
jest: true,
|
||||
},
|
||||
rules: {
|
||||
'simple-import-sort/imports': 'error',
|
||||
'simple-import-sort/exports': 'error',
|
||||
'@typescript-eslint/interface-name-prefix': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-inferrable-types': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/ban-ts-ignore': 'off',
|
||||
'@typescript-eslint/ban-ts-comment': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'lines-between-class-members': [
|
||||
'error',
|
||||
'always',
|
||||
{ exceptAfterSingleLine: true },
|
||||
],
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||
"plugins": ["typescript"],
|
||||
"env": {
|
||||
"builtin": true
|
||||
},
|
||||
"rules": {
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/no-inferrable-types": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"no-unused-vars": "off"
|
||||
}
|
||||
}
|
||||
+5
-11
@@ -17,18 +17,12 @@ repos:
|
||||
language: python
|
||||
stages: [commit-msg]
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: lint
|
||||
stages: [pre-commit]
|
||||
name: lint
|
||||
- id: oxlint
|
||||
name: oxlint
|
||||
entry: npx oxlint --fix --deny-warnings
|
||||
language: system
|
||||
entry: bash -c '$HOME/.nvm/nvm-exec npm run lint-cache'
|
||||
pass_filenames: false
|
||||
files: |
|
||||
(?x)^(
|
||||
src/.*|
|
||||
)$
|
||||
pass_filenames: true
|
||||
files: \.(ts|tsx|js|jsx)$
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||
rev: 'v3.1.0'
|
||||
|
||||
+1
-1
@@ -162,7 +162,7 @@ RUN if [ "$USE_BROWSER" = "chromium" ]; then \
|
||||
# Install Chrome
|
||||
# Available versions:
|
||||
# https://www.ubuntuupdates.org/package/google_chrome/stable/main/base/google-chrome-stable
|
||||
ARG CHROME_VERSION="137.0.7151.103-1"
|
||||
ARG CHROME_VERSION="140.0.7339.80-1"
|
||||
RUN if [ "$USE_BROWSER" = "chrome" ]; then \
|
||||
wget --no-verbose -O /tmp/chrome.deb https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_${CHROME_VERSION}_amd64.deb \
|
||||
&& apt-get update \
|
||||
|
||||
@@ -35,13 +35,13 @@ for-swagger:
|
||||
WHATSAPP_SWAGGER_CONFIG_ADVANCED=true . ${NVM_DIR}/nvm.sh && nvm exec yarn start
|
||||
|
||||
up-noweb:
|
||||
. ${NVM_DIR}/nvm.sh && nvm exec yarn up @adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-2025-07-04
|
||||
. ${NVM_DIR}/nvm.sh && nvm exec yarn up @adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-2025-09-21
|
||||
|
||||
up-noweb-libsignal:
|
||||
. ${NVM_DIR}/nvm.sh && nvm exec yarn up libsignal@github:devlikeapro/libsignal-node#fork-master
|
||||
|
||||
up-webjs:
|
||||
. ${NVM_DIR}/nvm.sh && nvm exec yarn up whatsapp-web.js@github:devlikeapro/whatsapp-web.js#fork-main-2025-06-09
|
||||
. ${NVM_DIR}/nvm.sh && nvm exec yarn up whatsapp-web.js@github:devlikeapro/whatsapp-web.js#fork-main-2025-09-10
|
||||
|
||||
start-proxy:
|
||||
docker run --rm -d --name squid-container -e TZ=UTC -p 3128:3128 ubuntu/squid:5.2-22.04_beta
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ services:
|
||||
# NOTE: Only if you're using PostgreSQL to save sessions
|
||||
# https://waha.devlike.pro/docs/how-to/storages/#media---postgresql
|
||||
# postgres:
|
||||
# image: postgres:17
|
||||
# image: postgres:17.6
|
||||
# restart: always
|
||||
# environment:
|
||||
# POSTGRES_USER: postgres
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
# Learn about the various environment variables at
|
||||
# https://www.chatwoot.com/docs/self-hosted/configuration/environment-variables/#rails-production-variables
|
||||
|
||||
# Increase rack default timeout (30s) to avoid timeout errors
|
||||
# Workaround for https://github.com/devlikeapro/waha/issues/1389
|
||||
RACK_TIMEOUT_SERVICE_TIMEOUT=60
|
||||
|
||||
# Used to verify the integrity of signed cookies. so ensure a secure value is set
|
||||
# SECRET_KEY_BASE should be alphanumeric. Avoid special characters or symbols.
|
||||
# Use `rake secret` to generate this variable
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
# ==================
|
||||
# Base URL for the API (used for webhooks, file URLs, etc.)
|
||||
WAHA_BASE_URL=http://waha:3000
|
||||
WAHA_PUBLIC_URL=http://localhost:3000
|
||||
|
||||
# Server configuration (if you need to customize hostname/port)
|
||||
# WHATSAPP_API_SCHEMA=http
|
||||
|
||||
@@ -24,10 +24,12 @@ services:
|
||||
- 8.8.8.8
|
||||
|
||||
base: &base
|
||||
image: chatwoot/chatwoot:v4.3.0
|
||||
image: chatwoot/chatwoot:v4.5.2
|
||||
env_file: .chatwoot.env ## Change this file for customized env variables
|
||||
volumes:
|
||||
- chatwoot_storage:/app/storage
|
||||
extra_hosts:
|
||||
- 'host.docker.internal:host-gateway'
|
||||
logging:
|
||||
driver: 'json-file'
|
||||
options:
|
||||
|
||||
+30
-9
@@ -4,8 +4,18 @@
|
||||
#
|
||||
# Calculate UV_THREADPOOL_SIZE based on number of CPUs
|
||||
#
|
||||
cpus=$(node -e "const os = require('os'); console.log(os.cpus().length);")
|
||||
uv_threadpool_size=$(($cpus * 1))
|
||||
# Try to get CPU count using Node.js, fallback to 1 if it fails
|
||||
cpus=$(node -e "const os = require('os'); console.log(os.cpus().length);" 2>/dev/null) || cpus=1
|
||||
# Make sure cpus is a number, default to 1 if not
|
||||
case $cpus in
|
||||
''|*[!0-9]*) cpus=1 ;;
|
||||
esac
|
||||
uv_threadpool_size=$(($cpus * 2))
|
||||
|
||||
# Check if uv_threadpool_size is less than 4 (default), set it to 4 if it is
|
||||
if [ "$uv_threadpool_size" -lt 4 ]; then
|
||||
uv_threadpool_size=4
|
||||
fi
|
||||
|
||||
# Set UV_THREADPOOL_SIZE as an environment variable
|
||||
export UV_THREADPOOL_SIZE="${UV_THREADPOOL_SIZE:-$uv_threadpool_size}"
|
||||
@@ -46,13 +56,22 @@ fi
|
||||
# xvfb-run
|
||||
#
|
||||
USE_XVFB=false
|
||||
if [ -z "$WHATSAPP_DEFAULT_ENGINE" ] || [ "$WHATSAPP_DEFAULT_ENGINE" = "WEBJS" ]; then
|
||||
# Try to run xvfb-run with a test command
|
||||
if xvfb-run --auto-servernum echo "xvfb-run is working!"; then
|
||||
USE_XVFB=true
|
||||
else
|
||||
echo "xvfb-run test failed, do not run it"
|
||||
USE_XVFB=false
|
||||
|
||||
# Check WAHA_RUN_XVFB parameter - only test for "false" case, treat all others as True
|
||||
if [ "$WAHA_RUN_XVFB" = "false" ] || [ "$WAHA_RUN_XVFB" = "False" ] || [ "$WAHA_RUN_XVFB" = "0" ]; then
|
||||
# Explicitly disabled by user
|
||||
echo "WAHA_RUN_XVFB value: $WAHA_RUN_XVFB - xvfb is disabled"
|
||||
USE_XVFB=false
|
||||
else
|
||||
# Check engine and run test if it's WEBJS or not specified
|
||||
if [ -z "$WHATSAPP_DEFAULT_ENGINE" ] || [ "$WHATSAPP_DEFAULT_ENGINE" = "WEBJS" ]; then
|
||||
# Try to run xvfb-run with a test command
|
||||
if xvfb-run --auto-servernum echo "xvfb-run is working!"; then
|
||||
USE_XVFB=true
|
||||
else
|
||||
echo "xvfb-run test failed, do not run it"
|
||||
USE_XVFB=false
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -60,7 +79,9 @@ fi
|
||||
# Start your application using node with exec to ensure proper signal handling
|
||||
#
|
||||
if [ "$USE_XVFB" = "true" ]; then
|
||||
echo "Executing node with xvfb-run..."
|
||||
exec xvfb-run --auto-servernum node dist/main
|
||||
else
|
||||
echo "Executing node without xvfb-run..."
|
||||
exec node dist/main
|
||||
fi
|
||||
Binary file not shown.
+2
-1
@@ -7,7 +7,8 @@
|
||||
"dashboard/**",
|
||||
"core/engines/webjs/*",
|
||||
"plus/engines/webjs/*",
|
||||
"apps/chatwoot/i18n/*.yaml"
|
||||
"apps/chatwoot/i18n/locales/*.yaml",
|
||||
"apps/chatwoot/i18n/locales/*.yml"
|
||||
],
|
||||
"watchAssets": true
|
||||
}
|
||||
|
||||
+15
-15
@@ -14,8 +14,8 @@
|
||||
"start:debug": "nest start --debug --watch",
|
||||
"start:prod": "node dist/main",
|
||||
"start:prod-exit": "node dist/main",
|
||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix --max-warnings=0",
|
||||
"lint-cache": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix --cache --max-warnings=0",
|
||||
"lint": "oxlint --deny-warnings",
|
||||
"lint-fix": "oxlint --fix --deny-warnings",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:cov": "jest --coverage",
|
||||
@@ -26,7 +26,7 @@
|
||||
"gows:proto": "yarn gows:proto:fetch && yarn gows:proto:build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@adiwajshing/baileys": "github:devlikeapro/Baileys#fork-master-2025-07-04",
|
||||
"@adiwajshing/baileys": "github:devlikeapro/Baileys#fork-master-2025-09-21",
|
||||
"@adiwajshing/keyed-db": "^0.2.4",
|
||||
"@aws-sdk/client-s3": "^3.633.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.633.0",
|
||||
@@ -41,7 +41,7 @@
|
||||
"@nestjs/config": "^3.2.3",
|
||||
"@nestjs/core": "^11.0.0",
|
||||
"@nestjs/passport": "^11.0.0",
|
||||
"@nestjs/platform-express": "^11.0.0",
|
||||
"@nestjs/platform-express": "^11.1.5",
|
||||
"@nestjs/platform-ws": "^11.0.0",
|
||||
"@nestjs/serve-static": "^5.0.0",
|
||||
"@nestjs/swagger": "^7.1.11",
|
||||
@@ -51,6 +51,7 @@
|
||||
"@types/lodash": "^4.14.194",
|
||||
"@types/mustache": "^4.2.5",
|
||||
"@types/passport": "^1.0.17",
|
||||
"@types/sqlite3": "^5.1.0",
|
||||
"@types/ws": "^8.5.4",
|
||||
"adm-zip": "0.5.10",
|
||||
"agentkeepalive": "^4.5.0",
|
||||
@@ -70,6 +71,7 @@
|
||||
"fs-extra": "^11.2.0",
|
||||
"google-protobuf": "^3.21.4",
|
||||
"https-proxy-agent": "^7.0.0",
|
||||
"ical.js": "^2.2.1",
|
||||
"ioredis": "^5",
|
||||
"joi": "^17.13.3",
|
||||
"knex": "^3.1.0",
|
||||
@@ -89,16 +91,17 @@
|
||||
"pino-pretty": "^11.2.1",
|
||||
"pretty-bytes": "5.6.0",
|
||||
"promise-retry": "^2.0.1",
|
||||
"puppeteer": "^24.10.0",
|
||||
"puppeteer": "^24.19.0",
|
||||
"qrcode": "^1.5.1",
|
||||
"qrcode-terminal": "^0.12.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^4.3.0",
|
||||
"rxjs": "^7.8.1",
|
||||
"sharp": "^0.33.4",
|
||||
"sqlite3": "^5.1.7",
|
||||
"swagger-ui-express": "^4.1.4",
|
||||
"ulid": "^2.3.0",
|
||||
"whatsapp-web.js": "github:devlikeapro/whatsapp-web.js#fork-main-2025-06-09",
|
||||
"whatsapp-web.js": "github:devlikeapro/whatsapp-web.js#fork-main-2025-09-10",
|
||||
"write-file-atomic": "^6.0.0",
|
||||
"yaml": "^2.7.1"
|
||||
},
|
||||
@@ -108,7 +111,7 @@
|
||||
"resolutions": {
|
||||
"bufferutil": "^4.0.8",
|
||||
"ws": "^8.18.0",
|
||||
"puppeteer": "^24.10.0",
|
||||
"puppeteer": "^24.19.0",
|
||||
"whatwg-url": "13.0.0",
|
||||
"libsignal": "github:devlikeapro/libsignal-node#fork-master",
|
||||
"axios": "^1.9.0"
|
||||
@@ -122,23 +125,20 @@
|
||||
"@types/express": "^4.17.3",
|
||||
"@types/jest": "26.0.10",
|
||||
"@types/node": "^18.14.2",
|
||||
"@types/node-fetch": "^2.6.13",
|
||||
"@types/semver": "^7.7.0",
|
||||
"@types/supertest": "^2.0.8",
|
||||
"@typescript-eslint/eslint-plugin": "3.9.1",
|
||||
"@typescript-eslint/parser": "3.9.1",
|
||||
"eslint": "7.7.0",
|
||||
"eslint-config-prettier": "^6.10.0",
|
||||
"eslint-plugin-import": "^2.20.1",
|
||||
"eslint-plugin-simple-import-sort": "^10.0.0",
|
||||
"grpc-tools": "^1.13.0",
|
||||
"jest": "^29.7.0",
|
||||
"oxlint": "^1.13.0",
|
||||
"prettier": "^1.19.1",
|
||||
"protoc-gen-ts": "^0.8.7",
|
||||
"supertest": "^4.0.2",
|
||||
"ts-jest": "^29.1.3",
|
||||
"ts-loader": "^6.2.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsconfig-paths": "^4.1.0",
|
||||
"typescript": "^4.8.4",
|
||||
"typescript": "5.9.2",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"jest": {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { isJidGroup } from '@adiwajshing/baileys';
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
transformAck,
|
||||
} from '@waha/structures/chats.dto';
|
||||
import { SendButtonsRequest } from '@waha/structures/chatting.buttons.dto';
|
||||
import { SendListRequest } from '@waha/structures/chatting.list.dto';
|
||||
|
||||
import { SessionManager } from '../core/abc/manager.abc';
|
||||
import {
|
||||
@@ -31,6 +32,7 @@ import {
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessagePollRequest,
|
||||
MessagePollVoteRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageStarRequest,
|
||||
@@ -121,8 +123,9 @@ export class ChattingController {
|
||||
|
||||
@Post('/sendButtons')
|
||||
@ApiOperation({
|
||||
summary: 'Send buttons (interactive message)',
|
||||
summary: 'Send buttons message (interactive)',
|
||||
description: 'Send Buttons',
|
||||
deprecated: true,
|
||||
})
|
||||
@UsePipes(new WAHAValidationPipe())
|
||||
async sendButtons(@Body() request: SendButtonsRequest) {
|
||||
@@ -130,6 +133,17 @@ export class ChattingController {
|
||||
return whatsapp.sendButtons(request);
|
||||
}
|
||||
|
||||
@Post('/sendList')
|
||||
@ApiOperation({
|
||||
summary: 'Send a list message (interactive)',
|
||||
description: 'Send a List message with sections and rows',
|
||||
})
|
||||
@UsePipes(new WAHAValidationPipe())
|
||||
async sendList(@Body() request: SendListRequest) {
|
||||
const whatsapp = await this.manager.getWorkingSession(request.session);
|
||||
return whatsapp.sendList(request);
|
||||
}
|
||||
|
||||
@Post('/forwardMessage')
|
||||
async forwardMessage(
|
||||
@Body() request: MessageForwardRequest,
|
||||
@@ -193,6 +207,17 @@ export class ChattingController {
|
||||
return whatsapp.sendPoll(request);
|
||||
}
|
||||
|
||||
@Post('/sendPollVote')
|
||||
@ApiOperation({
|
||||
summary: 'Vote on a poll',
|
||||
description: 'Cast vote(s) on an existing poll message',
|
||||
})
|
||||
@UsePipes(new WAHAValidationPipe())
|
||||
async sendPollVote(@Body() request: MessagePollVoteRequest) {
|
||||
const whatsapp = await this.manager.getWorkingSession(request.session);
|
||||
return whatsapp.sendPollVote(request);
|
||||
}
|
||||
|
||||
@Post('/sendLocation')
|
||||
async sendLocation(@Body() request: MessageLocationRequest) {
|
||||
const whatsapp = await this.manager.getWorkingSession(request.session);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { isLidUser } from '@adiwajshing/baileys/lib/WABinary/jid-utils';
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
@@ -22,6 +21,7 @@ import {
|
||||
import { PaginationParams, SortOrder } from '@waha/structures/pagination.dto';
|
||||
|
||||
import { SessionManager } from '../core/abc/manager.abc';
|
||||
import { isLidUser } from '@waha/core/utils/jids';
|
||||
|
||||
@ApiSecurity('api_key')
|
||||
@Controller('api/:session/lids')
|
||||
|
||||
@@ -50,3 +50,18 @@ export function HasBeenRetried(job: Job): boolean {
|
||||
const attemptsMade = job.attemptsMade + 1;
|
||||
return attemptsMade > 1;
|
||||
}
|
||||
|
||||
let base =
|
||||
process.env.WAHA_PUBLIC_URL ||
|
||||
process.env.WAHA_BASE_URL ||
|
||||
'http://localhost:3000';
|
||||
// cut / at the end
|
||||
base = base.replace(/\/+$/, '');
|
||||
|
||||
export function JobLink(job: Job): { text: string; url: string } {
|
||||
const text = `${job.queueName} => ${job.id}`;
|
||||
const url = `${base}/jobs/queue/${encodeURIComponent(job.queueName)}/${
|
||||
job.id
|
||||
}`;
|
||||
return { text: text, url: url };
|
||||
}
|
||||
@@ -48,10 +48,17 @@ export class AppsController {
|
||||
return await this.appsService.create(this.manager, app);
|
||||
}
|
||||
|
||||
@Get('/:id')
|
||||
@ApiOperation({ summary: 'Get app by ID' })
|
||||
@UsePipes(new WAHAValidationPipe())
|
||||
async get(@Param('id') id: string): Promise<App> {
|
||||
return await this.appsService.get(this.manager, id);
|
||||
}
|
||||
|
||||
@Put('/:id')
|
||||
@ApiOperation({ summary: 'Update an existing app' })
|
||||
@UsePipes(new WAHAValidationPipe())
|
||||
async update(@Param('id') id: string, @Body() app: App): Promise<void> {
|
||||
async update(@Param('id') id: string, @Body() app: App): Promise<App> {
|
||||
if (!app.id) {
|
||||
app.id = id;
|
||||
} else if (app.id !== id) {
|
||||
@@ -60,7 +67,7 @@ export class AppsController {
|
||||
);
|
||||
}
|
||||
|
||||
await this.appsService.update(this.manager, app);
|
||||
return await this.appsService.update(this.manager, app);
|
||||
}
|
||||
|
||||
@Delete('/:id')
|
||||
|
||||
@@ -4,19 +4,21 @@ import { parseBool } from '@waha/helpers';
|
||||
import * as basicAuth from 'express-basic-auth';
|
||||
|
||||
export function BullAuthMiddleware() {
|
||||
let username = process.env.WAHA_DASHBOARD_USERNAME;
|
||||
let password = process.env.WAHA_DASHBOARD_PASSWORD;
|
||||
const enabled = parseBool(process.env.WAHA_DASHBOARD_ENABLED);
|
||||
if (!enabled) {
|
||||
// Generate a random uuid4 username /password to prevent access
|
||||
username = 'admin';
|
||||
password = crypto.randomUUID();
|
||||
let username = process.env.WAHA_DASHBOARD_USERNAME || '';
|
||||
let password = process.env.WAHA_DASHBOARD_PASSWORD || '';
|
||||
if (process.env.WAHA_DASHBOARD_ENABLED) {
|
||||
const enabled = parseBool(process.env.WAHA_DASHBOARD_ENABLED);
|
||||
if (!enabled) {
|
||||
// Generate a random uuid4 username/password to effectively disable access
|
||||
username = 'admin';
|
||||
password = crypto.randomUUID();
|
||||
}
|
||||
}
|
||||
|
||||
return basicAuth({
|
||||
challenge: true,
|
||||
users: {
|
||||
[username]: password,
|
||||
[String(username)]: String(password),
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -1,6 +1,13 @@
|
||||
import { ChatWootAppConfig } from '@waha/apps/chatwoot/dto/config.dto';
|
||||
import { Type } from 'class-transformer';
|
||||
import { IsEnum, IsString, ValidateNested } from 'class-validator';
|
||||
import {
|
||||
IsBoolean,
|
||||
IsEnum,
|
||||
IsOptional,
|
||||
IsString,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
import { ApiExtraModels, ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export type AllowedAppConfig = ChatWootAppConfig;
|
||||
|
||||
@@ -8,6 +15,7 @@ export enum AppName {
|
||||
chatwoot = 'chatwoot',
|
||||
}
|
||||
|
||||
@ApiExtraModels(ChatWootAppConfig)
|
||||
export class App<T extends AllowedAppConfig = any> {
|
||||
@IsString()
|
||||
id: string;
|
||||
@@ -19,6 +27,16 @@ export class App<T extends AllowedAppConfig = any> {
|
||||
@IsEnum(AppName)
|
||||
app: AppName;
|
||||
|
||||
@ApiProperty({
|
||||
description:
|
||||
'Enable or disable this app without deleting it. If omitted, treated as enabled (true).',
|
||||
required: false,
|
||||
default: true,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
enabled?: boolean = true;
|
||||
|
||||
@ValidateNested()
|
||||
@Type((options) => {
|
||||
if (options && options.object && options.object.app) {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Knex } from 'knex';
|
||||
|
||||
exports.up = async function (knex: Knex) {
|
||||
// Add a boolean column 'enabled' defaulting to true and not nullable.
|
||||
const hasColumn = await knex.schema.hasColumn('apps', 'enabled');
|
||||
if (!hasColumn) {
|
||||
await knex.schema.alterTable('apps', (table) => {
|
||||
table.boolean('enabled').defaultTo(true);
|
||||
});
|
||||
// Ensure existing rows have enabled=true
|
||||
await knex('apps').update({ enabled: true });
|
||||
// Make the column NOT NULL
|
||||
await knex.schema.alterTable('apps', (table) => {
|
||||
table.boolean('enabled').notNullable().defaultTo(true).alter();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.down = async function (knex: Knex) {
|
||||
const hasColumn = await knex.schema.hasColumn('apps', 'enabled');
|
||||
if (hasColumn) {
|
||||
await knex.schema.alterTable('apps', (table) => {
|
||||
table.dropColumn('enabled');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -21,11 +21,15 @@ export class AppsDisabledService implements IAppsService {
|
||||
throw new AppsIsDisabledError();
|
||||
}
|
||||
|
||||
async get(manager: SessionManager, appId: string): Promise<App> {
|
||||
throw new AppsIsDisabledError();
|
||||
}
|
||||
|
||||
async create(manager: SessionManager, app: App): Promise<App> {
|
||||
throw new AppsIsDisabledError();
|
||||
}
|
||||
|
||||
async update(manager: SessionManager, app: App) {
|
||||
async update(manager: SessionManager, app: App): Promise<App> {
|
||||
throw new AppsIsDisabledError();
|
||||
}
|
||||
|
||||
|
||||
@@ -58,15 +58,32 @@ export class AppsEnabledService implements IAppsService {
|
||||
}
|
||||
|
||||
const service = this.getAppService(app);
|
||||
await service.beforeCreated(app);
|
||||
service.validate(app);
|
||||
// Only run beforeCreated when app is enabled (default true if omitted)
|
||||
if (app.enabled !== false) {
|
||||
await service.beforeCreated(app);
|
||||
}
|
||||
|
||||
const result = await repo.save(app);
|
||||
await this.restartIfRunning(manager, app.session);
|
||||
if (app.enabled) {
|
||||
await this.restartIfRunning(manager, app.session);
|
||||
}
|
||||
delete result.pk;
|
||||
return result;
|
||||
}
|
||||
|
||||
async update(manager: SessionManager, app: App) {
|
||||
async get(manager: SessionManager, appId: string): Promise<App> {
|
||||
const knex = manager.store.getWAHADatabase();
|
||||
const repo = new AppRepository(knex);
|
||||
const app = await repo.getById(appId);
|
||||
if (!app) {
|
||||
throw new NotFoundException(`App '${appId}' not found`);
|
||||
}
|
||||
delete (app as any).pk;
|
||||
return app;
|
||||
}
|
||||
|
||||
async update(manager: SessionManager, app: App): Promise<App> {
|
||||
await this.checkSessionExists(manager, app.session);
|
||||
const knex = manager.store.getWAHADatabase();
|
||||
const repo = new AppRepository(knex);
|
||||
@@ -86,11 +103,26 @@ export class AppsEnabledService implements IAppsService {
|
||||
}
|
||||
|
||||
const service = this.getAppService(app);
|
||||
await service.beforeUpdated(savedApp, app);
|
||||
service.validate(app);
|
||||
|
||||
const hasEnabledChange = savedApp.enabled !== app.enabled;
|
||||
|
||||
if (hasEnabledChange) {
|
||||
if (app.enabled) {
|
||||
await service.beforeEnabled(savedApp, app);
|
||||
} else {
|
||||
await service.beforeDisabled(savedApp, app);
|
||||
}
|
||||
} else {
|
||||
await service.beforeUpdated(savedApp, app);
|
||||
}
|
||||
|
||||
await repo.update(app.id, app);
|
||||
await this.restartIfRunning(manager, app.session);
|
||||
return;
|
||||
|
||||
const updated = await repo.getById(app.id);
|
||||
delete (updated as any)?.pk;
|
||||
return updated!;
|
||||
}
|
||||
|
||||
async delete(manager: SessionManager, appId: string) {
|
||||
@@ -110,7 +142,7 @@ export class AppsEnabledService implements IAppsService {
|
||||
async beforeSessionStart(session: WhatsappSession, store: DataStore) {
|
||||
const knex = store.getWAHADatabase();
|
||||
const repo = new AppRepository(knex);
|
||||
const apps = await repo.getAllBySession(session.name);
|
||||
const apps = await repo.getEnabledBySession(session.name);
|
||||
for (const app of apps) {
|
||||
const service = this.getAppService(app);
|
||||
await service.beforeSessionStart(app, session);
|
||||
|
||||
@@ -5,8 +5,20 @@ import { WhatsappSession } from '@waha/core/abc/session.abc';
|
||||
* Exact App service
|
||||
*/
|
||||
export interface IAppService {
|
||||
validate(app: App): void;
|
||||
|
||||
beforeCreated(app: App): Promise<void>;
|
||||
|
||||
/**
|
||||
* Called only when the app transitions from disabled -> enabled.
|
||||
*/
|
||||
beforeEnabled(savedApp: App, newApp: App): Promise<void>;
|
||||
|
||||
/**
|
||||
* Called only when the app transitions from enabled -> disabled.
|
||||
*/
|
||||
beforeDisabled(savedApp: App, newApp: App): Promise<void>;
|
||||
|
||||
beforeUpdated(savedApp: App, newApp: App): Promise<void>;
|
||||
|
||||
beforeDeleted(app: App): Promise<void>;
|
||||
|
||||
@@ -7,9 +7,11 @@ import { Knex } from 'knex';
|
||||
export interface IAppsService {
|
||||
list(manager: SessionManager, session: string): Promise<App[]>;
|
||||
|
||||
get(manager: SessionManager, appId: string): Promise<App>;
|
||||
|
||||
create(manager: SessionManager, app: App): Promise<App>;
|
||||
|
||||
update(manager: SessionManager, app: App): Promise<void>;
|
||||
update(manager: SessionManager, app: App): Promise<App>;
|
||||
|
||||
delete(manager: SessionManager, appId: string): Promise<void>;
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ export class AppRepository {
|
||||
* Saves an app to the database
|
||||
*/
|
||||
async save(app: Omit<App, 'pk'>): Promise<AppDB> {
|
||||
const appToSave = { ...app };
|
||||
const appToSave: any = { ...app };
|
||||
if (appToSave.config && typeof appToSave.config === 'object') {
|
||||
appToSave.config = JSON.stringify(appToSave.config);
|
||||
}
|
||||
@@ -29,7 +29,25 @@ export class AppRepository {
|
||||
private deserialize(app: AppDB): AppDB {
|
||||
const parsedConfig =
|
||||
typeof app.config === 'string' ? JSON.parse(app.config) : app.config;
|
||||
return { ...app, config: parsedConfig };
|
||||
|
||||
// Ensure 'enabled' is boolean (SQLite may return 0/1)
|
||||
let enabled: boolean;
|
||||
switch (app.enabled as any) {
|
||||
case undefined:
|
||||
case true:
|
||||
case 1:
|
||||
case '1':
|
||||
enabled = true;
|
||||
break;
|
||||
case false:
|
||||
case 0:
|
||||
enabled = false;
|
||||
break;
|
||||
default:
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
return { ...(app as any), enabled: enabled, config: parsedConfig } as AppDB;
|
||||
}
|
||||
|
||||
private serialize<T extends Partial<App>>(app: T): T {
|
||||
@@ -51,6 +69,20 @@ export class AppRepository {
|
||||
return this.deserialize(app);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an enabled app by id, or null if not found or disabled.
|
||||
*/
|
||||
async findEnabledAppById(id: string): Promise<AppDB | null> {
|
||||
const app = await this.knex(this.tableName)
|
||||
.where('id', id)
|
||||
.andWhere('enabled', true)
|
||||
.first();
|
||||
if (!app) {
|
||||
return null;
|
||||
}
|
||||
return this.deserialize(app);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all apps
|
||||
*/
|
||||
@@ -62,11 +94,26 @@ export class AppRepository {
|
||||
.then((apps) => apps.map((app) => this.deserialize(app)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets only enabled apps for a session.
|
||||
*/
|
||||
async getEnabledBySession(session: string): Promise<AppDB[]> {
|
||||
return this.knex(this.tableName)
|
||||
.select('*')
|
||||
.where('session', session)
|
||||
.andWhere('enabled', true)
|
||||
.orderBy('id', 'asc')
|
||||
.then((apps) => apps.map((app) => this.deserialize(app)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an app
|
||||
*/
|
||||
async update(id: string, app: Partial<Omit<App, 'id'>>): Promise<void> {
|
||||
const appToUpdate = this.serialize(app);
|
||||
const appToUpdate: any = this.serialize(app);
|
||||
if (appToUpdate.enabled === undefined) {
|
||||
delete appToUpdate.enabled; // keep current value
|
||||
}
|
||||
await this.knex(this.tableName).where('id', id).update(appToUpdate);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import { BullAuthMiddleware } from '@waha/apps/app_sdk/auth';
|
||||
import { AppsDisabledService } from '@waha/apps/app_sdk/services/AppsDisabledService';
|
||||
import { AppsEnabledService } from '@waha/apps/app_sdk/services/AppsEnabledService';
|
||||
import { AppsService } from '@waha/apps/app_sdk/services/IAppsService';
|
||||
import { ChatwootLocalesController } from '@waha/apps/chatwoot/api/chatwoot.locales.controller';
|
||||
import { ChatWootExports } from '@waha/apps/chatwoot/chatwoot.module';
|
||||
import { parseBool } from '@waha/helpers';
|
||||
import { RMutexModule } from '@waha/modules/rmutex';
|
||||
@@ -88,7 +89,7 @@ const AppsDisabled = {
|
||||
},
|
||||
],
|
||||
imports: [],
|
||||
controllers: [AppsController],
|
||||
controllers: [AppsController, ChatwootLocalesController],
|
||||
};
|
||||
|
||||
function checkApiKey() {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Controller, Get } from '@nestjs/common';
|
||||
import { sortBy } from 'lodash';
|
||||
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import { LOCALE_NAMES } from '@waha/apps/chatwoot/locale';
|
||||
import { i18n } from '@waha/apps/chatwoot/i18n';
|
||||
|
||||
interface LanguageResponse {
|
||||
name: string;
|
||||
@@ -17,9 +18,14 @@ export class ChatwootLocalesController {
|
||||
description: 'Get available languages for Chatwoot app',
|
||||
})
|
||||
getLanguages(): LanguageResponse[] {
|
||||
return Object.entries(LOCALE_NAMES).map(([locale, name]) => ({
|
||||
name: name,
|
||||
locale: locale,
|
||||
}));
|
||||
const locales = i18n.available();
|
||||
const priority = ['en-US', 'pt-BR', 'es-ES'];
|
||||
return sortBy(locales, [
|
||||
(x) => {
|
||||
const idx = priority.indexOf(x.locale);
|
||||
return idx === -1 ? Number.MAX_SAFE_INTEGER : idx;
|
||||
},
|
||||
'locale',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,26 @@
|
||||
import { Body, Controller, Param, Post } from '@nestjs/common';
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
NotFoundException,
|
||||
Param,
|
||||
Post,
|
||||
} from '@nestjs/common';
|
||||
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||
import { GetChatID } from '@waha/apps/chatwoot/client/ids';
|
||||
import { FindChatID } from '@waha/apps/chatwoot/client/ids';
|
||||
import { EventName, MessageType } from '@waha/apps/chatwoot/client/types';
|
||||
import { INBOX_CONTACT_CHAT_ID } from '@waha/apps/chatwoot/const';
|
||||
import { InboxData } from '@waha/apps/chatwoot/consumers/types';
|
||||
import { ChatWootQueueService } from '@waha/apps/chatwoot/services/ChatWootQueueService';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
import { AppRepository } from '@waha/apps/app_sdk/storage/AppRepository';
|
||||
|
||||
@Controller('webhooks/chatwoot/')
|
||||
@ApiTags('🧩 Apps')
|
||||
export class ChatwootWebhookController {
|
||||
constructor(private readonly chatWootQueueService: ChatWootQueueService) {}
|
||||
constructor(
|
||||
private readonly chatWootQueueService: ChatWootQueueService,
|
||||
private readonly manager: SessionManager,
|
||||
) {}
|
||||
|
||||
@Post(':session/:id')
|
||||
@ApiOperation({
|
||||
@@ -41,9 +52,17 @@ export class ChatwootWebhookController {
|
||||
body: body,
|
||||
};
|
||||
|
||||
// Skip if app is disabled or does not exist
|
||||
const knex = this.manager.store.getWAHADatabase();
|
||||
const repo = new AppRepository(knex);
|
||||
const app = await repo.findEnabledAppById(id);
|
||||
if (!app || app.session !== session) {
|
||||
throw new NotFoundException(`App '${id}' not found`);
|
||||
}
|
||||
|
||||
// Check if it's a command message (sent to the special inbox contact)
|
||||
const sender = body?.conversation?.meta?.sender;
|
||||
const chatId = GetChatID(sender);
|
||||
const chatId = FindChatID(sender);
|
||||
const isCommandsChat = chatId === INBOX_CONTACT_CHAT_ID;
|
||||
|
||||
// Check if it's a deleted message
|
||||
@@ -70,6 +89,7 @@ export class ChatwootWebhookController {
|
||||
return { success: true };
|
||||
default:
|
||||
// Ignore other events
|
||||
await this.chatWootQueueService.addJobToQueue(body.event, data);
|
||||
return { success: true };
|
||||
}
|
||||
}
|
||||
|
||||
+4
-5
@@ -1,8 +1,7 @@
|
||||
import { public_conversation } from '@figuro/chatwoot-sdk';
|
||||
import { ChatWootAPIConfig } from '@waha/apps/chatwoot/client/interfaces';
|
||||
import * as NodeCache from 'node-cache';
|
||||
|
||||
import { IConversationCache } from './IConversationCache';
|
||||
import { ConversationId, IConversationCache } from './IConversationCache';
|
||||
|
||||
const cache: NodeCache = new NodeCache({
|
||||
stdTTL: 24 * 60 * 60, // 1 day
|
||||
@@ -16,7 +15,7 @@ export function CacheForConfig(config: ChatWootAPIConfig): ConversationCache {
|
||||
class ConversationCache implements IConversationCache {
|
||||
constructor(private prefix: string) {}
|
||||
|
||||
fullKey(key: string) {
|
||||
private fullKey(key: string) {
|
||||
return `${this.prefix}.${key}`;
|
||||
}
|
||||
|
||||
@@ -25,7 +24,7 @@ class ConversationCache implements IConversationCache {
|
||||
cache.del(fullKey);
|
||||
}
|
||||
|
||||
get(key: string): public_conversation | null {
|
||||
get(key: string): ConversationId | null {
|
||||
const fullKey = this.fullKey(key);
|
||||
return cache.get(fullKey) || null;
|
||||
}
|
||||
@@ -35,7 +34,7 @@ class ConversationCache implements IConversationCache {
|
||||
return cache.has(fullKey);
|
||||
}
|
||||
|
||||
set(key: string, value: public_conversation): void {
|
||||
set(key: string, value: ConversationId): void {
|
||||
const fullKey = this.fullKey(key);
|
||||
cache.set(fullKey, value);
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
import { public_conversation } from '@figuro/chatwoot-sdk';
|
||||
export type ConversationId = number;
|
||||
|
||||
export interface IConversationCache {
|
||||
get(key: string): public_conversation | null;
|
||||
set(key: string, value: public_conversation): void;
|
||||
get(key: string): ConversationId | null;
|
||||
set(key: string, value: ConversationId): void;
|
||||
has(key: string): boolean;
|
||||
delete(key: string): void;
|
||||
clean(): void;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { RegisterAppQueue } from '@waha/apps/app_sdk/BullUtils';
|
||||
import {
|
||||
ExponentialRetriesJobOptions,
|
||||
@@ -26,6 +25,8 @@ import { WAHASessionStatusConsumer } from './consumers/waha/session.status';
|
||||
import { ChatWootQueueService } from './services/ChatWootQueueService';
|
||||
import { ChatWootScheduleService } from './services/ChatWootScheduleService';
|
||||
import { ChatWootWAHAQueueService } from './services/ChatWootWAHAQueueService';
|
||||
import { ChatWootConversationCreatedConsumer } from './consumers/inbox/conversation_created';
|
||||
import { ChatWootConversationStatusChangedConsumer } from '@waha/apps/chatwoot/consumers/inbox/conversation_status_changed';
|
||||
|
||||
const CONTROLLERS = [ChatwootWebhookController, ChatwootLocalesController];
|
||||
|
||||
@@ -66,6 +67,14 @@ const IMPORTS = lodash.flatten([
|
||||
name: QueueName.INBOX_MESSAGE_UPDATED,
|
||||
defaultJobOptions: merge(ExponentialRetriesJobOptions, JobRemoveOptions),
|
||||
}),
|
||||
RegisterAppQueue({
|
||||
name: QueueName.INBOX_CONVERSATION_CREATED,
|
||||
defaultJobOptions: merge(NoRetriesJobOptions, JobRemoveOptions),
|
||||
}),
|
||||
RegisterAppQueue({
|
||||
name: QueueName.INBOX_CONVERSATION_STATUS_CHANGED,
|
||||
defaultJobOptions: merge(NoRetriesJobOptions, JobRemoveOptions),
|
||||
}),
|
||||
RegisterAppQueue({
|
||||
name: QueueName.INBOX_MESSAGE_DELETED,
|
||||
defaultJobOptions: merge(ExponentialRetriesJobOptions, JobRemoveOptions),
|
||||
@@ -80,6 +89,9 @@ const PROVIDERS = [
|
||||
ChatWootInboxMessageCreatedConsumer,
|
||||
ChatWootInboxMessageUpdatedConsumer,
|
||||
ChatWootInboxMessageDeletedConsumer,
|
||||
// Conversation events
|
||||
ChatWootConversationCreatedConsumer,
|
||||
ChatWootConversationStatusChangedConsumer,
|
||||
ChatWootInboxCommandsConsumer,
|
||||
WAHASessionStatusConsumer,
|
||||
WAHAMessageAnyConsumer,
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import ChatwootClient, {
|
||||
ApiError,
|
||||
ApiError as ChatWootAPIError,
|
||||
public_contact_create_update_payload,
|
||||
public_conversation,
|
||||
} from '@figuro/chatwoot-sdk';
|
||||
import { ILogger } from '@waha/apps/app_sdk/ILogger';
|
||||
import { ContactAPI } from '@waha/apps/chatwoot/client/ContactAPI';
|
||||
import { ContactService } from '@waha/apps/chatwoot/client/ContactService';
|
||||
import { Conversation } from '@waha/apps/chatwoot/client/Conversation';
|
||||
import { ConversationAPI } from '@waha/apps/chatwoot/client/ConversationAPI';
|
||||
import { ConversationService } from '@waha/apps/chatwoot/client/ConversationService';
|
||||
import { ChatWootAPIConfig } from '@waha/apps/chatwoot/client/interfaces';
|
||||
import { InboxContactInfo } from '@waha/apps/chatwoot/contacts/InboxContactInfo';
|
||||
import { Locale } from '@waha/apps/chatwoot/locale';
|
||||
import { Locale } from '@waha/apps/chatwoot/i18n/locale';
|
||||
|
||||
import { CacheForConfig } from '../cache/ConversationCache';
|
||||
import { IConversationCache } from '../cache/IConversationCache';
|
||||
import {
|
||||
ConversationId,
|
||||
IConversationCache,
|
||||
} from '../cache/IConversationCache';
|
||||
|
||||
export interface ContactInfo {
|
||||
ChatId(): string;
|
||||
@@ -29,8 +31,8 @@ export class ContactConversationService {
|
||||
|
||||
constructor(
|
||||
private config: ChatWootAPIConfig,
|
||||
private contactAPI: ContactAPI,
|
||||
private conversationAPI: ConversationAPI,
|
||||
private contactService: ContactService,
|
||||
private conversationService: ConversationService,
|
||||
private accountAPI: ChatwootClient,
|
||||
private logger: ILogger,
|
||||
private l: Locale,
|
||||
@@ -40,7 +42,7 @@ export class ContactConversationService {
|
||||
|
||||
private async upsertByContactInfo(
|
||||
contactInfo: ContactInfo,
|
||||
): Promise<public_conversation> {
|
||||
): Promise<ConversationId> {
|
||||
const chatId = contactInfo.ChatId();
|
||||
|
||||
// Check cache for chat id
|
||||
@@ -51,61 +53,70 @@ export class ContactConversationService {
|
||||
//
|
||||
// Find or create contact
|
||||
//
|
||||
let contact = await this.contactAPI.searchByAnyID(chatId);
|
||||
let contact = await this.contactService.searchByAnyID(chatId);
|
||||
if (!contact) {
|
||||
const request = await contactInfo.PublicContactCreate();
|
||||
contact = await this.contactAPI.create(chatId, request);
|
||||
contact = await this.contactService.create(chatId, request);
|
||||
}
|
||||
|
||||
// Update custom attributes - always
|
||||
const attributes = await contactInfo.Attributes();
|
||||
this.logger.info(
|
||||
`Updating contact custom attributes for chat.id: ${chatId}, contact.id: ${contact.data.id}`,
|
||||
`Updating if required contact custom attributes for chat.id: ${chatId}, contact.id: ${contact.data.id}`,
|
||||
);
|
||||
await this.contactAPI.updateCustomAttributes(contact.data, attributes);
|
||||
await this.contactService.upsertCustomAttributes(contact.data, attributes);
|
||||
|
||||
// Update Avatar if nothing, but keep the original one if any
|
||||
if (!contact.data.thumbnail) {
|
||||
const avatarUrl = await contactInfo.AvatarUrl();
|
||||
const avatarUrl = await contactInfo.AvatarUrl().catch((err) => {
|
||||
this.logger.warn(
|
||||
`Error getting avatar for chat.id from WhatsApp: ${chatId}`,
|
||||
);
|
||||
this.logger.warn(err);
|
||||
return null;
|
||||
});
|
||||
if (avatarUrl) {
|
||||
this.contactAPI.updateAvatarUrlSafe(contact.data.id, avatarUrl);
|
||||
this.contactService.updateAvatarUrlSafe(contact.data.id, avatarUrl);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.info(
|
||||
`Using contact for chat.id: ${chatId}, contact.id: ${contact.sourceId}`,
|
||||
`Using contact for chat.id: ${chatId}, contact.id: ${contact.data.id}, contact.sourceId: ${contact.sourceId}`,
|
||||
);
|
||||
|
||||
//
|
||||
// Get or create a conversation for this inbox
|
||||
//
|
||||
const conversation = await this.conversationAPI.upsert(contact.sourceId);
|
||||
const conversation = await this.conversationService.upsert({
|
||||
id: contact.data.id,
|
||||
sourceId: contact.sourceId,
|
||||
});
|
||||
this.logger.info(
|
||||
`Using conversation for chat.id: ${chatId}, conversation.id: ${conversation.id}, contact.id: ${contact.sourceId}`,
|
||||
);
|
||||
|
||||
// Save to cache
|
||||
this.cache.set(chatId, conversation);
|
||||
return conversation;
|
||||
this.cache.set(chatId, conversation.id);
|
||||
return conversation.id;
|
||||
}
|
||||
|
||||
public async ConversationByContact(
|
||||
contactInfo: ContactInfo,
|
||||
): Promise<Conversation> {
|
||||
const chatId = contactInfo.ChatId();
|
||||
const publicConversation = await this.upsertByContactInfo(contactInfo);
|
||||
const conversationId = await this.upsertByContactInfo(contactInfo);
|
||||
const conversation = new Conversation(
|
||||
this.accountAPI,
|
||||
this.config.accountId,
|
||||
publicConversation.id,
|
||||
conversationId,
|
||||
);
|
||||
conversation.onError = (err) => {
|
||||
if (err instanceof ApiError) {
|
||||
if (err instanceof ChatWootAPIError) {
|
||||
// invalidate cache
|
||||
this.cache.delete(chatId);
|
||||
this.logger.error(`ApiError: ${err.message}`);
|
||||
this.logger.error(
|
||||
`ApiError occurred, invalidating cache for chat.id: ${chatId}, conversation.id: ${publicConversation.id}`,
|
||||
`ApiError occurred, invalidating cache for chat.id: ${chatId}, conversation.id: ${conversationId}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -127,4 +138,26 @@ export class ContactConversationService {
|
||||
public async InboxNotifications() {
|
||||
return this.ConversationByContact(new InboxContactInfo(this.l));
|
||||
}
|
||||
|
||||
public ResetCache(chatIds: Array<string>) {
|
||||
this.logger.info(`Resetting cache chat ids: ${chatIds.join(', ')}`);
|
||||
for (const chatId of chatIds) {
|
||||
this.cache.delete(chatId);
|
||||
}
|
||||
}
|
||||
|
||||
public ResetMismatchedCache(chatIds: Array<string>, value: ConversationId) {
|
||||
for (const chatId of chatIds) {
|
||||
if (!this.cache.has(chatId)) {
|
||||
continue;
|
||||
}
|
||||
const current = this.cache.get(chatId);
|
||||
if (current !== value) {
|
||||
this.logger.info(
|
||||
`Resetting cache for chat id: ${chatId}, value changed from ${current} to ${value}`,
|
||||
);
|
||||
this.cache.delete(chatId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-7
@@ -13,13 +13,14 @@ import { isJidCusFormat } from '@waha/utils/wa';
|
||||
import * as lodash from 'lodash';
|
||||
|
||||
import { AttributeKey } from '../const';
|
||||
import { E164Parser } from '@waha/core/utils/PhoneJidNormalizer';
|
||||
|
||||
export interface ContactResponse {
|
||||
data: generic_id & contact;
|
||||
sourceId: string;
|
||||
}
|
||||
|
||||
export class ContactAPI {
|
||||
export class ContactService {
|
||||
constructor(
|
||||
private config: ChatWootAPIConfig,
|
||||
private accountAPI: ChatwootClient,
|
||||
@@ -64,8 +65,8 @@ export class ContactAPI {
|
||||
|
||||
if (isJidCusFormat(chatId)) {
|
||||
// Search by phone
|
||||
let phone_number = chatId.split('@')[0];
|
||||
phone_number = phone_number.replace('+', '');
|
||||
const phoneNumberE164 = E164Parser.fromJid(chatId);
|
||||
const phone_number = phoneNumberE164.replace('+', '');
|
||||
payload[payload.length - 1].query_operator = 'OR';
|
||||
payload.push({
|
||||
attribute_key: 'phone_number',
|
||||
@@ -96,18 +97,22 @@ export class ContactAPI {
|
||||
};
|
||||
}
|
||||
|
||||
public updateCustomAttributes(
|
||||
public async upsertCustomAttributes(
|
||||
contact: generic_id & contact,
|
||||
attributes: any,
|
||||
) {
|
||||
): Promise<boolean> {
|
||||
if (lodash.isEqual(attributes, contact.custom_attributes)) {
|
||||
return false;
|
||||
}
|
||||
const update: contact_update = {
|
||||
custom_attributes: { ...contact.custom_attributes, ...attributes },
|
||||
};
|
||||
return this.accountAPI.contacts.update({
|
||||
await this.accountAPI.contacts.update({
|
||||
id: contact.id,
|
||||
accountId: this.config.accountId,
|
||||
data: update,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
public async create(
|
||||
@@ -142,7 +147,7 @@ export class ContactAPI {
|
||||
})
|
||||
.catch((e) => {
|
||||
this.logger.warn(
|
||||
'Error updating avatar_url for contact.id: ' + contactId,
|
||||
`Error updating avatar_url for contact.id: ${contactId}`,
|
||||
);
|
||||
this.logger.warn(e);
|
||||
});
|
||||
@@ -1,52 +0,0 @@
|
||||
import { public_conversation } from '@figuro/chatwoot-sdk';
|
||||
import { ILogger } from '@waha/apps/app_sdk/ILogger';
|
||||
import {
|
||||
ChatWootAPIConfig,
|
||||
ChatWootInboxAPI,
|
||||
} from '@waha/apps/chatwoot/client/interfaces';
|
||||
|
||||
export class ConversationAPI {
|
||||
constructor(
|
||||
private config: ChatWootAPIConfig,
|
||||
private inboxAPI: ChatWootInboxAPI,
|
||||
private logger: ILogger,
|
||||
) {}
|
||||
|
||||
private async find(
|
||||
contactIdentifier: string,
|
||||
): Promise<public_conversation | null> {
|
||||
const request = {
|
||||
inboxIdentifier: this.config.inboxIdentifier,
|
||||
contactIdentifier: contactIdentifier,
|
||||
};
|
||||
const conversations = await this.inboxAPI.conversations.list(request);
|
||||
if (conversations.length != 0) {
|
||||
return conversations[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private async create(
|
||||
contactIdentifier: string,
|
||||
): Promise<public_conversation> {
|
||||
const conversation = await this.inboxAPI.conversations.create({
|
||||
inboxIdentifier: this.config.inboxIdentifier,
|
||||
contactIdentifier: contactIdentifier,
|
||||
});
|
||||
this.logger.info(
|
||||
`Created conversation.id: ${conversation.id} for contact.id: ${contactIdentifier}`,
|
||||
);
|
||||
return conversation;
|
||||
}
|
||||
|
||||
async upsert(contactIdentifier: string): Promise<public_conversation> {
|
||||
let conversation = await this.find(contactIdentifier);
|
||||
if (!conversation) {
|
||||
conversation = await this.create(contactIdentifier);
|
||||
}
|
||||
this.logger.info(
|
||||
`Using conversation.id: ${conversation.id} for contact.id: ${contactIdentifier}`,
|
||||
);
|
||||
return conversation;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import ChatwootClient, { contact_conversations } from '@figuro/chatwoot-sdk';
|
||||
import { ILogger } from '@waha/apps/app_sdk/ILogger';
|
||||
import {
|
||||
ChatWootAPIConfig,
|
||||
ChatWootInboxAPI,
|
||||
} from '@waha/apps/chatwoot/client/interfaces';
|
||||
import type { conversation } from '@figuro/chatwoot-sdk/dist/models/conversation';
|
||||
import { ConversationSelector } from '@waha/apps/chatwoot/services/ConversationSelector';
|
||||
|
||||
export type ConversationResult = Pick<conversation, 'id' | 'account_id'>;
|
||||
|
||||
export interface ContactIds {
|
||||
id: number;
|
||||
sourceId: string;
|
||||
}
|
||||
|
||||
export class ConversationService {
|
||||
constructor(
|
||||
private config: ChatWootAPIConfig,
|
||||
private accountAPI: ChatwootClient,
|
||||
private inboxAPI: ChatWootInboxAPI,
|
||||
private selector: ConversationSelector,
|
||||
private logger: ILogger,
|
||||
) {}
|
||||
|
||||
private async find(contact: ContactIds): Promise<ConversationResult | null> {
|
||||
const result: { payload: contact_conversations } =
|
||||
(await this.accountAPI.contacts.listConversations({
|
||||
accountId: this.config.accountId,
|
||||
id: contact.id,
|
||||
})) as any;
|
||||
const conversations = result.payload;
|
||||
return this.selector.select(conversations);
|
||||
}
|
||||
|
||||
private async create(contact: ContactIds): Promise<ConversationResult> {
|
||||
const conversation = await this.inboxAPI.conversations.create({
|
||||
inboxIdentifier: this.config.inboxIdentifier,
|
||||
contactIdentifier: contact.sourceId,
|
||||
});
|
||||
this.logger.info(
|
||||
`Created conversation.id: ${conversation.id} for contact.id: ${contact.id}, contact.sourceId: ${contact.sourceId}`,
|
||||
);
|
||||
return conversation;
|
||||
}
|
||||
|
||||
async upsert(contact: ContactIds): Promise<ConversationResult> {
|
||||
let conversation = await this.find(contact);
|
||||
if (!conversation) {
|
||||
conversation = await this.create(contact);
|
||||
}
|
||||
this.logger.info(
|
||||
`Using conversation.id: ${conversation.id} for contact.id: ${contact.id}, contact.sourceId: ${contact.sourceId}`,
|
||||
);
|
||||
return conversation;
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
import ChatwootClient from '@figuro/chatwoot-sdk';
|
||||
import { ChatWootAccountAPIConfig } from '@waha/apps/chatwoot/client/interfaces';
|
||||
import {
|
||||
CustomAttributeModel,
|
||||
CustomAttributeType,
|
||||
} from '@waha/apps/chatwoot/client/types';
|
||||
|
||||
export interface CustomAttribute {
|
||||
key: string;
|
||||
name: string;
|
||||
type: CustomAttributeType;
|
||||
description: string;
|
||||
model: CustomAttributeModel;
|
||||
}
|
||||
|
||||
export class CustomAttributesAPI {
|
||||
constructor(
|
||||
private config: ChatWootAccountAPIConfig,
|
||||
private accountAPI: ChatwootClient,
|
||||
) {}
|
||||
|
||||
async upsert(attribute: CustomAttribute): Promise<void> {
|
||||
const attributes = await this.accountAPI.customAttributes.list({
|
||||
accountId: this.config.accountId,
|
||||
attributeModel: String(attribute.model) as '0' | '1',
|
||||
});
|
||||
const existing = attributes.find((a) => a.attribute_key === attribute.key);
|
||||
|
||||
if (existing) {
|
||||
await this.accountAPI.customAttributes.update({
|
||||
accountId: this.config.accountId,
|
||||
id: existing.id,
|
||||
data: {
|
||||
attribute_key: attribute.key,
|
||||
attribute_display_name: attribute.name,
|
||||
attribute_display_type: attribute.type,
|
||||
attribute_description: attribute.description,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await this.accountAPI.customAttributes.create({
|
||||
accountId: this.config.accountId,
|
||||
data: {
|
||||
attribute_key: attribute.key,
|
||||
attribute_display_name: attribute.name,
|
||||
attribute_display_type: attribute.type,
|
||||
attribute_description: attribute.description,
|
||||
attribute_model: attribute.model,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import ChatwootClient from '@figuro/chatwoot-sdk';
|
||||
import { ChatWootAccountAPIConfig } from '@waha/apps/chatwoot/client/interfaces';
|
||||
import {
|
||||
CustomAttributeModel,
|
||||
CustomAttributeType,
|
||||
} from '@waha/apps/chatwoot/client/types';
|
||||
import type { custom_attribute } from '@figuro/chatwoot-sdk/dist/models/custom_attribute';
|
||||
|
||||
export interface CustomAttribute {
|
||||
key: string;
|
||||
name: string;
|
||||
type: CustomAttributeType;
|
||||
description: string;
|
||||
model: CustomAttributeModel;
|
||||
}
|
||||
|
||||
export class CustomAttributesService {
|
||||
constructor(
|
||||
private config: ChatWootAccountAPIConfig,
|
||||
private accountAPI: ChatwootClient,
|
||||
) {}
|
||||
|
||||
async upsert(attributes: Array<CustomAttribute>): Promise<void> {
|
||||
const current: Record<CustomAttributeModel, Array<custom_attribute>> = {
|
||||
[CustomAttributeModel.CONVERSATION]: [],
|
||||
[CustomAttributeModel.CONTACT]: [],
|
||||
};
|
||||
const models = [
|
||||
CustomAttributeModel.CONVERSATION,
|
||||
CustomAttributeModel.CONTACT,
|
||||
];
|
||||
for (const model of models) {
|
||||
current[model] = await this.accountAPI.customAttributes.list({
|
||||
accountId: this.config.accountId,
|
||||
attributeModel: String(model) as '0' | '1',
|
||||
});
|
||||
}
|
||||
|
||||
for (const attribute of attributes) {
|
||||
const existing = current[attribute.model].find(
|
||||
(a) => a.attribute_key === attribute.key,
|
||||
);
|
||||
if (existing) {
|
||||
await this.accountAPI.customAttributes.update({
|
||||
accountId: this.config.accountId,
|
||||
id: existing.id,
|
||||
data: {
|
||||
attribute_key: attribute.key,
|
||||
attribute_display_name: attribute.name,
|
||||
attribute_display_type: attribute.type,
|
||||
attribute_description: attribute.description,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await this.accountAPI.customAttributes.create({
|
||||
accountId: this.config.accountId,
|
||||
data: {
|
||||
attribute_key: attribute.key,
|
||||
attribute_display_name: attribute.name,
|
||||
attribute_display_type: attribute.type,
|
||||
attribute_description: attribute.description,
|
||||
attribute_model: attribute.model,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { isLidUser } from '@adiwajshing/baileys/lib/WABinary/jid-utils';
|
||||
import { AttributeKey } from '@waha/apps/chatwoot/const';
|
||||
import { WhatsAppMessage } from '@waha/apps/chatwoot/storage';
|
||||
import { buildMessageId } from '@waha/core/engines/noweb/session.noweb.core';
|
||||
import { isLidUser } from '@waha/core/utils/jids';
|
||||
|
||||
export function GetJID(contact: any): string | null {
|
||||
return contact?.custom_attributes?.[AttributeKey.WA_JID];
|
||||
@@ -15,6 +15,29 @@ export function GetChatID(contact: any): string | null {
|
||||
return contact?.custom_attributes?.[AttributeKey.WA_CHAT_ID];
|
||||
}
|
||||
|
||||
export function GetAllChatIDs(contact: any): Array<string> {
|
||||
const attrs = contact?.custom_attributes || {};
|
||||
const ids = [
|
||||
attrs[AttributeKey.WA_CHAT_ID],
|
||||
attrs[AttributeKey.WA_JID],
|
||||
attrs[AttributeKey.WA_LID],
|
||||
];
|
||||
return ids.filter(Boolean);
|
||||
}
|
||||
|
||||
export function FindChatID(contact: any): string | null {
|
||||
if (GetJID(contact)) {
|
||||
return GetJID(contact);
|
||||
}
|
||||
if (GetLID(contact)) {
|
||||
return GetLID(contact);
|
||||
}
|
||||
if (GetChatID(contact)) {
|
||||
return GetChatID(contact);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function SerializeWhatsAppKey(message: WhatsAppMessage): string {
|
||||
const key = {
|
||||
id: message.message_id,
|
||||
|
||||
@@ -51,3 +51,10 @@ export enum CustomAttributeModel {
|
||||
CONVERSATION = 0,
|
||||
CONTACT = 1,
|
||||
}
|
||||
|
||||
export enum ConversationStatus {
|
||||
OPEN = 'open',
|
||||
PENDING = 'pending',
|
||||
SNOOZED = 'snoozed',
|
||||
RESOLVED = 'resolved',
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CustomAttribute } from '@waha/apps/chatwoot/client/CustomAttributesAPI';
|
||||
import { CustomAttribute } from '@waha/apps/chatwoot/client/CustomAttributesService';
|
||||
|
||||
import { CustomAttributeModel, CustomAttributeType } from './client/types';
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ export enum QueueName {
|
||||
//
|
||||
INBOX_MESSAGE_CREATED = 'chatwoot.inbox | message_created',
|
||||
INBOX_MESSAGE_UPDATED = 'chatwoot.inbox | message_updated',
|
||||
INBOX_CONVERSATION_CREATED = 'chatwoot.inbox | conversation_created',
|
||||
INBOX_CONVERSATION_STATUS_CHANGED = 'chatwoot.inbox | conversation_status_changed',
|
||||
//
|
||||
// ChatWoot Events - Artificial
|
||||
//
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { AppConsumer } from '@waha/apps/app_sdk/AppConsumer';
|
||||
import { JobLoggerWrapper } from '@waha/apps/app_sdk/JobLoggerWrapper';
|
||||
import { HasBeenRetried } from '@waha/apps/app_sdk/JobUtils';
|
||||
import { GetChatID } from '@waha/apps/chatwoot/client/ids';
|
||||
import { FindChatID } from '@waha/apps/chatwoot/client/ids';
|
||||
import { EventName } from '@waha/apps/chatwoot/client/types';
|
||||
import { ChatWootConversationKey } from '@waha/apps/chatwoot/consumers/mutex';
|
||||
import { InboxData } from '@waha/apps/chatwoot/consumers/types';
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
ChatIDNotFoundForContactError,
|
||||
PhoneNumberNotFoundInWhatsAppError,
|
||||
} from '@waha/apps/chatwoot/errors';
|
||||
import { TKey } from '@waha/apps/chatwoot/locale';
|
||||
import { WAHASessionAPI } from '@waha/apps/chatwoot/session/WAHASelf';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
import { RMutexService } from '@waha/modules/rmutex/rmutex.service';
|
||||
@@ -18,6 +17,7 @@ import { Job } from 'bullmq';
|
||||
import { PinoLogger } from 'nestjs-pino';
|
||||
|
||||
import { AppRepository } from '../../storage';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
|
||||
/**
|
||||
* Base class for ChatWoot inbox consumers
|
||||
@@ -58,13 +58,20 @@ export abstract class ChatWootInboxMessageConsumer extends AppConsumer {
|
||||
job: Job,
|
||||
): Promise<any>;
|
||||
|
||||
protected GetConversationID(body) {
|
||||
return body.conversation.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the job
|
||||
* This method is called by the queue processor
|
||||
*/
|
||||
async processJob(job: Job<InboxData, any, EventName>): Promise<any> {
|
||||
const body = job.data.body;
|
||||
const key = ChatWootConversationKey(job.data.app, body.conversation.id);
|
||||
const key = ChatWootConversationKey(
|
||||
job.data.app,
|
||||
this.GetConversationID(body),
|
||||
);
|
||||
return await this.withMutex(job, key, () =>
|
||||
this.ProcessAndReportStatus(job),
|
||||
);
|
||||
@@ -124,7 +131,7 @@ export async function LookupAndCheckChatId(
|
||||
body: any,
|
||||
): Promise<string> {
|
||||
const sender = body.conversation.meta.sender;
|
||||
let chatId = GetChatID(sender);
|
||||
let chatId = FindChatID(sender);
|
||||
if (!chatId && sender.phone_number) {
|
||||
const existResult = await session.contactCheckExists(sender.phone_number);
|
||||
if (!existResult.numberExists) {
|
||||
|
||||
@@ -7,13 +7,15 @@ import { MessageType } from '@waha/apps/chatwoot/client/types';
|
||||
import { ChatWootInboxMessageConsumer } from '@waha/apps/chatwoot/consumers/inbox/base';
|
||||
import { QueueName } from '@waha/apps/chatwoot/consumers/QueueName';
|
||||
import { DIContainer } from '@waha/apps/chatwoot/di/DIContainer';
|
||||
import { Locale, TKey } from '@waha/apps/chatwoot/locale';
|
||||
import { Locale } from '@waha/apps/chatwoot/i18n/locale';
|
||||
import { WAHASelf } from '@waha/apps/chatwoot/session/WAHASelf';
|
||||
import { SessionStatusEmoji } from '@waha/apps/chatwoot/SessionStatusEmoji';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
import { RMutexService } from '@waha/modules/rmutex/rmutex.service';
|
||||
import { Job } from 'bullmq';
|
||||
import { PinoLogger } from 'nestjs-pino';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
import { ChatWootCommandsConfig } from '@waha/apps/chatwoot/dto/config.dto';
|
||||
|
||||
@Processor(QueueName.INBOX_COMMANDS, { concurrency: JOB_CONCURRENCY })
|
||||
export class ChatWootInboxCommandsConsumer extends ChatWootInboxMessageConsumer {
|
||||
@@ -36,11 +38,14 @@ export class ChatWootInboxCommandsConsumer extends ChatWootInboxMessageConsumer
|
||||
job.data.session,
|
||||
container.Locale(),
|
||||
container.WAHASelf(),
|
||||
container.ChatWootConfig().commands,
|
||||
);
|
||||
return await handler.handle(body);
|
||||
}
|
||||
}
|
||||
|
||||
const CommandServerPrefix = 'server ';
|
||||
|
||||
enum Command {
|
||||
STATUS = 'status',
|
||||
RESTART = 'restart',
|
||||
@@ -99,6 +104,7 @@ class SessionCommandHandler {
|
||||
private session: string,
|
||||
private l: Locale,
|
||||
private waha: WAHASelf,
|
||||
private commands: ChatWootCommandsConfig,
|
||||
) {}
|
||||
|
||||
async handle(message: any) {
|
||||
@@ -107,6 +113,13 @@ class SessionCommandHandler {
|
||||
this.logger.info(
|
||||
`Executing command ${command} for session ${this.session}`,
|
||||
);
|
||||
const warning = this.commandDisabledWarning(command);
|
||||
const conversation = await this.repo.InboxNotifications();
|
||||
if (warning) {
|
||||
const text = this.l.key(warning).render();
|
||||
await conversation.incoming(text);
|
||||
return;
|
||||
}
|
||||
switch (command) {
|
||||
case Command.RESTART:
|
||||
await this.waha.restart(this.session);
|
||||
@@ -117,7 +130,6 @@ class SessionCommandHandler {
|
||||
case Command.LOGOUT:
|
||||
this.logger.info(`Logging out session ${this.session}`);
|
||||
await this.waha.logout(this.session);
|
||||
const conversation = await this.repo.InboxNotifications();
|
||||
const text = this.l.key(TKey.APP_LOGOUT_SUCCESS).render();
|
||||
await conversation.incoming(text);
|
||||
break;
|
||||
@@ -128,7 +140,6 @@ class SessionCommandHandler {
|
||||
case Command.STATUS: {
|
||||
this.logger.info(`Getting status for session ${this.session}`);
|
||||
const session = await this.waha.get(this.session);
|
||||
const conversation = await this.repo.InboxNotifications();
|
||||
const emoji = SessionStatusEmoji(session.status);
|
||||
const text = this.l.key(TKey.APP_SESSION_CURRENT_STATUS).render({
|
||||
emoji: emoji,
|
||||
@@ -144,7 +155,6 @@ class SessionCommandHandler {
|
||||
this.logger.info('Getting server version and status');
|
||||
const version = await this.waha.serverVersion();
|
||||
const status = await this.waha.serverStatus();
|
||||
const conversation = await this.repo.InboxNotifications();
|
||||
const text = this.l.key(TKey.APP_SERVER_VERSION_AND_STATUS).render({
|
||||
version: JSON.stringify(version, null, 2),
|
||||
status: JSON.stringify(status, null, 2),
|
||||
@@ -154,7 +164,6 @@ class SessionCommandHandler {
|
||||
}
|
||||
case Command.SERVER_REBOOT: {
|
||||
this.logger.info('Rebooting server (graceful)');
|
||||
const conversation = await this.repo.InboxNotifications();
|
||||
const text = this.l.key(TKey.APP_SERVER_REBOOT).render();
|
||||
await conversation.incoming(text);
|
||||
await this.waha.serverReboot(false);
|
||||
@@ -162,14 +171,12 @@ class SessionCommandHandler {
|
||||
}
|
||||
case Command.SERVER_REBOOT_FORCE: {
|
||||
this.logger.info('Rebooting server (force)');
|
||||
const conversation = await this.repo.InboxNotifications();
|
||||
const text = this.l.key(TKey.APP_SERVER_REBOOT_FORCE).render();
|
||||
await conversation.incoming(text);
|
||||
await this.waha.serverReboot(true);
|
||||
break;
|
||||
}
|
||||
case Command.QR: {
|
||||
const conversation = await this.repo.InboxNotifications();
|
||||
const content = await this.waha.qr(this.session);
|
||||
const message = AttachmentFromBuffer(content, 'qr.jpg');
|
||||
message.message_type = MessageType.INCOMING;
|
||||
@@ -178,7 +185,6 @@ class SessionCommandHandler {
|
||||
}
|
||||
case Command.SCREENSHOT: {
|
||||
this.logger.info(`Getting screenshot for session ${this.session}`);
|
||||
const conversation = await this.repo.InboxNotifications();
|
||||
const content = await this.waha.screenshot(this.session);
|
||||
const message = AttachmentFromBuffer(content, 'screenshot.jpg');
|
||||
message.message_type = MessageType.INCOMING;
|
||||
@@ -186,8 +192,9 @@ class SessionCommandHandler {
|
||||
break;
|
||||
}
|
||||
case Command.HELP: {
|
||||
const conversation = await this.repo.InboxNotifications();
|
||||
const text = this.l.key(TKey.APP_COMMANDS_LIST).render();
|
||||
const text = this.l
|
||||
.key(TKey.APP_COMMANDS_LIST)
|
||||
.render({ commands: this.commands });
|
||||
await conversation.incoming(text);
|
||||
break;
|
||||
}
|
||||
@@ -196,6 +203,17 @@ class SessionCommandHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the command allowed for this session
|
||||
* Returns `null` if allowed or the message key to show as an error
|
||||
*/
|
||||
commandDisabledWarning(command: Command): TKey | null {
|
||||
if (!this.commands.server && command.startsWith(CommandServerPrefix)) {
|
||||
return TKey.APP_COMMANDS_SERVER_DISABLED;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
findCommand(text: string): Command {
|
||||
// Remove empty from end
|
||||
text = text.trim();
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { Processor } from '@nestjs/bullmq';
|
||||
import { JOB_CONCURRENCY } from '@waha/apps/app_sdk/constants';
|
||||
import { QueueName } from '@waha/apps/chatwoot/consumers/QueueName';
|
||||
import { ChatWootConversationKey } from '@waha/apps/chatwoot/consumers/mutex';
|
||||
import { ChatWootInboxMessageConsumer } from '@waha/apps/chatwoot/consumers/inbox/base';
|
||||
import { InboxData } from '@waha/apps/chatwoot/consumers/types';
|
||||
import { Job } from 'bullmq';
|
||||
import { GetAllChatIDs } from '@waha/apps/chatwoot/client/ids';
|
||||
import { DIContainer } from '@waha/apps/chatwoot/di/DIContainer';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
import { ContactConversationService } from '@waha/apps/chatwoot/client/ContactConversationService';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
import { PinoLogger } from 'nestjs-pino';
|
||||
import { RMutexService } from '@waha/modules/rmutex';
|
||||
|
||||
@Processor(QueueName.INBOX_CONVERSATION_CREATED, {
|
||||
concurrency: JOB_CONCURRENCY,
|
||||
})
|
||||
export class ChatWootConversationCreatedConsumer extends ChatWootInboxMessageConsumer {
|
||||
constructor(
|
||||
protected readonly manager: SessionManager,
|
||||
log: PinoLogger,
|
||||
rmutex: RMutexService,
|
||||
) {
|
||||
super(manager, log, rmutex, 'ChatWootConversationCreatedConsumer');
|
||||
}
|
||||
protected ErrorHeaderKey(): TKey | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected GetConversationID(body) {
|
||||
return body.id;
|
||||
}
|
||||
|
||||
protected async Process(
|
||||
container: DIContainer,
|
||||
body: any,
|
||||
job: Job,
|
||||
): Promise<any> {
|
||||
const handler = new ConversationCreatedHandler(
|
||||
container.ContactConversationService(),
|
||||
);
|
||||
return handler.handle(body);
|
||||
}
|
||||
}
|
||||
|
||||
class ConversationCreatedHandler {
|
||||
constructor(private service: ContactConversationService) {}
|
||||
|
||||
async handle(body: any) {
|
||||
const ids = GetAllChatIDs(body?.meta?.sender);
|
||||
if (!ids || ids.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.service.ResetMismatchedCache(ids, body.id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { Processor } from '@nestjs/bullmq';
|
||||
import { JOB_CONCURRENCY } from '@waha/apps/app_sdk/constants';
|
||||
import { QueueName } from '@waha/apps/chatwoot/consumers/QueueName';
|
||||
import { ChatWootInboxMessageConsumer } from '@waha/apps/chatwoot/consumers/inbox/base';
|
||||
import { Job } from 'bullmq';
|
||||
import { DIContainer } from '../../di/DIContainer';
|
||||
import { TKey } from '../../i18n/templates';
|
||||
import { ContactConversationService } from '@waha/apps/chatwoot/client/ContactConversationService';
|
||||
import { AttributeKey } from '@waha/apps/chatwoot/const';
|
||||
import { ConversationSelector } from '@waha/apps/chatwoot/services/ConversationSelector';
|
||||
import { GetAllChatIDs } from '@waha/apps/chatwoot/client/ids';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
import { PinoLogger } from 'nestjs-pino';
|
||||
import { RMutexService } from '@waha/modules/rmutex';
|
||||
|
||||
@Processor(QueueName.INBOX_CONVERSATION_STATUS_CHANGED, {
|
||||
concurrency: JOB_CONCURRENCY,
|
||||
})
|
||||
export class ChatWootConversationStatusChangedConsumer extends ChatWootInboxMessageConsumer {
|
||||
constructor(
|
||||
protected readonly manager: SessionManager,
|
||||
log: PinoLogger,
|
||||
rmutex: RMutexService,
|
||||
) {
|
||||
super(manager, log, rmutex, 'ChatWootConversationStatusChangedConsumer');
|
||||
}
|
||||
|
||||
protected ErrorHeaderKey(): TKey | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected GetConversationID(body) {
|
||||
return body.id;
|
||||
}
|
||||
|
||||
protected async Process(
|
||||
container: DIContainer,
|
||||
body: any,
|
||||
job: Job,
|
||||
): Promise<any> {
|
||||
const handler = new ConversationStatusChangedHandler(
|
||||
container.ContactConversationService(),
|
||||
container.ConversationSelector(),
|
||||
);
|
||||
return await handler.handle(body);
|
||||
}
|
||||
}
|
||||
|
||||
class ConversationStatusChangedHandler {
|
||||
constructor(
|
||||
private service: ContactConversationService,
|
||||
private selector: ConversationSelector,
|
||||
) {}
|
||||
|
||||
async handle(body) {
|
||||
if (!this.selector.hasStatusFilter()) {
|
||||
return;
|
||||
}
|
||||
const ids = GetAllChatIDs(body.meta?.sender);
|
||||
this.service.ResetCache(ids);
|
||||
}
|
||||
}
|
||||
@@ -8,11 +8,11 @@ import {
|
||||
} from '@waha/apps/chatwoot/consumers/inbox/base';
|
||||
import { QueueName } from '@waha/apps/chatwoot/consumers/QueueName';
|
||||
import { DIContainer } from '@waha/apps/chatwoot/di/DIContainer';
|
||||
import { TKey } from '@waha/apps/chatwoot/locale';
|
||||
import { EngineHelper } from '@waha/apps/chatwoot/session';
|
||||
import { WAHASessionAPI } from '@waha/apps/chatwoot/session/WAHASelf';
|
||||
import {
|
||||
ChatwootMessage,
|
||||
MessageMapping,
|
||||
MessageMappingService,
|
||||
} from '@waha/apps/chatwoot/storage';
|
||||
import { MarkdownToWhatsApp } from '@waha/apps/chatwoot/text';
|
||||
@@ -30,6 +30,12 @@ import { Job } from 'bullmq';
|
||||
import { PinoLogger } from 'nestjs-pino';
|
||||
|
||||
import { SerializeWhatsAppKey } from '../../client/ids';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
import {
|
||||
ChatWootConfig,
|
||||
LinkPreview,
|
||||
} from '@waha/apps/chatwoot/dto/config.dto';
|
||||
import { Locale } from '@waha/apps/chatwoot/i18n/locale';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const mime = require('mime-types');
|
||||
@@ -45,7 +51,7 @@ export class ChatWootInboxMessageCreatedConsumer extends ChatWootInboxMessageCon
|
||||
}
|
||||
|
||||
ErrorHeaderKey(): TKey | null {
|
||||
return TKey.WHATSAPP_ERROR_SENDING_MESSAGE;
|
||||
return TKey.WHATSAPP_MESSAGE_SENDING_ERROR;
|
||||
}
|
||||
|
||||
protected async Process(container: DIContainer, body, job: Job) {
|
||||
@@ -55,6 +61,8 @@ export class ChatWootInboxMessageCreatedConsumer extends ChatWootInboxMessageCon
|
||||
container.MessageMappingService(),
|
||||
container.Logger(),
|
||||
session,
|
||||
container.ChatWootConfig(),
|
||||
container.Locale(),
|
||||
);
|
||||
return await handler.handle(body);
|
||||
}
|
||||
@@ -65,6 +73,8 @@ export class MessageHandler {
|
||||
private mappingService: MessageMappingService,
|
||||
private logger: ILogger,
|
||||
private session: WAHASessionAPI,
|
||||
private config: ChatWootConfig,
|
||||
private l: Locale,
|
||||
) {}
|
||||
|
||||
async handle(body: any) {
|
||||
@@ -78,37 +88,60 @@ export class MessageHandler {
|
||||
}
|
||||
|
||||
const content = MarkdownToWhatsApp(message.content);
|
||||
const attachments = message.attachments || [];
|
||||
const results = [];
|
||||
const multipleAttachments = attachments.length > 1;
|
||||
let part = 1;
|
||||
let part = 0; // Start from 0 and increment before each send/check
|
||||
const replyTo = await this.getReplyTo(message).catch((err) => {
|
||||
this.logger.error(`Error getting reply to message ID: ${err}`);
|
||||
this.logger.error(
|
||||
`ChatWoot => WhatsApp: error getting reply to message ID: ${err}`,
|
||||
);
|
||||
return undefined;
|
||||
});
|
||||
|
||||
// Send text
|
||||
if (attachments.length == 0 || multipleAttachments) {
|
||||
const msg = await this.sendTextMessage(chatId, content, replyTo);
|
||||
results.push(msg);
|
||||
part = await this.saveMapping(message, msg, part);
|
||||
this.logger.info(`Text message sent: ${msg.id}`);
|
||||
// Send text (Part 1 if present)
|
||||
const attachments = message.attachments || [];
|
||||
const sendText = content && attachments.length !== 1;
|
||||
if (sendText) {
|
||||
part += 1; // Text is the first possible part
|
||||
const exists = await this.getMapping(message, part);
|
||||
if (exists) {
|
||||
this.logger.warn(
|
||||
`Skip part ${part}: mapping exists for Chatwoot message ${message.id}`,
|
||||
);
|
||||
} else {
|
||||
const textTemplate = this.l.key(TKey.CW_TO_WA_MESSAGE_TEXT);
|
||||
const text = textTemplate.render({
|
||||
content: content,
|
||||
chatwoot: body,
|
||||
});
|
||||
const msg = await this.sendTextMessage(chatId, text, replyTo);
|
||||
results.push(msg);
|
||||
await this.saveMapping(message, msg, part);
|
||||
this.logger.info(`Text message sent: ${msg.id}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Send files
|
||||
const fileMessageContent = multipleAttachments ? '' : content;
|
||||
const captionTemplate = this.l.key(TKey.CW_TO_WA_MESSAGE_MEDIA_CAPTION);
|
||||
for (const file of attachments) {
|
||||
const msg = await this.sendFile(
|
||||
chatId,
|
||||
fileMessageContent,
|
||||
file,
|
||||
replyTo,
|
||||
);
|
||||
part += 1; // Increment before each attachment send/check
|
||||
const exists = await this.getMapping(message, part);
|
||||
if (exists) {
|
||||
this.logger.warn(
|
||||
`Skip part ${part}: mapping exists for Chatwoot message ${message.id}`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
const caption = captionTemplate.render({
|
||||
content: content,
|
||||
chatwoot: body,
|
||||
singleAttachment: attachments.length == 1,
|
||||
});
|
||||
const msg = await this.sendFile(chatId, caption, file, replyTo);
|
||||
this.logger.info(
|
||||
`File message sent: ${msg.id} - ${file.data_url} - ${file.file_type}`,
|
||||
);
|
||||
results.push(msg);
|
||||
part = await this.saveMapping(message, msg, part);
|
||||
await this.saveMapping(message, msg, part);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
@@ -117,15 +150,27 @@ export class MessageHandler {
|
||||
chatwootMessage: any,
|
||||
whatsappMessage: any,
|
||||
part: number,
|
||||
): Promise<number> {
|
||||
): Promise<void> {
|
||||
const chatwoot: Omit<ChatwootMessage, 'id'> = {
|
||||
timestamp: new Date(chatwootMessage.created_at),
|
||||
conversation_id: chatwootMessage.conversation.id,
|
||||
message_id: chatwootMessage.id,
|
||||
};
|
||||
const whatsapp = EngineHelper.WhatsAppMessageKeys(whatsappMessage);
|
||||
await this.mappingService.map(chatwoot, whatsapp, 1);
|
||||
return part + 1;
|
||||
await this.mappingService.map(chatwoot, whatsapp, part);
|
||||
}
|
||||
|
||||
private async getMapping(
|
||||
message: any,
|
||||
part: number,
|
||||
): Promise<MessageMapping | null> {
|
||||
return this.mappingService.getMappingByChatwootCombinedKeyAndPart(
|
||||
{
|
||||
conversation_id: message.conversation.id,
|
||||
message_id: message.id,
|
||||
},
|
||||
part,
|
||||
);
|
||||
}
|
||||
|
||||
async getReplyTo(message): Promise<string | undefined> {
|
||||
@@ -154,6 +199,10 @@ export class MessageHandler {
|
||||
chatId: chatId,
|
||||
text: content,
|
||||
reply_to: replyTo,
|
||||
linkPreview: [LinkPreview.LQ, LinkPreview.HQ].includes(
|
||||
this.config.linkPreview,
|
||||
),
|
||||
linkPreviewHighQuality: this.config.linkPreview == LinkPreview.HQ,
|
||||
};
|
||||
const session = this.session;
|
||||
await session.readMessages(chatId);
|
||||
|
||||
@@ -8,13 +8,13 @@ import {
|
||||
} from '@waha/apps/chatwoot/consumers/inbox/base';
|
||||
import { QueueName } from '@waha/apps/chatwoot/consumers/QueueName';
|
||||
import { DIContainer } from '@waha/apps/chatwoot/di/DIContainer';
|
||||
import { TKey } from '@waha/apps/chatwoot/locale';
|
||||
import { WAHASessionAPI } from '@waha/apps/chatwoot/session/WAHASelf';
|
||||
import { MessageMappingService } from '@waha/apps/chatwoot/storage';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
import { RMutexService } from '@waha/modules/rmutex/rmutex.service';
|
||||
import { Job } from 'bullmq';
|
||||
import { PinoLogger } from 'nestjs-pino';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
|
||||
@Processor(QueueName.INBOX_MESSAGE_DELETED, { concurrency: JOB_CONCURRENCY })
|
||||
export class ChatWootInboxMessageDeletedConsumer extends ChatWootInboxMessageConsumer {
|
||||
@@ -27,7 +27,7 @@ export class ChatWootInboxMessageDeletedConsumer extends ChatWootInboxMessageCon
|
||||
}
|
||||
|
||||
ErrorHeaderKey(): TKey | null {
|
||||
return TKey.WHATSAPP_ERROR_REMOVING_MESSAGE;
|
||||
return TKey.WHATSAPP_MESSAGE_REMOVING_ERROR;
|
||||
}
|
||||
|
||||
protected async Process(container: DIContainer, body, job: Job) {
|
||||
|
||||
@@ -4,13 +4,13 @@ import { ChatWootInboxMessageConsumer } from '@waha/apps/chatwoot/consumers/inbo
|
||||
import { MessageHandler } from '@waha/apps/chatwoot/consumers/inbox/message_created';
|
||||
import { QueueName } from '@waha/apps/chatwoot/consumers/QueueName';
|
||||
import { DIContainer } from '@waha/apps/chatwoot/di/DIContainer';
|
||||
import { TKey } from '@waha/apps/chatwoot/locale';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
import { RMutexService } from '@waha/modules/rmutex/rmutex.service';
|
||||
import { Job } from 'bullmq';
|
||||
import { PinoLogger } from 'nestjs-pino';
|
||||
|
||||
import { WAHASessionAPI } from '../../session/WAHASelf';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
|
||||
@Processor(QueueName.INBOX_MESSAGE_UPDATED, { concurrency: JOB_CONCURRENCY })
|
||||
export class ChatWootInboxMessageUpdatedConsumer extends ChatWootInboxMessageConsumer {
|
||||
@@ -23,7 +23,7 @@ export class ChatWootInboxMessageUpdatedConsumer extends ChatWootInboxMessageCon
|
||||
}
|
||||
|
||||
ErrorHeaderKey(): TKey | null {
|
||||
return TKey.WHATSAPP_ERROR_SENDING_MESSAGE;
|
||||
return TKey.WHATSAPP_MESSAGE_SENDING_ERROR;
|
||||
}
|
||||
|
||||
protected async Process(container: DIContainer, body, job: Job) {
|
||||
@@ -33,6 +33,8 @@ export class ChatWootInboxMessageUpdatedConsumer extends ChatWootInboxMessageCon
|
||||
container.MessageMappingService(),
|
||||
container.Logger(),
|
||||
session,
|
||||
container.ChatWootConfig(),
|
||||
container.Locale(),
|
||||
);
|
||||
return await handler.handle(body);
|
||||
}
|
||||
|
||||
@@ -5,13 +5,13 @@ import { MessageType } from '@waha/apps/chatwoot/client/types';
|
||||
import { ScheduledData } from '@waha/apps/chatwoot/consumers/types';
|
||||
import { DIContainer } from '@waha/apps/chatwoot/di/DIContainer';
|
||||
import { ChatWootAppConfig } from '@waha/apps/chatwoot/dto/config.dto';
|
||||
import { TKey } from '@waha/apps/chatwoot/locale';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
import { RMutexService } from '@waha/modules/rmutex/rmutex.service';
|
||||
import { Job } from 'bullmq';
|
||||
import { PinoLogger } from 'nestjs-pino';
|
||||
|
||||
import { AppRepository } from '../../storage';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
|
||||
/**
|
||||
* Base class for ChatWoot scheduled consumers
|
||||
|
||||
@@ -4,7 +4,6 @@ import { JOB_CONCURRENCY } from '@waha/apps/app_sdk/constants';
|
||||
import { ILogger } from '@waha/apps/app_sdk/ILogger';
|
||||
import { QueueName } from '@waha/apps/chatwoot/consumers/QueueName';
|
||||
import { DIContainer } from '@waha/apps/chatwoot/di/DIContainer';
|
||||
import { TKey } from '@waha/apps/chatwoot/locale';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
import { CHANGELOG_URL, SUPPORT_US_URL } from '@waha/core/constants';
|
||||
import { RMutexService } from '@waha/modules/rmutex/rmutex.service';
|
||||
@@ -14,6 +13,7 @@ import { Job } from 'bullmq';
|
||||
import { PinoLogger } from 'nestjs-pino';
|
||||
|
||||
import { ChatWootScheduledConsumer } from './base';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
|
||||
/**
|
||||
* Scheduled consumer for version checking
|
||||
@@ -26,7 +26,7 @@ export class CheckVersionConsumer extends ChatWootScheduledConsumer {
|
||||
}
|
||||
|
||||
protected ErrorHeaderKey(): TKey {
|
||||
return TKey.APP_SCHEDULED_JOB_ERROR;
|
||||
return TKey.JOB_SCHEDULED_ERROR_HEADER;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,7 +50,7 @@ export class CheckVersionConsumer extends ChatWootScheduledConsumer {
|
||||
return;
|
||||
}
|
||||
logger.info('WAHA is using the CORE version');
|
||||
const supportMessage = locale.key(TKey.APP_CORE_VERSION_USED).render({
|
||||
const supportMessage = locale.key(TKey.WAHA_CORE_VERSION_USED).render({
|
||||
supportUrl: SUPPORT_US_URL,
|
||||
});
|
||||
await conversation.incoming(supportMessage);
|
||||
@@ -74,7 +74,7 @@ export class CheckVersionConsumer extends ChatWootScheduledConsumer {
|
||||
|
||||
// Send a message to Chatwoot conversation about a new version
|
||||
const locale = container.Locale();
|
||||
const message = locale.key(TKey.APP_NEW_VERSION_AVAILABLE).render({
|
||||
const message = locale.key(TKey.WAHA_NEW_VERSION_AVAILABLE).render({
|
||||
currentVersion: currentVersion,
|
||||
newVersion: latestVersion,
|
||||
changelogUrl: CHANGELOG_URL,
|
||||
|
||||
@@ -3,13 +3,13 @@ import { Injectable } from '@nestjs/common';
|
||||
import { JOB_CONCURRENCY } from '@waha/apps/app_sdk/constants';
|
||||
import { QueueName } from '@waha/apps/chatwoot/consumers/QueueName';
|
||||
import { DIContainer } from '@waha/apps/chatwoot/di/DIContainer';
|
||||
import { TKey } from '@waha/apps/chatwoot/locale';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
import { RMutexService } from '@waha/modules/rmutex/rmutex.service';
|
||||
import { Job } from 'bullmq';
|
||||
import { PinoLogger } from 'nestjs-pino';
|
||||
|
||||
import { ChatWootScheduledConsumer } from './base';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
|
||||
/**
|
||||
* Scheduled consumer for message cleanup tasks
|
||||
@@ -26,7 +26,7 @@ export class MessageCleanupConsumer extends ChatWootScheduledConsumer {
|
||||
}
|
||||
|
||||
protected ErrorHeaderKey(): TKey {
|
||||
return TKey.APP_SCHEDULED_JOB_ERROR;
|
||||
return TKey.JOB_SCHEDULED_ERROR_HEADER;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { isJidGroup, isJidStatusBroadcast } from '@adiwajshing/baileys';
|
||||
import { conversation_message_create } from '@figuro/chatwoot-sdk';
|
||||
import type { generic_id } from '@figuro/chatwoot-sdk/dist/models/generic_id';
|
||||
import type { message } from '@figuro/chatwoot-sdk/dist/models/message';
|
||||
@@ -13,7 +12,7 @@ import { WhatsAppChatIdKey } from '@waha/apps/chatwoot/consumers/mutex';
|
||||
import { EventData } from '@waha/apps/chatwoot/consumers/types';
|
||||
import { WhatsAppContactInfo } from '@waha/apps/chatwoot/contacts/WhatsAppContactInfo';
|
||||
import { DIContainer } from '@waha/apps/chatwoot/di/DIContainer';
|
||||
import { Locale, TKey } from '@waha/apps/chatwoot/locale';
|
||||
import { Locale } from '@waha/apps/chatwoot/i18n/locale';
|
||||
import { WAHASelf, WAHASessionAPI } from '@waha/apps/chatwoot/session/WAHASelf';
|
||||
import {
|
||||
AppRepository,
|
||||
@@ -22,7 +21,6 @@ import {
|
||||
WhatsAppMessage,
|
||||
} from '@waha/apps/chatwoot/storage';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
import { toCusFormat } from '@waha/core/engines/noweb/session.noweb.core';
|
||||
import { parseMessageIdSerialized } from '@waha/core/utils/ids';
|
||||
import { RMutexService } from '@waha/modules/rmutex/rmutex.service';
|
||||
import { WAHAEvents } from '@waha/structures/enums.dto';
|
||||
@@ -35,7 +33,8 @@ import { sleep } from '@waha/utils/promiseTimeout';
|
||||
import { Job } from 'bullmq';
|
||||
import { PinoLogger } from 'nestjs-pino';
|
||||
|
||||
import { ChatWootAppConfig } from '../../dto/config.dto';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
import { isJidBroadcast, isJidGroup, toCusFormat } from '@waha/core/utils/jids';
|
||||
|
||||
export function ListenEventsForChatWoot() {
|
||||
return [
|
||||
@@ -64,7 +63,7 @@ export abstract class ChatWootWAHABaseConsumer extends AppConsumer {
|
||||
}
|
||||
|
||||
protected ErrorHeaderKey(): TKey | null {
|
||||
return TKey.WHATSAPP_ERROR_RECEIVING_MESSAGE;
|
||||
return TKey.WHATSAPP_MESSAGE_RECEIVING_ERROR;
|
||||
}
|
||||
|
||||
private async ProcessAndReportErrors(job) {
|
||||
@@ -151,7 +150,7 @@ export abstract class ChatWootWAHABaseConsumer extends AppConsumer {
|
||||
.ContactConversationService()
|
||||
.ConversationById(info.conversationId);
|
||||
} else {
|
||||
const conversation = await container
|
||||
conversation = await container
|
||||
.ContactConversationService()
|
||||
.InboxNotifications();
|
||||
}
|
||||
@@ -183,8 +182,15 @@ class MessageReportInfo implements IMessageInfo {
|
||||
}
|
||||
}
|
||||
|
||||
export interface ChatWootMessagePartial {
|
||||
content: string;
|
||||
attachments: SendAttachment[];
|
||||
private?: boolean;
|
||||
}
|
||||
|
||||
export abstract class MessageBaseHandler<Payload extends WAMessageBase> {
|
||||
constructor(
|
||||
protected job: Job,
|
||||
protected mappingService: MessageMappingService,
|
||||
protected repo: ContactConversationService,
|
||||
protected logger: ILogger,
|
||||
@@ -194,12 +200,12 @@ export abstract class MessageBaseHandler<Payload extends WAMessageBase> {
|
||||
protected waha: WAHASelf,
|
||||
) {}
|
||||
|
||||
abstract getContent(payload: Payload): string;
|
||||
protected abstract getMessage(
|
||||
payload: Payload,
|
||||
): Promise<ChatWootMessagePartial>;
|
||||
|
||||
abstract getReplyToWhatsAppID(payload: Payload): string | undefined;
|
||||
|
||||
abstract getAttachments(payload: Payload): Promise<SendAttachment[]>;
|
||||
|
||||
async handle(data: WAHAWebhook<Payload>) {
|
||||
const payload = data.payload;
|
||||
// Find the type as soon as possible for error reporting
|
||||
@@ -262,7 +268,8 @@ export abstract class MessageBaseHandler<Payload extends WAMessageBase> {
|
||||
private async buildChatWootMessage(
|
||||
payload: Payload,
|
||||
): Promise<conversation_message_create> {
|
||||
let content: string = this.getContent(payload);
|
||||
const message = await this.getMessage(payload);
|
||||
let content = message.content;
|
||||
|
||||
// Format the content if the message from me
|
||||
if (payload.fromMe && payload.source === MessageSource.APP) {
|
||||
@@ -276,7 +283,7 @@ export abstract class MessageBaseHandler<Payload extends WAMessageBase> {
|
||||
const chatId = payload.from;
|
||||
|
||||
// Add participant name to group messages
|
||||
const manyParticipants = isJidGroup(chatId) || isJidStatusBroadcast(chatId);
|
||||
const manyParticipants = isJidGroup(chatId) || isJidBroadcast(chatId);
|
||||
if (!payload.fromMe && manyParticipants) {
|
||||
const key = parseMessageIdSerialized(payload.id, true);
|
||||
let participant = toCusFormat(key.participant);
|
||||
@@ -290,14 +297,11 @@ export abstract class MessageBaseHandler<Payload extends WAMessageBase> {
|
||||
participant: participant,
|
||||
});
|
||||
}
|
||||
const attachments: SendAttachment[] = await this.getAttachments(payload);
|
||||
if (!content && attachments.length > 0) {
|
||||
// With no content ChatWoot render the message as an ugly big attachment
|
||||
content = ' ';
|
||||
}
|
||||
const replyTo = await this.getReplyToChatWootMessageID(payload).catch(
|
||||
(err) => {
|
||||
this.logger.error(`Error getting reply to message ID: ${err}`);
|
||||
this.logger.error(
|
||||
`WhatsApp => ChatWoot - error getting reply to message ID: ${err}`,
|
||||
);
|
||||
return undefined;
|
||||
},
|
||||
);
|
||||
@@ -306,8 +310,8 @@ export abstract class MessageBaseHandler<Payload extends WAMessageBase> {
|
||||
return {
|
||||
content: content,
|
||||
message_type: type,
|
||||
private: payload.fromMe,
|
||||
attachments: attachments as any,
|
||||
private: message.private ?? payload.fromMe,
|
||||
attachments: message.attachments as any,
|
||||
content_attributes: {
|
||||
in_reply_to: replyTo,
|
||||
},
|
||||
@@ -325,6 +329,6 @@ export abstract class MessageBaseHandler<Payload extends WAMessageBase> {
|
||||
chat_id: payload.from,
|
||||
message_id: replyToWhatsAppID,
|
||||
});
|
||||
return chatwoot.message_id;
|
||||
return chatwoot?.message_id;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,15 @@
|
||||
import type { proto } from '@adiwajshing/baileys';
|
||||
import { Processor } from '@nestjs/bullmq';
|
||||
import { JOB_CONCURRENCY } from '@waha/apps/app_sdk/constants';
|
||||
import { SendAttachment } from '@waha/apps/chatwoot/client/types';
|
||||
import { QueueName } from '@waha/apps/chatwoot/consumers/QueueName';
|
||||
import { EventData } from '@waha/apps/chatwoot/consumers/types';
|
||||
import {
|
||||
ChatWootMessagePartial,
|
||||
ChatWootWAHABaseConsumer,
|
||||
IMessageInfo,
|
||||
MessageBaseHandler,
|
||||
} from '@waha/apps/chatwoot/consumers/waha/base';
|
||||
import { MessageBaseHandler } from '@waha/apps/chatwoot/consumers/waha/base';
|
||||
import { WAHASessionAPI } from '@waha/apps/chatwoot/session/WAHASelf';
|
||||
import { WhatsappToMarkdown } from '@waha/apps/chatwoot/text';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
@@ -18,6 +20,10 @@ import { WAMessage } from '@waha/structures/responses.dto';
|
||||
import { WAHAWebhookMessageAny } from '@waha/structures/webhooks.dto';
|
||||
import { Job } from 'bullmq';
|
||||
import { PinoLogger } from 'nestjs-pino';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
import { JobLink } from '@waha/apps/app_sdk/JobUtils';
|
||||
import * as lodash from 'lodash';
|
||||
import { parseVCardV3, SimpleVCardInfo } from '@waha/core/vcard';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const mime = require('mime-types');
|
||||
@@ -44,6 +50,7 @@ export class WAHAMessageAnyConsumer extends ChatWootWAHABaseConsumer {
|
||||
const event: WAHAWebhookMessageAny = job.data.event as any;
|
||||
const session = new WAHASessionAPI(event.session, container.WAHASelf());
|
||||
const handler = new MessageAnyHandler(
|
||||
job,
|
||||
container.MessageMappingService(),
|
||||
container.ContactConversationService(),
|
||||
container.Logger(),
|
||||
@@ -56,10 +63,138 @@ export class WAHAMessageAnyConsumer extends ChatWootWAHABaseConsumer {
|
||||
}
|
||||
}
|
||||
|
||||
function isEmptyString(content: string) {
|
||||
if (!content) {
|
||||
return true;
|
||||
}
|
||||
return content == '' || content == '\n';
|
||||
}
|
||||
|
||||
class MessageAnyHandler extends MessageBaseHandler<WAMessage> {
|
||||
getContent(payload: WAMessage): string {
|
||||
const body = payload.body;
|
||||
return WhatsappToMarkdown(body);
|
||||
protected async getMessage(
|
||||
payload: WAMessage,
|
||||
): Promise<ChatWootMessagePartial> {
|
||||
const protoMessage = this.getProtoMessage(payload);
|
||||
let msg = await this.getTextMessage(payload, protoMessage);
|
||||
if (msg) {
|
||||
return msg;
|
||||
}
|
||||
msg = this.getLocationMessage(payload, protoMessage);
|
||||
if (msg) {
|
||||
return msg;
|
||||
}
|
||||
msg = this.getShareContactMessage(payload, protoMessage);
|
||||
if (msg) {
|
||||
return msg;
|
||||
}
|
||||
return this.getUnsupportedMessage();
|
||||
}
|
||||
|
||||
protected async getTextMessage(
|
||||
payload: WAMessage,
|
||||
_: proto.Message | null,
|
||||
): Promise<ChatWootMessagePartial | null> {
|
||||
const attachments = await this.getAttachments(payload);
|
||||
let content = this.l
|
||||
.key(TKey.WA_TO_CW_MESSAGE)
|
||||
.render({ payload: payload });
|
||||
if (isEmptyString(content) && attachments.length == 0) {
|
||||
return null;
|
||||
}
|
||||
if (isEmptyString(content)) {
|
||||
content = null;
|
||||
}
|
||||
return {
|
||||
content: WhatsappToMarkdown(content),
|
||||
attachments: attachments,
|
||||
private: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
private getLocationMessage(
|
||||
payload: WAMessage,
|
||||
message: proto.Message | null,
|
||||
): ChatWootMessagePartial | null {
|
||||
const hasLocation = !lodash.isEmpty(message?.locationMessage);
|
||||
const hasLiveLocation = !lodash.isEmpty(message?.liveLocationMessage);
|
||||
if (!hasLocation && !hasLiveLocation) {
|
||||
return null;
|
||||
}
|
||||
const location = this.l.key(TKey.WA_TO_CW_MESSAGE_LOCATION).r({
|
||||
payload,
|
||||
message,
|
||||
});
|
||||
if (isEmptyString(location)) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
content: location,
|
||||
attachments: [],
|
||||
private: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
private getShareContactMessage(
|
||||
_payload: WAMessage,
|
||||
message: proto.Message | null,
|
||||
): ChatWootMessagePartial | null {
|
||||
let vcards: string[] = [];
|
||||
|
||||
if (!lodash.isEmpty(message?.contactsArrayMessage?.contacts)) {
|
||||
vcards = message!.contactsArrayMessage!.contacts.map((c) => c.vcard);
|
||||
} else if (!lodash.isEmpty(message?.contactMessage?.vcard)) {
|
||||
vcards = [message!.contactMessage!.vcard];
|
||||
}
|
||||
if (vcards.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const attachments: SendAttachment[] = vcards.map((v, i) => ({
|
||||
content: Buffer.from(v, 'utf8').toString('base64'),
|
||||
encoding: 'base64',
|
||||
filename: `vcard-${i + 1}.vcf`,
|
||||
}));
|
||||
let contacts: SimpleVCardInfo[] = [];
|
||||
try {
|
||||
contacts = vcards.map(parseVCardV3);
|
||||
} catch (err) {
|
||||
this.logger.error(
|
||||
`Error parsing some vcards: vcards=${vcards}, err=${err}`,
|
||||
);
|
||||
}
|
||||
const msg = this.l.key(TKey.WA_TO_CW_MESSAGE_CONTACTS).r({ contacts });
|
||||
if (contacts.length === 0 && attachments.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
content: msg,
|
||||
attachments: attachments,
|
||||
private: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
private getUnsupportedMessage(): ChatWootMessagePartial {
|
||||
const unsupported = this.l
|
||||
.key(TKey.WA_TO_CW_MESSAGE_UNSUPPORTED)
|
||||
.render({ details: JobLink(this.job) });
|
||||
return {
|
||||
content: unsupported,
|
||||
attachments: [],
|
||||
private: true,
|
||||
};
|
||||
}
|
||||
|
||||
private getProtoMessage(payload: WAMessage): proto.Message | null {
|
||||
// GOWS
|
||||
if (payload._data.Message) {
|
||||
return payload._data.Message;
|
||||
}
|
||||
// NOWEB
|
||||
if (payload._data.message) {
|
||||
return payload._data.message;
|
||||
}
|
||||
// WEBJS - not available
|
||||
return null;
|
||||
}
|
||||
|
||||
getReplyToWhatsAppID(payload: WAMessage): string {
|
||||
@@ -72,6 +207,9 @@ class MessageAnyHandler extends MessageBaseHandler<WAMessage> {
|
||||
}
|
||||
|
||||
async getAttachments(payload: WAMessage): Promise<SendAttachment[]> {
|
||||
//
|
||||
// WAHA
|
||||
//
|
||||
const hasMedia = payload.media?.url;
|
||||
if (!hasMedia) {
|
||||
return [];
|
||||
|
||||
@@ -3,11 +3,11 @@ import { JOB_CONCURRENCY } from '@waha/apps/app_sdk/constants';
|
||||
import { QueueName } from '@waha/apps/chatwoot/consumers/QueueName';
|
||||
import { EventData } from '@waha/apps/chatwoot/consumers/types';
|
||||
import {
|
||||
ChatWootMessagePartial,
|
||||
ChatWootWAHABaseConsumer,
|
||||
IMessageInfo,
|
||||
} from '@waha/apps/chatwoot/consumers/waha/base';
|
||||
import { MessageBaseHandler } from '@waha/apps/chatwoot/consumers/waha/base';
|
||||
import { TKey } from '@waha/apps/chatwoot/locale';
|
||||
import { WhatsappToMarkdown } from '@waha/apps/chatwoot/text';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
import { RMutexService } from '@waha/modules/rmutex/rmutex.service';
|
||||
@@ -21,6 +21,8 @@ import { PinoLogger } from 'nestjs-pino';
|
||||
|
||||
import { SendAttachment } from '../../client/types';
|
||||
import { WAHASessionAPI } from '../../session/WAHASelf';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
import { WAMessage } from '@waha/structures/responses.dto';
|
||||
|
||||
@Processor(QueueName.WAHA_MESSAGE_EDITED, { concurrency: JOB_CONCURRENCY })
|
||||
export class WAHAMessageEditedConsumer extends ChatWootWAHABaseConsumer {
|
||||
@@ -44,6 +46,7 @@ export class WAHAMessageEditedConsumer extends ChatWootWAHABaseConsumer {
|
||||
const event: WAHAWebhookMessageEdited = job.data.event as any;
|
||||
const session = new WAHASessionAPI(event.session, container.WAHASelf());
|
||||
const handler = new MessageEditedHandler(
|
||||
job,
|
||||
container.MessageMappingService(),
|
||||
container.ContactConversationService(),
|
||||
container.Logger(),
|
||||
@@ -57,12 +60,19 @@ export class WAHAMessageEditedConsumer extends ChatWootWAHABaseConsumer {
|
||||
}
|
||||
|
||||
class MessageEditedHandler extends MessageBaseHandler<WAMessageEditedBody> {
|
||||
getContent(payload: WAMessageEditedBody): string {
|
||||
protected async getMessage(
|
||||
payload: WAMessageEditedBody,
|
||||
): Promise<ChatWootMessagePartial> {
|
||||
const body = payload.body;
|
||||
const formatted = WhatsappToMarkdown(body);
|
||||
return this.l
|
||||
const content = this.l
|
||||
.key(TKey.MESSAGE_EDITED_IN_WHATSAPP)
|
||||
.render({ text: formatted });
|
||||
return {
|
||||
content: content,
|
||||
attachments: [],
|
||||
private: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
getReplyToWhatsAppID(payload: WAMessageEditedBody): string {
|
||||
|
||||
@@ -4,11 +4,11 @@ import { SendAttachment } from '@waha/apps/chatwoot/client/types';
|
||||
import { QueueName } from '@waha/apps/chatwoot/consumers/QueueName';
|
||||
import { EventData } from '@waha/apps/chatwoot/consumers/types';
|
||||
import {
|
||||
ChatWootMessagePartial,
|
||||
ChatWootWAHABaseConsumer,
|
||||
IMessageInfo,
|
||||
} from '@waha/apps/chatwoot/consumers/waha/base';
|
||||
import { MessageBaseHandler } from '@waha/apps/chatwoot/consumers/waha/base';
|
||||
import { TKey } from '@waha/apps/chatwoot/locale';
|
||||
import { WAHASessionAPI } from '@waha/apps/chatwoot/session/WAHASelf';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
import { parseMessageIdSerialized } from '@waha/core/utils/ids';
|
||||
@@ -18,6 +18,7 @@ import { WAMessageReaction, WAReaction } from '@waha/structures/responses.dto';
|
||||
import { WAHAWebhookMessageReaction } from '@waha/structures/webhooks.dto';
|
||||
import { Job } from 'bullmq';
|
||||
import { PinoLogger } from 'nestjs-pino';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
|
||||
@Processor(QueueName.WAHA_MESSAGE_REACTION, { concurrency: JOB_CONCURRENCY })
|
||||
export class WAHAMessageReactionConsumer extends ChatWootWAHABaseConsumer {
|
||||
@@ -41,6 +42,7 @@ export class WAHAMessageReactionConsumer extends ChatWootWAHABaseConsumer {
|
||||
const event: WAHAWebhookMessageReaction = job.data.event as any;
|
||||
const session = new WAHASessionAPI(event.session, container.WAHASelf());
|
||||
const handler = new MessageReactionHandler(
|
||||
job,
|
||||
container.MessageMappingService(),
|
||||
container.ContactConversationService(),
|
||||
container.Logger(),
|
||||
@@ -54,15 +56,24 @@ export class WAHAMessageReactionConsumer extends ChatWootWAHABaseConsumer {
|
||||
}
|
||||
|
||||
export class MessageReactionHandler extends MessageBaseHandler<WAMessageReaction> {
|
||||
getContent(payload: WAMessageReaction) {
|
||||
protected async getMessage(
|
||||
payload: WAMessageReaction,
|
||||
): Promise<ChatWootMessagePartial> {
|
||||
const reaction = payload.reaction as WAReaction;
|
||||
const emoji = reaction.text;
|
||||
if (!emoji) {
|
||||
return this.l.key(TKey.WHATSAPP_REACTION_REMOVED).render();
|
||||
let content: string;
|
||||
if (emoji) {
|
||||
content = this.l.key(TKey.WHATSAPP_REACTION_ADDED).render({
|
||||
emoji: emoji,
|
||||
});
|
||||
} else {
|
||||
content = this.l.key(TKey.WHATSAPP_REACTION_REMOVED).render();
|
||||
}
|
||||
return this.l.key(TKey.WHATSAPP_REACTION_ADDED).render({
|
||||
emoji: emoji,
|
||||
});
|
||||
return {
|
||||
content: content,
|
||||
attachments: [],
|
||||
private: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
getReplyToWhatsAppID(payload: WAMessageReaction) {
|
||||
|
||||
@@ -10,18 +10,19 @@ import {
|
||||
ChatWootWAHABaseConsumer,
|
||||
IMessageInfo,
|
||||
} from '@waha/apps/chatwoot/consumers/waha/base';
|
||||
import { Locale, TKey } from '@waha/apps/chatwoot/locale';
|
||||
import { Locale } from '@waha/apps/chatwoot/i18n/locale';
|
||||
import {
|
||||
ChatwootMessage,
|
||||
MessageMappingService,
|
||||
} from '@waha/apps/chatwoot/storage';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
import { toCusFormat } from '@waha/core/engines/noweb/session.noweb.core';
|
||||
import { RMutexService } from '@waha/modules/rmutex/rmutex.service';
|
||||
import { WAHAEvents } from '@waha/structures/enums.dto';
|
||||
import { WAHAWebhookMessageRevoked } from '@waha/structures/webhooks.dto';
|
||||
import { Job } from 'bullmq';
|
||||
import { PinoLogger } from 'nestjs-pino';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
import { toCusFormat } from '@waha/core/utils/jids';
|
||||
|
||||
@Processor(QueueName.WAHA_MESSAGE_REVOKED, { concurrency: JOB_CONCURRENCY })
|
||||
export class WAHAMessageRevokedConsumer extends ChatWootWAHABaseConsumer {
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
ChatWootWAHABaseConsumer,
|
||||
IMessageInfo,
|
||||
} from '@waha/apps/chatwoot/consumers/waha/base';
|
||||
import { Locale, TKey } from '@waha/apps/chatwoot/locale';
|
||||
import { Locale } from '@waha/apps/chatwoot/i18n/locale';
|
||||
import { WAHASelf } from '@waha/apps/chatwoot/session/WAHASelf';
|
||||
import { SessionStatusEmoji } from '@waha/apps/chatwoot/SessionStatusEmoji';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
@@ -19,6 +19,8 @@ import { WAHAEvents, WAHASessionStatus } from '@waha/structures/enums.dto';
|
||||
import { WAHAWebhookSessionStatus } from '@waha/structures/webhooks.dto';
|
||||
import { Job } from 'bullmq';
|
||||
import { PinoLogger } from 'nestjs-pino';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
import { waitUntil } from '@waha/utils/promiseTimeout';
|
||||
|
||||
@Processor(QueueName.WAHA_SESSION_STATUS, { concurrency: JOB_CONCURRENCY })
|
||||
export class WAHASessionStatusConsumer extends ChatWootWAHABaseConsumer {
|
||||
@@ -48,6 +50,9 @@ export class WAHASessionStatusConsumer extends ChatWootWAHABaseConsumer {
|
||||
}
|
||||
}
|
||||
|
||||
const RECOVER_TIME_MS = 10_000;
|
||||
const CHECK_STATUS_INTERVAL_MS = 2_000;
|
||||
|
||||
export class SessionStatusHandler {
|
||||
constructor(
|
||||
private repo: ContactConversationService,
|
||||
@@ -56,28 +61,61 @@ export class SessionStatusHandler {
|
||||
) {}
|
||||
|
||||
async handle(data: WAHAWebhookSessionStatus) {
|
||||
const conversation = await this.repo.InboxNotifications();
|
||||
// Report session status
|
||||
const emoji = SessionStatusEmoji(data.payload.status);
|
||||
const activity = this.l.key(TKey.APP_SESSION_STATUS_CHANGE).r({
|
||||
emoji: emoji,
|
||||
session: data.session,
|
||||
status: data.payload.status,
|
||||
});
|
||||
await conversation.activity(activity);
|
||||
|
||||
const payload = data.payload;
|
||||
let text = '';
|
||||
const current = payload.statuses?.at(-1);
|
||||
const previous = payload.statuses?.at(-2);
|
||||
const older = payload.statuses?.at(-3);
|
||||
switch (payload.status) {
|
||||
case WAHASessionStatus.STARTING:
|
||||
// WORKING => STARTING [=> WORKING]
|
||||
if (previous?.status == WAHASessionStatus.WORKING) {
|
||||
// if previous is WORKING - wait, give time to recover
|
||||
const recovered = await waitUntil(
|
||||
async () => {
|
||||
const response = await this.waha.get(data.session);
|
||||
return response.status == WAHASessionStatus.WORKING;
|
||||
},
|
||||
CHECK_STATUS_INTERVAL_MS,
|
||||
RECOVER_TIME_MS,
|
||||
);
|
||||
if (recovered) {
|
||||
// Current status is WORKING, no needs for an alert
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WAHASessionStatus.WORKING:
|
||||
// WORKING => STARTING => WORKING
|
||||
if (
|
||||
previous?.status == WAHASessionStatus.STARTING &&
|
||||
older?.status == WAHASessionStatus.WORKING
|
||||
) {
|
||||
if (current?.timestamp - previous?.timestamp < RECOVER_TIME_MS) {
|
||||
// Session got recovered fast, no needs to notify about that
|
||||
return;
|
||||
}
|
||||
}
|
||||
text = this.l.key(TKey.APP_SESSION_STATUS_WORKING).r({
|
||||
name: data.me?.pushName || 'Unknown',
|
||||
id: data.me?.id || 'No phone number',
|
||||
});
|
||||
break;
|
||||
case WAHASessionStatus.STOPPED:
|
||||
try {
|
||||
// Check the session is yet in STOPPED status.
|
||||
// In case of server restarts,
|
||||
// the consumer can process STOPPED after STARTING/WORKING
|
||||
const response = await this.waha.get(data.session);
|
||||
if (response.status != WAHASessionStatus.STOPPED) {
|
||||
return;
|
||||
}
|
||||
} catch (_) {}
|
||||
text = this.l.key(TKey.APP_SESSION_STATUS_ERROR).r();
|
||||
text += '\n\n';
|
||||
text += this.l.key(TKey.APP_HELP_REMINDER).r();
|
||||
text += '\n\n';
|
||||
break;
|
||||
case WAHASessionStatus.FAILED:
|
||||
text = this.l.key(TKey.APP_SESSION_STATUS_ERROR).r();
|
||||
text += '\n\n';
|
||||
@@ -87,6 +125,18 @@ export class SessionStatusHandler {
|
||||
case WAHASessionStatus.SCAN_QR_CODE:
|
||||
text = this.l.key(TKey.APP_SESSION_SCAN_QR_CODE).r();
|
||||
}
|
||||
//
|
||||
// Report Status Change if required
|
||||
//
|
||||
const conversation = await this.repo.InboxNotifications();
|
||||
const emoji = SessionStatusEmoji(data.payload.status);
|
||||
const activity = this.l.key(TKey.APP_SESSION_STATUS_CHANGE).r({
|
||||
emoji: emoji,
|
||||
session: data.session,
|
||||
status: data.payload.status,
|
||||
});
|
||||
await conversation.activity(activity);
|
||||
|
||||
if (text) {
|
||||
const message: conversation_message_create = {
|
||||
content: text,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { public_contact_create_update_payload } from '@figuro/chatwoot-sdk';
|
||||
import { ContactInfo } from '@waha/apps/chatwoot/client/ContactConversationService';
|
||||
import { AttributeKey, INBOX_CONTACT_CHAT_ID } from '@waha/apps/chatwoot/const';
|
||||
import { Locale, TKey } from '@waha/apps/chatwoot/locale';
|
||||
import { Locale } from '@waha/apps/chatwoot/i18n/locale';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
|
||||
/**
|
||||
* Inbox Notifications Contact
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
import {
|
||||
isJidGroup,
|
||||
isJidNewsletter,
|
||||
isJidStatusBroadcast,
|
||||
} from '@adiwajshing/baileys';
|
||||
import { isLidUser } from '@adiwajshing/baileys/lib/WABinary/jid-utils';
|
||||
import { public_contact_create_update_payload as Contact } from '@figuro/chatwoot-sdk';
|
||||
import { ContactInfo } from '@waha/apps/chatwoot/client/ContactConversationService';
|
||||
import { AttributeKey } from '@waha/apps/chatwoot/const';
|
||||
import { Locale, TKey } from '@waha/apps/chatwoot/locale';
|
||||
import { Locale } from '@waha/apps/chatwoot/i18n/locale';
|
||||
import { WAHASessionAPI } from '@waha/apps/chatwoot/session/WAHASelf';
|
||||
import { Channel } from '@waha/structures/channels.dto';
|
||||
import { CacheAsync } from '@waha/utils/Cache';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
import {
|
||||
isJidBroadcast,
|
||||
isJidGroup,
|
||||
isJidNewsletter,
|
||||
isJidStatusBroadcast,
|
||||
isLidUser,
|
||||
isPnUser,
|
||||
} from '@waha/core/utils/jids';
|
||||
import { UnknownJIDFormat } from '@waha/apps/chatwoot/errors';
|
||||
import { E164Parser } from '@waha/core/utils/PhoneJidNormalizer';
|
||||
|
||||
/**
|
||||
* Base WhatsApp contact info class
|
||||
@@ -64,8 +69,7 @@ class JidContactInfo extends ChatContactInfo {
|
||||
const contact: any = await this.session.getContact(this.chatId);
|
||||
const name =
|
||||
contact?.name || contact?.pushName || contact?.pushname || this.chatId;
|
||||
const phoneNumber = this.chatId.split('@')[0];
|
||||
const phoneNumberE164 = '+' + phoneNumber;
|
||||
const phoneNumberE164 = E164Parser.fromJid(this.chatId);
|
||||
|
||||
const result: Contact = {
|
||||
name: name,
|
||||
@@ -147,6 +151,7 @@ class GroupContactInfo extends ChatContactInfo {
|
||||
const group: any = await this.session?.getGroup(this.chatId);
|
||||
if (group) {
|
||||
name = group.subject || group.name || group.topic || name;
|
||||
name = group.Name || name;
|
||||
const suffix = this.locale
|
||||
.key(TKey.WHATSAPP_CONTACT_GROUP_SUFFIX)
|
||||
.render();
|
||||
@@ -220,6 +225,31 @@ class StatusContactInfo extends ChatContactInfo {
|
||||
}
|
||||
}
|
||||
|
||||
class BroadcastContactInfo extends ChatContactInfo {
|
||||
async Attributes() {
|
||||
return {
|
||||
[AttributeKey.WA_CHAT_ID]: this.chatId,
|
||||
};
|
||||
}
|
||||
|
||||
@CacheAsync()
|
||||
async AvatarUrl(): Promise<string | null> {
|
||||
return null;
|
||||
}
|
||||
|
||||
async PublicContactCreate(): Promise<Contact> {
|
||||
const name = this.locale
|
||||
.key(TKey.WHATSAPP_CONTACT_BROADCAST_SUFFIX)
|
||||
.render();
|
||||
|
||||
return {
|
||||
identifier: this.chatId,
|
||||
name: `${name} (${this.chatId})`,
|
||||
custom_attributes: await this.Attributes(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory function to get the appropriate ContactInfo implementation
|
||||
* based on the chat ID type
|
||||
@@ -235,8 +265,13 @@ export function WhatsAppContactInfo(
|
||||
return new ChannelContactInfo(session, chatId, locale);
|
||||
} else if (isJidStatusBroadcast(chatId)) {
|
||||
return new StatusContactInfo(session, chatId, locale);
|
||||
} else if (isJidBroadcast(chatId)) {
|
||||
return new BroadcastContactInfo(session, chatId, locale);
|
||||
} else if (isLidUser(chatId)) {
|
||||
return new LidContactInfo(session, chatId, locale);
|
||||
} else if (isPnUser(chatId)) {
|
||||
return new JidContactInfo(session, chatId, locale);
|
||||
} else {
|
||||
throw new UnknownJIDFormat(chatId);
|
||||
}
|
||||
return new JidContactInfo(session, chatId, locale);
|
||||
}
|
||||
@@ -1,14 +1,20 @@
|
||||
import ChatwootClient from '@figuro/chatwoot-sdk';
|
||||
import * as lodash from 'lodash';
|
||||
import { AxiosLogging } from '@waha/apps/app_sdk/AxiosLogging';
|
||||
import { ILogger } from '@waha/apps/app_sdk/ILogger';
|
||||
import { ContactAPI } from '@waha/apps/chatwoot/client/ContactAPI';
|
||||
import { ContactService } from '@waha/apps/chatwoot/client/ContactService';
|
||||
import { ContactConversationService } from '@waha/apps/chatwoot/client/ContactConversationService';
|
||||
import { ConversationAPI } from '@waha/apps/chatwoot/client/ConversationAPI';
|
||||
import { CustomAttributesAPI } from '@waha/apps/chatwoot/client/CustomAttributesAPI';
|
||||
import { ConversationService } from '@waha/apps/chatwoot/client/ConversationService';
|
||||
import { CustomAttributesService } from '@waha/apps/chatwoot/client/CustomAttributesService';
|
||||
import { ChatWootInboxAPI } from '@waha/apps/chatwoot/client/interfaces';
|
||||
import { ChatWootAppConfig } from '@waha/apps/chatwoot/dto/config.dto';
|
||||
import {
|
||||
ChatWootAppConfig,
|
||||
ChatWootConfig,
|
||||
DEFAULT_LOCALE,
|
||||
LinkPreview,
|
||||
} from '@waha/apps/chatwoot/dto/config.dto';
|
||||
import { ChatWootErrorReporter } from '@waha/apps/chatwoot/error/ChatWootErrorReporter';
|
||||
import { Locale } from '@waha/apps/chatwoot/locale';
|
||||
import { Locale } from '@waha/apps/chatwoot/i18n/locale';
|
||||
import { WAHASelf } from '@waha/apps/chatwoot/session/WAHASelf';
|
||||
import {
|
||||
ChatwootMessageRepository,
|
||||
@@ -18,21 +24,18 @@ import {
|
||||
} from '@waha/apps/chatwoot/storage';
|
||||
import { Job } from 'bullmq';
|
||||
import { Knex } from 'knex';
|
||||
import { i18n } from '@waha/apps/chatwoot/i18n';
|
||||
import { CacheSync } from '@waha/utils/Cache';
|
||||
import {
|
||||
ConversationSelector,
|
||||
ConversationSort,
|
||||
} from '@waha/apps/chatwoot/services/ConversationSelector';
|
||||
|
||||
/**
|
||||
* Dependency Injection Container for ChatWoot
|
||||
* Manages the creation and caching of various clients and repositories
|
||||
*/
|
||||
export class DIContainer {
|
||||
private accountAPI: ChatwootClient;
|
||||
private inboxAPI: ChatWootInboxAPI;
|
||||
private contactAPI: ContactAPI;
|
||||
private conversationAPI: ConversationAPI;
|
||||
private contactConversationService: ContactConversationService;
|
||||
private locale: Locale;
|
||||
private messageMappingService: MessageMappingService;
|
||||
private wahaSelf: WAHASelf;
|
||||
|
||||
/**
|
||||
* Creates a new DIContainer with the given configuration
|
||||
*/
|
||||
@@ -61,121 +64,124 @@ export class DIContainer {
|
||||
return this.knex;
|
||||
}
|
||||
|
||||
@CacheSync()
|
||||
public Locale(): Locale {
|
||||
if (!this.locale) {
|
||||
this.locale = new Locale(this.config.locale);
|
||||
}
|
||||
return this.locale;
|
||||
let locale = i18n.locale(this.config.locale || DEFAULT_LOCALE);
|
||||
locale = locale.override(this.ChatWootConfig().templates);
|
||||
return locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the AccountAPI client
|
||||
* @returns ChatwootClient instance
|
||||
*/
|
||||
@CacheSync()
|
||||
public AccountAPI(): ChatwootClient {
|
||||
if (!this.accountAPI) {
|
||||
this.accountAPI = new ChatwootClient({
|
||||
config: {
|
||||
basePath: this.config.url,
|
||||
with_credentials: true,
|
||||
credentials: 'include',
|
||||
token: this.config.accountToken,
|
||||
},
|
||||
});
|
||||
}
|
||||
return this.accountAPI;
|
||||
return new ChatwootClient({
|
||||
config: {
|
||||
basePath: this.config.url,
|
||||
with_credentials: true,
|
||||
credentials: 'include',
|
||||
token: this.config.accountToken,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the InboxAPI client
|
||||
* @returns ChatWootInboxAPI instance
|
||||
*/
|
||||
@CacheSync()
|
||||
public InboxAPI(): ChatWootInboxAPI {
|
||||
if (!this.inboxAPI) {
|
||||
const chatwootClientAPI = new ChatwootClient({
|
||||
config: {
|
||||
basePath: this.config.url,
|
||||
with_credentials: true,
|
||||
credentials: 'include',
|
||||
token: this.config.inboxIdentifier,
|
||||
},
|
||||
});
|
||||
this.inboxAPI = chatwootClientAPI.client as ChatWootInboxAPI;
|
||||
}
|
||||
return this.inboxAPI;
|
||||
const chatwootClientAPI = new ChatwootClient({
|
||||
config: {
|
||||
basePath: this.config.url,
|
||||
with_credentials: true,
|
||||
credentials: 'include',
|
||||
token: this.config.inboxIdentifier,
|
||||
},
|
||||
});
|
||||
return chatwootClientAPI.client as ChatWootInboxAPI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ContactAPI
|
||||
* @returns ContactAPI instance
|
||||
* Gets the ContactService
|
||||
* @returns ContactService instance
|
||||
*/
|
||||
private ContactAPI(): ContactAPI {
|
||||
if (!this.contactAPI) {
|
||||
this.contactAPI = new ContactAPI(
|
||||
this.config,
|
||||
this.AccountAPI(),
|
||||
this.InboxAPI(),
|
||||
this.logger,
|
||||
);
|
||||
}
|
||||
return this.contactAPI;
|
||||
@CacheSync()
|
||||
private ContactService(): ContactService {
|
||||
return new ContactService(
|
||||
this.config,
|
||||
this.AccountAPI(),
|
||||
this.InboxAPI(),
|
||||
this.logger,
|
||||
);
|
||||
}
|
||||
|
||||
@CacheSync()
|
||||
public ConversationSelector() {
|
||||
const config = this.ChatWootConfig();
|
||||
return new ConversationSelector({
|
||||
sort: config.conversations.sort,
|
||||
status: config.conversations.status,
|
||||
inboxId: this.config.inboxId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ConversationAPI
|
||||
* @returns ConversationAPI instance
|
||||
* Gets the ConversationService
|
||||
* @returns ConversationService instance
|
||||
*/
|
||||
private ConversationAPI(): ConversationAPI {
|
||||
if (!this.conversationAPI) {
|
||||
this.conversationAPI = new ConversationAPI(
|
||||
this.config,
|
||||
this.InboxAPI(),
|
||||
this.logger,
|
||||
);
|
||||
}
|
||||
return this.conversationAPI;
|
||||
@CacheSync()
|
||||
private ConversationService(): ConversationService {
|
||||
return new ConversationService(
|
||||
this.config,
|
||||
this.AccountAPI(),
|
||||
this.InboxAPI(),
|
||||
this.ConversationSelector(),
|
||||
this.logger,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ContactConversationService
|
||||
* @returns ContactConversationService instance
|
||||
*/
|
||||
@CacheSync()
|
||||
public ContactConversationService(): ContactConversationService {
|
||||
if (!this.contactConversationService) {
|
||||
this.contactConversationService = new ContactConversationService(
|
||||
this.config,
|
||||
this.ContactAPI(),
|
||||
this.ConversationAPI(),
|
||||
this.AccountAPI(),
|
||||
this.logger,
|
||||
this.Locale(),
|
||||
);
|
||||
}
|
||||
return this.contactConversationService;
|
||||
return new ContactConversationService(
|
||||
this.config,
|
||||
this.ContactService(),
|
||||
this.ConversationService(),
|
||||
this.AccountAPI(),
|
||||
this.logger,
|
||||
this.Locale(),
|
||||
);
|
||||
}
|
||||
|
||||
@CacheSync()
|
||||
private ChatwootMessageRepository(): ChatwootMessageRepository {
|
||||
return new ChatwootMessageRepository(this.Knex(), this.AppPk());
|
||||
}
|
||||
|
||||
@CacheSync()
|
||||
private WhatsAppMessageRepository(): WhatsAppMessageRepository {
|
||||
return new WhatsAppMessageRepository(this.Knex(), this.AppPk());
|
||||
}
|
||||
|
||||
@CacheSync()
|
||||
private MessageMappingRepository(): MessageMappingRepository {
|
||||
return new MessageMappingRepository(this.Knex(), this.AppPk());
|
||||
}
|
||||
|
||||
@CacheSync()
|
||||
public MessageMappingService(): MessageMappingService {
|
||||
if (!this.messageMappingService) {
|
||||
this.messageMappingService = new MessageMappingService(
|
||||
this.Knex(),
|
||||
this.WhatsAppMessageRepository(),
|
||||
this.ChatwootMessageRepository(),
|
||||
this.MessageMappingRepository(),
|
||||
);
|
||||
}
|
||||
return this.messageMappingService;
|
||||
return new MessageMappingService(
|
||||
this.Knex(),
|
||||
this.WhatsAppMessageRepository(),
|
||||
this.ChatwootMessageRepository(),
|
||||
this.MessageMappingRepository(),
|
||||
);
|
||||
}
|
||||
|
||||
public ChatWootErrorReporter(job: Job): ChatWootErrorReporter {
|
||||
@@ -186,16 +192,32 @@ export class DIContainer {
|
||||
* Gets the WAHASelf instance
|
||||
* @returns WAHASelf instance
|
||||
*/
|
||||
@CacheSync()
|
||||
public WAHASelf(): WAHASelf {
|
||||
if (!this.wahaSelf) {
|
||||
this.wahaSelf = new WAHASelf();
|
||||
const logging = new AxiosLogging(this.Logger());
|
||||
logging.applyTo(this.wahaSelf.client);
|
||||
}
|
||||
return this.wahaSelf;
|
||||
const self = new WAHASelf();
|
||||
const logging = new AxiosLogging(this.Logger());
|
||||
logging.applyTo(self.client);
|
||||
return self;
|
||||
}
|
||||
|
||||
public CustomAttributesAPI() {
|
||||
return new CustomAttributesAPI(this.config, this.AccountAPI());
|
||||
@CacheSync()
|
||||
public CustomAttributesService() {
|
||||
return new CustomAttributesService(this.config, this.AccountAPI());
|
||||
}
|
||||
|
||||
@CacheSync()
|
||||
public ChatWootConfig(): ChatWootConfig {
|
||||
const defaults: ChatWootConfig = {
|
||||
templates: {},
|
||||
linkPreview: LinkPreview.OFF,
|
||||
commands: {
|
||||
server: true,
|
||||
},
|
||||
conversations: {
|
||||
sort: ConversationSort.created_newest,
|
||||
status: null,
|
||||
},
|
||||
};
|
||||
return lodash.defaults({}, this.config, defaults);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,48 @@
|
||||
import { ChatWootAPIConfig } from '@waha/apps/chatwoot/client/interfaces';
|
||||
import { DEFAULT_LOCALE, LOCALES } from '@waha/apps/chatwoot/locale';
|
||||
import { IsIn, IsNumber, IsString } from 'class-validator';
|
||||
import {
|
||||
IsBoolean,
|
||||
IsEnum,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsString,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
import { IsDynamicObject } from '@waha/nestjs/validation/IsDynamicObject';
|
||||
import {
|
||||
ConversationSelectorConfig,
|
||||
ConversationSort,
|
||||
} from '@waha/apps/chatwoot/services/ConversationSelector';
|
||||
import { ConversationStatus } from '@waha/apps/chatwoot/client/types';
|
||||
|
||||
export const DEFAULT_LOCALE = 'en-US';
|
||||
|
||||
export class ChatWootCommandsConfig {
|
||||
@IsBoolean()
|
||||
server: boolean = true;
|
||||
}
|
||||
|
||||
export enum LinkPreview {
|
||||
OFF = 'OFF',
|
||||
LQ = 'LG',
|
||||
HQ = 'HG',
|
||||
}
|
||||
|
||||
export class ChatWootConversationsConfig {
|
||||
@IsEnum(ConversationSort)
|
||||
sort: ConversationSort;
|
||||
|
||||
@IsOptional()
|
||||
@IsEnum(ConversationStatus, { each: true })
|
||||
status: Array<ConversationStatus> | null;
|
||||
}
|
||||
|
||||
export interface ChatWootConfig {
|
||||
templates: Record<string, string>;
|
||||
linkPreview: LinkPreview;
|
||||
commands: ChatWootCommandsConfig;
|
||||
conversations: ChatWootConversationsConfig;
|
||||
}
|
||||
|
||||
export class ChatWootAppConfig implements ChatWootAPIConfig {
|
||||
@IsString()
|
||||
@@ -18,7 +60,24 @@ export class ChatWootAppConfig implements ChatWootAPIConfig {
|
||||
@IsString()
|
||||
inboxIdentifier: string;
|
||||
|
||||
@IsEnum(LinkPreview)
|
||||
@IsOptional()
|
||||
linkPreview?: LinkPreview = LinkPreview.OFF;
|
||||
|
||||
@IsString()
|
||||
@IsIn(LOCALES)
|
||||
locale: string = DEFAULT_LOCALE;
|
||||
|
||||
@IsOptional()
|
||||
@IsDynamicObject()
|
||||
templates?: Record<string, string>;
|
||||
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
@Type(() => ChatWootCommandsConfig)
|
||||
commands?: ChatWootCommandsConfig;
|
||||
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
@Type(() => ChatWootConversationsConfig)
|
||||
conversations?: ChatWootConversationsConfig;
|
||||
}
|
||||
@@ -1,14 +1,20 @@
|
||||
import type { conversation_message_create } from '@figuro/chatwoot-sdk/dist/models/conversation_message_create';
|
||||
import { ILogger } from '@waha/apps/app_sdk/ILogger';
|
||||
import { NextAttemptDelayInWholeSeconds } from '@waha/apps/app_sdk/JobUtils';
|
||||
import {
|
||||
JobLink,
|
||||
NextAttemptDelayInWholeSeconds,
|
||||
} from '@waha/apps/app_sdk/JobUtils';
|
||||
import { Conversation } from '@waha/apps/chatwoot/client/Conversation';
|
||||
import { MessageType } from '@waha/apps/chatwoot/client/types';
|
||||
import { ErrorRenderer } from '@waha/apps/chatwoot/error/ErrorRenderer';
|
||||
import { Locale, TKey } from '@waha/apps/chatwoot/locale';
|
||||
import { Locale } from '@waha/apps/chatwoot/i18n/locale';
|
||||
import { Job } from 'bullmq';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
|
||||
const renderer: ErrorRenderer = new ErrorRenderer();
|
||||
|
||||
export class ChatWootErrorReporter {
|
||||
private errorRenderer: ErrorRenderer = new ErrorRenderer();
|
||||
private errorRenderer: ErrorRenderer = renderer;
|
||||
|
||||
constructor(
|
||||
private logger: ILogger,
|
||||
@@ -23,12 +29,15 @@ export class ChatWootErrorReporter {
|
||||
error: any,
|
||||
replyTo?: number,
|
||||
) {
|
||||
const errorText = this.errorRenderer.renderError(error);
|
||||
const errorText = this.errorRenderer.text(error);
|
||||
this.logger.error(errorText);
|
||||
const errorUrl = `http://localhost:3000/jobs/queue/${encodeURIComponent(
|
||||
this.job.queueName,
|
||||
)}/${this.job.id}`;
|
||||
const template = this.l.key(TKey.JOB_ERROR_REPORT);
|
||||
try {
|
||||
const data = this.errorRenderer.data(error);
|
||||
this.logger.error(JSON.stringify(data, null, 2));
|
||||
} catch (err) {
|
||||
this.logger.error(`Error occurred while login details for error: ${err}`);
|
||||
}
|
||||
const template = this.l.key(TKey.JOB_REPORT_ERROR);
|
||||
const nextDelay = NextAttemptDelayInWholeSeconds(this.job);
|
||||
const attempts = {
|
||||
current: this.job.attemptsMade + 1,
|
||||
@@ -38,10 +47,7 @@ export class ChatWootErrorReporter {
|
||||
const content = template.render({
|
||||
header: header,
|
||||
error: nextDelay != null ? null : errorText,
|
||||
details: {
|
||||
text: `${this.job.queueName} => ${this.job.id}`,
|
||||
url: errorUrl,
|
||||
},
|
||||
details: JobLink(this.job),
|
||||
attempts: attempts,
|
||||
});
|
||||
const request: conversation_message_create = {
|
||||
@@ -71,20 +77,14 @@ export class ChatWootErrorReporter {
|
||||
type: MessageType,
|
||||
replyTo?: number,
|
||||
): Promise<void> {
|
||||
const jobUrl = `http://localhost:3000/jobs/queue/${encodeURIComponent(
|
||||
this.job.queueName,
|
||||
)}/${this.job.id}`;
|
||||
const template = this.l.key(TKey.JOB_SUCCEEDED_REPORT);
|
||||
const template = this.l.key(TKey.JOB_REPORT_SUCCEEDED);
|
||||
const attempts = {
|
||||
current: this.job.attemptsMade + 1,
|
||||
max: this.job.opts?.attempts || 1,
|
||||
};
|
||||
|
||||
const content = template.render({
|
||||
details: {
|
||||
text: `${this.job.queueName} => ${this.job.id}`,
|
||||
url: jobUrl,
|
||||
},
|
||||
details: JobLink(this.job),
|
||||
attempts: attempts,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,45 +1,28 @@
|
||||
import { ApiError } from '@figuro/chatwoot-sdk/dist/core/ApiError';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ApiError as ChatWootAPIError } from '@figuro/chatwoot-sdk/dist/core/ApiError';
|
||||
import type { AxiosError } from 'axios';
|
||||
|
||||
/**
|
||||
* Class responsible for rendering error information based on error type
|
||||
*/
|
||||
export class ErrorRenderer {
|
||||
interface IErrorRender<T> {
|
||||
/**
|
||||
* Renders error information based on error type
|
||||
* @param error The error to render
|
||||
* @returns Formatted error text
|
||||
* Get an error text to show to the user
|
||||
*/
|
||||
public renderError(error: any): string {
|
||||
// Handle Axios errors
|
||||
if (error.isAxiosError) {
|
||||
return this.renderAxiosError(error as AxiosError);
|
||||
}
|
||||
|
||||
// Handle Chatwoot SDK ApiError
|
||||
if (error instanceof ApiError) {
|
||||
return this.renderApiError(error);
|
||||
}
|
||||
|
||||
// For all other errors
|
||||
return this.renderGenericError(error);
|
||||
}
|
||||
text(error: T): string;
|
||||
|
||||
/**
|
||||
* Renders Axios error information
|
||||
* @param error The Axios error to render
|
||||
* @returns Formatted error text
|
||||
* Structured error data for logging/inspection
|
||||
*/
|
||||
private renderAxiosError(error: AxiosError): string {
|
||||
let errorText = `Axios Error: ${error.message}`;
|
||||
data(error: T): Record<string, any>;
|
||||
}
|
||||
|
||||
class AxiosErrorRenderer implements IErrorRender<AxiosError> {
|
||||
text(error: AxiosError): string {
|
||||
let errorText = `API Error: ${error.message}`;
|
||||
if (!error.response?.data) {
|
||||
return errorText;
|
||||
}
|
||||
|
||||
// Add response data if it exists and is JSON
|
||||
try {
|
||||
const data = error.response.data as any;
|
||||
let json: undefined;
|
||||
let json: any;
|
||||
if (Buffer.isBuffer(data)) {
|
||||
json = JSON.parse(data.toString());
|
||||
} else if (typeof data === 'object') {
|
||||
@@ -55,16 +38,35 @@ export class ErrorRenderer {
|
||||
return errorText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders Chatwoot SDK ApiError information
|
||||
* @param error The ApiError to render
|
||||
* @returns Formatted error text
|
||||
*/
|
||||
private renderApiError(error: ApiError): string {
|
||||
let errorText = `API Error: ${error.message}`;
|
||||
data(error: AxiosError): Record<string, any> {
|
||||
const { config, response, request } = error as any;
|
||||
|
||||
return {
|
||||
class: 'APIError',
|
||||
request: {
|
||||
method: request?.method || config?.method,
|
||||
url: request?.path || config?.url,
|
||||
params: config?.params,
|
||||
body: request?.body || config?.data,
|
||||
},
|
||||
response: {
|
||||
status: response?.status,
|
||||
statusText: response?.statusText,
|
||||
headers: response?.headers,
|
||||
body: response?.data,
|
||||
},
|
||||
message: error.message,
|
||||
code: (error as any)?.code,
|
||||
stack: error.stack,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class ChatWootAPIErrorRenderer implements IErrorRender<ChatWootAPIError> {
|
||||
text(error: ChatWootAPIError): string {
|
||||
let errorText = `ChatWoot API Error: ${error.message}`;
|
||||
errorText += `\nStatus: ${error.status}`;
|
||||
|
||||
// Add body if it exists
|
||||
if (error.body) {
|
||||
try {
|
||||
const body =
|
||||
@@ -78,12 +80,75 @@ export class ErrorRenderer {
|
||||
return errorText;
|
||||
}
|
||||
|
||||
data(error: ChatWootAPIError): Record<string, any> {
|
||||
return {
|
||||
class: 'ChatWootAPIError',
|
||||
request: {
|
||||
method: error.request?.method,
|
||||
url: error.request?.url,
|
||||
query: error.request?.query,
|
||||
path: error.request?.path,
|
||||
body: error.request?.body,
|
||||
},
|
||||
response: {
|
||||
status: error.status,
|
||||
statusText: error.statusText,
|
||||
body: error.body,
|
||||
},
|
||||
message: error.message,
|
||||
stack: error.stack,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class GenericErrorRenderer implements IErrorRender<any> {
|
||||
text(error: any): string {
|
||||
return error?.toString?.() ?? String(error);
|
||||
}
|
||||
|
||||
data(error: any): Record<string, any> {
|
||||
return {
|
||||
class: error?.name ?? error?.constructor?.name ?? typeof error,
|
||||
message: error?.message ?? String(error),
|
||||
stack: error.stack,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class responsible for rendering error information based on error type
|
||||
*/
|
||||
export class ErrorRenderer implements IErrorRender<any> {
|
||||
private readonly axiosRenderer = new AxiosErrorRenderer();
|
||||
private readonly chatwootRenderer = new ChatWootAPIErrorRenderer();
|
||||
private readonly genericRenderer = new GenericErrorRenderer();
|
||||
|
||||
/**
|
||||
* Renders generic error information
|
||||
* Renders error information based on error type
|
||||
* @param error The error to render
|
||||
* @returns Formatted error text
|
||||
*/
|
||||
private renderGenericError(error: any): string {
|
||||
return error.toString();
|
||||
public text(error: any): string {
|
||||
if (error?.isAxiosError) {
|
||||
return this.axiosRenderer.text(error as AxiosError);
|
||||
}
|
||||
|
||||
if (error instanceof ChatWootAPIError) {
|
||||
return this.chatwootRenderer.text(error);
|
||||
}
|
||||
|
||||
return this.genericRenderer.text(error);
|
||||
}
|
||||
|
||||
public data(error: any): Record<string, any> {
|
||||
if (error?.isAxiosError) {
|
||||
return this.axiosRenderer.data(error as AxiosError);
|
||||
}
|
||||
|
||||
if (error instanceof ChatWootAPIError) {
|
||||
return this.chatwootRenderer.data(error);
|
||||
}
|
||||
|
||||
return this.genericRenderer.data(error);
|
||||
}
|
||||
}
|
||||
@@ -9,3 +9,9 @@ export class PhoneNumberNotFoundInWhatsAppError extends Error {
|
||||
super(`Phone number not found in WhatsApp: ${phone}`);
|
||||
}
|
||||
}
|
||||
|
||||
export class UnknownJIDFormat extends Error {
|
||||
constructor(public jid: string) {
|
||||
super(`WhatsApp Chat ID is not recognized: ${jid}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Locale } from '@waha/apps/chatwoot/i18n/locale';
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
|
||||
export class I18N {
|
||||
private readonly locales: Record<string, Locale>;
|
||||
|
||||
constructor() {
|
||||
this.locales = {};
|
||||
}
|
||||
|
||||
available(): Array<{ name: string; locale: string }> {
|
||||
const result = [];
|
||||
for (const [key, template] of Object.entries(this.locales)) {
|
||||
result.push({ locale: key, name: template.key(TKey.LOCALE_NAME).r() });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
load(locales: Record<string, Record<string, string>>) {
|
||||
for (const [locale, strings] of Object.entries(locales)) {
|
||||
this.add(locale, strings);
|
||||
}
|
||||
}
|
||||
|
||||
add(locale: string, strings: Record<string, string>) {
|
||||
if (!this.locales[locale]) {
|
||||
this.locales[locale] = new Locale(strings);
|
||||
} else {
|
||||
this.locales[locale] = this.locales[locale].override(strings);
|
||||
}
|
||||
}
|
||||
|
||||
locale(locale: string) {
|
||||
if (!this.has(locale)) {
|
||||
throw new Error(`Locale ${locale} not found`);
|
||||
}
|
||||
return this.locales[locale];
|
||||
}
|
||||
|
||||
has(locale: string) {
|
||||
return !!this.locales[locale];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import * as path from 'path';
|
||||
import { YamlLocaleLoader } from '@waha/apps/chatwoot/i18n/loader';
|
||||
import { I18N } from '@waha/apps/chatwoot/i18n/i18n';
|
||||
|
||||
const i18n = new I18N();
|
||||
const localesDir = path.join(__dirname, 'locales');
|
||||
// Load both .yml and .yaml files from locales directory (non-recursive)
|
||||
i18n.load(new YamlLocaleLoader(localesDir, 'yml').load());
|
||||
i18n.load(new YamlLocaleLoader(localesDir, 'yaml').load());
|
||||
|
||||
// Resolve env var (supports '.' and '~'); fallback to default
|
||||
const additional = process.env.WAHA_APPS_CHATWOOT_LANGUAGES_FOLDER?.trim();
|
||||
if (additional) {
|
||||
const resolved = path.resolve(additional);
|
||||
i18n.load(new YamlLocaleLoader(resolved, 'yml').load());
|
||||
i18n.load(new YamlLocaleLoader(resolved, 'yaml').load());
|
||||
}
|
||||
|
||||
export { i18n };
|
||||
@@ -0,0 +1,33 @@
|
||||
import * as fs from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import * as yaml from 'yaml';
|
||||
|
||||
export class YamlLocaleLoader {
|
||||
constructor(
|
||||
private readonly dir: string,
|
||||
private readonly ext: string,
|
||||
) {}
|
||||
|
||||
load(): Record<string, Record<string, string>> {
|
||||
const result: Record<string, Record<string, string>> = {};
|
||||
|
||||
const files = fs.readdirSync(this.dir, { withFileTypes: true });
|
||||
for (const entry of files) {
|
||||
if (!entry.isFile()) continue;
|
||||
|
||||
const filename = entry.name;
|
||||
if (!filename.endsWith(`.${this.ext}`)) continue;
|
||||
|
||||
const locale = path.basename(filename, `.${this.ext}`);
|
||||
const filePath = path.join(this.dir, filename);
|
||||
const content = fs.readFileSync(filePath, 'utf-8');
|
||||
|
||||
const parsed = yaml.parse(content) as Record<string, string> | undefined;
|
||||
if (parsed && typeof parsed === 'object') {
|
||||
result[locale] = parsed as Record<string, string>;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import * as Mustache from 'mustache';
|
||||
import { TemplatePayloads, TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
|
||||
export class Locale {
|
||||
constructor(private readonly strings: Record<string, string>) {}
|
||||
|
||||
key<K extends TKey>(key: K): Template<K> {
|
||||
return new Template(this.strings[key] || key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the existing strings with the provided strings for the locale.
|
||||
* Merges the new strings with the current strings.
|
||||
*/
|
||||
override(strings: Record<string, string>): Locale {
|
||||
return new Locale({ ...this.strings, ...strings });
|
||||
}
|
||||
}
|
||||
|
||||
export class Template<K extends TKey> {
|
||||
constructor(private readonly template: string) {}
|
||||
|
||||
render(data: TemplatePayloads[K]): string {
|
||||
return Mustache.render(this.template, data);
|
||||
}
|
||||
|
||||
r(data: TemplatePayloads[K]): string {
|
||||
return this.render(data);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
# Arabic translations for ChatWoot integration
|
||||
APP_INBOX_CONTACT_NAME: 'تكامل واتساب (WAHA)'
|
||||
locale.name: '🇦🇪 العربية (Arabic)'
|
||||
app.inbox.contact.name: 'تكامل واتساب (WAHA)'
|
||||
app.inbox.contact.avatar.url: 'https://raw.githubusercontent.com/devlikeapro/waha/core/logo.png'
|
||||
|
||||
JOB_ERROR_REPORT: |
|
||||
job.report.error: |-
|
||||
⚠️ **{{{header}}}**
|
||||
{{#attempts.nextDelay}}
|
||||
🔄 إعادة المحاولة في {{attempts.nextDelay}} ثانية...
|
||||
@@ -18,51 +20,52 @@ JOB_ERROR_REPORT: |
|
||||
```
|
||||
{{/error}}
|
||||
|
||||
JOB_SUCCEEDED_REPORT: |
|
||||
job.report.succeeded: |-
|
||||
✅ **نجاح**
|
||||
المحاولة: {{{attempts.current}}} / {{{attempts.max}}}
|
||||
التفاصيل: [{{{details.text}}}]({{{details.url}}})
|
||||
|
||||
WHATSAPP_ERROR_SENDING_MESSAGE: تعذر إرسال رسالة على واتساب.
|
||||
WHATSAPP_ERROR_RECEIVING_MESSAGE: تعذر استلام رسالة من واتساب
|
||||
WHATSAPP_ERROR_REMOVING_MESSAGE: تعذر إزالة رسالة من واتساب
|
||||
APP_SCHEDULED_JOB_ERROR: فشل تنفيذ المهمة المجدولة
|
||||
whatsapp.message.sending.error: تعذر إرسال رسالة على واتساب.
|
||||
whatsapp.message.receiving.error: تعذر استلام رسالة من واتساب
|
||||
whatsapp.message.removing.error: تعذر إزالة رسالة من واتساب
|
||||
job.scheduled.error.header: فشل تنفيذ المهمة المجدولة
|
||||
|
||||
MESSAGE_FROM_WHATSAPP: |
|
||||
message.from.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *أرسلت من واتساب*
|
||||
|
||||
MESSAGE_FROM_API: |
|
||||
message.from.api: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *أرسلت عبر API*
|
||||
|
||||
MESSAGE_REMOVED_IN_WHATSAPP: |
|
||||
message.removed.in.whatsapp: |-
|
||||
❌ *تم حذف هذه الرسالة في واتساب*
|
||||
|
||||
MESSAGE_EDITED_IN_WHATSAPP: |
|
||||
message.edited.in.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
✏️ *تم تعديلها في واتساب*
|
||||
|
||||
WHATSAPP_GROUP_MESSAGE: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.group.message: |-
|
||||
👥 *{{{participant}}}*
|
||||
|
||||
WHATSAPP_REACTION_ADDED: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.reaction.added: |-
|
||||
*تفاعل* {{{emoji}}}
|
||||
|
||||
WHATSAPP_REACTION_REMOVED: |
|
||||
whatsapp.reaction.removed: |-
|
||||
*تمت إزالة التفاعل*
|
||||
|
||||
WHATSAPP_CONTACT_GROUP_SUFFIX: 'مجموعة'
|
||||
WHATSAPP_CONTACT_CHANNEL_SUFFIX: 'قناة'
|
||||
whatsapp.contact.group.suffix: 'مجموعة'
|
||||
whatsapp.contact.channel.suffix: 'قناة'
|
||||
whatsapp.contact.broadcast.suffix: 'قائمة البث'
|
||||
# Aka Stories
|
||||
WHATSAPP_CONTACT_STATUS_NAME: 'الحالة'
|
||||
whatsapp.contact.status.name: 'الحالة'
|
||||
|
||||
APP_CONNECTED_MESSAGE: |
|
||||
app.connected.message: |-
|
||||
🔗 **متصل: جلسة واتساب إلى صندوق وارد ChatWoot**
|
||||
|
||||
✅ تم توصيل جلسة واتساب **{{{name}}}** بنجاح بصندوق وارد ChatWoot هذا.
|
||||
@@ -80,7 +83,7 @@ APP_CONNECTED_MESSAGE: |
|
||||
|
||||
لنبدأ! 🚀
|
||||
|
||||
APP_DISCONNECTED_MESSAGE: |
|
||||
app.disconnected.message: |-
|
||||
🔌 **غير متصل: جلسة واتساب من صندوق وارد ChatWoot**
|
||||
|
||||
❌ تم قطع اتصال جلسة واتساب **{{{name}}}** من صندوق وارد ChatWoot هذا.
|
||||
@@ -89,15 +92,15 @@ APP_DISCONNECTED_MESSAGE: |
|
||||
|
||||
لإعادة الاتصال، يرجى الاتصال بالمسؤول الخاص بك.
|
||||
|
||||
APP_UPDATED_MESSAGE: |
|
||||
app.updated.message: |-
|
||||
🔄 **تم التحديث: إعدادات جلسة واتساب**
|
||||
|
||||
✅ تم تحديث إعدادات جلسة واتساب **{{{name}}}**.
|
||||
|
||||
APP_COMMANDS_LIST: |
|
||||
app.commands.list: |-
|
||||
يمكنك إدارة **تكامل واتساب** عن طريق إرسال أحد الأوامر التالية:
|
||||
|
||||
🖥️ الجلسات:
|
||||
🖥️ **الجلسة**:
|
||||
1. **status** - الحصول على حالة الجلسة الحالية.
|
||||
2. **restart** - إعادة تشغيل الجلسة - سيحاول هذا إعادة توصيل حساب واتساب الخاص بك.
|
||||
3. **start** - بدء الجلسة.
|
||||
@@ -107,42 +110,47 @@ APP_COMMANDS_LIST: |
|
||||
7. **screenshot** - الحصول على لقطة شاشة للجلسة (متاح فقط في محرك **WEBJS**).
|
||||
8. **help** - الأوامر المتاحة.
|
||||
|
||||
{{#commands.server}}
|
||||
⚙️ الخادم:
|
||||
- **server status** - الحصول على معلومات إصدار الخادم وحالته.
|
||||
- **server reboot** - إعادة تشغيل الخادم بسلاسة.
|
||||
- **server reboot force** - إعادة تشغيل الخادم بالقوة.
|
||||
{{/commands.server}}
|
||||
|
||||
أرسل **أمرًا** (غير حساس لحالة الأحرف) أو **رقم أمر** إلى هذه المحادثة.
|
||||
|
||||
APP_HELP_REMINDER: |
|
||||
app.commands.server.disabled: ⛔ **تم تعطيل أوامر الخادم**.
|
||||
|
||||
يرجى التواصل مع مسؤول النظام لديك.
|
||||
|
||||
أرسل **help** للحصول على قائمة الأوامر المتاحة.
|
||||
|
||||
APP_SESSION_STATUS_CHANGE: |
|
||||
app.help.reminder: |-
|
||||
أرسل **help** للحصول على قائمة الأوامر المتاحة.
|
||||
|
||||
app.session.status.change: |-
|
||||
{{{emoji}}} تم تغيير حالة جلسة "{{{session}}}" إلى {{{status}}}
|
||||
|
||||
APP_SESSION_CURRENT_STATUS: |
|
||||
app.session.current.status: |-
|
||||
{{{emoji}}} حالة جلسة **{{{session}}}** هي **{{{status}}}**
|
||||
**حساب واتساب:**
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_DASHBOARD_LINK: |
|
||||
قم بزيارة [لوحة تحكم WAHA]({{{url}}}) لمزيد من التفاصيل.
|
||||
|
||||
APP_SESSION_STATUS_WORKING: |
|
||||
app.session.status.working: |-
|
||||
✅ صندوق وارد ChatWoot هذا مرتبط بـ **حساب واتساب** وجاهز لإرسال واستقبال الرسائل!
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_SESSION_STATUS_ERROR: |
|
||||
app.session.status.error: |-
|
||||
⚠️ **صندوق وارد ChatWoot هذا مرتبط بحساب واتساب ولكنه غير جاهز لإرسال واستقبال الرسائل!**
|
||||
|
||||
يرجى التحقق من حالة الجلسة ومحاولة إعادة تشغيلها أو تسجيل الخروج ومسح رمز QR مرة أخرى.
|
||||
|
||||
APP_SESSION_SCAN_QR_CODE: |
|
||||
app.session.scan.qr.code: |-
|
||||
⚠️ **امسح رمز QR على هاتفك لربط حساب واتساب بصندوق وارد ChatWoot هذا!**
|
||||
|
||||
APP_SERVER_VERSION_AND_STATUS: |
|
||||
app.server.version.and.status: |-
|
||||
**الإصدار:**
|
||||
```
|
||||
{{{version}}}
|
||||
@@ -153,16 +161,16 @@ APP_SERVER_VERSION_AND_STATUS: |
|
||||
{{{status}}}
|
||||
```
|
||||
|
||||
APP_SERVER_REBOOT: |
|
||||
app.server.reboot: |-
|
||||
يتم إعادة تشغيل الخادم بسلاسة...
|
||||
|
||||
APP_SERVER_REBOOT_FORCE: |
|
||||
app.server.reboot.force: |-
|
||||
يتم إعادة تشغيل الخادم بالقوة...
|
||||
|
||||
APP_LOGOUT_SUCCESS: |
|
||||
app.logout.success: |-
|
||||
✅ تم إلغاء تفويض الحساب بنجاح!
|
||||
|
||||
APP_NEW_VERSION_AVAILABLE: |
|
||||
waha.new.version.available: |-
|
||||
🔄 **إصدار جديد متاح!**
|
||||
|
||||
الإصدار الحالي: **{{{currentVersion}}}**
|
||||
@@ -170,7 +178,7 @@ APP_NEW_VERSION_AVAILABLE: |
|
||||
|
||||
👉 تحقق مما هو جديد في [**🆕 سجل التغييرات**]({{{changelogUrl}}})
|
||||
|
||||
APP_CORE_VERSION_USED: |
|
||||
waha.core.version.used: |-
|
||||
❤️ **ادعم WAHA!**
|
||||
|
||||
أنت تستخدم إصدار **WAHA Core** المجاني. إذا وجدت هذا المشروع مفيدًا، فيرجى التفكير في دعم تطويره.
|
||||
@@ -178,3 +186,51 @@ APP_CORE_VERSION_USED: |
|
||||
دعمك هو الطريقة الوحيدة التي يمكننا من خلالها الاستمرار في العمل على التحديثات والإصلاحات والميزات الجديدة.
|
||||
|
||||
[**🎁 ادعمنا**]({{{supportUrl}}})
|
||||
|
||||
chatwoot.to.whatsapp.message.text: |-
|
||||
{{{ content }}}
|
||||
|
||||
chatwoot.to.whatsapp.message.media.caption: |-
|
||||
{{#singleAttachment}}
|
||||
{{#content}}
|
||||
{{{ content }}}
|
||||
{{/content}}
|
||||
{{/singleAttachment}}
|
||||
|
||||
whatsapp.to.chatwoot.message: |-
|
||||
{{{payload.body}}}
|
||||
|
||||
whatsapp.to.chatwoot.message.contacts: |-
|
||||
👤 **جهات الاتصال المشتركة**
|
||||
|
||||
{{#contacts}}
|
||||
🪪 الاسم: **{{fullName}}**
|
||||
{{#phoneNumbers}}
|
||||
- 📞 الهاتف: **{{.}}**
|
||||
{{/phoneNumbers}}
|
||||
|
||||
{{/contacts}}
|
||||
|
||||
whatsapp.to.chatwoot.message.location: |-
|
||||
{{#message}}
|
||||
{{#locationMessage}}
|
||||
📍 **الموقع المشترك**
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/locationMessage}}
|
||||
|
||||
{{#liveLocationMessage}}
|
||||
📍📡 **مشاركة الموقع المباشر**
|
||||
افتح **WhatsApp** لعرض التحديثات اللحظية.
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/liveLocationMessage}}
|
||||
{{/message}}
|
||||
|
||||
whatsapp.to.chatwoot.message.unsupported: |-
|
||||
⚠️ **هذا النوع من الرسائل غير مدعوم في ChatWoot.**
|
||||
📱 يرجى فتح **WhatsApp** لعرضه.
|
||||
|
||||
التفاصيل: [{{{details.text}}}]({{{details.url}}})
|
||||
@@ -1,7 +1,9 @@
|
||||
# Bengali translations for ChatWoot integration
|
||||
APP_INBOX_CONTACT_NAME: 'হোয়াটসঅ্যাপ ইন্টিগ্রেশন (WAHA)'
|
||||
locale.name: '🇧🇩 বাংলা (Bengali)'
|
||||
app.inbox.contact.name: 'হোয়াটসঅ্যাপ ইন্টিগ্রেশন (WAHA)'
|
||||
app.inbox.contact.avatar.url: 'https://raw.githubusercontent.com/devlikeapro/waha/core/logo.png'
|
||||
|
||||
JOB_ERROR_REPORT: |
|
||||
job.report.error: |-
|
||||
⚠️ **{{{header}}}**
|
||||
{{#attempts.nextDelay}}
|
||||
🔄 {{attempts.nextDelay}} সেকেন্ডের মধ্যে পুনরায় চেষ্টা করা হচ্ছে...
|
||||
@@ -18,51 +20,52 @@ JOB_ERROR_REPORT: |
|
||||
```
|
||||
{{/error}}
|
||||
|
||||
JOB_SUCCEEDED_REPORT: |
|
||||
job.report.succeeded: |-
|
||||
✅ **সফল হয়েছে**
|
||||
প্রচেষ্টা: {{{attempts.current}}} / {{{attempts.max}}}
|
||||
বিবরণ: [{{{details.text}}}]({{{details.url}}})
|
||||
|
||||
WHATSAPP_ERROR_SENDING_MESSAGE: হোয়াটসঅ্যাপে বার্তা পাঠাতে পারেনি।
|
||||
WHATSAPP_ERROR_RECEIVING_MESSAGE: হোয়াটসঅ্যাপ থেকে বার্তা পেতে পারেনি
|
||||
WHATSAPP_ERROR_REMOVING_MESSAGE: হোয়াটসঅ্যাপ থেকে বার্তা সরাতে পারেনি
|
||||
APP_SCHEDULED_JOB_ERROR: নির্ধারিত কাজ সম্পাদন করতে ব্যর্থ হয়েছে
|
||||
whatsapp.message.sending.error: হোয়াটসঅ্যাপে বার্তা পাঠাতে পারেনি।
|
||||
whatsapp.message.receiving.error: হোয়াটসঅ্যাপ থেকে বার্তা পেতে পারেনি
|
||||
whatsapp.message.removing.error: হোয়াটসঅ্যাপ থেকে বার্তা সরাতে পারেনি
|
||||
job.scheduled.error.header: নির্ধারিত কাজ সম্পাদন করতে ব্যর্থ হয়েছে
|
||||
|
||||
MESSAGE_FROM_WHATSAPP: |
|
||||
message.from.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *হোয়াটসঅ্যাপ থেকে পাঠানো হয়েছে*
|
||||
|
||||
MESSAGE_FROM_API: |
|
||||
message.from.api: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *API এর মাধ্যমে পাঠানো হয়েছে*
|
||||
|
||||
MESSAGE_REMOVED_IN_WHATSAPP: |
|
||||
message.removed.in.whatsapp: |-
|
||||
❌ *এই বার্তাটি হোয়াটসঅ্যাপে মুছে ফেলা হয়েছে*
|
||||
|
||||
MESSAGE_EDITED_IN_WHATSAPP: |
|
||||
message.edited.in.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
✏️ *হোয়াটসঅ্যাপে সম্পাদিত*
|
||||
|
||||
WHATSAPP_GROUP_MESSAGE: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.group.message: |-
|
||||
👥 *{{{participant}}}*
|
||||
|
||||
WHATSAPP_REACTION_ADDED: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.reaction.added: |-
|
||||
*প্রতিক্রিয়া দিয়েছেন* {{{emoji}}}
|
||||
|
||||
WHATSAPP_REACTION_REMOVED: |
|
||||
whatsapp.reaction.removed: |-
|
||||
*প্রতিক্রিয়া সরানো হয়েছে*
|
||||
|
||||
WHATSAPP_CONTACT_GROUP_SUFFIX: 'গ্রুপ'
|
||||
WHATSAPP_CONTACT_CHANNEL_SUFFIX: 'চ্যানেল'
|
||||
whatsapp.contact.group.suffix: 'গ্রুপ'
|
||||
whatsapp.contact.channel.suffix: 'চ্যানেল'
|
||||
whatsapp.contact.broadcast.suffix: 'প্রচার তালিকা'
|
||||
# Aka Stories
|
||||
WHATSAPP_CONTACT_STATUS_NAME: 'স্ট্যাটাস'
|
||||
whatsapp.contact.status.name: 'স্ট্যাটাস'
|
||||
|
||||
APP_CONNECTED_MESSAGE: |
|
||||
app.connected.message: |-
|
||||
🔗 **সংযুক্ত: হোয়াটসঅ্যাপ সেশন থেকে ChatWoot ইনবক্স**
|
||||
|
||||
✅ হোয়াটসঅ্যাপ সেশন **{{{name}}}** সফলভাবে এই ChatWoot ইনবক্সের সাথে সংযুক্ত করা হয়েছে।
|
||||
@@ -80,7 +83,7 @@ APP_CONNECTED_MESSAGE: |
|
||||
|
||||
চলুন শুরু করা যাক! 🚀
|
||||
|
||||
APP_DISCONNECTED_MESSAGE: |
|
||||
app.disconnected.message: |-
|
||||
🔌 **সংযোগ বিচ্ছিন্ন: হোয়াটসঅ্যাপ সেশন থেকে ChatWoot ইনবক্স**
|
||||
|
||||
❌ হোয়াটসঅ্যাপ সেশন **{{{name}}}** এই ChatWoot ইনবক্স থেকে সংযোগ বিচ্ছিন্ন করা হয়েছে।
|
||||
@@ -89,15 +92,15 @@ APP_DISCONNECTED_MESSAGE: |
|
||||
|
||||
পুনরায় সংযোগ করতে, অনুগ্রহ করে আপনার প্রশাসকের সাথে যোগাযোগ করুন।
|
||||
|
||||
APP_UPDATED_MESSAGE: |
|
||||
app.updated.message: |-
|
||||
🔄 **আপডেট করা হয়েছে: হোয়াটসঅ্যাপ সেশন সেটিংস**
|
||||
|
||||
✅ হোয়াটসঅ্যাপ সেশন **{{{name}}}** এর সেটিংস আপডেট করা হয়েছে।
|
||||
|
||||
APP_COMMANDS_LIST: |
|
||||
app.commands.list: |-
|
||||
আপনি নিম্নলিখিত কমান্ডগুলির একটি পাঠিয়ে **হোয়াটসঅ্যাপ ইন্টিগ্রেশন** পরিচালনা করতে পারেন:
|
||||
|
||||
🖥️ সেশন:
|
||||
🖥️ **সেশন**:
|
||||
1. **status** - বর্তমান সেশনের স্ট্যাটাস পান।
|
||||
2. **restart** - সেশন পুনরায় চালু করুন - এটি আপনার হোয়াটসঅ্যাপ অ্যাকাউন্ট পুনরায় সংযোগ করার চেষ্টা করবে।
|
||||
3. **start** - সেশন শুরু করুন।
|
||||
@@ -107,42 +110,47 @@ APP_COMMANDS_LIST: |
|
||||
7. **screenshot** - সেশনের স্ক্রিনশট পান (শুধুমাত্র **WEBJS** ইঞ্জিনে উপলব্ধ)।
|
||||
8. **help** - উপলব্ধ কমান্ডগুলি।
|
||||
|
||||
{{#commands.server}}
|
||||
⚙️ সার্ভার:
|
||||
- **server status** - সার্ভারের সংস্করণ এবং স্ট্যাটাস তথ্য পান।
|
||||
- **server reboot** - সার্ভার সুন্দরভাবে পুনরায় চালু করুন।
|
||||
- **server reboot force** - সার্ভার জোর করে পুনরায় চালু করুন।
|
||||
{{/commands.server}}
|
||||
|
||||
এই কথোপকথনে একটি **কমান্ড** (কেস সংবেদনশীল নয়) বা **কমান্ড নম্বর** পাঠান।
|
||||
|
||||
APP_HELP_REMINDER: |
|
||||
app.commands.server.disabled: ⛔ **সার্ভার কমান্ড নিষ্ক্রিয় করা হয়েছে**।
|
||||
|
||||
দয়া করে আপনার প্রশাসকের সাথে যোগাযোগ করুন।
|
||||
|
||||
উপলব্ধ কমান্ডের তালিকা পেতে **help** পাঠান।
|
||||
|
||||
app.help.reminder: |-
|
||||
উপলব্ধ কমান্ডগুলির তালিকা পেতে **help** পাঠান।
|
||||
|
||||
APP_SESSION_STATUS_CHANGE: |
|
||||
app.session.status.change: |-
|
||||
{{{emoji}}} "{{{session}}}" সেশন {{{status}}} স্ট্যাটাসে পরিবর্তিত হয়েছে
|
||||
|
||||
APP_SESSION_CURRENT_STATUS: |
|
||||
app.session.current.status: |-
|
||||
{{{emoji}}} **{{{session}}}** সেশনের স্ট্যাটাস **{{{status}}}**
|
||||
**হোয়াটসঅ্যাপ অ্যাকাউন্ট:**
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_DASHBOARD_LINK: |
|
||||
আরও বিবরণের জন্য [WAHA ড্যাশবোর্ড]({{{url}}}) দেখুন।
|
||||
|
||||
APP_SESSION_STATUS_WORKING: |
|
||||
app.session.status.working: |-
|
||||
✅ এই ChatWoot ইনবক্স **হোয়াটসঅ্যাপ অ্যাকাউন্টের** সাথে সংযুক্ত এবং বার্তা পাঠাতে ও গ্রহণ করতে প্রস্তুত!
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_SESSION_STATUS_ERROR: |
|
||||
app.session.status.error: |-
|
||||
⚠️ **এই ChatWoot ইনবক্স হোয়াটসঅ্যাপ অ্যাকাউন্টের সাথে সংযুক্ত কিন্তু বার্তা পাঠাতে ও গ্রহণ করতে প্রস্তুত নয়!**
|
||||
|
||||
অনুগ্রহ করে সেশনের স্ট্যাটাস পরীক্ষা করুন এবং এটি পুনরায় চালু করার চেষ্টা করুন অথবা লগআউট করুন এবং QR কোড আবার স্ক্যান করুন।
|
||||
|
||||
APP_SESSION_SCAN_QR_CODE: |
|
||||
app.session.scan.qr.code: |-
|
||||
⚠️ **এই ChatWoot ইনবক্সের সাথে হোয়াটসঅ্যাপ অ্যাকাউন্ট লিঙ্ক করতে আপনার ফোনে QR কোড স্ক্যান করুন!**
|
||||
|
||||
APP_SERVER_VERSION_AND_STATUS: |
|
||||
app.server.version.and.status: |-
|
||||
**সংস্করণ:**
|
||||
```
|
||||
{{{version}}}
|
||||
@@ -153,16 +161,16 @@ APP_SERVER_VERSION_AND_STATUS: |
|
||||
{{{status}}}
|
||||
```
|
||||
|
||||
APP_SERVER_REBOOT: |
|
||||
app.server.reboot: |-
|
||||
সার্ভার সুন্দরভাবে পুনরায় চালু হচ্ছে...
|
||||
|
||||
APP_SERVER_REBOOT_FORCE: |
|
||||
app.server.reboot.force: |-
|
||||
সার্ভার জোর করে পুনরায় চালু হচ্ছে...
|
||||
|
||||
APP_LOGOUT_SUCCESS: |
|
||||
app.logout.success: |-
|
||||
✅ অ্যাকাউন্ট সফলভাবে অননুমোদিত করা হয়েছে!
|
||||
|
||||
APP_NEW_VERSION_AVAILABLE: |
|
||||
waha.new.version.available: |-
|
||||
🔄 **নতুন সংস্করণ উপলব্ধ!**
|
||||
|
||||
বর্তমান সংস্করণ: **{{{currentVersion}}}**
|
||||
@@ -170,7 +178,7 @@ APP_NEW_VERSION_AVAILABLE: |
|
||||
|
||||
👉 [**🆕 পরিবর্তন লগ**]({{{changelogUrl}}}) এ নতুন কি আছে তা দেখুন
|
||||
|
||||
APP_CORE_VERSION_USED: |
|
||||
waha.core.version.used: |-
|
||||
❤️ **WAHA সমর্থন করুন!**
|
||||
|
||||
আপনি বিনামূল্যের **WAHA Core** সংস্করণ ব্যবহার করছেন। যদি আপনি এই প্রকল্পটি উপযোগী মনে করেন, তবে এর বিকাশকে সমর্থন করার কথা বিবেচনা করুন।
|
||||
@@ -178,3 +186,51 @@ APP_CORE_VERSION_USED: |
|
||||
আপনার সমর্থন হল একমাত্র উপায় যা দিয়ে আমরা আপডেট, ফিক্স এবং নতুন বৈশিষ্ট্যগুলিতে কাজ চালিয়ে যেতে পারি।
|
||||
|
||||
[**🎁 আমাদের সমর্থন করুন**]({{{supportUrl}}})
|
||||
|
||||
chatwoot.to.whatsapp.message.text: |-
|
||||
{{{ content }}}
|
||||
|
||||
chatwoot.to.whatsapp.message.media.caption: |-
|
||||
{{#singleAttachment}}
|
||||
{{#content}}
|
||||
{{{ content }}}
|
||||
{{/content}}
|
||||
{{/singleAttachment}}
|
||||
|
||||
whatsapp.to.chatwoot.message: |-
|
||||
{{{payload.body}}}
|
||||
|
||||
whatsapp.to.chatwoot.message.contacts: |-
|
||||
👤 **শেয়ার করা যোগাযোগ**
|
||||
|
||||
{{#contacts}}
|
||||
🪪 নাম: **{{fullName}}**
|
||||
{{#phoneNumbers}}
|
||||
- 📞 ফোন: **{{.}}**
|
||||
{{/phoneNumbers}}
|
||||
|
||||
{{/contacts}}
|
||||
|
||||
whatsapp.to.chatwoot.message.location: |-
|
||||
{{#message}}
|
||||
{{#locationMessage}}
|
||||
📍 **শেয়ার করা লোকেশন**
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/locationMessage}}
|
||||
|
||||
{{#liveLocationMessage}}
|
||||
📍📡 **লাইভ লোকেশন শেয়ার করা হচ্ছে**
|
||||
রিয়েল-টাইম আপডেট দেখতে **WhatsApp** খুলুন।
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/liveLocationMessage}}
|
||||
{{/message}}
|
||||
|
||||
whatsapp.to.chatwoot.message.unsupported: |-
|
||||
⚠️ **এই ধরনের বার্তা ChatWoot-এ সমর্থিত নয়।**
|
||||
📱 এটি দেখতে অনুগ্রহ করে **WhatsApp** খুলুন।
|
||||
|
||||
বিস্তারিত: [{{{details.text}}}]({{{details.url}}})
|
||||
@@ -1,7 +1,9 @@
|
||||
# German translations for ChatWoot integration
|
||||
APP_INBOX_CONTACT_NAME: 'WhatsApp Integration (WAHA)'
|
||||
locale.name: '🇩🇪 Deutsch (German)'
|
||||
app.inbox.contact.name: 'WhatsApp Integration (WAHA)'
|
||||
app.inbox.contact.avatar.url: 'https://raw.githubusercontent.com/devlikeapro/waha/core/logo.png'
|
||||
|
||||
JOB_ERROR_REPORT: |
|
||||
job.report.error: |-
|
||||
⚠️ **{{{header}}}**
|
||||
{{#attempts.nextDelay}}
|
||||
🔄 Wiederholung in {{attempts.nextDelay}} Sekunden...
|
||||
@@ -18,54 +20,55 @@ JOB_ERROR_REPORT: |
|
||||
```
|
||||
{{/error}}
|
||||
|
||||
JOB_SUCCEEDED_REPORT: |
|
||||
job.report.succeeded: |-
|
||||
✅ **Erfolgreich**
|
||||
Versuch: {{{attempts.current}}} / {{{attempts.max}}}
|
||||
Details: [{{{details.text}}}]({{{details.url}}})
|
||||
|
||||
WHATSAPP_ERROR_SENDING_MESSAGE:
|
||||
whatsapp.message.sending.error:
|
||||
Nachricht konnte nicht über WhatsApp gesendet werden.
|
||||
WHATSAPP_ERROR_RECEIVING_MESSAGE:
|
||||
whatsapp.message.receiving.error:
|
||||
Nachricht konnte nicht von WhatsApp empfangen werden
|
||||
WHATSAPP_ERROR_REMOVING_MESSAGE:
|
||||
whatsapp.message.removing.error:
|
||||
Nachricht konnte nicht von WhatsApp entfernt werden
|
||||
APP_SCHEDULED_JOB_ERROR: Geplante Aufgabe konnte nicht ausgeführt werden
|
||||
job.scheduled.error.header: Geplante Aufgabe konnte nicht ausgeführt werden
|
||||
|
||||
MESSAGE_FROM_WHATSAPP: |
|
||||
message.from.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *Von WhatsApp gesendet*
|
||||
|
||||
MESSAGE_FROM_API: |
|
||||
message.from.api: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *Über API gesendet*
|
||||
|
||||
MESSAGE_REMOVED_IN_WHATSAPP: |
|
||||
message.removed.in.whatsapp: |-
|
||||
❌ *Diese Nachricht wurde in WhatsApp gelöscht*
|
||||
|
||||
MESSAGE_EDITED_IN_WHATSAPP: |
|
||||
message.edited.in.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
✏️ *In WhatsApp bearbeitet*
|
||||
|
||||
WHATSAPP_GROUP_MESSAGE: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.group.message: |-
|
||||
👥 *{{{participant}}}*
|
||||
|
||||
WHATSAPP_REACTION_ADDED: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.reaction.added: |-
|
||||
*Reagiert mit* {{{emoji}}}
|
||||
|
||||
WHATSAPP_REACTION_REMOVED: |
|
||||
whatsapp.reaction.removed: |-
|
||||
*Reaktion entfernt*
|
||||
|
||||
WHATSAPP_CONTACT_GROUP_SUFFIX: 'Gruppe'
|
||||
WHATSAPP_CONTACT_CHANNEL_SUFFIX: 'Kanal'
|
||||
whatsapp.contact.group.suffix: 'Gruppe'
|
||||
whatsapp.contact.channel.suffix: 'Kanal'
|
||||
whatsapp.contact.broadcast.suffix: 'Broadcast-Liste'
|
||||
# Aka Stories
|
||||
WHATSAPP_CONTACT_STATUS_NAME: 'Status'
|
||||
whatsapp.contact.status.name: 'Status'
|
||||
|
||||
APP_CONNECTED_MESSAGE: |
|
||||
app.connected.message: |-
|
||||
🔗 **VERBUNDEN: WhatsApp-Sitzung mit ChatWoot Inbox**
|
||||
|
||||
✅ WhatsApp-Sitzung **{{{name}}}** wurde erfolgreich mit dieser ChatWoot Inbox verbunden.
|
||||
@@ -83,7 +86,7 @@ APP_CONNECTED_MESSAGE: |
|
||||
|
||||
Lassen Sie uns beginnen! 🚀
|
||||
|
||||
APP_DISCONNECTED_MESSAGE: |
|
||||
app.disconnected.message: |-
|
||||
🔌 **GETRENNT: WhatsApp-Sitzung von ChatWoot Inbox**
|
||||
|
||||
❌ WhatsApp-Sitzung **{{{name}}}** wurde von dieser ChatWoot Inbox getrennt.
|
||||
@@ -92,15 +95,15 @@ APP_DISCONNECTED_MESSAGE: |
|
||||
|
||||
Um eine erneute Verbindung herzustellen, wenden Sie sich bitte an Ihren Administrator.
|
||||
|
||||
APP_UPDATED_MESSAGE: |
|
||||
app.updated.message: |-
|
||||
🔄 **AKTUALISIERT: WhatsApp-Sitzungseinstellungen**
|
||||
|
||||
✅ Einstellungen für WhatsApp-Sitzung **{{{name}}}** wurden aktualisiert.
|
||||
|
||||
APP_COMMANDS_LIST: |
|
||||
app.commands.list: |-
|
||||
Sie können die **WhatsApp Integration** verwalten, indem Sie einen der folgenden Befehle senden:
|
||||
|
||||
🖥️ Sitzungen:
|
||||
🖥️ **Sitzung**:
|
||||
1. **status** - den aktuellen Sitzungsstatus abrufen.
|
||||
2. **restart** - die Sitzung neu starten - dies versucht, Ihr WhatsApp-Konto neu zu verbinden.
|
||||
3. **start** - die Sitzung starten.
|
||||
@@ -110,42 +113,47 @@ APP_COMMANDS_LIST: |
|
||||
7. **screenshot** - einen Screenshot der Sitzung erhalten (nur in der **WEBJS**-Engine verfügbar).
|
||||
8. **help** - verfügbare Befehle.
|
||||
|
||||
{{#commands.server}}
|
||||
⚙️ Server:
|
||||
- **server status** - Serverversion und Statusinformationen abrufen.
|
||||
- **server reboot** - Server ordnungsgemäß neu starten.
|
||||
- **server reboot force** - Server erzwungen neu starten.
|
||||
{{/commands.server}}
|
||||
|
||||
Senden Sie einen **Befehl** (Groß-/Kleinschreibung wird nicht beachtet) oder eine **Befehlsnummer** an diese Konversation.
|
||||
|
||||
APP_HELP_REMINDER: |
|
||||
app.commands.server.disabled: ⛔ **Serverbefehle sind deaktiviert**.
|
||||
|
||||
Bitte wenden Sie sich an Ihren Administrator.
|
||||
|
||||
Senden Sie **help**, um die Liste der verfügbaren Befehle zu erhalten.
|
||||
|
||||
APP_SESSION_STATUS_CHANGE: |
|
||||
app.help.reminder: |-
|
||||
Senden Sie **help**, um die Liste der verfügbaren Befehle zu erhalten.
|
||||
|
||||
app.session.status.change: |-
|
||||
{{{emoji}}} Sitzung "{{{session}}}" hat den Status zu {{{status}}} gewechselt
|
||||
|
||||
APP_SESSION_CURRENT_STATUS: |
|
||||
app.session.current.status: |-
|
||||
{{{emoji}}} **{{{session}}}** Sitzungsstatus ist **{{{status}}}**
|
||||
**WhatsApp-Konto:**
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_DASHBOARD_LINK: |
|
||||
Besuchen Sie das [WAHA Dashboard]({{{url}}}) für weitere Details.
|
||||
|
||||
APP_SESSION_STATUS_WORKING: |
|
||||
app.session.status.working: |-
|
||||
✅ Diese ChatWoot Inbox ist mit dem **WhatsApp-Konto** verknüpft und bereit zum Senden und Empfangen von Nachrichten!
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_SESSION_STATUS_ERROR: |
|
||||
app.session.status.error: |-
|
||||
⚠️ **Diese ChatWoot Inbox ist mit dem WhatsApp-Konto verknüpft, aber NICHT bereit zum Senden und Empfangen von Nachrichten!**
|
||||
|
||||
Bitte überprüfen Sie den Sitzungsstatus und versuchen Sie, sie neu zu starten oder melden Sie sich ab und scannen Sie den QR-Code erneut.
|
||||
|
||||
APP_SESSION_SCAN_QR_CODE: |
|
||||
app.session.scan.qr.code: |-
|
||||
⚠️ **Scannen Sie den QR-Code auf Ihrem Telefon, um das WhatsApp-Konto mit dieser ChatWoot Inbox zu verknüpfen!**
|
||||
|
||||
APP_SERVER_VERSION_AND_STATUS: |
|
||||
app.server.version.and.status: |-
|
||||
**Version:**
|
||||
```
|
||||
{{{version}}}
|
||||
@@ -156,16 +164,16 @@ APP_SERVER_VERSION_AND_STATUS: |
|
||||
{{{status}}}
|
||||
```
|
||||
|
||||
APP_SERVER_REBOOT: |
|
||||
app.server.reboot: |-
|
||||
Server wird ordnungsgemäß neu gestartet...
|
||||
|
||||
APP_SERVER_REBOOT_FORCE: |
|
||||
app.server.reboot.force: |-
|
||||
Server wird erzwungen neu gestartet...
|
||||
|
||||
APP_LOGOUT_SUCCESS: |
|
||||
app.logout.success: |-
|
||||
✅ Konto erfolgreich abgemeldet!
|
||||
|
||||
APP_NEW_VERSION_AVAILABLE: |
|
||||
waha.new.version.available: |-
|
||||
🔄 **Neue Version verfügbar!**
|
||||
|
||||
Aktuelle Version: **{{{currentVersion}}}**
|
||||
@@ -173,7 +181,7 @@ APP_NEW_VERSION_AVAILABLE: |
|
||||
|
||||
👉 Sehen Sie, was neu ist im [**🆕 Änderungsprotokoll**]({{{changelogUrl}}})
|
||||
|
||||
APP_CORE_VERSION_USED: |
|
||||
waha.core.version.used: |-
|
||||
❤️ **Unterstützen Sie WAHA!**
|
||||
|
||||
Sie verwenden die kostenlose **WAHA Core** Version. Wenn Sie dieses Projekt nützlich finden, erwägen Sie bitte, seine Entwicklung zu unterstützen.
|
||||
@@ -181,3 +189,51 @@ APP_CORE_VERSION_USED: |
|
||||
Ihre Unterstützung ist der einzige Weg, wie wir weiterhin an Updates, Fehlerbehebungen und neuen Funktionen arbeiten können.
|
||||
|
||||
[**🎁 Unterstützen Sie uns**]({{{supportUrl}}})
|
||||
|
||||
chatwoot.to.whatsapp.message.text: |-
|
||||
{{{ content }}}
|
||||
|
||||
chatwoot.to.whatsapp.message.media.caption: |-
|
||||
{{#singleAttachment}}
|
||||
{{#content}}
|
||||
{{{ content }}}
|
||||
{{/content}}
|
||||
{{/singleAttachment}}
|
||||
|
||||
whatsapp.to.chatwoot.message: |-
|
||||
{{{payload.body}}}
|
||||
|
||||
whatsapp.to.chatwoot.message.contacts: |-
|
||||
👤 **Geteilte Kontakte**
|
||||
|
||||
{{#contacts}}
|
||||
🪪 Name: **{{fullName}}**
|
||||
{{#phoneNumbers}}
|
||||
- 📞 Telefon: **{{.}}**
|
||||
{{/phoneNumbers}}
|
||||
|
||||
{{/contacts}}
|
||||
|
||||
whatsapp.to.chatwoot.message.location: |-
|
||||
{{#message}}
|
||||
{{#locationMessage}}
|
||||
📍 **Geteilter Standort**
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/locationMessage}}
|
||||
|
||||
{{#liveLocationMessage}}
|
||||
📍📡 **Live-Standort wird geteilt**
|
||||
Öffne **WhatsApp**, um Aktualisierungen in Echtzeit zu sehen.
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/liveLocationMessage}}
|
||||
{{/message}}
|
||||
|
||||
whatsapp.to.chatwoot.message.unsupported: |-
|
||||
⚠️ **Dieser Nachrichtentyp wird in ChatWoot nicht unterstützt.**
|
||||
📱 Bitte öffne **WhatsApp**, um ihn anzusehen.
|
||||
|
||||
Details: [{{{details.text}}}]({{{details.url}}})
|
||||
@@ -1,8 +1,10 @@
|
||||
# English translations for ChatWoot integration
|
||||
APP_INBOX_CONTACT_NAME: 'WhatsApp Integration (WAHA)'
|
||||
APP_INBOX_CONTACT_AVATAR_URL: 'https://raw.githubusercontent.com/devlikeapro/waha/core/logo.png'
|
||||
locale.name: '🇺🇸 English (English)'
|
||||
|
||||
JOB_ERROR_REPORT: |
|
||||
app.inbox.contact.name: 'WhatsApp Integration (WAHA)'
|
||||
app.inbox.contact.avatar.url: 'https://raw.githubusercontent.com/devlikeapro/waha/core/logo.png'
|
||||
|
||||
job.report.error: |-
|
||||
⚠️ **{{{header}}}**
|
||||
{{#attempts.nextDelay}}
|
||||
🔄 Retrying in {{attempts.nextDelay}} seconds...
|
||||
@@ -19,51 +21,100 @@ JOB_ERROR_REPORT: |
|
||||
```
|
||||
{{/error}}
|
||||
|
||||
JOB_SUCCEEDED_REPORT: |
|
||||
job.report.succeeded: |-
|
||||
✅ **Succeeded**
|
||||
Attempt: {{{attempts.current}}} / {{{attempts.max}}}
|
||||
Details: [{{{details.text}}}]({{{details.url}}})
|
||||
|
||||
WHATSAPP_ERROR_SENDING_MESSAGE: Couldn't send a message on WhatsApp.
|
||||
WHATSAPP_ERROR_RECEIVING_MESSAGE: Couldn't receive a message from WhatsApp
|
||||
WHATSAPP_ERROR_REMOVING_MESSAGE: Couldn't remove a message from WhatsApp
|
||||
APP_SCHEDULED_JOB_ERROR: Scheduled job failed to execute
|
||||
whatsapp.message.sending.error: Couldn't send a message on WhatsApp.
|
||||
whatsapp.message.receiving.error: Couldn't receive a message from WhatsApp
|
||||
whatsapp.message.removing.error: Couldn't remove a message from WhatsApp
|
||||
job.scheduled.error.header: Scheduled job failed to execute
|
||||
|
||||
MESSAGE_FROM_WHATSAPP: |
|
||||
message.from.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *Sent from WhatsApp*
|
||||
|
||||
MESSAGE_FROM_API: |
|
||||
message.from.api: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *Sent via API*
|
||||
|
||||
MESSAGE_REMOVED_IN_WHATSAPP: |
|
||||
message.removed.in.whatsapp: |-
|
||||
❌ *This message was deleted in WhatsApp*
|
||||
|
||||
MESSAGE_EDITED_IN_WHATSAPP: |
|
||||
message.edited.in.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
✏️ *Edited in WhatsApp*
|
||||
|
||||
WHATSAPP_GROUP_MESSAGE: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.group.message: |-
|
||||
👥 *{{{participant}}}*
|
||||
|
||||
WHATSAPP_REACTION_ADDED: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.reaction.added: |-
|
||||
*Reacted* {{{emoji}}}
|
||||
|
||||
WHATSAPP_REACTION_REMOVED: |
|
||||
whatsapp.reaction.removed: |-
|
||||
*Reaction removed*
|
||||
|
||||
WHATSAPP_CONTACT_GROUP_SUFFIX: 'Group'
|
||||
WHATSAPP_CONTACT_CHANNEL_SUFFIX: 'Channel'
|
||||
whatsapp.contact.group.suffix: 'Group'
|
||||
whatsapp.contact.channel.suffix: 'Channel'
|
||||
whatsapp.contact.broadcast.suffix: 'Broadcast List'
|
||||
# Aka Stories
|
||||
WHATSAPP_CONTACT_STATUS_NAME: 'Status'
|
||||
whatsapp.contact.status.name: 'Status'
|
||||
|
||||
APP_CONNECTED_MESSAGE: |
|
||||
chatwoot.to.whatsapp.message.text: |-
|
||||
{{{ content }}}
|
||||
|
||||
chatwoot.to.whatsapp.message.media.caption: |-
|
||||
{{#singleAttachment}}
|
||||
{{#content}}
|
||||
{{{ content }}}
|
||||
{{/content}}
|
||||
{{/singleAttachment}}
|
||||
|
||||
whatsapp.to.chatwoot.message: |-
|
||||
{{{payload.body}}}
|
||||
|
||||
whatsapp.to.chatwoot.message.contacts: |-
|
||||
👤 **Shared Contact(s)**
|
||||
|
||||
{{#contacts}}
|
||||
🪪 Name: **{{fullName}}**
|
||||
{{#phoneNumbers}}
|
||||
- 📞 Phone: **{{.}}**
|
||||
{{/phoneNumbers}}
|
||||
|
||||
{{/contacts}}
|
||||
|
||||
whatsapp.to.chatwoot.message.location: |-
|
||||
{{#message}}
|
||||
{{#locationMessage}}
|
||||
📍 **Shared Location**
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/locationMessage}}
|
||||
|
||||
{{#liveLocationMessage}}
|
||||
📍📡 **Sharing Live Location**
|
||||
Open **WhatsApp** to see real-time updates.
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/liveLocationMessage}}
|
||||
{{/message}}
|
||||
|
||||
whatsapp.to.chatwoot.message.unsupported: |-
|
||||
⚠️ **This message type is not supported in ChatWoot.**
|
||||
📱 Please open **WhatsApp** to view it.
|
||||
|
||||
Details: [{{{details.text}}}]({{{details.url}}})
|
||||
|
||||
app.connected.message: |-
|
||||
🔗 **CONNECTED: WhatsApp Session to ChatWoot Inbox**
|
||||
|
||||
✅ WhatsApp session **{{{name}}}** has been successfully connected to this ChatWoot Inbox.
|
||||
@@ -81,7 +132,7 @@ APP_CONNECTED_MESSAGE: |
|
||||
|
||||
Let's get started! 🚀
|
||||
|
||||
APP_DISCONNECTED_MESSAGE: |
|
||||
app.disconnected.message: |-
|
||||
🔌 **DISCONNECTED: WhatsApp Session from ChatWoot Inbox**
|
||||
|
||||
❌ WhatsApp session **{{{name}}}** has been disconnected from this ChatWoot Inbox.
|
||||
@@ -90,15 +141,15 @@ APP_DISCONNECTED_MESSAGE: |
|
||||
|
||||
To reconnect, please contact your administrator.
|
||||
|
||||
APP_UPDATED_MESSAGE: |
|
||||
app.updated.message: |-
|
||||
🔄 **UPDATED: WhatsApp Session Settings**
|
||||
|
||||
✅ Settings for WhatsApp session **{{{name}}}** have been updated.
|
||||
|
||||
APP_COMMANDS_LIST: |
|
||||
app.commands.list: |-
|
||||
You can manage **WhatsApp Integration** by sending one of the following commands:
|
||||
|
||||
🖥️ Sessions:
|
||||
🖥️ **Session**:
|
||||
1. **status** - get the current session status.
|
||||
2. **restart** - restart the session - this will try to reconnect your WhatsApp account.
|
||||
3. **start** - start the session.
|
||||
@@ -108,42 +159,47 @@ APP_COMMANDS_LIST: |
|
||||
7. **screenshot** - get a screenshot of the session (only available in **WEBJS** engine).
|
||||
8. **help** - available commands.
|
||||
|
||||
⚙️ Server:
|
||||
{{#commands.server}}
|
||||
🛠️ **Server**:
|
||||
- **server status** - get the server version and status information.
|
||||
- **server reboot** - reboot the server gracefully.
|
||||
- **server reboot force** - force reboot the server.
|
||||
|
||||
{{/commands.server}}
|
||||
Send a **command** (case insensitive) or a **command number** to this conversation.
|
||||
|
||||
APP_HELP_REMINDER: |
|
||||
app.commands.server.disabled: ⛔ **Server commands are disabled**.
|
||||
|
||||
Please contact your administrator.
|
||||
|
||||
Send **help** to get the list of available commands.
|
||||
|
||||
APP_SESSION_STATUS_CHANGE: |
|
||||
app.help.reminder: |-
|
||||
Send **help** to get the list of available commands.
|
||||
|
||||
app.session.status.change: |-
|
||||
{{{emoji}}} "{{{session}}}" session switched to {{{status}}} status
|
||||
|
||||
APP_SESSION_CURRENT_STATUS: |
|
||||
app.session.current.status: |-
|
||||
{{{emoji}}} **{{{session}}}** session status is in **{{{status}}}**
|
||||
**WhatsApp Account:**
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_DASHBOARD_LINK: |
|
||||
Visit [WAHA Dashboard]({{{url}}}) for more details.
|
||||
|
||||
APP_SESSION_STATUS_WORKING: |
|
||||
app.session.status.working: |-
|
||||
✅ This ChatWoot Inbox is linked to **WhatsApp Account** and ready to send and receive messages!
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_SESSION_STATUS_ERROR: |
|
||||
app.session.status.error: |-
|
||||
⚠️ **This ChatWoot Inbox is linked to WhatsApp Account but NOT ready to send and receive messages!**
|
||||
|
||||
Please check the session status and try restarting it or logout and scan the QR code again.
|
||||
|
||||
APP_SESSION_SCAN_QR_CODE: |
|
||||
app.session.scan.qr.code: |-
|
||||
⚠️ **Scan the QR code on your phone to link WhatsApp Account with this ChatWoot Inbox!**
|
||||
|
||||
APP_SERVER_VERSION_AND_STATUS: |
|
||||
app.server.version.and.status: |-
|
||||
**Version:**
|
||||
```
|
||||
{{{version}}}
|
||||
@@ -154,16 +210,16 @@ APP_SERVER_VERSION_AND_STATUS: |
|
||||
{{{status}}}
|
||||
```
|
||||
|
||||
APP_SERVER_REBOOT: |
|
||||
app.server.reboot: |-
|
||||
Server is rebooting gracefully...
|
||||
|
||||
APP_SERVER_REBOOT_FORCE: |
|
||||
app.server.reboot.force: |-
|
||||
Server is force rebooting...
|
||||
|
||||
APP_LOGOUT_SUCCESS: |
|
||||
app.logout.success: |-
|
||||
✅ Account unauthorized successfully!
|
||||
|
||||
APP_NEW_VERSION_AVAILABLE: |
|
||||
waha.new.version.available: |-
|
||||
🔄 **New Version Available!**
|
||||
|
||||
Current version: **{{{currentVersion}}}**
|
||||
@@ -171,7 +227,7 @@ APP_NEW_VERSION_AVAILABLE: |
|
||||
|
||||
👉 Check out what's new in the [**🆕 Changelog**]({{{changelogUrl}}})
|
||||
|
||||
APP_CORE_VERSION_USED: |
|
||||
waha.core.version.used: |-
|
||||
❤️ **Support WAHA!**
|
||||
|
||||
You're using the free **WAHA Core** version. If you find this project useful, please consider supporting its development.
|
||||
@@ -1,7 +1,9 @@
|
||||
# Spanish translations for ChatWoot integration
|
||||
APP_INBOX_CONTACT_NAME: 'Integración de WhatsApp (WAHA)'
|
||||
locale.name: '🇪🇸 Español (Spanish)'
|
||||
app.inbox.contact.name: 'Integración de WhatsApp (WAHA)'
|
||||
app.inbox.contact.avatar.url: 'https://raw.githubusercontent.com/devlikeapro/waha/core/logo.png'
|
||||
|
||||
JOB_ERROR_REPORT: |
|
||||
job.report.error: |-
|
||||
⚠️ **{{{header}}}**
|
||||
{{#attempts.nextDelay}}
|
||||
🔄 Reintentando en {{attempts.nextDelay}} segundos...
|
||||
@@ -18,51 +20,52 @@ JOB_ERROR_REPORT: |
|
||||
```
|
||||
{{/error}}
|
||||
|
||||
JOB_SUCCEEDED_REPORT: |
|
||||
job.report.succeeded: |-
|
||||
✅ **Éxito**
|
||||
Intento: {{{attempts.current}}} / {{{attempts.max}}}
|
||||
Detalles: [{{{details.text}}}]({{{details.url}}})
|
||||
|
||||
WHATSAPP_ERROR_SENDING_MESSAGE: No se pudo enviar un mensaje en WhatsApp.
|
||||
WHATSAPP_ERROR_RECEIVING_MESSAGE: No se pudo recibir un mensaje de WhatsApp
|
||||
WHATSAPP_ERROR_REMOVING_MESSAGE: No se pudo eliminar un mensaje de WhatsApp
|
||||
APP_SCHEDULED_JOB_ERROR: La tarea programada no se pudo ejecutar
|
||||
whatsapp.message.sending.error: No se pudo enviar un mensaje en WhatsApp.
|
||||
whatsapp.message.receiving.error: No se pudo recibir un mensaje de WhatsApp
|
||||
whatsapp.message.removing.error: No se pudo eliminar un mensaje de WhatsApp
|
||||
job.scheduled.error.header: La tarea programada no se pudo ejecutar
|
||||
|
||||
MESSAGE_FROM_WHATSAPP: |
|
||||
message.from.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *Enviado desde WhatsApp*
|
||||
|
||||
MESSAGE_FROM_API: |
|
||||
message.from.api: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *Enviado a través de API*
|
||||
|
||||
MESSAGE_REMOVED_IN_WHATSAPP: |
|
||||
message.removed.in.whatsapp: |-
|
||||
❌ *Este mensaje fue eliminado en WhatsApp*
|
||||
|
||||
MESSAGE_EDITED_IN_WHATSAPP: |
|
||||
message.edited.in.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
✏️ *Editado en WhatsApp*
|
||||
|
||||
WHATSAPP_GROUP_MESSAGE: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.group.message: |-
|
||||
👥 *{{{participant}}}*
|
||||
|
||||
WHATSAPP_REACTION_ADDED: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.reaction.added: |-
|
||||
*Reaccionó con* {{{emoji}}}
|
||||
|
||||
WHATSAPP_REACTION_REMOVED: |
|
||||
whatsapp.reaction.removed: |-
|
||||
*Reacción eliminada*
|
||||
|
||||
WHATSAPP_CONTACT_GROUP_SUFFIX: 'Grupo'
|
||||
WHATSAPP_CONTACT_CHANNEL_SUFFIX: 'Canal'
|
||||
whatsapp.contact.group.suffix: 'Grupo'
|
||||
whatsapp.contact.channel.suffix: 'Canal'
|
||||
whatsapp.contact.broadcast.suffix: 'Lista de difusión'
|
||||
# Aka Stories
|
||||
WHATSAPP_CONTACT_STATUS_NAME: 'Estado'
|
||||
whatsapp.contact.status.name: 'Estado'
|
||||
|
||||
APP_CONNECTED_MESSAGE: |
|
||||
app.connected.message: |-
|
||||
🔗 **CONECTADO: Sesión de WhatsApp a Bandeja de Entrada de ChatWoot**
|
||||
|
||||
✅ La sesión de WhatsApp **{{{name}}}** ha sido conectada exitosamente a esta Bandeja de Entrada de ChatWoot.
|
||||
@@ -80,7 +83,7 @@ APP_CONNECTED_MESSAGE: |
|
||||
|
||||
¡Comencemos! 🚀
|
||||
|
||||
APP_DISCONNECTED_MESSAGE: |
|
||||
app.disconnected.message: |-
|
||||
🔌 **DESCONECTADO: Sesión de WhatsApp de Bandeja de Entrada de ChatWoot**
|
||||
|
||||
❌ La sesión de WhatsApp **{{{name}}}** ha sido desconectada de esta Bandeja de Entrada de ChatWoot.
|
||||
@@ -89,15 +92,15 @@ APP_DISCONNECTED_MESSAGE: |
|
||||
|
||||
Para reconectar, por favor contacta a tu administrador.
|
||||
|
||||
APP_UPDATED_MESSAGE: |
|
||||
app.updated.message: |-
|
||||
🔄 **ACTUALIZADO: Configuración de Sesión de WhatsApp**
|
||||
|
||||
✅ La configuración para la sesión de WhatsApp **{{{name}}}** ha sido actualizada.
|
||||
|
||||
APP_COMMANDS_LIST: |
|
||||
app.commands.list: |-
|
||||
Puedes gestionar la **Integración de WhatsApp** enviando uno de los siguientes comandos:
|
||||
|
||||
🖥️ Sesiones:
|
||||
🖥️ **Sesión**:
|
||||
1. **status** - obtener el estado actual de la sesión.
|
||||
2. **restart** - reiniciar la sesión - esto intentará reconectar tu cuenta de WhatsApp.
|
||||
3. **start** - iniciar la sesión.
|
||||
@@ -107,42 +110,50 @@ APP_COMMANDS_LIST: |
|
||||
7. **screenshot** - obtener una captura de pantalla de la sesión (solo disponible en el motor **WEBJS**).
|
||||
8. **help** - comandos disponibles.
|
||||
|
||||
{{#commands.server}}
|
||||
{{#commands.server}}
|
||||
⚙️ Servidor:
|
||||
- **server status** - obtener información de versión y estado del servidor.
|
||||
- **server reboot** - reiniciar el servidor de forma segura.
|
||||
- **server reboot force** - forzar el reinicio del servidor.
|
||||
{{/commands.server}}
|
||||
{{/commands.server}}
|
||||
|
||||
Envía un **comando** (no sensible a mayúsculas/minúsculas) o un **número de comando** a esta conversación.
|
||||
|
||||
APP_HELP_REMINDER: |
|
||||
app.commands.server.disabled: ⛔ **Los comandos del servidor están
|
||||
deshabilitados**.
|
||||
|
||||
Por favor, contacta a tu administrador.
|
||||
|
||||
Envía **help** para obtener la lista de comandos disponibles.
|
||||
|
||||
APP_SESSION_STATUS_CHANGE: |
|
||||
app.help.reminder: |-
|
||||
Envía **help** para obtener la lista de comandos disponibles.
|
||||
|
||||
app.session.status.change: |-
|
||||
{{{emoji}}} La sesión "{{{session}}}" cambió al estado {{{status}}}
|
||||
|
||||
APP_SESSION_CURRENT_STATUS: |
|
||||
app.session.current.status: |-
|
||||
{{{emoji}}} El estado de la sesión **{{{session}}}** es **{{{status}}}**
|
||||
**Cuenta de WhatsApp:**
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_DASHBOARD_LINK: |
|
||||
Visita el [Panel de WAHA]({{{url}}}) para más detalles.
|
||||
|
||||
APP_SESSION_STATUS_WORKING: |
|
||||
app.session.status.working: |-
|
||||
✅ ¡Esta Bandeja de Entrada de ChatWoot está vinculada a la **Cuenta de WhatsApp** y lista para enviar y recibir mensajes!
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_SESSION_STATUS_ERROR: |
|
||||
app.session.status.error: |-
|
||||
⚠️ **¡Esta Bandeja de Entrada de ChatWoot está vinculada a la Cuenta de WhatsApp pero NO está lista para enviar y recibir mensajes!**
|
||||
|
||||
Por favor, comprueba el estado de la sesión e intenta reiniciarla o cierra sesión y escanea el código QR de nuevo.
|
||||
|
||||
APP_SESSION_SCAN_QR_CODE: |
|
||||
app.session.scan.qr.code: |-
|
||||
⚠️ **¡Escanea el código QR en tu teléfono para vincular la Cuenta de WhatsApp con esta Bandeja de Entrada de ChatWoot!**
|
||||
|
||||
APP_SERVER_VERSION_AND_STATUS: |
|
||||
app.server.version.and.status: |-
|
||||
**Versión:**
|
||||
```
|
||||
{{{version}}}
|
||||
@@ -153,16 +164,16 @@ APP_SERVER_VERSION_AND_STATUS: |
|
||||
{{{status}}}
|
||||
```
|
||||
|
||||
APP_SERVER_REBOOT: |
|
||||
app.server.reboot: |-
|
||||
El servidor se está reiniciando de forma segura...
|
||||
|
||||
APP_SERVER_REBOOT_FORCE: |
|
||||
app.server.reboot.force: |-
|
||||
El servidor se está reiniciando forzadamente...
|
||||
|
||||
APP_LOGOUT_SUCCESS: |
|
||||
app.logout.success: |-
|
||||
✅ ¡Cuenta desautorizada con éxito!
|
||||
|
||||
APP_NEW_VERSION_AVAILABLE: |
|
||||
waha.new.version.available: |-
|
||||
🔄 **¡Nueva Versión Disponible!**
|
||||
|
||||
Versión actual: **{{{currentVersion}}}**
|
||||
@@ -170,7 +181,7 @@ APP_NEW_VERSION_AVAILABLE: |
|
||||
|
||||
👉 Mira qué hay de nuevo en el [**🆕 Registro de Cambios**]({{{changelogUrl}}})
|
||||
|
||||
APP_CORE_VERSION_USED: |
|
||||
waha.core.version.used: |-
|
||||
❤️ **¡Apoya a WAHA!**
|
||||
|
||||
Estás usando la versión gratuita **WAHA Core**. Si encuentras útil este proyecto, por favor considera apoyar su desarrollo.
|
||||
@@ -178,3 +189,51 @@ APP_CORE_VERSION_USED: |
|
||||
Tu apoyo es la única forma en que podemos seguir trabajando en actualizaciones, correcciones y nuevas funciones.
|
||||
|
||||
[**🎁 Apóyanos**]({{{supportUrl}}})
|
||||
|
||||
chatwoot.to.whatsapp.message.text: |-
|
||||
{{{ content }}}
|
||||
|
||||
chatwoot.to.whatsapp.message.media.caption: |-
|
||||
{{#singleAttachment}}
|
||||
{{#content}}
|
||||
{{{ content }}}
|
||||
{{/content}}
|
||||
{{/singleAttachment}}
|
||||
|
||||
whatsapp.to.chatwoot.message: |-
|
||||
{{{payload.body}}}
|
||||
|
||||
whatsapp.to.chatwoot.message.contacts: |-
|
||||
👤 **Contacto(s) compartido(s)**
|
||||
|
||||
{{#contacts}}
|
||||
🪪 Nombre: **{{fullName}}**
|
||||
{{#phoneNumbers}}
|
||||
- 📞 Teléfono: **{{.}}**
|
||||
{{/phoneNumbers}}
|
||||
|
||||
{{/contacts}}
|
||||
|
||||
whatsapp.to.chatwoot.message.location: |-
|
||||
{{#message}}
|
||||
{{#locationMessage}}
|
||||
📍 **Ubicación compartida**
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/locationMessage}}
|
||||
|
||||
{{#liveLocationMessage}}
|
||||
📍📡 **Compartiendo ubicación en tiempo real**
|
||||
Abre **WhatsApp** para ver las actualizaciones en tiempo real.
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/liveLocationMessage}}
|
||||
{{/message}}
|
||||
|
||||
whatsapp.to.chatwoot.message.unsupported: |-
|
||||
⚠️ **Este tipo de mensaje no es compatible con ChatWoot.**
|
||||
📱 Por favor, abre **WhatsApp** para verlo.
|
||||
|
||||
Detalles: [{{{details.text}}}]({{{details.url}}})
|
||||
@@ -1,7 +1,9 @@
|
||||
# Persian translations for ChatWoot integration
|
||||
APP_INBOX_CONTACT_NAME: 'ادغام واتساپ (WAHA)'
|
||||
locale.name: '🇮🇷 فارسی (Persian)'
|
||||
app.inbox.contact.name: 'ادغام واتساپ (WAHA)'
|
||||
app.inbox.contact.avatar.url: 'https://raw.githubusercontent.com/devlikeapro/waha/core/logo.png'
|
||||
|
||||
JOB_ERROR_REPORT: |
|
||||
job.report.error: |-
|
||||
⚠️ **{{{header}}}**
|
||||
{{#attempts.nextDelay}}
|
||||
🔄 تلاش مجدد در {{attempts.nextDelay}} ثانیه...
|
||||
@@ -18,51 +20,52 @@ JOB_ERROR_REPORT: |
|
||||
```
|
||||
{{/error}}
|
||||
|
||||
JOB_SUCCEEDED_REPORT: |
|
||||
job.report.succeeded: |-
|
||||
✅ **موفقیتآمیز**
|
||||
تلاش: {{{attempts.current}}} / {{{attempts.max}}}
|
||||
جزئیات: [{{{details.text}}}]({{{details.url}}})
|
||||
|
||||
WHATSAPP_ERROR_SENDING_MESSAGE: ارسال پیام در واتساپ امکانپذیر نبود.
|
||||
WHATSAPP_ERROR_RECEIVING_MESSAGE: دریافت پیام از واتساپ امکانپذیر نبود
|
||||
WHATSAPP_ERROR_REMOVING_MESSAGE: حذف پیام از واتساپ امکانپذیر نبود
|
||||
APP_SCHEDULED_JOB_ERROR: اجرای کار زمانبندی شده ناموفق بود
|
||||
whatsapp.message.sending.error: ارسال پیام در واتساپ امکانپذیر نبود.
|
||||
whatsapp.message.receiving.error: دریافت پیام از واتساپ امکانپذیر نبود
|
||||
whatsapp.message.removing.error: حذف پیام از واتساپ امکانپذیر نبود
|
||||
job.scheduled.error.header: اجرای کار زمانبندی شده ناموفق بود
|
||||
|
||||
MESSAGE_FROM_WHATSAPP: |
|
||||
message.from.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *ارسال شده از واتساپ*
|
||||
|
||||
MESSAGE_FROM_API: |
|
||||
message.from.api: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *ارسال شده از طریق API*
|
||||
|
||||
MESSAGE_REMOVED_IN_WHATSAPP: |
|
||||
message.removed.in.whatsapp: |-
|
||||
❌ *این پیام در واتساپ حذف شده است*
|
||||
|
||||
MESSAGE_EDITED_IN_WHATSAPP: |
|
||||
message.edited.in.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
✏️ *ویرایش شده در واتساپ*
|
||||
|
||||
WHATSAPP_GROUP_MESSAGE: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.group.message: |-
|
||||
👥 *{{{participant}}}*
|
||||
|
||||
WHATSAPP_REACTION_ADDED: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.reaction.added: |-
|
||||
*واکنش* {{{emoji}}}
|
||||
|
||||
WHATSAPP_REACTION_REMOVED: |
|
||||
whatsapp.reaction.removed: |-
|
||||
*واکنش حذف شد*
|
||||
|
||||
WHATSAPP_CONTACT_GROUP_SUFFIX: 'گروه'
|
||||
WHATSAPP_CONTACT_CHANNEL_SUFFIX: 'کانال'
|
||||
whatsapp.contact.group.suffix: 'گروه'
|
||||
whatsapp.contact.channel.suffix: 'کانال'
|
||||
whatsapp.contact.broadcast.suffix: 'فهرست انتشار'
|
||||
# Aka Stories
|
||||
WHATSAPP_CONTACT_STATUS_NAME: 'وضعیت'
|
||||
whatsapp.contact.status.name: 'وضعیت'
|
||||
|
||||
APP_CONNECTED_MESSAGE: |
|
||||
app.connected.message: |-
|
||||
🔗 **متصل: جلسه واتساپ به صندوق ورودی ChatWoot**
|
||||
|
||||
✅ جلسه واتساپ **{{{name}}}** با موفقیت به این صندوق ورودی ChatWoot متصل شده است.
|
||||
@@ -80,7 +83,7 @@ APP_CONNECTED_MESSAGE: |
|
||||
|
||||
بیایید شروع کنیم! 🚀
|
||||
|
||||
APP_DISCONNECTED_MESSAGE: |
|
||||
app.disconnected.message: |-
|
||||
🔌 **قطع اتصال: جلسه واتساپ از صندوق ورودی ChatWoot**
|
||||
|
||||
❌ جلسه واتساپ **{{{name}}}** از این صندوق ورودی ChatWoot قطع شده است.
|
||||
@@ -89,15 +92,15 @@ APP_DISCONNECTED_MESSAGE: |
|
||||
|
||||
برای اتصال مجدد، لطفاً با مدیر خود تماس بگیرید.
|
||||
|
||||
APP_UPDATED_MESSAGE: |
|
||||
app.updated.message: |-
|
||||
🔄 **بهروزرسانی: تنظیمات جلسه واتساپ**
|
||||
|
||||
✅ تنظیمات جلسه واتساپ **{{{name}}}** بهروزرسانی شده است.
|
||||
|
||||
APP_COMMANDS_LIST: |
|
||||
app.commands.list: |-
|
||||
شما میتوانید **ادغام واتساپ** را با ارسال یکی از دستورات زیر مدیریت کنید:
|
||||
|
||||
🖥️ جلسات:
|
||||
🖥️ **جلسه**:
|
||||
1. **status** - دریافت وضعیت فعلی جلسه.
|
||||
2. **restart** - راهاندازی مجدد جلسه - این تلاش خواهد کرد حساب واتساپ شما را مجدداً متصل کند.
|
||||
3. **start** - شروع جلسه.
|
||||
@@ -107,42 +110,47 @@ APP_COMMANDS_LIST: |
|
||||
7. **screenshot** - دریافت اسکرینشات از جلسه (فقط در موتور **WEBJS** در دسترس است).
|
||||
8. **help** - دستورات موجود.
|
||||
|
||||
{{#commands.server}}
|
||||
⚙️ سرور:
|
||||
- **server status** - دریافت اطلاعات نسخه و وضعیت سرور.
|
||||
- **server reboot** - راهاندازی مجدد سرور به صورت نرم.
|
||||
- **server reboot force** - راهاندازی مجدد اجباری سرور.
|
||||
{{/commands.server}}
|
||||
|
||||
یک **دستور** (بدون حساسیت به بزرگی و کوچکی حروف) یا **شماره دستور** را به این گفتگو ارسال کنید.
|
||||
|
||||
APP_HELP_REMINDER: |
|
||||
app.commands.server.disabled: ⛔ **دستورات سرور غیرفعال است**.
|
||||
|
||||
لطفاً با مدیر سیستم خود تماس بگیرید.
|
||||
|
||||
برای دریافت فهرست دستورات، **help** را ارسال کنید.
|
||||
|
||||
app.help.reminder: |-
|
||||
برای دریافت لیست دستورات موجود، **help** را ارسال کنید.
|
||||
|
||||
APP_SESSION_STATUS_CHANGE: |
|
||||
app.session.status.change: |-
|
||||
{{{emoji}}} جلسه "{{{session}}}" به وضعیت {{{status}}} تغییر کرد
|
||||
|
||||
APP_SESSION_CURRENT_STATUS: |
|
||||
app.session.current.status: |-
|
||||
{{{emoji}}} وضعیت جلسه **{{{session}}}** در **{{{status}}}** است
|
||||
**حساب واتساپ:**
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_DASHBOARD_LINK: |
|
||||
برای جزئیات بیشتر به [داشبورد WAHA]({{{url}}}) مراجعه کنید.
|
||||
|
||||
APP_SESSION_STATUS_WORKING: |
|
||||
app.session.status.working: |-
|
||||
✅ این صندوق ورودی ChatWoot به **حساب واتساپ** متصل است و آماده ارسال و دریافت پیام است!
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_SESSION_STATUS_ERROR: |
|
||||
app.session.status.error: |-
|
||||
⚠️ **این صندوق ورودی ChatWoot به حساب واتساپ متصل است اما آماده ارسال و دریافت پیام نیست!**
|
||||
|
||||
لطفاً وضعیت جلسه را بررسی کنید و سعی کنید آن را مجدداً راهاندازی کنید یا خارج شوید و کد QR را دوباره اسکن کنید.
|
||||
|
||||
APP_SESSION_SCAN_QR_CODE: |
|
||||
app.session.scan.qr.code: |-
|
||||
⚠️ **کد QR را در تلفن خود اسکن کنید تا حساب واتساپ را با این صندوق ورودی ChatWoot پیوند دهید!**
|
||||
|
||||
APP_SERVER_VERSION_AND_STATUS: |
|
||||
app.server.version.and.status: |-
|
||||
**نسخه:**
|
||||
```
|
||||
{{{version}}}
|
||||
@@ -153,16 +161,16 @@ APP_SERVER_VERSION_AND_STATUS: |
|
||||
{{{status}}}
|
||||
```
|
||||
|
||||
APP_SERVER_REBOOT: |
|
||||
app.server.reboot: |-
|
||||
سرور در حال راهاندازی مجدد نرم است...
|
||||
|
||||
APP_SERVER_REBOOT_FORCE: |
|
||||
app.server.reboot.force: |-
|
||||
سرور در حال راهاندازی مجدد اجباری است...
|
||||
|
||||
APP_LOGOUT_SUCCESS: |
|
||||
app.logout.success: |-
|
||||
✅ حساب با موفقیت غیرمجاز شد!
|
||||
|
||||
APP_NEW_VERSION_AVAILABLE: |
|
||||
waha.new.version.available: |-
|
||||
🔄 **نسخه جدید در دسترس است!**
|
||||
|
||||
نسخه فعلی: **{{{currentVersion}}}**
|
||||
@@ -170,7 +178,7 @@ APP_NEW_VERSION_AVAILABLE: |
|
||||
|
||||
👉 موارد جدید را در [**🆕 تغییرات**]({{{changelogUrl}}}) مشاهده کنید
|
||||
|
||||
APP_CORE_VERSION_USED: |
|
||||
waha.core.version.used: |-
|
||||
❤️ **از WAHA پشتیبانی کنید!**
|
||||
|
||||
شما از نسخه رایگان **WAHA Core** استفاده میکنید. اگر این پروژه را مفید میدانید، لطفاً حمایت از توسعه آن را در نظر بگیرید.
|
||||
@@ -178,3 +186,51 @@ APP_CORE_VERSION_USED: |
|
||||
حمایت شما تنها راهی است که ما میتوانیم به کار بر روی بهروزرسانیها، رفع اشکالات و ویژگیهای جدید ادامه دهیم.
|
||||
|
||||
[**🎁 از ما حمایت کنید**]({{{supportUrl}}})
|
||||
|
||||
chatwoot.to.whatsapp.message.text: |-
|
||||
{{{ content }}}
|
||||
|
||||
chatwoot.to.whatsapp.message.media.caption: |-
|
||||
{{#singleAttachment}}
|
||||
{{#content}}
|
||||
{{{ content }}}
|
||||
{{/content}}
|
||||
{{/singleAttachment}}
|
||||
|
||||
whatsapp.to.chatwoot.message: |-
|
||||
{{{payload.body}}}
|
||||
|
||||
whatsapp.to.chatwoot.message.contacts: |-
|
||||
👤 **مخاطب(ها)ی بهاشتراکگذاشتهشده**
|
||||
|
||||
{{#contacts}}
|
||||
🪪 نام: **{{fullName}}**
|
||||
{{#phoneNumbers}}
|
||||
- 📞 تلفن: **{{.}}**
|
||||
{{/phoneNumbers}}
|
||||
|
||||
{{/contacts}}
|
||||
|
||||
whatsapp.to.chatwoot.message.location: |-
|
||||
{{#message}}
|
||||
{{#locationMessage}}
|
||||
📍 **موقعیت مکانی بهاشتراکگذاشتهشده**
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/locationMessage}}
|
||||
|
||||
{{#liveLocationMessage}}
|
||||
📍📡 **اشتراکگذاری موقعیت مکانی زنده**
|
||||
برای دیدن بهروزرسانیهای لحظهای **WhatsApp** را باز کنید.
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/liveLocationMessage}}
|
||||
{{/message}}
|
||||
|
||||
whatsapp.to.chatwoot.message.unsupported: |-
|
||||
⚠️ **این نوع پیام در ChatWoot پشتیبانی نمیشود.**
|
||||
📱 لطفاً برای مشاهده آن **WhatsApp** را باز کنید.
|
||||
|
||||
جزئیات: [{{{details.text}}}]({{{details.url}}})
|
||||
@@ -1,7 +1,9 @@
|
||||
# French translations for ChatWoot integration
|
||||
APP_INBOX_CONTACT_NAME: 'Intégration WhatsApp (WAHA)'
|
||||
locale.name: '🇫🇷 Français (French)'
|
||||
app.inbox.contact.name: 'Intégration WhatsApp (WAHA)'
|
||||
app.inbox.contact.avatar.url: 'https://raw.githubusercontent.com/devlikeapro/waha/core/logo.png'
|
||||
|
||||
JOB_ERROR_REPORT: |
|
||||
job.report.error: |-
|
||||
⚠️ **{{{header}}}**
|
||||
{{#attempts.nextDelay}}
|
||||
🔄 Nouvelle tentative dans {{attempts.nextDelay}} secondes...
|
||||
@@ -18,51 +20,52 @@ JOB_ERROR_REPORT: |
|
||||
```
|
||||
{{/error}}
|
||||
|
||||
JOB_SUCCEEDED_REPORT: |
|
||||
job.report.succeeded: |-
|
||||
✅ **Réussi**
|
||||
Tentative : {{{attempts.current}}} / {{{attempts.max}}}
|
||||
Détails : [{{{details.text}}}]({{{details.url}}})
|
||||
|
||||
WHATSAPP_ERROR_SENDING_MESSAGE: Impossible d'envoyer un message sur WhatsApp.
|
||||
WHATSAPP_ERROR_RECEIVING_MESSAGE: Impossible de recevoir un message de WhatsApp
|
||||
WHATSAPP_ERROR_REMOVING_MESSAGE: Impossible de supprimer un message de WhatsApp
|
||||
APP_SCHEDULED_JOB_ERROR: La tâche planifiée n'a pas pu être exécutée
|
||||
whatsapp.message.sending.error: Impossible d'envoyer un message sur WhatsApp.
|
||||
whatsapp.message.receiving.error: Impossible de recevoir un message de WhatsApp
|
||||
whatsapp.message.removing.error: Impossible de supprimer un message de WhatsApp
|
||||
job.scheduled.error.header: La tâche planifiée n'a pas pu être exécutée
|
||||
|
||||
MESSAGE_FROM_WHATSAPP: |
|
||||
message.from.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *Envoyé depuis WhatsApp*
|
||||
|
||||
MESSAGE_FROM_API: |
|
||||
message.from.api: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *Envoyé via API*
|
||||
|
||||
MESSAGE_REMOVED_IN_WHATSAPP: |
|
||||
message.removed.in.whatsapp: |-
|
||||
❌ *Ce message a été supprimé dans WhatsApp*
|
||||
|
||||
MESSAGE_EDITED_IN_WHATSAPP: |
|
||||
message.edited.in.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
✏️ *Modifié dans WhatsApp*
|
||||
|
||||
WHATSAPP_GROUP_MESSAGE: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.group.message: |-
|
||||
👥 *{{{participant}}}*
|
||||
|
||||
WHATSAPP_REACTION_ADDED: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.reaction.added: |-
|
||||
*A réagi avec* {{{emoji}}}
|
||||
|
||||
WHATSAPP_REACTION_REMOVED: |
|
||||
whatsapp.reaction.removed: |-
|
||||
*Réaction supprimée*
|
||||
|
||||
WHATSAPP_CONTACT_GROUP_SUFFIX: 'Groupe'
|
||||
WHATSAPP_CONTACT_CHANNEL_SUFFIX: 'Canal'
|
||||
whatsapp.contact.group.suffix: 'Groupe'
|
||||
whatsapp.contact.channel.suffix: 'Canal'
|
||||
whatsapp.contact.broadcast.suffix: 'Liste de diffusion'
|
||||
# Aka Stories
|
||||
WHATSAPP_CONTACT_STATUS_NAME: 'Statut'
|
||||
whatsapp.contact.status.name: 'Statut'
|
||||
|
||||
APP_CONNECTED_MESSAGE: |
|
||||
app.connected.message: |-
|
||||
🔗 **CONNECTÉ : Session WhatsApp à la Boîte de Réception ChatWoot**
|
||||
|
||||
✅ La session WhatsApp **{{{name}}}** a été connectée avec succès à cette Boîte de Réception ChatWoot.
|
||||
@@ -80,7 +83,7 @@ APP_CONNECTED_MESSAGE: |
|
||||
|
||||
Commençons ! 🚀
|
||||
|
||||
APP_DISCONNECTED_MESSAGE: |
|
||||
app.disconnected.message: |-
|
||||
🔌 **DÉCONNECTÉ : Session WhatsApp de la Boîte de Réception ChatWoot**
|
||||
|
||||
❌ La session WhatsApp **{{{name}}}** a été déconnectée de cette Boîte de Réception ChatWoot.
|
||||
@@ -89,15 +92,15 @@ APP_DISCONNECTED_MESSAGE: |
|
||||
|
||||
Pour vous reconnecter, veuillez contacter votre administrateur.
|
||||
|
||||
APP_UPDATED_MESSAGE: |
|
||||
app.updated.message: |-
|
||||
🔄 **MIS À JOUR : Paramètres de Session WhatsApp**
|
||||
|
||||
✅ Les paramètres de la session WhatsApp **{{{name}}}** ont été mis à jour.
|
||||
|
||||
APP_COMMANDS_LIST: |
|
||||
app.commands.list: |-
|
||||
Vous pouvez gérer l'**Intégration WhatsApp** en envoyant l'une des commandes suivantes :
|
||||
|
||||
🖥️ Sessions :
|
||||
🖥️ **Session** :
|
||||
1. **status** - obtenir l'état actuel de la session.
|
||||
2. **restart** - redémarrer la session - cela tentera de reconnecter votre compte WhatsApp.
|
||||
3. **start** - démarrer la session.
|
||||
@@ -107,42 +110,47 @@ APP_COMMANDS_LIST: |
|
||||
7. **screenshot** - obtenir une capture d'écran de la session (disponible uniquement dans le moteur **WEBJS**).
|
||||
8. **help** - commandes disponibles.
|
||||
|
||||
{{#commands.server}}
|
||||
⚙️ Serveur :
|
||||
- **server status** - obtenir les informations de version et d'état du serveur.
|
||||
- **server reboot** - redémarrer le serveur en douceur.
|
||||
- **server reboot force** - forcer le redémarrage du serveur.
|
||||
{{/commands.server}}
|
||||
|
||||
Envoyez une **commande** (insensible à la casse) ou un **numéro de commande** à cette conversation.
|
||||
|
||||
APP_HELP_REMINDER: |
|
||||
app.commands.server.disabled: ⛔ **Les commandes serveur sont désactivées**.
|
||||
|
||||
Veuillez contacter votre administrateur.
|
||||
|
||||
Envoyez **help** pour obtenir la liste des commandes disponibles.
|
||||
|
||||
APP_SESSION_STATUS_CHANGE: |
|
||||
app.help.reminder: |-
|
||||
Envoyez **help** pour obtenir la liste des commandes disponibles.
|
||||
|
||||
app.session.status.change: |-
|
||||
{{{emoji}}} La session "{{{session}}}" est passée au statut {{{status}}}
|
||||
|
||||
APP_SESSION_CURRENT_STATUS: |
|
||||
app.session.current.status: |-
|
||||
{{{emoji}}} Le statut de la session **{{{session}}}** est **{{{status}}}**
|
||||
**Compte WhatsApp :**
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_DASHBOARD_LINK: |
|
||||
Visitez le [Tableau de bord WAHA]({{{url}}}) pour plus de détails.
|
||||
|
||||
APP_SESSION_STATUS_WORKING: |
|
||||
app.session.status.working: |-
|
||||
✅ Cette Boîte de Réception ChatWoot est liée au **Compte WhatsApp** et prête à envoyer et recevoir des messages !
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_SESSION_STATUS_ERROR: |
|
||||
app.session.status.error: |-
|
||||
⚠️ **Cette Boîte de Réception ChatWoot est liée au Compte WhatsApp mais N'EST PAS prête à envoyer et recevoir des messages !**
|
||||
|
||||
Veuillez vérifier l'état de la session et essayer de la redémarrer ou déconnectez-vous et scannez à nouveau le code QR.
|
||||
|
||||
APP_SESSION_SCAN_QR_CODE: |
|
||||
app.session.scan.qr.code: |-
|
||||
⚠️ **Scannez le code QR sur votre téléphone pour lier le Compte WhatsApp à cette Boîte de Réception ChatWoot !**
|
||||
|
||||
APP_SERVER_VERSION_AND_STATUS: |
|
||||
app.server.version.and.status: |-
|
||||
**Version :**
|
||||
```
|
||||
{{{version}}}
|
||||
@@ -153,16 +161,16 @@ APP_SERVER_VERSION_AND_STATUS: |
|
||||
{{{status}}}
|
||||
```
|
||||
|
||||
APP_SERVER_REBOOT: |
|
||||
app.server.reboot: |-
|
||||
Le serveur redémarre en douceur...
|
||||
|
||||
APP_SERVER_REBOOT_FORCE: |
|
||||
app.server.reboot.force: |-
|
||||
Le serveur redémarre de force...
|
||||
|
||||
APP_LOGOUT_SUCCESS: |
|
||||
app.logout.success: |-
|
||||
✅ Compte déconnecté avec succès !
|
||||
|
||||
APP_NEW_VERSION_AVAILABLE: |
|
||||
waha.new.version.available: |-
|
||||
🔄 **Nouvelle Version Disponible !**
|
||||
|
||||
Version actuelle : **{{{currentVersion}}}**
|
||||
@@ -170,7 +178,7 @@ APP_NEW_VERSION_AVAILABLE: |
|
||||
|
||||
👉 Découvrez les nouveautés dans le [**🆕 Journal des modifications**]({{{changelogUrl}}})
|
||||
|
||||
APP_CORE_VERSION_USED: |
|
||||
waha.core.version.used: |-
|
||||
❤️ **Soutenez WAHA !**
|
||||
|
||||
Vous utilisez la version gratuite **WAHA Core**. Si vous trouvez ce projet utile, veuillez envisager de soutenir son développement.
|
||||
@@ -178,3 +186,51 @@ APP_CORE_VERSION_USED: |
|
||||
Votre soutien est le seul moyen pour nous de continuer à travailler sur les mises à jour, les corrections et les nouvelles fonctionnalités.
|
||||
|
||||
[**🎁 Soutenez-nous**]({{{supportUrl}}})
|
||||
|
||||
chatwoot.to.whatsapp.message.text: |-
|
||||
{{{ content }}}
|
||||
|
||||
chatwoot.to.whatsapp.message.media.caption: |-
|
||||
{{#singleAttachment}}
|
||||
{{#content}}
|
||||
{{{ content }}}
|
||||
{{/content}}
|
||||
{{/singleAttachment}}
|
||||
|
||||
whatsapp.to.chatwoot.message: |-
|
||||
{{{payload.body}}}
|
||||
|
||||
whatsapp.to.chatwoot.message.contacts: |-
|
||||
👤 **Contact(s) partagé(s)**
|
||||
|
||||
{{#contacts}}
|
||||
🪪 Nom: **{{fullName}}**
|
||||
{{#phoneNumbers}}
|
||||
- 📞 Téléphone: **{{.}}**
|
||||
{{/phoneNumbers}}
|
||||
|
||||
{{/contacts}}
|
||||
|
||||
whatsapp.to.chatwoot.message.location: |-
|
||||
{{#message}}
|
||||
{{#locationMessage}}
|
||||
📍 **Position partagée**
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/locationMessage}}
|
||||
|
||||
{{#liveLocationMessage}}
|
||||
📍📡 **Partage de position en direct**
|
||||
Ouvrez **WhatsApp** pour voir les mises à jour en temps réel.
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/liveLocationMessage}}
|
||||
{{/message}}
|
||||
|
||||
whatsapp.to.chatwoot.message.unsupported: |-
|
||||
⚠️ **Ce type de message n’est pas pris en charge dans ChatWoot.**
|
||||
📱 Veuillez ouvrir **WhatsApp** pour l’afficher.
|
||||
|
||||
Détails: [{{{details.text}}}]({{{details.url}}})
|
||||
@@ -1,7 +1,9 @@
|
||||
# Hebrew translations for ChatWoot integration
|
||||
APP_INBOX_CONTACT_NAME: 'אינטגרציית וואטסאפ (WAHA)'
|
||||
locale.name: '🇮🇱 עברית (Hebrew)'
|
||||
app.inbox.contact.name: 'אינטגרציית וואטסאפ (WAHA)'
|
||||
app.inbox.contact.avatar.url: 'https://raw.githubusercontent.com/devlikeapro/waha/core/logo.png'
|
||||
|
||||
JOB_ERROR_REPORT: |
|
||||
job.report.error: |-
|
||||
⚠️ **{{{header}}}**
|
||||
{{#attempts.nextDelay}}
|
||||
🔄 מנסה שוב בעוד {{attempts.nextDelay}} שניות...
|
||||
@@ -18,51 +20,52 @@ JOB_ERROR_REPORT: |
|
||||
```
|
||||
{{/error}}
|
||||
|
||||
JOB_SUCCEEDED_REPORT: |
|
||||
job.report.succeeded: |-
|
||||
✅ **הצליח**
|
||||
ניסיון: {{{attempts.current}}} / {{{attempts.max}}}
|
||||
פרטים: [{{{details.text}}}]({{{details.url}}})
|
||||
|
||||
WHATSAPP_ERROR_SENDING_MESSAGE: לא ניתן לשלוח הודעה בוואטסאפ.
|
||||
WHATSAPP_ERROR_RECEIVING_MESSAGE: לא ניתן לקבל הודעה מוואטסאפ
|
||||
WHATSAPP_ERROR_REMOVING_MESSAGE: לא ניתן להסיר הודעה מוואטסאפ
|
||||
APP_SCHEDULED_JOB_ERROR: המשימה המתוזמנת נכשלה בביצוע
|
||||
whatsapp.message.sending.error: לא ניתן לשלוח הודעה בוואטסאפ.
|
||||
whatsapp.message.receiving.error: לא ניתן לקבל הודעה מוואטסאפ
|
||||
whatsapp.message.removing.error: לא ניתן להסיר הודעה מוואטסאפ
|
||||
job.scheduled.error.header: המשימה המתוזמנת נכשלה בביצוע
|
||||
|
||||
MESSAGE_FROM_WHATSAPP: |
|
||||
message.from.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *נשלח מוואטסאפ*
|
||||
|
||||
MESSAGE_FROM_API: |
|
||||
message.from.api: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *נשלח דרך API*
|
||||
|
||||
MESSAGE_REMOVED_IN_WHATSAPP: |
|
||||
message.removed.in.whatsapp: |-
|
||||
❌ *הודעה זו נמחקה בוואטסאפ*
|
||||
|
||||
MESSAGE_EDITED_IN_WHATSAPP: |
|
||||
message.edited.in.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
✏️ *נערך בוואטסאפ*
|
||||
|
||||
WHATSAPP_GROUP_MESSAGE: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.group.message: |-
|
||||
👥 *{{{participant}}}*
|
||||
|
||||
WHATSAPP_REACTION_ADDED: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.reaction.added: |-
|
||||
*הגיב* {{{emoji}}}
|
||||
|
||||
WHATSAPP_REACTION_REMOVED: |
|
||||
whatsapp.reaction.removed: |-
|
||||
*התגובה הוסרה*
|
||||
|
||||
WHATSAPP_CONTACT_GROUP_SUFFIX: 'קבוצה'
|
||||
WHATSAPP_CONTACT_CHANNEL_SUFFIX: 'ערוץ'
|
||||
whatsapp.contact.group.suffix: 'קבוצה'
|
||||
whatsapp.contact.channel.suffix: 'ערוץ'
|
||||
whatsapp.contact.broadcast.suffix: 'רשימת שידור'
|
||||
# Aka Stories
|
||||
WHATSAPP_CONTACT_STATUS_NAME: 'סטטוס'
|
||||
whatsapp.contact.status.name: 'סטטוס'
|
||||
|
||||
APP_CONNECTED_MESSAGE: |
|
||||
app.connected.message: |-
|
||||
🔗 **מחובר: הפעלת וואטסאפ לתיבת הדואר הנכנס של ChatWoot**
|
||||
|
||||
✅ הפעלת וואטסאפ **{{{name}}}** חוברה בהצלחה לתיבת הדואר הנכנס של ChatWoot.
|
||||
@@ -80,7 +83,7 @@ APP_CONNECTED_MESSAGE: |
|
||||
|
||||
בוא נתחיל! 🚀
|
||||
|
||||
APP_DISCONNECTED_MESSAGE: |
|
||||
app.disconnected.message: |-
|
||||
🔌 **מנותק: הפעלת וואטסאפ מתיבת הדואר הנכנס של ChatWoot**
|
||||
|
||||
❌ הפעלת וואטסאפ **{{{name}}}** נותקה מתיבת הדואר הנכנס של ChatWoot.
|
||||
@@ -89,15 +92,15 @@ APP_DISCONNECTED_MESSAGE: |
|
||||
|
||||
כדי להתחבר מחדש, אנא פנה למנהל המערכת שלך.
|
||||
|
||||
APP_UPDATED_MESSAGE: |
|
||||
app.updated.message: |-
|
||||
🔄 **עודכן: הגדרות הפעלת וואטסאפ**
|
||||
|
||||
✅ ההגדרות עבור הפעלת וואטסאפ **{{{name}}}** עודכנו.
|
||||
|
||||
APP_COMMANDS_LIST: |
|
||||
app.commands.list: |-
|
||||
אתה יכול לנהל **אינטגרציית וואטסאפ** על ידי שליחת אחת מהפקודות הבאות:
|
||||
|
||||
🖥️ הפעלות:
|
||||
🖥️ **הפעלה**:
|
||||
1. **status** - קבל את סטטוס ההפעלה הנוכחי.
|
||||
2. **restart** - הפעל מחדש את ההפעלה - זה ינסה לחבר מחדש את חשבון הוואטסאפ שלך.
|
||||
3. **start** - התחל את ההפעלה.
|
||||
@@ -107,42 +110,47 @@ APP_COMMANDS_LIST: |
|
||||
7. **screenshot** - קבל צילום מסך של ההפעלה (זמין רק במנוע **WEBJS**).
|
||||
8. **help** - פקודות זמינות.
|
||||
|
||||
{{#commands.server}}
|
||||
⚙️ שרת:
|
||||
- **server status** - קבל מידע על גרסת השרת והסטטוס.
|
||||
- **server reboot** - הפעל מחדש את השרת בצורה חלקה.
|
||||
- **server reboot force** - אלץ הפעלה מחדש של השרת.
|
||||
{{/commands.server}}
|
||||
|
||||
שלח **פקודה** (לא תלוי רישיות) או **מספר פקודה** לשיחה זו.
|
||||
|
||||
APP_HELP_REMINDER: |
|
||||
app.commands.server.disabled: ⛔ **פקודות השרת מושבתות**.
|
||||
|
||||
אנא פנו למנהל המערכת שלכם.
|
||||
|
||||
שלחו **help** כדי לקבל את רשימת הפקודות הזמינות.
|
||||
|
||||
app.help.reminder: |-
|
||||
שלח **help** כדי לקבל את רשימת הפקודות הזמינות.
|
||||
|
||||
APP_SESSION_STATUS_CHANGE: |
|
||||
app.session.status.change: |-
|
||||
{{{emoji}}} הפעלה "{{{session}}}" עברה לסטטוס {{{status}}}
|
||||
|
||||
APP_SESSION_CURRENT_STATUS: |
|
||||
app.session.current.status: |-
|
||||
{{{emoji}}} סטטוס ההפעלה **{{{session}}}** הוא **{{{status}}}**
|
||||
**חשבון וואטסאפ:**
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_DASHBOARD_LINK: |
|
||||
בקר ב[לוח הבקרה של WAHA]({{{url}}}) לפרטים נוספים.
|
||||
|
||||
APP_SESSION_STATUS_WORKING: |
|
||||
app.session.status.working: |-
|
||||
✅ תיבת הדואר הנכנס של ChatWoot מקושרת ל**חשבון וואטסאפ** ומוכנה לשלוח ולקבל הודעות!
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_SESSION_STATUS_ERROR: |
|
||||
app.session.status.error: |-
|
||||
⚠️ **תיבת הדואר הנכנס של ChatWoot מקושרת לחשבון וואטסאפ אך אינה מוכנה לשלוח ולקבל הודעות!**
|
||||
|
||||
אנא בדוק את סטטוס ההפעלה ונסה להפעיל אותה מחדש או התנתק וסרוק את קוד ה-QR שוב.
|
||||
|
||||
APP_SESSION_SCAN_QR_CODE: |
|
||||
app.session.scan.qr.code: |-
|
||||
⚠️ **סרוק את קוד ה-QR בטלפון שלך כדי לקשר את חשבון הוואטסאפ לתיבת הדואר הנכנס של ChatWoot!**
|
||||
|
||||
APP_SERVER_VERSION_AND_STATUS: |
|
||||
app.server.version.and.status: |-
|
||||
**גרסה:**
|
||||
```
|
||||
{{{version}}}
|
||||
@@ -153,16 +161,16 @@ APP_SERVER_VERSION_AND_STATUS: |
|
||||
{{{status}}}
|
||||
```
|
||||
|
||||
APP_SERVER_REBOOT: |
|
||||
app.server.reboot: |-
|
||||
השרת מופעל מחדש בצורה חלקה...
|
||||
|
||||
APP_SERVER_REBOOT_FORCE: |
|
||||
app.server.reboot.force: |-
|
||||
השרת מופעל מחדש בכוח...
|
||||
|
||||
APP_LOGOUT_SUCCESS: |
|
||||
app.logout.success: |-
|
||||
✅ החשבון בוטל בהצלחה!
|
||||
|
||||
APP_NEW_VERSION_AVAILABLE: |
|
||||
waha.new.version.available: |-
|
||||
🔄 **גרסה חדשה זמינה!**
|
||||
|
||||
גרסה נוכחית: **{{{currentVersion}}}**
|
||||
@@ -170,7 +178,7 @@ APP_NEW_VERSION_AVAILABLE: |
|
||||
|
||||
👉 בדוק מה חדש ב[**🆕 יומן שינויים**]({{{changelogUrl}}})
|
||||
|
||||
APP_CORE_VERSION_USED: |
|
||||
waha.core.version.used: |-
|
||||
❤️ **תמוך ב-WAHA!**
|
||||
|
||||
אתה משתמש בגרסת **WAHA Core** החינמית. אם אתה מוצא פרויקט זה שימושי, אנא שקול לתמוך בפיתוח שלו.
|
||||
@@ -178,3 +186,51 @@ APP_CORE_VERSION_USED: |
|
||||
התמיכה שלך היא הדרך היחידה שבה אנחנו יכולים להמשיך לעבוד על עדכונים, תיקונים ותכונות חדשות.
|
||||
|
||||
[**🎁 תמוך בנו**]({{{supportUrl}}})
|
||||
|
||||
chatwoot.to.whatsapp.message.text: |-
|
||||
{{{ content }}}
|
||||
|
||||
chatwoot.to.whatsapp.message.media.caption: |-
|
||||
{{#singleAttachment}}
|
||||
{{#content}}
|
||||
{{{ content }}}
|
||||
{{/content}}
|
||||
{{/singleAttachment}}
|
||||
|
||||
whatsapp.to.chatwoot.message: |-
|
||||
{{{payload.body}}}
|
||||
|
||||
whatsapp.to.chatwoot.message.contacts: |-
|
||||
👤 **אנשי קשר משותפים**
|
||||
|
||||
{{#contacts}}
|
||||
🪪 שם: **{{fullName}}**
|
||||
{{#phoneNumbers}}
|
||||
- 📞 טלפון: **{{.}}**
|
||||
{{/phoneNumbers}}
|
||||
|
||||
{{/contacts}}
|
||||
|
||||
whatsapp.to.chatwoot.message.location: |-
|
||||
{{#message}}
|
||||
{{#locationMessage}}
|
||||
📍 **מיקום משותף**
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/locationMessage}}
|
||||
|
||||
{{#liveLocationMessage}}
|
||||
📍📡 **משתף מיקום חי**
|
||||
פתח/י את **WhatsApp** כדי לראות עדכונים בזמן אמת.
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/liveLocationMessage}}
|
||||
{{/message}}
|
||||
|
||||
whatsapp.to.chatwoot.message.unsupported: |-
|
||||
⚠️ **סוג הודעה זה אינו נתמך ב-ChatWoot.**
|
||||
📱 אנא פתח/י את **WhatsApp** כדי לצפות בזה.
|
||||
|
||||
פרטים: [{{{details.text}}}]({{{details.url}}})
|
||||
@@ -1,7 +1,9 @@
|
||||
# Hindi translations for ChatWoot integration
|
||||
APP_INBOX_CONTACT_NAME: 'व्हाट्सएप इंटीग्रेशन (WAHA)'
|
||||
locale.name: '🇮🇳 हिंदी (Hindi)'
|
||||
app.inbox.contact.name: 'व्हाट्सएप इंटीग्रेशन (WAHA)'
|
||||
app.inbox.contact.avatar.url: 'https://raw.githubusercontent.com/devlikeapro/waha/core/logo.png'
|
||||
|
||||
JOB_ERROR_REPORT: |
|
||||
job.report.error: |-
|
||||
⚠️ **{{{header}}}**
|
||||
{{#attempts.nextDelay}}
|
||||
🔄 {{attempts.nextDelay}} सेकंड में पुनः प्रयास कर रहा है...
|
||||
@@ -18,51 +20,52 @@ JOB_ERROR_REPORT: |
|
||||
```
|
||||
{{/error}}
|
||||
|
||||
JOB_SUCCEEDED_REPORT: |
|
||||
job.report.succeeded: |-
|
||||
✅ **सफल**
|
||||
प्रयास: {{{attempts.current}}} / {{{attempts.max}}}
|
||||
विवरण: [{{{details.text}}}]({{{details.url}}})
|
||||
|
||||
WHATSAPP_ERROR_SENDING_MESSAGE: व्हाट्सएप पर संदेश नहीं भेज सका।
|
||||
WHATSAPP_ERROR_RECEIVING_MESSAGE: व्हाट्सएप से संदेश प्राप्त नहीं कर सका
|
||||
WHATSAPP_ERROR_REMOVING_MESSAGE: व्हाट्सएप से संदेश हटा नहीं सका
|
||||
APP_SCHEDULED_JOB_ERROR: निर्धारित कार्य निष्पादित करने में विफल रहा
|
||||
whatsapp.message.sending.error: व्हाट्सएप पर संदेश नहीं भेज सका।
|
||||
whatsapp.message.receiving.error: व्हाट्सएप से संदेश प्राप्त नहीं कर सका
|
||||
whatsapp.message.removing.error: व्हाट्सएप से संदेश हटा नहीं सका
|
||||
job.scheduled.error.header: निर्धारित कार्य निष्पादित करने में विफल रहा
|
||||
|
||||
MESSAGE_FROM_WHATSAPP: |
|
||||
message.from.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *व्हाट्सएप से भेजा गया*
|
||||
|
||||
MESSAGE_FROM_API: |
|
||||
message.from.api: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *API के माध्यम से भेजा गया*
|
||||
|
||||
MESSAGE_REMOVED_IN_WHATSAPP: |
|
||||
message.removed.in.whatsapp: |-
|
||||
❌ *यह संदेश व्हाट्सएप में हटा दिया गया था*
|
||||
|
||||
MESSAGE_EDITED_IN_WHATSAPP: |
|
||||
message.edited.in.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
✏️ *व्हाट्सएप में संपादित*
|
||||
|
||||
WHATSAPP_GROUP_MESSAGE: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.group.message: |-
|
||||
👥 *{{{participant}}}*
|
||||
|
||||
WHATSAPP_REACTION_ADDED: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.reaction.added: |-
|
||||
*प्रतिक्रिया दी* {{{emoji}}}
|
||||
|
||||
WHATSAPP_REACTION_REMOVED: |
|
||||
whatsapp.reaction.removed: |-
|
||||
*प्रतिक्रिया हटा दी गई*
|
||||
|
||||
WHATSAPP_CONTACT_GROUP_SUFFIX: 'समूह'
|
||||
WHATSAPP_CONTACT_CHANNEL_SUFFIX: 'चैनल'
|
||||
whatsapp.contact.group.suffix: 'समूह'
|
||||
whatsapp.contact.channel.suffix: 'चैनल'
|
||||
whatsapp.contact.broadcast.suffix: 'प्रसारण सूची'
|
||||
# Aka Stories
|
||||
WHATSAPP_CONTACT_STATUS_NAME: 'स्थिति'
|
||||
whatsapp.contact.status.name: 'स्थिति'
|
||||
|
||||
APP_CONNECTED_MESSAGE: |
|
||||
app.connected.message: |-
|
||||
🔗 **कनेक्टेड: व्हाट्सएप सत्र से ChatWoot इनबॉक्स**
|
||||
|
||||
✅ व्हाट्सएप सत्र **{{{name}}}** सफलतापूर्वक इस ChatWoot इनबॉक्स से जुड़ गया है।
|
||||
@@ -80,7 +83,7 @@ APP_CONNECTED_MESSAGE: |
|
||||
|
||||
चलिए शुरू करते हैं! 🚀
|
||||
|
||||
APP_DISCONNECTED_MESSAGE: |
|
||||
app.disconnected.message: |-
|
||||
🔌 **डिस्कनेक्टेड: व्हाट्सएप सत्र से ChatWoot इनबॉक्स**
|
||||
|
||||
❌ व्हाट्सएप सत्र **{{{name}}}** इस ChatWoot इनबॉक्स से डिस्कनेक्ट हो गया है।
|
||||
@@ -89,15 +92,15 @@ APP_DISCONNECTED_MESSAGE: |
|
||||
|
||||
फिर से कनेक्ट करने के लिए, कृपया अपने प्रशासक से संपर्क करें।
|
||||
|
||||
APP_UPDATED_MESSAGE: |
|
||||
app.updated.message: |-
|
||||
🔄 **अपडेटेड: व्हाट्सएप सत्र सेटिंग्स**
|
||||
|
||||
✅ व्हाट्सएप सत्र **{{{name}}}** की सेटिंग्स अपडेट की गई हैं।
|
||||
|
||||
APP_COMMANDS_LIST: |
|
||||
app.commands.list: |-
|
||||
आप निम्न कमांड में से एक भेजकर **व्हाट्सएप इंटीग्रेशन** का प्रबंधन कर सकते हैं:
|
||||
|
||||
🖥️ सत्र:
|
||||
🖥️ **सेशन**:
|
||||
1. **status** - वर्तमान सत्र स्थिति प्राप्त करें।
|
||||
2. **restart** - सत्र को पुनरारंभ करें - यह आपके व्हाट्सएप खाते को फिर से कनेक्ट करने का प्रयास करेगा।
|
||||
3. **start** - सत्र शुरू करें।
|
||||
@@ -107,42 +110,47 @@ APP_COMMANDS_LIST: |
|
||||
7. **screenshot** - सत्र का स्क्रीनशॉट प्राप्त करें (केवल **WEBJS** इंजन में उपलब्ध)।
|
||||
8. **help** - उपलब्ध कमांड।
|
||||
|
||||
{{#commands.server}}
|
||||
⚙️ सर्वर:
|
||||
- **server status** - सर्वर संस्करण और स्थिति जानकारी प्राप्त करें।
|
||||
- **server reboot** - सर्वर को सुचारू रूप से पुनरारंभ करें।
|
||||
- **server reboot force** - सर्वर को जबरदस्ती पुनरारंभ करें।
|
||||
{{/commands.server}}
|
||||
|
||||
इस वार्तालाप में **कमांड** (केस इनसेंसिटिव) या **कमांड नंबर** भेजें।
|
||||
|
||||
APP_HELP_REMINDER: |
|
||||
app.commands.server.disabled: ⛔ **सर्वर कमांड अक्षम हैं**।
|
||||
|
||||
कृपया अपने व्यवस्थापक से संपर्क करें।
|
||||
|
||||
उपलब्ध कमांड की सूची पाने के लिए **help** भेजें।
|
||||
|
||||
app.help.reminder: |-
|
||||
उपलब्ध कमांड की सूची प्राप्त करने के लिए **help** भेजें।
|
||||
|
||||
APP_SESSION_STATUS_CHANGE: |
|
||||
app.session.status.change: |-
|
||||
{{{emoji}}} "{{{session}}}" सत्र {{{status}}} स्थिति में बदल गया
|
||||
|
||||
APP_SESSION_CURRENT_STATUS: |
|
||||
app.session.current.status: |-
|
||||
{{{emoji}}} **{{{session}}}** सत्र की स्थिति **{{{status}}}** में है
|
||||
**व्हाट्सएप खाता:**
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_DASHBOARD_LINK: |
|
||||
अधिक जानकारी के लिए [WAHA डैशबोर्ड]({{{url}}}) पर जाएं।
|
||||
|
||||
APP_SESSION_STATUS_WORKING: |
|
||||
app.session.status.working: |-
|
||||
✅ यह ChatWoot इनबॉक्स **व्हाट्सएप खाते** से जुड़ा हुआ है और संदेश भेजने और प्राप्त करने के लिए तैयार है!
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_SESSION_STATUS_ERROR: |
|
||||
app.session.status.error: |-
|
||||
⚠️ **यह ChatWoot इनबॉक्स व्हाट्सएप खाते से जुड़ा हुआ है लेकिन संदेश भेजने और प्राप्त करने के लिए तैयार नहीं है!**
|
||||
|
||||
कृपया सत्र की स्थिति जांचें और इसे पुनरारंभ करने का प्रयास करें या लॉग आउट करें और QR कोड फिर से स्कैन करें।
|
||||
|
||||
APP_SESSION_SCAN_QR_CODE: |
|
||||
app.session.scan.qr.code: |-
|
||||
⚠️ **इस ChatWoot इनबॉक्स के साथ व्हाट्सएप खाता जोड़ने के लिए अपने फोन पर QR कोड स्कैन करें!**
|
||||
|
||||
APP_SERVER_VERSION_AND_STATUS: |
|
||||
app.server.version.and.status: |-
|
||||
**संस्करण:**
|
||||
```
|
||||
{{{version}}}
|
||||
@@ -153,16 +161,16 @@ APP_SERVER_VERSION_AND_STATUS: |
|
||||
{{{status}}}
|
||||
```
|
||||
|
||||
APP_SERVER_REBOOT: |
|
||||
app.server.reboot: |-
|
||||
सर्वर सुचारू रूप से पुनरारंभ हो रहा है...
|
||||
|
||||
APP_SERVER_REBOOT_FORCE: |
|
||||
app.server.reboot.force: |-
|
||||
सर्वर जबरदस्ती पुनरारंभ हो रहा है...
|
||||
|
||||
APP_LOGOUT_SUCCESS: |
|
||||
app.logout.success: |-
|
||||
✅ खाता सफलतापूर्वक अनधिकृत किया गया!
|
||||
|
||||
APP_NEW_VERSION_AVAILABLE: |
|
||||
waha.new.version.available: |-
|
||||
🔄 **नया संस्करण उपलब्ध!**
|
||||
|
||||
वर्तमान संस्करण: **{{{currentVersion}}}**
|
||||
@@ -170,7 +178,7 @@ APP_NEW_VERSION_AVAILABLE: |
|
||||
|
||||
👉 [**🆕 चेंजलॉग**]({{{changelogUrl}}}) में क्या नया है देखें
|
||||
|
||||
APP_CORE_VERSION_USED: |
|
||||
waha.core.version.used: |-
|
||||
❤️ **WAHA का समर्थन करें!**
|
||||
|
||||
आप मुफ्त **WAHA Core** संस्करण का उपयोग कर रहे हैं। यदि आपको यह प्रोजेक्ट उपयोगी लगता है, तो कृपया इसके विकास का समर्थन करने पर विचार करें।
|
||||
@@ -178,3 +186,51 @@ APP_CORE_VERSION_USED: |
|
||||
आपका समर्थन ही एकमात्र तरीका है जिससे हम अपडेट, फिक्स और नई सुविधाओं पर काम करना जारी रख सकते हैं।
|
||||
|
||||
[**🎁 हमें समर्थन दें**]({{{supportUrl}}})
|
||||
|
||||
chatwoot.to.whatsapp.message.text: |-
|
||||
{{{ content }}}
|
||||
|
||||
chatwoot.to.whatsapp.message.media.caption: |-
|
||||
{{#singleAttachment}}
|
||||
{{#content}}
|
||||
{{{ content }}}
|
||||
{{/content}}
|
||||
{{/singleAttachment}}
|
||||
|
||||
whatsapp.to.chatwoot.message: |-
|
||||
{{{payload.body}}}
|
||||
|
||||
whatsapp.to.chatwoot.message.contacts: |-
|
||||
👤 **साझा संपर्क**
|
||||
|
||||
{{#contacts}}
|
||||
🪪 नाम: **{{fullName}}**
|
||||
{{#phoneNumbers}}
|
||||
- 📞 फ़ोन: **{{.}}**
|
||||
{{/phoneNumbers}}
|
||||
|
||||
{{/contacts}}
|
||||
|
||||
whatsapp.to.chatwoot.message.location: |-
|
||||
{{#message}}
|
||||
{{#locationMessage}}
|
||||
📍 **साझा स्थान**
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/locationMessage}}
|
||||
|
||||
{{#liveLocationMessage}}
|
||||
📍📡 **लाइव लोकेशन साझा की जा रही है**
|
||||
रीयल-टाइम अपडेट देखने के लिए **WhatsApp** खोलें।
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/liveLocationMessage}}
|
||||
{{/message}}
|
||||
|
||||
whatsapp.to.chatwoot.message.unsupported: |-
|
||||
⚠️ **इस प्रकार का संदेश ChatWoot में समर्थित नहीं है।**
|
||||
📱 इसे देखने के लिए कृपया **WhatsApp** खोलें।
|
||||
|
||||
विवरण: [{{{details.text}}}]({{{details.url}}})
|
||||
@@ -1,7 +1,9 @@
|
||||
# Indonesian translations for ChatWoot integration
|
||||
APP_INBOX_CONTACT_NAME: 'Integrasi WhatsApp (WAHA)'
|
||||
locale.name: '🇮🇩 Bahasa Indonesia (Indonesian)'
|
||||
app.inbox.contact.name: 'Integrasi WhatsApp (WAHA)'
|
||||
app.inbox.contact.avatar.url: 'https://raw.githubusercontent.com/devlikeapro/waha/core/logo.png'
|
||||
|
||||
JOB_ERROR_REPORT: |
|
||||
job.report.error: |-
|
||||
⚠️ **{{{header}}}**
|
||||
{{#attempts.nextDelay}}
|
||||
🔄 Mencoba lagi dalam {{attempts.nextDelay}} detik...
|
||||
@@ -18,51 +20,52 @@ JOB_ERROR_REPORT: |
|
||||
```
|
||||
{{/error}}
|
||||
|
||||
JOB_SUCCEEDED_REPORT: |
|
||||
job.report.succeeded: |-
|
||||
✅ **Berhasil**
|
||||
Percobaan: {{{attempts.current}}} / {{{attempts.max}}}
|
||||
Detail: [{{{details.text}}}]({{{details.url}}})
|
||||
|
||||
WHATSAPP_ERROR_SENDING_MESSAGE: Tidak dapat mengirim pesan di WhatsApp.
|
||||
WHATSAPP_ERROR_RECEIVING_MESSAGE: Tidak dapat menerima pesan dari WhatsApp
|
||||
WHATSAPP_ERROR_REMOVING_MESSAGE: Tidak dapat menghapus pesan dari WhatsApp
|
||||
APP_SCHEDULED_JOB_ERROR: Tugas terjadwal gagal dijalankan
|
||||
whatsapp.message.sending.error: Tidak dapat mengirim pesan di WhatsApp.
|
||||
whatsapp.message.receiving.error: Tidak dapat menerima pesan dari WhatsApp
|
||||
whatsapp.message.removing.error: Tidak dapat menghapus pesan dari WhatsApp
|
||||
job.scheduled.error.header: Tugas terjadwal gagal dijalankan
|
||||
|
||||
MESSAGE_FROM_WHATSAPP: |
|
||||
message.from.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *Dikirim dari WhatsApp*
|
||||
|
||||
MESSAGE_FROM_API: |
|
||||
message.from.api: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *Dikirim melalui API*
|
||||
|
||||
MESSAGE_REMOVED_IN_WHATSAPP: |
|
||||
message.removed.in.whatsapp: |-
|
||||
❌ *Pesan ini telah dihapus di WhatsApp*
|
||||
|
||||
MESSAGE_EDITED_IN_WHATSAPP: |
|
||||
message.edited.in.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
✏️ *Diedit di WhatsApp*
|
||||
|
||||
WHATSAPP_GROUP_MESSAGE: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.group.message: |-
|
||||
👥 *{{{participant}}}*
|
||||
|
||||
WHATSAPP_REACTION_ADDED: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.reaction.added: |-
|
||||
*Bereaksi* {{{emoji}}}
|
||||
|
||||
WHATSAPP_REACTION_REMOVED: |
|
||||
whatsapp.reaction.removed: |-
|
||||
*Reaksi dihapus*
|
||||
|
||||
WHATSAPP_CONTACT_GROUP_SUFFIX: 'Grup'
|
||||
WHATSAPP_CONTACT_CHANNEL_SUFFIX: 'Saluran'
|
||||
whatsapp.contact.group.suffix: 'Grup'
|
||||
whatsapp.contact.channel.suffix: 'Saluran'
|
||||
whatsapp.contact.broadcast.suffix: 'Daftar Siaran'
|
||||
# Aka Stories
|
||||
WHATSAPP_CONTACT_STATUS_NAME: 'Status'
|
||||
whatsapp.contact.status.name: 'Status'
|
||||
|
||||
APP_CONNECTED_MESSAGE: |
|
||||
app.connected.message: |-
|
||||
🔗 **TERHUBUNG: Sesi WhatsApp ke Kotak Masuk ChatWoot**
|
||||
|
||||
✅ Sesi WhatsApp **{{{name}}}** telah berhasil terhubung ke Kotak Masuk ChatWoot ini.
|
||||
@@ -80,7 +83,7 @@ APP_CONNECTED_MESSAGE: |
|
||||
|
||||
Mari kita mulai! 🚀
|
||||
|
||||
APP_DISCONNECTED_MESSAGE: |
|
||||
app.disconnected.message: |-
|
||||
🔌 **TERPUTUS: Sesi WhatsApp dari Kotak Masuk ChatWoot**
|
||||
|
||||
❌ Sesi WhatsApp **{{{name}}}** telah terputus dari Kotak Masuk ChatWoot ini.
|
||||
@@ -89,15 +92,15 @@ APP_DISCONNECTED_MESSAGE: |
|
||||
|
||||
Untuk menghubungkan kembali, silakan hubungi administrator Anda.
|
||||
|
||||
APP_UPDATED_MESSAGE: |
|
||||
app.updated.message: |-
|
||||
🔄 **DIPERBARUI: Pengaturan Sesi WhatsApp**
|
||||
|
||||
✅ Pengaturan untuk sesi WhatsApp **{{{name}}}** telah diperbarui.
|
||||
|
||||
APP_COMMANDS_LIST: |
|
||||
app.commands.list: |-
|
||||
Anda dapat mengelola **Integrasi WhatsApp** dengan mengirimkan salah satu perintah berikut:
|
||||
|
||||
🖥️ Sesi:
|
||||
🖥️ **Sesi**:
|
||||
1. **status** - dapatkan status sesi saat ini.
|
||||
2. **restart** - mulai ulang sesi - ini akan mencoba menghubungkan kembali akun WhatsApp Anda.
|
||||
3. **start** - mulai sesi.
|
||||
@@ -107,42 +110,47 @@ APP_COMMANDS_LIST: |
|
||||
7. **screenshot** - dapatkan tangkapan layar sesi (hanya tersedia di mesin **WEBJS**).
|
||||
8. **help** - perintah yang tersedia.
|
||||
|
||||
{{#commands.server}}
|
||||
⚙️ Server:
|
||||
- **server status** - dapatkan informasi versi dan status server.
|
||||
- **server reboot** - mulai ulang server dengan anggun.
|
||||
- **server reboot force** - paksa mulai ulang server.
|
||||
{{/commands.server}}
|
||||
|
||||
Kirim **perintah** (tidak peka huruf besar/kecil) atau **nomor perintah** ke percakapan ini.
|
||||
|
||||
APP_HELP_REMINDER: |
|
||||
app.commands.server.disabled: ⛔ **Perintah server dinonaktifkan**.
|
||||
|
||||
Silakan hubungi administrator Anda.
|
||||
|
||||
Kirim **help** untuk melihat daftar perintah yang tersedia.
|
||||
|
||||
app.help.reminder: |-
|
||||
Kirim **help** untuk mendapatkan daftar perintah yang tersedia.
|
||||
|
||||
APP_SESSION_STATUS_CHANGE: |
|
||||
app.session.status.change: |-
|
||||
{{{emoji}}} Sesi "{{{session}}}" beralih ke status {{{status}}}
|
||||
|
||||
APP_SESSION_CURRENT_STATUS: |
|
||||
app.session.current.status: |-
|
||||
{{{emoji}}} Status sesi **{{{session}}}** adalah **{{{status}}}**
|
||||
**Akun WhatsApp:**
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_DASHBOARD_LINK: |
|
||||
Kunjungi [Dasbor WAHA]({{{url}}}) untuk detail lebih lanjut.
|
||||
|
||||
APP_SESSION_STATUS_WORKING: |
|
||||
app.session.status.working: |-
|
||||
✅ Kotak Masuk ChatWoot ini terhubung ke **Akun WhatsApp** dan siap untuk mengirim dan menerima pesan!
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_SESSION_STATUS_ERROR: |
|
||||
app.session.status.error: |-
|
||||
⚠️ **Kotak Masuk ChatWoot ini terhubung ke Akun WhatsApp tetapi TIDAK siap untuk mengirim dan menerima pesan!**
|
||||
|
||||
Silakan periksa status sesi dan coba mulai ulang atau keluar dan pindai kode QR lagi.
|
||||
|
||||
APP_SESSION_SCAN_QR_CODE: |
|
||||
app.session.scan.qr.code: |-
|
||||
⚠️ **Pindai kode QR di ponsel Anda untuk menghubungkan Akun WhatsApp dengan Kotak Masuk ChatWoot ini!**
|
||||
|
||||
APP_SERVER_VERSION_AND_STATUS: |
|
||||
app.server.version.and.status: |-
|
||||
**Versi:**
|
||||
```
|
||||
{{{version}}}
|
||||
@@ -153,16 +161,16 @@ APP_SERVER_VERSION_AND_STATUS: |
|
||||
{{{status}}}
|
||||
```
|
||||
|
||||
APP_SERVER_REBOOT: |
|
||||
app.server.reboot: |-
|
||||
Server sedang dimulai ulang dengan anggun...
|
||||
|
||||
APP_SERVER_REBOOT_FORCE: |
|
||||
app.server.reboot.force: |-
|
||||
Server sedang dipaksa untuk dimulai ulang...
|
||||
|
||||
APP_LOGOUT_SUCCESS: |
|
||||
app.logout.success: |-
|
||||
✅ Akun berhasil tidak diotorisasi!
|
||||
|
||||
APP_NEW_VERSION_AVAILABLE: |
|
||||
waha.new.version.available: |-
|
||||
🔄 **Versi Baru Tersedia!**
|
||||
|
||||
Versi saat ini: **{{{currentVersion}}}**
|
||||
@@ -170,7 +178,7 @@ APP_NEW_VERSION_AVAILABLE: |
|
||||
|
||||
👉 Lihat apa yang baru di [**🆕 Changelog**]({{{changelogUrl}}})
|
||||
|
||||
APP_CORE_VERSION_USED: |
|
||||
waha.core.version.used: |-
|
||||
❤️ **Dukung WAHA!**
|
||||
|
||||
Anda menggunakan versi **WAHA Core** gratis. Jika Anda merasa proyek ini bermanfaat, harap pertimbangkan untuk mendukung pengembangannya.
|
||||
@@ -178,3 +186,51 @@ APP_CORE_VERSION_USED: |
|
||||
Dukungan Anda adalah satu-satunya cara kami dapat terus bekerja pada pembaruan, perbaikan, dan fitur baru.
|
||||
|
||||
[**🎁 Dukung Kami**]({{{supportUrl}}})
|
||||
|
||||
chatwoot.to.whatsapp.message.text: |-
|
||||
{{{ content }}}
|
||||
|
||||
chatwoot.to.whatsapp.message.media.caption: |-
|
||||
{{#singleAttachment}}
|
||||
{{#content}}
|
||||
{{{ content }}}
|
||||
{{/content}}
|
||||
{{/singleAttachment}}
|
||||
|
||||
whatsapp.to.chatwoot.message: |-
|
||||
{{{payload.body}}}
|
||||
|
||||
whatsapp.to.chatwoot.message.contacts: |-
|
||||
👤 **Kontak yang dibagikan**
|
||||
|
||||
{{#contacts}}
|
||||
🪪 Nama: **{{fullName}}**
|
||||
{{#phoneNumbers}}
|
||||
- 📞 Telepon: **{{.}}**
|
||||
{{/phoneNumbers}}
|
||||
|
||||
{{/contacts}}
|
||||
|
||||
whatsapp.to.chatwoot.message.location: |-
|
||||
{{#message}}
|
||||
{{#locationMessage}}
|
||||
📍 **Lokasi yang dibagikan**
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/locationMessage}}
|
||||
|
||||
{{#liveLocationMessage}}
|
||||
📍📡 **Berbagi Lokasi Langsung**
|
||||
Buka **WhatsApp** untuk melihat pembaruan waktu nyata.
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/liveLocationMessage}}
|
||||
{{/message}}
|
||||
|
||||
whatsapp.to.chatwoot.message.unsupported: |-
|
||||
⚠️ **Jenis pesan ini tidak didukung di ChatWoot.**
|
||||
📱 Silakan buka **WhatsApp** untuk melihatnya.
|
||||
|
||||
Detail: [{{{details.text}}}]({{{details.url}}})
|
||||
@@ -1,7 +1,9 @@
|
||||
# Punjabi translations for ChatWoot integration
|
||||
APP_INBOX_CONTACT_NAME: 'ਵਟਸਐਪ ਇੰਟੀਗ੍ਰੇਸ਼ਨ (WAHA)'
|
||||
locale.name: '🇵🇰 ਪੰਜਾਬੀ (Punjabi)'
|
||||
app.inbox.contact.name: 'ਵਟਸਐਪ ਇੰਟੀਗ੍ਰੇਸ਼ਨ (WAHA)'
|
||||
app.inbox.contact.avatar.url: 'https://raw.githubusercontent.com/devlikeapro/waha/core/logo.png'
|
||||
|
||||
JOB_ERROR_REPORT: |
|
||||
job.report.error: |-
|
||||
⚠️ **{{{header}}}**
|
||||
{{#attempts.nextDelay}}
|
||||
🔄 {{attempts.nextDelay}} ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰ ਰਿਹਾ ਹੈ...
|
||||
@@ -18,51 +20,52 @@ JOB_ERROR_REPORT: |
|
||||
```
|
||||
{{/error}}
|
||||
|
||||
JOB_SUCCEEDED_REPORT: |
|
||||
job.report.succeeded: |-
|
||||
✅ **ਸਫਲ**
|
||||
ਕੋਸ਼ਿਸ਼: {{{attempts.current}}} / {{{attempts.max}}}
|
||||
ਵੇਰਵੇ: [{{{details.text}}}]({{{details.url}}})
|
||||
|
||||
WHATSAPP_ERROR_SENDING_MESSAGE: ਵਟਸਐਪ 'ਤੇ ਸੁਨੇਹਾ ਭੇਜ ਨਹੀਂ ਸਕਿਆ।
|
||||
WHATSAPP_ERROR_RECEIVING_MESSAGE: ਵਟਸਐਪ ਤੋਂ ਸੁਨੇਹਾ ਪ੍ਰਾਪਤ ਨਹੀਂ ਕਰ ਸਕਿਆ
|
||||
WHATSAPP_ERROR_REMOVING_MESSAGE: ਵਟਸਐਪ ਤੋਂ ਸੁਨੇਹਾ ਹਟਾ ਨਹੀਂ ਸਕਿਆ
|
||||
APP_SCHEDULED_JOB_ERROR: ਨਿਰਧਾਰਿਤ ਕੰਮ ਚਲਾਉਣ ਵਿੱਚ ਅਸਫਲ ਰਿਹਾ
|
||||
whatsapp.message.sending.error: ਵਟਸਐਪ 'ਤੇ ਸੁਨੇਹਾ ਭੇਜ ਨਹੀਂ ਸਕਿਆ।
|
||||
whatsapp.message.receiving.error: ਵਟਸਐਪ ਤੋਂ ਸੁਨੇਹਾ ਪ੍ਰਾਪਤ ਨਹੀਂ ਕਰ ਸਕਿਆ
|
||||
whatsapp.message.removing.error: ਵਟਸਐਪ ਤੋਂ ਸੁਨੇਹਾ ਹਟਾ ਨਹੀਂ ਸਕਿਆ
|
||||
job.scheduled.error.header: ਨਿਰਧਾਰਿਤ ਕੰਮ ਚਲਾਉਣ ਵਿੱਚ ਅਸਫਲ ਰਿਹਾ
|
||||
|
||||
MESSAGE_FROM_WHATSAPP: |
|
||||
message.from.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *ਵਟਸਐਪ ਤੋਂ ਭੇਜਿਆ ਗਿਆ*
|
||||
|
||||
MESSAGE_FROM_API: |
|
||||
message.from.api: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *API ਰਾਹੀਂ ਭੇਜਿਆ ਗਿਆ*
|
||||
|
||||
MESSAGE_REMOVED_IN_WHATSAPP: |
|
||||
message.removed.in.whatsapp: |-
|
||||
❌ *ਇਹ ਸੁਨੇਹਾ ਵਟਸਐਪ ਵਿੱਚ ਮਿਟਾ ਦਿੱਤਾ ਗਿਆ ਸੀ*
|
||||
|
||||
MESSAGE_EDITED_IN_WHATSAPP: |
|
||||
message.edited.in.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
✏️ *ਵਟਸਐਪ ਵਿੱਚ ਸੰਪਾਦਿਤ ਕੀਤਾ ਗਿਆ*
|
||||
|
||||
WHATSAPP_GROUP_MESSAGE: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.group.message: |-
|
||||
👥 *{{{participant}}}*
|
||||
|
||||
WHATSAPP_REACTION_ADDED: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.reaction.added: |-
|
||||
*ਪ੍ਰਤੀਕਿਰਿਆ ਕੀਤੀ* {{{emoji}}}
|
||||
|
||||
WHATSAPP_REACTION_REMOVED: |
|
||||
whatsapp.reaction.removed: |-
|
||||
*ਪ੍ਰਤੀਕਿਰਿਆ ਹਟਾਈ ਗਈ*
|
||||
|
||||
WHATSAPP_CONTACT_GROUP_SUFFIX: 'ਗਰੁੱਪ'
|
||||
WHATSAPP_CONTACT_CHANNEL_SUFFIX: 'ਚੈਨਲ'
|
||||
whatsapp.contact.group.suffix: 'ਗਰੁੱਪ'
|
||||
whatsapp.contact.channel.suffix: 'ਚੈਨਲ'
|
||||
whatsapp.contact.broadcast.suffix: 'ਪ੍ਰਸਾਰਣ ਸੂਚੀ'
|
||||
# Aka Stories
|
||||
WHATSAPP_CONTACT_STATUS_NAME: 'ਸਥਿਤੀ'
|
||||
whatsapp.contact.status.name: 'ਸਥਿਤੀ'
|
||||
|
||||
APP_CONNECTED_MESSAGE: |
|
||||
app.connected.message: |-
|
||||
🔗 **ਕਨੈਕਟ ਕੀਤਾ: ਵਟਸਐਪ ਸੈਸ਼ਨ ਤੋਂ ChatWoot ਇਨਬਾਕਸ**
|
||||
|
||||
✅ ਵਟਸਐਪ ਸੈਸ਼ਨ **{{{name}}}** ਨੂੰ ਸਫਲਤਾਪੂਰਵਕ ਇਸ ChatWoot ਇਨਬਾਕਸ ਨਾਲ ਜੋੜਿਆ ਗਿਆ ਹੈ।
|
||||
@@ -80,7 +83,7 @@ APP_CONNECTED_MESSAGE: |
|
||||
|
||||
ਆਓ ਸ਼ੁਰੂ ਕਰੀਏ! 🚀
|
||||
|
||||
APP_DISCONNECTED_MESSAGE: |
|
||||
app.disconnected.message: |-
|
||||
🔌 **ਡਿਸਕਨੈਕਟ ਕੀਤਾ: ਵਟਸਐਪ ਸੈਸ਼ਨ ਤੋਂ ChatWoot ਇਨਬਾਕਸ**
|
||||
|
||||
❌ ਵਟਸਐਪ ਸੈਸ਼ਨ **{{{name}}}** ਇਸ ChatWoot ਇਨਬਾਕਸ ਤੋਂ ਡਿਸਕਨੈਕਟ ਕੀਤਾ ਗਿਆ ਹੈ।
|
||||
@@ -89,15 +92,15 @@ APP_DISCONNECTED_MESSAGE: |
|
||||
|
||||
ਮੁੜ ਕਨੈਕਟ ਕਰਨ ਲਈ, ਕਿਰਪਾ ਕਰਕੇ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।
|
||||
|
||||
APP_UPDATED_MESSAGE: |
|
||||
app.updated.message: |-
|
||||
🔄 **ਅਪਡੇਟ ਕੀਤਾ: ਵਟਸਐਪ ਸੈਸ਼ਨ ਸੈਟਿੰਗਾਂ**
|
||||
|
||||
✅ ਵਟਸਐਪ ਸੈਸ਼ਨ **{{{name}}}** ਲਈ ਸੈਟਿੰਗਾਂ ਅਪਡੇਟ ਕੀਤੀਆਂ ਗਈਆਂ ਹਨ।
|
||||
|
||||
APP_COMMANDS_LIST: |
|
||||
app.commands.list: |-
|
||||
ਤੁਸੀਂ ਹੇਠਾਂ ਦਿੱਤੇ ਕਮਾਂਡਾਂ ਵਿੱਚੋਂ ਇੱਕ ਭੇਜ ਕੇ **ਵਟਸਐਪ ਇੰਟੀਗ੍ਰੇਸ਼ਨ** ਦਾ ਪ੍ਰਬੰਧਨ ਕਰ ਸਕਦੇ ਹੋ:
|
||||
|
||||
🖥️ ਸੈਸ਼ਨ:
|
||||
🖥️ **ਸੈਸ਼ਨ**:
|
||||
1. **status** - ਮੌਜੂਦਾ ਸੈਸ਼ਨ ਸਥਿਤੀ ਪ੍ਰਾਪਤ ਕਰੋ।
|
||||
2. **restart** - ਸੈਸ਼ਨ ਮੁੜ ਚਾਲੂ ਕਰੋ - ਇਹ ਤੁਹਾਡੇ ਵਟਸਐਪ ਖਾਤੇ ਨੂੰ ਮੁੜ ਕਨੈਕਟ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੇਗਾ।
|
||||
3. **start** - ਸੈਸ਼ਨ ਸ਼ੁਰੂ ਕਰੋ।
|
||||
@@ -107,42 +110,47 @@ APP_COMMANDS_LIST: |
|
||||
7. **screenshot** - ਸੈਸ਼ਨ ਦਾ ਸਕ੍ਰੀਨਸ਼ਾਟ ਪ੍ਰਾਪਤ ਕਰੋ (ਸਿਰਫ **WEBJS** ਇੰਜਣ ਵਿੱਚ ਉਪਲਬਧ)।
|
||||
8. **help** - ਉਪਲਬਧ ਕਮਾਂਡਾਂ।
|
||||
|
||||
{{#commands.server}}
|
||||
⚙️ ਸਰਵਰ:
|
||||
- **server status** - ਸਰਵਰ ਵਰਜਨ ਅਤੇ ਸਥਿਤੀ ਜਾਣਕਾਰੀ ਪ੍ਰਾਪਤ ਕਰੋ।
|
||||
- **server reboot** - ਸਰਵਰ ਨੂੰ ਸੁਚਾਰੂ ਢੰਗ ਨਾਲ ਮੁੜ ਚਾਲੂ ਕਰੋ।
|
||||
- **server reboot force** - ਸਰਵਰ ਨੂੰ ਜ਼ਬਰਦਸਤੀ ਮੁੜ ਚਾਲੂ ਕਰੋ।
|
||||
{{/commands.server}}
|
||||
|
||||
ਇਸ ਗੱਲਬਾਤ ਵਿੱਚ **ਕਮਾਂਡ** (ਕੇਸ ਇਨਸੈਂਸਿਟਿਵ) ਜਾਂ **ਕਮਾਂਡ ਨੰਬਰ** ਭੇਜੋ।
|
||||
|
||||
APP_HELP_REMINDER: |
|
||||
app.commands.server.disabled: ⛔ **ਸਰਵਰ ਕਮਾਂਡ ਅਯੋਗ ਹਨ**।
|
||||
|
||||
ਕਿਰਪਾ ਕਰਕੇ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।
|
||||
|
||||
ਉਪਲਬਧ ਕਮਾਂਡਾਂ ਦੀ ਸੂਚੀ ਲਈ **help** ਭੇਜੋ।
|
||||
|
||||
app.help.reminder: |-
|
||||
ਉਪਲਬਧ ਕਮਾਂਡਾਂ ਦੀ ਸੂਚੀ ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ **help** ਭੇਜੋ।
|
||||
|
||||
APP_SESSION_STATUS_CHANGE: |
|
||||
app.session.status.change: |-
|
||||
{{{emoji}}} "{{{session}}}" ਸੈਸ਼ਨ {{{status}}} ਸਥਿਤੀ 'ਤੇ ਬਦਲ ਗਿਆ
|
||||
|
||||
APP_SESSION_CURRENT_STATUS: |
|
||||
app.session.current.status: |-
|
||||
{{{emoji}}} **{{{session}}}** ਸੈਸ਼ਨ ਸਥਿਤੀ **{{{status}}}** ਵਿੱਚ ਹੈ
|
||||
**ਵਟਸਐਪ ਖਾਤਾ:**
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_DASHBOARD_LINK: |
|
||||
ਵਧੇਰੇ ਵੇਰਵਿਆਂ ਲਈ [WAHA ਡੈਸ਼ਬੋਰਡ]({{{url}}}) 'ਤੇ ਜਾਓ।
|
||||
|
||||
APP_SESSION_STATUS_WORKING: |
|
||||
app.session.status.working: |-
|
||||
✅ ਇਹ ChatWoot ਇਨਬਾਕਸ **ਵਟਸਐਪ ਖਾਤੇ** ਨਾਲ ਜੁੜਿਆ ਹੋਇਆ ਹੈ ਅਤੇ ਸੁਨੇਹੇ ਭੇਜਣ ਅਤੇ ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ ਤਿਆਰ ਹੈ!
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_SESSION_STATUS_ERROR: |
|
||||
app.session.status.error: |-
|
||||
⚠️ **ਇਹ ChatWoot ਇਨਬਾਕਸ ਵਟਸਐਪ ਖਾਤੇ ਨਾਲ ਜੁੜਿਆ ਹੋਇਆ ਹੈ ਪਰ ਸੁਨੇਹੇ ਭੇਜਣ ਅਤੇ ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ ਤਿਆਰ ਨਹੀਂ ਹੈ!**
|
||||
|
||||
ਕਿਰਪਾ ਕਰਕੇ ਸੈਸ਼ਨ ਸਥਿਤੀ ਦੀ ਜਾਂਚ ਕਰੋ ਅਤੇ ਇਸਨੂੰ ਮੁੜ ਚਾਲੂ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੋ ਜਾਂ ਲੌਗਆਉਟ ਕਰੋ ਅਤੇ QR ਕੋਡ ਦੁਬਾਰਾ ਸਕੈਨ ਕਰੋ।
|
||||
|
||||
APP_SESSION_SCAN_QR_CODE: |
|
||||
app.session.scan.qr.code: |-
|
||||
⚠️ **ਵਟਸਐਪ ਖਾਤੇ ਨੂੰ ਇਸ ChatWoot ਇਨਬਾਕਸ ਨਾਲ ਜੋੜਨ ਲਈ ਆਪਣੇ ਫੋਨ 'ਤੇ QR ਕੋਡ ਸਕੈਨ ਕਰੋ!**
|
||||
|
||||
APP_SERVER_VERSION_AND_STATUS: |
|
||||
app.server.version.and.status: |-
|
||||
**ਵਰਜਨ:**
|
||||
```
|
||||
{{{version}}}
|
||||
@@ -153,16 +161,16 @@ APP_SERVER_VERSION_AND_STATUS: |
|
||||
{{{status}}}
|
||||
```
|
||||
|
||||
APP_SERVER_REBOOT: |
|
||||
app.server.reboot: |-
|
||||
ਸਰਵਰ ਸੁਚਾਰੂ ਢੰਗ ਨਾਲ ਮੁੜ ਚਾਲੂ ਹੋ ਰਿਹਾ ਹੈ...
|
||||
|
||||
APP_SERVER_REBOOT_FORCE: |
|
||||
app.server.reboot.force: |-
|
||||
ਸਰਵਰ ਜ਼ਬਰਦਸਤੀ ਮੁੜ ਚਾਲੂ ਹੋ ਰਿਹਾ ਹੈ...
|
||||
|
||||
APP_LOGOUT_SUCCESS: |
|
||||
app.logout.success: |-
|
||||
✅ ਖਾਤਾ ਸਫਲਤਾਪੂਰਵਕ ਅਣਅਧਿਕਾਰਤ ਕੀਤਾ ਗਿਆ!
|
||||
|
||||
APP_NEW_VERSION_AVAILABLE: |
|
||||
waha.new.version.available: |-
|
||||
🔄 **ਨਵਾਂ ਵਰਜਨ ਉਪਲਬਧ!**
|
||||
|
||||
ਮੌਜੂਦਾ ਵਰਜਨ: **{{{currentVersion}}}**
|
||||
@@ -170,7 +178,7 @@ APP_NEW_VERSION_AVAILABLE: |
|
||||
|
||||
👉 [**🆕 ਬਦਲਾਅ ਲੌਗ**]({{{changelogUrl}}}) ਵਿੱਚ ਨਵਾਂ ਕੀ ਹੈ ਦੇਖੋ
|
||||
|
||||
APP_CORE_VERSION_USED: |
|
||||
waha.core.version.used: |-
|
||||
❤️ **WAHA ਦਾ ਸਮਰਥਨ ਕਰੋ!**
|
||||
|
||||
ਤੁਸੀਂ ਮੁਫਤ **WAHA Core** ਵਰਜਨ ਦੀ ਵਰਤੋਂ ਕਰ ਰਹੇ ਹੋ। ਜੇ ਤੁਹਾਨੂੰ ਇਹ ਪ੍ਰੋਜੈਕਟ ਲਾਭਦਾਇਕ ਲੱਗਦਾ ਹੈ, ਤਾਂ ਕਿਰਪਾ ਕਰਕੇ ਇਸਦੇ ਵਿਕਾਸ ਦਾ ਸਮਰਥਨ ਕਰਨ 'ਤੇ ਵਿਚਾਰ ਕਰੋ।
|
||||
@@ -178,3 +186,51 @@ APP_CORE_VERSION_USED: |
|
||||
ਤੁਹਾਡਾ ਸਮਰਥਨ ਹੀ ਇੱਕੋ ਇੱਕ ਤਰੀਕਾ ਹੈ ਜਿਸ ਨਾਲ ਅਸੀਂ ਅਪਡੇਟਾਂ, ਫਿਕਸਾਂ, ਅਤੇ ਨਵੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ 'ਤੇ ਕੰਮ ਕਰਨਾ ਜਾਰੀ ਰੱਖ ਸਕਦੇ ਹਾਂ।
|
||||
|
||||
[**🎁 ਸਾਡਾ ਸਮਰਥਨ ਕਰੋ**]({{{supportUrl}}})
|
||||
|
||||
chatwoot.to.whatsapp.message.text: |-
|
||||
{{{ content }}}
|
||||
|
||||
chatwoot.to.whatsapp.message.media.caption: |-
|
||||
{{#singleAttachment}}
|
||||
{{#content}}
|
||||
{{{ content }}}
|
||||
{{/content}}
|
||||
{{/singleAttachment}}
|
||||
|
||||
whatsapp.to.chatwoot.message: |-
|
||||
{{{payload.body}}}
|
||||
|
||||
whatsapp.to.chatwoot.message.contacts: |-
|
||||
👤 **ਸਾਂਝੇ ਕੀਤੇ ਸੰਪਰਕ**
|
||||
|
||||
{{#contacts}}
|
||||
🪪 ਨਾਮ: **{{fullName}}**
|
||||
{{#phoneNumbers}}
|
||||
- 📞 ਫ਼ੋਨ: **{{.}}**
|
||||
{{/phoneNumbers}}
|
||||
|
||||
{{/contacts}}
|
||||
|
||||
whatsapp.to.chatwoot.message.location: |-
|
||||
{{#message}}
|
||||
{{#locationMessage}}
|
||||
📍 **ਸਾਂਝੀ ਸਥਿਤੀ**
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/locationMessage}}
|
||||
|
||||
{{#liveLocationMessage}}
|
||||
📍📡 **ਲਾਈਵ ਸਥਿਤੀ ਸਾਂਝੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ**
|
||||
ਰੀਅਲ-ਟਾਈਮ ਅੱਪਡੇਟ ਦੇਖਣ ਲਈ **WhatsApp** ਖੋਲ੍ਹੋ।
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/liveLocationMessage}}
|
||||
{{/message}}
|
||||
|
||||
whatsapp.to.chatwoot.message.unsupported: |-
|
||||
⚠️ **ਇਹ ਸੁਨੇਹੇ ਦੀ ਕਿਸਮ ChatWoot ਵਿੱਚ ਸਮਰਥਿਤ ਨਹੀਂ ਹੈ।**
|
||||
📱 ਇਸਨੂੰ ਦੇਖਣ ਲਈ ਕਿਰਪਾ ਕਰਕੇ **WhatsApp** ਖੋਲ੍ਹੋ।
|
||||
|
||||
ਵੇਰਵੇ: [{{{details.text}}}]({{{details.url}}})
|
||||
@@ -1,7 +1,9 @@
|
||||
# Portuguese translations for ChatWoot integration
|
||||
APP_INBOX_CONTACT_NAME: 'Integração WhatsApp (WAHA)'
|
||||
locale.name: '🇧🇷🇵🇹 Português (Portuguese)'
|
||||
app.inbox.contact.name: 'Integração WhatsApp (WAHA)'
|
||||
app.inbox.contact.avatar.url: 'https://raw.githubusercontent.com/devlikeapro/waha/core/logo.png'
|
||||
|
||||
JOB_ERROR_REPORT: |
|
||||
job.report.error: |-
|
||||
⚠️ **{{{header}}}**
|
||||
{{#attempts.nextDelay}}
|
||||
🔄 Tentando novamente em {{attempts.nextDelay}} segundos...
|
||||
@@ -18,54 +20,55 @@ JOB_ERROR_REPORT: |
|
||||
```
|
||||
{{/error}}
|
||||
|
||||
JOB_SUCCEEDED_REPORT: |
|
||||
job.report.succeeded: |-
|
||||
✅ **Sucesso**
|
||||
Tentativa: {{{attempts.current}}} / {{{attempts.max}}}
|
||||
Detalhes: [{{{details.text}}}]({{{details.url}}})
|
||||
|
||||
WHATSAPP_ERROR_SENDING_MESSAGE:
|
||||
whatsapp.message.sending.error:
|
||||
Não foi possível enviar uma mensagem no WhatsApp.
|
||||
WHATSAPP_ERROR_RECEIVING_MESSAGE:
|
||||
whatsapp.message.receiving.error:
|
||||
Não foi possível receber uma mensagem do WhatsApp
|
||||
WHATSAPP_ERROR_REMOVING_MESSAGE:
|
||||
whatsapp.message.removing.error:
|
||||
Não foi possível remover uma mensagem do WhatsApp
|
||||
APP_SCHEDULED_JOB_ERROR: Falha ao executar tarefa agendada
|
||||
job.scheduled.error.header: Falha ao executar tarefa agendada
|
||||
|
||||
MESSAGE_FROM_WHATSAPP: |
|
||||
message.from.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *Enviado do WhatsApp*
|
||||
|
||||
MESSAGE_FROM_API: |
|
||||
message.from.api: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *Enviado via API*
|
||||
|
||||
MESSAGE_REMOVED_IN_WHATSAPP: |
|
||||
message.removed.in.whatsapp: |-
|
||||
❌ *Esta mensagem foi excluída no WhatsApp*
|
||||
|
||||
MESSAGE_EDITED_IN_WHATSAPP: |
|
||||
message.edited.in.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
✏️ *Editado no WhatsApp*
|
||||
|
||||
WHATSAPP_GROUP_MESSAGE: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.group.message: |-
|
||||
👥 *{{{participant}}}*
|
||||
|
||||
WHATSAPP_REACTION_ADDED: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.reaction.added: |-
|
||||
*Reagiu com* {{{emoji}}}
|
||||
|
||||
WHATSAPP_REACTION_REMOVED: |
|
||||
whatsapp.reaction.removed: |-
|
||||
*Reação removida*
|
||||
|
||||
WHATSAPP_CONTACT_GROUP_SUFFIX: 'Grupo'
|
||||
WHATSAPP_CONTACT_CHANNEL_SUFFIX: 'Canal'
|
||||
whatsapp.contact.group.suffix: 'Grupo'
|
||||
whatsapp.contact.channel.suffix: 'Canal'
|
||||
whatsapp.contact.broadcast.suffix: 'Lista de transmissão'
|
||||
# Aka Stories
|
||||
WHATSAPP_CONTACT_STATUS_NAME: 'Status'
|
||||
whatsapp.contact.status.name: 'Status'
|
||||
|
||||
APP_CONNECTED_MESSAGE: |
|
||||
app.connected.message: |-
|
||||
🔗 **CONECTADO: Sessão do WhatsApp para Caixa de Entrada do ChatWoot**
|
||||
|
||||
✅ A sessão do WhatsApp **{{{name}}}** foi conectada com sucesso a esta Caixa de Entrada do ChatWoot.
|
||||
@@ -83,7 +86,7 @@ APP_CONNECTED_MESSAGE: |
|
||||
|
||||
Vamos começar! 🚀
|
||||
|
||||
APP_DISCONNECTED_MESSAGE: |
|
||||
app.disconnected.message: |-
|
||||
🔌 **DESCONECTADO: Sessão do WhatsApp da Caixa de Entrada do ChatWoot**
|
||||
|
||||
❌ A sessão do WhatsApp **{{{name}}}** foi desconectada desta Caixa de Entrada do ChatWoot.
|
||||
@@ -92,15 +95,15 @@ APP_DISCONNECTED_MESSAGE: |
|
||||
|
||||
Para reconectar, entre em contato com seu administrador.
|
||||
|
||||
APP_UPDATED_MESSAGE: |
|
||||
app.updated.message: |-
|
||||
🔄 **ATUALIZADO: Configurações da Sessão do WhatsApp**
|
||||
|
||||
✅ As configurações para a sessão do WhatsApp **{{{name}}}** foram atualizadas.
|
||||
|
||||
APP_COMMANDS_LIST: |
|
||||
app.commands.list: |-
|
||||
Você pode gerenciar a **Integração WhatsApp** enviando um dos seguintes comandos:
|
||||
|
||||
🖥️ Sessões:
|
||||
🖥️ **Sessão**:
|
||||
1. **status** - obter o status atual da sessão.
|
||||
2. **restart** - reiniciar a sessão - isso tentará reconectar sua conta do WhatsApp.
|
||||
3. **start** - iniciar a sessão.
|
||||
@@ -110,42 +113,47 @@ APP_COMMANDS_LIST: |
|
||||
7. **screenshot** - obter uma captura de tela da sessão (disponível apenas no motor **WEBJS**).
|
||||
8. **help** - comandos disponíveis.
|
||||
|
||||
{{#commands.server}}
|
||||
⚙️ Servidor:
|
||||
- **server status** - obter informações sobre a versão e status do servidor.
|
||||
- **server reboot** - reiniciar o servidor suavemente.
|
||||
- **server reboot force** - forçar a reinicialização do servidor.
|
||||
{{/commands.server}}
|
||||
|
||||
Envie um **comando** (não sensível a maiúsculas/minúsculas) ou um **número de comando** para esta conversa.
|
||||
|
||||
APP_HELP_REMINDER: |
|
||||
app.commands.server.disabled: ⛔ **Os comandos do servidor estão desativados**.
|
||||
|
||||
Por favor, contate o seu administrador.
|
||||
|
||||
Envie **help** para obter a lista de comandos disponíveis.
|
||||
|
||||
APP_SESSION_STATUS_CHANGE: |
|
||||
app.help.reminder: |-
|
||||
Envie **help** para obter a lista de comandos disponíveis.
|
||||
|
||||
app.session.status.change: |-
|
||||
{{{emoji}}} A sessão "{{{session}}}" mudou para o status {{{status}}}
|
||||
|
||||
APP_SESSION_CURRENT_STATUS: |
|
||||
app.session.current.status: |-
|
||||
{{{emoji}}} O status da sessão **{{{session}}}** é **{{{status}}}**
|
||||
**Conta do WhatsApp:**
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_DASHBOARD_LINK: |
|
||||
Visite o [Painel WAHA]({{{url}}}) para mais detalhes.
|
||||
|
||||
APP_SESSION_STATUS_WORKING: |
|
||||
app.session.status.working: |-
|
||||
✅ Esta Caixa de Entrada do ChatWoot está vinculada à **Conta do WhatsApp** e pronta para enviar e receber mensagens!
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_SESSION_STATUS_ERROR: |
|
||||
app.session.status.error: |-
|
||||
⚠️ **Esta Caixa de Entrada do ChatWoot está vinculada à Conta do WhatsApp, mas NÃO está pronta para enviar e receber mensagens!**
|
||||
|
||||
Por favor, verifique o status da sessão e tente reiniciá-la ou saia e escaneie o código QR novamente.
|
||||
|
||||
APP_SESSION_SCAN_QR_CODE: |
|
||||
app.session.scan.qr.code: |-
|
||||
⚠️ **Escaneie o código QR no seu telefone para vincular a Conta do WhatsApp a esta Caixa de Entrada do ChatWoot!**
|
||||
|
||||
APP_SERVER_VERSION_AND_STATUS: |
|
||||
app.server.version.and.status: |-
|
||||
**Versão:**
|
||||
```
|
||||
{{{version}}}
|
||||
@@ -156,16 +164,16 @@ APP_SERVER_VERSION_AND_STATUS: |
|
||||
{{{status}}}
|
||||
```
|
||||
|
||||
APP_SERVER_REBOOT: |
|
||||
app.server.reboot: |-
|
||||
O servidor está reiniciando suavemente...
|
||||
|
||||
APP_SERVER_REBOOT_FORCE: |
|
||||
app.server.reboot.force: |-
|
||||
O servidor está reiniciando forçadamente...
|
||||
|
||||
APP_LOGOUT_SUCCESS: |
|
||||
app.logout.success: |-
|
||||
✅ Conta desautorizada com sucesso!
|
||||
|
||||
APP_NEW_VERSION_AVAILABLE: |
|
||||
waha.new.version.available: |-
|
||||
🔄 **Nova Versão Disponível!**
|
||||
|
||||
Versão atual: **{{{currentVersion}}}**
|
||||
@@ -173,7 +181,7 @@ APP_NEW_VERSION_AVAILABLE: |
|
||||
|
||||
👉 Confira o que há de novo no [**🆕 Registro de Alterações**]({{{changelogUrl}}})
|
||||
|
||||
APP_CORE_VERSION_USED: |
|
||||
waha.core.version.used: |-
|
||||
❤️ **Apoie o WAHA!**
|
||||
|
||||
Você está usando a versão gratuita **WAHA Core**. Se você acha este projeto útil, considere apoiar seu desenvolvimento.
|
||||
@@ -181,3 +189,51 @@ APP_CORE_VERSION_USED: |
|
||||
Seu apoio é a única maneira de continuarmos trabalhando em atualizações, correções e novos recursos.
|
||||
|
||||
[**🎁 Apoie-nos**]({{{supportUrl}}})
|
||||
|
||||
chatwoot.to.whatsapp.message.text: |-
|
||||
{{{ content }}}
|
||||
|
||||
chatwoot.to.whatsapp.message.media.caption: |-
|
||||
{{#singleAttachment}}
|
||||
{{#content}}
|
||||
{{{ content }}}
|
||||
{{/content}}
|
||||
{{/singleAttachment}}
|
||||
|
||||
whatsapp.to.chatwoot.message: |-
|
||||
{{{payload.body}}}
|
||||
|
||||
whatsapp.to.chatwoot.message.contacts: |-
|
||||
👤 **Contato(s) compartilhado(s)**
|
||||
|
||||
{{#contacts}}
|
||||
🪪 Nome: **{{fullName}}**
|
||||
{{#phoneNumbers}}
|
||||
- 📞 Telefone: **{{.}}**
|
||||
{{/phoneNumbers}}
|
||||
|
||||
{{/contacts}}
|
||||
|
||||
whatsapp.to.chatwoot.message.location: |-
|
||||
{{#message}}
|
||||
{{#locationMessage}}
|
||||
📍 **Localização compartilhada**
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/locationMessage}}
|
||||
|
||||
{{#liveLocationMessage}}
|
||||
📍📡 **Compartilhando localização ao vivo**
|
||||
Abra o **WhatsApp** para ver as atualizações em tempo real.
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/liveLocationMessage}}
|
||||
{{/message}}
|
||||
|
||||
whatsapp.to.chatwoot.message.unsupported: |-
|
||||
⚠️ **Esse tipo de mensagem não é suportado no ChatWoot.**
|
||||
📱 Por favor, abra o **WhatsApp** para visualizá-la.
|
||||
|
||||
Detalhes: [{{{details.text}}}]({{{details.url}}})
|
||||
@@ -1,7 +1,9 @@
|
||||
# Russian translations for ChatWoot integration
|
||||
APP_INBOX_CONTACT_NAME: 'WhatsApp Интеграция (WAHA)'
|
||||
locale.name: '🇷🇺 Русский (Russian)'
|
||||
app.inbox.contact.name: 'WhatsApp Интеграция (WAHA)'
|
||||
app.inbox.contact.avatar.url: 'https://raw.githubusercontent.com/devlikeapro/waha/core/logo.png'
|
||||
|
||||
JOB_ERROR_REPORT: |
|
||||
job.report.error: |-
|
||||
⚠️ **{{{header}}}**
|
||||
{{#attempts.nextDelay}}
|
||||
🔄 Повторная попытка через {{attempts.nextDelay}} секунд...
|
||||
@@ -18,51 +20,52 @@ JOB_ERROR_REPORT: |
|
||||
```
|
||||
{{/error}}
|
||||
|
||||
JOB_SUCCEEDED_REPORT: |
|
||||
job.report.succeeded: |-
|
||||
✅ **Успешно**
|
||||
Попытка: {{{attempts.current}}} / {{{attempts.max}}}
|
||||
Подробности: [{{{details.text}}}]({{{details.url}}})
|
||||
|
||||
WHATSAPP_ERROR_SENDING_MESSAGE: Не удалось отправить сообщение в WhatsApp.
|
||||
WHATSAPP_ERROR_RECEIVING_MESSAGE: Не удалось получить сообщение из WhatsApp
|
||||
WHATSAPP_ERROR_REMOVING_MESSAGE: Не удалось удалить сообщение из WhatsApp
|
||||
APP_SCHEDULED_JOB_ERROR: Запланированная задача не выполнена
|
||||
whatsapp.message.sending.error: Не удалось отправить сообщение в WhatsApp.
|
||||
whatsapp.message.receiving.error: Не удалось получить сообщение из WhatsApp
|
||||
whatsapp.message.removing.error: Не удалось удалить сообщение из WhatsApp
|
||||
job.scheduled.error.header: Запланированная задача не выполнена
|
||||
|
||||
MESSAGE_FROM_WHATSAPP: |
|
||||
message.from.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *Отправлено из WhatsApp*
|
||||
|
||||
MESSAGE_FROM_API: |
|
||||
message.from.api: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *Отправлено через API*
|
||||
|
||||
MESSAGE_REMOVED_IN_WHATSAPP: |
|
||||
message.removed.in.whatsapp: |-
|
||||
❌ *Это сообщение было удалено в WhatsApp*
|
||||
|
||||
MESSAGE_EDITED_IN_WHATSAPP: |
|
||||
message.edited.in.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
✏️ *Отредактировано в WhatsApp*
|
||||
|
||||
WHATSAPP_GROUP_MESSAGE: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.group.message: |-
|
||||
👥 *{{{participant}}}*
|
||||
|
||||
WHATSAPP_REACTION_ADDED: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.reaction.added: |-
|
||||
*Реакция* {{{emoji}}}
|
||||
|
||||
WHATSAPP_REACTION_REMOVED: |
|
||||
whatsapp.reaction.removed: |-
|
||||
*Реакция удалена*
|
||||
|
||||
WHATSAPP_CONTACT_GROUP_SUFFIX: 'Группа'
|
||||
WHATSAPP_CONTACT_CHANNEL_SUFFIX: 'Канал'
|
||||
whatsapp.contact.group.suffix: 'Группа'
|
||||
whatsapp.contact.channel.suffix: 'Канал'
|
||||
whatsapp.contact.broadcast.suffix: 'Список рассылки'
|
||||
# Aka Stories
|
||||
WHATSAPP_CONTACT_STATUS_NAME: 'Статус'
|
||||
whatsapp.contact.status.name: 'Статус'
|
||||
|
||||
APP_CONNECTED_MESSAGE: |
|
||||
app.connected.message: |-
|
||||
🔗 **ПОДКЛЮЧЕНО: Сессия WhatsApp к ChatWoot Inbox**
|
||||
|
||||
✅ Сессия WhatsApp **{{{name}}}** была успешно подключена к этому ChatWoot Inbox.
|
||||
@@ -80,7 +83,7 @@ APP_CONNECTED_MESSAGE: |
|
||||
|
||||
Давайте начнем! 🚀
|
||||
|
||||
APP_DISCONNECTED_MESSAGE: |
|
||||
app.disconnected.message: |-
|
||||
🔌 **ОТКЛЮЧЕНО: Сессия WhatsApp от ChatWoot Inbox**
|
||||
|
||||
❌ Сессия WhatsApp **{{{name}}}** была отключена от этого ChatWoot Inbox.
|
||||
@@ -89,15 +92,15 @@ APP_DISCONNECTED_MESSAGE: |
|
||||
|
||||
Для переподключения, пожалуйста, обратитесь к вашему администратору.
|
||||
|
||||
APP_UPDATED_MESSAGE: |
|
||||
app.updated.message: |-
|
||||
🔄 **ОБНОВЛЕНО: Настройки сессии WhatsApp**
|
||||
|
||||
✅ Настройки для сессии WhatsApp **{{{name}}}** были обновлены.
|
||||
|
||||
APP_COMMANDS_LIST: |
|
||||
app.commands.list: |-
|
||||
Вы можете управлять **WhatsApp Интеграцией**, отправив одну из следующих команд:
|
||||
|
||||
🖥️ Сессии:
|
||||
🖥️ **Сессия**:
|
||||
1. **status** - получить текущий статус сессии.
|
||||
2. **restart** - перезапустить сессию - это попытается переподключить ваш аккаунт WhatsApp.
|
||||
3. **start** - запустить сессию.
|
||||
@@ -107,42 +110,47 @@ APP_COMMANDS_LIST: |
|
||||
7. **screenshot** - получить скриншот сессии (доступно только в движке **WEBJS**).
|
||||
8. **help** - доступные команды.
|
||||
|
||||
{{#commands.server}}
|
||||
⚙️ Сервер:
|
||||
- **server status** - получить информацию о версии и статусе сервера.
|
||||
- **server reboot** - корректно перезагрузить сервер.
|
||||
- **server reboot force** - принудительно перезагрузить сервер.
|
||||
{{/commands.server}}
|
||||
|
||||
Отправьте **команду** (без учета регистра) или **номер команды** в этот разговор.
|
||||
|
||||
APP_HELP_REMINDER: |
|
||||
app.commands.server.disabled: ⛔ **Команды сервера отключены**.
|
||||
|
||||
Пожалуйста, свяжитесь с вашим администратором.
|
||||
|
||||
Отправьте **help**, чтобы получить список доступных команд.
|
||||
|
||||
APP_SESSION_STATUS_CHANGE: |
|
||||
app.help.reminder: |-
|
||||
Отправьте **help**, чтобы получить список доступных команд.
|
||||
|
||||
app.session.status.change: |-
|
||||
{{{emoji}}} Сессия "{{{session}}}" переключилась в статус {{{status}}}
|
||||
|
||||
APP_SESSION_CURRENT_STATUS: |
|
||||
app.session.current.status: |-
|
||||
{{{emoji}}} Статус сессии **{{{session}}}** - **{{{status}}}**
|
||||
**Аккаунт WhatsApp:**
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_DASHBOARD_LINK: |
|
||||
Посетите [WAHA Dashboard]({{{url}}}) для получения дополнительной информации.
|
||||
|
||||
APP_SESSION_STATUS_WORKING: |
|
||||
app.session.status.working: |-
|
||||
✅ Этот ChatWoot Inbox связан с **аккаунтом WhatsApp** и готов отправлять и получать сообщения!
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_SESSION_STATUS_ERROR: |
|
||||
app.session.status.error: |-
|
||||
⚠️ **Этот ChatWoot Inbox связан с аккаунтом WhatsApp, но НЕ готов отправлять и получать сообщения!**
|
||||
|
||||
Пожалуйста, проверьте статус сессии и попробуйте перезапустить её или выйдите и отсканируйте QR-код снова.
|
||||
|
||||
APP_SESSION_SCAN_QR_CODE: |
|
||||
app.session.scan.qr.code: |-
|
||||
⚠️ **Отсканируйте QR-код на вашем телефоне, чтобы связать аккаунт WhatsApp с этим ChatWoot Inbox!**
|
||||
|
||||
APP_SERVER_VERSION_AND_STATUS: |
|
||||
app.server.version.and.status: |-
|
||||
**Версия:**
|
||||
```
|
||||
{{{version}}}
|
||||
@@ -153,16 +161,16 @@ APP_SERVER_VERSION_AND_STATUS: |
|
||||
{{{status}}}
|
||||
```
|
||||
|
||||
APP_SERVER_REBOOT: |
|
||||
app.server.reboot: |-
|
||||
Сервер корректно перезагружается...
|
||||
|
||||
APP_SERVER_REBOOT_FORCE: |
|
||||
app.server.reboot.force: |-
|
||||
Сервер принудительно перезагружается...
|
||||
|
||||
APP_LOGOUT_SUCCESS: |
|
||||
app.logout.success: |-
|
||||
✅ Аккаунт успешно деавторизован!
|
||||
|
||||
APP_NEW_VERSION_AVAILABLE: |
|
||||
waha.new.version.available: |-
|
||||
🔄 **Доступна новая версия!**
|
||||
|
||||
Текущая версия: **{{{currentVersion}}}**
|
||||
@@ -170,7 +178,7 @@ APP_NEW_VERSION_AVAILABLE: |
|
||||
|
||||
👉 Узнайте, что нового в [**🆕 Списке изменений**]({{{changelogUrl}}})
|
||||
|
||||
APP_CORE_VERSION_USED: |
|
||||
waha.core.version.used: |-
|
||||
❤️ **Поддержите WAHA!**
|
||||
|
||||
Вы используете бесплатную версию **WAHA Core**. Если вы находите этот проект полезным, пожалуйста, рассмотрите возможность поддержать его разработку.
|
||||
@@ -178,3 +186,51 @@ APP_CORE_VERSION_USED: |
|
||||
Ваша поддержка - единственный способ, которым мы можем продолжать работать над обновлениями, исправлениями и новыми функциями.
|
||||
|
||||
[**🎁 Поддержать нас**]({{{supportUrl}}})
|
||||
|
||||
chatwoot.to.whatsapp.message.text: |-
|
||||
{{{ content }}}
|
||||
|
||||
chatwoot.to.whatsapp.message.media.caption: |-
|
||||
{{#singleAttachment}}
|
||||
{{#content}}
|
||||
{{{ content }}}
|
||||
{{/content}}
|
||||
{{/singleAttachment}}
|
||||
|
||||
whatsapp.to.chatwoot.message: |-
|
||||
{{{payload.body}}}
|
||||
|
||||
whatsapp.to.chatwoot.message.contacts: |-
|
||||
👤 **Переданные контакты**
|
||||
|
||||
{{#contacts}}
|
||||
🪪 Имя: **{{fullName}}**
|
||||
{{#phoneNumbers}}
|
||||
- 📞 Телефон: **{{.}}**
|
||||
{{/phoneNumbers}}
|
||||
|
||||
{{/contacts}}
|
||||
|
||||
whatsapp.to.chatwoot.message.location: |-
|
||||
{{#message}}
|
||||
{{#locationMessage}}
|
||||
📍 **Переданное местоположение**
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/locationMessage}}
|
||||
|
||||
{{#liveLocationMessage}}
|
||||
📍📡 **Делится геопозицией в реальном времени**
|
||||
Откройте **WhatsApp**, чтобы увидеть обновления в реальном времени.
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/liveLocationMessage}}
|
||||
{{/message}}
|
||||
|
||||
whatsapp.to.chatwoot.message.unsupported: |-
|
||||
⚠️ **Этот тип сообщения не поддерживается в ChatWoot.**
|
||||
📱 Пожалуйста, откройте **WhatsApp**, чтобы просмотреть.
|
||||
|
||||
Подробности: [{{{details.text}}}]({{{details.url}}})
|
||||
@@ -1,7 +1,9 @@
|
||||
# Turkish translations for ChatWoot integration
|
||||
APP_INBOX_CONTACT_NAME: 'WhatsApp Entegrasyonu (WAHA)'
|
||||
locale.name: '🇹🇷 Türkçe (Turkish)'
|
||||
app.inbox.contact.name: 'WhatsApp Entegrasyonu (WAHA)'
|
||||
app.inbox.contact.avatar.url: 'https://raw.githubusercontent.com/devlikeapro/waha/core/logo.png'
|
||||
|
||||
JOB_ERROR_REPORT: |
|
||||
job.report.error: |-
|
||||
⚠️ **{{{header}}}**
|
||||
{{#attempts.nextDelay}}
|
||||
🔄 {{attempts.nextDelay}} saniye içinde tekrar deneniyor...
|
||||
@@ -18,51 +20,52 @@ JOB_ERROR_REPORT: |
|
||||
```
|
||||
{{/error}}
|
||||
|
||||
JOB_SUCCEEDED_REPORT: |
|
||||
job.report.succeeded: |-
|
||||
✅ **Başarılı**
|
||||
Deneme: {{{attempts.current}}} / {{{attempts.max}}}
|
||||
Detaylar: [{{{details.text}}}]({{{details.url}}})
|
||||
|
||||
WHATSAPP_ERROR_SENDING_MESSAGE: WhatsApp'ta mesaj gönderilemedi.
|
||||
WHATSAPP_ERROR_RECEIVING_MESSAGE: WhatsApp'tan mesaj alınamadı
|
||||
WHATSAPP_ERROR_REMOVING_MESSAGE: WhatsApp'tan mesaj kaldırılamadı
|
||||
APP_SCHEDULED_JOB_ERROR: Zamanlanmış görev yürütülemedi
|
||||
whatsapp.message.sending.error: WhatsApp'ta mesaj gönderilemedi.
|
||||
whatsapp.message.receiving.error: WhatsApp'tan mesaj alınamadı
|
||||
whatsapp.message.removing.error: WhatsApp'tan mesaj kaldırılamadı
|
||||
job.scheduled.error.header: Zamanlanmış görev yürütülemedi
|
||||
|
||||
MESSAGE_FROM_WHATSAPP: |
|
||||
message.from.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *WhatsApp'tan gönderildi*
|
||||
|
||||
MESSAGE_FROM_API: |
|
||||
message.from.api: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *API aracılığıyla gönderildi*
|
||||
|
||||
MESSAGE_REMOVED_IN_WHATSAPP: |
|
||||
message.removed.in.whatsapp: |-
|
||||
❌ *Bu mesaj WhatsApp'ta silindi*
|
||||
|
||||
MESSAGE_EDITED_IN_WHATSAPP: |
|
||||
message.edited.in.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
✏️ *WhatsApp'ta düzenlendi*
|
||||
|
||||
WHATSAPP_GROUP_MESSAGE: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.group.message: |-
|
||||
👥 *{{{participant}}}*
|
||||
|
||||
WHATSAPP_REACTION_ADDED: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.reaction.added: |-
|
||||
*Tepki verdi* {{{emoji}}}
|
||||
|
||||
WHATSAPP_REACTION_REMOVED: |
|
||||
whatsapp.reaction.removed: |-
|
||||
*Tepki kaldırıldı*
|
||||
|
||||
WHATSAPP_CONTACT_GROUP_SUFFIX: 'Grup'
|
||||
WHATSAPP_CONTACT_CHANNEL_SUFFIX: 'Kanal'
|
||||
whatsapp.contact.group.suffix: 'Grup'
|
||||
whatsapp.contact.channel.suffix: 'Kanal'
|
||||
whatsapp.contact.broadcast.suffix: 'Yayın Listesi'
|
||||
# Aka Stories
|
||||
WHATSAPP_CONTACT_STATUS_NAME: 'Durum'
|
||||
whatsapp.contact.status.name: 'Durum'
|
||||
|
||||
APP_CONNECTED_MESSAGE: |
|
||||
app.connected.message: |-
|
||||
🔗 **BAĞLANDI: WhatsApp Oturumu ChatWoot Gelen Kutusuna**
|
||||
|
||||
✅ WhatsApp oturumu **{{{name}}}** bu ChatWoot Gelen Kutusuna başarıyla bağlandı.
|
||||
@@ -80,7 +83,7 @@ APP_CONNECTED_MESSAGE: |
|
||||
|
||||
Hadi başlayalım! 🚀
|
||||
|
||||
APP_DISCONNECTED_MESSAGE: |
|
||||
app.disconnected.message: |-
|
||||
🔌 **BAĞLANTI KESİLDİ: WhatsApp Oturumu ChatWoot Gelen Kutusundan**
|
||||
|
||||
❌ WhatsApp oturumu **{{{name}}}** bu ChatWoot Gelen Kutusundan bağlantısı kesildi.
|
||||
@@ -89,15 +92,15 @@ APP_DISCONNECTED_MESSAGE: |
|
||||
|
||||
Yeniden bağlanmak için, lütfen yöneticinizle iletişime geçin.
|
||||
|
||||
APP_UPDATED_MESSAGE: |
|
||||
app.updated.message: |-
|
||||
🔄 **GÜNCELLENDİ: WhatsApp Oturum Ayarları**
|
||||
|
||||
✅ WhatsApp oturumu **{{{name}}}** için ayarlar güncellendi.
|
||||
|
||||
APP_COMMANDS_LIST: |
|
||||
app.commands.list: |-
|
||||
Aşağıdaki komutlardan birini göndererek **WhatsApp Entegrasyonu**nu yönetebilirsiniz:
|
||||
|
||||
🖥️ Oturumlar:
|
||||
🖥️ **Oturum**:
|
||||
1. **status** - mevcut oturum durumunu alın.
|
||||
2. **restart** - oturumu yeniden başlatın - bu, WhatsApp hesabınızı yeniden bağlamaya çalışacaktır.
|
||||
3. **start** - oturumu başlatın.
|
||||
@@ -107,42 +110,47 @@ APP_COMMANDS_LIST: |
|
||||
7. **screenshot** - oturumun ekran görüntüsünü alın (yalnızca **WEBJS** motorunda kullanılabilir).
|
||||
8. **help** - kullanılabilir komutlar.
|
||||
|
||||
{{#commands.server}}
|
||||
⚙️ Sunucu:
|
||||
- **server status** - sunucu sürümü ve durum bilgilerini alın.
|
||||
- **server reboot** - sunucuyu nazikçe yeniden başlatın.
|
||||
- **server reboot force** - sunucuyu zorla yeniden başlatın.
|
||||
{{/commands.server}}
|
||||
|
||||
Bu konuşmaya bir **komut** (büyük/küçük harf duyarsız) veya **komut numarası** gönderin.
|
||||
|
||||
APP_HELP_REMINDER: |
|
||||
app.commands.server.disabled: ⛔ **Sunucu komutları devre dışı**.
|
||||
|
||||
Lütfen yöneticinizle iletişime geçin.
|
||||
|
||||
Kullanılabilir komutların listesini almak için **help** gönderin.
|
||||
|
||||
APP_SESSION_STATUS_CHANGE: |
|
||||
app.help.reminder: |-
|
||||
Kullanılabilir komutların listesini almak için **help** gönderin.
|
||||
|
||||
app.session.status.change: |-
|
||||
{{{emoji}}} "{{{session}}}" oturumu {{{status}}} durumuna geçti
|
||||
|
||||
APP_SESSION_CURRENT_STATUS: |
|
||||
app.session.current.status: |-
|
||||
{{{emoji}}} **{{{session}}}** oturum durumu **{{{status}}}** içinde
|
||||
**WhatsApp Hesabı:**
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_DASHBOARD_LINK: |
|
||||
Daha fazla ayrıntı için [WAHA Kontrol Paneli]({{{url}}}) ziyaret edin.
|
||||
|
||||
APP_SESSION_STATUS_WORKING: |
|
||||
app.session.status.working: |-
|
||||
✅ Bu ChatWoot Gelen Kutusu **WhatsApp Hesabına** bağlı ve mesaj gönderip almaya hazır!
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_SESSION_STATUS_ERROR: |
|
||||
app.session.status.error: |-
|
||||
⚠️ **Bu ChatWoot Gelen Kutusu WhatsApp Hesabına bağlı ancak mesaj gönderip almaya hazır DEĞİL!**
|
||||
|
||||
Lütfen oturum durumunu kontrol edin ve yeniden başlatmayı deneyin veya çıkış yapın ve QR kodu tekrar tarayın.
|
||||
|
||||
APP_SESSION_SCAN_QR_CODE: |
|
||||
app.session.scan.qr.code: |-
|
||||
⚠️ **WhatsApp Hesabını bu ChatWoot Gelen Kutusuna bağlamak için telefonunuzda QR kodu tarayın!**
|
||||
|
||||
APP_SERVER_VERSION_AND_STATUS: |
|
||||
app.server.version.and.status: |-
|
||||
**Sürüm:**
|
||||
```
|
||||
{{{version}}}
|
||||
@@ -153,16 +161,16 @@ APP_SERVER_VERSION_AND_STATUS: |
|
||||
{{{status}}}
|
||||
```
|
||||
|
||||
APP_SERVER_REBOOT: |
|
||||
app.server.reboot: |-
|
||||
Sunucu nazikçe yeniden başlatılıyor...
|
||||
|
||||
APP_SERVER_REBOOT_FORCE: |
|
||||
app.server.reboot.force: |-
|
||||
Sunucu zorla yeniden başlatılıyor...
|
||||
|
||||
APP_LOGOUT_SUCCESS: |
|
||||
app.logout.success: |-
|
||||
✅ Hesap başarıyla yetkilendirilmedi!
|
||||
|
||||
APP_NEW_VERSION_AVAILABLE: |
|
||||
waha.new.version.available: |-
|
||||
🔄 **Yeni Sürüm Mevcut!**
|
||||
|
||||
Mevcut sürüm: **{{{currentVersion}}}**
|
||||
@@ -170,7 +178,7 @@ APP_NEW_VERSION_AVAILABLE: |
|
||||
|
||||
👉 [**🆕 Değişiklik Günlüğü**]({{{changelogUrl}}}) içinde yenilikleri kontrol edin
|
||||
|
||||
APP_CORE_VERSION_USED: |
|
||||
waha.core.version.used: |-
|
||||
❤️ **WAHA'yı Destekleyin!**
|
||||
|
||||
Ücretsiz **WAHA Core** sürümünü kullanıyorsunuz. Bu projeyi faydalı buluyorsanız, lütfen geliştirilmesini desteklemeyi düşünün.
|
||||
@@ -178,3 +186,51 @@ APP_CORE_VERSION_USED: |
|
||||
Desteğiniz, güncellemeler, düzeltmeler ve yeni özellikler üzerinde çalışmaya devam edebilmemizin tek yoludur.
|
||||
|
||||
[**🎁 Bizi Destekleyin**]({{{supportUrl}}})
|
||||
|
||||
chatwoot.to.whatsapp.message.text: |-
|
||||
{{{ content }}}
|
||||
|
||||
chatwoot.to.whatsapp.message.media.caption: |-
|
||||
{{#singleAttachment}}
|
||||
{{#content}}
|
||||
{{{ content }}}
|
||||
{{/content}}
|
||||
{{/singleAttachment}}
|
||||
|
||||
whatsapp.to.chatwoot.message: |-
|
||||
{{{payload.body}}}
|
||||
|
||||
whatsapp.to.chatwoot.message.contacts: |-
|
||||
👤 **Paylaşılan Kişi(ler)**
|
||||
|
||||
{{#contacts}}
|
||||
🪪 İsim: **{{fullName}}**
|
||||
{{#phoneNumbers}}
|
||||
- 📞 Telefon: **{{.}}**
|
||||
{{/phoneNumbers}}
|
||||
|
||||
{{/contacts}}
|
||||
|
||||
whatsapp.to.chatwoot.message.location: |-
|
||||
{{#message}}
|
||||
{{#locationMessage}}
|
||||
📍 **Paylaşılan Konum**
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/locationMessage}}
|
||||
|
||||
{{#liveLocationMessage}}
|
||||
📍📡 **Canlı Konum Paylaşılıyor**
|
||||
Gerçek zamanlı güncellemeleri görmek için **WhatsApp’ı** açın.
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/liveLocationMessage}}
|
||||
{{/message}}
|
||||
|
||||
whatsapp.to.chatwoot.message.unsupported: |-
|
||||
⚠️ **Bu mesaj türü ChatWoot’ta desteklenmiyor.**
|
||||
📱 Görüntülemek için lütfen **WhatsApp’ı** açın.
|
||||
|
||||
Ayrıntılar: [{{{details.text}}}]({{{details.url}}})
|
||||
@@ -1,7 +1,9 @@
|
||||
# Ukrainian translations for ChatWoot integration
|
||||
APP_INBOX_CONTACT_NAME: 'Інтеграція WhatsApp (WAHA)'
|
||||
locale.name: '🇺🇦 Українська (Ukrainian)'
|
||||
app.inbox.contact.name: 'Інтеграція WhatsApp (WAHA)'
|
||||
app.inbox.contact.avatar.url: 'https://raw.githubusercontent.com/devlikeapro/waha/core/logo.png'
|
||||
|
||||
JOB_ERROR_REPORT: |
|
||||
job.report.error: |-
|
||||
⚠️ **{{{header}}}**
|
||||
{{#attempts.nextDelay}}
|
||||
🔄 Повторна спроба через {{attempts.nextDelay}} секунд...
|
||||
@@ -18,51 +20,52 @@ JOB_ERROR_REPORT: |
|
||||
```
|
||||
{{/error}}
|
||||
|
||||
JOB_SUCCEEDED_REPORT: |
|
||||
job.report.succeeded: |-
|
||||
✅ **Успішно**
|
||||
Спроба: {{{attempts.current}}} / {{{attempts.max}}}
|
||||
Деталі: [{{{details.text}}}]({{{details.url}}})
|
||||
|
||||
WHATSAPP_ERROR_SENDING_MESSAGE: Не вдалося надіслати повідомлення у WhatsApp.
|
||||
WHATSAPP_ERROR_RECEIVING_MESSAGE: Не вдалося отримати повідомлення з WhatsApp
|
||||
WHATSAPP_ERROR_REMOVING_MESSAGE: Не вдалося видалити повідомлення з WhatsApp
|
||||
APP_SCHEDULED_JOB_ERROR: Заплановане завдання не вдалося виконати
|
||||
whatsapp.message.sending.error: Не вдалося надіслати повідомлення у WhatsApp.
|
||||
whatsapp.message.receiving.error: Не вдалося отримати повідомлення з WhatsApp
|
||||
whatsapp.message.removing.error: Не вдалося видалити повідомлення з WhatsApp
|
||||
job.scheduled.error.header: Заплановане завдання не вдалося виконати
|
||||
|
||||
MESSAGE_FROM_WHATSAPP: |
|
||||
message.from.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *Надіслано з WhatsApp*
|
||||
|
||||
MESSAGE_FROM_API: |
|
||||
message.from.api: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *Надіслано через API*
|
||||
|
||||
MESSAGE_REMOVED_IN_WHATSAPP: |
|
||||
message.removed.in.whatsapp: |-
|
||||
❌ *Це повідомлення було видалено у WhatsApp*
|
||||
|
||||
MESSAGE_EDITED_IN_WHATSAPP: |
|
||||
message.edited.in.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
✏️ *Відредаговано у WhatsApp*
|
||||
|
||||
WHATSAPP_GROUP_MESSAGE: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.group.message: |-
|
||||
👥 *{{{participant}}}*
|
||||
|
||||
WHATSAPP_REACTION_ADDED: |
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.reaction.added: |-
|
||||
*Реакція* {{{emoji}}}
|
||||
|
||||
WHATSAPP_REACTION_REMOVED: |
|
||||
whatsapp.reaction.removed: |-
|
||||
*Реакцію видалено*
|
||||
|
||||
WHATSAPP_CONTACT_GROUP_SUFFIX: 'Група'
|
||||
WHATSAPP_CONTACT_CHANNEL_SUFFIX: 'Канал'
|
||||
whatsapp.contact.group.suffix: 'Група'
|
||||
whatsapp.contact.channel.suffix: 'Канал'
|
||||
whatsapp.contact.broadcast.suffix: 'Список розсилки'
|
||||
# Aka Stories
|
||||
WHATSAPP_CONTACT_STATUS_NAME: 'Статус'
|
||||
whatsapp.contact.status.name: 'Статус'
|
||||
|
||||
APP_CONNECTED_MESSAGE: |
|
||||
app.connected.message: |-
|
||||
🔗 **ПІДКЛЮЧЕНО: Сесія WhatsApp до Вхідних ChatWoot**
|
||||
|
||||
✅ Сесія WhatsApp **{{{name}}}** була успішно підключена до цих Вхідних ChatWoot.
|
||||
@@ -80,7 +83,7 @@ APP_CONNECTED_MESSAGE: |
|
||||
|
||||
Давайте почнемо! 🚀
|
||||
|
||||
APP_DISCONNECTED_MESSAGE: |
|
||||
app.disconnected.message: |-
|
||||
🔌 **ВІДКЛЮЧЕНО: Сесія WhatsApp від Вхідних ChatWoot**
|
||||
|
||||
❌ Сесія WhatsApp **{{{name}}}** була відключена від цих Вхідних ChatWoot.
|
||||
@@ -89,15 +92,15 @@ APP_DISCONNECTED_MESSAGE: |
|
||||
|
||||
Щоб повторно підключитися, зверніться до свого адміністратора.
|
||||
|
||||
APP_UPDATED_MESSAGE: |
|
||||
app.updated.message: |-
|
||||
🔄 **ОНОВЛЕНО: Налаштування сесії WhatsApp**
|
||||
|
||||
✅ Налаштування для сесії WhatsApp **{{{name}}}** були оновлені.
|
||||
|
||||
APP_COMMANDS_LIST: |
|
||||
app.commands.list: |-
|
||||
Ви можете керувати **Інтеграцією WhatsApp**, надіславши одну з наступних команд:
|
||||
|
||||
🖥️ Сесії:
|
||||
🖥️ **Сесія**:
|
||||
1. **status** - отримати поточний статус сесії.
|
||||
2. **restart** - перезапустити сесію - це спробує повторно підключити ваш обліковий запис WhatsApp.
|
||||
3. **start** - запустити сесію.
|
||||
@@ -107,42 +110,47 @@ APP_COMMANDS_LIST: |
|
||||
7. **screenshot** - отримати знімок екрану сесії (доступно лише в двигуні **WEBJS**).
|
||||
8. **help** - доступні команди.
|
||||
|
||||
{{#commands.server}}
|
||||
⚙️ Сервер:
|
||||
- **server status** - отримати інформацію про версію та статус сервера.
|
||||
- **server reboot** - перезавантажити сервер плавно.
|
||||
- **server reboot force** - примусово перезавантажити сервер.
|
||||
{{/commands.server}}
|
||||
|
||||
Надішліть **команду** (без урахування регістру) або **номер команди** у цю розмову.
|
||||
|
||||
APP_HELP_REMINDER: |
|
||||
app.commands.server.disabled: ⛔ **Команди сервера вимкнені**.
|
||||
|
||||
Будь ласка, зв’яжіться з вашим адміністратором.
|
||||
|
||||
Надішліть **help**, щоб отримати список доступних команд.
|
||||
|
||||
APP_SESSION_STATUS_CHANGE: |
|
||||
app.help.reminder: |-
|
||||
Надішліть **help**, щоб отримати список доступних команд.
|
||||
|
||||
app.session.status.change: |-
|
||||
{{{emoji}}} Сесія "{{{session}}}" перейшла у статус {{{status}}}
|
||||
|
||||
APP_SESSION_CURRENT_STATUS: |
|
||||
app.session.current.status: |-
|
||||
{{{emoji}}} Статус сесії **{{{session}}}** - **{{{status}}}**
|
||||
**Обліковий запис WhatsApp:**
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_DASHBOARD_LINK: |
|
||||
Відвідайте [Панель керування WAHA]({{{url}}}) для отримання додаткової інформації.
|
||||
|
||||
APP_SESSION_STATUS_WORKING: |
|
||||
app.session.status.working: |-
|
||||
✅ Ці Вхідні ChatWoot пов'язані з **Обліковим записом WhatsApp** і готові надсилати та отримувати повідомлення!
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
APP_SESSION_STATUS_ERROR: |
|
||||
app.session.status.error: |-
|
||||
⚠️ **Ці Вхідні ChatWoot пов'язані з Обліковим записом WhatsApp, але НЕ готові надсилати та отримувати повідомлення!**
|
||||
|
||||
Будь ласка, перевірте статус сесії та спробуйте перезапустити її або вийдіть і відскануйте QR-код знову.
|
||||
|
||||
APP_SESSION_SCAN_QR_CODE: |
|
||||
app.session.scan.qr.code: |-
|
||||
⚠️ **Відскануйте QR-код на вашому телефоні, щоб пов'язати Обліковий запис WhatsApp з цими Вхідними ChatWoot!**
|
||||
|
||||
APP_SERVER_VERSION_AND_STATUS: |
|
||||
app.server.version.and.status: |-
|
||||
**Версія:**
|
||||
```
|
||||
{{{version}}}
|
||||
@@ -153,16 +161,16 @@ APP_SERVER_VERSION_AND_STATUS: |
|
||||
{{{status}}}
|
||||
```
|
||||
|
||||
APP_SERVER_REBOOT: |
|
||||
app.server.reboot: |-
|
||||
Сервер плавно перезавантажується...
|
||||
|
||||
APP_SERVER_REBOOT_FORCE: |
|
||||
app.server.reboot.force: |-
|
||||
Сервер примусово перезавантажується...
|
||||
|
||||
APP_LOGOUT_SUCCESS: |
|
||||
app.logout.success: |-
|
||||
✅ Обліковий запис успішно деавторизовано!
|
||||
|
||||
APP_NEW_VERSION_AVAILABLE: |
|
||||
waha.new.version.available: |-
|
||||
🔄 **Доступна нова версія!**
|
||||
|
||||
Поточна версія: **{{{currentVersion}}}**
|
||||
@@ -170,7 +178,7 @@ APP_NEW_VERSION_AVAILABLE: |
|
||||
|
||||
👉 Перевірте, що нового у [**🆕 Журналі змін**]({{{changelogUrl}}})
|
||||
|
||||
APP_CORE_VERSION_USED: |
|
||||
waha.core.version.used: |-
|
||||
❤️ **Підтримайте WAHA!**
|
||||
|
||||
Ви використовуєте безкоштовну версію **WAHA Core**. Якщо ви вважаєте цей проект корисним, будь ласка, розгляньте можливість підтримати його розробку.
|
||||
@@ -178,3 +186,51 @@ APP_CORE_VERSION_USED: |
|
||||
Ваша підтримка - єдиний спосіб, яким ми можемо продовжувати працювати над оновленнями, виправленнями та новими функціями.
|
||||
|
||||
[**🎁 Підтримайте нас**]({{{supportUrl}}})
|
||||
|
||||
chatwoot.to.whatsapp.message.text: |-
|
||||
{{{ content }}}
|
||||
|
||||
chatwoot.to.whatsapp.message.media.caption: |-
|
||||
{{#singleAttachment}}
|
||||
{{#content}}
|
||||
{{{ content }}}
|
||||
{{/content}}
|
||||
{{/singleAttachment}}
|
||||
|
||||
whatsapp.to.chatwoot.message: |-
|
||||
{{{payload.body}}}
|
||||
|
||||
whatsapp.to.chatwoot.message.contacts: |-
|
||||
👤 **Надісланий контакт(и)**
|
||||
|
||||
{{#contacts}}
|
||||
🪪 Ім’я: **{{fullName}}**
|
||||
{{#phoneNumbers}}
|
||||
- 📞 Телефон: **{{.}}**
|
||||
{{/phoneNumbers}}
|
||||
|
||||
{{/contacts}}
|
||||
|
||||
whatsapp.to.chatwoot.message.location: |-
|
||||
{{#message}}
|
||||
{{#locationMessage}}
|
||||
📍 **Надіслана локація**
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/locationMessage}}
|
||||
|
||||
{{#liveLocationMessage}}
|
||||
📍📡 **Надсилання геолокації в реальному часі**
|
||||
Відкрийте **WhatsApp**, щоб побачити оновлення в реальному часі.
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/liveLocationMessage}}
|
||||
{{/message}}
|
||||
|
||||
whatsapp.to.chatwoot.message.unsupported: |-
|
||||
⚠️ **Цей тип повідомлення не підтримується в ChatWoot.**
|
||||
📱 Будь ласка, відкрийте **WhatsApp**, щоб переглянути.
|
||||
|
||||
Подробиці: [{{{details.text}}}]({{{details.url}}})
|
||||
@@ -0,0 +1,236 @@
|
||||
# Urdu translations for ChatWoot integration
|
||||
locale.name: '🇵🇰 اردو (Urdu)'
|
||||
app.inbox.contact.name: 'واٹس ایپ انٹیگریشن (WAHA)'
|
||||
app.inbox.contact.avatar.url: 'https://raw.githubusercontent.com/devlikeapro/waha/core/logo.png'
|
||||
|
||||
job.report.error: |-
|
||||
⚠️ **{{{header}}}**
|
||||
{{#attempts.nextDelay}}
|
||||
🔄 {{attempts.nextDelay}} سیکنڈ میں دوبارہ کوشش کر رہا ہے...
|
||||
{{/attempts.nextDelay}}
|
||||
{{^attempts.nextDelay}}
|
||||
❌ مزید کوششیں نہیں بچی ہیں۔ براہ کرم بعد میں دوبارہ کوشش کریں۔
|
||||
{{/attempts.nextDelay}}
|
||||
کوشش: {{{attempts.current}}} / {{{attempts.max}}}
|
||||
تفصیلات: [{{{details.text}}}]({{{details.url}}})
|
||||
{{#error}}
|
||||
```
|
||||
|
||||
{{{error}}}
|
||||
```
|
||||
{{/error}}
|
||||
|
||||
job.report.succeeded: |-
|
||||
✅ **کامیاب ہوا**
|
||||
کوشش: {{{attempts.current}}} / {{{attempts.max}}}
|
||||
تفصیلات: [{{{details.text}}}]({{{details.url}}})
|
||||
|
||||
whatsapp.message.sending.error: واٹس ایپ پر پیغام نہیں بھیج سکا۔
|
||||
whatsapp.message.receiving.error: واٹس ایپ سے پیغام موصول نہیں کر سکا
|
||||
whatsapp.message.removing.error: واٹس ایپ سے پیغام ہٹا نہیں سکا
|
||||
job.scheduled.error.header: شیڈول کردہ کام انجام دینے میں ناکام رہا
|
||||
|
||||
message.from.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *واٹس ایپ سے بھیجا گیا*
|
||||
|
||||
message.from.api: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *API کے ذریعے بھیجا گیا*
|
||||
|
||||
message.removed.in.whatsapp: |-
|
||||
❌ *یہ پیغام واٹس ایپ میں حذف کر دیا گیا تھا*
|
||||
|
||||
message.edited.in.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
✏️ *واٹس ایپ میں ترمیم کی گئی*
|
||||
|
||||
whatsapp.group.message: |-
|
||||
👥 *{{{participant}}}*
|
||||
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.reaction.added: |-
|
||||
*ردعمل دیا* {{{emoji}}}
|
||||
|
||||
whatsapp.reaction.removed: |-
|
||||
*ردعمل ہٹا دیا گیا*
|
||||
|
||||
whatsapp.contact.group.suffix: 'گروپ'
|
||||
whatsapp.contact.channel.suffix: 'چینل'
|
||||
whatsapp.contact.broadcast.suffix: 'براڈکاسٹ فہرست'
|
||||
# Aka Stories
|
||||
whatsapp.contact.status.name: 'سٹیٹس'
|
||||
|
||||
app.connected.message: |-
|
||||
🔗 **منسلک: واٹس ایپ سیشن ChatWoot انبکس سے**
|
||||
|
||||
✅ واٹس ایپ سیشن **{{{name}}}** کامیابی سے اس ChatWoot انبکس سے منسلک ہو گیا ہے۔
|
||||
|
||||
یہ انبکس اب آپ کے **واٹس ایپ اکاؤنٹ** سے منسلک ہے۔ آپ یہاں سے براہ راست پیغامات بھیج اور موصول کر سکتے ہیں — بالکل واٹس ایپ استعمال کرنے کی طرح، لیکن ChatWoot کے اندر۔
|
||||
|
||||
آپ اس انبکس سے منسلک واٹس ایپ سیشن کا انتظام بھی کر سکتے ہیں۔ دستیاب اقدامات دیکھنے کے لیے، اس چیٹ میں **help** بھیجیں۔
|
||||
|
||||
📋 عام اقدامات جو آپ کر سکتے ہیں:
|
||||
- چیک کریں کہ آیا واٹس ایپ سیشن فعال ہے
|
||||
- واٹس ایپ سیشن کو دوبارہ شروع کریں یا روکیں
|
||||
- لاگ آؤٹ کریں اور نیا QR کوڈ اسکین کر کے دوبارہ منسلک ہوں
|
||||
|
||||
اگر سب کچھ کام کر رہا ہے، تو آپ آزادانہ طور پر چیٹ کر سکیں گے۔ اگر آپ کو انتباہات نظر آتے ہیں، تو آپ کو اپنے واٹس ایپ اکاؤنٹ کو دوبارہ منسلک کرنے کی ضرورت ہو سکتی ہے۔
|
||||
|
||||
آئیے شروع کریں! 🚀
|
||||
|
||||
app.disconnected.message: |-
|
||||
🔌 **منقطع: واٹس ایپ سیشن ChatWoot انبکس سے**
|
||||
|
||||
❌ واٹس ایپ سیشن **{{{name}}}** اس ChatWoot انبکس سے منقطع ہو گیا ہے۔
|
||||
|
||||
آپ اب واٹس ایپ سے پیغامات بھیجنے یا موصول کرنے کے قابل نہیں ہوں گے۔
|
||||
|
||||
دوبارہ منسلک ہونے کے لیے، براہ کرم اپنے منتظم سے رابطہ کریں۔
|
||||
|
||||
app.updated.message: |-
|
||||
🔄 **اپڈیٹ شدہ: واٹس ایپ سیشن کی ترتیبات**
|
||||
|
||||
✅ واٹس ایپ سیشن **{{{name}}}** کی ترتیبات اپڈیٹ کر دی گئی ہیں۔
|
||||
|
||||
app.commands.list: |-
|
||||
آپ درج ذیل کمانڈز میں سے ایک بھیج کر **واٹس ایپ انٹیگریشن** کا انتظام کر سکتے ہیں:
|
||||
|
||||
🖥️ **سیشن**:
|
||||
1. **status** - موجودہ سیشن کی حالت حاصل کریں۔
|
||||
2. **restart** - سیشن کو دوبارہ شروع کریں - یہ آپ کے واٹس ایپ اکاؤنٹ کو دوبارہ منسلک کرنے کی کوشش کرے گا۔
|
||||
3. **start** - سیشن شروع کریں۔
|
||||
4. **stop** - سیشن روکیں۔
|
||||
5. **logout** - سیشن سے لاگ آؤٹ کریں، تاکہ آپ QR کوڈ اسکین کر سکیں اور سیشن کی مرمت کر سکیں۔
|
||||
6. **qr** - سیشن کے لیے QR کوڈ حاصل کریں۔
|
||||
7. **screenshot** - سیشن کا اسکرین شاٹ حاصل کریں (صرف **WEBJS** انجن میں دستیاب)۔
|
||||
8. **help** - دستیاب کمانڈز۔
|
||||
|
||||
{{#commands.server}}
|
||||
⚙️ سرور:
|
||||
- **server status** - سرور ورژن اور حالت کی معلومات حاصل کریں۔
|
||||
- **server reboot** - سرور کو آرام سے دوبارہ شروع کریں۔
|
||||
- **server reboot force** - سرور کو زبردستی دوبارہ شروع کریں۔
|
||||
{{/commands.server}}
|
||||
|
||||
اس گفتگو میں **کمانڈ** (کیس سے غیر حساس) یا **کمانڈ نمبر** بھیجیں۔
|
||||
|
||||
app.commands.server.disabled: ⛔ **سرور کمانڈز غیر فعال ہیں**۔
|
||||
|
||||
براہ کرم اپنے منتظم سے رابطہ کریں۔
|
||||
|
||||
دستیاب کمانڈز کی فہرست حاصل کرنے کے لیے **help** بھیجیں۔
|
||||
|
||||
app.help.reminder: |-
|
||||
دستیاب کمانڈز کی فہرست حاصل کرنے کے لیے **help** بھیجیں۔
|
||||
|
||||
app.session.status.change: |-
|
||||
{{{emoji}}} "{{{session}}}" سیشن {{{status}}} حالت میں تبدیل ہو گیا
|
||||
|
||||
app.session.current.status: |-
|
||||
{{{emoji}}} **{{{session}}}** سیشن کی حالت **{{{status}}}** میں ہے
|
||||
**واٹس ایپ اکاؤنٹ:**
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
app.session.status.working: |-
|
||||
✅ یہ ChatWoot انبکس **واٹس ایپ اکاؤنٹ** سے منسلک ہے اور پیغامات بھیجنے اور موصول کرنے کے لیے تیار ہے!
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
app.session.status.error: |-
|
||||
⚠️ **یہ ChatWoot انبکس واٹس ایپ اکاؤنٹ سے منسلک ہے لیکن پیغامات بھیجنے اور موصول کرنے کے لیے تیار نہیں ہے!**
|
||||
|
||||
براہ کرم سیشن کی حالت چیک کریں اور اسے دوبارہ شروع کرنے کی کوشش کریں یا لاگ آؤٹ کریں اور QR کوڈ دوبارہ اسکین کریں۔
|
||||
|
||||
app.session.scan.qr.code: |-
|
||||
⚠️ **اس ChatWoot انبکس کے ساتھ واٹس ایپ اکاؤنٹ کو منسلک کرنے کے لیے اپنے فون پر QR کوڈ اسکین کریں!**
|
||||
|
||||
app.server.version.and.status: |-
|
||||
**ورژن:**
|
||||
```
|
||||
{{{version}}}
|
||||
```
|
||||
|
||||
**حالت:**
|
||||
```
|
||||
{{{status}}}
|
||||
```
|
||||
|
||||
app.server.reboot: |-
|
||||
سرور آرام سے دوبارہ شروع ہو رہا ہے...
|
||||
|
||||
app.server.reboot.force: |-
|
||||
سرور زبردستی دوبارہ شروع ہو رہا ہے...
|
||||
|
||||
app.logout.success: |-
|
||||
✅ اکاؤنٹ کامیابی سے غیر مجاز ہو گیا!
|
||||
|
||||
waha.new.version.available: |-
|
||||
🔄 **نیا ورژن دستیاب ہے!**
|
||||
|
||||
موجودہ ورژن: **{{{currentVersion}}}**
|
||||
نیا ورژن: **{{{newVersion}}}**
|
||||
|
||||
👉 [**🆕 تبدیلیوں کی فہرست**]({{{changelogUrl}}}) میں نیا کیا ہے دیکھیں
|
||||
|
||||
waha.core.version.used: |-
|
||||
❤️ **WAHA کی حمایت کریں!**
|
||||
|
||||
آپ مفت **WAHA Core** ورژن استعمال کر رہے ہیں۔ اگر آپ کو یہ پروجیکٹ مفید لگتا ہے، تو براہ کرم اس کی ترقی کی حمایت کرنے پر غور کریں۔
|
||||
|
||||
آپ کی حمایت ہی وہ واحد طریقہ ہے جس سے ہم اپڈیٹس، فکسز، اور نئی خصوصیات پر کام جاری رکھ سکتے ہیں۔
|
||||
|
||||
[**🎁 ہماری حمایت کریں**]({{{supportUrl}}})
|
||||
|
||||
chatwoot.to.whatsapp.message.text: |-
|
||||
{{{ content }}}
|
||||
|
||||
chatwoot.to.whatsapp.message.media.caption: |-
|
||||
{{#singleAttachment}}
|
||||
{{#content}}
|
||||
{{{ content }}}
|
||||
{{/content}}
|
||||
{{/singleAttachment}}
|
||||
|
||||
whatsapp.to.chatwoot.message: |-
|
||||
{{{payload.body}}}
|
||||
|
||||
whatsapp.to.chatwoot.message.contacts: |-
|
||||
👤 **شیئر کیے گئے رابطہ(رابطے)**
|
||||
|
||||
{{#contacts}}
|
||||
🪪 نام: **{{fullName}}**
|
||||
{{#phoneNumbers}}
|
||||
- 📞 فون: **{{.}}**
|
||||
{{/phoneNumbers}}
|
||||
|
||||
{{/contacts}}
|
||||
|
||||
whatsapp.to.chatwoot.message.location: |-
|
||||
{{#message}}
|
||||
{{#locationMessage}}
|
||||
📍 **شیئر کی گئی لوکیشن**
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/locationMessage}}
|
||||
|
||||
{{#liveLocationMessage}}
|
||||
📍📡 **لائیو لوکیشن شیئر کی جا رہی ہے**
|
||||
حقیقی وقت کی تازہ کاریوں کے لیے **WhatsApp** کھولیں۔
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/liveLocationMessage}}
|
||||
{{/message}}
|
||||
|
||||
whatsapp.to.chatwoot.message.unsupported: |-
|
||||
⚠️ **ChatWoot میں اس قسم کا پیغام معاونت یافتہ نہیں ہے۔**
|
||||
📱 اسے دیکھنے کے لیے براہ کرم **WhatsApp** کھولیں۔
|
||||
|
||||
تفصیلات: [{{{details.text}}}]({{{details.url}}})
|
||||
@@ -0,0 +1,238 @@
|
||||
# Simplified Chinese translations for ChatWoot integration
|
||||
locale.name: '🇨🇳 中文(Simplified Chinese)'
|
||||
app.inbox.contact.name: 'WhatsApp 集成(WAHA)'
|
||||
app.inbox.contact.avatar.url: 'https://raw.githubusercontent.com/devlikeapro/waha/core/logo.png'
|
||||
|
||||
job.report.error: |-
|
||||
⚠️ **{{{header}}}**
|
||||
{{#attempts.nextDelay}}
|
||||
🔄 将在 {{attempts.nextDelay}} 秒后重试...
|
||||
{{/attempts.nextDelay}}
|
||||
{{^attempts.nextDelay}}
|
||||
❌ 没有更多重试机会。请稍后再试。
|
||||
{{/attempts.nextDelay}}
|
||||
尝试:{{{attempts.current}}} / {{{attempts.max}}}
|
||||
详情:[{{{details.text}}}]({{{details.url}}})
|
||||
{{#error}}
|
||||
```
|
||||
|
||||
{{{error}}}
|
||||
```
|
||||
{{/error}}
|
||||
|
||||
job.report.succeeded: |-
|
||||
✅ **成功**
|
||||
尝试:{{{attempts.current}}} / {{{attempts.max}}}
|
||||
详情:[{{{details.text}}}]({{{details.url}}})
|
||||
|
||||
whatsapp.message.sending.error: 无法在 WhatsApp 中发送消息。
|
||||
whatsapp.message.receiving.error: 无法接收来自 WhatsApp 的消息
|
||||
whatsapp.message.removing.error: 无法从 WhatsApp 中删除消息
|
||||
job.scheduled.error.header: 计划任务执行失败
|
||||
|
||||
message.from.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *通过 WhatsApp 发送*
|
||||
|
||||
message.from.api: |-
|
||||
{{{text}}}
|
||||
|
||||
📱 *通过 API 发送*
|
||||
|
||||
message.removed.in.whatsapp: |-
|
||||
❌ *此消息已在 WhatsApp 中被删除*
|
||||
|
||||
message.edited.in.whatsapp: |-
|
||||
{{{text}}}
|
||||
|
||||
✏️ *已在 WhatsApp 中编辑*
|
||||
|
||||
whatsapp.group.message: |-
|
||||
👥 *{{{participant}}}*
|
||||
|
||||
{{{text}}}
|
||||
|
||||
whatsapp.reaction.added: |-
|
||||
*已反应* {{{emoji}}}
|
||||
|
||||
whatsapp.reaction.removed: |-
|
||||
*已移除反应*
|
||||
|
||||
whatsapp.contact.group.suffix: '群组'
|
||||
whatsapp.contact.channel.suffix: '频道'
|
||||
whatsapp.contact.broadcast.suffix: '广播列表'
|
||||
# Aka Stories
|
||||
whatsapp.contact.status.name: '状态'
|
||||
|
||||
app.connected.message: |-
|
||||
🔗 **已连接:WhatsApp 会话到 ChatWoot 收件箱**
|
||||
|
||||
✅ WhatsApp 会话 **{{{name}}}** 已成功连接到此 ChatWoot 收件箱。
|
||||
|
||||
此收件箱现已链接到你的**WhatsApp 账号**。你可以在这里直接收发消息——就像使用 WhatsApp 一样,但在 ChatWoot 内完成。
|
||||
|
||||
你也可以管理与此收件箱关联的 WhatsApp 会话。要查看可用操作,请向此对话发送 **help**。
|
||||
|
||||
📋 你可以执行的常见操作:
|
||||
- 检查 WhatsApp 会话是否活动
|
||||
- 重启或停止 WhatsApp 会话
|
||||
- 登出并通过扫描新的二维码重新连接
|
||||
|
||||
如果一切正常,你就可以自由聊天。如果你看到警告,可能需要重新连接你的 WhatsApp 账号。
|
||||
|
||||
开始吧!🚀
|
||||
|
||||
app.disconnected.message: |-
|
||||
🔌 **已断开:从 ChatWoot 收件箱断开 WhatsApp 会话**
|
||||
|
||||
❌ WhatsApp 会话 **{{{name}}}** 已与此 ChatWoot 收件箱断开。
|
||||
|
||||
你将无法再从 WhatsApp 发送或接收消息。
|
||||
|
||||
如需重新连接,请联系你的管理员。
|
||||
|
||||
app.updated.message: |-
|
||||
🔄 **已更新:WhatsApp 会话设置**
|
||||
|
||||
✅ WhatsApp 会话 **{{{name}}}** 的设置已更新。
|
||||
|
||||
app.commands.list: |-
|
||||
你可以通过发送以下命令来管理**WhatsApp 集成**:
|
||||
|
||||
🖥️ **会话**:
|
||||
1. **status** - 获取当前会话状态。
|
||||
2. **restart** - 重启会话——将尝试重新连接你的 WhatsApp 账号。
|
||||
3. **start** - 启动会话。
|
||||
4. **stop** - 停止会话。
|
||||
5. **logout** - 登出会话,以便你可以扫描二维码并修复会话。
|
||||
6. **qr** - 获取该会话的二维码。
|
||||
7. **screenshot** - 获取会话截图(仅在 **WEBJS** 引擎中可用)。
|
||||
8. **help** - 查看可用命令。
|
||||
|
||||
{{#commands.server}}
|
||||
{{#commands.server}}
|
||||
⚙️ 服务器:
|
||||
- **server status** - 获取服务器版本和状态信息。
|
||||
- **server reboot** - 优雅地重启服务器。
|
||||
- **server reboot force** - 强制重启服务器。
|
||||
{{/commands.server}}
|
||||
{{/commands.server}}
|
||||
|
||||
向此对话发送**命令**(不区分大小写)或**命令编号**。
|
||||
|
||||
app.commands.server.disabled: ⛔ **服务器命令已禁用**。
|
||||
|
||||
请联系你的管理员。
|
||||
|
||||
发送 **help** 获取可用命令列表。
|
||||
|
||||
app.help.reminder: |-
|
||||
发送 **help** 获取可用命令列表。
|
||||
|
||||
app.session.status.change: |-
|
||||
{{{emoji}}} "{{{session}}}" 会话已切换为 {{{status}}} 状态
|
||||
|
||||
app.session.current.status: |-
|
||||
{{{emoji}}} **{{{session}}}** 会话状态为 **{{{status}}}**
|
||||
**WhatsApp 账号:**
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
app.session.status.working: |-
|
||||
✅ 此 ChatWoot 收件箱已链接到**WhatsApp 账号**,可以正常收发消息!
|
||||
|
||||
📱 **{{{name}}} ({{{id}}})**
|
||||
|
||||
app.session.status.error: |-
|
||||
⚠️ **此 ChatWoot 收件箱已链接到 WhatsApp 账号,但尚未准备好收发消息!**
|
||||
|
||||
请检查会话状态,尝试重启,或登出后重新扫描二维码。
|
||||
|
||||
app.session.scan.qr.code: |-
|
||||
⚠️ **请在手机上扫描二维码,将 WhatsApp 账号与此 ChatWoot 收件箱关联!**
|
||||
|
||||
app.server.version.and.status: |-
|
||||
**版本:**
|
||||
```
|
||||
{{{version}}}
|
||||
```
|
||||
|
||||
**状态:**
|
||||
```
|
||||
{{{status}}}
|
||||
```
|
||||
|
||||
app.server.reboot: |-
|
||||
服务器正在优雅重启...
|
||||
|
||||
app.server.reboot.force: |-
|
||||
服务器正在强制重启...
|
||||
|
||||
app.logout.success: |-
|
||||
✅ 账号已成功取消授权!
|
||||
|
||||
waha.new.version.available: |-
|
||||
🔄 **有新版本可用!**
|
||||
|
||||
当前版本:**{{{currentVersion}}}**
|
||||
新版本:**{{{newVersion}}}**
|
||||
|
||||
👉 查看[**🆕 更新日志**]({{{changelogUrl}}})
|
||||
|
||||
waha.core.version.used: |-
|
||||
❤️ **支持 WAHA!**
|
||||
|
||||
你正在使用免费的 **WAHA Core** 版本。如果你觉得该项目有帮助,请考虑支持其开发。
|
||||
|
||||
你的支持是我们持续进行更新、修复和新增功能的唯一动力。
|
||||
|
||||
[**🎁 支持我们**]({{{supportUrl}}})
|
||||
|
||||
chatwoot.to.whatsapp.message.text: |-
|
||||
{{{ content }}}
|
||||
|
||||
chatwoot.to.whatsapp.message.media.caption: |-
|
||||
{{#singleAttachment}}
|
||||
{{#content}}
|
||||
{{{ content }}}
|
||||
{{/content}}
|
||||
{{/singleAttachment}}
|
||||
|
||||
whatsapp.to.chatwoot.message: |-
|
||||
{{{payload.body}}}
|
||||
|
||||
whatsapp.to.chatwoot.message.contacts: |-
|
||||
👤 **共享联系人**
|
||||
|
||||
{{#contacts}}
|
||||
🪪 姓名: **{{fullName}}**
|
||||
{{#phoneNumbers}}
|
||||
- 📞 电话: **{{.}}**
|
||||
{{/phoneNumbers}}
|
||||
|
||||
{{/contacts}}
|
||||
|
||||
whatsapp.to.chatwoot.message.location: |-
|
||||
{{#message}}
|
||||
{{#locationMessage}}
|
||||
📍 **共享位置**
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/locationMessage}}
|
||||
|
||||
{{#liveLocationMessage}}
|
||||
📍📡 **正在共享实时位置**
|
||||
打开 **WhatsApp** 查看实时更新。
|
||||
|
||||
https://www.google.com/maps?q={{degreesLatitude}},{{degreesLongitude}}
|
||||
{{#caption}}{{caption}}{{/caption}}
|
||||
{{/liveLocationMessage}}
|
||||
{{/message}}
|
||||
|
||||
whatsapp.to.chatwoot.message.unsupported: |-
|
||||
⚠️ **ChatWoot 不支持此消息类型。**
|
||||
📱 请打开 **WhatsApp** 查看。
|
||||
|
||||
详情: [{{{details.text}}}]({{{details.url}}})
|
||||
@@ -0,0 +1,189 @@
|
||||
import type { proto } from '@adiwajshing/baileys';
|
||||
import { ChatWootCommandsConfig } from '@waha/apps/chatwoot/dto/config.dto';
|
||||
import { WAMessage } from '@waha/structures/responses.dto';
|
||||
import { SimpleVCardInfo } from '@waha/core/vcard';
|
||||
|
||||
export enum TKey {
|
||||
LOCALE_NAME = 'locale.name',
|
||||
|
||||
//
|
||||
// Jobs
|
||||
//
|
||||
JOB_REPORT_ERROR = 'job.report.error',
|
||||
JOB_REPORT_SUCCEEDED = 'job.report.succeeded',
|
||||
JOB_SCHEDULED_ERROR_HEADER = 'job.scheduled.error.header',
|
||||
|
||||
//
|
||||
// WhatsApp Message Status
|
||||
//
|
||||
WHATSAPP_MESSAGE_SENDING_ERROR = 'whatsapp.message.sending.error',
|
||||
WHATSAPP_MESSAGE_RECEIVING_ERROR = 'whatsapp.message.receiving.error',
|
||||
WHATSAPP_MESSAGE_REMOVING_ERROR = 'whatsapp.message.removing.error',
|
||||
|
||||
//
|
||||
// WhatsApp Messages
|
||||
//
|
||||
MESSAGE_FROM_WHATSAPP = 'message.from.whatsapp',
|
||||
MESSAGE_FROM_API = 'message.from.api',
|
||||
MESSAGE_REMOVED_IN_WHATSAPP = 'message.removed.in.whatsapp',
|
||||
MESSAGE_EDITED_IN_WHATSAPP = 'message.edited.in.whatsapp',
|
||||
WHATSAPP_GROUP_MESSAGE = 'whatsapp.group.message',
|
||||
WHATSAPP_REACTION_ADDED = 'whatsapp.reaction.added',
|
||||
WHATSAPP_REACTION_REMOVED = 'whatsapp.reaction.removed',
|
||||
|
||||
//
|
||||
// Contact Suffixes
|
||||
//
|
||||
WHATSAPP_CONTACT_GROUP_SUFFIX = 'whatsapp.contact.group.suffix',
|
||||
WHATSAPP_CONTACT_CHANNEL_SUFFIX = 'whatsapp.contact.channel.suffix',
|
||||
WHATSAPP_CONTACT_BROADCAST_SUFFIX = 'whatsapp.contact.broadcast.suffix',
|
||||
WHATSAPP_CONTACT_STATUS_NAME = 'whatsapp.contact.status.name',
|
||||
|
||||
//
|
||||
// ChatWoot to WhatsApp
|
||||
//
|
||||
CW_TO_WA_MESSAGE_TEXT = 'chatwoot.to.whatsapp.message.text',
|
||||
CW_TO_WA_MESSAGE_MEDIA_CAPTION = 'chatwoot.to.whatsapp.message.media.caption',
|
||||
|
||||
//
|
||||
// WhatsApp to ChatWoot
|
||||
//
|
||||
WA_TO_CW_MESSAGE = 'whatsapp.to.chatwoot.message',
|
||||
WA_TO_CW_MESSAGE_CONTACTS = 'whatsapp.to.chatwoot.message.contacts',
|
||||
WA_TO_CW_MESSAGE_LOCATION = 'whatsapp.to.chatwoot.message.location',
|
||||
WA_TO_CW_MESSAGE_UNSUPPORTED = 'whatsapp.to.chatwoot.message.unsupported',
|
||||
|
||||
//
|
||||
// App Inbox
|
||||
//
|
||||
APP_INBOX_CONTACT_NAME = 'app.inbox.contact.name',
|
||||
APP_INBOX_CONTACT_AVATAR_URL = 'app.inbox.contact.avatar.url',
|
||||
|
||||
//
|
||||
// App Status
|
||||
//
|
||||
APP_CONNECTED_MESSAGE = 'app.connected.message',
|
||||
APP_DISCONNECTED_MESSAGE = 'app.disconnected.message',
|
||||
APP_UPDATED_MESSAGE = 'app.updated.message',
|
||||
|
||||
//
|
||||
// App Session Status
|
||||
//
|
||||
APP_SESSION_STATUS_CHANGE = 'app.session.status.change',
|
||||
APP_SESSION_CURRENT_STATUS = 'app.session.current.status',
|
||||
APP_SESSION_STATUS_WORKING = 'app.session.status.working',
|
||||
APP_SESSION_STATUS_ERROR = 'app.session.status.error',
|
||||
APP_SESSION_SCAN_QR_CODE = 'app.session.scan.qr.code',
|
||||
|
||||
//
|
||||
// App Commands
|
||||
//
|
||||
APP_COMMANDS_LIST = 'app.commands.list',
|
||||
APP_COMMANDS_SERVER_DISABLED = 'app.commands.server.disabled',
|
||||
APP_HELP_REMINDER = 'app.help.reminder',
|
||||
APP_SERVER_VERSION_AND_STATUS = 'app.server.version.and.status',
|
||||
APP_SERVER_REBOOT = 'app.server.reboot',
|
||||
APP_SERVER_REBOOT_FORCE = 'app.server.reboot.force',
|
||||
APP_LOGOUT_SUCCESS = 'app.logout.success',
|
||||
|
||||
//
|
||||
// App Inbox
|
||||
//
|
||||
WAHA_NEW_VERSION_AVAILABLE = 'waha.new.version.available',
|
||||
WAHA_CORE_VERSION_USED = 'waha.core.version.used',
|
||||
}
|
||||
|
||||
// Define payload types
|
||||
interface Link {
|
||||
text: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export type TemplatePayloads = {
|
||||
[TKey.LOCALE_NAME]: void;
|
||||
[TKey.APP_INBOX_CONTACT_NAME]: void;
|
||||
[TKey.APP_INBOX_CONTACT_AVATAR_URL]: void;
|
||||
[TKey.MESSAGE_FROM_WHATSAPP]: { text: string };
|
||||
[TKey.MESSAGE_FROM_API]: { text: string };
|
||||
[TKey.MESSAGE_REMOVED_IN_WHATSAPP]: void;
|
||||
[TKey.MESSAGE_EDITED_IN_WHATSAPP]: { text: string };
|
||||
[TKey.WHATSAPP_GROUP_MESSAGE]: { text: string; participant: string };
|
||||
[TKey.WHATSAPP_REACTION_ADDED]: { emoji: string };
|
||||
[TKey.WHATSAPP_REACTION_REMOVED]: void;
|
||||
[TKey.WHATSAPP_MESSAGE_SENDING_ERROR]: void;
|
||||
[TKey.WHATSAPP_MESSAGE_RECEIVING_ERROR]: void;
|
||||
[TKey.WHATSAPP_MESSAGE_REMOVING_ERROR]: void;
|
||||
[TKey.WHATSAPP_CONTACT_GROUP_SUFFIX]: void;
|
||||
[TKey.WHATSAPP_CONTACT_CHANNEL_SUFFIX]: void;
|
||||
[TKey.WHATSAPP_CONTACT_BROADCAST_SUFFIX]: void;
|
||||
[TKey.WHATSAPP_CONTACT_STATUS_NAME]: void;
|
||||
[TKey.CW_TO_WA_MESSAGE_TEXT]: {
|
||||
content: string;
|
||||
chatwoot: any;
|
||||
};
|
||||
[TKey.CW_TO_WA_MESSAGE_MEDIA_CAPTION]: {
|
||||
content: string;
|
||||
chatwoot: any;
|
||||
singleAttachment: boolean;
|
||||
};
|
||||
[TKey.WA_TO_CW_MESSAGE]: {
|
||||
payload: WAMessage;
|
||||
};
|
||||
[TKey.WA_TO_CW_MESSAGE_CONTACTS]: { contacts: SimpleVCardInfo[] };
|
||||
[TKey.WA_TO_CW_MESSAGE_LOCATION]: { payload: any; message: proto.Message };
|
||||
[TKey.WA_TO_CW_MESSAGE_UNSUPPORTED]: { details: Link };
|
||||
[TKey.JOB_SCHEDULED_ERROR_HEADER]: void;
|
||||
[TKey.JOB_REPORT_ERROR]: {
|
||||
header: string;
|
||||
error: string;
|
||||
details: Link;
|
||||
attempts: {
|
||||
current: number;
|
||||
max: number;
|
||||
nextDelay?: number;
|
||||
};
|
||||
};
|
||||
[TKey.JOB_REPORT_SUCCEEDED]: {
|
||||
details: Link;
|
||||
attempts: {
|
||||
current: number;
|
||||
max: number;
|
||||
};
|
||||
};
|
||||
[TKey.APP_CONNECTED_MESSAGE]: { name: string };
|
||||
[TKey.APP_DISCONNECTED_MESSAGE]: { name: string };
|
||||
[TKey.APP_UPDATED_MESSAGE]: { name: string };
|
||||
[TKey.APP_SESSION_STATUS_CHANGE]: {
|
||||
emoji: string;
|
||||
session: string;
|
||||
status: string;
|
||||
};
|
||||
[TKey.APP_SESSION_CURRENT_STATUS]: {
|
||||
emoji: string;
|
||||
session: string;
|
||||
status: string;
|
||||
name: string;
|
||||
id: string;
|
||||
};
|
||||
[TKey.APP_SESSION_STATUS_WORKING]: { name: string; id: string };
|
||||
[TKey.APP_SESSION_STATUS_ERROR]: void;
|
||||
[TKey.APP_SESSION_SCAN_QR_CODE]: void;
|
||||
[TKey.APP_HELP_REMINDER]: void;
|
||||
[TKey.APP_COMMANDS_LIST]: { commands: ChatWootCommandsConfig };
|
||||
[TKey.APP_COMMANDS_SERVER_DISABLED]: void;
|
||||
[TKey.APP_SERVER_VERSION_AND_STATUS]: {
|
||||
version: string;
|
||||
status: string;
|
||||
};
|
||||
[TKey.APP_SERVER_REBOOT]: void;
|
||||
[TKey.APP_SERVER_REBOOT_FORCE]: void;
|
||||
[TKey.APP_LOGOUT_SUCCESS]: void;
|
||||
[TKey.WAHA_NEW_VERSION_AVAILABLE]: {
|
||||
currentVersion: string;
|
||||
newVersion: string;
|
||||
changelogUrl: string;
|
||||
};
|
||||
[TKey.WAHA_CORE_VERSION_USED]: {
|
||||
supportUrl: string;
|
||||
};
|
||||
};
|
||||
@@ -1,233 +0,0 @@
|
||||
import * as fs from 'fs-extra';
|
||||
import * as lodash from 'lodash';
|
||||
import * as Mustache from 'mustache';
|
||||
import * as path from 'path';
|
||||
import * as yaml from 'yaml';
|
||||
|
||||
export enum LocaleCode {
|
||||
EN_US = 'en-US',
|
||||
AR_AE = 'ar-AE',
|
||||
BN_BD = 'bn-BD',
|
||||
PT_BR = 'pt-BR',
|
||||
DE_DE = 'de-DE',
|
||||
ES_ES = 'es-ES',
|
||||
FR_FR = 'fr-FR',
|
||||
ID_ID = 'id-ID',
|
||||
HE_IL = 'he-IL',
|
||||
HI_IN = 'hi-IN',
|
||||
FA_IR = 'fa-IR',
|
||||
PA_PK = 'pa-PK',
|
||||
RU_RU = 'ru-RU',
|
||||
TR_TR = 'tr-TR',
|
||||
UK_UA = 'uk-UA',
|
||||
}
|
||||
|
||||
export const LOCALES = [
|
||||
LocaleCode.EN_US,
|
||||
LocaleCode.AR_AE,
|
||||
LocaleCode.BN_BD,
|
||||
LocaleCode.PT_BR,
|
||||
LocaleCode.DE_DE,
|
||||
LocaleCode.ES_ES,
|
||||
LocaleCode.FR_FR,
|
||||
LocaleCode.ID_ID,
|
||||
LocaleCode.HE_IL,
|
||||
LocaleCode.HI_IN,
|
||||
LocaleCode.FA_IR,
|
||||
LocaleCode.PA_PK,
|
||||
LocaleCode.RU_RU,
|
||||
LocaleCode.TR_TR,
|
||||
LocaleCode.UK_UA,
|
||||
];
|
||||
|
||||
export const LOCALE_NAMES: Record<LocaleCode, string> = {
|
||||
[LocaleCode.EN_US]: '🇺🇸 English (English)',
|
||||
[LocaleCode.AR_AE]: '🇦🇪 العربية (Arabic)',
|
||||
[LocaleCode.BN_BD]: '🇧🇩 বাংলা (Bengali)',
|
||||
[LocaleCode.PT_BR]: '🇧🇷🇵🇹 Português (Portuguese)',
|
||||
[LocaleCode.DE_DE]: '🇩🇪 Deutsch (German)',
|
||||
[LocaleCode.ES_ES]: '🇪🇸 Español (Spanish)',
|
||||
[LocaleCode.FR_FR]: '🇫🇷 Français (French)',
|
||||
[LocaleCode.ID_ID]: '🇮🇩 Bahasa Indonesia (Indonesian)',
|
||||
[LocaleCode.HE_IL]: '🇮🇱 עברית (Hebrew)',
|
||||
[LocaleCode.HI_IN]: '🇮🇳 हिंदी (Hindi)',
|
||||
[LocaleCode.FA_IR]: '🇮🇷 فارسی (Persian)',
|
||||
[LocaleCode.PA_PK]: '🇵🇰 ਪੰਜਾਬੀ (Punjabi)',
|
||||
[LocaleCode.RU_RU]: '🇷🇺 Русский (Russian)',
|
||||
[LocaleCode.TR_TR]: '🇹🇷 Türkçe (Turkish)',
|
||||
[LocaleCode.UK_UA]: '🇺🇦 Українська (Ukrainian)',
|
||||
};
|
||||
export const DEFAULT_LOCALE = 'en-US';
|
||||
|
||||
function loadTemplateStrings(locale: string) {
|
||||
const filename = `${locale}.yaml`;
|
||||
const yamlPath = path.join(__dirname, 'i18n', filename);
|
||||
const content = fs.readFileSync(yamlPath, 'utf-8');
|
||||
return yaml.parse(content);
|
||||
}
|
||||
|
||||
export interface Link {
|
||||
text: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
function loadLocales(locales: string[]) {
|
||||
const defaults = loadTemplateStrings(DEFAULT_LOCALE);
|
||||
const result: Record<string, Record<string, string>> = {};
|
||||
for (const locale of locales) {
|
||||
const strings = loadTemplateStrings(locale);
|
||||
result[locale] = lodash.merge({}, defaults, strings);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
let locales: Record<string, Record<string, string>> = {};
|
||||
try {
|
||||
locales = loadLocales(LOCALES);
|
||||
} catch (error) {
|
||||
console.error('Error loading locales:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
export enum TKey {
|
||||
WHATSAPP_ERROR_SENDING_MESSAGE = 'WHATSAPP_ERROR_SENDING_MESSAGE',
|
||||
WHATSAPP_ERROR_RECEIVING_MESSAGE = 'WHATSAPP_ERROR_RECEIVING_MESSAGE',
|
||||
WHATSAPP_ERROR_REMOVING_MESSAGE = 'WHATSAPP_ERROR_REMOVING_MESSAGE',
|
||||
JOB_ERROR_REPORT = 'JOB_ERROR_REPORT',
|
||||
JOB_SUCCEEDED_REPORT = 'JOB_SUCCEEDED_REPORT',
|
||||
MESSAGE_FROM_WHATSAPP = 'MESSAGE_FROM_WHATSAPP',
|
||||
MESSAGE_FROM_API = 'MESSAGE_FROM_API',
|
||||
MESSAGE_REMOVED_IN_WHATSAPP = 'MESSAGE_REMOVED_IN_WHATSAPP',
|
||||
MESSAGE_EDITED_IN_WHATSAPP = 'MESSAGE_EDITED_IN_WHATSAPP',
|
||||
WHATSAPP_GROUP_MESSAGE = 'WHATSAPP_GROUP_MESSAGE',
|
||||
WHATSAPP_REACTION_ADDED = 'WHATSAPP_REACTION_ADDED',
|
||||
WHATSAPP_REACTION_REMOVED = 'WHATSAPP_REACTION_REMOVED',
|
||||
//
|
||||
// Contact Suffixes
|
||||
//
|
||||
WHATSAPP_CONTACT_GROUP_SUFFIX = 'WHATSAPP_CONTACT_GROUP_SUFFIX',
|
||||
WHATSAPP_CONTACT_CHANNEL_SUFFIX = 'WHATSAPP_CONTACT_CHANNEL_SUFFIX',
|
||||
WHATSAPP_CONTACT_STATUS_NAME = 'WHATSAPP_CONTACT_STATUS_NAME',
|
||||
|
||||
//
|
||||
// App Inbox
|
||||
//
|
||||
APP_INBOX_CONTACT_NAME = 'APP_INBOX_CONTACT_NAME',
|
||||
APP_INBOX_CONTACT_AVATAR_URL = 'APP_INBOX_CONTACT_AVATAR_URL',
|
||||
APP_CONNECTED_MESSAGE = 'APP_CONNECTED_MESSAGE',
|
||||
APP_DISCONNECTED_MESSAGE = 'APP_DISCONNECTED_MESSAGE',
|
||||
APP_UPDATED_MESSAGE = 'APP_UPDATED_MESSAGE',
|
||||
APP_COMMANDS_LIST = 'APP_COMMANDS_LIST',
|
||||
APP_HELP_REMINDER = 'APP_HELP_REMINDER',
|
||||
APP_SESSION_STATUS_CHANGE = 'APP_SESSION_STATUS_CHANGE',
|
||||
APP_SESSION_CURRENT_STATUS = 'APP_SESSION_CURRENT_STATUS',
|
||||
APP_DASHBOARD_LINK = 'APP_DASHBOARD_LINK',
|
||||
APP_SESSION_STATUS_WORKING = 'APP_SESSION_STATUS_WORKING',
|
||||
APP_SESSION_STATUS_ERROR = 'APP_SESSION_STATUS_ERROR',
|
||||
APP_SESSION_SCAN_QR_CODE = 'APP_SESSION_SCAN_QR_CODE',
|
||||
APP_SERVER_VERSION_AND_STATUS = 'APP_SERVER_VERSION_AND_STATUS',
|
||||
APP_SERVER_REBOOT = 'APP_SERVER_REBOOT',
|
||||
APP_SERVER_REBOOT_FORCE = 'APP_SERVER_REBOOT_FORCE',
|
||||
APP_LOGOUT_SUCCESS = 'APP_LOGOUT_SUCCESS',
|
||||
APP_NEW_VERSION_AVAILABLE = 'APP_NEW_VERSION_AVAILABLE',
|
||||
APP_CORE_VERSION_USED = 'APP_CORE_VERSION_USED',
|
||||
APP_SCHEDULED_JOB_ERROR = 'APP_SCHEDULED_JOB_ERROR',
|
||||
}
|
||||
|
||||
// Define payload types
|
||||
type TemplatePayloads = {
|
||||
[TKey.APP_INBOX_CONTACT_NAME]: void;
|
||||
[TKey.APP_INBOX_CONTACT_AVATAR_URL]: void;
|
||||
[TKey.MESSAGE_FROM_WHATSAPP]: { text: string };
|
||||
[TKey.MESSAGE_FROM_API]: { text: string };
|
||||
[TKey.MESSAGE_REMOVED_IN_WHATSAPP]: void;
|
||||
[TKey.MESSAGE_EDITED_IN_WHATSAPP]: { text: string };
|
||||
[TKey.WHATSAPP_GROUP_MESSAGE]: { text: string; participant: string };
|
||||
[TKey.WHATSAPP_REACTION_ADDED]: { emoji: string };
|
||||
[TKey.WHATSAPP_REACTION_REMOVED]: void;
|
||||
[TKey.WHATSAPP_ERROR_SENDING_MESSAGE]: void;
|
||||
[TKey.WHATSAPP_ERROR_RECEIVING_MESSAGE]: void;
|
||||
[TKey.WHATSAPP_ERROR_REMOVING_MESSAGE]: void;
|
||||
[TKey.WHATSAPP_CONTACT_GROUP_SUFFIX]: void;
|
||||
[TKey.WHATSAPP_CONTACT_CHANNEL_SUFFIX]: void;
|
||||
[TKey.WHATSAPP_CONTACT_STATUS_NAME]: void;
|
||||
[TKey.APP_SCHEDULED_JOB_ERROR]: void;
|
||||
[TKey.JOB_ERROR_REPORT]: {
|
||||
header: string;
|
||||
error: string;
|
||||
details: Link;
|
||||
attempts: {
|
||||
current: number;
|
||||
max: number;
|
||||
nextDelay?: number;
|
||||
};
|
||||
};
|
||||
[TKey.JOB_SUCCEEDED_REPORT]: {
|
||||
details: Link;
|
||||
attempts: {
|
||||
current: number;
|
||||
max: number;
|
||||
};
|
||||
};
|
||||
[TKey.APP_CONNECTED_MESSAGE]: { name: string };
|
||||
[TKey.APP_DISCONNECTED_MESSAGE]: { name: string };
|
||||
[TKey.APP_UPDATED_MESSAGE]: { name: string };
|
||||
[TKey.APP_SESSION_STATUS_CHANGE]: {
|
||||
emoji: string;
|
||||
session: string;
|
||||
status: string;
|
||||
};
|
||||
[TKey.APP_SESSION_CURRENT_STATUS]: {
|
||||
emoji: string;
|
||||
session: string;
|
||||
status: string;
|
||||
name: string;
|
||||
id: string;
|
||||
};
|
||||
[TKey.APP_DASHBOARD_LINK]: { url: string };
|
||||
[TKey.APP_SESSION_STATUS_WORKING]: { name: string; id: string };
|
||||
[TKey.APP_SESSION_STATUS_ERROR]: void;
|
||||
[TKey.APP_SESSION_SCAN_QR_CODE]: void;
|
||||
[TKey.APP_HELP_REMINDER]: void;
|
||||
[TKey.APP_COMMANDS_LIST]: void;
|
||||
[TKey.APP_SERVER_VERSION_AND_STATUS]: { version: string; status: string };
|
||||
[TKey.APP_SERVER_REBOOT]: void;
|
||||
[TKey.APP_SERVER_REBOOT_FORCE]: void;
|
||||
[TKey.APP_LOGOUT_SUCCESS]: void;
|
||||
[TKey.APP_NEW_VERSION_AVAILABLE]: {
|
||||
currentVersion: string;
|
||||
newVersion: string;
|
||||
changelogUrl: string;
|
||||
};
|
||||
[TKey.APP_CORE_VERSION_USED]: {
|
||||
supportUrl: string;
|
||||
};
|
||||
};
|
||||
|
||||
export class Locale {
|
||||
private readonly strings: Record<string, string>;
|
||||
|
||||
constructor(locale: string = DEFAULT_LOCALE) {
|
||||
locale = locale || DEFAULT_LOCALE;
|
||||
if (!locales[locale]) {
|
||||
throw new Error(`Locale '${locale}' not found`);
|
||||
}
|
||||
this.strings = locales[locale];
|
||||
}
|
||||
|
||||
key<K extends TKey>(key: K): Template<K> {
|
||||
return new Template(this.strings[key] || key);
|
||||
}
|
||||
}
|
||||
|
||||
export class Template<K extends TKey> {
|
||||
constructor(private readonly template: string) {}
|
||||
|
||||
render(data: TemplatePayloads[K]): string {
|
||||
return Mustache.render(this.template, data);
|
||||
}
|
||||
|
||||
r(data: TemplatePayloads[K]): string {
|
||||
return this.render(data);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Injectable, UnprocessableEntityException } from '@nestjs/common';
|
||||
import { IAppService } from '@waha/apps/app_sdk/services/IAppService';
|
||||
import { CacheForConfig } from '@waha/apps/chatwoot/cache/ConversationCache';
|
||||
import { CHATWOOT_CUSTOM_ATTRIBUTES } from '@waha/apps/chatwoot/const';
|
||||
@@ -10,7 +10,10 @@ import { WhatsappSession } from '@waha/core/abc/session.abc';
|
||||
import { InjectPinoLogger, PinoLogger } from 'nestjs-pino';
|
||||
|
||||
import { DIContainer } from '../di/DIContainer';
|
||||
import { TKey } from '../locale';
|
||||
|
||||
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
|
||||
import { session } from 'passport';
|
||||
import { i18n } from '@waha/apps/chatwoot/i18n';
|
||||
|
||||
@Injectable()
|
||||
export class ChatWootAppService implements IAppService {
|
||||
@@ -21,11 +24,37 @@ export class ChatWootAppService implements IAppService {
|
||||
protected logger: PinoLogger,
|
||||
) {}
|
||||
|
||||
validate(app: App<ChatWootAppConfig>): void {
|
||||
if (!i18n.has(app.config.locale)) {
|
||||
throw new UnprocessableEntityException(
|
||||
`Unknown '${app.config.locale}' locale in 'config.local'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async beforeCreated(app: App<ChatWootAppConfig>) {
|
||||
await this.setupCustomAttributes(app);
|
||||
await this.sendConnectedMessage(app);
|
||||
}
|
||||
|
||||
async beforeEnabled(
|
||||
savedApp: App<ChatWootAppConfig>,
|
||||
newApp: App<ChatWootAppConfig>,
|
||||
): Promise<void> {
|
||||
// Enabling -> behave like created
|
||||
await this.beforeCreated(newApp);
|
||||
return;
|
||||
}
|
||||
|
||||
async beforeDisabled(
|
||||
savedApp: App<ChatWootAppConfig>,
|
||||
newApp: App<ChatWootAppConfig>,
|
||||
): Promise<void> {
|
||||
// Disabling -> behave like deleted
|
||||
await this.beforeDeleted(savedApp);
|
||||
return;
|
||||
}
|
||||
|
||||
async beforeUpdated(
|
||||
savedApp: App<ChatWootAppConfig>,
|
||||
newApp: App<ChatWootAppConfig>,
|
||||
@@ -100,10 +129,8 @@ export class ChatWootAppService implements IAppService {
|
||||
|
||||
private async setupCustomAttributes(app: App<ChatWootAppConfig>) {
|
||||
const di = new DIContainer(0, app.config, this.logger, null);
|
||||
const api = di.CustomAttributesAPI();
|
||||
for (const attr of CHATWOOT_CUSTOM_ATTRIBUTES) {
|
||||
await api.upsert(attr);
|
||||
}
|
||||
const service = di.CustomAttributesService();
|
||||
await service.upsert(CHATWOOT_CUSTOM_ATTRIBUTES);
|
||||
}
|
||||
|
||||
private cleanCache(app: App<ChatWootAppConfig>) {
|
||||
|
||||
@@ -19,6 +19,10 @@ export class ChatWootQueueService {
|
||||
private readonly messageUpdatedQueue: Queue,
|
||||
@InjectQueue(QueueName.INBOX_MESSAGE_DELETED)
|
||||
private readonly messageDeletedQueue: Queue,
|
||||
@InjectQueue(QueueName.INBOX_CONVERSATION_CREATED)
|
||||
private readonly conversationCreatedQueue: Queue,
|
||||
@InjectQueue(QueueName.INBOX_CONVERSATION_STATUS_CHANGED)
|
||||
private readonly conversationStatusChanged: Queue,
|
||||
@InjectQueue(QueueName.INBOX_COMMANDS)
|
||||
private readonly commandsQueue: Queue,
|
||||
) {}
|
||||
@@ -41,10 +45,14 @@ export class ChatWootQueueService {
|
||||
*/
|
||||
private getQueueForEvent(event: string): Queue | null {
|
||||
switch (event) {
|
||||
case EventName.CONVERSATION_CREATED:
|
||||
return this.conversationCreatedQueue;
|
||||
case EventName.MESSAGE_CREATED:
|
||||
return this.messageCreatedQueue;
|
||||
case EventName.MESSAGE_UPDATED:
|
||||
return this.messageUpdatedQueue;
|
||||
case EventName.CONVERSATION_STATUS_CHANGED:
|
||||
return this.conversationStatusChanged;
|
||||
case 'message_deleted':
|
||||
return this.messageDeletedQueue;
|
||||
case 'commands':
|
||||
@@ -95,9 +103,9 @@ export class ChatWootQueueService {
|
||||
*/
|
||||
async addJobToQueue(event: string, data: InboxData): Promise<any> {
|
||||
const queue = this.getQueueForEvent(event);
|
||||
if (queue) {
|
||||
return await this.add(queue, event, data);
|
||||
if (!queue) {
|
||||
return;
|
||||
}
|
||||
return { ignored: true, event };
|
||||
await this.add(queue, event, data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import { ConversationStatus } from '@waha/apps/chatwoot/client/types';
|
||||
import { contact_conversations } from '@figuro/chatwoot-sdk/dist/models/contact_conversations';
|
||||
import * as lodash from 'lodash';
|
||||
import type { conversation } from '@figuro/chatwoot-sdk/dist/models/conversation';
|
||||
|
||||
export enum ConversationSort {
|
||||
activity_newest = 'activity_newest',
|
||||
created_newest = 'created_newest',
|
||||
created_oldest = 'created_oldest',
|
||||
activity_oldest = 'activity_oldest',
|
||||
}
|
||||
|
||||
export type ConversationSelectorConfig = {
|
||||
sort: ConversationSort;
|
||||
status?: Array<ConversationStatus>;
|
||||
inboxId: number;
|
||||
};
|
||||
|
||||
export type ConversationResult = Pick<conversation, 'id' | 'account_id'>;
|
||||
|
||||
export class ConversationSelector {
|
||||
constructor(private config: ConversationSelectorConfig) {}
|
||||
|
||||
hasStatusFilter() {
|
||||
return this.config.status;
|
||||
}
|
||||
|
||||
select(conversations: contact_conversations): ConversationResult | null {
|
||||
conversations = this.filter(conversations);
|
||||
conversations = this.sort(conversations);
|
||||
return conversations[0] || null;
|
||||
}
|
||||
|
||||
private filter(conversations: contact_conversations): contact_conversations {
|
||||
// Filter by inbox id
|
||||
conversations = lodash.filter(conversations, {
|
||||
inbox_id: this.config.inboxId,
|
||||
}) as contact_conversations;
|
||||
|
||||
// Filter by status
|
||||
if (this.config.status && this.config.status.length > 0) {
|
||||
conversations = lodash.filter(conversations, (conversation) => {
|
||||
return this.config.status.includes(
|
||||
conversation.status as ConversationStatus,
|
||||
);
|
||||
});
|
||||
}
|
||||
return conversations;
|
||||
}
|
||||
|
||||
private sort(conversations: contact_conversations): contact_conversations {
|
||||
let field = null;
|
||||
let dir = null;
|
||||
switch (this.config.sort) {
|
||||
case ConversationSort.activity_newest:
|
||||
[field, dir] = ['last_activity_at', 'desc'];
|
||||
break;
|
||||
case ConversationSort.created_newest:
|
||||
[field, dir] = ['created_at', 'desc'];
|
||||
break;
|
||||
case ConversationSort.created_oldest:
|
||||
[field, dir] = ['created_at', 'asc'];
|
||||
break;
|
||||
case ConversationSort.activity_oldest:
|
||||
[field, dir] = ['last_activity_at', 'asc'];
|
||||
}
|
||||
if (!field || !dir) {
|
||||
return conversations;
|
||||
}
|
||||
return lodash.orderBy(conversations, [field], [dir]);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { WhatsAppMessage } from '@waha/apps/chatwoot/storage';
|
||||
import { toCusFormat } from '@waha/core/engines/noweb/session.noweb.core';
|
||||
import { WAHAEngine } from '@waha/structures/enums.dto';
|
||||
import { getEngineName } from '@waha/version';
|
||||
import { Message as MessageInstance } from 'whatsapp-web.js/src/structures';
|
||||
import { toCusFormat } from '@waha/core/utils/jids';
|
||||
|
||||
interface IEngineHelper {
|
||||
WhatsAppMessageKeys(message: any): WhatsAppMessage;
|
||||
|
||||
@@ -74,4 +74,17 @@ export class MessageMappingRepository {
|
||||
})
|
||||
.first();
|
||||
}
|
||||
|
||||
async getByChatwootMessageIdAndPart(
|
||||
id: number,
|
||||
part: number,
|
||||
): Promise<MessageMapping | null> {
|
||||
return this.knex(this.tableName)
|
||||
.where({
|
||||
app_pk: this.appPk,
|
||||
chatwoot_message_id: id,
|
||||
part: part,
|
||||
})
|
||||
.first();
|
||||
}
|
||||
}
|
||||
@@ -123,4 +123,26 @@ export class MessageMappingService {
|
||||
}
|
||||
return whatsapp;
|
||||
}
|
||||
|
||||
async getMappingByChatwootCombinedKeyAndPart(
|
||||
chatwoot: ChatWootCombinedKey,
|
||||
part: number,
|
||||
): Promise<MessageMapping | null> {
|
||||
const chatwootMessages =
|
||||
await this.chatwootMessageRepository.getByCombinedKey(chatwoot);
|
||||
if (!chatwootMessages || chatwootMessages.length === 0) {
|
||||
return null;
|
||||
}
|
||||
for (const cw of chatwootMessages) {
|
||||
const mapping =
|
||||
await this.messageMappingRepository.getByChatwootMessageIdAndPart(
|
||||
cw.id,
|
||||
part,
|
||||
);
|
||||
if (mapping) {
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -20,12 +20,15 @@ export function MarkdownToWhatsApp(text: string): string {
|
||||
// Links: [text](url) → text (url)
|
||||
.replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g, '$1 ($2)')
|
||||
// Lists: -, +, * → * item
|
||||
.replace(/^[\-\+\*] (.*)/gm, '* $1')
|
||||
.replace(/^[-+*] (.*)/gm, '* $1')
|
||||
);
|
||||
}
|
||||
|
||||
export function WhatsappToMarkdown(text: string): string {
|
||||
if (!text) {
|
||||
return text;
|
||||
}
|
||||
if (text == '') {
|
||||
return '';
|
||||
}
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Injectable, Logger, OnApplicationBootstrap } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { GlobalWebhookConfigConfig } from '@waha/core/config/GlobalWebhookConfig';
|
||||
import { IgnoreJidConfig } from '@waha/core/utils/jids';
|
||||
|
||||
import { parseBool } from './helpers';
|
||||
import { WebhookConfig } from './structures/webhooks.config.dto';
|
||||
@@ -178,6 +179,26 @@ export class WhatsappConfigService implements OnApplicationBootstrap {
|
||||
return parseBool(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Global default "ignore settings" for chats.
|
||||
* If not defined, defaults to false (do not ignore anything).
|
||||
*/
|
||||
getIgnoreChatsConfig(): IgnoreJidConfig {
|
||||
const status = parseBool(
|
||||
this.configService.get('WAHA_SESSION_CONFIG_IGNORE_STATUS', 'false'),
|
||||
);
|
||||
const groups = parseBool(
|
||||
this.configService.get('WAHA_SESSION_CONFIG_IGNORE_GROUPS', 'false'),
|
||||
);
|
||||
const channels = parseBool(
|
||||
this.configService.get('WAHA_SESSION_CONFIG_IGNORE_CHANNELS', 'false'),
|
||||
);
|
||||
const broadcast = parseBool(
|
||||
this.configService.get('WAHA_SESSION_CONFIG_IGNORE_BROADCAST', 'false'),
|
||||
);
|
||||
return { status, groups, channels, broadcast };
|
||||
}
|
||||
|
||||
onApplicationBootstrap() {
|
||||
const error = this.webhookConfig.validateConfig();
|
||||
if (error) {
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import { WAHAEngine } from '@waha/structures/enums.dto';
|
||||
|
||||
export function getEngineName(): string {
|
||||
// Load engine name from WHATSAPP_DEFAULT_ENGINE environment variable
|
||||
// If not set - use WEBJS
|
||||
return process.env.WHATSAPP_DEFAULT_ENGINE || WAHAEngine.WEBJS;
|
||||
}
|
||||
@@ -14,9 +14,11 @@ import { GowsEngineConfigService } from '@waha/core/config/GowsEngineConfigServi
|
||||
import { GowsBootstrap } from '@waha/core/engines/gows/GowsBootstrap';
|
||||
import { ISessionMeRepository } from '@waha/core/storage/ISessionMeRepository';
|
||||
import { ISessionWorkerRepository } from '@waha/core/storage/ISessionWorkerRepository';
|
||||
import { IgnoreJidConfig } from '@waha/core/utils/jids';
|
||||
import { WAHAWebhook } from '@waha/structures/webhooks.dto';
|
||||
import { waitUntil } from '@waha/utils/promiseTimeout';
|
||||
import { VERSION } from '@waha/version';
|
||||
import * as lodash from 'lodash';
|
||||
import { PinoLogger } from 'nestjs-pino';
|
||||
import { merge, Observable, of } from 'rxjs';
|
||||
|
||||
@@ -235,6 +237,12 @@ export abstract class SessionManager
|
||||
}
|
||||
return new NoopEngineBootstrap();
|
||||
}
|
||||
|
||||
protected ignoreChatsConfig(config: SessionConfig) {
|
||||
const ignore: IgnoreJidConfig = this.config.getIgnoreChatsConfig();
|
||||
// Given the default, overwrite from the config if any
|
||||
return lodash.defaults({}, config?.ignore, ignore);
|
||||
}
|
||||
}
|
||||
|
||||
export function populateSessionInfo(
|
||||
|
||||
Loaded 100 of 165 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user