გორა.
AI-translation · draft (awaiting native review)
ჩანაწერი · 18 მაისი, 2026 · 9 წუთი წასაკითხი

Hreflang × subdomain × subdirectory: რა ავირჩიოთ

აპრილში ერთ-ერთ პროექტზე hreflang-ი დავხვეწე — სამი ლოკალი: en, ka, lt. ტეგები Next.js metadata-ს მეშვეობით head-ში გავწერე, ხელით შევამოწმე ათობით გვერდზე, რამდენიმე URL სხვადასხვა IP-დან ინკოგნიტოში გავხსენი. ყველაფერი სწორად ჩანდა: ქართველი ხედავდა ka-ს, ლიტველი — lt-ს, დანარჩენი მსოფლიო — en-ს. დავხურე დავალება, შემდეგზე გადავერთე.

ორი კვირის შემდეგ ვხსნი Google Search Console-ს. International Targeting-ის ნაწილი წითლად ანათებს: "Return tag missing" 60 URL-ზე. Hreflang-ტეგები en-დან ka-ზე და lt-ზე მიუთითებენ, მაგრამ უკუ-ლინკებს გვერდების ნაწილი არ აძლევს. Google ასეთ კავშირებს ორივე მხრიდან უგულებელყოფს — ანუ ჩემი hreflang-ის ნახევარი მისთვის უბრალოდ არ არსებობს. და მთელი ეს დრო საიტი აშშ-ის მომხმარებლებს, რომლებიც ინგლისურად ეძებდნენ, ka-ვერსიას უჩვენებდა.

მრავალენოვანი SEO ცალკე ქვესისტემაა, საკუთარი ფაილებით, საკუთარი შემოწმებებით, საკუთარი URL-გენერაციის ლოგიკით. და გადაწყვეტილება URL-ის სტრუქტურის შესახებ — სად მოვათავსოთ ლოკალი, დომენში, ქვედომენში თუ ფოლდერში — ერთხელ მიიღება, საწყის ეტაპზე. შემდგომ შეცვლა — ეს 301-რედირექტი, sitemap-ის მიგრაცია, ახალი რეგისტრაცია GSC-ში, მინიმუმ ნახევარი წელი პოზიციების აღსადგენად. უკან თამაშის გადათამაშება თითქმის შეუძლებელია.

ამ პოსტში — სამი URL-სტრატეგია, როგორ ურთიერთქმედებენ ისინი hreflang-თან და რა ავირჩიე hiregora.com-სთვის.


Hreflang — რა არის ეს

Hreflang არის სიგნალი Google-სთვის: "აი ეს გვერდი ამ ენაზე ამ ქვეყნისთვისაა". არაფერი მეტი. არ არის რანჟირების ფაქტორი პირდაპირ, არ არის მაგია — უბრალოდ მეტამონაცემები, რომლებიც Google-ს ეხმარება გაიგოს, თქვენი 3-4 ენოვანი ვერსიიდან რომელი უჩვენოს კონკრეტულ მომხმარებელს.

ფორმატი სტანდარტულია:

<link rel="alternate" hreflang="ru" href="https://example.com/ru/page" />
<link rel="alternate" hreflang="en" href="https://example.com/en/page" />
<link rel="alternate" hreflang="x-default" href="https://example.com/page" />

დასადებად სამი ადგილია: გვერდის <head>-ში, sitemap.xml-ში როგორც <xhtml:link>, ან HTTP-სათაურში Link (არა-HTML ფაილებისთვის, როგორიცაა PDF). მე head-ში ვდებ და sitemap-ში ვადუბლირებ. დუბლირება დაზღვევაა: თუ გვერდზე JS-მა head-ის რენდერინგი დაამტვრია, sitemap მაინც ასწორებს სურათს Google-სთვის.

