Claude Code for Babel: Python Internationalization and Localization — Claude Skills 360 Blog
Blog / AI / Claude Code for Babel: Python Internationalization and Localization
AI

Claude Code for Babel: Python Internationalization and Localization

Published: February 25, 2028
Read time: 5 min read
By: Claude Skills 360

Babel provides i18n and l10n for Python applications. pip install babel. Numbers: from babel.numbers import format_decimal, format_currency, format_percent. format_decimal(1234567.89, locale="en_US") → “1,234,567.89”. format_decimal(1234567.89, locale="de_DE") → “1.234.567,89”. format_currency(1234.56, "USD", locale="en_US") → “$1,234.56”. format_currency(1234.56, "EUR", locale="fr_FR") → “1 234,56 €”. format_percent(0.253, locale="en_US") → “25%”. Dates: from babel.dates import format_date, format_time, format_datetime, format_timedelta. format_date(date.today(), locale="en_US") → “Jan 5, 2024”. format_date(date.today(), format="full", locale="de") → “Freitag, 5. Januar 2024”. format_time(datetime.now(), locale="ja_JP"). format_datetime(dt, locale="zh_CN"). format_timedelta(timedelta(hours=2), locale="fr_FR") → “dans 2 heures”. Locale: from babel import Locale. Locale("de", "DE"). Locale.parse("de_DE"). locale.display_name. locale.number_symbols. locale.currency_symbols. Timezones: from babel.dates import get_timezone, format_datetime. tz = get_timezone("America/New_York"). format_datetime(dt, tzinfo=tz, locale="en_US"). get_timezone_name(tz, locale="en"). Translations: gettext, ngettext, lazy_gettext. Flask-Babel: flask_babel.Babel(app). @babel.localeselector. Claude Code generates Babel formatters, Flask-Babel integrations, and locale-aware display layers.

CLAUDE.md for Babel

## Babel Stack
- Version: babel >= 2.14 | pip install babel
- Numbers: format_decimal(n, locale="de_DE") | format_currency(n, "EUR", locale="fr_FR")
- Dates: format_date(d, format="full", locale="ja") | format_datetime(dt, locale="zh_CN")
- Timedelta: format_timedelta(td, add_direction=True, locale="fr") → "in 2 hours"
- Locale: Locale.parse("de_DE").display_name | locale.currency_symbols["USD"]
- Timezone: get_timezone("America/New_York") | format_datetime(dt, tzinfo=tz, locale="en")
- Flask: Flask-Babel extension for request.locale detection + gettext

Babel Internationalization Pipeline

# app/i18n.py — Babel number, date, currency, and timezone formatting
from __future__ import annotations

from datetime import date, datetime, timedelta, timezone
from typing import Any

from babel import Locale
from babel.dates import (
    format_date,
    format_datetime,
    format_time,
    format_timedelta,
    get_timezone,
    get_timezone_name,
)
from babel.numbers import (
    format_compact_decimal,
    format_currency,
    format_decimal,
    format_percent,
    format_scientific,
    get_currency_name,
    get_currency_symbol,
)


# ─────────────────────────────────────────────────────────────────────────────
# 1. Number formatting
# ─────────────────────────────────────────────────────────────────────────────

def format_number(value: float, locale: str = "en_US") -> str:
    """
    Format a number using locale-specific grouping and decimal separators.
    US: 1,234,567.89 | German: 1.234.567,89 | French: 1 234 567,89
    """
    return format_decimal(value, locale=locale)


def format_number_compact(value: float, locale: str = "en_US") -> str:
    """
    Compact notation: 1200000 → "1.2M" (en_US) or "1,2 Mio." (de_DE).
    Useful for dashboards where space is limited.
    """
    return format_compact_decimal(value, locale=locale)


def format_money(
    value: float,
    currency: str = "USD",
    locale: str = "en_US",
    format_type: str = "standard",
) -> str:
    """
    Format a monetary value with the correct symbol and separators.
    format_type: "standard" ($1,234.56), "accounting" (parentheses for negative).
    """
    return format_currency(value, currency, locale=locale, format_type=format_type)


def format_pct(value: float, decimal_quantization: bool = True, locale: str = "en_US") -> str:
    """Format a ratio as a percentage: 0.253 → "25%"."""
    return format_percent(value, locale=locale)


