@@ -165,6 +165,75 @@ def filter(self, record):
165
165
"port" : 3033 ,
166
166
}
167
167
168
+ # Month and weekday names for different languages to handle date formatting
169
+ # without relying on locale settings which might not be available in containers
170
+ MONTH_NAMES = {
171
+ "en" : [
172
+ "January" ,
173
+ "February" ,
174
+ "March" ,
175
+ "April" ,
176
+ "May" ,
177
+ "June" ,
178
+ "July" ,
179
+ "August" ,
180
+ "September" ,
181
+ "October" ,
182
+ "November" ,
183
+ "December" ,
184
+ ],
185
+ "de" : [
186
+ "Januar" ,
187
+ "Februar" ,
188
+ "März" ,
189
+ "April" ,
190
+ "Mai" ,
191
+ "Juni" ,
192
+ "Juli" ,
193
+ "August" ,
194
+ "September" ,
195
+ "Oktober" ,
196
+ "November" ,
197
+ "Dezember" ,
198
+ ],
199
+ "fr" : [
200
+ "janvier" ,
201
+ "février" ,
202
+ "mars" ,
203
+ "avril" ,
204
+ "mai" ,
205
+ "juin" ,
206
+ "juillet" ,
207
+ "août" ,
208
+ "septembre" ,
209
+ "octobre" ,
210
+ "novembre" ,
211
+ "décembre" ,
212
+ ],
213
+ }
214
+
215
+ WEEKDAY_NAMES = {
216
+ "en" : [
217
+ "Monday" ,
218
+ "Tuesday" ,
219
+ "Wednesday" ,
220
+ "Thursday" ,
221
+ "Friday" ,
222
+ "Saturday" ,
223
+ "Sunday" ,
224
+ ],
225
+ "de" : [
226
+ "Montag" ,
227
+ "Dienstag" ,
228
+ "Mittwoch" ,
229
+ "Donnerstag" ,
230
+ "Freitag" ,
231
+ "Samstag" ,
232
+ "Sonntag" ,
233
+ ],
234
+ "fr" : ["lundi" , "mardi" , "mercredi" , "jeudi" , "vendredi" , "samedi" , "dimanche" ],
235
+ }
236
+
168
237
169
238
class KofiWebhook (commands .Cog ):
170
239
def __init__ (self , bot ):
@@ -179,6 +248,11 @@ def __init__(self, bot):
179
248
# Load configuration
180
249
self .config = self .load_config ()
181
250
251
+ # Store the custom messages by language
252
+ self .custom_messages = {}
253
+ self .custom_footers = {}
254
+ self .load_custom_messages ()
255
+
182
256
# Log configuration
183
257
logger .info ("Ko-fi configuration loaded:" )
184
258
logger .info (f" → Ko-Fi Language: '{ self .config ['language' ]} '" )
@@ -192,6 +266,54 @@ def __init__(self, bot):
192
266
# Setup Flask routes
193
267
self .setup_routes ()
194
268
269
+ def load_custom_messages (self ):
270
+ """Load custom messages for different languages"""
271
+ try :
272
+ # Try to import regular custom message
273
+ from config .settings import KOFI_CUSTOM_MESSAGE , KOFI_CUSTOM_FOOTER
274
+
275
+ # Store the messages for all languages
276
+ for lang in TRANSLATIONS .keys ():
277
+ # If we have a language-specific message, use it, otherwise use the generic one
278
+ try :
279
+ # Try to import language-specific message (e.g. KOFI_CUSTOM_MESSAGE_DE)
280
+ specific_message_var = f"KOFI_CUSTOM_MESSAGE_{ lang .upper ()} "
281
+ specific_footer_var = f"KOFI_CUSTOM_FOOTER_{ lang .upper ()} "
282
+
283
+ # Import dynamically if exists
284
+ try :
285
+ specific_message = getattr (
286
+ __import__ (
287
+ "config.settings" , fromlist = [specific_message_var ]
288
+ ),
289
+ specific_message_var ,
290
+ )
291
+ self .custom_messages [lang ] = specific_message
292
+ except (ImportError , AttributeError ):
293
+ # If language-specific message doesn't exist, use generic one
294
+ if "KOFI_CUSTOM_MESSAGE" in locals () and KOFI_CUSTOM_MESSAGE :
295
+ self .custom_messages [lang ] = KOFI_CUSTOM_MESSAGE
296
+
297
+ # Same for footer
298
+ try :
299
+ specific_footer = getattr (
300
+ __import__ (
301
+ "config.settings" , fromlist = [specific_footer_var ]
302
+ ),
303
+ specific_footer_var ,
304
+ )
305
+ self .custom_footers [lang ] = specific_footer
306
+ except (ImportError , AttributeError ):
307
+ # If language-specific footer doesn't exist, use generic one
308
+ if "KOFI_CUSTOM_FOOTER" in locals () and KOFI_CUSTOM_FOOTER :
309
+ self .custom_footers [lang ] = KOFI_CUSTOM_FOOTER
310
+
311
+ except Exception as e :
312
+ logger .debug (f"Error loading specific message for { lang } : { e } " )
313
+
314
+ except ImportError :
315
+ logger .debug ("No custom Ko-fi messages found in settings" )
316
+
195
317
def configure_flask_logging (self ):
196
318
"""Configure Flask's logging to suppress common port scanning errors"""
197
319
# Suppress Flask/Werkzeug logging
@@ -220,8 +342,6 @@ def load_config(self):
220
342
from config .settings import (
221
343
KOFI_NAME ,
222
344
KOFI_LOGO ,
223
- KOFI_CUSTOM_MESSAGE ,
224
- KOFI_CUSTOM_FOOTER ,
225
345
)
226
346
227
347
# Load basic settings
@@ -230,18 +350,6 @@ def load_config(self):
230
350
if "KOFI_LOGO" in locals () and KOFI_LOGO :
231
351
config ["kofi_logo" ] = KOFI_LOGO
232
352
233
- # If custom messages are defined, override the translations
234
- if "KOFI_CUSTOM_MESSAGE" in locals () and KOFI_CUSTOM_MESSAGE :
235
- lang = config ["language" ]
236
- if lang in TRANSLATIONS :
237
- TRANSLATIONS [lang ]["CustomMessage" ] = KOFI_CUSTOM_MESSAGE
238
-
239
- # If custom footer is defined, override the translations
240
- if "KOFI_CUSTOM_FOOTER" in locals () and KOFI_CUSTOM_FOOTER :
241
- lang = config ["language" ]
242
- if lang in TRANSLATIONS :
243
- TRANSLATIONS [lang ]["CustomFooter" ] = KOFI_CUSTOM_FOOTER
244
-
245
353
except ImportError :
246
354
pass # Optional settings not defined
247
355
@@ -374,39 +482,51 @@ def t(self, key):
374
482
if lang not in TRANSLATIONS :
375
483
lang = "en" # Fall back to English
376
484
377
- # Handle CustomMessage and CustomFooter specially to allow overrides from settings
378
- if key in ["CustomMessage" , "CustomFooter" ]:
379
- try :
380
- # Try to import custom message settings
381
- if key == "CustomMessage" :
382
- from config .settings import KOFI_CUSTOM_MESSAGE
383
-
384
- if "KOFI_CUSTOM_MESSAGE" in locals () and KOFI_CUSTOM_MESSAGE :
385
- return KOFI_CUSTOM_MESSAGE
386
- elif key == "CustomFooter" :
387
- from config .settings import KOFI_CUSTOM_FOOTER
388
-
389
- if "KOFI_CUSTOM_FOOTER" in locals () and KOFI_CUSTOM_FOOTER :
390
- return KOFI_CUSTOM_FOOTER
391
- except ImportError :
392
- pass
393
-
394
- # Get translation from the dictionary
485
+ # Special handling for custom messages
486
+ if key == "CustomMessage" :
487
+ # If we have a custom message for this language, use it
488
+ if lang in self .custom_messages :
489
+ return self .custom_messages [lang ]
490
+ # Otherwise fall back to the default translation
491
+ return TRANSLATIONS [lang ].get (key , TRANSLATIONS ["en" ].get (key , key ))
492
+
493
+ elif key == "CustomFooter" :
494
+ # If we have a custom footer for this language, use it
495
+ if lang in self .custom_footers :
496
+ return self .custom_footers [lang ]
497
+ # Otherwise fall back to the default translation
498
+ return TRANSLATIONS [lang ].get (key , TRANSLATIONS ["en" ].get (key , key ))
499
+
500
+ # Regular translations
395
501
text = TRANSLATIONS [lang ].get (key , TRANSLATIONS ["en" ].get (key , key ))
396
502
return text .replace ("{KOFI_NAME}" , self .config ["kofi_name" ])
397
503
398
504
def format_date (self , timestamp ):
399
- """Format timestamp nicely based on language"""
505
+ """Format timestamp nicely based on language using manual localization """
400
506
try :
401
507
date = datetime .datetime .fromisoformat (timestamp .replace ("Z" , "+00:00" ))
402
-
403
- if self .config ["language" ] == "de" :
404
- return date .strftime ("%A, %d. %B %Y, %H:%M Uhr" )
405
- elif self .config ["language" ] == "fr" :
406
- return date .strftime ("%A %d %B %Y, %H:%M" )
508
+ lang = self .config ["language" ].lower ()
509
+
510
+ # Get localized month and weekday names
511
+ month_name = MONTH_NAMES .get (lang , MONTH_NAMES ["en" ])[date .month - 1 ]
512
+ weekday_name = WEEKDAY_NAMES .get (lang , WEEKDAY_NAMES ["en" ])[date .weekday ()]
513
+
514
+ # Format the date according to the language conventions
515
+ if lang == "de" :
516
+ # German format: Montag, 7. Mai 2025, 15:30 Uhr
517
+ return f"{ weekday_name } , { date .day } . { month_name } { date .year } , { date .hour :02d} :{ date .minute :02d} Uhr"
518
+ elif lang == "fr" :
519
+ # French format: lundi 7 mai 2025, 15:30
520
+ return f"{ weekday_name } { date .day } { month_name } { date .year } , { date .hour :02d} :{ date .minute :02d} "
407
521
else :
408
- return date .strftime ("%A, %B %d, %Y at %I:%M %p" )
409
- except :
522
+ # English format: Monday, May 7, 2025 at 3:30 PM
523
+ hour = date .hour % 12
524
+ if hour == 0 :
525
+ hour = 12
526
+ am_pm = "PM" if date .hour >= 12 else "AM"
527
+ return f"{ weekday_name } , { month_name } { date .day } , { date .year } at { hour } :{ date .minute :02d} { am_pm } "
528
+ except Exception as e :
529
+ logger .error (f"Error formatting date: { e } " )
410
530
return timestamp or "Unknown date"
411
531
412
532
def get_type_emoji (self , type_str ):
0 commit comments