დაფარვა — ორ დონეზე. ან წმინდა ენა (en, ru, de) — მუშაობს ყველა ქვეყნისთვის, სადაც ამ ენაზე ლაპარაკობენ. ან ენა პლუს რეგიონი (en-US, en-GB) — ზუსტი მიბმა ქვეყანასთან. თუ კონტენტი ერთია ყველა ინგლისურენოვანისთვის — საკმარისია en. თუ რეალურად სხვადასხვა ფასები გაქვს აშშ-სა და ბრიტანეთისთვის — გჭირდება en-US და en-GB ცალკე გვერდებად.

x-default — fallback-ი. როცა მომხმარებელი არცერთ გამოცხადებულ hreflang-კომბინაციას არ ერგება, Google ამ ვერსიას უჩვენებს. ჩვეულებრივ ისმება ძირითად ლოკალზე ან სპეციალურ language picker გვერდზე.

მთავარია: hreflang-ი რანჟირებაზე პირდაპირ არ მოქმედებს. ის გავლენას ახდენს იმაზე, რომელ ვერსიას დაინახავს მომხმარებელი. ხედავს თავის ვერსიას — 3 წამში არ მიდის, ქცევითი სიგნალები კარგია, პოზიციები არაპირდაპირ იზრდება. დამახინჯებული hreflang = ცუდი UX = ცუდი ქცევითი სიგნალები = პოზიციები ქვემოთ.


URL-ის სამი სტრატეგია

URL-ის შესახებ გადაწყვეტილება hreflang-ის კონფიგურაციამდე მიიღება. ლოკალის სამ ადგილზე დადება შეიძლება: თვით დომენში, ქვედომენში, ფოლდერში. თითოეული ვარიანტი hreflang-თან მუშაობს, მაგრამ სხვადასხვაგვარად ურთიერთქმედებს დომენის ავტორიტეტთან, ინდექსაციასთან და ინფრასტრუქტურასთან.

ccTLD — ცალკე დომენი ქვეყანაზე

სტრუქტურა: example.de, example.fr, example.com.br. თითოეულ ქვეყანას აქვს თავისი დომენი ეროვნული დაბოლოებით.

დადებითი მხარეები სერიოზულია. ccTLD ყველაზე ძლიერი გეო-სიგნალია. .de ეს გერმანიაა, ვარიანტების გარეშე, GSC-ში არანაირი კონფიგურაცია არ სჭირდება. დომენის რეპუტაცია გროვდება per-country: ბმულები გერმანული საიტებიდან example.de-ზე გერმანულ ვერსიას აძლიერებენ, დანარჩენებზე არ ნაწილდებიან. და იურიდიულად მოსახერხებელია: ცალკე დომენი შეიძლება ადგილობრივ კომპანიაზე დარეგისტრირდეს.

უარყოფითი მხარეებიც სერიოზულია. თითოეული ccTLD ცალკე დომენია ნულიდან. არანაირი საერთო DR. თუ ძირითად example.com-ს აქვს DR 60, ახალი example.de DR 0-დან იწყებს და მის გადარხევას ბმულებით ნულიდან მოგიწევთ — მინიმუმ 6-12 თვე. პლუს ინფრა: 5 ქვეყანა ეს 5 DNS-ზონაა, 5 სერტიფიკატი, 5 ცალკე GSC-property.

როდის ავირჩიოთ: enterprise დიდი per-country კონტენტით, სხვადასხვა იურიდიული პირებით, ლოკალური გუნდებით. თუ გერმანიაში გყავს თავისი იურიდიული პირი, თავისი ფასები, თავისი გუნდი — example.de გამართლებულია. ერთი პროდუქტი ოთხ ენაზე — ზედმეტობაა.

Subdomain — ქვედომენი ლოკალზე

სტრუქტურა: de.example.com, fr.example.com, en.example.com. ლოკალი ქვედომენშია.

დადებითი მხარეები. ტექნიკური იზოლაცია. თითოეული ქვედომენი თავის სერვერზე, თავის CMS-ზე, თავის სტეკზე შეიძლება დაჯდეს. მოსახერხებელია, როცა de-ს გერმანული გუნდი ეწევა WordPress-ზე, ხოლო en-ს — სხვა გუნდი Next.js-ზე. და შემდეგ ccTLD-ში მიგრაცია იოლია: 301-რედირექტი de.example.com-დან example.de-ზე და ავტორიტეტის ნაწილი გადავა.

