Artigos
Use front-end puro para criar um blog multilíngue "dinâmico + artigo"
Transformei meu site em um blog multilíngue "dinâmico + artigo": o conteúdo é gerenciado com Markdown, a tradução é concluída na postagem, páginas estáticas são geradas durante a construção e o navegador é responsável pela leitura e troca de idiomas. Este artigo detalha o modelo de conteúdo, pipelines compartilhados, compensações entre carregamento sob demanda e SEO e o que exatamente o front-end puro salva.
· 9 min de leitura
Espero que meu site possa ser usado para anotar um parágrafo de pensamentos ou para escrever claramente uma questão técnica completa. Coloque “dinâmica” no curto e “artigo” no longo. Os dois podem ser interligados e, quando o visitante troca de idioma, o conteúdo também deve ser trocado em conjunto.
Esse requisito parece muito comum, mas se você adicionar um banco de dados, back-end e API de conteúdo desde o início e depois lidar com a versão de cada linguagem, logo se tornará outro produto que requer manutenção de longo prazo.
Optei primeiro por restringir os requisitos ao que realmente posso usar: **Um autor, insira o conteúdo no Git e reconstrua o site após a publicação. O leitor precisa apenas de arquivos estáticos e de um navegador. ** Esta é a atual estrutura "dinâmica + artigo" de stephen.taipei.
Front-end puro refere-se ao final da leitura#
Vamos deixar os limites claros primeiro. Este projeto usa React, Vite e Tailwind. O Node.js ainda é necessário para processamento de conteúdo, conversão de imagens e criação de scripts; a tradução também recorrerá a serviços externos durante a fase de publicação. Após a implantação, os arquivos estáticos são fornecidos pelo Nginx.
Então, o que quero dizer com front-end puro é que quando os leitores abrem o site, eles não precisam de um back-end especial do Blog para buscar informações, agrupar páginas ou traduzir em tempo real. Possui um processo de construção e um host, mas nenhuma API de aplicativo persistente ou banco de dados para leitura de artigos.
Se o trabalho for feito com antecedência, o final da leitura será muito mais fácil.
Notícias e artigos compartilham a mesma fonte, cada um tem seu próprio modelo#
O conteúdo está concentrado em content/, e o texto original é todo Markdown. Os dois conteúdos não estão colocados no mesmo 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
Dinâmicas são cartas curtas. O nome do arquivo usa o minuto do horário de Taipei como ID. Pode ser marcado com ideias, aprendizagem, online, trapaça ou leitura. Pode ser estabelecido apenas escrevendo um parágrafo, sem ter que pensar sempre em um título. Um lembrete aparecerá se ultrapassar 500 palavras e deverá ser transformado em artigo se ultrapassar 1.000 palavras.
Os artigos possuem slug, título, resumo, data fixos, podendo também ter capa e horário de atualização. O URL não será alterado após ser tornado público para evitar que o link compartilhado original se torne inválido.
Os dois estão relacionados usando article:. Para atualizações, você pode escrever a pergunta primeiro e depois vincular ao artigo completo; a página do artigo listará as atualizações que fazem referência a ele ao contrário. O conteúdo curto mantém o ponto de partida atual, e o conteúdo longo é responsável por finalizar a derivação. Não há necessidade de postar o mesmo texto completo em ambos os lados.
Deixe as regras de conteúdo bloquearem erros antes de construir#
Se o Markdown fosse simplesmente colocado em cena, muitos problemas não seriam vistos até que ele fosse lançado: datas erradas, artigos desconectados, imagens sem alts ou o mesmo tópico sendo escrito com três tags semelhantes.
Coloquei essas regras no pipeline de conteúdo compartilhado. loadContent Leia o arquivo, verifique os campos com Zod e depois processe Markdown, imagens, idioma e relacionamentos de conteúdo. Tanto a inspeção CLI quanto a construção do Vite usam esse pipeline para reduzir a lacuna entre “a máquina local diz que funciona, mas o ambiente oficial não”.
A tag aceita apenas tags.yaml chaves registradas; devem existir artigos referenciados dinamicamente e outras dinâmicas; a visualização local pode ler rascunhos e a versão oficial excluirá rascunhos. Essas regras não se baseiam em lembrá-las durante a postagem, mas na verdade bloqueiam as inspeções.
O Markdown também tem limites de saída bem definidos: o raw HTML não é emitido diretamente, o HTML gerado é sanitizado e os blocos de código são destacados durante o build. As imagens de conteúdo referenciadas por caminhos relativos locais são convertidas para WebP, com largura máxima de 1600px, e os metadados EXIF, incluindo os dados de GPS, são removidos. Artigos, cards e prévias de compartilhamento usam as imagens processadas. Imagens remotas e imagens referenciadas por caminhos absolutos a partir da raiz não passam por esse processo de conversão local.
O custo do sistema multilíngue será pago no momento da publicação do artigo.#
O site atualmente suporta 22 idiomas. O texto original em chinês tradicional é escrito uma vez, e os títulos, resumos, descrições de texto e imagens dos outros 21 idiomas são armazenados no locales.yaml próximo a ele.
Aqui está uma decisão que me interessa: **Os leitores não precisam esperar pela tradução. ** content:localize Gere traduções ao postar. A compilação oficial apenas lê os arquivos existentes e não chama o serviço de tradução novamente sempre que é implantado.
Use o resumo de origem para comparar o texto original e o texto traduzido. Se o texto original for alterado, a tradução antiga não poderá mais ser considerada a versão mais recente; se uma família de idiomas estiver faltando ou a tradução estiver desatualizada, content:check falhará. O processo de tradução protege o código, o código embutido e os destinos de link da tradução de identificadores técnicos ou URLs.
Isto não significa que a tradução automática tenha a qualidade da edição humana. Ele aborda a integridade e a consistência atualizada, e a linguagem e o tom profissionais ainda exigem revisão. O texto original que não foi alterado manterá a tradução existente e o texto modificado manualmente não será substituído pela nova execução.
Leia o resumo na lista, clique para carregar o artigo#
Após o aumento do conteúdo, se a página inicial carregar o texto completo de cada artigo e de cada família de idiomas, o front-end puro ficará muito lento.
O plugin do Vite divide o conteúdo em três pontos de entrada: virtual:content/latest para a página inicial, virtual:content/index para as páginas de conteúdo e um virtual:content/article/<slug> próprio para cada artigo. A página inicial mostra as três notas mais recentes e três cards de artigos. Os dados das notas ainda incluem o texto completo e as traduções; o card apenas corta o que exibe. Os cards dos artigos longos trazem somente resumos e dados relacionados, enquanto o corpo completo é carregado separadamente para cada artigo por meio de dynamic import.
O Suspense do React é responsável por aguardar o texto, e o limite externo do erro é responsável por exibir a mensagem de falha no carregamento. Quando a solicitação de texto falha, o título, o resumo e a navegação da página permanecem.
Há também compensações aqui: atualmente, há um pedaço de texto por artigo, que contém traduções de cada família linguística, e ainda não foi dividido em um pedaço por família linguística. O texto completo dinâmico e as traduções são inseridos no índice de conteúdo. À medida que o volume de conteúdo continua a aumentar, o tamanho do índice e o número de downloads de texto multilíngue são os próximos passos a serem medidos.
Deve haver comutação frontal e uma entrada para leitura estática.#
Fazemos apenas SPA e, quando o compartilhamos, muitas vezes vemos apenas o título e a imagem na página inicial. Isso não é suficiente para o artigo.
Portanto, ao configurar, cada URL dinâmico, de artigo e de tag possui seu próprio shell HTML, que contém título, descrição, canônico, Open Graph e JSON-LD, e o texto original legível é colocado em noscript. Você pode obter o conteúdo e a capa exclusiva deste artigo sem executar JavaScript.
O mesmo conteúdo também produzirá feed.xml, sitemap-content.xml, a versão Markdown do artigo e o índice do artigo para llms.txt. Estes são produtos construídos, não outro conjunto de conteúdo que requer sincronização manual.
No entanto, os limites do SEO multilíngue também devem ficar claros: **Atualmente, atualizações e artigos compartilham a mesma URL em cada idioma, e o idioma é trocado pelo front end; páginas de conteúdo estático, feeds e versões Markdown mantêm o texto original. ** A página inicial também possui pré-renderização para idioma e modos claro e escuro. Isso não significa que cada artigo também tenha 22 páginas em idiomas indexáveis de forma independente.
Se você precisar permitir que cada família de idiomas seja incluída pelos mecanismos de pesquisa no futuro, será necessário adicionar o roteamento da família de idiomas, as páginas estáticas correspondentes e o hreflang. Esse é outro requisito que este conjunto ainda não cumpre.
Postar também é um processo de entrega#
Meu processo de publicação é: escrever o texto original, gerar a tradução, verificar o conteúdo, enviar para o Git e depois mesclar em main. As ações existentes do GitHub reconstruirão o site e o implantarão.
npm run content:localize
npm run content:check
npm run test:content
npm run build
Se ainda faltarem idiomas, primeiro completo as traduções. Artigos em rascunho ficam na prévia local. A saída de produção também verifica se as páginas de rascunho estão ausentes e procura marcadores de rascunho nos principais arquivos públicos, como feed, sitemap, página inicial e bundles JavaScript. Assim como o código, o conteúdo tem diffs e histórico de versões, e pode ser revertido junto com ele.
Este método sacrifica atualizações em tempo real: se você alterar um trecho de texto, terá que aguardar uma implantação. Mas para o meu site técnico, estou disposto a trocar essa espera em troca de um back-end a menos, uma dependência a menos do período de execução e um registro de alterações que seja mais fácil de rastrear.
Quando é apropriado fazer isso?#
Se você é um autor, a frequência de postagem pode ser reconstruída, o conteúdo é principalmente texto e você está acostumado com o Git, essa arquitetura é muito adequada. Atualizações curtas reduzem o limite de escrita, o artigo mantém a derivação completa e o multilíngue permite que o mesmo conteúdo seja lido por mais pessoas.
Se os requisitos se tornarem colaboração em tempo real entre várias pessoas, gerenciamento de permissões, comentários de leitores, login ou assinatura, então o CMS e o backend precisarão ser reavaliados. O front-end puro não fará com que essas necessidades desapareçam automaticamente, mas não as coloquei no escopo deste blog no momento.
Os princípios de design desta vez estão muito próximos do que escrevi em Padrão de arquitetura para múltiplos layouts e temas: primeiro separe as responsabilidades claramente e depois deixe as regras compartilhadas manterem a consistência.
Para este site, o ponto chave é permitir-me continuar escrevendo e saber qual conteúdo está realmente sendo entregue cada vez que publico.