<link rel="stylesheet" href="/assets/fonts/jetbrains-mono/jetbrains-mono.css" />
All posts

Një blog në 7 gjuhë me URL të përkthyera: si është ndërtuar kjo faqe

Ky blog lindi në italisht. Kur shtova gjashtë gjuhët e tjera — anglisht, shqip, portugalisht, spanjisht, frëngjisht dhe gjermanisht — përkthimi i teksteve ishte pjesa e lehtë. Pjesa e vështirë ishte gjithçka tjetër: URL-të, lidhjet e ndara tashmë, motorët e kërkimit dhe një përkthim automatik që dukej se funksiononte, por në fakt e prishte përmbajtjen në heshtje.

Problemi: një URL italisht për shtatë gjuhë

Në fillim çdo artikull kishte një slug të vetëm, atë italisht. Rezultati ishin adresa si /de/blog/perche-il-blog-non-viene-indicizzato: një faqe në gjermanisht me URL në italisht. E shëmtuar për t'u ndarë, e paqartë për lexuesin dhe një humbje për SEO-në, sepse fjalët në URL kanë rëndësi.

Modeli i të dhënave: një artikull, shtatë gjuhë

Zgjodha të mbaj një dokument të vetëm për çdo artikull, me fusha për çdo gjuhë: title_en, content_de, slug_fr e kështu me radhë. Alternativa ishte një dokument për çdo përkthim, por atëherë do të më duhej të mbaja të sinkronizuara etiketat, shikimet dhe statusin e publikimit në shtatë kopje. Me një dokument të vetëm, artikulli mbetet një gjë e vetme.

Slug-e të përkthyera që nuk ndryshojnë kurrë

Çdo slug për gjuhë gjenerohet vetëm një herë, nga titulli i përkthyer, dhe më pas nuk preket më, as kur e korrigjoj titullin: një URL e ndarë tashmë duhet të vazhdojë të funksionojë. Për më tepër, çdo slug duhet të jetë unik mes të gjitha fushave të të gjithë artikujve, që një adresë të çojë gjithmonë te një artikull i vetëm, nga cilado gjuhë të vijë:

// Fill slug_xx from the translated title, only where it's missing.
// Existing slugs are never touched: they're in URLs people have shared.
for (const lang of ['en', 'sq', 'pt', 'es', 'fr', 'de']) {
  if (post[`slug_${lang}`]) continue;
  const title = post[`title_${lang}`];
  if (title?.trim()) {
    post[`slug_${lang}`] = await ensureUniqueSlug(title); // unique across ALL slug fields
  }
}

Lidhjet e vjetra vazhdojnë të funksionojnë

Para slug-eve të përkthyera, shumë lidhje ishin ndarë tashmë në formën /sq/blog/slug-italisht. T'i prishja do të thoshte faqe 404 dhe sinjale negative për Google. Prandaj build-i e gjeneron çdo artikull edhe me slug-un italisht nën çdo prefiks gjuhe, me canonical-in që tregon versionin e përkthyer: kush vjen nga lidhja e vjetër sheh faqen e duhur, dhe Google e di cila adresë është ajo zyrtare.

SEO për çdo gjuhë

  • hreflang në çdo faqe, që lidh mes tyre shtatë versionet e të njëjtit artikull.
  • og:locale dinamik, që parapamjet në rrjetet sociale të tregojnë gjuhën, titullin dhe përshkrimin e saktë.
  • Sitemap me të gjitha versionet, e përditësuar automatikisht në çdo publikim.
  • Faqe të prerenderizuara për çdo gjuhë: pa to, Google shihte vetëm guaskën e aplikacionit, siç e kam treguar në këtë artikull.

Përkthimi automatik që prishte kodin

Për të përkthyer pa prekur HTML-në, zëvendësoja etiketat dhe blloqet e kodit me shenja zëvendësuese, ia dërgoja tekstin përkthyesit dhe pastaj i rivendosja të gjitha. Funksiononte pothuajse gjithmonë. Por kur disa shenja ishin afër njëra-tjetrës — tipike për artikujt me shumë blloqe kodi — përkthyesi ndonjëherë dyfishonte njërën dhe humbiste një tjetër. Nuk ishte gabim i rastësishëm: duke e rinisur, përsëritej identik, sidomos në shqip.

Zgjidhja ishte të mos ia dërgoja fare shenjat përkthyesit: e ndaj tekstin te shenjat dhe përkthej vetëm copat e prozës. Më shumë thirrje, por asnjë mundësi që një shenjë të ndryshohet:

// Split on the placeholders: the translator never sees them
const parts = text.split(/(✦\d+✦)/);
const out = [];
for (const part of parts) {
  out.push(/^✦\d+✦$/.test(part) ? part : await translate(part, lang));
}
return out.join('');

Dhe që atëherë, pas çdo përkthimi, e krahasoj strukturën e çdo gjuhe me atë italisht — i njëjti numër titujsh, paragrafësh, tabelash dhe blloqesh kodi — pa iu besuar "asnjë gabimi" që raporton skripti.


Në përmbledhje

Një blog shumëgjuhësh nuk është një blog me një përkthyes të ngjitur: duhen një model i qartë të dhënash, URL të qëndrueshme për çdo gjuhë, lidhje të vjetra që nuk prishen dhe kontrolle automatike mbi përkthimin. Janë të njëjtat zgjedhje që propozoj kur një klient do një faqe në disa gjuhë. Nëse është rasti yt, më shkruaj.

💬 Shënime nga lexuesit

0 shënime

Shkruaj një shënim

Ndaj mendimin tënd, një sugjerim ose një kompliment

Shënimet e fundit

Ende asnjë shënim. Bëhu i pari që komenton!