Articoli
Utilizza il front-end puro per creare un blog multilingue "dinamico + articolo".
Ho trasformato il mio sito web in un blog multilingue "dinamico + articolo": il contenuto è gestito con Markdown, la traduzione viene completata al momento della pubblicazione, le pagine statiche vengono generate durante la costruzione e il browser è responsabile della lettura e del cambio delle lingue. Questo articolo analizza il modello di contenuto, le pipeline condivise, i compromessi tra caricamento su richiesta e SEO e cosa salva esattamente il front-end puro.
· 9 min di lettura
Spero che il mio sito web possa essere utilizzato per annotare un paragrafo di pensieri o per scrivere in modo chiaro un problema tecnico completo. Metti "dinamica" nel breve e "articolo" nel lungo. I due possono essere collegati tra loro e quando il visitatore cambia lingua, anche il contenuto deve essere cambiato insieme.
Questo requisito sembra molto ordinario, ma se aggiungi un database, un backend e un'API di contenuto fin dall'inizio e poi gestisci la versione di ciascuna lingua, diventerà presto un altro prodotto che richiede manutenzione a lungo termine.
Ho scelto di restringere innanzitutto i requisiti a ciò che posso realmente utilizzare: **Un autore, inserisce il contenuto in Git e ricostruisce il sito Web dopo la pubblicazione. Il lettore necessita solo di file statici e di un browser. ** Questa è l'attuale struttura "dinamica + articolo" di stephen.taipei.
Il front-end puro si riferisce alla fine della lettura#
Innanzitutto chiariamo i confini. Questo progetto utilizza React, Vite e Tailwind. Node.js è ancora necessario per l'elaborazione dei contenuti, la conversione delle immagini e la creazione di script; la traduzione si avvarrà anche di servizi esterni in fase di pubblicazione. Dopo la distribuzione, i file statici vengono forniti da Nginx.
Quindi quello che intendo per front-end puro è che quando i lettori aprono il sito web, non hanno bisogno di uno speciale back-end del blog per cercare informazioni, raggruppare pagine o tradurre in tempo reale. Ha un processo di compilazione e un host, ma nessuna API applicativa persistente o database per la lettura degli articoli.
Se il lavoro viene svolto in anticipo, la fine della lettura sarà molto più semplice.
Notizie e articoli condividono la stessa fonte, ognuno ha il proprio modello#
Il contenuto è concentrato in content/ e il testo originale è tutto Markdown. I due contenuti non sono inseriti nello stesso formato:
content/
tags.yaml
tags.locales.yaml
notes/2026/20261004-0944.md
notes/2026/20261004-0944.locales.yaml
articles/frontend-only-multilingual-blog/
index.md
locales.yaml
cover.webp
Le dinamiche sono carte corte. Il nome del file utilizza il minuto dell'ora di Taipei come ID. Può essere contrassegnato con idee, apprendimento, online, imbrogli o lettura. Può essere stabilito semplicemente scrivendo un paragrafo senza dover pensare ogni volta a un titolo. Se supera le 500 parole verrà visualizzato un promemoria e se supera le 1.000 parole dovrà essere trasformato in un articolo.
Gli articoli hanno uno slug, un titolo, un abstract e una data fissi e possono anche avere una copertina e un orario di aggiornamento. L'URL non verrà modificato dopo essere stato reso pubblico per evitare che il collegamento condiviso originale diventi non valido.
I due sono collegati usando article:. Per gli aggiornamenti è possibile scrivere prima la domanda e poi collegarsi all'articolo completo; la pagina dell'articolo elencherà gli aggiornamenti che fanno riferimento ad esso al contrario. Il contenuto breve mantiene il punto di partenza corrente e il contenuto lungo è responsabile del completamento della derivazione. Non è necessario pubblicare lo stesso testo completo su entrambi i lati.
Lascia che le regole del contenuto blocchino gli errori prima della creazione#
Se Markdown fosse semplicemente inserito nella situazione, molti problemi non si vedrebbero fino a quando non sarà pubblicato: date errate, articoli non collegati, immagini senza alt o lo stesso argomento scritto con tre tag simili.
Ho inserito queste regole nella pipeline dei contenuti condivisi. loadContent Leggi il file, controlla i campi con Zod, quindi elabora Markdown, immagini, lingua e relazioni tra contenuti. Sia l'ispezione CLI che la costruzione di Vite utilizzano questa pipeline per ridurre il divario tra "la macchina locale dice che funziona, ma l'ambiente ufficiale no".
Il tag accetta solo tags.yaml chiavi registrate; devono esistere articoli con riferimenti dinamici e altre dinamiche; l'anteprima locale può leggere le bozze e la build ufficiale escluderà le bozze. Queste regole non si basano sul ricordarle al momento della pubblicazione, ma bloccano realmente i controlli.
Anche Markdown ha limiti di output ben definiti: il raw HTML non viene emesso direttamente, l’HTML generato viene sanificato e i blocchi di codice vengono evidenziati durante il build. Le immagini dei contenuti referenziate con percorsi relativi locali vengono convertite in WebP, con una larghezza massima di 1600px, e i metadati EXIF, inclusi i dati GPS, vengono rimossi. Articoli, schede e anteprime di condivisione usano le immagini elaborate. Le immagini remote e quelle referenziate con percorsi assoluti dalla root non passano attraverso questa conversione locale.
Il costo del sistema multilingue verrà pagato al momento della pubblicazione dell'articolo.#
Il sito Web attualmente supporta 22 lingue. Il testo originale in cinese tradizionale viene scritto una volta e i titoli, gli abstract, i testi e le descrizioni delle immagini delle altre 21 lingue vengono memorizzati nel locales.yaml accanto ad esso.
Ecco una decisione che mi sta a cuore: **I lettori non devono aspettare la traduzione. ** content:localize Genera traduzioni durante la pubblicazione. La build ufficiale legge solo i file esistenti e non richiama nuovamente il servizio di traduzione ogni volta che viene distribuito.
Utilizza il digest della fonte per confrontare il testo originale e il testo tradotto. Se il testo originale viene modificato, la vecchia traduzione non può più essere considerata come l'ultima versione; se manca una famiglia linguistica o la traduzione non è aggiornata, content:check fallirà. Il processo di traduzione protegge il codice, il codice in linea e le destinazioni dei collegamenti dalla traduzione di identificatori tecnici o URL.
Ciò non significa che la traduzione automatica abbia la qualità dell’editing umano. Affronta la completezza e la coerenza aggiornata, e il linguaggio e il tono professionali richiedono ancora una correzione di bozze. Il testo originale che non è stato modificato manterrà la traduzione esistente e il testo modificato manualmente non verrà sovrascritto dalla riesecuzione.
Leggi l'abstract nell'elenco, clicca per caricare l'articolo#
Dopo che il contenuto è stato aumentato, se la homepage carica il testo completo di ogni articolo e di ogni famiglia linguistica, il front-end puro sarà molto lento.
Il plugin Vite divide i contenuti in tre punti di ingresso: virtual:content/latest per la homepage, virtual:content/index per le pagine dei contenuti e un virtual:content/article/<slug> separato per ogni articolo. La homepage mostra le tre note più recenti e tre schede di articoli. I dati delle note includono comunque il testo completo e le traduzioni; la scheda ne mostra solo una parte. Le schede degli articoli lunghi contengono soltanto riepiloghi e dati correlati, mentre il testo completo viene caricato separatamente per ciascun articolo tramite dynamic import.
La suspense di React è responsabile dell'attesa del testo e il limite di errore esterno è responsabile della visualizzazione del messaggio di errore di caricamento. Quando la richiesta di testo fallisce, rimangono il titolo, l'abstract e la navigazione della pagina.
Anche qui ci sono dei compromessi: attualmente c'è una porzione di testo per articolo, che contiene le traduzioni di ciascuna famiglia linguistica, e non è stata ancora suddivisa in una porzione per famiglia linguistica. Il testo completo dinamico e le traduzioni vengono inseriti nell'indice dei contenuti. Poiché il volume dei contenuti continua ad aumentare, i prossimi passi da misurare sono la dimensione dell’indice e il numero di download di testo multilingue.
Deve essere presente un front-end switching e un ingresso per la lettura statica.#
Facciamo solo SPA e quando la condividiamo spesso vediamo solo il titolo e l'immagine sulla home page. Questo non basta per l'articolo.
Pertanto, durante la configurazione, ogni URL dinamico, articolo e tag ha la propria shell HTML, che contiene titolo, descrizione, canonico, Open Graph e JSON-LD e il testo originale leggibile viene inserito in noscript. Puoi ottenere il contenuto e la copertina esclusiva di questo articolo senza eseguire JavaScript.
Lo stesso contenuto produrrà anche feed.xml, sitemap-content.xml, la versione Markdown dell'articolo e l'indice dell'articolo per llms.txt. Si tratta di prodotti integrati, non di un altro insieme di contenuti che richiede la sincronizzazione manuale.
Tuttavia, devono essere chiariti anche i confini del SEO multilingue: **Attualmente, gli aggiornamenti e gli articoli condividono lo stesso URL in ciascuna lingua e la lingua viene cambiata dal front-end; le pagine di contenuto statico, i feed e le versioni Markdown mantengono il testo originale. ** La home page dispone anche di pre-rendering per la lingua e le modalità chiaro e scuro. Ciò non significa che ogni articolo abbia anche 22 pagine linguistiche indicizzabili in modo indipendente.
Se in futuro desideri consentire a ciascuna famiglia linguistica di essere inclusa dai motori di ricerca, dovrai aggiungere il routing della famiglia linguistica, le pagine statiche corrispondenti e l'hreflang. Questo è un altro requisito che questo set non soddisfa ancora.
La pubblicazione è anche un processo di consegna#
Il mio processo di pubblicazione è: scrivere il testo originale, generare la traduzione, controllare il contenuto, inviarlo a Git e quindi unirlo in main. Le azioni GitHub esistenti ricostruiranno il sito Web e lo distribuiranno.
npm run content:localize
npm run content:check
npm run test:content
npm run build
Se le traduzioni non coprono ancora tutte le lingue, completo prima quelle mancanti. Gli articoli in bozza restano nell’anteprima locale. L’output di produzione verifica anche che non esistano pagine di bozze e cerca i relativi indicatori nei principali artefatti pubblici, come feed, sitemap, homepage e bundle JavaScript. Come il codice, anche i contenuti hanno diff e cronologia delle versioni e possono essere ripristinati insieme.
Questo metodo sacrifica gli aggiornamenti in tempo reale: se modifichi una parte di testo, devi attendere una distribuzione. Ma per il mio sito web tecnico, sono disposto a scambiare questa attesa in cambio di un backend in meno, di una dipendenza dal periodo di esecuzione in meno e di un record di modifiche più facile da monitorare.
Quando è opportuno farlo?#
Se sei un autore, la frequenza di pubblicazione può essere ricostruita, il contenuto è principalmente testo e sei abituato a Git, questa architettura è molto adatta. Aggiornamenti brevi abbassano la soglia di scrittura, l'articolo mantiene la derivazione completa e la multilingua permette di leggere lo stesso contenuto a più persone.
Se i requisiti diventano collaborazione in tempo reale tra più persone, gestione dei permessi, commenti dei lettori, login o abbonamento, allora il CMS e il backend devono essere rivalutati. Il puro front-end non farà scomparire automaticamente queste esigenze, ma al momento non le ho inserite nell'ambito di questo blog.
I principi di progettazione questa volta sono molto vicini a quello che ho scritto in Pattern architetturale per layout e temi multipli: prima separare chiaramente le responsabilità, e poi lasciare che le regole condivise mantengano la coerenza.
Per questo sito web, il punto chiave è permettermi di continuare a scrivere e di sapere quali contenuti vengono effettivamente forniti ogni volta che pubblico.