บทความ
ใช้ส่วนหน้าเพื่อสร้างบล็อกหลายภาษา "ไดนามิก + บทความ"
ฉันทำให้เว็บไซต์ของฉันกลายเป็นบล็อกหลายภาษา "ไดนามิก + บทความ": เนื้อหาได้รับการจัดการด้วย Markdown, การแปลเสร็จสิ้นเมื่อโพสต์, หน้าคงที่ถูกสร้างขึ้นระหว่างการก่อสร้าง และเบราว์เซอร์มีหน้าที่ในการอ่านและเปลี่ยนภาษา บทความนี้จะแจกแจงรายละเอียดโมเดลเนื้อหา ไปป์ไลน์ที่ใช้ร่วมกัน การแลกเปลี่ยนระหว่างการโหลดตามความต้องการและ SEO และสิ่งที่ช่วยประหยัดจากส่วนหน้าอย่างแท้จริง
· อ่าน 1 นาที
ฉันหวังว่าเว็บไซต์ของฉันจะสามารถใช้เพื่อจดความคิดเห็นหนึ่งย่อหน้า หรือเขียนปัญหาทางเทคนิคทั้งหมดได้อย่างชัดเจน ใส่ "ไดนามิก" ไว้ในส่วนสั้น และ "บทความ" ไว้ในส่วนยาว ทั้งสองสามารถเชื่อมโยงถึงกัน และเมื่อผู้เยี่ยมชมเปลี่ยนภาษา เนื้อหาจะต้องถูกสลับพร้อมกันด้วย
ข้อกำหนดนี้ดูธรรมดามาก แต่ถ้าคุณเพิ่มฐานข้อมูล แบ็กเอนด์ และ API เนื้อหาตั้งแต่ต้น แล้วจัดการเวอร์ชันของแต่ละภาษา ในไม่ช้า ข้อกำหนดนี้จะกลายเป็นอีกผลิตภัณฑ์หนึ่งที่ต้องมีการบำรุงรักษาระยะยาว
ฉันเลือกที่จะจำกัดข้อกำหนดให้แคบลงให้แคบลงตามสิ่งที่ฉันสามารถใช้ได้จริง: **ผู้เขียนหนึ่งคน ป้อนเนื้อหาลงใน Git และสร้างเว็บไซต์ใหม่หลังจากเผยแพร่ เครื่องอ่านต้องการเพียงไฟล์คงที่และเบราว์เซอร์เท่านั้น ** นี่คือโครงสร้าง "ไดนามิก + บทความ" ปัจจุบันของ stephen.taipei
ส่วนหน้าบริสุทธิ์หมายถึงส่วนท้ายของการอ่าน#
มาทำให้ขอบเขตชัดเจนก่อน โปรเจ็กต์นี้ใช้ React, Vite และ Tailwind ยังคงต้องใช้ Node.js สำหรับการประมวลผลเนื้อหา การแปลงรูปภาพ และการสร้างสคริปต์ การแปลจะเรียกใช้บริการภายนอกในระหว่างขั้นตอนการเผยแพร่ หลังจากการปรับใช้ Nginx จะจัดเตรียมไฟล์คงที่
ดังนั้นสิ่งที่ฉันหมายถึงโดยส่วนหน้าคือ เมื่อผู้อ่านเปิดเว็บไซต์ พวกเขาไม่จำเป็นต้องใช้ส่วนหลังของบล็อกพิเศษเพื่อค้นหาข้อมูล จัดกลุ่มหน้า หรือแปลแบบเรียลไทม์ มีกระบวนการสร้างและโฮสต์ แต่ไม่มี API แอปพลิเคชันหรือฐานข้อมูลถาวรสำหรับการอ่านบทความ
หากทำงานเสร็จล่วงหน้าการสิ้นสุดการอ่านจะง่ายขึ้นมาก
ข่าวสารและบทความแบ่งปันแหล่งเดียวกัน แต่ละแห่งมีรูปแบบของตัวเอง#
เนื้อหาเน้นที่ content/ และข้อความต้นฉบับคือ Markdown ทั้งหมด เนื้อหาทั้งสองไม่ได้ถูกผูกไว้ในรูปแบบเดียวกัน:
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
Dynamics เป็นไพ่สั้น ชื่อไฟล์ใช้นาทีของเวลาไทเปเป็น ID สามารถทำเครื่องหมายด้วยไอเดีย การเรียนรู้ ออนไลน์ การโกง หรือการอ่าน สามารถสร้างได้ด้วยการเขียนย่อหน้าโดยไม่ต้องคิดชื่อเรื่องทุกครั้ง การแจ้งเตือนจะปรากฏขึ้นหากเกิน 500 คำ และควรเปลี่ยนเป็นบทความหากเกิน 1,000 คำ
บทความมีกระสุน ชื่อเรื่อง บทคัดย่อ วันที่ตายตัว และยังสามารถมีเวลาหน้าปกและอัปเดตอีกด้วย URL จะไม่มีการเปลี่ยนแปลงหลังจากที่เปิดเผยต่อสาธารณะแล้ว เพื่อป้องกันไม่ให้ลิงก์ที่แชร์เดิมกลายเป็นโมฆะ
ทั้งสองเกี่ยวข้องกันโดยใช้ article: สำหรับข้อมูลอัปเดต คุณสามารถจดคำถามไว้ก่อนแล้วจึงลิงก์ไปยังบทความฉบับเต็ม หน้าบทความจะแสดงรายการอัปเดตที่อ้างอิงถึงแบบย้อนกลับ เนื้อหาแบบสั้นยังคงเป็นจุดเริ่มต้นในปัจจุบัน และเนื้อหาแบบยาวมีหน้าที่รับผิดชอบในการสิ้นสุดการสืบทอด ไม่จำเป็นต้องโพสต์ข้อความเต็มเหมือนกันทั้งสองด้าน
ให้กฎเนื้อหาบล็อกข้อผิดพลาดก่อนที่จะสร้าง#
หากเพียงแค่ใส่ Markdown เข้าไปในรูปภาพ ปัญหาต่างๆ มากมายก็จะไม่เห็นจนกว่าจะเผยแพร่ไปแล้ว เช่น วันที่ผิด บทความที่ไม่เชื่อมโยงกัน รูปภาพที่ไม่มี Alt หรือหัวข้อเดียวกันที่เขียนด้วยแท็กที่คล้ายกันสามแท็ก
ฉันใส่กฎเหล่านี้ลงในไปป์ไลน์เนื้อหาที่แชร์ loadContent อ่านไฟล์ ตรวจสอบฟิลด์ด้วย Zod จากนั้นประมวลผลความสัมพันธ์ของ Markdown รูปภาพ ภาษา และเนื้อหา ทั้งการตรวจสอบ CLI และการก่อสร้าง Vite ใช้ไปป์ไลน์นี้เพื่อลดช่องว่างระหว่าง "เครื่องจักรในพื้นที่บอกว่าใช้งานได้ แต่สภาพแวดล้อมอย่างเป็นทางการไม่เป็นเช่นนั้น"
แท็กยอมรับเฉพาะคีย์ที่ลงทะเบียน tags.yaml เท่านั้น บทความอ้างอิงแบบไดนามิกและการเปลี่ยนแปลงอื่น ๆ ต้องมีอยู่ การแสดงตัวอย่างในเครื่องสามารถอ่านฉบับร่างได้ และเวอร์ชันอย่างเป็นทางการจะไม่รวมฉบับร่าง กฎเหล่านี้ไม่ได้ขึ้นอยู่กับการจดจำกฎเหล่านี้เมื่อโพสต์ แต่จะบล็อกการตรวจสอบจริงๆ
Markdown มีขอบเขตของผลลัพธ์ที่ชัดเจนเช่นกัน: จะไม่ส่ง raw HTML ออกมาโดยตรง, HTML ที่สร้างขึ้นจะผ่านการทำความสะอาด และบล็อกโค้ดจะถูกไฮไลต์ในขั้น build รูปภาพเนื้อหาที่อ้างอิงด้วย relative path ในเครื่องจะถูกแปลงเป็น WebP โดยมีความกว้างสูงสุด 1600px พร้อมลบข้อมูล EXIF รวมถึงข้อมูล GPS ออก บทความ การ์ด และตัวอย่างสำหรับแชร์ใช้รูปภาพที่ผ่านการประมวลผลชุดเดียวกัน ส่วนรูปภาพจากระยะไกลและรูปภาพที่อ้างอิงด้วย absolute path จาก root จะไม่ผ่านขั้นตอนแปลงในเครื่องนี้
จะมีการชำระค่าใช้จ่ายของระบบหลายภาษาเมื่อเผยแพร่บทความ#
ปัจจุบันเว็บไซต์รองรับ 22 ภาษา ข้อความต้นฉบับภาษาจีนดั้งเดิมเขียนเพียงครั้งเดียว และชื่อเรื่อง บทคัดย่อ ข้อความ และคำอธิบายรูปภาพของอีก 21 ภาษาจะถูกจัดเก็บไว้ใน locales.yaml ข้างๆ
การตัดสินใจที่ฉันใส่ใจ: **ผู้อ่านไม่ต้องรอการแปล ** content:localize สร้างคำแปลเมื่อโพสต์ โครงสร้างอย่างเป็นทางการจะอ่านเฉพาะไฟล์ที่มีอยู่เท่านั้น และจะไม่เรียกใช้บริการแปลอีกทุกครั้งที่มีการปรับใช้
ใช้การแยกย่อยแหล่งที่มาเพื่อเปรียบเทียบข้อความต้นฉบับกับข้อความที่แปล หากข้อความต้นฉบับมีการเปลี่ยนแปลง คำแปลเก่าจะไม่ถือเป็นเวอร์ชันล่าสุดอีกต่อไป หากตระกูลภาษาหนึ่งหายไปหรือการแปลล้าสมัย content:check จะล้มเหลว กระบวนการแปลจะปกป้องโค้ด โค้ดอินไลน์ และเป้าหมายลิงก์จากการแปลตัวระบุทางเทคนิคหรือ URL
นี่ไม่ได้หมายความว่าการแปลอัตโนมัติมีคุณภาพเทียบเท่ากับการแก้ไขโดยมนุษย์ โดยเน้นถึงความสมบูรณ์และความสม่ำเสมอที่ได้รับการปรับปรุง และภาษาและน้ำเสียงระดับมืออาชีพยังคงต้องมีการพิสูจน์อักษร ข้อความต้นฉบับที่ไม่มีการเปลี่ยนแปลงจะคงคำแปลที่มีอยู่ไว้ และข้อความที่แก้ไขด้วยตนเองจะไม่ถูกเขียนทับโดยการเรียกใช้ใหม่
อ่านบทคัดย่อในรายการ คลิกเพื่อโหลดบทความ#
หลังจากที่เนื้อหาเพิ่มขึ้น หากหน้าแรกโหลดข้อความเต็มของแต่ละบทความและแต่ละตระกูลภาษา ส่วนหน้าที่แท้จริงจะช้ามาก
Vite plugin แบ่งเนื้อหาออกเป็นสาม entry point ได้แก่ virtual:content/latest สำหรับหน้าแรก, virtual:content/index สำหรับหน้าเนื้อหา และ virtual:content/article/<slug> แยกสำหรับแต่ละบทความ หน้าแรกแสดงบันทึกล่าสุดสามรายการและการ์ดบทความสามใบ ข้อมูลบันทึกยังมีเนื้อหาเต็มและคำแปลอยู่ เพียงแต่การ์ดตัดข้อความที่แสดงให้สั้นลง การ์ดบทความยาวมีเฉพาะสรุปและข้อมูลที่เกี่ยวข้อง ส่วนเนื้อหาเต็มจะโหลดแยกตามบทความด้วย dynamic import
Suspense ของ React มีหน้าที่รอข้อความ และขอบเขตข้อผิดพลาดภายนอกมีหน้าที่แสดงข้อความโหลดล้มเหลว เมื่อคำขอข้อความล้มเหลว ชื่อเรื่อง บทคัดย่อ และการนำทางเพจจะยังคงอยู่
นอกจากนี้ยังมีข้อเสียอยู่ด้วย ในปัจจุบัน มีหนึ่งส่วนข้อความต่อบทความ ซึ่งประกอบด้วยคำแปลของแต่ละตระกูลภาษา และยังไม่ได้แบ่งออกเป็นหนึ่งส่วนต่อตระกูลภาษา ข้อความแบบเต็มแบบไดนามิกและการแปลจะถูกป้อนลงในดัชนีเนื้อหา เนื่องจากปริมาณเนื้อหาเพิ่มขึ้นอย่างต่อเนื่อง ขนาดดัชนีและจำนวนการดาวน์โหลดข้อความหลายภาษาจึงเป็นขั้นตอนต่อไปที่ต้องวัด
จะต้องมีการสลับส่วนหน้าและทางเข้าสำหรับการอ่านแบบคงที่#
เราทำเฉพาะสปาเท่านั้น และเมื่อเราแบ่งปันข้อมูลนั้น เรามักจะเห็นเพียงชื่อและรูปภาพในหน้าแรกเท่านั้น นี่ไม่เพียงพอสำหรับบทความ
ดังนั้น เมื่อตั้งค่า URL แบบไดนามิก บทความ และแท็กแต่ละรายการจะมีเชลล์ HTML ของตัวเอง ซึ่งประกอบด้วยชื่อ คำอธิบาย ตามรูปแบบบัญญัติ Open Graph และ JSON-LD และข้อความต้นฉบับที่อ่านได้จะอยู่ใน noscript คุณสามารถรับเนื้อหาและหน้าปกพิเศษของบทความนี้ได้โดยไม่ต้องรัน JavaScript
เนื้อหาเดียวกันนี้ยังสร้าง feed.xml, sitemap-content.xml, เวอร์ชัน Markdown ของบทความ และดัชนีบทความสำหรับ llms.txt สิ่งเหล่านี้เป็นผลิตภัณฑ์ที่สร้างขึ้น ไม่ใช่ชุดเนื้อหาอื่นที่ต้องมีการซิงโครไนซ์ด้วยตนเอง
อย่างไรก็ตาม ขอบเขตของ SEO หลายภาษาจะต้องมีความชัดเจน: **ปัจจุบัน การอัปเดตและบทความใช้ URL เดียวกันในแต่ละภาษา และภาษาจะถูกเปลี่ยนโดยส่วนหน้า หน้าเนื้อหาคงที่ ฟีด และเวอร์ชัน Markdown จะคงข้อความต้นฉบับไว้ ** หน้าแรกยังมีการเรนเดอร์ภาษาและโหมดแสงและมืดล่วงหน้าด้วย นี่ไม่ได้หมายความว่าแต่ละบทความจะมีหน้าภาษาที่สามารถจัดทำดัชนีได้อย่างอิสระ 22 หน้า
หากคุณจำเป็นต้องอนุญาตให้เครื่องมือค้นหารวมตระกูลภาษาแต่ละภาษาไว้ในอนาคต คุณจะต้องเพิ่มการกำหนดเส้นทางตระกูลภาษา หน้าคงที่ที่เกี่ยวข้อง และ hreflang นั่นเป็นข้อกำหนดอีกประการหนึ่งที่ชุดนี้ยังไม่บรรลุผล
การโพสต์ก็เป็นขั้นตอนการจัดส่งเช่นกัน#
ขั้นตอนการเผยแพร่ของฉันคือ: เขียนข้อความต้นฉบับ สร้างการแปล ตรวจสอบเนื้อหา ส่งไปที่ Git แล้วรวมเข้ากับ main GitHub Actions ที่มีอยู่จะสร้างเว็บไซต์ใหม่และปรับใช้
npm run content:localize
npm run content:check
npm run test:content
npm run build
หากคำแปลยังไม่ครบทุกภาษา ฉันจะเติมให้ครบก่อน บทความที่ยังเป็นฉบับร่างจะอยู่ในตัวอย่างบนเครื่องเท่านั้น ผลลัพธ์ production ยังตรวจด้วยว่าไม่มีหน้าฉบับร่าง และค้นหาเครื่องหมายฉบับร่างในไฟล์สาธารณะหลัก เช่น feed, sitemap, หน้าแรก และ JavaScript bundle เนื้อหาก็มี diff และประวัติเวอร์ชันเหมือนโค้ด และสามารถย้อนกลับพร้อมกันได้
วิธีการนี้จะเสียสละการอัปเดตแบบเรียลไทม์ หากคุณเปลี่ยนข้อความ คุณจะต้องรอการปรับใช้ แต่สำหรับเว็บไซต์ด้านเทคนิคของฉัน ฉันยินดีที่จะแลกเปลี่ยนการรอคอยนี้เพื่อแลกกับแบ็กเอนด์ที่น้อยกว่าหนึ่งรายการ การพึ่งพาระยะเวลาดำเนินการน้อยกว่าหนึ่งรายการ และบันทึกการเปลี่ยนแปลงที่ติดตามได้ง่ายกว่า
เมื่อใดจึงควรทำเช่นนี้?#
หากคุณเป็นผู้เขียน ความถี่ในการโพสต์สามารถสร้างขึ้นใหม่ได้ เนื้อหาส่วนใหญ่เป็นข้อความ และคุณคุ้นเคยกับ Git สถาปัตยกรรมนี้เหมาะสมมาก การอัปเดตแบบสั้นช่วยลดเกณฑ์การเขียน บทความยังคงรักษาที่มาที่สมบูรณ์ และหลายภาษาทำให้ผู้คนสามารถอ่านเนื้อหาเดียวกันได้มากขึ้น
หากข้อกำหนดกลายเป็นการทำงานร่วมกันแบบเรียลไทม์ระหว่างบุคคลหลายคน การจัดการสิทธิ์ ความคิดเห็นของผู้อ่าน การเข้าสู่ระบบหรือการสมัครสมาชิก CMS และแบ็กเอนด์จำเป็นต้องได้รับการประเมินอีกครั้ง ส่วนหน้าที่แท้จริงจะไม่ทำให้ความต้องการเหล่านี้หายไปโดยอัตโนมัติ แต่ฉันยังไม่ได้รวมไว้ในขอบเขตของบล็อกนี้ในขณะนี้
หลักการออกแบบในครั้งนี้ใกล้เคียงกับสิ่งที่ฉันเขียนไว้ใน รูปแบบการออกแบบสถาปัตยกรรมสำหรับหลาย layout และหลาย theme: อันดับแรกแยกความรับผิดชอบให้ชัดเจน จากนั้นปล่อยให้กฎที่ใช้ร่วมกันรักษาความสอดคล้องกัน
สำหรับเว็บไซต์นี้ ประเด็นสำคัญคือการอนุญาตให้ฉันเขียนต่อไปและรู้ว่าเนื้อหาใดที่ถูกส่งจริงทุกครั้งที่ฉันเผยแพร่