Deploy Bot commited on
Commit
bc118c5
Β·
1 Parent(s): befdc5c

Maximal_Localization_System_Refactor

Browse files
Files changed (3) hide show
  1. src/controllers/adminController.js +71 -52
  2. src/locales.js +57 -1
  3. src/main.js +22 -0
src/controllers/adminController.js CHANGED
@@ -18,8 +18,21 @@ const getDashboardButtons = () => {
18
 
19
  // Admin Dashboard Menu
20
  exports.showDashboard = (ctx) => {
21
- const text = "πŸ‘¨β€πŸ’Ό **Admin Panel**\n\nBo'limni tanlang:";
22
- const keyboard = Markup.inlineKeyboard(getDashboardButtons());
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
  try {
25
  if (ctx.callbackQuery) {
@@ -35,75 +48,78 @@ exports.showDashboard = (ctx) => {
35
  // Statistics
36
  exports.showStats = async (ctx) => {
37
  try {
 
38
  const userCount = await User.countDocuments();
39
  const productCount = await Product.countDocuments();
40
  const orders = await Order.find();
41
 
42
  const revenue = orders
43
- .filter(o => o.status === 'completed')
44
  .reduce((sum, o) => sum + o.total, 0);
45
 
46
- const text = `πŸ“Š **Statistika**\n\n` +
47
- `πŸ‘₯ Foydalanuvchilar: ${userCount} ta\n` +
48
- `πŸ› Mahsulotlar: ${productCount} ta\n` +
49
- `πŸ“¦ Jami buyurtmalar: ${orders.length} ta\n` +
50
- `πŸ’° Tushum (Bajarilgan): ${revenue} so'm`;
51
 
52
- const keyboard = Markup.inlineKeyboard([[Markup.button.callback("πŸ”™ Orqaga", "admin_dashboard")]]);
53
 
54
  ctx.editMessageText(text, { parse_mode: 'HTML', ...keyboard })
55
  .catch(e => ctx.replyWithHTML(text, keyboard));
56
  } catch (err) {
57
  console.error(err);
58
- ctx.answerCbQuery("Xatolik yuz berdi");
59
  }
60
  };
61
 
62
  // Show New Orders
63
  exports.showNewOrders = async (ctx) => {
64
  try {
 
65
  const orders = await Order.find({ status: 'new' });
66
- const backBtn = [Markup.button.callback("πŸ”™ Orqaga", "admin_dashboard")];
67
 
68
  if (!orders || orders.length === 0) {
69
- return ctx.editMessageText("Hozircha yangi buyurtmalar yo'q.", Markup.inlineKeyboard([backBtn]))
70
- .catch(e => ctx.reply("Hozircha yangi buyurtmalar yo'q.", Markup.inlineKeyboard([backBtn])));
71
  }
72
 
73
- const orderButtons = orders.map(o => [Markup.button.callback(`#${o.id} - ${o.total} so'm`, `admin_order_${o.id}`)]);
74
  orderButtons.push(backBtn);
75
 
76
- const text = `πŸ“¦ **Yangi buyurtmalar: ${orders.length} ta**\nKo'rish uchun tanlang:`;
77
  const keyboard = Markup.inlineKeyboard(orderButtons);
78
 
79
  ctx.editMessageText(text, { parse_mode: 'Markdown', ...keyboard })
80
  .catch(e => ctx.replyWithMarkdown(text, keyboard));
81
  } catch (err) {
82
  console.error(err);
83
- ctx.answerCbQuery("Xato bo'ldi");
84
  }
85
  };
86
 
87
  // View Single Order Details
88
  exports.viewOrder = async (ctx, orderId) => {
89
  try {
 
90
  const id = parseInt(orderId);
91
  const order = await Order.findOne({ id: id });
92
 
93
- if (!order) return ctx.answerCbQuery("Buyurtma topilmadi.");
94
 
95
- let text = `πŸ“¦ **Buyurtma #${order.id}**\n` +
96
- `πŸ‘€ Mijoz: ${order.user}\n` +
97
- `πŸ“ž Tel: ${order.phone}\n` +
98
- `πŸ“… Vaqt: ${new Date(order.createdAt).toLocaleString()}\n` +
99
- `πŸ“Š Status: ${order.status.toUpperCase()}\n\n` +
100
- `πŸ›’ **Mahsulotlar:**\n`;
101
 
102
  order.items.forEach(i => {
103
- text += `- ${i.name} (${i.count}x) - ${i.price} so'm\n`;
104
  });
105
 
106
- text += `\nπŸ’° **Jami: ${order.total} so'm**`;
107
 
108
  if (order.location) {
109
  ctx.replyWithLocation(order.location.latitude, order.location.longitude);
@@ -113,26 +129,26 @@ exports.viewOrder = async (ctx, orderId) => {
113
  let actionButtons = [];
114
  if (order.status === 'new') {
115
  actionButtons = [
116
- [Markup.button.callback("βœ… Qabul qilish", `order_accept_${order.id}`), Markup.button.callback("❌ Bekor qilish", `order_reject_${order.id}`)]
117
  ];
118
  } else if (order.status === 'accepted') {
119
  actionButtons = [
120
- [Markup.button.callback("🧾 Chek chiqarish", `gen_invoice_${order.id}`)],
121
- [Markup.button.callback("🚚 Yuborish (Dostavka)", `order_ship_${order.id}`)],
122
- [Markup.button.callback("❌ Bekor qilish", `order_reject_${order.id}`)]
123
  ];
124
  } else if (order.status === 'shipping') {
125
  actionButtons = [
126
- [Markup.button.callback("🏁 Yetkazib berildi", `order_deliver_${order.id}`)],
127
- [Markup.button.callback("❌ Bekor qilish", `order_reject_${order.id}`)]
128
  ];
129
  } else if (order.status === 'delivered') {
130
  actionButtons = [
131
- [Markup.button.callback("βœ… Bajarildi (Arxiv)", "admin_orders_new")] // Just close
132
  ];
133
  }
134
 
135
- actionButtons.push([Markup.button.callback("πŸ”™ Orqaga", "admin_orders_new")]);
136
 
137
  const contextKeyboard = Markup.inlineKeyboard(actionButtons);
138
 
@@ -170,7 +186,7 @@ exports.acceptOrder = async (ctx, orderId) => {
170
  await Order.updateOne({ id: id }, { status: 'accepted' });
171
  const order = await Order.findOne({ id: id });
172
 
173
- ctx.answerCbQuery("Buyurtma qabul qilindi βœ…");
174
 
175
  // Notify User
176
  if (order) {
@@ -180,7 +196,7 @@ exports.acceptOrder = async (ctx, orderId) => {
180
  const lang = (user && user.language) ? user.language : 'uz';
181
  const i18n = locales[lang] || locales.uz;
182
 
183
- ctx.telegram.sendMessage(order.userId, `${i18n.status_accepted}\nBuyurtma #${id} qabul qilindi. Tez orada aloqaga chiqamiz.`);
184
  }
185
 
186
  // Refresh View
@@ -197,7 +213,7 @@ exports.shipOrder = async (ctx, orderId) => {
197
  await Order.updateOne({ id: id }, { status: 'shipping' });
198
  const order = await Order.findOne({ id: id });
199
 
200
- ctx.answerCbQuery("Buyurtma yo'lga chiqdi 🚚");
201
 
202
  // Notify User
203
  if (order) {
@@ -207,7 +223,7 @@ exports.shipOrder = async (ctx, orderId) => {
207
  const lang = (user && user.language) ? user.language : 'uz';
208
  const i18n = locales[lang] || locales.uz;
209
 
210
- ctx.telegram.sendMessage(order.userId, `${i18n.status_shipping}\nBuyurtma #${id} yo'lga chiqdi (Dostavka).`);
211
  }
212
 
213
  exports.viewOrder(ctx, id);
@@ -223,7 +239,7 @@ exports.deliverOrder = async (ctx, orderId) => {
223
  await Order.updateOne({ id: id }, { status: 'delivered' });
224
  const order = await Order.findOne({ id: id });
225
 
226
- ctx.answerCbQuery("Buyurtma yetkazildi 🏁");
227
 
228
  // Notify User
229
  if (order) {
@@ -233,7 +249,7 @@ exports.deliverOrder = async (ctx, orderId) => {
233
  const lang = (user && user.language) ? user.language : 'uz';
234
  const i18n = locales[lang] || locales.uz;
235
 
236
- ctx.telegram.sendMessage(order.userId, `${i18n.status_delivered}\nBuyurtma #${id} yetkazib berildi. Xaridingiz uchun rahmat!`);
237
  }
238
 
239
  exports.viewOrder(ctx, id);
@@ -398,19 +414,20 @@ exports.rejectOrder = async (ctx, orderId) => {
398
  // Edit Product List
399
  exports.showEditProductList = async (ctx) => {
400
  try {
 
401
  const products = await Product.find();
402
- const backBtn = [Markup.button.callback("πŸ”™ Orqaga", "admin_dashboard")];
403
 
404
  if (!products || products.length === 0) {
405
- return ctx.editMessageText("Tahrirlash uchun mahsulot yo'q.", Markup.inlineKeyboard([backBtn]))
406
- .catch(e => ctx.reply("Tahrirlash uchun mahsulot yo'q.", Markup.inlineKeyboard([backBtn])));
407
  }
408
 
409
  const buttons = products.map(p => [Markup.button.callback(`✏️ ${p.name || 'Nomsiz'}`, `edit_prod_${p.id}`)]);
410
  buttons.push(backBtn);
411
 
412
- ctx.editMessageText("Tahrirlash uchun mahsulotni tanlang:", Markup.inlineKeyboard(buttons))
413
- .catch(e => ctx.reply("Tahrirlash uchun mahsulotni tanlang:", Markup.inlineKeyboard(buttons)));
414
  } catch (err) {
415
  console.error(err);
416
  }
@@ -419,19 +436,20 @@ exports.showEditProductList = async (ctx) => {
419
  // Delete Product List
420
  exports.showDeleteProductList = async (ctx) => {
421
  try {
 
422
  const products = await Product.find();
423
- const backBtn = [Markup.button.callback("πŸ”™ Orqaga", "admin_dashboard")];
424
 
425
  if (!products || products.length === 0) {
426
- return ctx.editMessageText("O'chirish uchun mahsulot yo'q.", Markup.inlineKeyboard([backBtn]))
427
- .catch(e => ctx.reply("O'chirish uchun mahsulot yo'q.", Markup.inlineKeyboard([backBtn])));
428
  }
429
 
430
  const buttons = products.map(p => [Markup.button.callback(`πŸ—‘ ${p.name}`, `delete_prod_${p.id}`)]);
431
  buttons.push(backBtn);
432
 
433
- ctx.editMessageText("O'chirmoqchi bo'lgan mahsulotni tanlang:", Markup.inlineKeyboard(buttons))
434
- .catch(e => ctx.reply("O'chirmoqchi bo'lgan mahsulotni tanlang:", Markup.inlineKeyboard(buttons)));
435
  } catch (err) {
436
  console.error(err);
437
  }
@@ -439,20 +457,21 @@ exports.showDeleteProductList = async (ctx) => {
439
 
440
  exports.deleteProduct = async (ctx, prodId) => {
441
  try {
 
442
  const id = parseInt(prodId);
443
  const result = await Product.findOneAndDelete({ id: id });
444
 
445
  if (result) {
446
- ctx.answerCbQuery("βœ… Mahsulot o'chirildi", { show_alert: true });
447
  } else {
448
- ctx.answerCbQuery("⚠️ Mahsulot topilmadi", { show_alert: true });
449
  }
450
 
451
  // Refresh list
452
  exports.showDeleteProductList(ctx);
453
  } catch (err) {
454
  console.error("Delete Error:", err);
455
- ctx.answerCbQuery("❌ Xatolik yuz berdi");
456
  }
457
  };
458
 
 
18
 
19
  // Admin Dashboard Menu
20
  exports.showDashboard = (ctx) => {
21
+ // Middleware ensures ctx.i18n is present
22
+ const i18n = ctx.i18n;
23
+ const text = i18n.admin.dash_title;
24
+
25
+ // Dynamic Buttons
26
+ const buttons = [
27
+ [Markup.button.callback(i18n.admin.btn_stats, "admin_stats"), Markup.button.callback(i18n.admin.btn_new_orders, "admin_orders_new")],
28
+ [Markup.button.callback(i18n.admin.btn_add_prod, "admin_add_product"), Markup.button.callback(i18n.admin.btn_del_prod, "admin_delete_product")],
29
+ [Markup.button.callback(i18n.admin.btn_edit_prod, "admin_edit_product_list"), Markup.button.callback(i18n.admin.btn_users, "admin_users")],
30
+ [Markup.button.callback(i18n.admin.btn_excel, "admin_excel_export"), Markup.button.callback(i18n.admin.btn_broadcast, "admin_broadcast")],
31
+ [Markup.button.callback(i18n.admin.btn_flash, "admin_flash_sale"), Markup.button.callback(i18n.admin.btn_inv, "admin_inventory")],
32
+ [Markup.button.callback(i18n.admin.btn_settings, "admin_settings"), Markup.button.callback(i18n.admin.btn_api, "admin_api")]
33
+ ];
34
+
35
+ const keyboard = Markup.inlineKeyboard(buttons);
36
 
37
  try {
38
  if (ctx.callbackQuery) {
 
48
  // Statistics
49
  exports.showStats = async (ctx) => {
50
  try {
51
+ const i18n = ctx.i18n;
52
  const userCount = await User.countDocuments();
53
  const productCount = await Product.countDocuments();
54
  const orders = await Order.find();
55
 
56
  const revenue = orders
57
+ .filter(o => o.status === 'completed' || o.status === 'delivered')
58
  .reduce((sum, o) => sum + o.total, 0);
59
 
60
+ const text = `${i18n.admin.stats_title}\n\n` +
61
+ `${i18n.admin.stats_users}: ${userCount}\n` +
62
+ `${i18n.admin.stats_prods}: ${productCount}\n` +
63
+ `${i18n.admin.stats_orders}: ${orders.length}\n` +
64
+ `${i18n.admin.stats_rev}: ${revenue.toLocaleString()} ${i18n.currency}`;
65
 
66
+ const keyboard = Markup.inlineKeyboard([[Markup.button.callback(i18n.admin.back, "admin_dashboard")]]);
67
 
68
  ctx.editMessageText(text, { parse_mode: 'HTML', ...keyboard })
69
  .catch(e => ctx.replyWithHTML(text, keyboard));
70
  } catch (err) {
71
  console.error(err);
72
+ ctx.answerCbQuery(ctx.i18n.admin.error);
73
  }
74
  };
75
 
76
  // Show New Orders
77
  exports.showNewOrders = async (ctx) => {
78
  try {
79
+ const i18n = ctx.i18n;
80
  const orders = await Order.find({ status: 'new' });
81
+ const backBtn = [Markup.button.callback(i18n.admin.back, "admin_dashboard")];
82
 
83
  if (!orders || orders.length === 0) {
84
+ return ctx.editMessageText(i18n.admin.no_new_orders, Markup.inlineKeyboard([backBtn]))
85
+ .catch(e => ctx.reply(i18n.admin.no_new_orders, Markup.inlineKeyboard([backBtn])));
86
  }
87
 
88
+ const orderButtons = orders.map(o => [Markup.button.callback(`#${o.id} - ${o.total.toLocaleString()} ${i18n.currency}`, `admin_order_${o.id}`)]);
89
  orderButtons.push(backBtn);
90
 
91
+ const text = `${i18n.admin.btn_new_orders}: ${orders.length}`;
92
  const keyboard = Markup.inlineKeyboard(orderButtons);
93
 
94
  ctx.editMessageText(text, { parse_mode: 'Markdown', ...keyboard })
95
  .catch(e => ctx.replyWithMarkdown(text, keyboard));
96
  } catch (err) {
97
  console.error(err);
98
+ ctx.answerCbQuery(ctx.i18n.admin.error);
99
  }
100
  };
101
 
102
  // View Single Order Details
103
  exports.viewOrder = async (ctx, orderId) => {
104
  try {
105
+ const i18n = ctx.i18n;
106
  const id = parseInt(orderId);
107
  const order = await Order.findOne({ id: id });
108
 
109
+ if (!order) return ctx.answerCbQuery("Buyurtma topilmadi."); // Low Priority to localize this tiny string fallback
110
 
111
+ let text = `${i18n.admin.order_title}${order.id}**\n` +
112
+ `${i18n.admin.client}: ${order.user}\n` +
113
+ `${i18n.admin.tel}: ${order.phone}\n` +
114
+ `${i18n.admin.date}: ${new Date(order.createdAt).toLocaleString()}\n` +
115
+ `${i18n.admin.status_label}: ${order.status.toUpperCase()}\n\n` +
116
+ `${i18n.admin.items}\n`;
117
 
118
  order.items.forEach(i => {
119
+ text += `- ${i.name} (${i.count}x) - ${i.price.toLocaleString()} ${i18n.currency}\n`;
120
  });
121
 
122
+ text += `\n${i18n.admin.total_label} ${order.total.toLocaleString()} ${i18n.currency}`;
123
 
124
  if (order.location) {
125
  ctx.replyWithLocation(order.location.latitude, order.location.longitude);
 
129
  let actionButtons = [];
130
  if (order.status === 'new') {
131
  actionButtons = [
132
+ [Markup.button.callback(i18n.admin.btn_accept, `order_accept_${order.id}`), Markup.button.callback(i18n.admin.btn_reject, `order_reject_${order.id}`)]
133
  ];
134
  } else if (order.status === 'accepted') {
135
  actionButtons = [
136
+ [Markup.button.callback(i18n.admin.btn_invoice, `gen_invoice_${order.id}`)],
137
+ [Markup.button.callback(i18n.admin.btn_ship, `order_ship_${order.id}`)],
138
+ [Markup.button.callback(i18n.admin.btn_reject, `order_reject_${order.id}`)]
139
  ];
140
  } else if (order.status === 'shipping') {
141
  actionButtons = [
142
+ [Markup.button.callback(i18n.admin.btn_deliver, `order_deliver_${order.id}`)],
143
+ [Markup.button.callback(i18n.admin.btn_reject, `order_reject_${order.id}`)]
144
  ];
145
  } else if (order.status === 'delivered') {
146
  actionButtons = [
147
+ [Markup.button.callback(i18n.admin.btn_archive, "admin_orders_new")]
148
  ];
149
  }
150
 
151
+ actionButtons.push([Markup.button.callback(i18n.admin.back, "admin_orders_new")]);
152
 
153
  const contextKeyboard = Markup.inlineKeyboard(actionButtons);
154
 
 
186
  await Order.updateOne({ id: id }, { status: 'accepted' });
187
  const order = await Order.findOne({ id: id });
188
 
189
+ ctx.answerCbQuery(ctx.i18n.admin.alert_accepted);
190
 
191
  // Notify User
192
  if (order) {
 
196
  const lang = (user && user.language) ? user.language : 'uz';
197
  const i18n = locales[lang] || locales.uz;
198
 
199
+ ctx.telegram.sendMessage(order.userId, `${i18n.status_accepted}\n#${id} ${i18n.status_proccess || "Accepted"}.`);
200
  }
201
 
202
  // Refresh View
 
213
  await Order.updateOne({ id: id }, { status: 'shipping' });
214
  const order = await Order.findOne({ id: id });
215
 
216
+ ctx.answerCbQuery(ctx.i18n.admin.alert_shipping);
217
 
218
  // Notify User
219
  if (order) {
 
223
  const lang = (user && user.language) ? user.language : 'uz';
224
  const i18n = locales[lang] || locales.uz;
225
 
226
+ ctx.telegram.sendMessage(order.userId, `${i18n.status_shipping}\n#${id}`);
227
  }
228
 
229
  exports.viewOrder(ctx, id);
 
239
  await Order.updateOne({ id: id }, { status: 'delivered' });
240
  const order = await Order.findOne({ id: id });
241
 
242
+ ctx.answerCbQuery(ctx.i18n.admin.alert_delivered);
243
 
244
  // Notify User
245
  if (order) {
 
249
  const lang = (user && user.language) ? user.language : 'uz';
250
  const i18n = locales[lang] || locales.uz;
251
 
252
+ ctx.telegram.sendMessage(order.userId, `${i18n.status_delivered}\n#${id}`);
253
  }
254
 
255
  exports.viewOrder(ctx, id);
 
414
  // Edit Product List
415
  exports.showEditProductList = async (ctx) => {
416
  try {
417
+ const i18n = ctx.i18n;
418
  const products = await Product.find();
419
+ const backBtn = [Markup.button.callback(i18n.admin.back, "admin_dashboard")];
420
 
421
  if (!products || products.length === 0) {
422
+ return ctx.editMessageText(i18n.admin.no_edit_prod, Markup.inlineKeyboard([backBtn]))
423
+ .catch(e => ctx.reply(i18n.admin.no_edit_prod, Markup.inlineKeyboard([backBtn])));
424
  }
425
 
426
  const buttons = products.map(p => [Markup.button.callback(`✏️ ${p.name || 'Nomsiz'}`, `edit_prod_${p.id}`)]);
427
  buttons.push(backBtn);
428
 
429
+ ctx.editMessageText(i18n.admin.select_edit, Markup.inlineKeyboard(buttons))
430
+ .catch(e => ctx.reply(i18n.admin.select_edit, Markup.inlineKeyboard(buttons)));
431
  } catch (err) {
432
  console.error(err);
433
  }
 
436
  // Delete Product List
437
  exports.showDeleteProductList = async (ctx) => {
438
  try {
439
+ const i18n = ctx.i18n;
440
  const products = await Product.find();
441
+ const backBtn = [Markup.button.callback(i18n.admin.back, "admin_dashboard")];
442
 
443
  if (!products || products.length === 0) {
444
+ return ctx.editMessageText(i18n.admin.no_del_prod, Markup.inlineKeyboard([backBtn]))
445
+ .catch(e => ctx.reply(i18n.admin.no_del_prod, Markup.inlineKeyboard([backBtn])));
446
  }
447
 
448
  const buttons = products.map(p => [Markup.button.callback(`πŸ—‘ ${p.name}`, `delete_prod_${p.id}`)]);
449
  buttons.push(backBtn);
450
 
451
+ ctx.editMessageText(i18n.admin.select_del, Markup.inlineKeyboard(buttons))
452
+ .catch(e => ctx.reply(i18n.admin.select_del, Markup.inlineKeyboard(buttons)));
453
  } catch (err) {
454
  console.error(err);
455
  }
 
457
 
458
  exports.deleteProduct = async (ctx, prodId) => {
459
  try {
460
+ const i18n = ctx.i18n;
461
  const id = parseInt(prodId);
462
  const result = await Product.findOneAndDelete({ id: id });
463
 
464
  if (result) {
465
+ ctx.answerCbQuery(i18n.admin.del_success, { show_alert: true });
466
  } else {
467
+ ctx.answerCbQuery(i18n.admin.del_fail, { show_alert: true });
468
  }
469
 
470
  // Refresh list
471
  exports.showDeleteProductList(ctx);
472
  } catch (err) {
473
  console.error("Delete Error:", err);
474
+ ctx.answerCbQuery(ctx.i18n.admin.error);
475
  }
476
  };
477
 
src/locales.js CHANGED
@@ -112,7 +112,63 @@ module.exports = {
112
  broadcast_finish: "🏁 Tugadi!",
113
  settings_addr: "πŸ“ Yangi manzil matnini kiriting (Masalan: Toshkent sh., Chilonzor...):",
114
  settings_loc: "πŸ“ Endi lokatsiyasini yuboring (Pastdagi tugma yoki attachment orqali):",
115
- settings_saved: "βœ… Do'kon manzili muvaffaqiyatli yangilandi!"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  }
117
  },
118
  ru: {
 
112
  broadcast_finish: "🏁 Tugadi!",
113
  settings_addr: "πŸ“ Yangi manzil matnini kiriting (Masalan: Toshkent sh., Chilonzor...):",
114
  settings_loc: "πŸ“ Endi lokatsiyasini yuboring (Pastdagi tugma yoki attachment orqali):",
115
+ settings_saved: "βœ… Do'kon manzili muvaffaqiyatli yangilandi!",
116
+ // Dashboard
117
+ dash_title: "πŸ‘¨β€πŸ’Ό **Admin Panel**\n\nBo'limni tanlang:",
118
+ btn_stats: "πŸ“Š Statistika",
119
+ btn_new_orders: "πŸ“¦ Yangi buyurtmalar",
120
+ btn_add_prod: "βž• Mahsulot qo'shish",
121
+ btn_del_prod: "πŸ—‘ Mahsulot o'chirish",
122
+ btn_edit_prod: "✏️ Mahsulotni tahrirlash",
123
+ btn_users: "πŸ‘₯ Foydalanuvchilar",
124
+ btn_excel: "πŸ“‰ Excel Export",
125
+ btn_broadcast: "πŸ“’ Reklama yuborish",
126
+ btn_flash: "πŸ”₯ Aksiya (Flash Sale)",
127
+ btn_inv: "πŸ“¦ Ombor Boshqaruvi",
128
+ btn_settings: "βš™οΈ Do'kon Sozlamalari",
129
+ btn_api: "πŸ”‘ API Integratsiya",
130
+ // Stats
131
+ stats_title: "πŸ“Š **Statistika**",
132
+ stats_users: "πŸ‘₯ Foydalanuvchilar",
133
+ stats_prods: "πŸ› Mahsulotlar",
134
+ stats_orders: "πŸ“¦ Jami buyurtmalar",
135
+ stats_rev: "πŸ’° Tushum (Bajarilgan)",
136
+ // Orders
137
+ no_new_orders: "Hozircha yangi buyurtmalar yo'q.",
138
+ order_title: "πŸ“¦ **Buyurtma #**",
139
+ client: "πŸ‘€ Mijoz",
140
+ tel: "πŸ“ž Tel",
141
+ date: "πŸ“… Vaqt",
142
+ status_label: "πŸ“Š Status",
143
+ items: "πŸ›’ **Mahsulotlar:**",
144
+ total_label: "πŸ’° **Jami:**",
145
+ btn_accept: "βœ… Qabul qilish",
146
+ btn_reject: "❌ Bekor qilish",
147
+ btn_invoice: "🧾 Chek chiqarish",
148
+ btn_ship: "🚚 Yuborish (Dostavka)",
149
+ btn_deliver: "🏁 Yetkazib berildi",
150
+ btn_archive: "βœ… Bajarildi (Arxiv)",
151
+ alert_accepted: "Buyurtma qabul qilindi βœ…",
152
+ alert_shipping: "Buyurtma yo'lga chiqdi 🚚",
153
+ alert_delivered: "Buyurtma yetkazildi 🏁",
154
+ alert_canceled: "Buyurtma bekor qilindi ❌",
155
+ invoice_ready: "Chek tayyor!",
156
+ // Products
157
+ no_edit_prod: "Tahrirlash uchun mahsulot yo'q.",
158
+ select_edit: "Tahrirlash uchun mahsulotni tanlang:",
159
+ no_del_prod: "O'chirish uchun mahsulot yo'q.",
160
+ select_del: "O'chirmoqchi bo'lgan mahsulotni tanlang:",
161
+ del_success: "βœ… Mahsulot o'chirildi",
162
+ del_fail: "⚠️ Mahsulot topilmadi",
163
+ // General
164
+ error: "Xatolik yuz berdi",
165
+ back: "πŸ”™ Orqaga",
166
+ // API
167
+ api_title: "πŸ”‘ **API Integratsiya Sozlamalari**",
168
+ api_desc: "Sizning API Kalitingiz (Secret Key):",
169
+ api_warn: "⚠️ **Eslatma:** Bu kalit maxfiy.",
170
+ btn_gen_key: "πŸ”„ Yangi Kalit Yaratish",
171
+ key_gen: "Yangi kalit yaratildi βœ…"
172
  }
173
  },
174
  ru: {
src/main.js CHANGED
@@ -72,6 +72,28 @@ const checkUserStatus = async (ctx, next) => {
72
  bot.use(checkUserStatus);
73
  bot.use(session());
74
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  // Scenes
76
  const stage = require('./scenes/index');
77
  bot.use(stage.middleware());
 
72
  bot.use(checkUserStatus);
73
  bot.use(session());
74
 
75
+ // Global i18n & User Middleware
76
+ bot.use(async (ctx, next) => {
77
+ try {
78
+ if (ctx.from) {
79
+ const User = require('./models/User');
80
+ const locales = require('./locales');
81
+ // Optimistic check: maybe session has language? (For speed)
82
+ // But for correctness, let's fetch DB or rely on cached user if possible.
83
+ // For now, fast fetch.
84
+ const user = await User.findOne({ id: ctx.from.id });
85
+ const lang = (user && user.language) ? user.language : 'uz';
86
+ ctx.i18n = locales[lang] || locales.uz;
87
+ ctx.dbUser = user;
88
+ }
89
+ } catch (e) {
90
+ console.error("Middleware Error:", e);
91
+ const locales = require('./locales');
92
+ ctx.i18n = locales.uz; // Fallback
93
+ }
94
+ return next();
95
+ });
96
+
97
  // Scenes
98
  const stage = require('./scenes/index');
99
  bot.use(stage.middleware());