# План замены хардкод-текстов на локализационные ключи ## Текущее состояние ✅ **Реализовано:** - Система локализации с i18next - Выбор языка при первом запуске - 10 поддерживаемых языков - Сохранение языка в БД ⚠️ **Требуется:** - Извлечение и замена ~500+ хардкод-текстов в коде - Дополнение языковых файлов ## Стратегия замены ### Фаза 1: Критически важные пользовательские тексты (СНАЧАЛА) #### Приоритет: HIGH Файлы с наибольшим количеством пользовательских сообщений: 1. **src/handlers/messageHandlers.ts** (~150 текстов) - Создание профиля - Ввод данных (имя, возраст, город, био) - Валидация ввода - Сообщения об ошибках 2. **src/handlers/callbackHandlers.ts** (~200 текстов) - Кнопки меню - Просмотр профилей - Лайки/дислайки - Настройки профиля - VIP функции 3. **src/handlers/commandHandlers.ts** (~50 текстов) - Команды бота - Главное меню - Справка ### Фаза 2: Второстепенные тексты #### Приоритет: MEDIUM 4. **src/services/notificationService.ts** (~30 текстов) - Уведомления о лайках - Уведомления о матчах - Уведомления о сообщениях 5. **src/handlers/notificationHandlers.ts** (~20 текстов) - Настройки уведомлений ### Фаза 3: Служебные тексты #### Приоритет: LOW 6. **src/services/profileService.ts** (~10 текстов) - Сообщения об ошибках валидации 7. **src/services/matchingService.ts** (~5 текстов) - Логирование и отладка ## Процесс замены (пошаговый) ### Шаг 1: Анализ файла ```bash # Найти все хардкод-тексты grep -n "'[А-Яа-яЁё]" src/handlers/messageHandlers.ts grep -n '"[А-Яа-яЁё]' src/handlers/messageHandlers.ts ``` ### Шаг 2: Создание ключей локализации Для каждого найденного текста: 1. **Определить категорию:** - `profile.*` - профиль - `buttons.*` - кнопки - `errors.*` - ошибки - `messages.*` - сообщения - `commands.*` - команды - `search.*` - поиск - `matches.*` - матчи - `settings.*` - настройки - `notifications.*` - уведомления 2. **Создать понятный ключ:** ``` Плохо: "text1", "msg2" Хорошо: "profile.namePrompt", "errors.invalidAge" ``` 3. **Добавить в ru.json:** ```json { "profile": { "namePrompt": "👤 Введите ваше имя:", "agePrompt": "🎂 Сколько вам лет?", "cityPrompt": "🌍 В каком городе вы находитесь?" } } ``` ### Шаг 3: Замена в коде #### Было: ```typescript await bot.sendMessage(chatId, '👤 Введите ваше имя:'); ``` #### Стало: ```typescript const userId = msg.from?.id.toString(); const lang = await profileService.getUserLanguage(userId); localizationService.setLanguage(lang); await bot.sendMessage(chatId, localizationService.t('profile.namePrompt')); ``` #### Оптимизация (для методов класса): ```typescript // В начале метода private async sendLocalizedMessage( chatId: number, userId: string, key: string, options?: any ): Promise { const lang = await this.profileService.getUserLanguage(userId); this.localizationService.setLanguage(lang); const text = this.localizationService.t(key, options); await this.bot.sendMessage(chatId, text); } // Использование await this.sendLocalizedMessage(chatId, userId, 'profile.namePrompt'); ``` ### Шаг 4: Перевод на другие языки После добавления ключа в `ru.json`, добавить переводы: **en.json:** ```json { "profile": { "namePrompt": "👤 Enter your name:", "agePrompt": "🎂 How old are you?", "cityPrompt": "🌍 What city are you in?" } } ``` **ko.json:** ```json { "profile": { "namePrompt": "👤 이름을 입력하세요:", "agePrompt": "🎂 나이가 어떻게 되세요?", "cityPrompt": "🌍 어느 도시에 계세요?" } } ``` И так для всех 10 языков. ## Примеры типичных замен ### 1. Простое сообщение **Было:** ```typescript await bot.sendMessage(chatId, 'Анкеты закончились! Попробуйте позже.'); ``` **Стало:** ```typescript await bot.sendMessage(chatId, localizationService.t('search.noProfiles')); ``` ### 2. Сообщение с параметрами **Было:** ```typescript await bot.sendMessage(chatId, `Привет, ${name}! С возвращением!`); ``` **Стало:** ```json // ru.json { "welcome": { "greeting": "Привет, {{name}}! С возвращением!" } } ``` ```typescript await bot.sendMessage( chatId, localizationService.t('welcome.greeting', { name }) ); ``` ### 3. Кнопки **Было:** ```typescript const keyboard = { inline_keyboard: [ [{ text: '❤️ Нравится', callback_data: 'like' }], [{ text: '👎 Не нравится', callback_data: 'dislike' }] ] }; ``` **Стало:** ```json // ru.json { "buttons": { "like": "❤️ Нравится", "dislike": "👎 Не нравится" } } ``` ```typescript const keyboard = { inline_keyboard: [ [{ text: localizationService.t('buttons.like'), callback_data: 'like' }], [{ text: localizationService.t('buttons.dislike'), callback_data: 'dislike' }] ] }; ``` ### 4. Множественное число (плюрализация) **Было:** ```typescript const text = count === 1 ? `У вас ${count} новый матч` : `У вас ${count} новых матчей`; ``` **Стало:** ```json // ru.json { "matches": { "newCount_one": "У вас {{count}} новый матч", "newCount_few": "У вас {{count}} новых матча", "newCount_many": "У вас {{count}} новых матчей" } } ``` ```typescript await bot.sendMessage( chatId, localizationService.t('matches.newCount', { count }) ); ``` ## Инструменты для автоматизации ### Скрипт поиска хардкод-текстов ```bash #!/bin/bash # find_hardcoded_texts.sh echo "Поиск русских текстов в кавычках..." grep -rn "'[А-Яа-яЁё]" src/ --include="*.ts" | wc -l grep -rn '"[А-Яа-яЁё]' src/ --include="*.ts" | wc -l echo "Топ-10 файлов с наибольшим количеством хардкода:" grep -rn "'[А-Яа-яЁё]\|\"[А-Яа-яЁё]" src/ --include="*.ts" | \ cut -d: -f1 | \ sort | \ uniq -c | \ sort -rn | \ head -10 ``` ### Скрипт проверки покрытия переводами ```typescript // scripts/check-translations.ts import * as fs from 'fs'; import * as path from 'path'; const localesPath = path.join(__dirname, '..', 'src', 'locales'); const ruFile = JSON.parse(fs.readFileSync(path.join(localesPath, 'ru.json'), 'utf8')); function getAllKeys(obj: any, prefix = ''): string[] { let keys: string[] = []; for (const key in obj) { const fullKey = prefix ? `${prefix}.${key}` : key; if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) { keys = keys.concat(getAllKeys(obj[key], fullKey)); } else { keys.push(fullKey); } } return keys; } const ruKeys = getAllKeys(ruFile); const languages = ['en', 'es', 'fr', 'de', 'it', 'pt', 'zh', 'ja', 'ko']; languages.forEach(lang => { const langFile = JSON.parse(fs.readFileSync(path.join(localesPath, `${lang}.json`), 'utf8')); const langKeys = getAllKeys(langFile); const missing = ruKeys.filter(key => !langKeys.includes(key)); console.log(`\n${lang}.json:`); console.log(` Всего ключей: ${langKeys.length}/${ruKeys.length}`); if (missing.length > 0) { console.log(` Отсутствуют: ${missing.length}`); console.log(` Пример: ${missing.slice(0, 5).join(', ')}`); } else { console.log(` ✅ Все ключи присутствуют`); } }); ``` ## Контрольный список (Checklist) ### Перед началом замены файла: - [ ] Сделать backup файла или создать новую ветку в Git - [ ] Прочитать весь файл, понять структуру - [ ] Составить список всех текстов для замены ### В процессе замены: - [ ] Заменять по 10-20 текстов за раз - [ ] Тестировать после каждой замены - [ ] Проверять TypeScript ошибки: `npm run build` - [ ] Коммитить изменения: `git commit -m "localize: messageHandlers profile section"` ### После замены файла: - [ ] Убедиться, что нет TypeScript ошибок - [ ] Протестировать все функции файла в боте - [ ] Обновить переводы для всех 10 языков - [ ] Запустить скрипт проверки покрытия - [ ] Создать Pull Request для review ## Рекомендации 1. **Начинайте с самого используемого функционала:** - Регистрация (messageHandlers.ts - createProfile) - Просмотр анкет (callbackHandlers.ts - showNextCandidate) - Главное меню (commandHandlers.ts - handleStart) 2. **Группируйте ключи логически:** ```json { "profile": { "prompts": { "name": "...", "age": "...", "city": "..." }, "validation": { "nameLength": "...", "ageRange": "...", "cityRequired": "..." } } } ``` 3. **Используйте консистентную нотацию:** - Всегда camelCase для ключей - Всегда точки для разделения уровней - Prefix для категории (profile, button, error) 4. **Не переводите:** - Технические логи - Callback_data значения - Имена переменных и функций 5. **Делайте переводы качественными:** - Нанимайте native speakers для перевода - Используйте контекст культуры (эмодзи, формальность) - Учитывайте длину текста (для кнопок) ## Оценка объема работ ### Время на замену (приблизительно): - **messageHandlers.ts**: 4-6 часов - **callbackHandlers.ts**: 6-8 часов - **commandHandlers.ts**: 2-3 часа - **notificationService.ts**: 1-2 часа - **Прочие файлы**: 2-3 часа **Итого на замену:** ~15-22 часа ### Время на переводы: - **1 язык (native speaker)**: 2-3 часа - **9 языков**: 18-27 часов **ОБЩИЙ ОБЪЕМ:** ~33-49 часов ## Следующий шаг Начните с файла **src/handlers/messageHandlers.ts**, секция создания профиля: ```bash # Создайте ветку для работы git checkout -b localization-phase1-message-handlers # Начните замену code src/handlers/messageHandlers.ts ``` Удачи! 🚀