უარყოფითი მხარეები. Google-ი default-ად თითოეულ ქვედომენს ცალკე საიტად მიიჩნევს. DR ძირითადი example.com-დან de.example.com-ზე სრულად არ გადადის — გადადის ნაწილობრივ, მაგრამ არა ისე, როგორც ფოლდერიდან. თუ 2 წელი ჩადევი example.com-ის გადარხევაში DR 50-მდე — de.example.com 20-30-ის რაიონში დაიწყებს. პლუს GSC მოითხოვს თითოეული ქვედომენის ცალკე რეგისტრაციას, როგორც property-ის.

როდის ავირჩიოთ: როცა ენობრივ ვერსიებს რეალურად სხვადასხვა ტექნიკური სტეკი, სხვადასხვა გუნდი, სხვადასხვა გამოშვების ციკლი აქვს. ან როცა მომავალში ccTLD-ში მიგრაცია იგეგმება. ან ცალკე პროდუქტისთვის იმავე ბრენდის ქვეშ — ჩემთან ასეა seo.hiregora.com-თან: ეს არ არის ენა, ეს ცალკე ხელსაწყოა, თავისი კოდბაზით.

Subdirectory — ფოლდერი ლოკალზე

სტრუქტურა: example.com/de/, example.com/fr/, example.com/en/. ლოკალი უბრალოდ პათის პირველი სეგმენტია.

დადებითი მხარეები. ერთი დომენი, ერთი დომენის ავტორიტეტი, ყველაფერი ჯამდება. ბმული example.com/de/page-ზე მთელ დომენს აძლიერებს, რუსული და ინგლისური ვერსიების ჩათვლით. ერთი GSC-property, ერთი ანალიტიკა, ერთი SSL, ერთი CDN. ადმინისტრირება ბევრად იოლია. მთელი კონტენტი ერთ დომენ-ერთეულზე მუშაობს.

უარყოფითი მხარეები. საერთო ინფრა — იგივე უპირატესობა და ნაკლი ერთდროულად. ძირითადი საიტი ჩამოვარდა — მთელი მრავალენოვანი საიტი ჩამოვარდა. ლოკალურ გუნდს მისი ფოლდერისთვის ცალკე წვდომის მიცემა შეუძლებელია. მთავარი შეზღუდვა: გეო-ტარგეტინგი GSC-ში მხოლოდ domain-wide კონფიგურირდება. შეუძლებელია გითხრა "მთელი /de/ გერმანიაზე ტარგეტდება, ხოლო /en/ — აშშ-ზე". მხოლოდ რეგიონიანი hreflang-ით — მუშაობს, მაგრამ უფრო სუსტად, ვიდრე ccTLD-სიგნალი.

როდის ავირჩიოთ: ერთიანი პროდუქტი რამდენიმე ენაზე, ერთიანი გუნდი, ერთიანი სტეკი. დომენის DR ფასეულია და მისი გადანაწილება არ გინდა. ინფრასტრუქტურული სიმარტივე ტექნიკურ იზოლაციაზე უფრო მნიშვნელოვანია. 10-დან 9 SaaS / კონტენტ-პროექტში ეს სწორი არჩევანია.



რა ავირჩიე მე

hiregora.com-სთვის — subdirectory: /en, /ka, /lt და ფესვი რუსული ვერსიისთვის. ასე გადავწყვიტე.

ერთი პროდუქტი, ერთი მფლობელი, ერთი სტეკი — Next.js 15. ერთი კონტენტ-გუნდი (ეს მე ვარ). არანაირი ლოკალური იურიდიული პირი, არანაირი სხვადასხვა ფასი. ტიპიური კონფიგურაცია, სადაც subdirectory ყველა ფრონტზე იგებს.

