Files
tg_tinder_bot/docs/LOCALIZATION_MIGRATION_PLAN.md
2025-11-24 17:00:20 +09:00

431 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# План замены хардкод-текстов на локализационные ключи
## Текущее состояние
**Реализовано:**
- Система локализации с 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<void> {
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
```
Удачи! 🚀