Beimbet

September 28, 2026 · 5 min read

Website in Kazakh, Russian and English: how to do it right

We build trilingual websites for government agencies, contractors and online services - from the website of the Zhylyoi District Police Department to a QR menu in 19 languages. Below is what separates real multilingual support from a “translate” button, and the mistakes we learned from ourselves.

A separate URL for each language

The most common mistake is switching the language with a script on one and the same page. Search engines index URLs, not the state of a button: they see one version, usually the default one, and the Kazakh or English version never makes it into search results.

The right way is a separate URL for each language: /kk, /ru, /en or subdomains. Then each version is indexed on its own, has its own title and description, and shows up for searches in its language.

hreflang: so search shows the right version

The language versions of a page are linked with hreflang markup. Each version lists every variant, including itself, plus the default variant, x-default. The language codes are kk for Kazakh, ru for Russian and en for English.

The markup has to be reciprocal: if the Kazakh page points to the Russian one, the Russian page must point back to the Kazakh one, or the search engine ignores the link. We keep the list of language URLs in a single function and use it for both the pages and sitemap.xml, so the two sets of markup never drift apart.

Translate more than the body text

  • The title and meta description of every page
  • Social previews: the title, description and image text in the page's language
  • Image alt text
  • schema.org markup: names and descriptions
  • The lang attribute on the html tag
  • Buttons, error messages, hints and emails
  • Date, number and currency formats

If any of this is left in Russian, the Kazakh version looks unfinished - to people and to search engines alike.

Your fonts need the Kazakh letters

The Kazakh alphabet has nine letters that Russian does not: ә, ғ, қ, ң, ө, ұ, ү, һ, і. Not every font includes them, and when one does, they often sit in a separate character subset, cyrillic-ext, that has to be loaded explicitly.

When a letter is missing, the browser borrows it from a system font, and a glyph of a different shape appears in the middle of a word. We have been caught by this ourselves: the Google Fonts build of the monospaced JetBrains Mono has no capital Ә, Ғ, Қ, Ң, Ұ, Һ, so on this site we had to replace it with IBM Plex Mono. The tenge sign is a similar story: in Google Fonts, ₸ lives in the extended Latin subset, latin-ext, and without it an amount shows up with an empty box.

Checking takes a minute: type “ӘҒҚҢӨҰҮҺІ әғқңөұүһі ₸” on the page in every font the site uses and see whether any character looks out of place.

Plural forms after numbers

In Russian, a noun after a number takes three forms: 1 проект, 2 проекта, 5 проектов - all of them meaning “project”. English has two: 1 project, 5 projects. In Kazakh the noun does not change after a number at all: 1 жоба, 5 жоба.

So you cannot glue a number to a word using one language's rules. Browsers and Node.js have a standard tool for this, Intl.PluralRules: it returns the right plural category for each language, while the word forms themselves live in the dictionary.

Same numbers on the server and in the browser

Russian and Kazakh use a space as the thousands separator, English uses a comma. If a site formats numbers both on the server and in the browser, standard formatting can produce different spaces: a regular space in one place and a narrow no-break space in the other. React sees mismatched markup and re-renders the block. In the end we set the separators explicitly for each language.

How to switch languages

  • The switcher leads to the same page in the other language, not to the home page
  • We detect the language from browser settings only when someone lands on the site root; on inner pages the URL itself sets the language
  • We don't redirect by IP address: search engine crawlers come from other countries and would never see the Kazakh version
  • Language names in the switcher are written in the languages themselves: Қаз, Рус, Eng

How not to lose a translation

When texts live in per-language dictionaries, it is easy to add a string in Russian and forget the Kazakh one. We check for this automatically: a test compares the structure of all dictionaries and fails if any language is missing a key or has an empty string. That way a new page never ships to production half translated.

Checklist

  • A separate URL for each language
  • Reciprocal hreflang and x-default on every page and in sitemap.xml
  • Translated title, description, social previews, alt text and markup
  • Fonts render ә, ғ, қ, ң, ө, ұ, ү, һ, і and ₸
  • Plural forms follow each language's rules
  • The switcher leads to the same page
  • No redirects by IP
  • An automated check that no language falls behind

Contact

Have a project? Let's talk

Message us on TelegramMessage us on WhatsApp

The founder answers personally.