Skip to content

Repository files navigation

Letusgoshopping

Turn any brand's product data into platform-ready, multilingual commerce assets. 把任何品牌的商品数据,一键变成多平台、多语言的电商素材。

CI License Release Python


1. The problem

Selling cross-border, the bottleneck usually isn't the product — it's content.

Every SKU has to be re-published for every destination, and each destination wants a different shape of the same facts:

  • A spec card for the listing gallery, a 1:1 square for social, a tall detail page for A+ / 详情页.
  • Amazon wants a title under 200 characters and at most 5 bullets. Google Merchant wants a TSV feed with id/title/price/brand. Shopify wants an import CSV with its own column names.
  • And all of it again in the next language.

Done by hand, that is (SKUs × formats × platforms × languages) copies of the same information, each drifting out of sync with the others. Teams end up maintaining per-category templates, per-platform spreadsheets, and per-language documents that nobody can keep aligned.

Letusgoshopping makes it data-driven. You describe a product once, in one neutral JSON schema. The engine generates the images-ready HTML, the platform feeds, and the translated fields from that single source. Change the data, regenerate everything.

一句话:商品数据写一次,多平台 / 多格式 / 多语言的素材自动生成——不用为每个类目改代码。

Who it's for: cross-border sellers, brand/agency content teams, and anyone maintaining product listings across more than one platform or language. What you need: Python 3.9+ and your product data (or one of the bundled examples to try it on).

The engine is brand- and category-agnostic: category differences live in the data (attribute_groups, dynamic-column spec_table), never in code — adding a category means adding data, not adding code.


2. What it does

Capability What you get
One product schema Describe a product once in JSON — name, brand, price, marketing bullets, attribute groups, and a spec table whose columns you define per product. Every language variant lives in the same file.
Three asset formats Render the same product as a dense spec card, a 1:1 social square, or a tall detail page — three different templates, zero data changes.
Three platform adapters Convert the same product into Amazon listing fields (with Seller Central limits applied), a Google Merchant Center TSV feed, or a Shopify product-import CSV. (Shopify is on main; it is not in the v0.1.0 tag — see CHANGELOG.md [Unreleased].)
Multilingual output Any text field can hold multiple languages. Missing translations get filled by an offline glossary, a human-edited translation-memory file, or the Claude API — layered so a curated translation always wins.
One-command full kit kit runs the whole pipeline — localize, render every template, run every platform adapter, write a manifest — into a single output folder.
Validation build checks every product against the JSON Schema before rendering and reports problems per file instead of failing the whole run. (adapt and kit skip validation — run build first if you want the report.)
Data tooling Scripts to ingest a vendor's raw parameter files into the schema, and to de-identify a real dataset into a redistributable example.

How it fits together

flowchart LR
    SRC["Raw vendor data"] -->|"scripts/ingest_sa.py"| DATA["products/*.json<br/>one neutral schema"]
    DATA --> B["build<br/>validate, then render"]
    DATA --> L["localize<br/>fill missing languages"]
    DATA --> A["adapt"]
    DATA --> K["kit<br/>localize in memory, then<br/>every template + platform"]
    B --> T1["sku-card"]
    B --> T2["social-square"]
    B --> T3["detail-page"]
    A --> P1["Amazon JSON"]
    A --> P2["Google Merchant TSV"]
    A --> P3["Shopify CSV"]
Loading

Only build validates against schema/product.schema.json; adapt and kit assume the data is already clean.

The core is small on purpose: listingforge/ loads and validates, templates/ renders, adapters.py maps to platforms. Each is an independent extension point — most contributions are one new file. See CONTRIBUTING.md.


3. Installation

Prerequisites

Requirement Notes
Python 3.9 or newer Tested in CI on 3.9, 3.11 and 3.12.
Git Templates, the schema, and the examples live at the repo root, so the tool is designed to run from a clone (or an editable install of one).
A browser Output is HTML — you open it to look at it. Optional.

Install

git clone https://github.com/KeepIntouch2024/Letusgoshopping.git
cd Letusgoshopping

# Option A — just the runtime dependencies
pip install -r requirements.txt

# Option B — editable install (also gives you the `listingforge` command)
pip install -e ".[dev]"

