Metadata-Version: 2.4
Name: localbiz-page
Version: 0.1.0
Summary: Turn local-business data into structured, SEO-ready HTML with a zero-dependency template engine and Schema.org JSON-LD builder.
Project-URL: Homepage, https://github.com/asapura/localbiz-page
Project-URL: Repository, https://github.com/asapura/localbiz-page
Author: asapura
License: MIT
License-File: LICENSE
Keywords: html,json-ld,local-business,schema-org,seo,template-engine
Classifier: Development Status :: 4 - Beta
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Internet :: WWW/HTTP :: Site Management
Classifier: Topic :: Text Processing :: Markup :: HTML
Requires-Python: >=3.8
Description-Content-Type: text/markdown

# localbiz-page

[![CI](https://github.com/asapura/localbiz-page/actions/workflows/ci.yml/badge.svg)](https://github.com/asapura/localbiz-page/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/localbiz-page.svg)](https://pypi.org/project/localbiz-page/)
[![Python versions](https://img.shields.io/pypi/pyversions/localbiz-page.svg)](https://pypi.org/project/localbiz-page/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

Turn local-business data into structured, SEO-ready HTML — with **zero runtime dependencies**.

`localbiz-page` pairs a tiny HTML template engine with deterministic parsers for
Japanese local-business data (postal codes, addresses, opening hours, languages)
and a [Schema.org](https://schema.org/LocalBusiness) JSON-LD builder. Feed it a
plain `dict` and an HTML template; get back a rendered page plus valid structured
data for rich search results.

- **No dependencies.** Pure Python standard library. `pip install` pulls in nothing else.
- **Deterministic.** Same input → same output. No AI, no network calls.
- **Composable.** Use the template engine, the parsers, or the JSON-LD builder independently.

> 日本語の説明は[下のほうにあります](#日本語)。

## Install

```bash
pip install localbiz-page
```

Or just copy `src/localbiz_page/` into your project — it has no dependencies.

## Quick start

```python
from localbiz_page import (
    TemplateEngine, build_local_business, to_script_tag,
    format_postal_code, parse_address, parse_opening_hours, map_languages,
)

# 1. Build Schema.org JSON-LD from raw fields.
jsonld = build_local_business(
    "青葉珈琲店",
    business_type="CafeOrCoffeeShop",
    url="https://example.com",
    telephone="03-1234-5678",
    postal_code=format_postal_code("1600021"),          # -> "160-0021"
    address=parse_address("東京都渋谷区神南1-2-3"),       # -> region / locality / street
    opening_hours=parse_opening_hours("09:00-18:00", "水"),
    languages=map_languages([{"対応可能な外国語名": "英語"}]),  # -> ["ja", "en"]
)

# 2. Render an HTML template against your data.
html = TemplateEngine().render(
    "<h1>{{ name }}</h1>{{ json_ld }}",
    {"name": "青葉珈琲店", "json_ld": to_script_tag(jsonld)},
)
```

See [`examples/generate.py`](examples/generate.py) for a full
`cafe.json` + `cafe_template.html` → HTML pipeline.

## The template engine

**Double-brace** syntax (so it never clashes with the single braces in inline
CSS/JS or serialized JSON), three constructs:

| Syntax | Meaning |
| --- | --- |
| `{{ name }}` / `{{ shop.city }}` | Variable substitution, with dotted paths |
| `{{#if path}}...{{/if}}` | Conditional block (truthiness of `path`); nests freely |
| `{{#for item in items}}...{{/for}}` | Loop over a list; `item` is exposed in the body |

```python
from localbiz_page import render

render("{{#if open}}Welcome, {{ name }}!{{/if}}", {"open": True, "name": "Aoba"})
# "Welcome, Aoba!"

# {{#if}} works inside {{#for}}, and outer variables stay in scope:
render("{{#for m in menu}}<li>{{ m.item }}{{#if m.hot}} 🔥{{/if}}</li>{{/for}}",
       {"menu": [{"item": "Coffee", "hot": True}]})
# "<li>Coffee 🔥</li>"
```

Rendering is recursive-descent, so conditionals and loops nest correctly and a
loop body can reference both the loop variable and outer variables. Empty/missing
values render as an empty string; `None`, `""`, `[]`, `{}` and `False` are falsy
for `{{#if}}`. An unclosed block raises `ValueError`.

> **No auto-escaping.** Values are inserted verbatim — intended for trusted,
> structured input (you often *want* to embed HTML). Escape untrusted values
> yourself (e.g. `html.escape`) before putting them in the data dict. Single
> braces in the template pass through untouched, so inline CSS/JS is safe.

## Local-business parsers

All functions are pure and side-effect free:

| Function | Input → Output |
| --- | --- |
| `format_postal_code("1600021")` | `"160-0021"` |
| `parse_address("東京都渋谷区…")` | `{"addressRegion": "東京都", "addressLocality": "渋谷区", "streetAddress": "…"}` |
| `parse_opening_hours("09:00-18:00", "水")` | Schema.org `OpeningHoursSpecification[]` |
| `parse_days_off("木 日 祝日")` | `["Thursday", "Sunday"]` |
| `map_languages([...])` | ISO 639-1 codes, always including `"ja"` |
| `should_display(value)` | filters Japanese "no data" markers (`-`, `無し`, …) |
| `safe_get(data, "a.b.c")` | nested dict access with default |

## JSON-LD builder

`build_local_business(name, ...)` returns a Schema.org JSON-LD `dict`. It accepts
any [`LocalBusiness` subtype](https://schema.org/LocalBusiness) via `business_type`
(`"Restaurant"`, `"Store"`, `"BeautySalon"`, …), omits empty fields, and takes an
`extra=` dict for any additional Schema.org property. `to_script_tag(jsonld)` wraps
it in a ready-to-embed `<script type="application/ld+json">` tag.

## Develop & test

```bash
PYTHONPATH=src python -m unittest discover -s tests -v
python examples/generate.py
```

No test dependencies — everything runs on the standard library.

## Why "local business"?

The parsers encode conventions specific to Japanese local businesses (prefecture
splitting, weekday-based opening hours, language-name mapping), so they shine for
restaurants, cafes, salons, shops, studios and similar listing/directory pages.
The template engine and JSON-LD builder, however, are entirely domain-agnostic —
use them for any structured-content page.

## License

MIT — see [LICENSE](LICENSE).

---

<a name="日本語"></a>

## 日本語

ローカルビジネスの情報を、**外部依存ゼロ**で構造化された SEO 向け HTML に変換するツールキットです。

- 軽量 HTML テンプレートエンジン（`{{#if}}` / `{{#for}}` / `{{ 変数 }}` の二重ブレース構文）
- 日本のローカルビジネス向けパーサ（郵便番号・住所・営業時間・対応言語）
- Schema.org `LocalBusiness` の JSON-LD ビルダ

いずれも Python 標準ライブラリのみで動作し、確定的（同じ入力なら同じ出力、AI 推論なし）です。
飲食店・サロン・クリニック・店舗など、住所と営業時間を持つ施設ページの生成に向いています。
テンプレートエンジンと JSON-LD ビルダ自体は業種非依存で、あらゆる用途に使えます。

使い方は [`examples/generate.py`](examples/generate.py)（`cafe.json` から HTML を生成する一連の流れ）を参照してください。

ライセンスは MIT です。
