Skip to content

Localization Guide

Comprehensive guide to using Carbonic's multi-language support for datetime formatting and humanization.

Overview

Carbonic provides comprehensive localization support for: - Date/time formatting with localized month and day names - Duration humanization with proper pluralization rules - Number formatting with locale-specific decimal separators - 6 languages: English, Polish, Spanish, French, German, Portuguese

Supported Locales

from carbonic import DateTime, Duration

# Available locales
locales = ["en", "pl", "es", "fr", "de", "pt"]

dt = DateTime(2024, 1, 15, 14, 30)
duration = Duration(hours=2, minutes=30)

for locale in locales:
    formatted = dt.format("l, F j, Y", locale=locale)
    humanized = duration.humanize(locale=locale)
    print(f"{locale}: {formatted} - {humanized}")

Date and Time Formatting

Month Names

from carbonic import DateTime

dt = DateTime(2024, 1, 15, 14, 30)

# Full month names
print("Full month names:")
print(f"English:    {dt.format('F', locale='en')}")     # January
print(f"Polish:     {dt.format('F', locale='pl')}")     # stycznia (genitive)
print(f"Spanish:    {dt.format('F', locale='es')}")     # enero
print(f"French:     {dt.format('F', locale='fr')}")     # janvier
print(f"German:     {dt.format('F', locale='de')}")     # Januar
print(f"Portuguese: {dt.format('F', locale='pt')}")     # janeiro

# Short month names
print("\nShort month names:")
print(f"English:    {dt.format('M', locale='en')}")     # Jan
print(f"Polish:     {dt.format('M', locale='pl')}")     # sty
print(f"Spanish:    {dt.format('M', locale='es')}")     # ene

Day Names

from carbonic import DateTime

dt = DateTime(2024, 1, 15, 14, 30)  # Monday

# Full day names
print("Full day names:")
print(f"English:    {dt.format('l', locale='en')}")     # Monday
print(f"Polish:     {dt.format('l', locale='pl')}")     # poniedziałek
print(f"Spanish:    {dt.format('l', locale='es')}")     # lunes
print(f"French:     {dt.format('l', locale='fr')}")     # lundi
print(f"German:     {dt.format('l', locale='de')}")     # Montag
print(f"Portuguese: {dt.format('l', locale='pt')}")     # segunda-feira

# Short day names
print("\nShort day names:")
print(f"English:    {dt.format('D', locale='en')}")     # Mon
print(f"Polish:     {dt.format('D', locale='pl')}")     # pon
print(f"Spanish:    {dt.format('D', locale='es')}")     # lun

Complete Date Formats

from carbonic import DateTime

dt = DateTime(2024, 1, 15, 14, 30)

# Natural date formats for each locale
formats = {
    "en": "l, F j, Y",           # Monday, January 15, 2024
    "pl": "l, j F Y",            # poniedziałek, 15 stycznia 2024
    "es": "l, j {d}e F {d}e Y",  # lunes, 15 de enero de 2024
    "fr": "l j F Y",             # lundi 15 janvier 2024
    "de": "l, j. F Y",           # Montag, 15. Januar 2024
    "pt": "l, j {d}e F {d}e Y",  # segunda-feira, 15 de janeiro de 2024
}

for locale, format_str in formats.items():
    result = dt.format(format_str, locale=locale)
    print(f"{locale}: {result}")

Duration Humanization

Basic Humanization

from carbonic import Duration

duration = Duration(hours=2, minutes=30)

print("2 hours 30 minutes:")
print(f"English:    {duration.humanize(locale='en')}")    # 2 hours 30 minutes
print(f"Polish:     {duration.humanize(locale='pl')}")    # 2 godziny 30 minut
print(f"Spanish:    {duration.humanize(locale='es')}")    # 2 horas 30 minutos
print(f"French:     {duration.humanize(locale='fr')}")    # 2 heures 30 minutes
print(f"German:     {duration.humanize(locale='de')}")    # 2 Stunden 30 Minuten
print(f"Portuguese: {duration.humanize(locale='pt')}")    # 2 horas 30 minutos

Pluralization Rules

Different languages have different pluralization rules:

from carbonic import Duration