That installs two packages: jinja2 (required — the templating engine) and jsonschema (optional — enables full JSON-Schema validation; without it the tool falls back to minimal structural checks and still runs).

Verify the install:

python -m unittest discover -s tests -v      # 9 tests, stdlib only — no pytest needed
python -m listingforge build examples/apparel-demo --lang en

Environment variables

None are required. Everything above works fully offline.

One variable matters only if you want LLM translation (--provider anthropic, or --provider auto when you want it to pick Claude automatically):

Variable Required? Purpose
ANTHROPIC_API_KEY Optional Credentials for the Claude translation provider.
ANTHROPIC_AUTH_TOKEN Optional Alternative to the above; either one is accepted.
export ANTHROPIC_API_KEY="sk-ant-..."   # only for `--provider anthropic`
pip install anthropic                    # the LLM provider is an optional dependency

If neither variable is set, --provider auto silently falls back to the offline glossary — so CI and first-time users never need a key.

说明:不配任何环境变量也能完整跑通ANTHROPIC_API_KEY 只在用 Claude 做翻译时才需要。

Optional extras
pip install -e ".[llm]"      # anthropic — enables `localize --provider anthropic`
pip install -e ".[schema]"   # jsonschema — full JSON-Schema validation
pip install -e ".[render]"   # playwright — then: playwright install chromium

[render] is for scripts/render_png.py, which rasterizes built HTML cards to PNG.


4. Usage

Quickstart — the shortest path that works

From the repo root, after installing:

# 1. Render a spec card for every product in the demo, in English
python -m listingforge build examples/apparel-demo --lang en

# 2. Open the result in your browser
#    macOS: open · Linux: xdg-open · Windows: start
open examples/apparel-demo/output/sku-card/index.html

That's it. You just turned examples/apparel-demo/products/*.json into browsable HTML cards. Now try the whole pipeline in one command:

python -m listingforge kit examples/apparel-demo --lang zh

which localizes, renders all three templates, runs all three platform adapters, and writes a manifest — into examples/apparel-demo/kit/zh/.

The same engine, a different category

The point of the schema is that nothing above is apparel-specific. The bundled examples/fly-demo is an anonymized fly-fishing dataset (188 products, dense technical spec tables) and it runs through the identical commands and the identical templates:

python -m listingforge build examples/fly-demo --lang zh
python -m listingforge kit   examples/fly-demo --lang zh

两个完全不同的类目(服装 / 飞钓线),同一套命令、同一套模板——这就是本项目的核心。

The four commands

python -m listingforge <command> <example-dir> [options]

<example-dir> is any directory containing a products/ folder of *.json files (the tool also accepts a directory of *.json files directly).

Command What it does
build Renders one template into HTML, one file per product, plus an index.html.
localize Fills in missing-language fields using a translator, writing updated JSON.
adapt Converts the products into one platform's format.
kit Everything at once: localize in memory → all templates → all platforms → manifest.

Common invocations:

# A different asset format from the same data
python -m listingforge build examples/apparel-demo --lang en --template social-square
python -m listingforge build examples/apparel-demo --lang en --template detail-page

# Platform feeds
python -m listingforge adapt examples/apparel-demo --platform amazon          --lang en
python -m listingforge adapt examples/apparel-demo --platform google-merchant --lang en
python -m listingforge adapt examples/apparel-demo --platform shopify         --lang en

# Fill missing Chinese fields using the offline glossary, writing to a new folder
python -m listingforge localize examples/fly-demo --lang zh --provider glossary --out /tmp/localized

# Use a human-curated translation memory (layered on top — the TM always wins)
python -m listingforge localize examples/fly-demo --lang zh --tm my-translations.json

# Use Claude for real translation (needs ANTHROPIC_API_KEY)
python -m listingforge localize examples/fly-demo --lang zh --provider anthropic
Full option reference

Every command takes the example directory as its first positional argument.

build — render SKU cards from an example's product data

Option Default Notes
--lang en Language code, e.g. en / zh.
--template sku-card One of sku-card, social-square, detail-page, or any folder you add under templates/.
--out <example>/output/<template> Output directory.