def demo_numbers() -> None:
    number = 1_234_567.89
    locales = ["en_US", "de_DE", "fr_FR", "ja_JP", "ar_SA", "hi_IN"]
    print("  Number formatting:")
    for loc in locales:
        print(f"    {loc:10}{format_decimal(number, locale=loc)}")

    print("\n  Currency formatting ($1,234.56):")
    samples = [
        ("USD", "en_US"), ("EUR", "de_DE"), ("EUR", "fr_FR"),
        ("JPY", "ja_JP"), ("GBP", "en_GB"), ("CNY", "zh_CN"),
    ]
    for curr, loc in samples:
        print(f"    {curr}/{loc:10}{format_currency(1234.56, curr, locale=loc)}")


# ─────────────────────────────────────────────────────────────────────────────
# 2. Date and time formatting
# ─────────────────────────────────────────────────────────────────────────────

def format_locale_date(
    d: date,
    locale: str = "en_US",
    fmt: str = "medium",
) -> str:
    """
    Format a date object using locale-specific format.
    fmt: "short" (1/5/24), "medium" (Jan 5, 2024), "long" (January 5, 2024),
         "full" (Friday, January 5, 2024).
    Babel translates month/day names to the target locale.
    """
    return format_date(d, format=fmt, locale=locale)


def format_locale_datetime(
    dt: datetime,
    locale: str = "en_US",
    fmt: str = "medium",
    tz_name: str | None = None,
) -> str:
    """Format a datetime with optional timezone conversion."""
    tz = get_timezone(tz_name) if tz_name else None
    return format_datetime(dt, format=fmt, locale=locale, tzinfo=tz)


def format_relative_time(td: timedelta, locale: str = "en_US") -> str:
    """
    Format a timedelta as a human-readable relative string.
    add_direction=True → "in 2 hours" or "2 hours ago".
    """
    return format_timedelta(td, add_direction=True, locale=locale)


def demo_dates() -> None:
    today = date(2024, 1, 5)
    now   = datetime(2024, 1, 5, 14, 30, 0)
    fmts  = ["short", "medium", "long", "full"]
    locales = ["en_US", "de_DE", "fr_FR", "zh_CN", "ja_JP", "ar_SA"]

    print("  Date formats (en_US):")
    for f in fmts:
        print(f"    {f:8}{format_date(today, format=f, locale='en_US')}")

    print("\n  Full date by locale:")
    for loc in locales:
        print(f"    {loc:10}{format_date(today, format='full', locale=loc)}")

    print("\n  Relative time:")
    deltas = [timedelta(minutes=5), timedelta(hours=2), timedelta(days=3), timedelta(weeks=2)]
    for loc in ["en_US", "de_DE", "fr_FR", "zh_CN"]:
        print(f"    [{loc}] {format_timedelta(timedelta(hours=2), add_direction=True, locale=loc)}")


# ─────────────────────────────────────────────────────────────────────────────
# 3. Locale introspection
# ─────────────────────────────────────────────────────────────────────────────

def get_locale_info(locale_str: str) -> dict[str, Any]:
    """
    Return metadata about a locale identifier.
    Locale.parse("de_DE") returns a Locale object with rich introspection.
    """
    try:
        locale = Locale.parse(locale_str)
    except Exception as e:
        return {"error": str(e)}
    return {
        "identifier":         str(locale),
        "display_name":       locale.display_name,
        "language":           locale.language,
        "territory":          locale.territory,
        "decimal_symbol":     locale.number_symbols.get("decimal"),
        "group_symbol":       locale.number_symbols.get("group"),
        "currency_symbol":    locale.currency_symbols.get(locale.territory or "US", ""),
        "first_week_day":     locale.first_week_day,   # 0=Mon, 6=Sun
        "days":               list(locale.days["wide"]["format"].values()),
    }


def list_locales(language: str) -> list[str]:
    """List all available locales for a given language code."""
    from babel import core
    return sorted(
        s for s in core.locale_identifiers()
        if s.startswith(language + "_") or s == language
    )


# ─────────────────────────────────────────────────────────────────────────────
# 4. Timezone display
# ─────────────────────────────────────────────────────────────────────────────

