Anton Bohachuk
← ALL WORK

Eliza Barber

Personal site for a barber in Varna — four locales, reciprocal hreflang and structured data, bookings through Altegio.

Type
Client work
Year
2026
Duration
A week
Team
Solo
Eliza Barber
Context

A personal site for Eliza, a barber working out of Zeus Barbershop in Varna. Her clients are a mix of Bulgarians, Ukrainian and Russian speakers who have settled in the city, and visitors passing through — all searching in different languages for the same thing. The site has one job: be findable in whichever language someone types, show the work and the prices, and take a booking without a phone call.

Problem

Four languages on a five-section site is an SEO problem, not a translation problem. Each locale needs its own indexable URL, reciprocal hreflang across all four plus x-default, localized metadata and structured data that matches the business profile exactly. Get any of it wrong and three of the four languages quietly never rank. Most of the real work went into the parts a visitor never sees.

Stack

Next.js 16 on the app router, statically generated for every locale and served from Vercel — images are still optimized and resized per request, so nothing is lost by prerendering the pages. next-intl handles locale routing and messages, Tailwind carries the styling. No backend and no CMS — copy lives in per-locale JSON, and bookings open the barbershop's existing Altegio widget.

ROUTING
Request
middleware · locale negotiation
STATIC PER LOCALE
/bg
/en
/ru
/uk
hreflang + sitemap
reciprocal · x-default
JSON-LD
LocalBusiness · Person
Altegio
booking widget
TypeScriptNext.jsReactnext-intlTailwind CSSVercel
Decisions

Path-prefixed locales, no forced redirect

Every locale gets a real URL and every page is generated for all four. Language is suggested from Accept-Language but never enforced, so a link shared in Ukrainian opens in Ukrainian rather than bouncing someone to the default. Crawlers see four stable trees instead of one page behind a redirect.

Structured data, not just meta tags

LocalBusiness and Person JSON-LD carrying real opening hours and address, matching the Google Business Profile exactly. For a local service business the structured data is what produces the map card and the hours in the result — ranking is only half of being found.

Hand off booking rather than rebuild it

Bookings go through Altegio, the scheduling tool the barbershop already runs. A second calendar would have created a sync problem and a source of truth nobody trusts, so the site stays fully static and opens the widget at the booking step.

Prerender everything, optimize images anyway

The site started out server-rendered on the assumption that image resizing needed a request to hang off. It doesn't — Vercel's image pipeline runs independently of how the page was produced, so moving to static generation kept correctly sized images and dropped a render on every visit. Four locales of five sections are now four sets of prebuilt HTML.

Outcome
1 language4 locales
each indexable, with its own metadata
meta tagsreciprocal hreflang
verified against Google's own rules
SSRSSG
prerendered per locale, images still optimized

Fully static, no backend, no database — the whole site runs on a free Vercel plan and a scheduling tool the shop already paid for.

Trade-offs

hreflang is unforgiving and the defaults fought me. next-intl ships with alternateLinks enabled, which emits HTTP Link headers alongside the HTML tags — and the two disagreed on x-default until I found it. Separately, /robots.txt was returning the homepage, because the i18n middleware matched the path and tried to localize it. Neither is exotic; both fail silently, and both only surface if you actually inspect what the server sends.

Content in the repository means a price change is a commit and a deploy rather than something Eliza can do herself. Static generation makes that stricter, not looser — the copy is baked in at build time. Right for five sections, wrong for fifty, and a small CMS is what the next version needs.

Handing the booking step to Altegio also makes the end of the funnel invisible from my side. I can see who reached the button, not who finished.

Contact

Let's talk

Open to full stack roles, remote or on-site in Varna. The fastest way to reach me is email or Telegram.

ANTON BOHACHUK · VARNA, BULGARIA (EET)© 2026