8 Dilli Uygulamamı Next.js 16’ya Taşıdım: Google Search Console Neden Çıldırdı?
Merhaba geliştiriciler! Bugün sizlere, sekiz farklı dilde hizmet veren kapsamlı bir web uygulamamı Next.js 16’ya taşıma sürecimde yaşadığım zorlukları ve özellikle Google Search Console (GSC) ile olan “kavgalarımı” anlatacağım. Modern web geliştirmenin sunduğu yenilikleri kucaklarken, çok dilli SEO’nun inceliklerini göz ardı etmenin ne gibi sonuçlar doğurabileceğini kendi tecrübelerimle aktaracağım. Bu makale, benzer bir geçiş yapmayı düşünen veya mevcut çok dilli Next.js projelerinde SEO sorunları yaşayan herkes için değerli bilgiler sunmayı amaçlamaktadır.
Neden Next.js 16? Çok Dilli Bir Uygulama İçin Yeni Ufuklar
Uygulamamızın eski altyapısı, yıllar içinde biriken teknik borçlar ve performans darboğazları nedeniyle sürdürülemez hale gelmişti. Yeni nesil web standartlarına uyum sağlamak, geliştirici deneyimini iyileştirmek ve son kullanıcıya daha hızlı, daha dinamik bir deneyim sunmak amacıyla Next.js 16’ya geçiş kararı aldık.
App Router ve Sunucu Bileşenlerinin Cazibesi
Next.js 16 ile gelen App Router ve Sunucu Bileşenleri (Server Components), özellikle veri çekme (data fetching) ve performans optimizasyonu konularında devrim niteliğinde yenilikler sunuyordu. Çok dilli bir uygulamada, her dil için ayrı ayrı veri çekme ve render etme süreçlerinin optimize edilmesi büyük önem taşıyordu. Sunucu Bileşenleri, bu yükü istemciden sunucuya taşıyarak ilk yükleme sürelerini (FCP, LCP) kısaltma potansiyeli taşıyordu.
Geliştirici Deneyimini İyileştirme Hedefi
Eski yapımızda, çok dillilik yönetimi için karmaşık bir yapı kullanıyorduk. Next.js’in yerleşik i18n (uluslararasılaşma) desteği ve App Router’ın getirdiği düzenli dosya sistemi tabanlı yönlendirme, hem kod okunabilirliğini artıracak hem de yeni özelliklerin daha hızlı geliştirilmesine olanak tanıyacaktı. Bu geçişin, uzun vadede geliştirici verimliliğini önemli ölçüde artıracağına inanıyorduk.
Çok Dillilik Yönetimi: Eski Yapıdan Yeniye Geçiş
Uygulamamızın sekiz dili desteklemesi, taşıma sürecinin en kritik ve karmaşık yönlerinden biriydi. Eski sistemde kullandığımız yaklaşımlar ile Next.js 16’nın sunduğu çözümler arasında ciddi farklılıklar vardı.
Eski Yapıda i18n Yaklaşımı
Önceki altyapımızda, çok dillilik genellikle istemci tarafında, URL parametreleri veya alt alan adları (subdomain) ile yönetiliyordu. Örneğin, example.com/en/page veya en.example.com/page gibi yapılar kullanıyorduk. Dil dosyaları, uygulamanın başlangıcında yükleniyor ve React Context API aracılığıyla bileşenlere aktarılıyordu. Bu yaklaşım, ilk yüklemede tüm dil dosyalarının indirilmesine neden olabiliyor ve SEO açısından bazı zorluklar çıkarıyordu. Özellikle arama motorlarının her dil sürümünü doğru bir şekilde dizinlemesi için özel önlemler almak gerekiyordu.
Next.js 16 ile i18n Entegrasyonu
Next.js 16 ile birlikte App Router, çok dillilik için daha esnek ve güçlü bir yapı sunuyor. next.config.js dosyası üzerinden i18n yapılandırması, alt dizin (subpath) veya alan adı (domain) tabanlı dil yönlendirmesini kolaylaştırıyor. Bizim tercihimiz, /[lang]/ şeklinde alt dizin tabanlı bir yapıya geçmek oldu (örneğin, /tr/hakkimizda, /en/about-us).
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
i18n: {
locales: ['en', 'tr', 'de', 'fr', 'es', 'it', 'pt', 'nl'],
defaultLocale: 'en',
localeDetection: false, // Manuel dil tespiti için false
},
// ... diğer ayarlar
};
module.exports = nextConfig;
Bu yapılandırma, her dil için ayrı bir sayfa yolu oluşturmayı ve sunucu tarafında dilin kolayca tespit edilmesini sağlıyordu. Ayrıca, dil dosyalarını dinamik olarak yüklemek için react-i18next veya benzeri kütüphaneleri Sunucu Bileşenleri ve İstemci Bileşenleri arasında entegre etmek gerekiyordu.
Taşıma Süreci ve İlk Başarısızlıklar
Taşıma süreci, tahmin ettiğimizden çok daha fazla teknik zorlukla doluydu. Özellikle eski kod tabanının modern Next.js yapısına uyarlanması zaman aldı.
Bileşenleri Yeniden Yazma ve Adaptasyon
Uygulamamızın yüzlerce bileşeni vardı ve bunların çoğunu Next.js 16'nın Sunucu Bileşenleri ve İstemci Bileşenleri ayrımına göre yeniden düzenlememiz gerekti. Hangi bileşenin sunucuda, hangisinin istemcide çalışması gerektiğine karar vermek, performans ve etkileşim dengesini kurmak kritikti. use client direktifi, bu ayrımı yaparken kilit rol oynadı.
Veri Çekme Stratejileri ve Önbellekleme
Eski sistemde API çağrıları genellikle istemci tarafında yapılıyordu. Next.js 16 ile birlikte, Sunucu Bileşenlerinde fetch API'sinin doğrudan kullanılması ve otomatik önbellekleme yetenekleri, veri çekme stratejimizi tamamen değiştirdi. Ancak bu yeni yaklaşım, bazı durumlarda beklenmedik önbellekleme sorunlarına yol açtı ve güncel verilerin doğru bir şekilde gösterilmesini engelledi.
Google Search Console'un Çığlıkları: Sorun Ne?
Uygulamayı Next.js 16'ya taşıyıp canlıya aldıktan sonra, Google Search Console'dan gelen bildirimler adeta bir çığlık gibiydi. Beklediğimizin aksine, GSC'deki performans metrikleri düşüşe geçmiş, dizinleme sorunları baş göstermişti.
Dizinleme Sorunları ve Sayfa Sayısında Düşüş
GSC'de "Dizinlenen Sayfalar" grafiği hızla düşüşe geçmişti. Yeni URL yapılandırmamızın (örneğin, /tr/sayfa yerine /sayfa veya farklı bir dil yapısı) arama motorları tarafından doğru bir şekilde algılanmadığı açıktı. Birçok sayfa "Taranmadı" veya "Dizinlenmedi" olarak işaretleniyordu. Bu, uygulamanın arama motoru görünürlüğünün ciddi şekilde zarar gördüğü anlamına geliyordu.
Yinelenen İçerik Uyarıları
En can sıkıcı sorunlardan biri de "Yinelenen İçerik" uyarılarıydı. GSC, farklı dil sürümlerini (örneğin, /tr/hakkimizda ve /en/about-us) veya hatta dil içindeki farklı URL varyasyonlarını (örneğin, /tr/hakkimizda ve /hakkimizda) ayrı ayrı veya yinelenen içerik olarak algılıyordu. Bu durum, arama motorlarının hangi sayfanın "ana" sürüm olduğunu belirlemesini zorlaştırıyor ve sıralamamızı olumsuz etkiliyordu.
Hreflang Hataları ve Yanlış Dil Tespiti
Çok dilli uygulamalar için hayati önem taşıyan hreflang etiketlerinde de sorunlar yaşıyorduk. GSC, hreflang etiketlerinin yanlış uygulandığını, karşılıklı referansların eksik olduğunu veya geçersiz dil kodları kullanıldığını belirtiyordu. Bu da Google'ın kullanıcıya doğru dildeki sayfayı sunmasını engelliyor ve uluslararası SEO performansımızı baltalıyordu.
Kök Nedeni Araştırması: i18n ve SEO Kesişimi
GSC'nin çığlıkları üzerine detaylı bir kök neden araştırmasına giriştik. Sorunların temelinde, Next.js 16'nın yeni i18n yapısı ile geleneksel SEO prensiplerini doğru bir şekilde birleştiremememiz yatıyordu.
Hreflang Etiketlerinin Önemi ve Yanlış Kullanımı
hreflang etiketleri, arama motorlarına bir sayfanın farklı dil veya bölge varyasyonlarını bildirmek için kullanılır. Örneğin:
Bizim durumumuzda, bu etiketleri ya hiç eklememiş ya da yanlış bir şekilde eklemiştik. Özellikle dinamik rotalar için hreflang etiketlerini doğru bir şekilde oluşturmak, Next.js'in Sunucu Bileşenleri yapısında ekstra dikkat gerektiriyordu. Her sayfa için tüm dil varyasyonlarını manuel olarak eklemek yerine, dinamik olarak oluşturulacak bir yapıya ihtiyacımız vardı.
Canonical URL'lerin Karmaşası
canonical etiketleri, yinelenen içerik sorunlarını çözmek için kullanılır ve arama motorlarına bir sayfanın tercih edilen (ana) URL'sini bildirir. Next.js 16'da, özellikle locale (dil) parametresiyle çalışan dinamik rotalarda, doğru canonical URL'yi belirlemek karmaşık hale gelebiliyordu. Örneğin, /tr/hakkimizda sayfası için canonical URL'nin /tr/hakkimizda olması gerekirken, yanlışlıkla /hakkimizda veya başka bir dilin URL'si olarak ayarlanmış olabiliyordu.
Dinamik Rota ve Dil Entegrasyonu
Next.js App Router'ın dinamik rotaları ([slug], [...slug]) ile dil parametrelerini ([lang]) birleştirmek, URL yapısını ve dolayısıyla SEO'yu doğrudan etkiliyordu. Örneğin, app/[lang]/[category]/[slug]/page.js gibi bir yapı kullanırken, her dil için benzersiz ve doğru URL'lerin oluşturulduğundan emin olmak gerekiyordu. Aksi takdirde, arama motorları aynı içeriği farklı URL'lerde görerek yinelenen içerik olarak işaretleyebiliyordu.
Çözüm Yolları ve Uygulanan Stratejiler
Sorunları tespit ettikten sonra, GSC'nin çığlıklarını susturmak ve SEO performansımızı geri kazanmak için kapsamlı bir strateji geliştirdik.
Doğru Hreflang Uygulaması
Her sayfa için tüm dil varyasyonlarını içeren hreflang etiketlerini bölümüne dinamik olarak ekledik. Bunu, Next.js'in generateMetadata fonksiyonunu kullanarak veya bir layout bileşeni içinde Head bileşeni ile gerçekleştirdik.
// app/[lang]/[slug]/page.js (veya layout.js içinde)
import { getDictionary } from '@/lib/dictionaries'; // Dil dosyalarını çeken bir fonksiyon
import { Metadata } from 'next';
export async function generateMetadata({ params }): Promise {
const { lang, slug } = params;
const dictionary = await getDictionary(lang); // Dil dosyasını yükle
const alternatveUrls = {
canonical: https://example.com/${lang}/${slug},
languages: {
'en-US': https://example.com/en/${slug},
'tr-TR': https://example.com/tr/${slug},
// ... diğer diller
'x-default': https://example.com/en/${slug}, // Varsayılan dil
},
};
return {
title: dictionary.pageTitles[slug], // Dinamik başlık
description: dictionary.pageDescriptions[slug], // Dinamik açıklama
alternates: alternatveUrls,
};
}
Bu yaklaşım, her sayfa için doğru hreflang ve canonical etiketlerinin otomatik olarak oluşturulmasını sağladı.
Canonical URL'lerin Kesinleştirilmesi
Her sayfanın kendi dil ve yoluna uygun canonical URL'sini doğru bir şekilde ayarladık. Bu, Next.js'in metadata API'si ile kolayca yönetilebiliyor. Özellikle dil seçimi olmayan bir varsayılan URL'ye sahipsek (örneğin, example.com/about-us), bu sayfanın da diğer dil varyasyonlarına hreflang ile referans vermesi ve kendisinin canonical olarak işaretlenmesi sağlandı.
Çok Dilli Site Haritası (Sitemap) Oluşturma
Arama motorlarının tüm dil varyasyonlarını kolayca keşfetmesi için çok dilli bir site haritası (sitemap.xml) oluşturduk. Bu site haritası, her dil için ayrı bir URL listesi içermeli ve her URL için hreflang referanslarını barındırmalıdır. Next.js 16'da, app/sitemap.js dosyasını kullanarak dinamik olarak site haritası oluşturmak mümkündür.
// app/sitemap.js
import { getPosts } from '@/lib/api'; // İçerikleri çeken bir fonksiyon
const locales = ['en', 'tr', 'de']; // Desteklenen diller
export default async function sitemap() {
const posts = await getPosts(); // Tüm dillerdeki gönderileri çek
const postEntries = locales.flatMap((lang) =>
posts.map((post) => ({
url: https://example.com/${lang}/blog/${post.slug},
lastModified: new Date(post.updatedAt),
alternates: {
languages: locales.reduce((acc, currentLang) => {
acc[currentLang] = https://example.com/${currentLang}/blog/${post.slug};
return acc;
}, {}),
},
}))
);
return [
{
url: 'https://example.com',
lastModified: new Date(),
alternates: {
languages: locales.reduce((acc, lang) => {
acc[lang] = https://example.com/${lang};
return acc;
}, {}),
},
},
...postEntries,
];
}
Bu yapı, arama motorlarının tüm dil ve sayfa varyasyonlarını eksiksiz bir şekilde taramasını ve dizinlemesini kolaylaştırdı.
Dil Yönlendirme ve Kullanıcı Deneyimi
Kullanıcıların tercih ettikleri dile otomatik olarak yönlendirilmesi için next.config.js içindeki localeDetection ayarını false yaparak manuel bir yönlendirme stratejisi izledik. Tarayıcı dilini tespit edip, henüz dil seçimi yapmamış kullanıcıları uygun dil sürümüne yönlendiren bir mekanizma kurduk. Bu, hem kullanıcı deneyimini iyileştirdi hem de arama motorlarının yanlış dil sürümünü dizinlemesini engelledi.
Dersler ve Gelecek İçin Öneriler
Bu taşıma süreci ve sonrasındaki SEO sorunları, bize çok değerli dersler öğretti.
SEO'yu En Başından Düşünmek
Herhangi bir büyük taşıma veya yeni özellik geliştirme sürecinde, SEO'nun sadece sonradan eklenecek bir şey olmadığını, projenin temel mimarisine dahil edilmesi gereken kritik bir unsur olduğunu bir kez daha anladık. Özellikle çok dilli uygulamalarda, hreflang ve canonical gibi etiketlerin doğru bir şekilde uygulanması, projenin başlangıcından itibaren planlanmalıdır.
Google Search Console'u Yakından Takip Etmek
GSC, web sitenizin arama motoru performansını izlemek için paha biçilmez bir araçtır. Herhangi bir büyük değişiklikten sonra GSC verilerini yakından takip etmek, olası sorunları erken tespit etmek ve hızlıca müdahale etmek için hayati önem taşır. "URL Denetleme" aracı, belirli URL'lerin Google tarafından nasıl görüldüğünü anlamak için çok faydalıdır.
Next.js i18n ve SEO Entegrasyonunda Dikkat Edilmesi Gerekenler
Next.js 16'nın sunduğu yeni özellikler harika olsa da, çok dilli uygulamalar için SEO entegrasyonu konusunda bazı incelikler barındırıyor. generateMetadata fonksiyonu, alternates özelliği ile hreflang ve canonical etiketlerini yönetmek için güçlü bir yol sunuyor. Ancak bu API'yi doğru bir şekilde kullanmak ve tüm sayfa tipleri için tutarlılığı sağlamak kritik.
Sonuç
8 dilli uygulamamızı Next.js 16'ya taşıma maceramız, modern web geliştirmenin getirdiği fırsatları ve beraberindeki zorlukları net bir şekilde ortaya koydu. Performans ve geliştirici deneyimi açısından büyük kazanımlar elde etsek de, çok dilli SEO'nun karmaşıklığını hafife almanın bedelini Google Search Console'dan gelen "çığlıklarla" ödedik. Ancak bu süreç, bize hreflang etiketlerinin, canonical URL'lerin ve çok dilli site haritalarının doğru uygulanmasının ne kadar kritik olduğunu öğretti. Umarım bu tecrübeler, sizin benzer projelerinizde karşılaşabileceğiniz sorunları önlemenize yardımcı olur ve SEO dostu, çok dilli Next.js uygulamaları geliştirmenize katkı sağlar. Unutmayın, iyi bir kullanıcı deneyimi kadar, arama motoru deneyimi de başarının anahtarıdır.
SSS (Sık Sorulan Sorular)
Next.js 16'da çok dilli bir uygulama için en iyi URL yapısı nedir?
Genellikle alt dizin (subpath) yapısı (example.com/en/page) önerilir. Bu yapı, Next.js'in yerleşik i18n yönlendirme sistemiyle iyi çalışır ve alan adı (domain) tabanlı yapıya göre daha kolay yönetilebilir.
Hreflang etiketlerini Next.js 16'da nasıl doğru bir şekilde ekleyebilirim?
Next.js 13 ve üzeri sürümlerde app dizini kullanıyorsanız, generateMetadata fonksiyonu içinde alternates özelliğini kullanarak hreflang etiketlerini dinamik olarak ekleyebilirsiniz. Her dil için canonical ve languages nesnelerini doğru bir şekilde yapılandırmanız gerekir.
Google Search Console'da "Yinelenen İçerik" uyarıları alıyorum, ne yapmalıyım?
Bu genellikle canonical etiketlerinin yanlış yapılandırılmasından veya hreflang etiketlerinin eksik olmasından kaynaklanır. Her sayfanın kendi diline ait URL'sini canonical olarak işaretlediğinizden ve tüm dil varyasyonlarını hreflang ile belirttiğinizden emin olun. Ayrıca, çok dilli bir site haritası gönderdiğinizden emin olun.
Next.js'de dil tespiti için localeDetection ayarını true mu false mu yapmalıyım?
localeDetection: true (varsayılan) Next.js'in tarayıcı diline göre otomatik yönlendirme yapmasını sağlar. Ancak bu, SEO için bazen sorun yaratabilir (örneğin, Googlebot'un farklı bir dildeki içeriği taramasına neden olabilir). Genellikle, localeDetection: false yaparak manuel bir dil yönlendirme mekanizması kurmak ve kullanıcıya dil seçimi sunmak daha kontrollü bir yaklaşımdır.
Çok dilli bir Next.js uygulamasında SEO performansını artırmak için başka neler yapabilirim?
* Her dil için özelleştirilmiş title ve description meta etiketleri kullanın.
* Görseller için alt etiketlerini her dilde optimize edin.
* Yerel arama motorları için yerel dizinlere kayıt olun (örneğin, Yandex için Rusya).
* Sayfa hızını (Core Web Vitals) tüm dil varyasyonları için optimize edin.
* Kullanıcıların kolayca dil değiştirebileceği görünür bir dil seçici sunun.