def format_with_timezone(
    dt: datetime,
    from_tz: str,
    to_tz: str,
    locale: str = "en_US",
) -> str:
    """
    Convert a naive datetime from one timezone to another and format it.
    get_timezone() returns a pytz/zoneinfo-compatible timezone object.
    """
    from_zone = get_timezone(from_tz)
    to_zone   = get_timezone(to_tz)
    # Localize naive datetime
    if dt.tzinfo is None:
        from pytz import timezone as pytz_tz
        dt = pytz_tz(from_tz).localize(dt)
    tz_name = get_timezone_name(to_zone, locale=locale)
    formatted = format_datetime(dt, format="long", locale=locale, tzinfo=to_zone)
    return f"{formatted} ({tz_name})"


# ─────────────────────────────────────────────────────────────────────────────
# 5. Flask-Babel integration pattern
# ─────────────────────────────────────────────────────────────────────────────

FLASK_BABEL_EXAMPLE = '''
from flask import Flask, request, g
from flask_babel import Babel, format_currency, format_date, gettext as _

app = Flask(__name__)
babel = Babel(app)

SUPPORTED_LOCALES = ["en", "de", "fr", "ja", "zh"]

@babel.localeselector
def get_locale():
    """Detect locale from Accept-Language header or user preference."""
    return request.accept_languages.best_match(SUPPORTED_LOCALES) or "en"

@app.route("/price/<float:amount>")
def show_price(amount: float):
    locale = get_locale()
    formatted = format_currency(amount, "USD", locale=locale)
    return {"price": formatted, "locale": locale}

# In Jinja2 templates:
# {{ amount | format_currency("USD") }}
# {{ date_value | format_date("full") }}
# {{ _("Hello, %(name)s!", name=user.name) }}
'''


# ─────────────────────────────────────────────────────────────────────────────
# 6. Currency info helpers
# ─────────────────────────────────────────────────────────────────────────────

def get_currency_info(currency_code: str, locale: str = "en_US") -> dict[str, str]:
    """Return display name and symbol for a currency code."""
    return {
        "code":   currency_code,
        "name":   get_currency_name(currency_code, locale=locale),
        "symbol": get_currency_symbol(currency_code, locale=locale),
    }


# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    print("=== Number formatting ===")
    demo_numbers()

    print("\n=== Date formatting ===")
    demo_dates()

    print("\n=== Locale info ===")
    for loc in ["en_US", "de_DE", "fr_FR", "ja_JP"]:
        info = get_locale_info(loc)
        print(f"  [{loc}] {info.get('display_name')} — "
              f"decimal={info.get('decimal_symbol')!r} "
              f"group={info.get('group_symbol')!r}")

    print("\n=== Currency info ===")
    for code in ["USD", "EUR", "JPY", "GBP", "CHF"]:
        info = get_currency_info(code)
        print(f"  {info['code']}: {info['name']:25} ({info['symbol']})")

    print("\n=== Compact numbers ===")
    for n in [1_200, 15_000, 1_200_000, 2_400_000_000]:
        print(f"  {n:>15,}{format_compact_decimal(n, locale='en_US')}")

For the locale (stdlib) alternative — Python’s built-in locale module uses the OS system locale (set via locale.setlocale()), which is a process-global change that breaks thread safety and CI reproducibility; Babel passes the locale as a function argument (format_currency(value, "EUR", locale="fr_FR")), making per-request locale formatting safe in multi-threaded web servers without any global state. For the babel vs. arrow alternative — Arrow is a datetime manipulation library (“3 days ago” creation and relative difference), while Babel is a display/formatting library — they solve different problems and are often used together: Arrow for datetime arithmetic, Babel for rendering the result in a user’s locale with format_date(arrow_dt.date(), format="full", locale=user_locale). The Claude Skills 360 bundle includes Babel skill sets covering format_decimal for locale-aware number formatting, format_currency with currency code and locale, format_compact_decimal for compact notation, format_date/format_time/format_datetime with short/medium/long/full formats, format_timedelta with add_direction, Locale.parse() introspection, get_locale_info() metadata extraction, get_currency_name/symbol helpers, format_with_timezone using get_timezone, and Flask-Babel localeselector pattern. Start with the free tier to try internationalization formatting code generation.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free