|
28 | 28 |
|
29 | 29 | SPONSORSHIP_PATH = "/sponsorship/" |
30 | 30 | SPONSORSHIP_PUBLIC_URL = f"{SITE_URL}sponsorship/" |
| 31 | +SPONSORSHIP_DESCRIPTION = "Sponsorship for awesome-python: tiers, audience, and how to get your product in front of professional Python developers evaluating tools for production use." |
31 | 32 |
|
32 | 33 | SOURCE_TYPE_DOMAINS = { |
33 | 34 | "docs.python.org": "Built-in", |
@@ -128,6 +129,8 @@ def _website_node() -> dict: |
128 | 129 | "@id": WEBSITE_ID, |
129 | 130 | "name": "Awesome Python", |
130 | 131 | "url": SITE_URL, |
| 132 | + "inLanguage": "en", |
| 133 | + "sameAs": "https://github.com/vinta/awesome-python", |
131 | 134 | } |
132 | 135 |
|
133 | 136 |
|
@@ -164,34 +167,98 @@ def build_homepage_json_ld(entries: Sequence[TemplateEntry], total_categories: i |
164 | 167 | "url": SITE_URL, |
165 | 168 | "description": description, |
166 | 169 | "isPartOf": ISPARTOF_WEBSITE, |
| 170 | + "inLanguage": "en", |
167 | 171 | "mainEntity": _item_list_payload(entries), |
168 | 172 | }, |
169 | 173 | ], |
170 | 174 | } |
171 | 175 |
|
172 | 176 |
|
173 | | -def category_meta_description(name: str, entry_count: int, description: str) -> str: |
174 | | - count_sentence = f"Explore {entry_count} curated Python projects in {name}." |
| 177 | +def category_meta_title(name: str, parent_name: str | None = None) -> str: |
| 178 | + if parent_name: |
| 179 | + title = f"{name} for {parent_name} - Awesome Python" |
| 180 | + if len(title) <= 60: |
| 181 | + return title |
| 182 | + title = f"{parent_name}: {name} - Awesome Python" |
| 183 | + if len(title) <= 60: |
| 184 | + return title |
| 185 | + return f"{name} - Awesome Python" |
| 186 | + title = f"{name} Python Libraries - Awesome Python" |
| 187 | + if len(title) <= 60: |
| 188 | + return title |
| 189 | + return f"{name} - Awesome Python" |
| 190 | + |
| 191 | + |
| 192 | +def category_meta_description(name: str, entry_count: int, description: str, parent_name: str | None = None) -> str: |
| 193 | + target = f"{name} for {parent_name}" if parent_name else name |
| 194 | + count_sentence = f"Explore {entry_count} curated Python projects in {target}." |
175 | 195 | if description: |
176 | 196 | lead = description if description.endswith((".", "!", "?")) else f"{description}." |
177 | 197 | return f"{lead} {count_sentence}" |
178 | 198 | return f"{count_sentence} Part of the Awesome Python catalog." |
179 | 199 |
|
180 | 200 |
|
181 | | -def build_category_json_ld(name: str, url: str, description: str, entries: Sequence[TemplateEntry]) -> dict: |
| 201 | +def build_breadcrumb_json_ld(items: Sequence[tuple[str, str]]) -> dict: |
| 202 | + return { |
| 203 | + "@type": "BreadcrumbList", |
| 204 | + "itemListElement": [ |
| 205 | + { |
| 206 | + "@type": "ListItem", |
| 207 | + "position": i, |
| 208 | + "name": name, |
| 209 | + "item": url, |
| 210 | + } |
| 211 | + for i, (name, url) in enumerate(items, start=1) |
| 212 | + ], |
| 213 | + } |
| 214 | + |
| 215 | + |
| 216 | +def build_category_json_ld( |
| 217 | + name: str, |
| 218 | + url: str, |
| 219 | + description: str, |
| 220 | + entries: Sequence[TemplateEntry], |
| 221 | + breadcrumbs: Sequence[tuple[str, str]], |
| 222 | +) -> dict: |
182 | 223 | return { |
183 | 224 | "@context": "https://schema.org", |
184 | 225 | "@graph": [ |
185 | 226 | _website_node(), |
186 | 227 | { |
187 | 228 | "@type": "CollectionPage", |
188 | 229 | "@id": url, |
189 | | - "name": f"{name} Python Libraries", |
| 230 | + "name": name, |
190 | 231 | "url": url, |
191 | 232 | "description": description, |
192 | 233 | "isPartOf": ISPARTOF_WEBSITE, |
| 234 | + "inLanguage": "en", |
193 | 235 | "mainEntity": _item_list_payload(entries), |
194 | 236 | }, |
| 237 | + build_breadcrumb_json_ld(breadcrumbs), |
| 238 | + ], |
| 239 | + } |
| 240 | + |
| 241 | + |
| 242 | +def build_sponsorship_json_ld() -> dict: |
| 243 | + return { |
| 244 | + "@context": "https://schema.org", |
| 245 | + "@graph": [ |
| 246 | + _website_node(), |
| 247 | + { |
| 248 | + "@type": "WebPage", |
| 249 | + "@id": SPONSORSHIP_PUBLIC_URL, |
| 250 | + "name": "Sponsor Awesome Python", |
| 251 | + "url": SPONSORSHIP_PUBLIC_URL, |
| 252 | + "description": SPONSORSHIP_DESCRIPTION, |
| 253 | + "isPartOf": ISPARTOF_WEBSITE, |
| 254 | + "inLanguage": "en", |
| 255 | + }, |
| 256 | + build_breadcrumb_json_ld( |
| 257 | + [ |
| 258 | + ("Awesome Python", SITE_URL), |
| 259 | + ("Sponsorship", SPONSORSHIP_PUBLIC_URL), |
| 260 | + ] |
| 261 | + ), |
195 | 262 | ], |
196 | 263 | } |
197 | 264 |
|
@@ -548,14 +615,21 @@ def render_category( |
548 | 615 | group_categories: Sequence[ParsedSection] | None = None, |
549 | 616 | ) -> None: |
550 | 617 | page_dir.mkdir(parents=True, exist_ok=True) |
551 | | - category_description = category_meta_description(category["name"], len(entries), category["description"]) |
| 618 | + parent_name = parent_category["name"] if parent_category else None |
| 619 | + category_title = category_meta_title(category["name"], parent_name) |
| 620 | + category_description = category_meta_description(category["name"], len(entries), category["description"], parent_name) |
| 621 | + breadcrumbs = [("Awesome Python", SITE_URL)] |
| 622 | + if parent_category: |
| 623 | + breadcrumbs.append((parent_category["name"], category_public_url(parent_category))) |
| 624 | + breadcrumbs.append((category["name"], category_url)) |
552 | 625 | category_json_ld = json.dumps( |
553 | | - build_category_json_ld(category["name"], category_url, category_description, entries), |
| 626 | + build_category_json_ld(category_title.removesuffix(" - Awesome Python"), category_url, category_description, entries, breadcrumbs), |
554 | 627 | ensure_ascii=False, |
555 | 628 | ).replace("</", "<\\/") |
556 | 629 | (page_dir / "index.html").write_text( |
557 | 630 | tpl_category.render( |
558 | 631 | category=category, |
| 632 | + category_title=category_title, |
559 | 633 | category_url=category_url, |
560 | 634 | category_description=category_description, |
561 | 635 | entries=entries, |
@@ -607,7 +681,11 @@ def render_category( |
607 | 681 | hero_stats.append(f"{repo_stars}+ stars on GitHub") |
608 | 682 | hero_stats.append(f"Updated {build_date.strftime('%B %d, %Y')}") |
609 | 683 | (sponsorship_dir / "index.html").write_text( |
610 | | - tpl_sponsorship.render(hero_stats=hero_stats), |
| 684 | + tpl_sponsorship.render( |
| 685 | + hero_stats=hero_stats, |
| 686 | + sponsorship_description=SPONSORSHIP_DESCRIPTION, |
| 687 | + sponsorship_json_ld=json.dumps(build_sponsorship_json_ld(), ensure_ascii=False).replace("</", "<\\/"), |
| 688 | + ), |
611 | 689 | encoding="utf-8", |
612 | 690 | ) |
613 | 691 |
|
|
0 commit comments