fix(i18n): русские сообщения валидации — lang/ru/validation.php
Accessibility (Pa11y live) / a11y (push) Has been cancelled
Accessibility (Pa11y live) / a11y (push) Has been cancelled
UI-аудит раунд 2: APP_LOCALE=ru, но директории lang/ не было → Laravel отдавал сырой ключ «validation.required» во все формы без кастомных messages() (профиль, создание проекта, реквизиты для оплаты и т.д.). Auth-формы свой messages() имеют. Добавлен каноничный ru-перевод (laravel-lang) + секция attributes с русскими именами полей продукта (Имя/Телефон/Лимит лидов в день/ИНН/…). Верификация: trans(validation.required)→«Поле … обязательно для заполнения.»; форма профиля в Playwright показывает «Поле Имя обязательно для заполнения.» вместо «validation.required». Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Русские сообщения валидации (UI-аудит 21.06.2026).
|
||||
*
|
||||
* Причина: APP_LOCALE=ru, но директории lang/ не было → Laravel отдавал сырой
|
||||
* ключ «validation.required» во все формы без кастомных messages() (профиль,
|
||||
* создание проекта и т.д.). Auth-формы свои messages() имеют — их не затрагивает.
|
||||
*
|
||||
* Базис — каноничный перевод laravel-lang/lang (ru).
|
||||
*/
|
||||
|
||||
return [
|
||||
'accepted' => 'Вы должны принять :attribute.',
|
||||
'accepted_if' => 'Вы должны принять :attribute, когда :other равно :value.',
|
||||
'active_url' => 'Поле :attribute содержит недействительный URL.',
|
||||
'after' => 'Поле :attribute должно содержать дату после :date.',
|
||||
'after_or_equal' => 'Поле :attribute должно содержать дату не раньше :date.',
|
||||
'alpha' => 'Поле :attribute может содержать только буквы.',
|
||||
'alpha_dash' => 'Поле :attribute может содержать только буквы, цифры, дефис и нижнее подчёркивание.',
|
||||
'alpha_num' => 'Поле :attribute может содержать только буквы и цифры.',
|
||||
'array' => 'Поле :attribute должно быть массивом.',
|
||||
'ascii' => 'Поле :attribute может содержать только однобайтовые буквенно-цифровые символы.',
|
||||
'before' => 'Поле :attribute должно содержать дату до :date.',
|
||||
'before_or_equal' => 'Поле :attribute должно содержать дату не позже :date.',
|
||||
'between' => [
|
||||
'array' => 'Количество элементов в поле :attribute должно быть от :min до :max.',
|
||||
'file' => 'Размер файла в поле :attribute должен быть от :min до :max Кбайт.',
|
||||
'numeric' => 'Поле :attribute должно быть от :min до :max.',
|
||||
'string' => 'Количество символов в поле :attribute должно быть от :min до :max.',
|
||||
],
|
||||
'boolean' => 'Поле :attribute должно иметь значение логического типа.',
|
||||
'can' => 'Поле :attribute содержит недопустимое значение.',
|
||||
'confirmed' => 'Поле :attribute не совпадает с подтверждением.',
|
||||
'current_password' => 'Неверный пароль.',
|
||||
'date' => 'Поле :attribute не является датой.',
|
||||
'date_equals' => 'Поле :attribute должно содержать дату, равную :date.',
|
||||
'date_format' => 'Поле :attribute не соответствует формату :format.',
|
||||
'decimal' => 'Поле :attribute должно иметь :decimal знаков после запятой.',
|
||||
'declined' => 'Поле :attribute должно быть отклонено.',
|
||||
'declined_if' => 'Поле :attribute должно быть отклонено, когда :other равно :value.',
|
||||
'different' => 'Поля :attribute и :other должны различаться.',
|
||||
'digits' => 'Длина цифрового поля :attribute должна быть :digits.',
|
||||
'digits_between' => 'Длина цифрового поля :attribute должна быть от :min до :max.',
|
||||
'dimensions' => 'Поле :attribute имеет недопустимые размеры изображения.',
|
||||
'distinct' => 'Поле :attribute содержит повторяющееся значение.',
|
||||
'doesnt_end_with' => 'Поле :attribute не должно заканчиваться одним из следующих значений: :values.',
|
||||
'doesnt_start_with' => 'Поле :attribute не должно начинаться с одного из следующих значений: :values.',
|
||||
'email' => 'Поле :attribute должно быть действительным электронным адресом.',
|
||||
'ends_with' => 'Поле :attribute должно заканчиваться одним из следующих значений: :values.',
|
||||
'enum' => 'Выбранное значение для :attribute некорректно.',
|
||||
'exists' => 'Выбранное значение для :attribute некорректно.',
|
||||
'extensions' => 'Поле :attribute должно иметь одно из следующих расширений: :values.',
|
||||
'file' => 'Поле :attribute должно быть файлом.',
|
||||
'filled' => 'Поле :attribute обязательно для заполнения.',
|
||||
'gt' => [
|
||||
'array' => 'Количество элементов в поле :attribute должно быть больше :value.',
|
||||
'file' => 'Размер файла в поле :attribute должен быть больше :value Кбайт.',
|
||||
'numeric' => 'Поле :attribute должно быть больше :value.',
|
||||
'string' => 'Количество символов в поле :attribute должно быть больше :value.',
|
||||
],
|
||||
'gte' => [
|
||||
'array' => 'Количество элементов в поле :attribute должно быть не меньше :value.',
|
||||
'file' => 'Размер файла в поле :attribute должен быть не меньше :value Кбайт.',
|
||||
'numeric' => 'Поле :attribute должно быть не меньше :value.',
|
||||
'string' => 'Количество символов в поле :attribute должно быть не меньше :value.',
|
||||
],
|
||||
'hex_color' => 'Поле :attribute должно содержать корректный шестнадцатеричный цвет.',
|
||||
'image' => 'Поле :attribute должно быть изображением.',
|
||||
'in' => 'Выбранное значение для :attribute некорректно.',
|
||||
'in_array' => 'Поле :attribute должно существовать в :other.',
|
||||
'integer' => 'Поле :attribute должно быть целым числом.',
|
||||
'ip' => 'Поле :attribute должно быть действительным IP-адресом.',
|
||||
'ipv4' => 'Поле :attribute должно быть действительным IPv4-адресом.',
|
||||
'ipv6' => 'Поле :attribute должно быть действительным IPv6-адресом.',
|
||||
'json' => 'Поле :attribute должно быть JSON-строкой.',
|
||||
'lowercase' => 'Поле :attribute должно быть в нижнем регистре.',
|
||||
'lt' => [
|
||||
'array' => 'Количество элементов в поле :attribute должно быть меньше :value.',
|
||||
'file' => 'Размер файла в поле :attribute должен быть меньше :value Кбайт.',
|
||||
'numeric' => 'Поле :attribute должно быть меньше :value.',
|
||||
'string' => 'Количество символов в поле :attribute должно быть меньше :value.',
|
||||
],
|
||||
'lte' => [
|
||||
'array' => 'Количество элементов в поле :attribute должно быть не больше :value.',
|
||||
'file' => 'Размер файла в поле :attribute должен быть не больше :value Кбайт.',
|
||||
'numeric' => 'Поле :attribute должно быть не больше :value.',
|
||||
'string' => 'Количество символов в поле :attribute должно быть не больше :value.',
|
||||
],
|
||||
'mac_address' => 'Поле :attribute должно быть корректным MAC-адресом.',
|
||||
'max' => [
|
||||
'array' => 'Количество элементов в поле :attribute не может превышать :max.',
|
||||
'file' => 'Размер файла в поле :attribute не может быть больше :max Кбайт.',
|
||||
'numeric' => 'Поле :attribute не может быть больше :max.',
|
||||
'string' => 'Количество символов в поле :attribute не может превышать :max.',
|
||||
],
|
||||
'max_digits' => 'Поле :attribute не должно содержать более :max цифр.',
|
||||
'mimes' => 'Поле :attribute должно быть файлом одного из типов: :values.',
|
||||
'mimetypes' => 'Поле :attribute должно быть файлом одного из типов: :values.',
|
||||
'min' => [
|
||||
'array' => 'Количество элементов в поле :attribute должно быть не меньше :min.',
|
||||
'file' => 'Размер файла в поле :attribute должен быть не меньше :min Кбайт.',
|
||||
'numeric' => 'Поле :attribute должно быть не меньше :min.',
|
||||
'string' => 'Количество символов в поле :attribute должно быть не меньше :min.',
|
||||
],
|
||||
'min_digits' => 'Поле :attribute должно содержать не менее :min цифр.',
|
||||
'missing' => 'Поле :attribute должно отсутствовать.',
|
||||
'missing_if' => 'Поле :attribute должно отсутствовать, когда :other равно :value.',
|
||||
'missing_unless' => 'Поле :attribute должно отсутствовать, если :other не равно :value.',
|
||||
'missing_with' => 'Поле :attribute должно отсутствовать, когда :values присутствует.',
|
||||
'missing_with_all' => 'Поле :attribute должно отсутствовать, когда :values присутствуют.',
|
||||
'multiple_of' => 'Поле :attribute должно быть кратным :value.',
|
||||
'not_in' => 'Выбранное значение для :attribute некорректно.',
|
||||
'not_regex' => 'Поле :attribute имеет некорректный формат.',
|
||||
'numeric' => 'Поле :attribute должно быть числом.',
|
||||
'password' => [
|
||||
'letters' => 'Поле :attribute должно содержать хотя бы одну букву.',
|
||||
'mixed' => 'Поле :attribute должно содержать буквы верхнего и нижнего регистра.',
|
||||
'numbers' => 'Поле :attribute должно содержать хотя бы одну цифру.',
|
||||
'symbols' => 'Поле :attribute должно содержать хотя бы один символ.',
|
||||
'uncompromised' => 'Указанное значение :attribute было найдено в утечке данных. Пожалуйста, выберите другое значение :attribute.',
|
||||
],
|
||||
'present' => 'Поле :attribute должно присутствовать.',
|
||||
'present_if' => 'Поле :attribute должно присутствовать, когда :other равно :value.',
|
||||
'present_unless' => 'Поле :attribute должно присутствовать, если :other не равно :value.',
|
||||
'present_with' => 'Поле :attribute должно присутствовать, когда :values присутствует.',
|
||||
'present_with_all' => 'Поле :attribute должно присутствовать, когда :values присутствуют.',
|
||||
'prohibited' => 'Поле :attribute запрещено.',
|
||||
'prohibited_if' => 'Поле :attribute запрещено, когда :other равно :value.',
|
||||
'prohibited_unless' => 'Поле :attribute запрещено, если :other не входит в :values.',
|
||||
'prohibits' => 'Поле :attribute запрещает присутствие :other.',
|
||||
'regex' => 'Поле :attribute имеет некорректный формат.',
|
||||
'required' => 'Поле :attribute обязательно для заполнения.',
|
||||
'required_array_keys' => 'Поле :attribute должно содержать записи для: :values.',
|
||||
'required_if' => 'Поле :attribute обязательно для заполнения, когда :other равно :value.',
|
||||
'required_if_accepted' => 'Поле :attribute обязательно для заполнения, когда :other принято.',
|
||||
'required_unless' => 'Поле :attribute обязательно для заполнения, когда :other не входит в :values.',
|
||||
'required_with' => 'Поле :attribute обязательно для заполнения, когда :values указано.',
|
||||
'required_with_all' => 'Поле :attribute обязательно для заполнения, когда :values указаны.',
|
||||
'required_without' => 'Поле :attribute обязательно для заполнения, когда :values не указано.',
|
||||
'required_without_all' => 'Поле :attribute обязательно для заполнения, когда ни одно из :values не указано.',
|
||||
'same' => 'Значение поля :attribute должно совпадать со значением :other.',
|
||||
'size' => [
|
||||
'array' => 'Количество элементов в поле :attribute должно быть равным :size.',
|
||||
'file' => 'Размер файла в поле :attribute должен быть равен :size Кбайт.',
|
||||
'numeric' => 'Поле :attribute должно быть равным :size.',
|
||||
'string' => 'Количество символов в поле :attribute должно быть равным :size.',
|
||||
],
|
||||
'starts_with' => 'Поле :attribute должно начинаться с одного из следующих значений: :values.',
|
||||
'string' => 'Поле :attribute должно быть строкой.',
|
||||
'timezone' => 'Поле :attribute должно содержать корректную временную зону.',
|
||||
'unique' => 'Такое значение поля :attribute уже существует.',
|
||||
'uploaded' => 'Загрузка поля :attribute не удалась.',
|
||||
'uppercase' => 'Поле :attribute должно быть в верхнем регистре.',
|
||||
'url' => 'Поле :attribute должно содержать корректный URL.',
|
||||
'ulid' => 'Поле :attribute должно содержать корректный ULID.',
|
||||
'uuid' => 'Поле :attribute должно содержать корректный UUID.',
|
||||
|
||||
/*
|
||||
| Кастомные сообщения для конкретных пар «атрибут.правило».
|
||||
*/
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
| Человекочитаемые имена полей (вместо сырых first_name и т.п.).
|
||||
*/
|
||||
'attributes' => [
|
||||
'first_name' => 'Имя',
|
||||
'last_name' => 'Фамилия',
|
||||
'name' => 'Название',
|
||||
'email' => 'Email',
|
||||
'phone' => 'Телефон',
|
||||
'password' => 'Пароль',
|
||||
'password_confirmation' => 'Подтверждение пароля',
|
||||
'timezone' => 'Тайм-зона',
|
||||
'comment' => 'Комментарий',
|
||||
'daily_limit' => 'Лимит лидов в день',
|
||||
'signal_identifier' => 'Источник',
|
||||
'signal_type' => 'Тип',
|
||||
'sms_senders' => 'Отправители',
|
||||
'sms_keyword' => 'Ключевое слово',
|
||||
'regions' => 'Регионы',
|
||||
'inn' => 'ИНН',
|
||||
'kpp' => 'КПП',
|
||||
'ogrn' => 'ОГРН',
|
||||
'ogrnip' => 'ОГРНИП',
|
||||
'legal_address' => 'Юридический адрес',
|
||||
'organization_name' => 'Название организации',
|
||||
'contact_name' => 'Контактное имя',
|
||||
'contact_phone' => 'Контактный телефон',
|
||||
'bank_name' => 'Наименование банка',
|
||||
'bik' => 'БИК',
|
||||
'account_number' => 'Расчётный счёт',
|
||||
'corr_account' => 'Корреспондентский счёт',
|
||||
'message' => 'Сообщение',
|
||||
'contact' => 'Контакт',
|
||||
],
|
||||
];
|
||||
+21
-22
@@ -1,6 +1,6 @@
|
||||
# Brain Status (auto-generated)
|
||||
|
||||
Last updated: 2026-06-21T01:43:28.079Z
|
||||
Last updated: 2026-06-21T11:34:36.544Z
|
||||
|
||||
| Контролёр | Состояние | Детали |
|
||||
|---|---|---|
|
||||
@@ -33,22 +33,29 @@ Last updated: 2026-06-21T01:43:28.079Z
|
||||
| enforce-coverage-verify.mjs | `enforce-coverage-verify.mjs` | 🔴 |
|
||||
| enforce-todowrite-skill-verifier.mjs | `enforce-todowrite-skill-verifier.mjs` | 🔴 |
|
||||
|
||||
Недавние escape владельца: 0 · Недавние блоки: 10
|
||||
Недавние escape владельца: 2 · Недавние блоки: 10
|
||||
|
||||
**Недавние escape владельца (детали):**
|
||||
|
||||
| Время | Действие | Причина |
|
||||
|---|---|---|
|
||||
| 2026-06-21T06:38:08.264Z | plan-done | escape владельца |
|
||||
| 2026-06-21T02:22:23.069Z | owner-seal:e0f8a7dad28f952f5f18bf323a26f82cabe9f7bd3fd45c8477773af19b8f1af1 | escape владельца |
|
||||
|
||||
**Недавние блоки (детали):**
|
||||
|
||||
| Время | Действие | Причина |
|
||||
|---|---|---|
|
||||
| 2026-06-21T01:43:31.680Z | powershell:$f = "$env:TEMP\claude-economy-07bce0ef-8004-4d79-a417-5c6315d3bbd4.json"; if (Test-Path $f) { Get-Content $f | разговорный режим: только думать/спрашивать (реализация — после печати артефакта и плана) |
|
||||
| 2026-06-21T01:43:28.478Z | write:c:/users/administrator/.claude/projects/c--------------claude-brain/07bce0ef-8004-4d79-a417-5c6315d3bbd4.jsonl | path «C:/Users/Administrator/.claude/projects/c--------------claude-brain/07bce0ef-8004-4d79-a417-5c6315d3bbd4.jsonl» pr |
|
||||
| 2026-06-21T01:43:23.370Z | bash:ls $TEMP/claude-economy-07bce0ef-8004-4d79-a417-5c6315d3bbd4.json 2>/dev/null && cat $TEMP/claude-economy-07bce0ef- | разговорный режим: только думать/спрашивать (реализация — после печати артефакта и плана) |
|
||||
| 2026-06-21T01:43:23.221Z | bash:ls $TEMP/claude-economy-07bce0ef-8004-4d79-a417-5c6315d3bbd4.json 2>/dev/null && cat $TEMP/claude-economy-07bce0ef- | floor: опасная по содержанию команда без аварийного выхода — блок (правило 8); FLOOR-ESCAPE: bash:ls $TEMP/claude-econom |
|
||||
| 2026-06-21T01:42:58.754Z | write:c:/моя/проекты/claude-brain | разговорный режим: только думать/спрашивать (реализация — после печати артефакта и плана) |
|
||||
| 2026-06-21T01:42:48.892Z | powershell:$path = "$env:TEMP\claude-economy-07bce0ef-8004-4d79-a417-5c6315d3bbd4.json"; if (Test-Path $path) { Get-Cont | разговорный режим: только думать/спрашивать (реализация — после печати артефакта и плана) |
|
||||
| 2026-06-21T01:42:45.501Z | bash:cat "$TEMP/claude-economy-07bce0ef-8004-4d79-a417-5c6315d3bbd4.json" 2>/dev/null \|\| echo "FILE_NOT_FOUND" | разговорный режим: только думать/спрашивать (реализация — после печати артефакта и плана) |
|
||||
| 2026-06-21T01:42:45.325Z | bash:cat "$TEMP/claude-economy-07bce0ef-8004-4d79-a417-5c6315d3bbd4.json" 2>/dev/null \|\| echo "FILE_NOT_FOUND" | floor: опасная по содержанию команда без аварийного выхода — блок (правило 8); FLOOR-ESCAPE: bash:cat "$TEMP/claude-econ |
|
||||
| 2026-06-21T01:42:41.095Z | write:c:/users/administrator/.claude/projects/c--------------claude-brain/07bce0ef-8004-4d79-a417-5c6315d3bbd4.jsonl | path «C:/Users/Administrator/.claude/projects/c--------------claude-brain/07bce0ef-8004-4d79-a417-5c6315d3bbd4.jsonl» pr |
|
||||
| 2026-06-21T01:37:32.150Z | write:c:/моя/проекты/claude-brain | разговорный режим: только думать/спрашивать (реализация — после печати артефакта и плана) |
|
||||
| 2026-06-21T11:20:27.250Z | write:c:/моя/проекты/claude-brain | разговорный режим: только думать/спрашивать (реализация — после печати артефакта и плана) |
|
||||
| 2026-06-21T11:20:18.178Z | write:c:/users/administrator/.claude/projects/c--------------claude-brain/dbbe0ee2-5c67-4b7f-87c5-7f47f8bd14bd.jsonl | path «C:/Users/Administrator/.claude/projects/c--------------claude-brain/dbbe0ee2-5c67-4b7f-87c5-7f47f8bd14bd.jsonl» pr |
|
||||
| 2026-06-21T11:20:10.771Z | bash:cat "$TEMP/claude-economy-dbbe0ee2-5c67-4b7f-87c5-7f47f8bd14bd.json" 2>/dev/null \|\| echo "FILE_NOT_FOUND" | разговорный режим: только думать/спрашивать (реализация — после печати артефакта и плана) |
|
||||
| 2026-06-21T11:20:10.641Z | bash:cat "$TEMP/claude-economy-dbbe0ee2-5c67-4b7f-87c5-7f47f8bd14bd.json" 2>/dev/null \|\| echo "FILE_NOT_FOUND" | floor: опасная по содержанию команда без аварийного выхода — блок (правило 8); FLOOR-ESCAPE: bash:cat "$TEMP/claude-econ |
|
||||
| 2026-06-21T11:19:59.051Z | write:c:/моя/проекты/claude-brain | разговорный режим: только думать/спрашивать (реализация — после печати артефакта и плана) |
|
||||
| 2026-06-21T11:19:48.786Z | write:c:/users/administrator/.claude/projects/c--------------claude-brain/dbbe0ee2-5c67-4b7f-87c5-7f47f8bd14bd.jsonl | path «C:/Users/Administrator/.claude/projects/c--------------claude-brain/dbbe0ee2-5c67-4b7f-87c5-7f47f8bd14bd.jsonl» pr |
|
||||
| 2026-06-21T11:19:43.736Z | bash:cat "$TEMP/claude-economy-dbbe0ee2-5c67-4b7f-87c5-7f47f8bd14bd.json" 2>/dev/null \|\| echo "FILE_NOT_FOUND" | разговорный режим: только думать/спрашивать (реализация — после печати артефакта и плана) |
|
||||
| 2026-06-21T11:19:43.631Z | bash:cat "$TEMP/claude-economy-dbbe0ee2-5c67-4b7f-87c5-7f47f8bd14bd.json" 2>/dev/null \|\| echo "FILE_NOT_FOUND" | floor: опасная по содержанию команда без аварийного выхода — блок (правило 8); FLOOR-ESCAPE: bash:cat "$TEMP/claude-econ |
|
||||
| 2026-06-21T11:10:44.290Z | write:c:/моя/проекты/claude-brain | разговорный режим: только думать/спрашивать (реализация — после печати артефакта и плана) |
|
||||
| 2026-06-21T11:10:36.250Z | bash:ls "$TEMP/claude-economy-dbbe0ee2-5c67-4b7f-87c5-7f47f8bd14bd.json" 2>/dev/null && cat "$TEMP/claude-economy-dbbe0e | разговорный режим: только думать/спрашивать (реализация — после печати артефакта и плана) |
|
||||
|
||||
## Метрики (информационные, не алерты)
|
||||
|
||||
@@ -128,15 +135,7 @@ Episodes since last run: 542 / threshold: 10
|
||||
|
||||
## System Health
|
||||
|
||||
Топ-3 процессов с CPU > 1ч:
|
||||
|
||||
| PID | Имя | CPU-время | Возраст |
|
||||
|---|---|---|---|
|
||||
| 3024 | Code | 4.90ч | 0.0ч |
|
||||
| 3260 | MsMpEng | 3.99ч | 0.0ч |
|
||||
| 1108 | svchost | 2.07ч | NaNч |
|
||||
|
||||
⚠️ Проверь, не «осиротевшие» ли это процессы от завершённых Claude-сессий.
|
||||
Долго работающих процессов нет (порог CPU > 1ч).
|
||||
|
||||
## Очередь обучения роутера
|
||||
|
||||
@@ -150,7 +149,7 @@ Episodes since last run: 542 / threshold: 10
|
||||
|
||||
## Целостность журналов действий
|
||||
|
||||
🔴 Битые цепочки (3 из 97):
|
||||
🔴 Битые цепочки (3 из 102):
|
||||
|
||||
| session | broken at seq |
|
||||
|---|---|
|
||||
|
||||
Reference in New Issue
Block a user