Metadata-Version: 2.4
Name: GeoCanon
Version: 0.1.0
Summary: Global-ready Django apps from day one. Jurisdictions, dial codes, flags, holidays, timezones, languages & more.
Project-URL: Homepage, https://github.com/Tunet-xyz/geo_canon
Project-URL: Documentation, https://github.com/Tunet-xyz/geo_canon/blob/main/docs/README.md
Project-URL: Repository, https://github.com/Tunet-xyz/geo_canon
Project-URL: Issues, https://github.com/Tunet-xyz/geo_canon/issues
Project-URL: Changelog, https://github.com/Tunet-xyz/geo_canon/blob/main/CHANGELOG.md
Author-email: Alex C <alex@coded.uk>
License-Expression: MIT
License-File: LICENSE
Keywords: dial-codes,django,flags,global,holidays,i18n,internationalization,jurisdiction,l10n,languages,locale,localization,timezones
Classifier: Framework :: Django
Classifier: Framework :: Django :: 4.2
Classifier: Framework :: Django :: 5.0
Classifier: Framework :: Django :: 5.1
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Internationalization
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Localization
Requires-Python: >=3.10
Requires-Dist: django>=4.2
Provides-Extra: all
Requires-Dist: holidays>=0.40; extra == 'all'
Requires-Dist: pytz>=2023.3; extra == 'all'
Provides-Extra: dev
Requires-Dist: django-stubs>=4.2.0; extra == 'dev'
Requires-Dist: mypy>=1.0.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
Requires-Dist: pytest-django>=4.5.0; extra == 'dev'
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Provides-Extra: holidays
Requires-Dist: holidays>=0.40; extra == 'holidays'
Provides-Extra: timezones
Requires-Dist: pytz>=2023.3; extra == 'timezones'
Description-Content-Type: text/markdown

# GeoCanon
### Global-Ready Django Apps From Day One

**Jurisdictions. Dial Codes. Flags. Timezones. Holidays. Languages. One Package.**

---

## What is GeoCanon?

GeoCanon is a **locale & jurisdiction toolkit** for Django that gives your app global awareness out of the box.

Instead of hand-rolling country lists, phone validation, timezone lookups, and holiday calendars, you import **one consistent library** and ship internationally from your first deploy.

### The Problem

```python
# Scattered across your codebase...
COUNTRIES = [("US", "United States"), ...]  # hand-maintained
DIAL_CODES = {"+1": "US", ...}             # incomplete
TIMEZONE_MAP = {"US": "America/New_York"}   # 8 entries
# No holiday detection, no flag icons, no language defaults
```

### The Solution

```python
from geo_canon import (
    get_jurisdiction_choices,      # 190+ countries, sorted, translatable
    get_dial_code,                 # "Romania" → "+40"
    validate_phone,                # per-country regex validation
    get_flag_css_class,            # "Romania" → "fi-ro"
    get_current_local_time,        # "Romania" → aware datetime in Europe/Bucharest
    get_language_for_jurisdiction,  # "Romania" → "ro"
    format_duration,               # 3661 → "1 hour, 1 minute, 1 second"
)

# Optional: holiday detection
from geo_canon.holidays import is_public_holiday
is_public_holiday("Romania", date(2025, 12, 25))  # True
```

---

## Quick Start

### 1. Install

```bash
# Core (zero non-Django dependencies)
pip install geocanon

# With optional extras
pip install geocanon[holidays]     # Public holiday detection
pip install geocanon[timezones]    # pytz fallback for Python <3.9
pip install geocanon[all]          # Everything
```

**Available extras:**
| Extra | What it adds |
|-------|-------------|
| `holidays` | Public holiday detection (140+ countries) |
| `timezones` | `pytz` fallback for legacy Python |
| `all` | Everything above |

### 2. Configure (optional)

```python
# settings.py — zero config required, but you CAN customise:
from geo_canon.settings import GeoCanonSettings

GEOCANON = GeoCanonSettings(
    default_jurisdiction="United Kingdom",
    default_language="en",
    timezone_overrides={"My Custom Region": "Europe/London"},
)
```

### 3. Use Anywhere

```python
from geo_canon import get_dial_code, get_flag_css_class, get_current_local_time

# Phone dial codes
get_dial_code("Romania")       # "+40"
get_dial_code("United States") # "+1"

# Flag CSS classes (for flag-icons library)
get_flag_css_class("Romania")  # "fi-ro"

# Current local time
get_current_local_time("Japan")  # datetime in Asia/Tokyo

# Language defaults
from geo_canon import get_language_for_jurisdiction
get_language_for_jurisdiction("France")  # "fr"

# Duration formatting (i18n-aware)
from geo_canon import format_duration
format_duration(7200)  # "2 hours"
```

### 4. Django Forms

```python
from geo_canon.jurisdictions.forms import JurisdictionContextSwitchForm

# Drop-in jurisdiction selector
form = JurisdictionContextSwitchForm()
```

### 5. Middleware

```python
# settings.py
MIDDLEWARE = [
    ...
    "geo_canon.jurisdictions.middleware.JurisdictionMiddleware",
]

# Now every request has request.jurisdiction
```

---

## Modules

| Module | Status | Description |
|--------|--------|-------------|
| **Jurisdictions** | Production | 190+ countries with translatable names, forms, middleware |
| **Dial Codes** | Production | International dial codes + per-country phone validation |
| **Flags** | Production | Country → ISO-3166 flag CSS class mapping |
| **Timezones** | Production | 200+ jurisdiction → IANA timezone mappings |
| **Languages** | Production | Language choices + jurisdiction → default language |
| **Duration** | Production | i18n-aware human-readable duration formatting |
| **Holidays** | Production | Public holiday detection for 140+ countries |
| **Settings** | Production | Pydantic-validated configuration |

---

## Features

- **190+ jurisdictions** — sorted, translatable, with O(1) lookups
- **Phone validation** — per-country regex patterns for national number formats
- **Flag icons** — CSS class mapping compatible with [flag-icons](https://flagicons.lipis.dev/)
- **200+ timezones** — uses `zoneinfo` (3.9+) with `pytz` fallback
- **Holiday detection** — powered by the battle-tested `holidays` library
- **75+ languages** — ISO 639-1 choices with jurisdiction → language mapping
- **Duration formatting** — respects Django's active translation
- **Jurisdiction middleware** — automatic `request.jurisdiction` on every request
- **Django form fields** — drop-in `JurisdictionChoiceField` and context-switch form
- **Pydantic settings** — type-safe configuration with sensible defaults
- **Rich exceptions** — actionable error messages with hints and docs links
- **Zero config** — works with defaults, customise when you need to
- **PEP 561** — `py.typed` marker for mypy/pyright

---

## Why GeoCanon?

- **One Source of Truth** — no more scattered country lists and timezone dicts
- **Production-Tested** — extracted from a live Django platform serving multiple jurisdictions
- **Translatable** — all labels use `gettext_lazy` for full i18n support
- **Minimal Dependencies** — only Django required; extras are truly optional
- **Type-Safe** — Pydantic validation, type hints throughout, PEP 561 compliant
- **Extensible** — override timezones, holiday mappings, and more via settings

---

## License

MIT — Because global-ready Django should be free.

---

**[→ Read Full Documentation](docs/README.md)**