localize — fill missing-language i18n fields via a translator

Option Default Notes
--lang zh Target language code.
--provider auto auto | anthropic | glossary | memory. auto uses Claude when credentials are present, else the offline glossary.
--model claude-opus-4-8 Claude model, used only with --provider anthropic.
--tm Translation-memory JSON file ({"english": "target"}), layered on top of the chosen provider. Required for --provider memory.
--out overwrite in place Output directory; omit to edit the source files.

adapt — convert products to a platform's format

Option Default Notes
--platform required amazon | google-merchant | shopify.
--lang en Language code.
--out <example>/adapters/<platform> Output directory.

kit — one command: localize + all templates + all platform adapters

Option Default Notes
--lang zh Target language code.
--provider auto Same choices as localize. Localization happens in memory — source files are untouched.
--model claude-opus-4-8 Claude model for --provider anthropic.
--tm Translation-memory JSON.
--templates all three Comma-separated list, e.g. sku-card,detail-page.
--out <example>/kit/<lang> Output directory.

If you installed with pip install -e ., a listingforge console command is available and is equivalent to python -m listingforge.


5. Input and output

Input: one product, one JSON file

Products live in <example>/products/*.json. Only id and identity.name are required — everything else is optional. Here is the real examples/apparel-demo/products/ACME-TEE-42.json, abridged:

{
  "id": "ACME-TEE-42",
  "identity": {
    "name": { "en": "Organic Cotton Crew Tee", "zh": "有机棉圆领T恤" },
    "brand": "ACME",
    "series": "Everyday Basics"
  },
  "taxonomy": { "category": "Apparel", "tags": ["unisex", "cotton", "tee"] },
  "pricing": { "currency": "USD", "value": 29.00 },
  "copy": {
    "bullets": {
      "en": [
        "180gsm 100% organic ring-spun cotton, breathable and soft",
        "Pre-shrunk for a lasting fit wash after wash",
        "Reinforced shoulder seams and ribbed crew neck",
        "Unisex regular fit"
      ],
      "zh": [
        "180gsm 100% 有机环纺棉,透气柔软",
        "预缩处理,多次水洗不变形",
        "加固肩缝 + 罗纹圆领",
        "中性常规版型"
      ]
    }
  },
  "attribute_groups": [
    { "group": { "en": "Material", "zh": "材质" }, "values": [
      { "label": { "en": "100% Organic Cotton", "zh": "100% 有机棉" }, "icon": "cotton" },
      { "label": { "en": "180 gsm", "zh": "180 克重" } }
    ]},
    { "group": { "en": "Care", "zh": "洗护" }, "values": [
      { "label": { "en": "Machine Wash Cold", "zh": "冷水机洗" }, "icon": "wash-cold" }
    ]}
  ],
  "spec_table": {
    "columns": [
      { "key": "size",   "label": { "en": "SIZE",   "zh": "尺码" } },
      { "key": "chest",  "label": { "en": "CHEST",  "zh": "胸围" } },
      { "key": "length", "label": { "en": "LENGTH", "zh": "衣长" } }
    ],
    "rows": [
      { "size": "S", "chest": "36\" / 91cm",  "length": "27\" / 69cm" },
      { "size": "M", "chest": "38\" / 96cm",  "length": "28\" / 71cm" },
      { "size": "L", "chest": "41\" / 104cm", "length": "29\" / 74cm" }
    ]
  },
  "localization": { "units": "dual", "size_system": "US->EU/UK" }
}

(Abridged — the real file also has a third Fit attribute group, two more Care values, an eu spec column and an XL row; all of them show up in the Amazon search_terms below.)

Two things carry the whole design:

  • attribute_groups — the group names and their values are data. Apparel gets Material / Care / Fit; the fishing example gets Water Type / Species / Material. Same template, no code change.
  • spec_table.columns — you declare the columns per product. Apparel uses size / chest / length / eu; a tippet spool uses item / size / diameter / break_strength.

Every user-visible string is a {"lang": "text"} map, which is what makes multilingual output a data property rather than a separate pipeline.

Output A: rendered HTML

$ python -m listingforge build examples/apparel-demo --lang en
  ✓ ACME-HOODIE-07.json → examples/apparel-demo/output/sku-card/ACME-HOODIE-07.en.html
  ✓ ACME-TEE-42.json → examples/apparel-demo/output/sku-card/ACME-TEE-42.en.html

2/2 rendered → examples/apparel-demo/output/sku-card/  (open examples/apparel-demo/output/sku-card/index.html)
examples/apparel-demo/output/
└── sku-card/                     # one folder per template
    ├── index.html                # linked list of everything rendered
    ├── ACME-HOODIE-07.en.html
    └── ACME-TEE-42.en.html       # <id>.<lang>.html

Each HTML file is fully self-contained (inline CSS) — open it in a browser, or screenshot it for the listing gallery.

Output B: platform feeds

$ python -m listingforge adapt examples/apparel-demo --platform amazon --lang en
2 Amazon listing(s) → examples/apparel-demo/adapters/amazon/  (0 constraint issue(s))

adapters/amazon/ACME-TEE-42.json — Amazon Seller Central fields. Note the bullets were taken from copy.bullets, the search terms were synthesized from attribute_groups, and the description was assembled because the source had none:

{
  "title": "ACME Organic Cotton Crew Tee",
  "brand": "ACME",
  "bullet_points": [
    "180gsm 100% organic ring-spun cotton, breathable and soft",
    "Pre-shrunk for a lasting fit wash after wash",
    "Reinforced shoulder seams and ribbed crew neck",
    "Unisex regular fit"
  ],
  "description": "ACME Organic Cotton Crew Tee. 180gsm 100% organic ring-spun cotton, breathable and soft. Pre-shrunk for a lasting fit wash after wash. ...",
  "search_terms": [
    "100% Organic Cotton", "180 gsm", "Machine Wash Cold",
    "Tumble Dry Low", "Do Not Bleach", "Regular / Unisex"
  ],
  "standard_price": "29.00 USD"
}

The adapter enforces Amazon's Seller Central limits while it builds the listing — the title is cut to 200 characters and the bullets to the first 5, each capped at 500 characters — and validate_amazon() re-checks the result, which is why a clean run reports 0 constraint issue(s).

adapters/google-merchant/feed.google.tsv — a Google Merchant Center feed, one row per product (tab-separated, 12 columns; the last two, item_group_id and mpn, are cut from the snippet below to fit):

id	title	description	link	image_link	availability	price	brand	condition	google_product_category
ACME-HOODIE-07	ACME Heavyweight Fleece Hoodie	Heavyweight Fleece Hoodie	https://example.com/p/ACME-HOODIE-07		in_stock	59.00 USD	ACME	new	Apparel
ACME-TEE-42	ACME Organic Cotton Crew Tee	Organic Cotton Crew Tee	https://example.com/p/ACME-TEE-42		in_stock	29.00 USD	ACME	new	Apparel

adapters/shopify/products.shopify.csv is a Shopify product-import CSV with Shopify's own column names (Handle, Title, Body (HTML), Vendor, Variant SKU, Variant Price, …).

Output C: the full kit

$ python -m listingforge kit examples/apparel-demo --lang zh
kit for examples/apparel-demo (zh)
  localized  : 0 field(s) filled in memory
  assets     :
      sku-card       2 cards
      social-square  2 cards
      detail-page    2 cards
  platforms  :
      amazon          2 listings (0 issue(s))
      google-merchant 2-row feed
      shopify         2-row csv
  → examples/apparel-demo/kit/zh/  (manifest.json)
examples/apparel-demo/kit/zh/
├── manifest.json
├── assets/
│   ├── sku-card/       { index.html, ACME-TEE-42.html, ACME-HOODIE-07.html }
│   ├── social-square/  { index.html, ACME-TEE-42.html, ACME-HOODIE-07.html }
│   └── detail-page/    { index.html, ACME-TEE-42.html, ACME-HOODIE-07.html }
└── platforms/
    ├── amazon/         { ACME-TEE-42.json, ACME-HOODIE-07.json }
    ├── google-merchant/ feed.google.tsv
    └── shopify/         products.shopify.csv

manifest.json is the machine-readable summary of that run:

{
  "example": "apparel-demo",
  "lang": "zh",
  "products": 2,
  "localized_fields": 0,
  "assets": { "sku-card": 2, "social-square": 2, "detail-page": 2 },
  "platforms": {
    "amazon": { "listings": 2, "issues": 0 },
    "google-merchant": { "feed_rows": 2 },
    "shopify": { "csv_rows": 2 }
  }
}

(localized_fields is 0 here because the apparel demo already ships bilingual. Running the same command on examples/fly-demo, where many Chinese fields are missing, fills 199 fields from the offline glossary and renders 188 products per template.)

Output D: localization

$ python -m listingforge localize examples/fly-demo --lang zh --provider glossary --out /tmp/localized
localizing 188 product(s) → zh  (provider: GlossaryTranslator)
  ✓ FD-AC-01.json: filled 1 field(s)
  ✓ FD-AC-02.json: filled 2 field(s)
  ...
filled 199 field(s) across 116/188 products → /tmp/localized/
note: offline glossary fills known terms only — product names and marketing copy need `--provider anthropic` (set ANTHROPIC_API_KEY).

Localization only ever adds a missing language to a field that already has English — it never overwrites an existing translation. The three providers layer: a --tm translation memory takes precedence, then the chosen provider (glossary or Claude).


Project layout

listingforge/          # engine: model.py (load/validate/i18n), renderer.py, adapters.py, localize.py, cli.py
schema/
  product.schema.json  # the one contract every template and adapter speaks
templates/
  sku-card/            # dense spec card
  social-square/       # 1:1 social creative
  detail-page/         # tall A+/detail long-page
examples/
  apparel-demo/        # 2 products — fully synthetic, fictional "ACME" brand
  fly-demo/            # 188 products — anonymized fishing case, fictional "Northbank"
scripts/
  ingest_sa.py         # vendor parameter files → schema JSON
  anonymize.py         # de-identify a local dataset into a shippable example
  render_png.py        # optional: HTML → PNG via Playwright
tests/                 # stdlib unittest suite (9 tests)

Generated output (output/, adapters/, kit/, localized/) is git-ignored.

Status and honest notes

  • v0.1.0 preview, plus unreleased work on main. The v0.1.0 tag ships the engine, schema, 3 templates, 2 platform adapters (Amazon, Google Merchant), localization, the full-kit command, tests and CI. The Shopify adapter is implemented, wired into adapt and kit, and covered by a test, but has not been tagged in a release yet.
  • Not on PyPI. Templates, the schema, and the examples live at the repo root, so run from a clone or an editable install. Shipping them as package data is a known follow-up.
  • examples/apparel-demo is fully synthetic (fictional "ACME" brand) — safe to redistribute.
  • examples/fly-demo is anonymized: fictional brand ("Northbank"), generic model-number names, genericized technology labels, and scrambled item numbers, produced by scripts/anonymize.py. It keeps the structure — dense parameters, dynamic-column spec tables, bilingual attributes — that makes it a good schema stress test, without any third party's brand or copyrighted copy.
  • HTML is the only rendering path today; PNG export needs Playwright (scripts/render_png.py).

Roadmap

Near-term work is deliberately contributor-sized — more platform adapters (TikTok Shop, eBay, Etsy, Temu), more templates (comparison table, hero/banner, print sheet), and more UI languages via translation-memory files. Further out: upstream ingestion of messy vendor data, LLM copy generation beyond translation, an online playground, and a review-mining loop.

Full detail in ROADMAP.md; design rationale in PRD.md; release history in CHANGELOG.md.

Contributing

pip install -e ".[dev]"
python -m unittest discover -s tests -v

CI runs the suite on Python 3.9 / 3.11 / 3.12 plus a build-and-kit smoke test on every push. The architecture is made of small extension points — adding a template, a platform adapter, or an example is usually one new file. See CONTRIBUTING.md.

License

Apache-2.0 © 2026 The Letusgoshopping Authors.

About

Open-source engine that turns any brand's product data into platform-ready, multilingual commerce assets — spec cards, social creatives, detail pages, Amazon listings, Google Merchant feeds. Schema-driven, category-agnostic: one dataset → many formats × platforms.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages