from decimal import Decimal, ROUND_HALF_UP from datetime import date UNITS = ( "ZERO ONE TWO THREE FOUR FIVE SIX SEVEN EIGHT NINE TEN ELEVEN TWELVE " "THIRTEEN FOURTEEN FIFTEEN SIXTEEN SEVENTEEN EIGHTEEN NINETEEN" ).split() TENS = "ZERO TEN TWENTY THIRTY FORTY FIFTY SIXTY SEVENTY EIGHTY NINETY".split() def format_date_en(d): if not d: return '' day = d.day # Gestion des suffixes ordinaux if 10 <= day % 100 <= 20: suffix = 'TH' else: suffix = {1: 'ST', 2: 'ND', 3: 'RD'}.get(day % 10, 'TH') return f"{day}{suffix} {d.strftime('%B').upper()} {d.year}" def _under_thousand(n): words = [] hundreds = n // 100 remainder = n % 100 if hundreds: words.append(UNITS[hundreds]) words.append("HUNDRED") if remainder: words.append("AND") if remainder: if remainder < 20: words.append(UNITS[remainder]) else: words.append(TENS[remainder // 10]) if remainder % 10: words.append(UNITS[remainder % 10]) return " ".join(words) def integer_to_words(n): if n == 0: return "ZERO" parts = [] millions = n // 1_000_000 thousands = (n // 1_000) % 1_000 remainder = n % 1_000 if millions: parts.append(_under_thousand(millions)) parts.append("MILLION") if thousands: parts.append(_under_thousand(thousands)) parts.append("THOUSAND") if remainder: parts.append(_under_thousand(remainder)) return " ".join(parts) # ============================== # 💰 MONETARY # ============================== def amount_to_currency_words(amount, major_singular="DOLLAR", major_plural="DOLLARS", minor_singular="CENT", minor_plural="CENTS"): """ Example: 1.20 → ONE DOLLAR AND TWENTY CENTS 2.00 → TWO DOLLARS """ amount = Decimal(str(amount)).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP) integer_part = int(amount) decimal_part = int((amount - integer_part) * 100) words = [] # Major unit major_words = integer_to_words(integer_part) words.append(major_words) if integer_part == 1: words.append(major_singular) else: words.append(major_plural) # Minor unit if decimal_part: words.append("AND") minor_words = integer_to_words(decimal_part) words.append(minor_words) if decimal_part == 1: words.append(minor_singular) else: words.append(minor_plural) return " ".join(words) # ============================== # ⚖️ QUANTITY WITH UNIT # ============================== def quantity_to_words(quantity, unit_singular="METRIC TON", unit_plural="METRIC TONS"): """ Example: 1 → ONE METRIC TON 23 → TWENTY THREE METRIC TONS 1.5 → ONE POINT FIVE METRIC TONS """ quantity = Decimal(str(quantity)).normalize() if quantity == quantity.to_integral(): integer_part = int(quantity) words = integer_to_words(integer_part) if integer_part == 1: unit = unit_singular else: unit = unit_plural return f"{words} {unit}" else: # lecture décimale simple pour quantités integer_part = int(quantity) decimal_str = str(quantity).split(".")[1] words = integer_to_words(integer_part) decimal_words = " ".join(UNITS[int(d)] for d in decimal_str) return f"{words} POINT {decimal_words} {unit_plural}"