fix(hosting): smart slug generation with fallback chain
Slugify now handles both domains and business names gracefully: - Domain: strip protocol/www/TLD → batirenovation-strasbourg - Business name: take first 3 meaningful words, skip filler (le, la, du, des, the, and) → boulangerie-coin - Cap at 30 chars Clients without a domain get clean slugs from their business name instead of the full title truncated mid-word. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -34,20 +34,30 @@ ALLOWED_TRANSITIONS: dict[HostedSiteStatus, list[HostedSiteStatus]] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _slugify(name: str) -> str:
|
def _slugify(name: str, max_length: int = 30) -> str:
|
||||||
"""Generate a short URL-safe slug from a business name or domain."""
|
"""Generate a short URL-safe slug from a domain or business name.
|
||||||
|
|
||||||
|
Priority: domain name (clean) > first 3 words of business name > full slug truncated.
|
||||||
|
"""
|
||||||
slug = name.lower().strip()
|
slug = name.lower().strip()
|
||||||
# Remove protocol/www if domain was passed
|
# If it looks like a domain, extract the hostname part
|
||||||
for prefix in ["https://", "http://", "www."]:
|
for prefix in ["https://", "http://", "www."]:
|
||||||
if slug.startswith(prefix):
|
if slug.startswith(prefix):
|
||||||
slug = slug[len(prefix):]
|
slug = slug[len(prefix):]
|
||||||
slug = slug.rstrip("/")
|
slug = slug.rstrip("/")
|
||||||
# Remove TLD if it looks like a domain
|
|
||||||
if "." in slug and " " not in slug:
|
if "." in slug and " " not in slug:
|
||||||
|
# Domain: remove TLD → batirenovation-strasbourg.fr → batirenovation-strasbourg
|
||||||
slug = slug.rsplit(".", 1)[0]
|
slug = slug.rsplit(".", 1)[0]
|
||||||
|
else:
|
||||||
|
# Business name: take first 3 meaningful words for brevity
|
||||||
|
words = re.sub(r"[^a-z0-9\s]", "", slug).split()
|
||||||
|
# Skip filler words
|
||||||
|
filler = {"the", "le", "la", "les", "de", "du", "des", "et", "and", "und", "die", "der", "das"}
|
||||||
|
words = [w for w in words if w not in filler][:3]
|
||||||
|
slug = " ".join(words)
|
||||||
slug = re.sub(r"[^a-z0-9\s-]", "", slug)
|
slug = re.sub(r"[^a-z0-9\s-]", "", slug)
|
||||||
slug = re.sub(r"[\s-]+", "-", slug)
|
slug = re.sub(r"[\s-]+", "-", slug)
|
||||||
return slug.strip("-")[:30]
|
return slug.strip("-")[:max_length]
|
||||||
|
|
||||||
|
|
||||||
class HostedSiteService:
|
class HostedSiteService:
|
||||||
|
|||||||
Reference in New Issue
Block a user