დომენის DR ფასეულია — ბოლო ნახევარი წელია ვარხევ მას და ნებისმიერ ენაზე თითოეული სტატია საერთო ციფრზე მუშაობს. რომ გამეთიშა ენები ქვედომენებში, თითოეული ცალკე უნდა გადამერხია — მინიმუმ წელი იმავე მოთხოვნებზე პოზიციების აღსადგენად.

Cross-locale ბმულები. ხშირად ვაკავშირებ რუსულ პოსტს ინგლისურთან — მომხმარებელი ხედავს "available in English" და გადადის en-ვერსიაზე. როცა ორივე ერთ ფოლდერშია, ეს უბრალოდ <Link href="/en/writings/..."> სხვა დომენზე გასვლის გარეშე. ანალიტიკაც ერთია, სესია ენის გადართვისას არ წყდება.

Subdomain-ს მე მხოლოდ seo.hiregora.com-ისთვის ვიყენებ — მაგრამ ეს უკვე არ არის ენა, ეს ცალკე პროდუქტია. SEO-ჩეკერი თავის კოდბაზაზე ცხოვრობს, სხვა სტეკით. ამიტომ ქვედომენი გამართლებულია: ტექნიკური იზოლაცია საჭიროა, ხოლო DR ნაწილობრივ ჯამდება საერთო მშობელი დომენის ხარჯზე.

რომ ხვალ გადავწყვიტო hiregora.de-ის გაკეთება ლოკალური გერმანული გუნდით — მაშინ ccTLD. მაგრამ ეს ჰიპოთეზაა 2027-ისთვის. ახლა — ფოლდერები.


იმპლემენტაცია Next.js 15-ში

Next.js 15-ში app router-ით ეს ყველაფერი დინამიური სეგმენტით app/[lang]/ იწყობა. ფოლდერების სტრუქტურა URL-ის სტრუქტურას ირეკლავს:

app/
  [lang]/
    page.tsx              → /, /en, /ka, /lt
    writings/
      page.tsx            → /writings, /en/writings, ...
      [slug]/
        page.tsx          → /writings/foo, /en/writings/foo, ...

Middleware იჭერს მოთხოვნებს, ამოწმებს პათის პირველ სეგმენტს და წყვეტს, არის თუ არა იქ ვალიდური ლოკალი. თუ არ არის — ენას Accept-Language-ით ადგენს, არჩეული ლოკალით cookie-ს ბაჯნებს და რედირექტს აკეთებს. ერთი middleware, ერთი ჭეშმარიტების წყარო, ყველა გვერდზე მუშაობს.

generateStaticParams თითოეული გვერდისთვის აბრუნებს ყველა ლოკალის მასივს — [{lang: 'ru'}, {lang: 'en'}, {lang: 'ka'}, {lang: 'lt'}]. ეს იძლევა სტატიკურ გენერაციას: ბილდზე Next.js თითოეული გვერდის 4 ვერსიას აწყობს ცალკე HTML-ფაილებად. არანაირი SSR runtime-ზე, არანაირი დატვირთვა სერვერზე — უბრალოდ სტატიკა, რომელსაც CDN ანაწილებს.

Hreflang-ტეგებს გენერირებს helper buildAlternates() lib/seo.ts-დან. იღებს მიმდინარე პათს ლოკალის გარეშე — აბრუნებს ობიექტს Next.js metadata API-სთვის:

alternates: {
  canonical: 'https://hiregora.com/writings/foo',
  languages: {
    'ru': 'https://hiregora.com/writings/foo',
    'en': 'https://hiregora.com/en/writings/foo',
    'ka': 'https://hiregora.com/ka/writings/foo',
    'lt': 'https://hiregora.com/lt/writings/foo',
    'x-default': 'https://hiregora.com/writings/foo',
  },
}

Next.js თვითონ ბაჯნებს ამას <head>-ში სწორ <link rel="alternate">-ად. არანაირი ხელით ჩასმა, არანაირი გამოტოვებული გვერდი — რადგან ეს metadata-ს ნაწილია, რომელიც თითოეული რაუტისთვის ავტომატურად გენერირდება.

Sitemap-ს ცალკე route handler-ით ვაგენერირებ app/sitemap.xml/route.ts-ში. თითოეული გვერდისთვის ის ერთ URL-ს კი არ აძლევს, არამედ ბლოკს 4 ლოკალისგან <xhtml:link rel="alternate" hreflang="..."> შიგნით. ეს დაზღვევაა: თუ head-ში რამე ჩამოვარდა, sitemap მაინც ასწორებს Google-სთვის ლოკალებს შორის კავშირების სურათს.


ყველაზე ხშირი შეცდომა — return tags

ეს არის ის წითელი ნივთი, რომლითაც პოსტი დავიწყე. და ეს არის შეცდომა ნომერი ერთი hreflang-ის კონფიგურაციებში, რომელიც ყოველ მეორე პროექტზე მინახავს.

წესი მარტივია და განხილვას არ ექვემდებარება. თუ გვერდი A მიუთითებს გვერდ B-ზე hreflang-ის მეშვეობით — გვერდი B ვალდებულია უკან მიუთითოს გვერდ A-ზე. ამას ჰქვია reciprocal linking, და Google მას მკაცრად ამოწმებს. თუ B არ მიუთითებს A-ზე — Google ორივე ბმულს უგულებელყოფს. არა ერთს, ორივეს.

მაგალითი. ru-გვერდზე /writings/foo დგას hreflang-ტეგები: ru → ru/foo, en → en/foo, ka → ka/foo, lt → lt/foo. ვხსნი en/foo-ს და ვამოწმებ — იქაც ოთხივე უნდა იდგას, ru/foo-ზე ბმულის ჩათვლით. თუ en/foo-ში მითითებულია მხოლოდ en და ka — კავშირი en↔ru გატეხილია, Google მას გადაყრის და რუსულზე ძიებისას ჩემი ru-გვერდი სწორ სიგნალს ვერ მიიღებს.

საიდან ჩნდება პრაქტიკაში ასეთი გატეხილი კავშირები. ყველაზე ხშირი მიზეზი — დინამიური გენერაცია საერთო წყაროს გარეშე. en-გვერდებზე ერთი ფუნქცია გამოიყენება hreflang-ის გენერაციისთვის, ka-ზე — სხვა (მაგალითად, კოპიპასტა, რომელიც ვიღაცამ განახლება დაავიწყდა). ისინი იშლება და ტესტები ამას ვერ იჭერენ, რადგან თითოეული გვერდი ცალკე ვალიდურია.

მკურნალობს ერთი helper-ით, რომელიც hreflang-ბლოკს ნებისმიერი ლოკალისთვის ერთი და იმავე შესასვლელით აგენერირებს — ლოკალის გარეშე პათით. თუ შესასვლელი პარამეტრი ერთია და ფუნქცია ერთია, ყველა ლოკალი ერთსა და იმავე hreflang-ბმულების ბლოკს გასცემს. მაშინ reciprocal linking აღარ არის წესი, რომელიც უნდა გახსოვდეს, არამედ არქიტექტურის შედეგია.

შემოწმება — GSC International Targeting-ის მეშვეობით, კვირაში ერთხელ. იქ ჩანს: რამდენი ბმული იპოვა Google-მა, რამდენი მათგანი არის გატეხილი, რომელ URL-ებზეა პრობლემა. ამ ანგარიშის გარეშე პრობლემებზე მხოლოდ მაშინ შეიტყობ, როცა პოზიციები დაიწევს.


x-default — როდის გჭირდება

x-default — ცალკე hreflang-ტეგი იმ მომხმარებლებისთვის, რომლებიც არცერთ გამოცხადებულ ენობრივ კომბინაციას არ ერგებიან. მაგალითად, გაქვს en, ru, ka, lt. შემოდის მომხმარებელი იაპონიიდან ბრაუზერში იაპონურით. Google უყურებს: en — არის, ru — არ არის, ka — არ არის, lt — არ არის. იაპონური არ გაქვს. და აქ მუშავდება x-default: Google უჩვენებს ვერსიას, რომელიც fallback-ად აქვს მონიშნული.

