forked from 1b-agent/opencadstudio-upstream
fix(site): consolidate homepage search signals
This commit is contained in:
1 parent
f69f0b32be
commit
cf70d60944
3 files changed
+27
-8
No files matched your search
@@ -28,6 +28,7 @@
|
|||||||
<meta name="twitter:description" content="{{description}}" />
|
<meta name="twitter:description" content="{{description}}" />
|
||||||
<meta name="twitter:image" content="https://www.opencadstudio.com{{workspace}}" />
|
<meta name="twitter:image" content="https://www.opencadstudio.com{{workspace}}" />
|
||||||
<script type="application/ld+json">{{schema}}</script>
|
<script type="application/ld+json">{{schema}}</script>
|
||||||
|
{{website_schema}}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<a class="skip-link" href="#main">{{skip}}</a>
|
<a class="skip-link" href="#main">{{skip}}</a>
|
||||||
|
|||||||
+16
-5
@@ -18,6 +18,10 @@ def locale_path(locale):
|
|||||||
return f"/{locale}/"
|
return f"/{locale}/"
|
||||||
|
|
||||||
|
|
||||||
|
def public_path(locale):
|
||||||
|
return "/" if locale == "en-US" else locale_path(locale)
|
||||||
|
|
||||||
|
|
||||||
def load_catalogs():
|
def load_catalogs():
|
||||||
catalogs = {p.stem: json.loads(p.read_text()) for p in sorted((ROOT / "site/locales").glob("*.json"))}
|
catalogs = {p.stem: json.loads(p.read_text()) for p in sorted((ROOT / "site/locales").glob("*.json"))}
|
||||||
supported = {p.parent.name for p in (ROOT / "locales").glob("*/opencadstudio.ftl")}
|
supported = {p.parent.name for p in (ROOT / "locales").glob("*/opencadstudio.ftl")}
|
||||||
@@ -65,14 +69,14 @@ def build(output):
|
|||||||
script = "const SITE_LOCALES = " + json.dumps(list(catalogs)) + ";\n" + (ROOT / "site/site.js").read_text()
|
script = "const SITE_LOCALES = " + json.dumps(list(catalogs)) + ";\n" + (ROOT / "site/site.js").read_text()
|
||||||
(output / "site.js").write_text(script, encoding="utf-8")
|
(output / "site.js").write_text(script, encoding="utf-8")
|
||||||
js_version = hashlib.sha256(script.encode()).hexdigest()[:12]
|
js_version = hashlib.sha256(script.encode()).hexdigest()[:12]
|
||||||
alternates = '\n'.join(f'<link rel="alternate" hreflang="{lang}" href="{BASE}{locale_path(lang)}" />' for lang in catalogs)
|
alternates = '\n'.join(f'<link rel="alternate" hreflang="{lang}" href="{BASE}{public_path(lang)}" />' for lang in catalogs)
|
||||||
alternates += f'\n<link rel="alternate" hreflang="x-default" href="{BASE}/" />'
|
alternates += f'\n<link rel="alternate" hreflang="x-default" href="{BASE}/" />'
|
||||||
for locale, messages in catalogs.items():
|
for locale, messages in catalogs.items():
|
||||||
path = locale_path(locale)
|
path = public_path(locale)
|
||||||
destination = output / path.lstrip("/")
|
destination = output / locale_path(locale).lstrip("/")
|
||||||
destination.mkdir(parents=True, exist_ok=True)
|
destination.mkdir(parents=True, exist_ok=True)
|
||||||
language_links = '\n'.join(
|
language_links = '\n'.join(
|
||||||
f'<a href="{locale_path(lang)}" lang="{lang}" hreflang="{lang}" dir="auto"'
|
f'<a href="{public_path(lang)}" lang="{lang}" hreflang="{lang}" dir="auto"'
|
||||||
+ (' aria-current="page"' if lang == locale else '')
|
+ (' aria-current="page"' if lang == locale else '')
|
||||||
+ f'>{escape(labels["name"])}</a>' for lang, labels in catalogs.items()
|
+ f'>{escape(labels["name"])}</a>' for lang, labels in catalogs.items()
|
||||||
)
|
)
|
||||||
@@ -85,6 +89,11 @@ def build(output):
|
|||||||
"downloadUrl": REPO + "/releases/latest", "installUrl": BASE + "/app/",
|
"downloadUrl": REPO + "/releases/latest", "installUrl": BASE + "/app/",
|
||||||
"offers": {"@type": "Offer", "price": "0", "priceCurrency": "USD"},
|
"offers": {"@type": "Offer", "price": "0", "priceCurrency": "USD"},
|
||||||
}
|
}
|
||||||
|
website_schema = {
|
||||||
|
"@context": "https://schema.org", "@type": "WebSite",
|
||||||
|
"name": "Open CAD Studio", "alternateName": ["OpenCADStudio", "opencadstudio.com"],
|
||||||
|
"url": BASE + "/",
|
||||||
|
}
|
||||||
values = {key: escape(value) for key, value in messages.items()}
|
values = {key: escape(value) for key, value in messages.items()}
|
||||||
values.update(locale=locale, direction="rtl" if locale == "ar-SA" else "ltr",
|
values.update(locale=locale, direction="rtl" if locale == "ar-SA" else "ltr",
|
||||||
path=path, url=BASE + path, og_locale=locale.replace("-", "_"),
|
path=path, url=BASE + path, og_locale=locale.replace("-", "_"),
|
||||||
@@ -92,6 +101,8 @@ def build(output):
|
|||||||
css_version=css_version, js_version=js_version, alternates=alternates,
|
css_version=css_version, js_version=js_version, alternates=alternates,
|
||||||
languages=escape(messages["languages"].format(count=len(catalogs))),
|
languages=escape(messages["languages"].format(count=len(catalogs))),
|
||||||
language_links=language_links,
|
language_links=language_links,
|
||||||
|
website_schema=(f'<script type="application/ld+json">{json.dumps(website_schema)}</script>'
|
||||||
|
if locale == "en-US" else ""),
|
||||||
schema=json.dumps(schema, ensure_ascii=False).replace("<", "\\u003c"))
|
schema=json.dumps(schema, ensure_ascii=False).replace("<", "\\u003c"))
|
||||||
rendered = re.sub(r"\{\{(\w+)\}\}", lambda match: values[match[1]], template)
|
rendered = re.sub(r"\{\{(\w+)\}\}", lambda match: values[match[1]], template)
|
||||||
(destination / "index.html").write_text(rendered, encoding="utf-8")
|
(destination / "index.html").write_text(rendered, encoding="utf-8")
|
||||||
@@ -101,7 +112,7 @@ def build(output):
|
|||||||
(destination / "site.webmanifest").write_text(json.dumps(localized_manifest, ensure_ascii=False, indent=2) + '\n', encoding="utf-8")
|
(destination / "site.webmanifest").write_text(json.dumps(localized_manifest, ensure_ascii=False, indent=2) + '\n', encoding="utf-8")
|
||||||
for filename in ("index.html", "site.webmanifest"):
|
for filename in ("index.html", "site.webmanifest"):
|
||||||
shutil.copyfile(output / "en-US" / filename, output / filename)
|
shutil.copyfile(output / "en-US" / filename, output / filename)
|
||||||
urls = f'<url><loc>{BASE}/</loc></url>\n' + ''.join(f'<url><loc>{BASE}{locale_path(locale)}</loc></url>\n' for locale in catalogs)
|
urls = ''.join(f'<url><loc>{BASE}{public_path(locale)}</loc></url>\n' for locale in catalogs)
|
||||||
(output / "sitemap.xml").write_text('<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n' + urls + '</urlset>\n')
|
(output / "sitemap.xml").write_text('<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n' + urls + '</urlset>\n')
|
||||||
|
|
||||||
app = output / "app/index.html"
|
app = output / "app/index.html"
|
||||||
|
|||||||
+10
-3
@@ -57,7 +57,8 @@ with tempfile.TemporaryDirectory() as directory:
|
|||||||
links = [attrs for tag, attrs in page.tags if tag == 'link']
|
links = [attrs for tag, attrs in page.tags if tag == 'link']
|
||||||
assert {link['href'] for link in links if link.get('rel') == 'icon'} == {'/favicon.ico', '/favicon.png', '/favicon.svg'}
|
assert {link['href'] for link in links if link.get('rel') == 'icon'} == {'/favicon.ico', '/favicon.png', '/favicon.svg'}
|
||||||
assert {link['hreflang'] for link in links if link.get('rel') == 'alternate'} == supported | {'x-default'}
|
assert {link['hreflang'] for link in links if link.get('rel') == 'alternate'} == supported | {'x-default'}
|
||||||
assert next(link['href'] for link in links if link.get('rel') == 'canonical') == f'https://www.opencadstudio.com/{locale}/'
|
expected_path = '/' if locale == 'en-US' else f'/{locale}/'
|
||||||
|
assert next(link['href'] for link in links if link.get('rel') == 'canonical') == f'https://www.opencadstudio.com{expected_path}'
|
||||||
choices = [attrs for tag, attrs in page.tags if tag == 'a' and 'hreflang' in attrs]
|
choices = [attrs for tag, attrs in page.tags if tag == 'a' and 'hreflang' in attrs]
|
||||||
assert {choice['hreflang'] for choice in choices} == supported
|
assert {choice['hreflang'] for choice in choices} == supported
|
||||||
assert [choice['hreflang'] for choice in choices if choice.get('aria-current') == 'page'] == [locale]
|
assert [choice['hreflang'] for choice in choices if choice.get('aria-current') == 'page'] == [locale]
|
||||||
@@ -74,7 +75,7 @@ with tempfile.TemporaryDirectory() as directory:
|
|||||||
path = output / urlsplit(target).path.lstrip('/')
|
path = output / urlsplit(target).path.lstrip('/')
|
||||||
assert path.exists(), (locale, target)
|
assert path.exists(), (locale, target)
|
||||||
manifest = json.loads((output / locale / 'site.webmanifest').read_text())
|
manifest = json.loads((output / locale / 'site.webmanifest').read_text())
|
||||||
assert manifest['lang'] == locale and manifest['start_url'] == f'/{locale}/'
|
assert manifest['lang'] == locale and manifest['start_url'] == expected_path
|
||||||
for icon in manifest['icons']:
|
for icon in manifest['icons']:
|
||||||
assert (output / icon['src'].lstrip('/')).exists()
|
assert (output / icon['src'].lstrip('/')).exists()
|
||||||
if locale != 'en-US':
|
if locale != 'en-US':
|
||||||
@@ -87,7 +88,13 @@ with tempfile.TemporaryDirectory() as directory:
|
|||||||
assert icon == '/favicon.svg'
|
assert icon == '/favicon.svg'
|
||||||
assert (output / icon.lstrip('/')).read_bytes() == (ROOT / 'site/favicon.svg').read_bytes()
|
assert (output / icon.lstrip('/')).read_bytes() == (ROOT / 'site/favicon.svg').read_bytes()
|
||||||
sitemap = ET.parse(output / 'sitemap.xml')
|
sitemap = ET.parse(output / 'sitemap.xml')
|
||||||
assert len(sitemap.getroot()) == len(supported) + 1
|
locations = {url[0].text for url in sitemap.getroot()}
|
||||||
|
assert len(locations) == len(supported)
|
||||||
|
assert 'https://www.opencadstudio.com/' in locations
|
||||||
|
assert 'https://www.opencadstudio.com/en-US/' not in locations
|
||||||
assert (output / 'index.html').read_bytes() == (output / 'en-US/index.html').read_bytes()
|
assert (output / 'index.html').read_bytes() == (output / 'en-US/index.html').read_bytes()
|
||||||
|
homepage_schemas = [json.loads(value) for value in re.findall(r'<script type="application/ld\+json">(.*?)</script>', (output / 'index.html').read_text())]
|
||||||
|
website = next(schema for schema in homepage_schemas if schema['@type'] == 'WebSite')
|
||||||
|
assert website['url'] == 'https://www.opencadstudio.com/' and 'OpenCADStudio' in website['alternateName']
|
||||||
subprocess.run(['node', 'scripts/test_site.cjs', str(output / 'site.js')], cwd=ROOT, check=True)
|
subprocess.run(['node', 'scripts/test_site.cjs', str(output / 'site.js')], cwd=ROOT, check=True)
|
||||||
print(f'All {len(supported)} translations, metadata, local links, charts, manifests and icons passed')
|
print(f'All {len(supported)} translations, metadata, local links, charts, manifests and icons passed')
|
||||||
Reference in new issue
Block a user