# English: simple plural (1 hour, 2 hours)
print("English pluralization:")
print(Duration(hours=1).humanize(locale="en"))    # 1 hour
print(Duration(hours=2).humanize(locale="en"))    # 2 hours
print(Duration(hours=5).humanize(locale="en"))    # 5 hours

# Polish: complex 3-form pluralization
print("\nPolish pluralization:")
print(Duration(hours=1).humanize(locale="pl"))    # 1 godzina (singular)
print(Duration(hours=2).humanize(locale="pl"))    # 2 godziny (plural 2-4)
print(Duration(hours=5).humanize(locale="pl"))    # 5 godzin (plural 5+)
print(Duration(hours=22).humanize(locale="pl"))   # 22 godziny (ends in 2-4)
print(Duration(hours=25).humanize(locale="pl"))   # 25 godzin (ends in 5+)

Different Time Units

from carbonic import Duration

# Various durations
durations = [
    Duration(seconds=30),
    Duration(minutes=1),
    Duration(hours=1),
    Duration(days=1),
    Duration(weeks=1),
    Duration(months=1),
    Duration(years=1)
]

print("Duration humanization across locales:")
for duration in durations:
    en = duration.humanize(locale="en")
    pl = duration.humanize(locale="pl")
    es = duration.humanize(locale="es")
    print(f"{en:15} | {pl:15} | {es}")

Number Formatting

Decimal Separators

from carbonic import Duration

# Duration with fractional seconds
duration = Duration(seconds=45, microseconds=500000)  # 45.5 seconds

print("Decimal separator formatting:")
print(f"English (dot):     {duration.humanize(locale='en')}")    # 45.5 seconds
print(f"Polish (comma):    {duration.humanize(locale='pl')}")    # 45,5 sekundy
print(f"Spanish (comma):   {duration.humanize(locale='es')}")    # 45,5 segundos
print(f"French (comma):    {duration.humanize(locale='fr')}")    # 45,5 secondes
print(f"German (comma):    {duration.humanize(locale='de')}")    # 45,5 Sekunden
print(f"Portuguese (comma): {duration.humanize(locale='pt')}")   # 45,5 segundos

Advanced Localization

Handling Special Cases

from carbonic import DateTime

# Month names in different contexts
dt = DateTime(2024, 5, 15, 14, 30)

# Polish months change form in different contexts
print("Polish month handling:")
print(f"Nominative: {dt.format('F', locale='pl')}")      # maja (genitive case)
print(f"With day:   {dt.format('j F', locale='pl')}")    # 15 maja

# French months (some are invariant)
dt_march = DateTime(2024, 3, 15)
print(f"French March: {dt_march.format('F', locale='fr')}")  # mars (no change)

Zero and Negative Durations

from carbonic import Duration

zero_duration = Duration()
negative_duration = Duration(hours=-2, minutes=-30)

print("Special duration cases:")
for locale in ["en", "pl", "es", "fr", "de", "pt"]:
    zero = zero_duration.humanize(locale=locale)
    negative = negative_duration.humanize(locale=locale)
    print(f"{locale}: '{zero}' | '{negative}'")

Controlling Precision

from carbonic import Duration

long_duration = Duration(days=1, hours=2, minutes=30, seconds=45)

print("Duration precision control:")
for locale in ["en", "pl", "es"]:
    # Default (all units)
    full = long_duration.humanize(locale=locale)

    # Limited units
    limited = long_duration.humanize(locale=locale, max_units=2)

    print(f"{locale}:")
    print(f"  Full:    {full}")
    print(f"  Limited: {limited}")

Practical Examples

User Interface Localization

from carbonic import DateTime, Duration

def format_user_datetime(dt, user_locale="en"):
    """Format datetime for user interface based on their locale."""
    formats = {
        "en": "l, M j, Y \\a\\t g:i A",        # Monday, Jan 15, 2024 at 2:30 PM
        "pl": "l, j M Y o G:i",               # poniedziałek, 15 sty 2024 o 14:30
        "es": "l, j {d}e M {d}e Y {a} \\l\\a\\s G:i",  # lunes, 15 de ene de 2024 a las 14:30
        "fr": "l j M Y \\à G:i",              # lundi 15 jan 2024 à 14:30
        "de": "l, j. M Y \\u\\m G:i",         # Montag, 15. Jan 2024 um 14:30
        "pt": "l, j {d}e M {d}e Y \\à\\s G:i", # segunda-feira, 15 de jan de 2024 às 14:30
    }

    format_str = formats.get(user_locale, formats["en"])
    return dt.format(format_str, locale=user_locale)

