|
1 | 1 | <script lang="ts"> |
| 2 | + import { |
| 3 | + ALIGNER_SITE_URL, |
| 4 | + SITE_AUTHOR_NAME, |
| 5 | + SITE_AUTHOR_URL, |
| 6 | + SITE_CONTACT_EMAIL |
| 7 | + } from '$lib/brand.js'; |
| 8 | + import { SITE_NAME, DEFAULT_DESCRIPTION } from '$lib/seo/metadata.js'; |
| 9 | +
|
2 | 10 | /** |
3 | | - * FAQPage JSON-LD for the visible FAQ block in `SeoSections.svelte`. |
| 11 | + * Homepage structured data: WebSite, WebApplication, and FAQPage. |
4 | 12 | * |
5 | | - * The `SoftwareApplication` schema used to live here too, but Google's docs require a real |
6 | | - * `aggregateRating` or `review` on that type — with no legitimate review data we were shipping |
7 | | - * invalid markup that Google ignores. We will add it back when there is something to rate. |
| 13 | + * WebApplication intentionally omits `aggregateRating`/`offers.review`. Google's *rich result* |
| 14 | + * for software needs a real rating, which we do not have, so this will not produce a rich |
| 15 | + * result — but the markup is valid and helps search engines and LLMs identify what the tool is |
| 16 | + * (entity resolution, AI Overviews/ChatGPT/Perplexity citation). Add a rating block here only |
| 17 | + * when there is legitimate review data. |
8 | 18 | * |
9 | 19 | * FAQ rich results are effectively restricted to well-known health/government sites since 2023 |
10 | | - * (https://developers.google.com/search/blog/2023/08/howto-faq-changes) so this markup is kept |
11 | | - * mainly for semantic coverage and ordinary snippet quality. The answer text here mirrors the |
12 | | - * visible FAQ copy on the page, which Google requires for any FAQPage markup. |
| 20 | + * (https://developers.google.com/search/blog/2023/08/howto-faq-changes) so the FAQPage block is |
| 21 | + * kept mainly for semantic coverage and AI citation. The answer text mirrors the visible FAQ |
| 22 | + * copy on the page, which Google requires for any FAQPage markup. |
13 | 23 | */ |
| 24 | + const creator = { |
| 25 | + '@type': 'Person', |
| 26 | + name: SITE_AUTHOR_NAME, |
| 27 | + url: SITE_AUTHOR_URL, |
| 28 | + email: SITE_CONTACT_EMAIL |
| 29 | + }; |
| 30 | +
|
| 31 | + const website = { |
| 32 | + '@context': 'https://schema.org', |
| 33 | + '@type': 'WebSite', |
| 34 | + name: SITE_NAME, |
| 35 | + url: ALIGNER_SITE_URL + '/', |
| 36 | + description: DEFAULT_DESCRIPTION, |
| 37 | + inLanguage: 'en', |
| 38 | + publisher: creator |
| 39 | + }; |
| 40 | +
|
| 41 | + const webApplication = { |
| 42 | + '@context': 'https://schema.org', |
| 43 | + '@type': 'WebApplication', |
| 44 | + name: SITE_NAME, |
| 45 | + url: ALIGNER_SITE_URL + '/', |
| 46 | + description: DEFAULT_DESCRIPTION, |
| 47 | + applicationCategory: 'EducationalApplication', |
| 48 | + operatingSystem: 'Any', |
| 49 | + browserRequirements: 'Requires a modern web browser with JavaScript enabled', |
| 50 | + offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' }, |
| 51 | + featureList: [ |
| 52 | + 'Word-by-word translation visualization', |
| 53 | + 'Interlinear gloss support', |
| 54 | + 'IPA tier support', |
| 55 | + 'Right-to-left script support (Hebrew, Arabic)', |
| 56 | + 'Export to PNG, SVG, PDF, and HTML', |
| 57 | + 'Shareable URLs', |
| 58 | + 'Free REST API' |
| 59 | + ], |
| 60 | + inLanguage: 'en', |
| 61 | + creator |
| 62 | + }; |
| 63 | +
|
14 | 64 | const faq = { |
15 | 65 | '@context': 'https://schema.org', |
16 | 66 | '@type': 'FAQPage', |
|
71 | 121 | <!-- JSON-LD is trusted (serialized from app constants); @html avoids nested script parsing issues --> |
72 | 122 | <!-- eslint-disable svelte/no-at-html-tags --> |
73 | 123 | <svelte:head> |
| 124 | + {@html safeJsonLd(website)} |
| 125 | + {@html safeJsonLd(webApplication)} |
74 | 126 | {@html safeJsonLd(faq)} |
75 | 127 | </svelte:head> |
0 commit comments