Kodokon kodokon.com

การทำสากลานุวัตร (Internationalization): lang, dir, charset และกับดัก Unicode

ใช้ lang, dir และการประกาศการเข้ารหัสอย่างชาญฉลาด และเอาชนะกับดักการทำ normalization ของ Unicode และทิศทางการอ่าน

9 นาที · 3 คำถาม

เปิดบทเรียนนี้ใน Kodokon

แอตทริบิวต์ lang เป็นมากกว่าเมตาดาต้า: มันขับเคลื่อนเสียงของโปรแกรมอ่านหน้าจอ การแบ่งพยางค์ (hyphens: auto ไม่ทำงานหากไม่มีมัน) การเลือกกลิฟ CJK (อักษรภาพเดียวกันถูกวาดต่างกันในภาษาญี่ปุ่นและจีน) เครื่องหมายอัญประกาศที่ <q> สร้างขึ้น และตัวเลือก CSS :lang() มันสืบทอดได้: ประกาศมันบน <html> ด้วยแท็ก BCP 47 (en, en-GB, ja) และแทนที่มันในระดับท้องถิ่นทุกครั้งที่เปลี่ยนภาษา

HTML
<html lang="en">
  <p>She said: <q>hello</q>.</p>
  <p lang="fr">Elle a dit : <q>bonjour</q>.</p>
</html>
อัญประกาศของ q ตามภาษา: “hello” แล้วก็ « bonjour »

dir=rtl พลิกการจัดแนวเริ่มต้นและลำดับภาพของอักขระที่มีทิศทางเป็นกลาง สำหรับเนื้อหาผู้ใช้ที่คาดเดาไม่ได้ dir=auto จะเลือกทิศทางตาม อักขระที่มีทิศทางชัดเจนตัวแรก องค์ประกอบ <bdi> แยกส่วนย่อยออกจากอัลกอริทึมสองทิศทาง (bidirectional): หากไม่มีมัน ชื่อผู้ใช้ภาษาอาหรับตามด้วย ": 12 points" จะเห็นเครื่องหมายวรรคตอนของมันถูกจัดเรียงใหม่จนกลายเป็นเรื่องไร้สาระ

HTML
<p dir="auto">مرحبا - inferred direction: RTL</p>
<ul>
  <li><bdi>مستخدم</bdi>: 12 points</li>
  <li><bdi>Alice</bdi>: 8 points</li>
</ul>
bdi ปกป้องเลย์เอาต์จากชื่อผู้ใช้แบบสองทิศทาง

การประกาศ <meta charset=utf-8> ต้องปรากฏ ภายใน 1024 ไบต์แรก ของเอกสาร: เบราว์เซอร์จะทำการสแกนล่วงหน้า (prescan) ที่จำกัดอยู่ในหน้าต่างนั้นก่อนเลือกการเข้ารหัส หากไม่มีการประกาศและไม่มีส่วนหัว HTTP การเข้ารหัสเริ่มต้นจะขึ้นอยู่กับ locale ของผู้ใช้ (มักเป็น windows-1252 ในยุโรปตะวันตก) - ไม่เคยเป็น UTF-8 อย่างไรก็ตาม BOM ที่จุดเริ่มต้นของไฟล์จะแทนที่ทุกอย่าง รวมถึงส่วนหัว HTTP ด้วย

JAVASCRIPT
const composed = "\u00e9";
const decomposed = "e\u0301";
console.log(composed === decomposed); // false
const nfc = decomposed.normalize("NFC");
console.log(composed === nfc);        // true
“é” สองตัวที่ดูเหมือนกันด้วยตา แต่ต่างกันในหน่วยความจำ

macOS จัดเก็บชื่อไฟล์บางชื่อในรูปแบบที่แยกส่วน (NFD): ดังนั้น "é" ที่มาจากการอัปโหลดจึงอาจต่างจากตัวที่พิมพ์บนแป้นพิมพ์ ทำ normalize อินพุตของผู้ใช้ทั้งหมดให้เป็น NFC อย่างเป็นระบบก่อนจัดเก็บหรือเปรียบเทียบมัน สุดท้าย .length นับหน่วยรหัส UTF-16 ไม่ใช่อักขระที่รับรู้ได้: อีโมจิครอบครัวรวมมันมากกว่าเจ็ดตัว; ใช้ Intl.Segmenter เพื่อนับกราฟีม (grapheme) จริง

ทดสอบความรู้

ตรวจสอบว่าคุณจำประเด็นสำคัญของบทเรียนนี้ได้ครบถ้วน

  1. การประกาศ <meta charset=utf-8> ต้องตั้งอยู่ที่ไหนอย่างจำเป็น?
    • ที่ใดก็ได้ใน <head>
    • ภายใน 1024 ไบต์แรกของเอกสาร
    • ก่อนการประกาศ DOCTYPE
    • ภายใน 512 ไบต์แรกของ <body>
  2. dir=auto กำหนดทิศทางขององค์ประกอบอย่างไร?
    • มันตรวจสอบอักขระที่มีทิศทางชัดเจนตัวแรกของเนื้อหา
    • มันใช้ทิศทางที่ประกาศไว้บนองค์ประกอบ <html>
    • มันนับอักขระ RTL และ LTR แล้วเก็บฝ่ายข้างมากไว้
  3. ทำไมสตริงสองตัวที่แสดง “é” เหมือนกันจึงต่างกันได้สำหรับ ===?
    • เพราะตัวหนึ่งถูกเข้ารหัสใน UTF-8 และอีกตัวใน UTF-16
    • เพราะการทำตัวพิมพ์ใหญ่-เล็กของ Unicode ต่างกันตาม locale
    • เพราะตัวหนึ่งใช้อักขระประกอบสำเร็จ U+00E9 และอีกตัวใช้ลำดับที่แยกส่วน e + U+0301