
Neden Contentful içeriğiniz henüz gerçekten çok dilli değil
By Robert
Neden Contentful içeriğiniz henüz gerçekten çok dilli değil
Contentful, yerel ayarları iyi yönetir. İhtiyacınız kadarını tanımlayabilir, bir yedekleme zinciri ayarlayabilir, editörde aralarında geçiş yapabilir ve her rota için doğru dili sunan bir ön yüz oluşturabilirsiniz. Çok dilli içerik için altyapı gerçekten iyidir.
Contentful'un yapmadığı şey ise içeriğinizi çevirmek.
Bu doğrudan söylendiğinde bariz görünüyor, ancak "yerel alanlar kurduk" ile "çok dilliğiz" kavramlarını karıştırmak şaşırtıcı derecede kolaydır. İkisi aynı şey değildir. Yerel alanlar bir konteynerdir. Çok dillilik, konteynerin içinde içerik olması demektir.
Contentful alanınızda Fransızca ve Almanca yerel ayarları yapılandırılmış ama bu yerel alanlardaki alanlar boşsa, ya da yer tutucu olarak İngilizce metinle doldurulmuşsa ya da site açıldığından beri kimsenin gözden geçirmediği kaba bir ilk taslakla doldurulmuşsa — çok dilli değilsiniz demektir. Çok dillilik için iskelete sahipsiniz.
Bu yazı, o boşluğu kapatmakla ilgili.
Contentful size gerçekte ne sunar
Contentful'un yerel sistemleri iyi tasarlanmıştır. Her içerik girdisi, yerel bazda alan değerlerine sahip olabilir. Varsayılan bir yerel ayarlarsınız, yedeklemeleri yapılandırırsınız ve teslimat API'niz istenildiğinde doğru yereli döner. İçerik modellemesi, farklı içerik türleri arasında karmaşık çok dilli gereksinimleri karşılayacak kadar esnektir.
Ancak sistem, çevrilmiş içeriğin nasıl girdiği konusunda tamamen tarafsızdır. Contentful, Fransızca yerel alanlarınızın profesyonel çeviriler içerip içermediğini, makine tarafından çevrilmiş metin mi olduğunu, yanlışlıkla yapıştırılmış İngilizce metin mi olduğunu ya da hiç bir şey içerip içermediğini bilmez. Sadece sizin koyduğunuzu depolar ve teslim eder.
Çeviri problemi tamamen sizin çözmeniz gereken bir konudur.
Takımlar genellikle nasıl yönetir (ve nerede aksar)
Contentful çevirisini yöneten çoğu takım birkaç kalıptan birine girer.
Manuel dışa aktarma kalıbı. Bir geliştirici Contentful’dan içerik dışa aktarır, bir çeviri ajansına veya serbest çalışana gönderir, geri gelmesini bekler, yeniden biçimlendirir ve içe aktarır. Bu, tek seferlik bir lansman için işe yarar ancak içerik değiştikçe sürdürülemez hale gelir. Kaynak yerel dildeki her güncelleme tüm döngünün yeniden yapılması anlamına gelir. Pratikte, çevrilmiş içerik hızla kaynağın gerisinde kalır ve kimsenin bunu yakalamaya zamanı olmaz.
Editör içi çeviri kalıbı. Bir editör her girdiyi açar, hedef yerel dile geçer ve alan alan manuel olarak ya da bir çeviri aracına içerik yapıştırarak çevirir. Bu doğru ama yavaştır. Ayrıca ölçeklenemez — eğer onlarca içerik türünde yüzlerce girdiniz varsa, manuel iş hacmi önemli olur.
"İdare eder" kalıbı. Çevrilmiş içerik vardır ama ilk üretildiğinden beri gözden geçirilmemiştir. Kaynak yerel dil o zamandan beri birkaç kez güncellenmiştir. Fiyatlandırma sayfanızın Fransızca versiyonu sekiz ay önce kaldırdığınız bir planı hâlâ referans gösterir. Almanca ana sayfa hâlâ eski sloganı taşır. Kimse bunu işaret etmemiştir çünkü kimse kontrol etmemiştir.
Üç kalıp da aynı temel sorunu paylaşır: çeviri, içerik iş akışının sürekli bir parçası olarak değil, tek seferlik bir görev olarak ele alınır.
Çok dilli içerik aslında ne gerektirir
Contentful'da gerçek çok dilli içerik, birlikte çalışan üç şeye ihtiyaç duyar.
Doğru başlangıç çevirisi. Her hedef dildeki her alan, doğru, uygun şekilde yerelleştirilmiş ve temel bir çeviri aracından geçirilip gözden geçirilmeden bırakılmış gibi değil, o pazar için yazılmış gibi okunan çevrilmiş içeriğe ihtiyaç duyar.
Çevirilerin güncel tutulması için bir süreç. Kaynak içerik değiştiğinde, çevrilmiş içerik de değişmelidir. Bu, çoğu ekibin hafife aldığı kısımdır. Haftada birkaç güncelleme yayınlayan, dört dil ve elli içerik türü olan bir Contentful alanında çalışan bir içerik ekibi, eğer manuel olarak yapılırsa önemli bir sürekli çeviri iş yükü ile karşı karşıyadır.
Çevirilerin güncel olmadığını bilmenin bir yolu. Contentful'un dil sistemi eskimeyi göstermez. Bir girdinin İngilizce metnini güncellerseniz ve Fransızca metni güncellemeyi unutursanız, Fransızca versiyon sessizce eski içeriği sunmaya devam eder. Bunu yakalamak için ya bir süreç ya da araçlara ihtiyacınız vardır.
PolyLingo'nun Yeri
PolyLingo'nun API'si, yapıyı koruyarak yapılandırılmış içeriği çevirir. Contentful için ilgili format JSON'dur — bir Contentful girdisinin alan değerleri çıkarılır ve API'ye gönderilir, aynı yapı korunarak çevrilmiş şekilde geri gelir.
Node.js'deki temel akış:
import PolyLingo from 'polylingo'
import { createClient } from 'contentful-management'
const poly = new PolyLingo({ apiKey: process.env.POLYLINGO_API_KEY })
const contentful = createClient({
accessToken: process.env.CONTENTFUL_MANAGEMENT_TOKEN,
})
const space = await contentful.getSpace(process.env.CONTENTFUL_SPACE_ID)
const environment = await space.getEnvironment('master')
// Çevirmek istediğiniz girdiyi alın
const entry = await environment.getEntry('your-entry-id')
// PolyLingo, bölge olmadan BCP-47 kodları kullanır (fr, de).
// Bunları Contentful yerel kimliklerinizle eşleştirin, eğer farklıysa (örneğin fr-FR, de-DE).
const localeMap = { fr: 'fr', de: 'de' } // alanınızın yerel kimliklerine uyacak şekilde ayarlayın
// Sadece İngilizce metin alanlarını çıkarın — referanslar, bağlantılar, boolean ve sayıları atlayın
const sourceFields = Object.fromEntries(
Object.entries(entry.fields)
.filter(([, value]) => typeof value['en-US'] === 'string')
.map(([key, value]) => [key, value['en-US']])
)
// Tek bir istekte Fransızca ve Almanca'ya çevirin
const result = await poly.translate({
content: JSON.stringify(sourceFields),
format: 'json',
targets: Object.keys(localeMap),
})
// Çevrilmiş değerleri Contentful yerel kimliklerini kullanarak girdiye yazın
for (const [polyLocale, translated] of Object.entries(result.translations)) {
const contentfulLocale = localeMap[polyLocale]
const parsed = JSON.parse(translated)
for (const [field, value] of Object.entries(parsed)) {
if (!entry.fields[field]) entry.fields[field] = {}
entry.fields[field][contentfulLocale] = value
}
}
await entry.update()
await entry.publish()
console.log('Girdi çevrildi ve yayımlandı.')
Tek bir API çağrısı hem Fransızca hem Almanca'yı döner. Girdi aynı betikte güncellenir ve yayımlanır.
Yerel kimlikler hakkında not: PolyLingo, bölge eki olmadan BCP-47 kodları kullanır (fr, de). Contentful alanları genellikle fr-FR veya de-DE gibi bölge nitelikli kimlikler kullanır. Yukarıdaki localeMap nesnesi, bunları hizaladığınız yerdir — Contentful alanınızın kullandığı yerel kimliklere uyacak şekilde güncelleyin.
Aynı desen Python'da da çalışır:
import os, json, requests
from contentful_management import Client
poly_key = os.environ['POLYLINGO_API_KEY']
contentful = Client(os.environ['CONTENTFUL_MANAGEMENT_TOKEN'])
space = contentful.spaces().find(os.environ['CONTENTFUL_SPACE_ID'])
environment = space.environments().find('master')
entry = environment.entries().find('your-entry-id')
# İngilizce alan değerlerini çıkar
source_fields = {
key: value.get('en-US')
for key, value in entry.fields().items()
if value.get('en-US')
}
# Fransızca ve Almanca'ya çevir
r = requests.post(
'https://api.usepolylingo.com/v1/translate',
headers={'Authorization': f"Bearer {poly_key}"},
json={
'content': json.dumps(source_fields),
'format': 'json',
'targets': ['fr', 'de'],
},
timeout=120,
)
r.raise_for_status()
translations = r.json()['translations']
# Girdiye geri yaz
for locale, translated in translations.items():
parsed = json.loads(translated)
for field, value in parsed.items():
if field in entry.fields():
entry.fields()[field][locale] = value
entry.save()
entry.publish()
print('Girdi çevrildi ve yayımlandı.')
Ölçeklendirilmiş Çeviri
Yukarıdaki örnek tek bir girdiyi ele alır. Birden fazla içerik türünde birçok girdiye sahip bir Contentful alanı için, toplu uç nokta istekte en fazla 100 öğeyi işler:
// Birden fazla girdiyi al ve tek bir toplu çağrıda çevir
const entries = await environment.getEntries({
content_type: 'blogPost',
limit: 50,
})
// PolyLingo yerel kodlarını Contentful yerel kimliklerine eşle
const localeMap = { fr: 'fr', de: 'de', es: 'es' } // alanınıza uyacak şekilde ayarlayın
const items = entries.items.map(entry => ({
id: entry.sys.id,
content: JSON.stringify(
Object.fromEntries(
Object.entries(entry.fields)
.filter(([, value]) => typeof value['en-US'] === 'string')
.map(([k, v]) => [k, v['en-US']])
)
),
format: 'json',
}))
const batch = await poly.batch({
items,
targets: Object.keys(localeMap),
})
for (const result of batch.results) {
const entry = entries.items.find(e => e.sys.id === result.id)
for (const [polyLocale, translated] of Object.entries(result.translations)) {
const contentfulLocale = localeMap[polyLocale]
const parsed = JSON.parse(translated)
for (const [field, value] of Object.entries(parsed)) {
if (!entry.fields[field]) entry.fields[field] = {}
entry.fields[field][contentfulLocale] = value
}
}
await entry.update()
await entry.publish()
}
Elli girdi, üç dil, tek bir toplu istek.
Çevirileri Güncel Tutmak
Yukarıdaki betikler talep üzerine çalıştırılabilir veya yayın iş akışınıza entegre edilebilir. Yaygın bir yöntem, kaynak içerik değiştiğinde tetiklenen bir CI işi kapsamında çeviri çalıştırmak veya son 24 saatte güncellenen girdileri yakalayan bir programda çalıştırmaktır.
Contentful ayrıca webhookları destekler — varsayılan yerelde bir giriş yayınlandığında tetiklenen bir webhook yapılandırabilirsiniz, bu da otomatik olarak bir çeviri işini başlatabilir. PolyLingo'yu bu webhook'a bağlamak, bir editör güncellenmiş İngilizce içeriği yayınladığında, çevrilmiş yerellerin herhangi bir manuel adım olmadan güncellenmesi anlamına gelir. Bu, özel bir PolyLingo entegrasyonu için yol haritasında yer almaktadır; bu arada API, bu akışı kendiniz oluşturmanız için ihtiyacınız olan her şeyi sağlar.
Alan türleri hakkında bir not
Yukarıdaki yaklaşım, kısa metin, uzun metin ve dize olarak saklanan zengin metin için iyi çalışır. Bazı Contentful alan türleri ayrı olarak ele alınmalıdır:
Contentful'un belge formatında saklanan zengin metin alanları (düz dizeler değil) PolyLingo'ya göndermeden önce düz metne veya HTML'ye serileştirilmelidir, ardından tekrar seriden çıkarılmalıdır. @contentful/rich-text-html-renderer paketi serileştirme adımını yönetir ve PolyLingo tarafında format: "html" işaretlemeyi doğru şekilde korur.
Referans alanları (diğer girdilere veya varlıklara bağlantılar) çevrilmemelidir — bunlar metin değil, kimliklerdir. API'ye gönderdiğiniz alanlardan hariç tutun.
Sayı, boolean ve tarih alanları doğaları gereği çevrilemez. Kaynak nesnenizi oluşturmadan önce bunları filtreleyin.
Başlarken
PolyLingo'nun ücretsiz katmanı ayda 50.000 token içerir. Orta miktarda içeriğe sahip bir Contentful alanı için, bu, birden fazla yerel dilde birkaç girişte ilk çeviri geçişini kapsar ve devam eden güncellemeler için fazladan alan bırakır.
Tam API dokümantasyonu usepolylingo.com/docs adresindedir. SDK paketleri Node.js, Python, Ruby, PHP, Java ve Go için mevcuttur.
npm install polylingo