Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
733 lines
101 KiB
TypeScript
733 lines
101 KiB
TypeScript
import { useLang, type Lang } from '../i18n.tsx';
|
||
|
||
const ru = {
|
||
tabs: { pool: 'Пул', mine: 'Мои', all: 'Все' },
|
||
view: { table: 'Таблица', kanban: 'Канбан' },
|
||
search: 'Телефон, адрес, ID объявления',
|
||
add: 'Добавить объект',
|
||
take: 'Беру',
|
||
bumped: 'Поднято на List.am',
|
||
taken: 'Взят',
|
||
empty: { pool: 'В пуле пусто. Новые объекты появятся здесь, как только сработает фильтр.', mine: 'У вас пока нет объектов в работе.', all: 'Объектов пока нет.' },
|
||
noFilters: 'Чтобы объекты начали приходить, создайте первый фильтр.',
|
||
toFilters: 'Создать фильтр',
|
||
col: { object: 'Объект', price: 'Цена', place: 'Район', status: 'Статус', agent: 'Ответственный', created: 'Создан' },
|
||
f: { status: 'Статус', agent: 'Агент', district: 'Район', priceFrom: 'Цена от', priceTo: 'до', from: 'Создан с', to: 'по', any: 'Любой', reset: 'Сбросить', more: 'Фильтры' },
|
||
pool: 'в пуле',
|
||
card: {
|
||
onListAm: 'Открыть на List.am', contact: 'Контакт', call: 'Позвонить', phoneHidden: 'Телефон откроется после «Беру»',
|
||
noPhone: 'Телефон — в объявлении на List.am', assignee: 'Ответственный', status: 'Статус', nextAction: 'Следующее действие',
|
||
nextNote: 'Что сделать', remind: 'Напомнить в боте', clear: 'Убрать', comment: 'Комментарий', addComment: 'Добавить',
|
||
history: 'История', isAgent: 'Это агент', toPool: 'Вернуть в пул', manual: 'Вручную', agency: 'Агентство',
|
||
clients: 'Клиенты, которым предложен объект', attach: 'Прикрепить к клиенту…',
|
||
previous: 'Уже был в работе', confirmAgent: 'Отметить автора как агента? Объект уйдёт в «Отказ».',
|
||
confirmPool: 'Вернуть объект в пул? Его сможет взять любой агент.',
|
||
gone: 'Объявления больше нет', confirmGone: 'Отметить, что объявление снято с List.am? Отметка появится у всех, кто ведёт этот объект.',
|
||
editTitle: 'Данные объекта',
|
||
},
|
||
ev: {
|
||
created: 'Объект создан', createdListam: 'Пришёл с List.am', createdManual: 'Создан вручную', taken: 'Взял в работу',
|
||
assigned: (a: string | null, b: string | null) => (a ? `Переназначен: ${a} → ${b}` : `Назначен: ${b}`),
|
||
status: (a: string | null, b: string | null) => `Статус: ${a ?? '—'} → ${b}`,
|
||
deal: (text: string | null) => `Сделка${text ? `, комиссия ${text}` : ''}`,
|
||
poolReturn: (who: string | null) => (who ? `Возврат в пул (был у: ${who})` : 'Возврат в пул'),
|
||
clientCreated: 'Клиент создан', edited: 'Данные изменены', dealEdited: (text: string | null) => `Сделка исправлена${text ? `: комиссия ${text}` : ''}`,
|
||
offered: (v: string | null) => `Предложен объект: ${v ?? '—'}`, shown: (v: string | null) => `Показан объект: ${v ?? '—'}`,
|
||
unlinked: (v: string | null) => `Объект откреплён${v ? `: ${v}` : ''}`,
|
||
clientOffered: (v: string | null) => `Предложен клиенту: ${v ?? '—'}`, clientShown: (v: string | null) => `Показан клиенту: ${v ?? '—'}`,
|
||
blacklisted: 'Отмечен как агент', system: 'Система', listingRemoved: 'Отмечено: объявления больше нет',
|
||
},
|
||
dlg: {
|
||
reject: 'Причина отказа', deal: 'Закрытие сделки', commission: 'Комиссия агентства', currency: 'Валюта', date: 'Дата сделки',
|
||
ownerPart: 'С собственника', clientPart: 'С клиента', splitHint: 'Часть с собственника получает агент объекта, часть с клиента — агент клиента. Если стороны нет — поставьте 0.',
|
||
edit: 'Изменить', dealEdit: 'Правка сделки', pairClient: 'Сделка с клиентом из CRM', pairLead: 'Сделка с объектом из CRM',
|
||
noPair: 'Без пары — вторая сторона вне CRM', pairHint: 'Сделка закроется один раз: оба перейдут в «Сделка», комиссия не задвоится.',
|
||
pairEmptyClient: 'Чтобы закрыть сделку вместе с клиентом, сначала прикрепите объект к клиенту.',
|
||
pairEmptyLead: 'Чтобы закрыть сделку вместе с объектом, сначала прикрепите к клиенту объект, взятый в работу.',
|
||
title: 'Название', description: 'Описание', address: 'Адрес', price: 'Цена', rooms: 'Комнат', area: 'Площадь, м²',
|
||
floor: 'Этаж', floors: 'Этажей', author: 'Имя собственника', phone: 'Телефон', link: 'Ссылка на объявление',
|
||
},
|
||
deal: { sale: 'Продажа', rent: 'Аренда' },
|
||
ptype: { apartment: 'Квартира', house: 'Дом', commercial: 'Коммерческая', land: 'Участок', garage: 'Гараж' },
|
||
unit: { rooms: 'комн.', floor: 'этаж', perMonth: '/мес' },
|
||
filters: {
|
||
title: 'Фильтры', sub: 'Объявление становится лидом, если подошло под общий фильтр компании или под личный фильтр агента.',
|
||
company: 'Общие фильтры компании', personal: 'Мои личные фильтры', others: 'Личные фильтры агентов', add: 'Новый фильтр',
|
||
none: 'Фильтров нет.', name: 'Название', scope: 'Для кого', scopeCompany: 'Вся компания', scopePersonal: 'Только я',
|
||
dealType: 'Тип сделки', types: 'Тип объекта', region: 'Регион', allArmenia: 'Вся Армения', districts: 'Районы',
|
||
localities: 'Населённые пункты, через запятую', price: 'Цена', area: 'Площадь, м²', rooms: 'Комнат',
|
||
author: 'Автор объявления', ownersOnly: 'Только собственники', everyone: 'Все объявления', enabled: 'Включён',
|
||
any: 'любой', anyType: 'любой тип', from: 'от', to: 'до', confirmDelete: 'Удалить фильтр?', fromBase: (n: number) => `Из базы за последние 3 дня в пул добавлено объектов: ${n}`,
|
||
},
|
||
cl: {
|
||
sub: 'Покупатели и арендаторы. Клиент закреплён за агентом; переназначает руководитель.',
|
||
add: 'Добавить клиента', one: 'Клиент', name: 'Имя', kindLabel: 'Тип клиента', kind: { buyer: 'Покупатель', tenant: 'Арендатор' },
|
||
anyKind: 'Все типы', source: 'Источник', sourceHint: 'Instagram, рекомендация…', me: 'Я', request: 'Запрос', budget: 'Бюджет',
|
||
noRequest: 'Запрос не заполнен. Заполните его — и здесь появятся подходящие объекты.', search: 'Имя или телефон',
|
||
empty: 'Клиентов пока нет. Добавьте первого покупателя или арендатора.', notFound: 'Ничего не найдено.',
|
||
objectsCol: 'Объекты', objects: (n: number) => `объектов: ${n}`, noObjects: 'Объекты пока не прикреплены.',
|
||
suggested: 'Подходят под запрос', attach: 'Прикрепить', detach: 'Открепить', state: { offered: 'Предложен', shown: 'Показан' },
|
||
phoneHidden: 'Телефон видит ответственный агент', noPhone: 'Телефон не указан', dealLead: 'Объект',
|
||
},
|
||
ar: {
|
||
sub: 'Объекты и клиенты, закрытые сделкой или отказом, и объекты, снятые с List.am. Попадают сюда автоматически.',
|
||
tabs: { leads: 'Объекты', contacts: 'Клиенты' }, resultLabel: 'Итог', anyResult: 'Любой итог', result: { deal: 'Сделка', rejected: 'Отказ' },
|
||
closed: 'Закрыт', contact: 'Клиент', objects: 'Объекты', empty: 'В базе пока пусто: сюда попадут объекты и клиенты после сделки или отказа.',
|
||
removed: (d: string) => `Снято с List.am ${d}`,
|
||
},
|
||
an: {
|
||
pipeline: { object: 'Объекты', client: 'Клиенты' }, period: { today: 'Сегодня', week: 'Неделя', month: 'Месяц', custom: 'Период' },
|
||
came: 'Пришло лидов', takenTotal: 'Взято в работу', inPool: 'Сейчас в пуле', inWork: 'Сейчас в работе', deals: 'Сделки',
|
||
funnel: 'Воронка целиком', funnelHintObject: 'Лиды, пришедшие за период: сколько из них дошли до каждого этапа.',
|
||
funnelHintClient: 'Клиенты, созданные за период: сколько из них дошли до каждого этапа.', noData: 'За этот период данных нет.',
|
||
byAgent: 'По сотрудникам', tableHintObject: 'Проценты — доля лидов, взятых агентом за период, которые дошли до этапа при нём.',
|
||
tableHintClient: 'Проценты — доля клиентов агента, созданных за период, которые дошли до этапа.',
|
||
agent: 'Агент', taken: 'Взято лидов', newRequests: 'Новые запросы', reaction: 'Скорость реакции', poolReturns: 'Возвраты в пул', showings: 'Показы',
|
||
commission: 'Сумма комиссий', total: 'Итого', reasons: 'Причины отказа', reason: 'Причина', noRejects: 'За период отказов нет.',
|
||
sec: 'с', min: 'мин', hour: 'ч',
|
||
},
|
||
ls: {
|
||
sub: 'Общая база сервиса: всё, что парсер собрал с List.am. Отсюда объявления расходятся клиентам по фильтрам.',
|
||
search: 'Номер объявления, название, адрес, телефон', total: (n: number) => `Найдено: ${n}`, anyDeal: 'Любая сделка', anyRegion: 'Все регионы',
|
||
state: { any: 'На сайте и снятые', active: 'На сайте', removed: 'Сняты' }, leads: { any: 'С лидами и без', yes: 'Есть лиды', no: 'Без лидов' },
|
||
author: { any: 'Любой автор', owner: 'Собственник', agency: 'Агентство' },
|
||
col: { listing: 'Объявление', price: 'Цена', place: 'Район', published: 'Размещено', found: 'Найдено', leads: 'Лиды' },
|
||
empty: 'Объявлений нет.', prev: 'Назад', next: 'Дальше', page: (a: number, b: number) => `Страница ${a} из ${b}`,
|
||
number: 'Номер', sentTo: 'Кому ушло лидом', noLeads: 'Ни под один фильтр не подошло.', pool: 'в пуле',
|
||
},
|
||
ps: {
|
||
title: 'Настройки парсера', hint: 'Применяются со следующего прохода, перезапуск не нужен.',
|
||
enabled: 'Парсер включён: сам обходит List.am по кругу', freshDays: 'Свежесть, дней', freshHint: 'Для блока «Топ» и первого прохода: объявления, размещённые не раньше. Поднятые в обычном списке идут в базу всегда',
|
||
pauseSec: 'Пауза между проходами, секунд', maxPages: 'Страниц категории за проход', pagesHint: 'Читаются, пока на них есть незнакомые объявления',
|
||
categories: 'Категории List.am', keyTitle: 'Ключ ридера Jina',
|
||
keyHint: 'С ключом проход быстрее и известно точное время размещения, но ключ платный. Без ключа парсер работает медленнее. Если баланс ключа кончился, парсер сам переходит на работу без ключа.',
|
||
useKey: 'Использовать ключ', key: 'Текущий ключ', keyNone: 'не задан', keyEnv: 'из настроек сервера', keySet: 'задан здесь',
|
||
keyNew: 'Вставьте новый ключ, чтобы заменить', keyClear: 'Убрать ключ', keyConfirm: 'Убрать ключ, заданный в админке?',
|
||
quietTitle: 'Ночная пауза', quietHint: 'В эти часы по Еревану парсер и проверка снятых объявлений не работают — так не тратятся токены ридера. Сторож парсера в паузу не тревожит.',
|
||
quietOn: 'Останавливать парсер на ночь', quietFrom: 'С (Ереван)', quietTo: 'До (Ереван)', quietSame: 'Начало и конец совпадают — паузы не будет',
|
||
removalTitle: 'Отметка «Снято с List.am»', removalCheck: 'Проверять, не сняты ли объявления, по которым есть лиды',
|
||
recheckHours: 'Перепроверять объявление раз в, часов', removalBatch: 'Объявлений за заход (раз в 10 минут)', batchHint: (n: number) => `До ${n} проверок в сутки`,
|
||
},
|
||
pl: {
|
||
title: { object: 'Воронка объекта', client: 'Воронка клиента' },
|
||
hint: 'Названия сохраняются сразу. Статусы с замком системные: их можно переименовать, но нельзя удалить или передвинуть.',
|
||
statuses: 'Статусы', reasons: 'Причины отказа', statusName: 'Название статуса', reasonName: 'Причина отказа',
|
||
newStatus: 'Новый статус', newReason: 'Новая причина', add: 'Добавить', up: 'Выше', down: 'Ниже',
|
||
pool: 'возврат в пул', poolHint: 'Взятый объект в этом статусе вернётся в пул, если статус долго не меняется',
|
||
system: 'Системный статус', systemReason: 'Системная причина: её ставит кнопка «Это агент»',
|
||
confirmStatus: (n: string) => `Удалить статус «${n}»?`, confirmReason: (n: string) => `Удалить причину «${n}»?`,
|
||
removeTitle: (n: string) => `Удалить статус «${n}»`, removeHint: (n: number) => `В этом статусе карточек: ${n}. Выберите, куда их перевести.`,
|
||
moveTo: 'Перевести в статус…',
|
||
},
|
||
pay: {
|
||
title: 'Условия оплаты', notSet: 'Не заданы', modes: { fixed: 'Оклад', percent: 'Процент с его сделок', mixed: 'Оклад + процент с его сделок' },
|
||
salary: (v: string) => `оклад ${v}`, share: (v: number) => `${v}% со сделок`, shareSplit: (sale: number, rent: number) => `${sale}% с продажи, ${rent}% с аренды`,
|
||
fixedLabel: 'Оклад в месяц', percentLabel: 'Процент с продажи', percentRentLabel: 'Процент с аренды', payoutCurrency: 'Валюта выплаты',
|
||
hint: 'Процент считается от части комиссии, которая приходится на агента: с собственника — агенту объекта, с клиента — агенту клиента.', edit: 'Условия оплаты',
|
||
payroll: 'Кому сколько платить', payrollHint: 'Оклад за месяц и процент от части комиссии агента по сделкам этого месяца. Нажмите на сотрудника, чтобы увидеть его сделки.', month: 'Месяц',
|
||
col: { agent: 'Сотрудник', terms: 'Условия', deals: 'Сделок', commission: 'Его часть комиссии', share: 'Процент', fixed: 'Оклад', total: 'К выплате', sum: 'Всего к выплате' },
|
||
mine: 'Моя оплата', thisMonth: 'Начислено за месяц',
|
||
dealsOf: (name: string) => `Сделки: ${name}`, myDeals: 'Мои сделки за месяц', noDeals: 'Сделок за этот месяц нет.',
|
||
dcol: { date: 'Дата', deal: 'Объект и клиент', kind: 'Вид', side: 'Сторона', part: 'Часть комиссии', percent: 'Процент', accrued: 'Начислено' },
|
||
side: { owner: 'объект', client: 'клиент', both: 'объект и клиент' }, withPartner: (name: string) => `вторая сторона: ${name}`, ofDeal: (v: string) => `из ${v}`,
|
||
planTitle: 'План на месяц', planDeals: 'Сделок', planCommission: 'Комиссия агента', planHint: 'Пустое поле — показатель не задан. План выполнен, когда достигнуты все заданные показатели.',
|
||
bonusTitle: 'Бонус за выполненный план', bonusModes: { none: 'Нет', fixed: 'Сумма', percent: 'Надбавка к проценту' }, bonusValue: 'Размер', bonusHint: 'Надбавка считается от всей комиссии агента за месяц.',
|
||
planOf: (done: string, plan: string) => `${done} из ${plan}`, planDone: 'План выполнен', planNot: 'План не выполнен',
|
||
other: 'Бонус и прочее', status: 'Выплата', paid: (d: string) => `Выплачено ${d}`, notPaid: 'Не выплачено',
|
||
lines: 'Начисления', lineFixed: 'Оклад', lineShare: 'Процент со сделок', lineBonus: 'Бонус за план', lineRecalc: (m: string) => `Перерасчёт за ${m}`, lineTotal: 'Итого к выплате',
|
||
addLine: 'Добавить запись', lineAmount: 'Сумма (с минусом — удержание)', lineNote: 'За что', lineNotePh: 'Премия, штраф, аванс…', add: 'Добавить', remove: 'Удалить запись',
|
||
payTitle: 'Отметить выплату', payAmount: 'Выплачено', payDate: 'Дата выплаты', payNote: 'Комментарий', markPaid: 'Выплачено', cancelPaid: 'Отменить отметку',
|
||
paidInfo: (v: string, d: string) => `Выплачено ${v} · ${d}`, debt: (v: string) => `Остаток ${v} перейдёт в следующий месяц без выплаты.`, overpaid: (v: string) => `Переплата ${v} будет удержана в следующем месяце без выплаты.`,
|
||
closedHint: 'Месяц закрыт: считается по условиям и курсам на день выплаты. Изменения его сделок уходят перерасчётом в следующий месяц.',
|
||
history: 'История выплат', accruedOf: (v: string) => `начислено ${v}`,
|
||
trend: 'Динамика по месяцам', trendHint: 'Сделки и часть комиссии каждого сотрудника. Комиссия — в долларах по текущему курсу.', trendMine: 'Моя динамика',
|
||
metricDeals: 'Сделки', metricCommission: 'Комиссия', company: 'Вся компания', vsPrev: (d: string) => `${d} к прошлому месяцу`, same: 'как в прошлом месяце',
|
||
asTable: 'Таблицей', asChart: 'Графиком', metric: 'Показатель',
|
||
rating: 'Рейтинг месяца', ratingHint: 'Место — по числу сделок; при равенстве выше тот, у кого комиссия больше. Суммы в рейтинге не показываются.',
|
||
place: 'Место', plan: 'План', noPlan: 'нет плана', you: 'вы',
|
||
export: 'Скачать для Excel', paidCol: 'Выплачено', currency: 'Валюта', client: 'Клиент', object: 'Объект',
|
||
reportsTitle: 'Отчёты в Telegram', reportsHint: 'Приходят руководителю в бот Lead Radar в 9 утра по Еревану.', reportWeekly: 'Итоги недели — по понедельникам', reportMonthly: 'Итоги месяца с ведомостью — первого числа',
|
||
},
|
||
cm: {
|
||
title: 'Комиссия агентства', mode: 'условие', none: 'Не задано', percent: 'Процент', fixed: 'Фикс', mixed: 'Фикс + процент', amount: 'сумма', notSet: 'Не задана',
|
||
ofPrice: (v: number) => `${v}% от цены`, ofRent: (v: number) => `${v}% от месячной платы`,
|
||
fromSettings: 'как в настройках компании', custom: 'изменено в этой карточке', reset: 'Как в настройках', forThis: 'Условие для этой карточки',
|
||
hintLead: 'Условие не задано в настройках — укажите своё.', hintClient: 'Условие не задано в настройках — укажите своё. Процент считается от бюджета клиента.',
|
||
settings: 'Комиссия агентства', settingsHint: 'Условия по умолчанию. Процент считается от цены объекта, при аренде — от месячной платы; у клиента — от его бюджета. Агент может поменять условие в карточке.',
|
||
objectSale: 'Объекты: продажа (с собственника)', objectRent: 'Объекты: аренда (с собственника)', clientBuyer: 'Клиенты: покупатель', clientTenant: 'Клиенты: арендатор',
|
||
prefill: 'Сумма подставлена по условию комиссии — поправьте, если договорились иначе.',
|
||
evChanged: (from: string, to: string) => `Комиссия: ${from} → ${to}`, asSettings: 'как в настройках', points: (v: string) => `${v} п.п.`, sumDelta: (v: string) => `сумма ${v}%`,
|
||
},
|
||
sh: {
|
||
page: 'Страница для клиента', pageHint: 'Клиент открывает её без входа: видит прикреплённые объекты и записывается на показ. Адрес и ссылку на List.am страница не показывает.',
|
||
create: 'Создать страницу', createMatch: 'Подобрать объекты и создать', added: (n: number) => (n ? `Прикреплено подходящих объектов: ${n}.` : 'Подходящих объектов сейчас нет — страница создана с уже прикреплёнными.'),
|
||
close: 'Закрыть страницу', confirmClose: 'Закрыть страницу? Ссылка у клиента перестанет открываться.', open: 'Открыть',
|
||
viewings: 'Записи на показ', viewingLine: (day: string, title: string) => `${day} — ${title}`,
|
||
intake: 'Ссылка на анкету', intakeTitle: 'Анкета для клиента',
|
||
intakeText: 'Отправьте ссылку клиенту или разместите в объявлении. Он ответит на вопросы в Telegram — и появится здесь как ваш клиент. Вам в бот придёт анкета с вопросом, показать ли ему подходящие объекты.',
|
||
intakeOff: 'Анкета пока не подключена: клиентский бот не настроен.',
|
||
evViewing: (title: string | null, day: string | null) => `Клиент записался на показ ${day ?? ''}: ${title ?? '—'}`,
|
||
evClientViewing: (name: string | null, day: string | null) => `Запись на показ ${day ?? ''}: ${name ?? '—'}`,
|
||
ownerPhone: 'Телефон собственника', ownerPhoneHint: 'Вставьте номер из объявления на List.am — он сохранится в карточке.', savePhone: 'Сохранить номер', changePhone: 'Изменить номер',
|
||
clientText: 'Описание для клиента', copyText: 'Копировать текст', original: 'Объявление на List.am: исходный текст и характеристики', photosLoading: 'Догружаем остальные фото…',
|
||
evPhone: (v: string | null) => (v ? `Внесён телефон собственника: ${v}` : 'Телефон собственника убран'),
|
||
variants: 'Номера из общей базы', variantsHint: 'Их внесли агенты, работавшие с этим объявлением.', useVariant: 'Взять этот номер',
|
||
confidence: (pct: number, votes: number) => `точность ${pct}% · совпал у ${votes}`, unconfirmed: 'не подтверждён: указал один агент',
|
||
slug: 'Адрес страниц для клиентов', slugHint: 'Латинские буквы, цифры и дефис. Если поменять, старые ссылки клиентов перестанут открываться.',
|
||
},
|
||
hh: {
|
||
title: 'Кто будет жить', who: { alone: 'Один', friend: 'С другом', couple: 'С партнёром (пара)' }, notSet: 'Не указано',
|
||
children: 'Дети', pets: 'Животные', count: 'Сколько', age: 'Возраст', ageHintChildren: '3 и 7 лет', ageHintPets: 'кот, 2 года',
|
||
childrenLine: (n: number, age: string) => `детей: ${n}${age ? ` (${age})` : ''}`, petsLine: (n: number, age: string) => `животных: ${n}${age ? ` (${age})` : ''}`,
|
||
photos: 'Фото', addPhoto: 'Добавить фото', removePhoto: 'Удалить фото', photosHint: 'Жильцы, животные, документы. До 10 фото, каждое до 5 МБ.',
|
||
confirmRemove: 'Удалить фото?', empty: 'Не заполнено.',
|
||
about: 'Об объекте', amenities: 'Удобства', rules: { children: 'С детьми', pets: 'С животными' },
|
||
allow: { yes: 'можно', no: 'нельзя', negotiable: 'по договорённости' },
|
||
},
|
||
x: {
|
||
byUrl: 'По ссылке', byUrlTitle: 'Объект по ссылке на List.am', byUrlLabel: 'Ссылка на объявление',
|
||
byUrlHint: 'Если объект уже есть в CRM и свободен, он закрепится за вами. Если его нет, скачаем с List.am и заведём на вас.',
|
||
byUrlGo: 'Проверить и закрепить', byUrlLoading: 'Ищем объект, при необходимости скачиваем с List.am — это может занять до минуты…',
|
||
taken: 'Объект был свободен — теперь он закреплён за вами.', created: 'Объекта не было в CRM — скачали с List.am и закрепили за вами.',
|
||
mine: 'Этот объект уже закреплён за вами.', busy: (name: string | null) => (name ? `Объект уже закреплён за агентом ${name}.` : 'Объект уже в работе у другого агента.'),
|
||
open: 'Открыть карточку', districts: 'Районы',
|
||
sendTg: 'Отправить в Telegram', sendingTg: 'Отправляем…', sentTg: 'Отправлено в группу', botNotSet: 'Бот не настроен',
|
||
del: 'Удалить карточку', delConfirm: 'Удалить карточку вместе с историей? Отменить это нельзя.', delDeal: 'У карточки есть сделка: удалить её может только суперадмин — сделка пропадёт из аналитики и ведомости.',
|
||
phrase: { broker: 'В объявлении похоже на посредника', noAgents: 'Собственник пишет, что не работает с агентами' },
|
||
telegram: 'Telegram', telegramPh: '@ник или ссылка t.me', rentTerm: 'Срок аренды', term: { short: 'До 6 месяцев', mid: '6–12 месяцев', long: 'От года' },
|
||
},
|
||
tg: { link: 'Привязать Telegram', open: 'Откройте бота и нажмите «Start»:', hint: 'После привязки сюда начнут приходить новые объекты.' },
|
||
parser: {
|
||
title: 'Парсер', off: 'Источник объявлений не настроен.', lastOk: 'Последний успешный проход', day: 'Добавлено в базу за сутки',
|
||
total: 'Всего в базе', cycle: 'Полный круг парсера', delay: 'Задержка «размещено → лид», медиана за сутки', delayN: (n: number) => `по ${n} лидам`, day3: 'В базе: свежие, не старше 3 дней', run: 'Запустить сейчас', runs: 'Последние запуски', started: 'Начало', took: 'Длительность',
|
||
found: 'Новых', status: 'Статус', errors: 'Ошибки', ok: 'успешно', failed: 'сбой', running: 'идёт', sec: 'с',
|
||
},
|
||
dp: {
|
||
favorite: 'Избранное', unseen: 'Не просмотренные', addFav: 'В избранное', removeFav: 'Убрать из избранного', unseenMark: 'Не просмотрен',
|
||
currency: 'Валюта', cur: { AMD: 'АМД', USD: 'ДОЛ' } as Record<string, string>, priceHint: 'Цены в другой валюте пересчитываются по курсу',
|
||
sendBot: 'Отправить в бот', sendingBot: 'Отправляем…', sentBot: 'Отправлено вам в бот',
|
||
linkTitle: 'Telegram не привязан к боту',
|
||
linkText: 'Объект приходит в бот тому, кто нажал кнопку, — в Telegram, привязанный к вашему аккаунту. Нажмите «Привязать Telegram», откройте бота, нажмите «Start» и отправьте объект ещё раз. Привязка есть и в «Настройках».',
|
||
blockedText: 'Бот не может вам написать: откройте бота в Telegram, нажмите «Start» (или разблокируйте его) и попробуйте ещё раз.',
|
||
linkBtn: 'Привязать Telegram', openBot: 'Открыть бота',
|
||
departments: 'Отделы', department: 'Отдел', noDepartment: 'Без отдела', allDepartments: 'Все отделы', add: 'Новый отдел', namePh: 'Название отдела',
|
||
rename: 'Переименовать', del: 'Удалить отдел', delConfirm: 'Удалить отдел? Его фильтры и объекты из пула, которые никто не брал, удалятся.',
|
||
hint: 'У каждого отдела свои фильтры, объекты и клиенты. Сотрудник видит только данные своего отдела, руководитель — все отделы. При смене отдела объекты и клиенты, которые ведёт сотрудник, переходят вместе с ним.',
|
||
stats: (m: number, f: number, l: number, c: number) => `сотрудников: ${m} · фильтров: ${f} · объектов: ${l} · клиентов: ${c}`,
|
||
kept: (n: number) => `Объектов осталось в прежнем отделе: ${n} — в новом уже есть карточки тех же объявлений.`,
|
||
none: 'Отделов пока нет — вся компания работает с общими объектами и клиентами.',
|
||
scope: 'Отдел', filtersOf: (name: string) => `Фильтры отдела «${name}»`, mine: (name: string) => `Ваш отдел: ${name}`,
|
||
removed: 'Сняты с List.am',
|
||
},
|
||
errors: {
|
||
ALREADY_TAKEN: 'Этот объект уже взял другой агент', LEAD_NOT_FOUND: 'Объект не найден', NOT_YOUR_LEAD: 'Объект ведёт другой агент',
|
||
TAKE_FIRST: 'Сначала возьмите объект в работу', REJECT_REASON_REQUIRED: 'Укажите причину отказа',
|
||
COMMISSION_REQUIRED: 'Укажите сумму комиссии', USE_RETURN_TO_POOL: 'Чтобы вернуть объект в пул, используйте кнопку «Вернуть в пул»',
|
||
MODULE_NOT_AVAILABLE: 'Раздел доступен в тарифах Team и Agency',
|
||
CLIENT_NOT_FOUND: 'Клиент не найден', NOT_YOUR_CLIENT: 'Клиента ведёт другой агент', BAD_ASSIGNEE: 'Такого участника нет в компании',
|
||
PAIR_NOT_LINKED: 'Сначала прикрепите объект к клиенту', DEAL_HAS_PAIR: 'По этой сделке уже указана другая пара. Сначала отмените ту сделку',
|
||
BAD_STATUS: 'Такого статуса нет в воронке', SYSTEM_STATUS: 'Системный статус удалить нельзя', STATUS_IN_USE: 'В статусе есть карточки: выберите, куда их перевести',
|
||
SYSTEM_REASON: 'Системную причину удалить нельзя', LAST_REASON: 'Нужна хотя бы одна причина отказа',
|
||
DEAL_CLOSED: 'Сделка закрыта: статус меняет руководитель', TELEGRAM_DISABLED: 'Бот не настроен', PARSER_DISABLED: 'Парсер не настроен', BAD_LISTAM_URL: 'Это не ссылка на объявление List.am', LISTAM_NOT_FOUND: 'Такого объявления на List.am нет — возможно, его сняли', LISTAM_UNAVAILABLE: 'Не удалось прочитать объявление с List.am, попробуйте ещё раз', HAS_DEAL: 'У карточки есть сделка: удалить её может только суперадмин', GROUP_BOT_NOT_SET: 'Бот не настроен', GROUP_SEND_FAILED: 'Не удалось отправить в Telegram, попробуйте ещё раз', TELEGRAM_NOT_LINKED: 'Telegram не привязан к боту', BOT_CHAT_UNAVAILABLE: 'Бот не может вам написать: откройте бота и нажмите «Start»', BOT_SEND_FAILED: 'Не удалось отправить в бот, попробуйте ещё раз', DEPARTMENT_NOT_EMPTY: 'В отделе есть сотрудники, клиенты или объекты в работе — сначала переведите их', BAD_DEPARTMENT: 'Такого отдела нет', DEPARTMENT_HAS_LEAD: 'В отделе этого сотрудника уже есть карточка по этому объявлению',
|
||
MONTH_PAID: 'Месяц уже закрыт выплатой. Чтобы изменить его, отмените отметку', PAYOUT_NOT_LAST: 'Отменить можно только последнюю выплату сотрудника',
|
||
} as Record<string, string>,
|
||
};
|
||
|
||
type Dict = typeof ru;
|
||
|
||
const hy: Dict = {
|
||
tabs: { pool: 'Ընդհանուր', mine: 'Իմը', all: 'Բոլորը' },
|
||
view: { table: 'Աղյուսակ', kanban: 'Կանբան' },
|
||
search: 'Հեռախոս, հասցե, հայտարարության ID',
|
||
add: 'Ավելացնել օբյեկտ',
|
||
take: 'Վերցնում եմ',
|
||
bumped: 'Բարձրացվել է List.am-ում',
|
||
taken: 'Վերցված է',
|
||
empty: { pool: 'Ընդհանուր ցուցակը դատարկ է։ Նոր օբյեկտները կհայտնվեն այստեղ, երբ ֆիլտրը աշխատի։', mine: 'Դուք դեռ ընթացիկ օբյեկտներ չունեք։', all: 'Օբյեկտներ դեռ չկան։' },
|
||
noFilters: 'Որպեսզի օբյեկտները սկսեն գալ, ստեղծեք առաջին ֆիլտրը։',
|
||
toFilters: 'Ստեղծել ֆիլտր',
|
||
col: { object: 'Օբյեկտ', price: 'Գին', place: 'Շրջան', status: 'Կարգավիճակ', agent: 'Պատասխանատու', created: 'Ստեղծվել է' },
|
||
f: { status: 'Կարգավիճակ', agent: 'Գործակալ', district: 'Շրջան', priceFrom: 'Գինը՝ սկսած', priceTo: 'մինչև', from: 'Ստեղծվել է՝ սկսած', to: 'մինչև', any: 'Ցանկացած', reset: 'Մաքրել', more: 'Ֆիլտրեր' },
|
||
pool: 'ընդհանուր ցուցակում',
|
||
card: {
|
||
onListAm: 'Բացել List.am-ում', contact: 'Կոնտակտ', call: 'Զանգահարել', phoneHidden: 'Հեռախոսը կբացվի «Վերցնում եմ»-ից հետո',
|
||
noPhone: 'Հեռախոսը՝ List.am-ի հայտարարության մեջ', assignee: 'Պատասխանատու', status: 'Կարգավիճակ', nextAction: 'Հաջորդ քայլը',
|
||
nextNote: 'Ինչ անել', remind: 'Հիշեցնել բոտում', clear: 'Հեռացնել', comment: 'Մեկնաբանություն', addComment: 'Ավելացնել',
|
||
history: 'Պատմություն', isAgent: 'Սա գործակալ է', toPool: 'Վերադարձնել ընդհանուր ցուցակ', manual: 'Ձեռքով', agency: 'Գործակալություն',
|
||
clients: 'Հաճախորդներ, որոնց առաջարկվել է օբյեկտը', attach: 'Կցել հաճախորդին…',
|
||
previous: 'Արդեն եղել է աշխատանքում', confirmAgent: 'Նշե՞լ հեղինակին որպես գործակալ։ Օբյեկտը կտեղափոխվի «Մերժում»։',
|
||
confirmPool: 'Վերադարձնե՞լ օբյեկտը ընդհանուր ցուցակ։ Այն կկարողանա վերցնել ցանկացած գործակալ։',
|
||
gone: 'Հայտարարությունն այլևս չկա', confirmGone: 'Նշե՞լ, որ հայտարարությունը հանվել է List.am-ից։ Նշումը կերևա բոլորին, ովքեր վարում են այս օբյեկտը։',
|
||
editTitle: 'Օբյեկտի տվյալներ',
|
||
},
|
||
ev: {
|
||
created: 'Օբյեկտը ստեղծվել է', createdListam: 'Եկել է List.am-ից', createdManual: 'Ստեղծվել է ձեռքով', taken: 'Վերցրել է աշխատանքի',
|
||
assigned: (a, b) => (a ? `Վերանշանակվել է՝ ${a} → ${b}` : `Նշանակվել է՝ ${b}`),
|
||
status: (a, b) => `Կարգավիճակ՝ ${a ?? '—'} → ${b}`,
|
||
deal: (text) => `Գործարք${text ? `, միջնորդավճար՝ ${text}` : ''}`,
|
||
poolReturn: (who) => (who ? `Վերադարձ ընդհանուր ցուցակ (եղել է՝ ${who})` : 'Վերադարձ ընդհանուր ցուցակ'),
|
||
clientCreated: 'Հաճախորդը ստեղծվել է', edited: 'Տվյալները փոխվել են', dealEdited: (text) => `Գործարքը ուղղվել է${text ? `. միջնորդավճար՝ ${text}` : ''}`,
|
||
offered: (v) => `Առաջարկվել է օբյեկտ՝ ${v ?? '—'}`, shown: (v) => `Ցուցադրվել է օբյեկտ՝ ${v ?? '—'}`,
|
||
unlinked: (v) => `Օբյեկտը անջատվել է${v ? `՝ ${v}` : ''}`,
|
||
clientOffered: (v) => `Առաջարկվել է հաճախորդին՝ ${v ?? '—'}`, clientShown: (v) => `Ցուցադրվել է հաճախորդին՝ ${v ?? '—'}`,
|
||
blacklisted: 'Նշվել է որպես գործակալ', system: 'Համակարգ', listingRemoved: 'Նշվել է. հայտարարությունն այլևս չկա',
|
||
},
|
||
dlg: {
|
||
reject: 'Մերժման պատճառ', deal: 'Գործարքի փակում', commission: 'Գործակալության միջնորդավճար', currency: 'Արժույթ', date: 'Գործարքի ամսաթիվ',
|
||
ownerPart: 'Սեփականատիրոջից', clientPart: 'Հաճախորդից', splitHint: 'Սեփականատիրոջից ստացված մասը ստանում է օբյեկտի գործակալը, հաճախորդից ստացվածը՝ հաճախորդի գործակալը։ Եթե կողմ չկա՝ նշեք 0։',
|
||
edit: 'Փոխել', dealEdit: 'Գործարքի ուղղում', pairClient: 'Գործարք CRM-ի հաճախորդի հետ', pairLead: 'Գործարք CRM-ի օբյեկտի հետ',
|
||
noPair: 'Առանց զույգի. երկրորդ կողմը CRM-ից դուրս է', pairHint: 'Գործարքը կփակվի մեկ անգամ. երկուսն էլ կանցնեն «Գործարք», միջնորդավճարը չի կրկնապատկվի։',
|
||
pairEmptyClient: 'Հաճախորդի հետ միասին փակելու համար նախ կցեք օբյեկտը հաճախորդին։',
|
||
pairEmptyLead: 'Օբյեկտի հետ միասին փակելու համար նախ հաճախորդին կցեք աշխատանքի վերցված օբյեկտ։',
|
||
title: 'Անվանում', description: 'Նկարագրություն', address: 'Հասցե', price: 'Գին', rooms: 'Սենյակներ', area: 'Մակերես, մ²',
|
||
floor: 'Հարկ', floors: 'Հարկայնություն', author: 'Սեփականատիրոջ անունը', phone: 'Հեռախոս', link: 'Հայտարարության հղում',
|
||
},
|
||
deal: { sale: 'Վաճառք', rent: 'Վարձակալություն' },
|
||
ptype: { apartment: 'Բնակարան', house: 'Տուն', commercial: 'Կոմերցիոն', land: 'Հողամաս', garage: 'Ավտոտնակ' },
|
||
unit: { rooms: 'սեն.', floor: 'հարկ', perMonth: '/ամիս' },
|
||
filters: {
|
||
title: 'Ֆիլտրեր', sub: 'Հայտարարությունը դառնում է լիդ, եթե համապատասխանում է ընկերության ընդհանուր ֆիլտրին կամ գործակալի անձնական ֆիլտրին։',
|
||
company: 'Ընկերության ընդհանուր ֆիլտրեր', personal: 'Իմ անձնական ֆիլտրերը', others: 'Գործակալների անձնական ֆիլտրեր', add: 'Նոր ֆիլտր',
|
||
none: 'Ֆիլտրեր չկան։', name: 'Անվանում', scope: 'Ում համար', scopeCompany: 'Ամբողջ ընկերությունը', scopePersonal: 'Միայն ես',
|
||
dealType: 'Գործարքի տեսակ', types: 'Օբյեկտի տեսակ', region: 'Մարզ', allArmenia: 'Ամբողջ Հայաստանը', districts: 'Շրջաններ',
|
||
localities: 'Բնակավայրեր՝ ստորակետով', price: 'Գին', area: 'Մակերես, մ²', rooms: 'Սենյակներ',
|
||
author: 'Հայտարարության հեղինակ', ownersOnly: 'Միայն սեփականատերեր', everyone: 'Բոլոր հայտարարությունները', enabled: 'Միացված է',
|
||
any: 'ցանկացած', anyType: 'ցանկացած տեսակ', from: 'սկսած', to: 'մինչև', confirmDelete: 'Ջնջե՞լ ֆիլտրը', fromBase: (n) => `Վերջին 3 օրվա բազայից ընդհանուր ցուցակ ավելացված օբյեկտներ՝ ${n}`,
|
||
},
|
||
cl: {
|
||
sub: 'Գնորդներ և վարձակալներ։ Հաճախորդը ամրագրված է գործակալին. վերանշանակում է ղեկավարը։',
|
||
add: 'Ավելացնել հաճախորդ', one: 'Հաճախորդ', name: 'Անուն', kindLabel: 'Հաճախորդի տեսակ', kind: { buyer: 'Գնորդ', tenant: 'Վարձակալ' },
|
||
anyKind: 'Բոլոր տեսակները', source: 'Աղբյուր', sourceHint: 'Instagram, խորհուրդ…', me: 'Ես', request: 'Հարցում', budget: 'Բյուջե',
|
||
noRequest: 'Հարցումը լրացված չէ։ Լրացրեք այն, և այստեղ կհայտնվեն համապատասխան օբյեկտները։', search: 'Անուն կամ հեռախոս',
|
||
empty: 'Հաճախորդներ դեռ չկան։ Ավելացրեք առաջին գնորդին կամ վարձակալին։', notFound: 'Ոչինչ չի գտնվել։',
|
||
objectsCol: 'Օբյեկտներ', objects: (n) => `օբյեկտներ՝ ${n}`, noObjects: 'Օբյեկտներ դեռ կցված չեն։',
|
||
suggested: 'Համապատասխանում են հարցմանը', attach: 'Կցել', detach: 'Անջատել', state: { offered: 'Առաջարկված', shown: 'Ցուցադրված' },
|
||
phoneHidden: 'Հեռախոսը տեսնում է պատասխանատու գործակալը', noPhone: 'Հեռախոսը նշված չէ', dealLead: 'Օբյեկտ',
|
||
},
|
||
ar: {
|
||
sub: 'Գործարքով կամ մերժումով փակված օբյեկտներ և հաճախորդներ, ինչպես նաև List.am-ից հանված օբյեկտներ։ Այստեղ են հայտնվում ինքնաշխատ։',
|
||
tabs: { leads: 'Օբյեկտներ', contacts: 'Հաճախորդներ' }, resultLabel: 'Արդյունք', anyResult: 'Ցանկացած արդյունք', result: { deal: 'Գործարք', rejected: 'Մերժում' },
|
||
closed: 'Փակվել է', contact: 'Հաճախորդ', objects: 'Օբյեկտներ', empty: 'Բազան դեռ դատարկ է. այստեղ կհայտնվեն օբյեկտներն ու հաճախորդները գործարքից կամ մերժումից հետո։',
|
||
removed: (d) => `Հանվել է List.am-ից ${d}`,
|
||
},
|
||
an: {
|
||
pipeline: { object: 'Օբյեկտներ', client: 'Հաճախորդներ' }, period: { today: 'Այսօր', week: 'Շաբաթ', month: 'Ամիս', custom: 'Ժամանակահատված' },
|
||
came: 'Եկած լիդեր', takenTotal: 'Վերցված աշխատանքի', inPool: 'Հիմա ընդհանուր ցուցակում', inWork: 'Հիմա աշխատանքում', deals: 'Գործարքներ',
|
||
funnel: 'Ամբողջ ձագարը', funnelHintObject: 'Ժամանակահատվածում եկած լիդերը. քանիսն են հասել յուրաքանչյուր փուլին։',
|
||
funnelHintClient: 'Ժամանակահատվածում ստեղծված հաճախորդները. քանիսն են հասել յուրաքանչյուր փուլին։', noData: 'Այս ժամանակահատվածի համար տվյալներ չկան։',
|
||
byAgent: 'Ըստ աշխատակիցների', tableHintObject: 'Տոկոսները՝ գործակալի վերցրած լիդերի մասը, որոնք նրա մոտ հասել են փուլին։',
|
||
tableHintClient: 'Տոկոսները՝ գործակալի՝ ժամանակահատվածում ստեղծված հաճախորդների մասը, որոնք հասել են փուլին։',
|
||
agent: 'Գործակալ', taken: 'Վերցված լիդեր', newRequests: 'Նոր հարցումներ', reaction: 'Արձագանքի արագություն', poolReturns: 'Վերադարձներ ընդհանուր ցուցակ', showings: 'Ցուցադրումներ',
|
||
commission: 'Միջնորդավճարների գումար', total: 'Ընդամենը', reasons: 'Մերժման պատճառներ', reason: 'Պատճառ', noRejects: 'Ժամանակահատվածում մերժումներ չկան։',
|
||
sec: 'վ', min: 'ր', hour: 'ժ',
|
||
},
|
||
ls: {
|
||
sub: 'Ծառայության ընդհանուր բազան՝ այն ամենը, ինչ պարսերը հավաքել է List.am-ից։ Այստեղից հայտարարությունները բաշխվում են հաճախորդներին ըստ ֆիլտրերի։',
|
||
search: 'Հայտարարության համար, անվանում, հասցե, հեռախոս', total: (n) => `Գտնվել է՝ ${n}`, anyDeal: 'Ցանկացած գործարք', anyRegion: 'Բոլոր մարզերը',
|
||
state: { any: 'Կայքում և հանված', active: 'Կայքում', removed: 'Հանված' }, leads: { any: 'Լիդերով և առանց', yes: 'Կան լիդեր', no: 'Առանց լիդերի' },
|
||
author: { any: 'Ցանկացած հեղինակ', owner: 'Սեփականատեր', agency: 'Գործակալություն' },
|
||
col: { listing: 'Հայտարարություն', price: 'Գին', place: 'Շրջան', published: 'Տեղադրվել է', found: 'Գտնվել է', leads: 'Լիդեր' },
|
||
empty: 'Հայտարարություններ չկան։', prev: 'Հետ', next: 'Առաջ', page: (a, b) => `Էջ ${a}՝ ${b}-ից`,
|
||
number: 'Համար', sentTo: 'Ում է գնացել որպես լիդ', noLeads: 'Ոչ մի ֆիլտրի չի համապատասխանել։', pool: 'ընդհանուր ցուցակում',
|
||
},
|
||
ps: {
|
||
title: 'Պարսերի կարգավորումներ', hint: 'Կիրառվում են հաջորդ անցումից, վերագործարկում պետք չէ։',
|
||
enabled: 'Պարսերը միացված է. ինքն է շրջանցում List.am-ը', freshDays: 'Թարմություն, օր', freshHint: '«Թոփ» բլոկի և առաջին անցման համար՝ ոչ ավելի վաղ տեղադրված հայտարարությունները։ Սովորական ցուցակում բարձրացվածները միշտ գնում են բազա',
|
||
pauseSec: 'Դադար անցումների միջև, վայրկյան', maxPages: 'Կատեգորիայի էջեր մեկ անցման համար', pagesHint: 'Կարդացվում են, քանի դեռ կան անծանոթ հայտարարություններ',
|
||
categories: 'List.am-ի կատեգորիաներ', keyTitle: 'Jina ընթերցիչի բանալի',
|
||
keyHint: 'Բանալիով անցումն ավելի արագ է, և հայտնի է տեղադրման ճշգրիտ ժամը, բայց բանալին վճարովի է։ Առանց բանալու պարսերն ավելի դանդաղ է։ Եթե բանալու մնացորդը սպառվի, պարսերն ինքը կանցնի առանց բանալու աշխատանքի։',
|
||
useKey: 'Օգտագործել բանալին', key: 'Ընթացիկ բանալի', keyNone: 'նշված չէ', keyEnv: 'սերվերի կարգավորումներից', keySet: 'նշված է այստեղ',
|
||
keyNew: 'Տեղադրեք նոր բանալի՝ փոխարինելու համար', keyClear: 'Հեռացնել բանալին', keyConfirm: 'Հեռացնե՞լ ադմինկայում նշված բանալին',
|
||
quietTitle: 'Գիշերային դադար', quietHint: 'Այս ժամերին (Երևանի ժամանակով) պարսերը և հանված հայտարարությունների ստուգումը չեն աշխատում՝ ընթերցիչի տոկենները չեն ծախսվում։ Պարսերի պահակը դադարի ժամանակ չի անհանգստացնում։',
|
||
quietOn: 'Գիշերը կանգնեցնել պարսերը', quietFrom: 'Սկսած (Երևան)', quietTo: 'Մինչև (Երևան)', quietSame: 'Սկիզբը և ավարտը համընկնում են՝ դադար չի լինի',
|
||
removalTitle: '«Հանվել է List.am-ից» նշում', removalCheck: 'Ստուգել՝ արդյոք հանված են լիդ ունեցող հայտարարությունները',
|
||
recheckHours: 'Վերստուգել հայտարարությունը, ժամը մեկ', removalBatch: 'Հայտարարություններ մեկ մոտեցմամբ (10 րոպեն մեկ)', batchHint: (n) => `Օրական մինչև ${n} ստուգում`,
|
||
},
|
||
pl: {
|
||
title: { object: 'Օբյեկտի ձագար', client: 'Հաճախորդի ձագար' },
|
||
hint: 'Անվանումները պահպանվում են անմիջապես։ Կողպեքով կարգավիճակները համակարգային են. կարելի է վերանվանել, բայց ոչ ջնջել կամ տեղափոխել։',
|
||
statuses: 'Կարգավիճակներ', reasons: 'Մերժման պատճառներ', statusName: 'Կարգավիճակի անվանում', reasonName: 'Մերժման պատճառ',
|
||
newStatus: 'Նոր կարգավիճակ', newReason: 'Նոր պատճառ', add: 'Ավելացնել', up: 'Վերև', down: 'Ներքև',
|
||
pool: 'վերադարձ ընդհանուր ցուցակ', poolHint: 'Այս կարգավիճակում վերցված օբյեկտը կվերադառնա ընդհանուր ցուցակ, եթե կարգավիճակը երկար չփոխվի',
|
||
system: 'Համակարգային կարգավիճակ', systemReason: 'Համակարգային պատճառ. այն դնում է «Սա գործակալ է» կոճակը',
|
||
confirmStatus: (n) => `Ջնջե՞լ «${n}» կարգավիճակը`, confirmReason: (n) => `Ջնջե՞լ «${n}» պատճառը`,
|
||
removeTitle: (n) => `Ջնջել «${n}» կարգավիճակը`, removeHint: (n) => `Այս կարգավիճակում քարտեր՝ ${n}։ Ընտրեք, թե ուր տեղափոխել դրանք։`,
|
||
moveTo: 'Տեղափոխել կարգավիճակ…',
|
||
},
|
||
pay: {
|
||
title: 'Վճարման պայմաններ', notSet: 'Նշված չեն', modes: { fixed: 'Աշխատավարձ', percent: 'Տոկոս իր գործարքներից', mixed: 'Աշխատավարձ + տոկոս իր գործարքներից' },
|
||
salary: (v) => `աշխատավարձ ${v}`, share: (v) => `գործարքների ${v}%-ը`, shareSplit: (sale, rent) => `վաճառքից ${sale}%, վարձակալությունից ${rent}%`,
|
||
fixedLabel: 'Ամսական աշխատավարձ', percentLabel: 'Տոկոս վաճառքից', percentRentLabel: 'Տոկոս վարձակալությունից', payoutCurrency: 'Վճարման արժույթ',
|
||
hint: 'Տոկոսը հաշվվում է միջնորդավճարի այն մասից, որը բաժին է հասնում գործակալին. սեփականատիրոջից՝ օբյեկտի գործակալին, հաճախորդից՝ հաճախորդի գործակալին։', edit: 'Վճարման պայմաններ',
|
||
payroll: 'Ում որքան վճարել', payrollHint: 'Ամսվա աշխատավարձը և տոկոսը՝ այս ամսվա գործարքներում գործակալի միջնորդավճարի մասից։ Սեղմեք աշխատակցի վրա՝ նրա գործարքները տեսնելու համար։', month: 'Ամիս',
|
||
col: { agent: 'Աշխատակից', terms: 'Պայմաններ', deals: 'Գործարքներ', commission: 'Միջնորդավճարի նրա մասը', share: 'Տոկոս', fixed: 'Աշխատավարձ', total: 'Վճարման ենթակա', sum: 'Ընդամենը վճարման ենթակա' },
|
||
mine: 'Իմ վճարումը', thisMonth: 'Հաշվարկված ամսվա համար',
|
||
dealsOf: (name) => `Գործարքներ՝ ${name}`, myDeals: 'Իմ գործարքները այս ամիս', noDeals: 'Այս ամիս գործարքներ չկան։',
|
||
dcol: { date: 'Ամսաթիվ', deal: 'Օբյեկտ և հաճախորդ', kind: 'Տեսակ', side: 'Կողմ', part: 'Միջնորդավճարի մաս', percent: 'Տոկոս', accrued: 'Հաշվարկված' },
|
||
side: { owner: 'օբյեկտ', client: 'հաճախորդ', both: 'օբյեկտ և հաճախորդ' }, withPartner: (name) => `երկրորդ կողմը՝ ${name}`, ofDeal: (v) => `${v}-ից`,
|
||
planTitle: 'Ամսական պլան', planDeals: 'Գործարքներ', planCommission: 'Գործակալի միջնորդավճար', planHint: 'Դատարկ դաշտ՝ ցուցանիշը նշված չէ։ Պլանը կատարված է, երբ բոլոր նշված ցուցանիշները հասած են։',
|
||
bonusTitle: 'Բոնուս կատարված պլանի համար', bonusModes: { none: 'Չկա', fixed: 'Գումար', percent: 'Հավելում տոկոսին' }, bonusValue: 'Չափ', bonusHint: 'Հավելումը հաշվվում է գործակալի ամսվա ամբողջ միջնորդավճարից։',
|
||
planOf: (done, plan) => `${done}՝ ${plan}-ից`, planDone: 'Պլանը կատարված է', planNot: 'Պլանը կատարված չէ',
|
||
other: 'Բոնուս և այլ', status: 'Վճարում', paid: (d) => `Վճարված է ${d}`, notPaid: 'Վճարված չէ',
|
||
lines: 'Հաշվարկներ', lineFixed: 'Աշխատավարձ', lineShare: 'Տոկոս գործարքներից', lineBonus: 'Բոնուս պլանի համար', lineRecalc: (m) => `Վերահաշվարկ՝ ${m}`, lineTotal: 'Ընդամենը վճարման ենթակա',
|
||
addLine: 'Ավելացնել գրառում', lineAmount: 'Գումար (մինուսով՝ պահում)', lineNote: 'Ինչի համար', lineNotePh: 'Պարգև, տուգանք, կանխավճար…', add: 'Ավելացնել', remove: 'Ջնջել գրառումը',
|
||
payTitle: 'Նշել վճարումը', payAmount: 'Վճարված է', payDate: 'Վճարման ամսաթիվ', payNote: 'Մեկնաբանություն', markPaid: 'Վճարված է', cancelPaid: 'Չեղարկել նշումը',
|
||
paidInfo: (v, d) => `Վճարված է ${v} · ${d}`, debt: (v) => `Մնացորդը՝ ${v}, կտեղափոխվի հաջորդ չվճարված ամիս։`, overpaid: (v) => `Գերավճարը՝ ${v}, կպահվի հաջորդ չվճարված ամսում։`,
|
||
closedHint: 'Ամիսը փակված է. հաշվվում է վճարման օրվա պայմաններով և փոխարժեքներով։ Նրա գործարքների փոփոխությունները վերահաշվարկով անցնում են հաջորդ ամիս։',
|
||
history: 'Վճարումների պատմություն', accruedOf: (v) => `հաշվարկված՝ ${v}`,
|
||
trend: 'Դինամիկան ըստ ամիսների', trendHint: 'Յուրաքանչյուր աշխատակցի գործարքները և միջնորդավճարի մասը։ Միջնորդավճարը՝ դոլարով, ընթացիկ փոխարժեքով։', trendMine: 'Իմ դինամիկան',
|
||
metricDeals: 'Գործարքներ', metricCommission: 'Միջնորդավճար', company: 'Ամբողջ ընկերությունը', vsPrev: (d) => `${d}՝ նախորդ ամսվա համեմատ`, same: 'ինչպես նախորդ ամիս',
|
||
asTable: 'Աղյուսակով', asChart: 'Գրաֆիկով', metric: 'Ցուցանիշ',
|
||
rating: 'Ամսվա վարկանիշ', ratingHint: 'Տեղը՝ ըստ գործարքների թվի. հավասարության դեպքում բարձր է նա, ում միջնորդավճարն ավելի մեծ է։ Գումարները վարկանիշում չեն ցուցադրվում։',
|
||
place: 'Տեղ', plan: 'Պլան', noPlan: 'պլան չկա', you: 'դուք',
|
||
export: 'Ներբեռնել Excel-ի համար', paidCol: 'Վճարված է', currency: 'Արժույթ', client: 'Հաճախորդ', object: 'Օբյեկտ',
|
||
reportsTitle: 'Հաշվետվություններ Telegram-ում', reportsHint: 'Գալիս են ղեկավարին Lead Radar բոտում՝ առավոտյան 9-ին Երևանի ժամանակով։', reportWeekly: 'Շաբաթվա արդյունքները՝ երկուշաբթի օրերին', reportMonthly: 'Ամսվա արդյունքները տեղեկագրով՝ ամսի մեկին',
|
||
},
|
||
cm: {
|
||
title: 'Գործակալության միջնորդավճար', mode: 'պայման', none: 'Նշված չէ', percent: 'Տոկոս', fixed: 'Ֆիքսված', mixed: 'Ֆիքսված + տոկոս', amount: 'գումար', notSet: 'Նշված չէ',
|
||
ofPrice: (v) => `գնի ${v}%-ը`, ofRent: (v) => `ամսական վարձի ${v}%-ը`,
|
||
fromSettings: 'ինչպես ընկերության կարգավորումներում', custom: 'փոխված է այս քարտում', reset: 'Ինչպես կարգավորումներում', forThis: 'Պայման այս քարտի համար',
|
||
hintLead: 'Պայմանը կարգավորումներում նշված չէ. նշեք Ձերը։', hintClient: 'Պայմանը կարգավորումներում նշված չէ. նշեք Ձերը։ Տոկոսը հաշվվում է հաճախորդի բյուջեից։',
|
||
settings: 'Գործակալության միջնորդավճար', settingsHint: 'Լռելյայն պայմաններ։ Տոկոսը հաշվվում է օբյեկտի գնից, վարձակալության դեպքում՝ ամսական վարձից, հաճախորդի դեպքում՝ նրա բյուջեից։ Գործակալը կարող է փոխել պայմանը քարտում։',
|
||
objectSale: 'Օբյեկտներ՝ վաճառք (սեփականատիրոջից)', objectRent: 'Օբյեկտներ՝ վարձակալություն (սեփականատիրոջից)', clientBuyer: 'Հաճախորդներ՝ գնորդ', clientTenant: 'Հաճախորդներ՝ վարձակալ',
|
||
prefill: 'Գումարը լրացվել է ըստ միջնորդավճարի պայմանի. ուղղեք, եթե այլ կերպ եք պայմանավորվել։',
|
||
evChanged: (from, to) => `Միջնորդավճար՝ ${from} → ${to}`, asSettings: 'ինչպես կարգավորումներում', points: (v) => `${v} տոկոսային կետ`, sumDelta: (v) => `գումարը ${v}%`,
|
||
},
|
||
sh: {
|
||
page: 'Էջ հաճախորդի համար', pageHint: 'Հաճախորդը բացում է այն առանց մուտքի. տեսնում է կցված օբյեկտները և գրանցվում ցուցադրության։ Էջը չի ցուցադրում հասցեն և List.am-ի հղումը։',
|
||
create: 'Ստեղծել էջ', createMatch: 'Ընտրել օբյեկտներ և ստեղծել', added: (n) => (n ? `Կցված համապատասխան օբյեկտներ՝ ${n}։` : 'Համապատասխան օբյեկտներ հիմա չկան. էջը ստեղծվել է արդեն կցվածներով։'),
|
||
close: 'Փակել էջը', confirmClose: 'Փակե՞լ էջը։ Հաճախորդի հղումն այլևս չի բացվի։', open: 'Բացել',
|
||
viewings: 'Ցուցադրության գրանցումներ', viewingLine: (day, title) => `${day} — ${title}`,
|
||
intake: 'Հարցաթերթիկի հղում', intakeTitle: 'Հարցաթերթիկ հաճախորդի համար',
|
||
intakeText: 'Ուղարկեք հղումը հաճախորդին կամ տեղադրեք հայտարարության մեջ։ Նա կպատասխանի հարցերին Telegram-ում և կհայտնվի այստեղ որպես Ձեր հաճախորդ։ Բոտում կստանաք հարցաթերթիկը և հարց՝ ցույց տա՞լ նրան համապատասխան օբյեկտները։',
|
||
intakeOff: 'Հարցաթերթիկը դեռ միացված չէ. հաճախորդների բոտը կարգավորված չէ։',
|
||
evViewing: (title, day) => `Հաճախորդը գրանցվել է ցուցադրության ${day ?? ''}՝ ${title ?? '—'}`,
|
||
evClientViewing: (name, day) => `Ցուցադրության գրանցում ${day ?? ''}՝ ${name ?? '—'}`,
|
||
ownerPhone: 'Սեփականատիրոջ հեռախոսը', ownerPhoneHint: 'Տեղադրեք համարը List.am-ի հայտարարությունից. այն կպահպանվի քարտում։', savePhone: 'Պահպանել համարը', changePhone: 'Փոխել համարը',
|
||
clientText: 'Նկարագրություն հաճախորդի համար', copyText: 'Պատճենել տեքստը', original: 'Հայտարարությունը List.am-ում՝ սկզբնական տեքստ և բնութագրեր', photosLoading: 'Բեռնում ենք մնացած լուսանկարները…',
|
||
evPhone: (v) => (v ? `Ավելացվել է սեփականատիրոջ հեռախոսը՝ ${v}` : 'Սեփականատիրոջ հեռախոսը հեռացվել է'),
|
||
variants: 'Համարներ ընդհանուր բազայից', variantsHint: 'Դրանք ավելացրել են այս հայտարարության հետ աշխատած գործակալները։', useVariant: 'Վերցնել այս համարը',
|
||
confidence: (pct, votes) => `ճշգրտություն ${pct}% · համընկել է ${votes}-ի մոտ`, unconfirmed: 'հաստատված չէ. նշել է մեկ գործակալ',
|
||
slug: 'Հաճախորդների էջերի հասցե', slugHint: 'Լատինատառեր, թվեր և գծիկ։ Փոխելու դեպքում հաճախորդների հին հղումները չեն բացվի։',
|
||
},
|
||
hh: {
|
||
title: 'Ով է ապրելու', who: { alone: 'Մենակ', friend: 'Ընկերոջ հետ', couple: 'Զուգընկերոջ հետ (զույգ)' }, notSet: 'Նշված չէ',
|
||
children: 'Երեխաներ', pets: 'Կենդանիներ', count: 'Քանիսը', age: 'Տարիք', ageHintChildren: '3 և 7 տարեկան', ageHintPets: 'կատու, 2 տարեկան',
|
||
childrenLine: (n, age) => `երեխաներ՝ ${n}${age ? ` (${age})` : ''}`, petsLine: (n, age) => `կենդանիներ՝ ${n}${age ? ` (${age})` : ''}`,
|
||
photos: 'Լուսանկարներ', addPhoto: 'Ավելացնել լուսանկար', removePhoto: 'Ջնջել լուսանկարը', photosHint: 'Բնակիչներ, կենդանիներ, փաստաթղթեր։ Մինչև 10 լուսանկար, յուրաքանչյուրը՝ մինչև 5 ՄԲ։',
|
||
confirmRemove: 'Ջնջե՞լ լուսանկարը', empty: 'Լրացված չէ։',
|
||
about: 'Օբյեկտի մասին', amenities: 'Հարմարություններ', rules: { children: 'Երեխաներով', pets: 'Կենդանիներով' },
|
||
allow: { yes: 'կարելի է', no: 'չի կարելի', negotiable: 'պայմանավորվածությամբ' },
|
||
},
|
||
x: {
|
||
byUrl: 'Հղումով', byUrlTitle: 'Օբյեկտ List.am-ի հղումով', byUrlLabel: 'Հայտարարության հղումը',
|
||
byUrlHint: 'Եթե օբյեկտն արդեն CRM-ում է և ազատ է, այն կամրագրվի ձեզ։ Եթե չկա, կներբեռնենք List.am-ից և կգրանցենք ձեզ վրա։',
|
||
byUrlGo: 'Ստուգել և ամրագրել', byUrlLoading: 'Փնտրում ենք օբյեկտը, անհրաժեշտության դեպքում ներբեռնում List.am-ից — կարող է տևել մինչև մեկ րոպե…',
|
||
taken: 'Օբյեկտը ազատ էր — այժմ այն ամրագրված է ձեզ։', created: 'Օբյեկտը CRM-ում չկար — ներբեռնեցինք List.am-ից և ամրագրեցինք ձեզ։',
|
||
mine: 'Այս օբյեկտն արդեն ամրագրված է ձեզ։', busy: (name: string | null) => (name ? `Օբյեկտն արդեն ամրագրված է ${name} գործակալին։` : 'Օբյեկտն արդեն մեկ այլ գործակալի մոտ է։'),
|
||
open: 'Բացել քարտը', districts: 'Շրջաններ',
|
||
sendTg: 'Ուղարկել Telegram', sendingTg: 'Ուղարկում ենք…', sentTg: 'Ուղարկված է խմբին', botNotSet: 'Բոտը կարգավորված չէ',
|
||
del: 'Ջնջել քարտը', delConfirm: 'Ջնջե՞լ քարտը պատմության հետ միասին։ Հնարավոր չէ չեղարկել։', delDeal: 'Քարտն ունի գործարք․ այն կարող է ջնջել միայն սուպերադմինը — գործարքը կհեռացվի վերլուծությունից և վճարացուցակից։',
|
||
phrase: { broker: 'Հայտարարությունը կարծես միջնորդից է', noAgents: 'Սեփականատերը գրում է, որ չի աշխատում գործակալների հետ' },
|
||
telegram: 'Telegram', telegramPh: '@անուն կամ t.me հղում', rentTerm: 'Վարձակալության ժամկետ', term: { short: 'Մինչև 6 ամիս', mid: '6–12 ամիս', long: 'Մեկ տարուց ավելի' },
|
||
},
|
||
tg: { link: 'Կապել Telegram-ը', open: 'Բացեք բոտը և սեղմեք «Start».', hint: 'Կապելուց հետո նոր օբյեկտները կգան այստեղ։' },
|
||
parser: {
|
||
title: 'Պարսեր', off: 'Հայտարարությունների աղբյուրը կարգավորված չէ։', lastOk: 'Վերջին հաջող անցումը', day: 'Հայտարարություններ՝ վերջին օրվա ընթացքում',
|
||
total: 'Ընդամենը հայտարարություններ', cycle: 'Պարսերի լրիվ շրջանը', delay: '«Տեղադրվել է → լիդ» ուշացում, օրվա մեդիան', delayN: (n) => `${n} լիդի հիման վրա`, day3: 'Բազայում՝ թարմ, 3 օրից ոչ հին', run: 'Գործարկել հիմա', runs: 'Վերջին գործարկումները', started: 'Սկիզբ', took: 'Տևողություն',
|
||
found: 'Նոր', status: 'Կարգավիճակ', errors: 'Սխալներ', ok: 'հաջող', failed: 'ձախողում', running: 'ընթացքում', sec: 'վ',
|
||
},
|
||
dp: {
|
||
favorite: 'Ընտրված', unseen: 'Չդիտված', addFav: 'Ավելացնել ընտրվածներին', removeFav: 'Հանել ընտրվածներից', unseenMark: 'Չդիտված',
|
||
currency: 'Արժույթ', cur: { AMD: 'ՀՀԴ', USD: 'ԴՈԼ' } as Record<string, string>, priceHint: 'Այլ արժույթով գները վերահաշվարկվում են փոխարժեքով',
|
||
sendBot: 'Ուղարկել բոտին', sendingBot: 'Ուղարկում ենք…', sentBot: 'Ուղարկվեց ձեզ բոտում',
|
||
linkTitle: 'Telegram-ը կապված չէ բոտին',
|
||
linkText: 'Օբյեկտը բոտում ստանում է նա, ով սեղմել է կոճակը՝ ձեր հաշվին կապված Telegram-ում։ Սեղմեք «Կապել Telegram-ը», բացեք բոտը, սեղմեք «Start» և նորից ուղարկեք օբյեկտը։ Կապելը հասանելի է նաև «Կարգավորումներում»։',
|
||
blockedText: 'Բոտը չի կարող գրել ձեզ․ բացեք բոտը Telegram-ում, սեղմեք «Start» (կամ ապաարգելափակեք այն) և փորձեք կրկին։',
|
||
linkBtn: 'Կապել Telegram-ը', openBot: 'Բացել բոտը',
|
||
departments: 'Բաժիններ', department: 'Բաժին', noDepartment: 'Առանց բաժնի', allDepartments: 'Բոլոր բաժինները', add: 'Նոր բաժին', namePh: 'Բաժնի անվանումը',
|
||
rename: 'Վերանվանել', del: 'Ջնջել բաժինը', delConfirm: 'Ջնջե՞լ բաժինը։ Կջնջվեն նրա ֆիլտրերը և պուլի այն օբյեկտները, որոնք ոչ ոք չի վերցրել։',
|
||
hint: 'Յուրաքանչյուր բաժին ունի իր ֆիլտրերը, օբյեկտները և հաճախորդները։ Աշխատակիցը տեսնում է միայն իր բաժնի տվյալները, ղեկավարը՝ բոլոր բաժինները։ Բաժինը փոխելիս աշխատակցի վարած օբյեկտներն ու հաճախորդները տեղափոխվում են նրա հետ։',
|
||
stats: (m: number, f: number, l: number, c: number) => `աշխատակից՝ ${m} · ֆիլտր՝ ${f} · օբյեկտ՝ ${l} · հաճախորդ՝ ${c}`,
|
||
kept: (n: number) => `Նախկին բաժնում մնաց ${n} օբյեկտ․ նորում արդեն կան նույն հայտարարությունների քարտերը։`,
|
||
none: 'Բաժիններ դեռ չկան․ ամբողջ ընկերությունն աշխատում է ընդհանուր օբյեկտներով և հաճախորդներով։',
|
||
scope: 'Բաժին', filtersOf: (name: string) => `«${name}» բաժնի ֆիլտրերը`, mine: (name: string) => `Ձեր բաժինը՝ ${name}`,
|
||
removed: 'Հանված են List.am-ից',
|
||
},
|
||
errors: {
|
||
MONTH_PAID: 'Ամիսն արդեն փակված է վճարումով։ Փոխելու համար չեղարկեք նշումը', PAYOUT_NOT_LAST: 'Կարելի է չեղարկել միայն աշխատակցի վերջին վճարումը',
|
||
ALREADY_TAKEN: 'Այս օբյեկտն արդեն վերցրել է այլ գործակալ', LEAD_NOT_FOUND: 'Օբյեկտը չի գտնվել', NOT_YOUR_LEAD: 'Օբյեկտը վարում է այլ գործակալ',
|
||
TAKE_FIRST: 'Նախ վերցրեք օբյեկտը աշխատանքի', REJECT_REASON_REQUIRED: 'Նշեք մերժման պատճառը',
|
||
COMMISSION_REQUIRED: 'Նշեք միջնորդավճարի գումարը', USE_RETURN_TO_POOL: 'Օբյեկտը վերադարձնելու համար օգտագործեք «Վերադարձնել ընդհանուր ցուցակ» կոճակը',
|
||
MODULE_NOT_AVAILABLE: 'Բաժինը հասանելի է Team և Agency սակագներում',
|
||
CLIENT_NOT_FOUND: 'Հաճախորդը չի գտնվել', NOT_YOUR_CLIENT: 'Հաճախորդին վարում է այլ գործակալ', BAD_ASSIGNEE: 'Ընկերությունում նման մասնակից չկա',
|
||
PAIR_NOT_LINKED: 'Նախ կցեք օբյեկտը հաճախորդին', DEAL_HAS_PAIR: 'Այս գործարքում արդեն նշված է այլ զույգ։ Նախ չեղարկեք այն',
|
||
BAD_STATUS: 'Ձագարում նման կարգավիճակ չկա', SYSTEM_STATUS: 'Համակարգային կարգավիճակը հնարավոր չէ ջնջել', STATUS_IN_USE: 'Կարգավիճակում քարտեր կան. ընտրեք, թե ուր տեղափոխել',
|
||
SYSTEM_REASON: 'Համակարգային պատճառը հնարավոր չէ ջնջել', LAST_REASON: 'Անհրաժեշտ է առնվազն մեկ մերժման պատճառ',
|
||
DEAL_CLOSED: 'Գործարքը փակված է. կարգավիճակը փոխում է ղեկավարը', TELEGRAM_DISABLED: 'Բոտը կարգավորված չէ', PARSER_DISABLED: 'Պարսերը կարգավորված չէ', BAD_LISTAM_URL: 'Սա List.am-ի հայտարարության հղում չէ', LISTAM_NOT_FOUND: 'Նման հայտարարություն List.am-ում չկա — հնարավոր է՝ հանվել է', LISTAM_UNAVAILABLE: 'Չհաջողվեց կարդալ հայտարարությունը List.am-ից, փորձեք կրկին', HAS_DEAL: 'Քարտն ունի գործարք․ այն կարող է ջնջել միայն սուպերադմինը', GROUP_BOT_NOT_SET: 'Բոտը կարգավորված չէ', GROUP_SEND_FAILED: 'Չհաջողվեց ուղարկել Telegram, փորձեք կրկին', TELEGRAM_NOT_LINKED: 'Telegram-ը կապված չէ բոտին', BOT_CHAT_UNAVAILABLE: 'Բոտը չի կարող գրել ձեզ․ բացեք բոտը և սեղմեք «Start»', BOT_SEND_FAILED: 'Չհաջողվեց ուղարկել բոտին, փորձեք կրկին', DEPARTMENT_NOT_EMPTY: 'Բաժնում կան աշխատակիցներ, հաճախորդներ կամ աշխատանքի մեջ գտնվող օբյեկտներ․ նախ տեղափոխեք դրանք', BAD_DEPARTMENT: 'Նման բաժին չկա', DEPARTMENT_HAS_LEAD: 'Այս աշխատակցի բաժնում արդեն կա այս հայտարարության քարտը',
|
||
},
|
||
};
|
||
|
||
const en: Dict = {
|
||
tabs: { pool: 'Pool', mine: 'Mine', all: 'All' },
|
||
view: { table: 'Table', kanban: 'Kanban' },
|
||
search: 'Phone, address, listing ID',
|
||
add: 'Add property',
|
||
take: 'Take',
|
||
bumped: 'Bumped on List.am',
|
||
taken: 'Taken',
|
||
empty: { pool: 'The pool is empty. New properties appear here as soon as a filter matches.', mine: 'You have no properties in progress yet.', all: 'No properties yet.' },
|
||
noFilters: 'Create your first filter to start receiving properties.',
|
||
toFilters: 'Create filter',
|
||
col: { object: 'Property', price: 'Price', place: 'District', status: 'Status', agent: 'Assignee', created: 'Created' },
|
||
f: { status: 'Status', agent: 'Agent', district: 'District', priceFrom: 'Price from', priceTo: 'to', from: 'Created from', to: 'to', any: 'Any', reset: 'Reset', more: 'Filters' },
|
||
pool: 'in pool',
|
||
card: {
|
||
onListAm: 'Open on List.am', contact: 'Contact', call: 'Call', phoneHidden: 'The phone opens after “Take”',
|
||
noPhone: 'The phone is in the List.am listing', assignee: 'Assignee', status: 'Status', nextAction: 'Next action',
|
||
nextNote: 'What to do', remind: 'Remind in the bot', clear: 'Clear', comment: 'Comment', addComment: 'Add',
|
||
history: 'History', isAgent: 'It is an agent', toPool: 'Return to pool', manual: 'Manual', agency: 'Agency',
|
||
clients: 'Clients this property was offered to', attach: 'Attach to a client…',
|
||
previous: 'Was in progress before', confirmAgent: 'Mark the author as an agent? The property moves to “Rejected”.',
|
||
confirmPool: 'Return the property to the pool? Any agent will be able to take it.',
|
||
gone: 'Listing is gone', confirmGone: 'Mark the listing as removed from List.am? Everyone handling this property will see the mark.',
|
||
editTitle: 'Property details',
|
||
},
|
||
ev: {
|
||
created: 'Property created', createdListam: 'Came from List.am', createdManual: 'Created manually', taken: 'Took it',
|
||
assigned: (a, b) => (a ? `Reassigned: ${a} → ${b}` : `Assigned: ${b}`),
|
||
status: (a, b) => `Status: ${a ?? '—'} → ${b}`,
|
||
deal: (text) => `Deal${text ? `, commission ${text}` : ''}`,
|
||
poolReturn: (who) => (who ? `Returned to pool (was with: ${who})` : 'Returned to pool'),
|
||
clientCreated: 'Client created', edited: 'Details changed', dealEdited: (text) => `Deal corrected${text ? `: commission ${text}` : ''}`,
|
||
offered: (v) => `Property offered: ${v ?? '—'}`, shown: (v) => `Property shown: ${v ?? '—'}`,
|
||
unlinked: (v) => `Property detached${v ? `: ${v}` : ''}`,
|
||
clientOffered: (v) => `Offered to client: ${v ?? '—'}`, clientShown: (v) => `Shown to client: ${v ?? '—'}`,
|
||
blacklisted: 'Marked as an agent', system: 'System', listingRemoved: 'Marked: listing is gone',
|
||
},
|
||
dlg: {
|
||
reject: 'Reject reason', deal: 'Close the deal', commission: 'Agency commission', currency: 'Currency', date: 'Deal date',
|
||
ownerPart: 'From the owner', clientPart: 'From the client', splitHint: 'The owner’s part goes to the property’s agent, the client’s part to the client’s agent. Enter 0 if there is no such side.',
|
||
edit: 'Edit', dealEdit: 'Correct the deal', pairClient: 'Deal with a CRM client', pairLead: 'Deal with a CRM property',
|
||
noPair: 'No pair — the other side is outside the CRM', pairHint: 'The deal closes once: both move to “Deal” and the commission is not counted twice.',
|
||
pairEmptyClient: 'To close the deal together with a client, attach the property to the client first.',
|
||
pairEmptyLead: 'To close the deal together with a property, first attach a property that is in progress.',
|
||
title: 'Title', description: 'Description', address: 'Address', price: 'Price', rooms: 'Rooms', area: 'Area, m²',
|
||
floor: 'Floor', floors: 'Floors', author: 'Owner name', phone: 'Phone', link: 'Listing link',
|
||
},
|
||
deal: { sale: 'Sale', rent: 'Rent' },
|
||
ptype: { apartment: 'Apartment', house: 'House', commercial: 'Commercial', land: 'Land', garage: 'Garage' },
|
||
unit: { rooms: 'rooms', floor: 'floor', perMonth: '/mo' },
|
||
filters: {
|
||
title: 'Filters', sub: 'A listing becomes a lead when it matches a company filter or an agent’s personal filter.',
|
||
company: 'Company filters', personal: 'My personal filters', others: 'Agents’ personal filters', add: 'New filter',
|
||
none: 'No filters.', name: 'Name', scope: 'For whom', scopeCompany: 'Whole company', scopePersonal: 'Only me',
|
||
dealType: 'Deal type', types: 'Property type', region: 'Region', allArmenia: 'All Armenia', districts: 'Districts',
|
||
localities: 'Localities, comma-separated', price: 'Price', area: 'Area, m²', rooms: 'Rooms',
|
||
author: 'Listing author', ownersOnly: 'Owners only', everyone: 'All listings', enabled: 'Enabled',
|
||
any: 'any', anyType: 'any type', from: 'from', to: 'to', confirmDelete: 'Delete the filter?', fromBase: (n) => `Properties added to the pool from the last 3 days of the base: ${n}`,
|
||
},
|
||
cl: {
|
||
sub: 'Buyers and tenants. A client belongs to an agent; the manager reassigns.',
|
||
add: 'Add client', one: 'Client', name: 'Name', kindLabel: 'Client type', kind: { buyer: 'Buyer', tenant: 'Tenant' },
|
||
anyKind: 'All types', source: 'Source', sourceHint: 'Instagram, referral…', me: 'Me', request: 'Request', budget: 'Budget',
|
||
noRequest: 'The request is empty. Fill it in and matching properties will appear here.', search: 'Name or phone',
|
||
empty: 'No clients yet. Add your first buyer or tenant.', notFound: 'Nothing found.',
|
||
objectsCol: 'Properties', objects: (n) => `properties: ${n}`, noObjects: 'No properties attached yet.',
|
||
suggested: 'Match the request', attach: 'Attach', detach: 'Detach', state: { offered: 'Offered', shown: 'Shown' },
|
||
phoneHidden: 'The phone is visible to the assigned agent', noPhone: 'No phone', dealLead: 'Property',
|
||
},
|
||
ar: {
|
||
sub: 'Properties and clients closed with a deal or a rejection, and properties removed from List.am. They appear here automatically.',
|
||
tabs: { leads: 'Properties', contacts: 'Clients' }, resultLabel: 'Result', anyResult: 'Any result', result: { deal: 'Deal', rejected: 'Rejected' },
|
||
closed: 'Closed', contact: 'Client', objects: 'Properties', empty: 'The base is empty: properties and clients appear here after a deal or a rejection.',
|
||
removed: (d) => `Removed from List.am ${d}`,
|
||
},
|
||
an: {
|
||
pipeline: { object: 'Properties', client: 'Clients' }, period: { today: 'Today', week: 'Week', month: 'Month', custom: 'Range' },
|
||
came: 'Leads received', takenTotal: 'Taken', inPool: 'In the pool now', inWork: 'In progress now', deals: 'Deals',
|
||
funnel: 'Whole funnel', funnelHintObject: 'Leads received in the period: how many reached each stage.',
|
||
funnelHintClient: 'Clients created in the period: how many reached each stage.', noData: 'No data for this period.',
|
||
byAgent: 'By agent', tableHintObject: 'Percentages: share of the leads the agent took in the period that reached the stage with them.',
|
||
tableHintClient: 'Percentages: share of the agent’s clients created in the period that reached the stage.',
|
||
agent: 'Agent', taken: 'Leads taken', newRequests: 'New requests', reaction: 'Reaction time', poolReturns: 'Pool returns', showings: 'Showings',
|
||
commission: 'Commission total', total: 'Total', reasons: 'Reject reasons', reason: 'Reason', noRejects: 'No rejections in the period.',
|
||
sec: 's', min: 'min', hour: 'h',
|
||
},
|
||
ls: {
|
||
sub: 'The shared base: everything the parser collected from List.am. From here listings go to clients by their filters.',
|
||
search: 'Listing number, title, address, phone', total: (n) => `Found: ${n}`, anyDeal: 'Any deal', anyRegion: 'All regions',
|
||
state: { any: 'Live and removed', active: 'Live', removed: 'Removed' }, leads: { any: 'With and without leads', yes: 'Has leads', no: 'No leads' },
|
||
author: { any: 'Any author', owner: 'Owner', agency: 'Agency' },
|
||
col: { listing: 'Listing', price: 'Price', place: 'District', published: 'Posted', found: 'Found', leads: 'Leads' },
|
||
empty: 'No listings.', prev: 'Back', next: 'Next', page: (a, b) => `Page ${a} of ${b}`,
|
||
number: 'Number', sentTo: 'Sent as a lead to', noLeads: 'It matched no filter.', pool: 'in pool',
|
||
},
|
||
ps: {
|
||
title: 'Parser settings', hint: 'Applied from the next run; no restart needed.',
|
||
enabled: 'Parser is on: it crawls List.am in a loop', freshDays: 'Freshness, days', freshHint: 'For the Top block and the first pass: listings posted no earlier than this. Bumped listings in the regular list always go to the base',
|
||
pauseSec: 'Pause between runs, seconds', maxPages: 'Category pages per run', pagesHint: 'Read while they contain unseen listings',
|
||
categories: 'List.am categories', keyTitle: 'Jina reader key',
|
||
keyHint: 'With a key a run is faster and the exact posting time is known, but the key is paid. Without it the parser is slower. If the key balance runs out, the parser switches to keyless mode by itself.',
|
||
useKey: 'Use the key', key: 'Current key', keyNone: 'not set', keyEnv: 'from server settings', keySet: 'set here',
|
||
keyNew: 'Paste a new key to replace', keyClear: 'Remove key', keyConfirm: 'Remove the key set in the admin panel?',
|
||
quietTitle: 'Night pause', quietHint: 'During these hours (Yerevan time) the parser and the removal check do not run, so reader tokens are not spent. The parser watchdog stays silent during the pause.',
|
||
quietOn: 'Stop the parser at night', quietFrom: 'From (Yerevan)', quietTo: 'Until (Yerevan)', quietSame: 'Start and end are the same, so there is no pause',
|
||
removalTitle: '“Removed from List.am” mark', removalCheck: 'Check whether listings with leads were removed',
|
||
recheckHours: 'Recheck a listing every, hours', removalBatch: 'Listings per batch (every 10 minutes)', batchHint: (n) => `Up to ${n} checks a day`,
|
||
},
|
||
pl: {
|
||
title: { object: 'Property pipeline', client: 'Client pipeline' },
|
||
hint: 'Names are saved immediately. Statuses with a lock are system ones: they can be renamed but not deleted or moved.',
|
||
statuses: 'Statuses', reasons: 'Reject reasons', statusName: 'Status name', reasonName: 'Reject reason',
|
||
newStatus: 'New status', newReason: 'New reason', add: 'Add', up: 'Up', down: 'Down',
|
||
pool: 'return to pool', poolHint: 'A taken property in this status returns to the pool if the status stays unchanged for too long',
|
||
system: 'System status', systemReason: 'System reason: set by the “It is an agent” button',
|
||
confirmStatus: (n) => `Delete the status “${n}”?`, confirmReason: (n) => `Delete the reason “${n}”?`,
|
||
removeTitle: (n) => `Delete the status “${n}”`, removeHint: (n) => `Cards in this status: ${n}. Choose where to move them.`,
|
||
moveTo: 'Move to status…',
|
||
},
|
||
pay: {
|
||
title: 'Pay terms', notSet: 'Not set', modes: { fixed: 'Salary', percent: 'Percent of their deals', mixed: 'Salary + percent of their deals' },
|
||
salary: (v) => `salary ${v}`, share: (v) => `${v}% of deals`, shareSplit: (sale, rent) => `${sale}% of sales, ${rent}% of rentals`,
|
||
fixedLabel: 'Monthly salary', percentLabel: 'Percent of sales', percentRentLabel: 'Percent of rentals', payoutCurrency: 'Payout currency',
|
||
hint: 'The percentage is taken from the agent’s part of the commission: the owner’s part goes to the property’s agent, the client’s part to the client’s agent.', edit: 'Pay terms',
|
||
payroll: 'Who gets paid how much', payrollHint: 'Monthly salary plus a percentage of the agent’s part of the commission on this month’s deals. Click an employee to see their deals.', month: 'Month',
|
||
col: { agent: 'Employee', terms: 'Terms', deals: 'Deals', commission: 'Their part of commission', share: 'Percent', fixed: 'Salary', total: 'To pay', sum: 'Total to pay' },
|
||
mine: 'My pay', thisMonth: 'Accrued this month',
|
||
dealsOf: (name) => `Deals: ${name}`, myDeals: 'My deals this month', noDeals: 'No deals this month.',
|
||
dcol: { date: 'Date', deal: 'Property and client', kind: 'Type', side: 'Side', part: 'Commission part', percent: 'Percent', accrued: 'Accrued' },
|
||
side: { owner: 'property', client: 'client', both: 'property and client' }, withPartner: (name) => `other side: ${name}`, ofDeal: (v) => `of ${v}`,
|
||
planTitle: 'Monthly plan', planDeals: 'Deals', planCommission: 'Agent’s commission', planHint: 'An empty field means no target. The plan is met when every target set is reached.',
|
||
bonusTitle: 'Bonus for meeting the plan', bonusModes: { none: 'None', fixed: 'Amount', percent: 'Extra percent' }, bonusValue: 'Size', bonusHint: 'The extra percent applies to the agent’s whole commission for the month.',
|
||
planOf: (done, plan) => `${done} of ${plan}`, planDone: 'Plan met', planNot: 'Plan not met',
|
||
other: 'Bonus and other', status: 'Payout', paid: (d) => `Paid ${d}`, notPaid: 'Not paid',
|
||
lines: 'Accruals', lineFixed: 'Salary', lineShare: 'Percent of deals', lineBonus: 'Plan bonus', lineRecalc: (m) => `Recalculation for ${m}`, lineTotal: 'Total to pay',
|
||
addLine: 'Add an entry', lineAmount: 'Amount (negative to deduct)', lineNote: 'What for', lineNotePh: 'Bonus, penalty, advance…', add: 'Add', remove: 'Delete entry',
|
||
payTitle: 'Mark as paid', payAmount: 'Paid', payDate: 'Payment date', payNote: 'Comment', markPaid: 'Paid', cancelPaid: 'Undo',
|
||
paidInfo: (v, d) => `Paid ${v} · ${d}`, debt: (v) => `The remaining ${v} moves to the next unpaid month.`, overpaid: (v) => `The overpayment of ${v} will be deducted in the next unpaid month.`,
|
||
closedHint: 'The month is closed: it is calculated with the terms and rates of the payment day. Changes to its deals go to the next month as a recalculation.',
|
||
history: 'Payout history', accruedOf: (v) => `accrued ${v}`,
|
||
trend: 'Monthly trend', trendHint: 'Deals and each employee’s part of the commission. Commission is in dollars at the current rate.', trendMine: 'My trend',
|
||
metricDeals: 'Deals', metricCommission: 'Commission', company: 'Whole company', vsPrev: (d) => `${d} vs last month`, same: 'same as last month',
|
||
asTable: 'As table', asChart: 'As chart', metric: 'Metric',
|
||
rating: 'Rating of the month', ratingHint: 'Ranked by number of deals; on a tie the higher commission wins. No amounts are shown in the rating.',
|
||
place: 'Place', plan: 'Plan', noPlan: 'no plan', you: 'you',
|
||
export: 'Download for Excel', paidCol: 'Paid', currency: 'Currency', client: 'Client', object: 'Property',
|
||
reportsTitle: 'Telegram reports', reportsHint: 'Sent to the manager in the Lead Radar bot at 9 am Yerevan time.', reportWeekly: 'Week summary — on Mondays', reportMonthly: 'Month summary with payroll — on the 1st',
|
||
},
|
||
cm: {
|
||
title: 'Agency commission', mode: 'terms', none: 'Not set', percent: 'Percent', fixed: 'Fixed', mixed: 'Fixed + percent', amount: 'amount', notSet: 'Not set',
|
||
ofPrice: (v) => `${v}% of the price`, ofRent: (v) => `${v}% of the monthly rent`,
|
||
fromSettings: 'as in company settings', custom: 'changed in this card', reset: 'As in settings', forThis: 'Terms for this card',
|
||
hintLead: 'No terms in settings — set your own.', hintClient: 'No terms in settings — set your own. The percentage is taken from the client’s budget.',
|
||
settings: 'Agency commission', settingsHint: 'Default terms. The percentage is taken from the property price, for rent — from the monthly rent; for a client — from their budget. An agent can change the terms in a card.',
|
||
objectSale: 'Properties: sale (from the owner)', objectRent: 'Properties: rent (from the owner)', clientBuyer: 'Clients: buyer', clientTenant: 'Clients: tenant',
|
||
prefill: 'The amount is filled in from the commission terms — adjust it if you agreed otherwise.',
|
||
evChanged: (from, to) => `Commission: ${from} → ${to}`, asSettings: 'as in settings', points: (v) => `${v} pp`, sumDelta: (v) => `amount ${v}%`,
|
||
},
|
||
sh: {
|
||
page: 'Page for the client', pageHint: 'The client opens it without logging in: sees the attached properties and books a viewing. The page does not show the address or the List.am link.',
|
||
create: 'Create page', createMatch: 'Pick properties and create', added: (n) => (n ? `Matching properties attached: ${n}.` : 'No matching properties right now — the page was created with those already attached.'),
|
||
close: 'Close page', confirmClose: 'Close the page? The client’s link will stop opening.', open: 'Open',
|
||
viewings: 'Viewing bookings', viewingLine: (day, title) => `${day} — ${title}`,
|
||
intake: 'Questionnaire link', intakeTitle: 'Questionnaire for a client',
|
||
intakeText: 'Send the link to a client or put it in your ad. They answer the questions in Telegram and appear here as your client. You get the questionnaire in the bot with a question whether to show them matching properties.',
|
||
intakeOff: 'The questionnaire is not connected yet: the client bot is not configured.',
|
||
evViewing: (title, day) => `The client booked a viewing ${day ?? ''}: ${title ?? '—'}`,
|
||
evClientViewing: (name, day) => `Viewing booked ${day ?? ''}: ${name ?? '—'}`,
|
||
ownerPhone: 'Owner’s phone', ownerPhoneHint: 'Paste the number from the List.am listing — it will be saved in the card.', savePhone: 'Save number', changePhone: 'Change number',
|
||
clientText: 'Description for the client', copyText: 'Copy text', original: 'List.am listing: original text and details', photosLoading: 'Loading the rest of the photos…',
|
||
evPhone: (v) => (v ? `Owner’s phone added: ${v}` : 'Owner’s phone removed'),
|
||
variants: 'Numbers from the shared base', variantsHint: 'Added by agents who worked with this listing.', useVariant: 'Use this number',
|
||
confidence: (pct, votes) => `accuracy ${pct}% · matched by ${votes}`, unconfirmed: 'unconfirmed: given by one agent',
|
||
slug: 'Address of client pages', slugHint: 'Latin letters, digits and hyphen. If you change it, clients’ old links stop opening.',
|
||
},
|
||
hh: {
|
||
title: 'Who will live there', who: { alone: 'Alone', friend: 'With a friend', couple: 'With a partner (couple)' }, notSet: 'Not set',
|
||
children: 'Children', pets: 'Pets', count: 'How many', age: 'Age', ageHintChildren: '3 and 7 years', ageHintPets: 'cat, 2 years',
|
||
childrenLine: (n, age) => `children: ${n}${age ? ` (${age})` : ''}`, petsLine: (n, age) => `pets: ${n}${age ? ` (${age})` : ''}`,
|
||
photos: 'Photos', addPhoto: 'Add a photo', removePhoto: 'Remove the photo', photosHint: 'Tenants, pets, documents. Up to 10 photos, 5 MB each.',
|
||
confirmRemove: 'Remove the photo?', empty: 'Not filled in.',
|
||
about: 'About the property', amenities: 'Amenities', rules: { children: 'Children', pets: 'Pets' },
|
||
allow: { yes: 'allowed', no: 'not allowed', negotiable: 'negotiable' },
|
||
},
|
||
x: {
|
||
byUrl: 'By link', byUrlTitle: 'Property by List.am link', byUrlLabel: 'Listing link',
|
||
byUrlHint: 'If the property is already in the CRM and free, it will be assigned to you. If not, we will download it from List.am and assign it to you.',
|
||
byUrlGo: 'Check and assign', byUrlLoading: 'Looking for the property and downloading it from List.am if needed — this can take up to a minute…',
|
||
taken: 'The property was free — it is now assigned to you.', created: 'The property was not in the CRM — downloaded from List.am and assigned to you.',
|
||
mine: 'This property is already assigned to you.', busy: (name: string | null) => (name ? `The property is already assigned to ${name}.` : 'Another agent is already working on this property.'),
|
||
open: 'Open card', districts: 'Districts',
|
||
sendTg: 'Send to Telegram', sendingTg: 'Sending…', sentTg: 'Sent to the group', botNotSet: 'Bot is not set up',
|
||
del: 'Delete card', delConfirm: 'Delete the card together with its history? This cannot be undone.', delDeal: 'The card has a deal: only the superadmin can delete it — the deal will disappear from analytics and payroll.',
|
||
phrase: { broker: 'The listing looks like it is from an intermediary', noAgents: 'The owner says they do not work with agents' },
|
||
telegram: 'Telegram', telegramPh: '@username or t.me link', rentTerm: 'Rental term', term: { short: 'Up to 6 months', mid: '6–12 months', long: 'A year or more' },
|
||
},
|
||
tg: { link: 'Link Telegram', open: 'Open the bot and press “Start”:', hint: 'Once linked, new properties will arrive there.' },
|
||
parser: {
|
||
title: 'Parser', off: 'The listing source is not configured.', lastOk: 'Last successful run', day: 'Listings in 24 hours',
|
||
total: 'Listings total', cycle: 'Full parser cycle', delay: '“Posted → lead” delay, 24h median', delayN: (n) => `over ${n} leads`, day3: 'In the base: fresh, up to 3 days old', run: 'Run now', runs: 'Recent runs', started: 'Started', took: 'Duration',
|
||
found: 'New', status: 'Status', errors: 'Errors', ok: 'ok', failed: 'failed', running: 'running', sec: 's',
|
||
},
|
||
dp: {
|
||
favorite: 'Favourites', unseen: 'Not viewed', addFav: 'Add to favourites', removeFav: 'Remove from favourites', unseenMark: 'Not viewed',
|
||
currency: 'Currency', cur: { AMD: 'AMD', USD: 'USD' } as Record<string, string>, priceHint: 'Prices in another currency are converted at the current rate',
|
||
sendBot: 'Send to bot', sendingBot: 'Sending…', sentBot: 'Sent to you in the bot',
|
||
linkTitle: 'Telegram is not linked to the bot',
|
||
linkText: 'The property goes to whoever pressed the button — to the Telegram linked to your account. Press “Link Telegram”, open the bot, press “Start” and send the property again. Linking is also available in Settings.',
|
||
blockedText: 'The bot cannot message you: open the bot in Telegram, press “Start” (or unblock it) and try again.',
|
||
linkBtn: 'Link Telegram', openBot: 'Open the bot',
|
||
departments: 'Departments', department: 'Department', noDepartment: 'No department', allDepartments: 'All departments', add: 'New department', namePh: 'Department name',
|
||
rename: 'Rename', del: 'Delete department', delConfirm: 'Delete the department? Its filters and the pool properties nobody took will be deleted.',
|
||
hint: 'Each department has its own filters, properties and clients. An employee sees only their department’s data; the manager sees all departments. When an employee changes department, the properties and clients they handle move with them.',
|
||
stats: (m: number, f: number, l: number, c: number) => `employees: ${m} · filters: ${f} · properties: ${l} · clients: ${c}`,
|
||
kept: (n: number) => `Properties left in the previous department: ${n} — the new one already has cards for the same listings.`,
|
||
none: 'No departments yet — the whole company works with shared properties and clients.',
|
||
scope: 'Department', filtersOf: (name: string) => `“${name}” department filters`, mine: (name: string) => `Your department: ${name}`,
|
||
removed: 'Removed from List.am',
|
||
},
|
||
errors: {
|
||
MONTH_PAID: 'The month is already closed by a payout. Undo the payout to change it', PAYOUT_NOT_LAST: 'Only the employee’s latest payout can be undone',
|
||
ALREADY_TAKEN: 'Another agent has already taken this property', LEAD_NOT_FOUND: 'Property not found', NOT_YOUR_LEAD: 'Another agent handles this property',
|
||
TAKE_FIRST: 'Take the property first', REJECT_REASON_REQUIRED: 'Choose a reject reason',
|
||
COMMISSION_REQUIRED: 'Enter the commission amount', USE_RETURN_TO_POOL: 'Use “Return to pool” to send the property back',
|
||
MODULE_NOT_AVAILABLE: 'This section is available on the Team and Agency plans',
|
||
CLIENT_NOT_FOUND: 'Client not found', NOT_YOUR_CLIENT: 'Another agent handles this client', BAD_ASSIGNEE: 'No such member in the company',
|
||
PAIR_NOT_LINKED: 'Attach the property to the client first', DEAL_HAS_PAIR: 'This deal already has another pair. Cancel that deal first',
|
||
BAD_STATUS: 'No such status in the pipeline', SYSTEM_STATUS: 'A system status cannot be deleted', STATUS_IN_USE: 'The status has cards: choose where to move them',
|
||
SYSTEM_REASON: 'A system reason cannot be deleted', LAST_REASON: 'At least one reject reason is required',
|
||
DEAL_CLOSED: 'The deal is closed: only the manager changes the status', TELEGRAM_DISABLED: 'The bot is not configured', PARSER_DISABLED: 'The parser is not configured', BAD_LISTAM_URL: 'This is not a List.am listing link', LISTAM_NOT_FOUND: 'There is no such listing on List.am — it may have been removed', LISTAM_UNAVAILABLE: 'Could not read the listing from List.am, please try again', HAS_DEAL: 'The card has a deal: only the superadmin can delete it', GROUP_BOT_NOT_SET: 'Bot is not set up', GROUP_SEND_FAILED: 'Could not send to Telegram, please try again', TELEGRAM_NOT_LINKED: 'Telegram is not linked to the bot', BOT_CHAT_UNAVAILABLE: 'The bot cannot message you: open the bot and press “Start”', BOT_SEND_FAILED: 'Could not send to the bot, please try again', DEPARTMENT_NOT_EMPTY: 'The department has employees, clients or properties in work — move them first', BAD_DEPARTMENT: 'No such department', DEPARTMENT_HAS_LEAD: 'This employee’s department already has a card for this listing',
|
||
},
|
||
};
|
||
|
||
const dict: Record<Lang, Dict> = { ru, hy, en };
|
||
const LOCALES: Record<Lang, string> = { ru: 'ru-RU', hy: 'hy-AM', en: 'en-GB' };
|
||
const SYMBOL: Record<string, string> = { USD: '$', EUR: '€', AMD: '֏', RUB: '₽' };
|
||
|
||
/** Тексты CRM и форматирование на языке пользователя. Ошибки ищутся сначала здесь, потом в общем словаре. */
|
||
export function useCrm() {
|
||
const base = useLang();
|
||
const c = dict[base.lang];
|
||
return {
|
||
...base,
|
||
c,
|
||
err: (e: unknown) => c.errors[(e as { code?: string } | null)?.code ?? ''] ?? base.err(e),
|
||
price: (price: number | null, currency: string | null, dealType?: string | null) => {
|
||
if (price == null) return '—';
|
||
const n = Math.round(price).toLocaleString('ru-RU');
|
||
const sym = SYMBOL[currency ?? 'USD'] ?? '';
|
||
const text = currency === 'AMD' || currency === 'RUB' ? `${n} ${sym}` : `${sym}${n}`;
|
||
return dealType === 'rent' ? `${text}${c.unit.perMonth}` : text;
|
||
},
|
||
/** «окт» из «2026-10» — подпись под столбцом. */
|
||
monthShort: (ym: string) => new Date(`${ym}-01T00:00:00`).toLocaleDateString(LOCALES[base.lang], { month: 'short' }).replace('.', ''),
|
||
/** «октябрь 2026» из «2026-10». */
|
||
monthName: (ym: string) => new Date(`${ym}-01T00:00:00`).toLocaleDateString(LOCALES[base.lang], { month: 'long', year: 'numeric' }),
|
||
dateTime: (iso: string | null | undefined) =>
|
||
iso
|
||
? new Date(iso).toLocaleString(LOCALES[base.lang], { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' })
|
||
: '—',
|
||
};
|
||
}
|