სად დავდოთ x-default — დამოკიდებულია პროდუქტზე. სამი ვარიანტი:

  1. ძირითად ლოკალზე. თუ ტრაფიკის 70% რუსულად ლაპარაკობს — x-default → / (რუსული ვერსია). იაპონელი დაინახავს რუსულს. იდეალური არ არის, მაგრამ მინიმუმ მუშა გვერდზე მოხვდება და არა 404-ზე ან რედირექტ-მარყუჟზე.

  2. ინგლისურ ვერსიაზე. თუ პროდუქტი საერთაშორისოა — x-default → /en/. ინგლისურენოვანი გვერდი მუშაობს როგორც უნივერსალური fallback, რადგან ინგლისურს დაახლოებით მთელი ინტერნეტის მოსახლეობა იგებს.

  3. language picker-ზე. თუ ყველა ლოკალი თანაბრად ძლიერი გაქვს და აშკარა fallback არ არსებობს — x-default → /select-language/. გვერდი, სადაც მომხმარებელი თვითონ ირჩევს ენას. ნაკლებად ლამაზია, მაგრამ უფრო პატიოსანი, ვიდრე მისთვის ru-ის თავს მოხვევა, როცა რუსული არ იცის.

ჩემთან — ვარიანტი 1: x-default → / (რუსული ვერსია). ეს ახლა კონტენტის ძირითადი ენაა და სანამ დანარჩენი ლოკალები მოცულობით არ მოეწევიან, fallback რუსულზე ლოგიკურია. როცა en-ვერსია სრულფასოვანი გახდება — x-default-ს მასზე გადავრთავ.

და კიდევ: x-default ყოველთვის ცალკე ტეგია, არა ჩვეულებრივი hreflang-ის ჩანაცვლება. ანუ ru-გვერდს უნდა ჰქონდეს hreflang="ru"-ც (რუსულენოვანებისთვის) და hreflang="x-default"-იც (როგორც fallback). ორი ტეგი ერთ გვერდზე — ეს ნორმალურია.


შეჯამება

URL-სტრუქტურის არჩევანი — ეს გადაწყვეტილებაა, რომელსაც ერთხელ იღებ, საწყის ეტაპზე. ccTLD — enterprise-ისთვის ლოკალური იურიდიული პირებით და დიდი ბიუჯეტით ინფრასტრუქტურაზე. Subdomain — როცა სტეკები ან გუნდები რეალურად სხვადასხვაა, ან როგორც შუალედური ნაბიჯი ccTLD-ისკენ. Subdirectory — დანარჩენი ყველაფრისთვის და ეს სწორი არჩევანია 10 შემთხვევიდან 9-ში.

Hreflang ნებისმიერი ვარიანტის თავზე ერთნაირად მუშაობს, მაგრამ მოითხოვს სამ რამეს: ერთ საერთო გენერატორს ყველა ლოკალისთვის (რათა reciprocal linking არ ტყდებოდეს), sitemap-ში დუბლირებას (head-ში JS-ჩამოვარდნებისგან დაზღვევა) და x-default-ს როგორც fallback. შემოწმება — GSC International Targeting-ის მეშვეობით, კვირაში ერთხელ.

და გახსოვდეს, რომ hreflang არ არის რანჟირების შესახებ პირდაპირ. ეს არის იმაზე, რომ სწორმა ადამიანმა სწორი გვერდი დაინახოს. როცა ეს მუშაობს — ქცევითი სიგნალები კარგია. როცა გატეხილია — Google ლიტველს ru-ვერსიას უჩვენებს, ის 3 წამში მიდის და მთელი შენი SEO-ფუნდამენტი ზემოდან იშლება. დაწვრილებით ფაქტორების ზოგად სიაზე — SEO 2026-ის 30 ფაქტორი. canonical-თან ურთიერთქმედებაზე — როდის გჭირდება canonical URL. ინდექსაციის კონფიგურაციაზე — რა დავბლოკოთ robots.txt-ში.

Hreflang × subdomain × subdirectory: რა ავირჩიოთ · hiregora.com