- Add i18n module with tForUser/tForLang/t functions and {{param}} interpolation
- Add 3 locale files: en.json, es.json, de.json (201 keys each)
- Add language selection on /start and /language command with flag emojis
- Localize all bot user-facing strings (handlers, keyboards, errors)
- Localize messageRouter keyboard matching via locale keys
- Add DB migrations 008 (language column) and 009 (language_set column)
- Add localization admin tab at /locales for editing translations
- Add userService.getUserLanguage/setUserLanguage methods
- Cache user object on msg.__user to avoid triple DB fetch
- Idempotent migrations with checkColumnExists guards
- Error boundary on i18n locale file loading
- Admin locales route uses AVAILABLE_LANGUAGES import
83 lines
2.8 KiB
JavaScript
83 lines
2.8 KiB
JavaScript
import 'dotenv/config';
|
|
import { runMigrations, cleanUpInvalidForeignKeys } from './migrations/runner.js';
|
|
import { registerRoutes } from './router/routes.js';
|
|
import bot, { botAvailable } from './context/bot.js';
|
|
import ErrorHandler from './utils/errorHandler.js';
|
|
import logger from './utils/logger.js';
|
|
import userHandler from './handlers/userHandlers/userHandler.js';
|
|
import adminHandler from './handlers/adminHandlers/adminHandler.js';
|
|
import callbackRouter from './router/callbackRouter.js';
|
|
import messageRouter from './router/messageRouter.js';
|
|
|
|
import { initStates } from './services/stateService.js';
|
|
|
|
await runMigrations();
|
|
await cleanUpInvalidForeignKeys();
|
|
await initStates();
|
|
registerRoutes();
|
|
|
|
if (bot && botAvailable) {
|
|
bot.onText(/\/start/, async (msg) => {
|
|
const canUse = await userHandler.canUseBot(msg);
|
|
if (!canUse) return;
|
|
try {
|
|
await userHandler.handleStart(msg);
|
|
} catch (error) {
|
|
await ErrorHandler.handleError(bot, msg.chat.id, error, 'start command');
|
|
}
|
|
});
|
|
|
|
bot.onText(/\/language/, async (msg) => {
|
|
try {
|
|
await userHandler.handleLanguageCommand(msg);
|
|
} catch (error) {
|
|
await ErrorHandler.handleError(bot, msg.chat.id, error, 'language command');
|
|
}
|
|
});
|
|
|
|
bot.onText(/\/admin/, async (msg) => {
|
|
try {
|
|
await adminHandler.handleAdminCommand(msg);
|
|
} catch (error) {
|
|
await ErrorHandler.handleError(bot, msg.chat.id, error, 'admin command');
|
|
}
|
|
});
|
|
|
|
bot.on('message', async (msg) => {
|
|
if (msg.text?.toLowerCase() === '/start') return;
|
|
const canUse = await userHandler.canUseBot(msg);
|
|
if (!canUse) return;
|
|
try {
|
|
await messageRouter.dispatch(msg);
|
|
} catch (error) {
|
|
await ErrorHandler.handleError(bot, msg.chat.id, error, 'message handler');
|
|
}
|
|
});
|
|
|
|
bot.on('callback_query', async (callbackQuery) => {
|
|
const canUse = await userHandler.canUseBot(callbackQuery);
|
|
if (!canUse) {
|
|
await bot.answerCallbackQuery(callbackQuery.id);
|
|
return;
|
|
}
|
|
try {
|
|
await callbackRouter.dispatch(callbackQuery);
|
|
await bot.answerCallbackQuery(callbackQuery.id);
|
|
} catch (error) {
|
|
await ErrorHandler.handleError(bot, callbackQuery.message.chat.id, error, 'callback query');
|
|
}
|
|
});
|
|
|
|
bot.on('polling_error', ErrorHandler.handlePollingError);
|
|
|
|
logger.info('Bot is running...');
|
|
} else {
|
|
logger.warn('Bot is not available. Running in admin-only mode. Admin panel will continue to work.');
|
|
}
|
|
|
|
process.on('unhandledRejection', (error) => {
|
|
logger.error({ err: error }, 'Unhandled promise rejection');
|
|
});
|
|
|
|
import { startAdminPanel } from './admin/server.js';
|
|
startAdminPanel(); |