# Usage
dt = DateTime(2024, 1, 15, 14, 30)
for locale in ["en", "pl", "es", "fr", "de", "pt"]:
    formatted = format_user_datetime(dt, locale)
    print(f"{locale}: {formatted}")

Relative Time Display

from carbonic import DateTime, Duration

def relative_time_display(past_dt, current_dt=None, locale="en"):
    """Display relative time like 'posted 2 hours ago'."""
    if current_dt is None:
        current_dt = DateTime.now()

    duration = current_dt.diff(past_dt)
    humanized = duration.humanize(locale=locale, max_units=1)

    # Locale-specific formatting
    ago_text = {
        "en": "ago",
        "pl": "temu",
        "es": "hace",
        "fr": "il y a",
        "de": "vor",
        "pt": "atrás"
    }

    ago = ago_text.get(locale, ago_text["en"])

    if locale in ["fr"]:
        return f"{ago} {humanized}"  # French: "il y a 2 heures"
    elif locale in ["es"]:
        return f"{ago} {humanized}"  # Spanish: "hace 2 horas"
    else:
        return f"{humanized} {ago}"  # Others: "2 hours ago"

# Usage
past_time = DateTime.now().subtract(hours=2, minutes=15)
current_time = DateTime.now()

for locale in ["en", "pl", "es", "fr", "de", "pt"]:
    relative = relative_time_display(past_time, current_time, locale)
    print(f"{locale}: {relative}")

Multilingual Logging

from carbonic import DateTime

class LocalizedLogger:
    def __init__(self, locale="en"):
        self.locale = locale

    def log_event(self, event, level="INFO"):
        """Create localized log entry."""
        timestamp = DateTime.now()

        # Locale-specific timestamp format
        if self.locale == "en":
            time_str = timestamp.format("M j, Y H:i:s")
        elif self.locale == "pl":
            time_str = timestamp.format("j M Y H:i:s", locale="pl")
        elif self.locale == "es":
            time_str = timestamp.format("j {d}e M {d}e Y H:i:s", locale="es")
        else:
            time_str = timestamp.to_iso_string()

        return f"[{time_str}] {level}: {event}"

# Usage
loggers = {
    "en": LocalizedLogger("en"),
    "pl": LocalizedLogger("pl"),
    "es": LocalizedLogger("es")
}

for locale, logger in loggers.items():
    entry = logger.log_event("User login successful")
    print(f"{locale}: {entry}")

Error Handling

from carbonic import DateTime, Duration

def safe_localized_format(dt, format_str, locale="en"):
    """Safely format with fallback to English."""
    try:
        return dt.format(format_str, locale=locale)
    except (ValueError, KeyError):
        # Fallback to English if locale not supported
        return dt.format(format_str, locale="en")

# Usage
dt = DateTime(2024, 1, 15, 14, 30)
result = safe_localized_format(dt, "l, F j, Y", locale="invalid_locale")
print(result)  # Falls back to English

Performance Considerations

Locale Caching

Carbonic automatically caches locale data for performance:

from carbonic import DateTime, Duration

# First call loads locale data
dt = DateTime(2024, 1, 15)
result1 = dt.format("l, F j, Y", locale="pl")  # Loads Polish locale

# Subsequent calls use cached data
result2 = dt.format("j F Y", locale="pl")      # Uses cached Polish locale

# Different locale loads separately
result3 = dt.format("l, F j, Y", locale="es")  # Loads Spanish locale

Bulk Operations

from carbonic import DateTime

# Efficient for multiple operations with same locale
dates = [DateTime(2024, 1, i) for i in range(1, 32)]

# Good: Consistent locale
formatted_pl = [dt.format("j F", locale="pl") for dt in dates]

# Less efficient: Switching locales frequently
# formatted_mixed = [dt.format("j F", locale="pl" if i % 2 else "en") for i, dt in enumerate(dates)]

See Also