> For the complete documentation index, see [llms.txt](https://overleaf-pro.ayaka.space/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://overleaf-pro.ayaka.space/latex/vi/bai-viet-chuyen-sau/51-unicode-utf-8-and-multilingual-text-an-introduction.md).

# Unicode, UTF-8 và văn bản đa ngôn ngữ: Giới thiệu

## Unicode và OpenType: Ký tự và glyph

Các bộ máy TeX hiện đại, tức XeTeX và LuaTeX, đã phát triển từ bộ máy TeX nguyên bản của Knuth chủ yếu do nhu cầu phải theo kịp những tiến triển trong bối cảnh công nghệ, đặc biệt là Unicode (cho văn bản) và OpenType (cho phông chữ). Ngày nay, thông qua việc sử dụng các gói như [fontspec](https://ctan.org/pkg/fontspec?lang=en) và [unicode-math](https://ctan.org/pkg/unicode-math?lang=en), người dùng LaTeX có thể truy cập các khả năng dàn trang cực kỳ tinh vi do phông chữ OpenType cung cấp — bao gồm dàn trang đa ngôn ngữ nâng cao và dàn trang toán học dựa trên OpenType ([do Microsoft khởi xướng](https://blogs.msdn.microsoft.com/murrays)).

Tuy nhiên, để tận dụng tối đa việc dùng phông chữ OpenType với XeTeX/LuaTeX, có thể hữu ích nếu làm quen với một số chủ đề/khái niệm nền tảng — đặc biệt là khi khắc phục sự cố hoặc mở đường cho công việc nâng cao/phức tạp hơn. Ví dụ, bạn có thể đọc rằng các bộ máy XeTeX và LuaTeX dùng “đầu vào UTF-8” hoặc rằng chúng “nhận biết Unicode”, và khi tìm hiểu thêm về phông chữ OpenType, bạn có thể thấy các chủ đề như “mã hóa Unicode”, “tính năng phông chữ” của OpenType, “glyph”, “ID glyph”, “tên glyph”, v.v. Mục tiêu của chúng tôi là giới thiệu các thuật ngữ/chủ đề này và ghép lại một khuôn khổ cơ bản để cho thấy chúng liên hệ với nhau như thế nào và, hy vọng, hỗ trợ cho công việc tiếp theo hoặc giải quyết vấn đề.

Các chủ đề chúng tôi dự định đề cập chia khá gọn thành hai lĩnh vực chính: *Unicode* về thực chất, cư trú trong thế giới của văn bản/ký tự và mã hóa văn bản, và *OpenType* thế giới của nó là phông chữ và glyph; nhưng tất nhiên, hai thế giới đó có liên hệ với nhau và có sự giao thoa, ngay cả trong bài viết đầu tiên này.

### Chúng ta sẽ thảo luận những chủ đề nào?

Trọng tâm chính của bài viết này là một số chủ đề liên quan đến Unicode: bắt đầu bằng việc bàn về ý nghĩa của “ký tự” rồi chuyển sang giới thiệu hệ chữ/ngôn ngữ, mã hóa Unicode và UTF-8 — cùng với một ví dụ làm việc với các tệp văn bản đa ngôn ngữ. Một bài viết tiếp theo sẽ phát triển từ bài này để đề cập đến các chủ đề nền tảng liên quan đến công nghệ phông chữ OpenType. Rõ ràng, trong giới hạn của một bài blog thì không thể cố gắng “đào sâu” vào tất cả các lĩnh vực mà chúng tôi hy vọng bàn tới: mục tiêu đã nêu của chúng tôi là cung cấp một khuôn khổ tổng thể cho thấy một vài khái niệm then chốt liên hệ và phối hợp với nhau như thế nào. Chúng ta sẽ bắt đầu với khái niệm cơ bản nhất: đó là *ký tự*.

## Ký tự: Một viên gạch cơ bản

Một ý tưởng/khái niệm nền tảng là trung tâm của các thảo luận của chúng ta (và của Unicode) là ý nghĩa của “ký tự”: đây là một trong những từ mà ý nghĩa của nó thường được “mặc định” thông qua cách dùng trong công việc và trò chuyện hằng ngày. Tuy nhiên, từ góc nhìn của Unicode, dàn trang và công nghệ phông chữ, chúng ta cần chính xác hơn một chút và định nghĩa “một ký tự” nghĩa là gì. Ví dụ, với chúng ta có thể khá tự nhiên khi nghĩ về **a** và *a* như những “ký tự” khác nhau: ‘a đậm’ và ‘a nghiêng’. Nhưng không phải vậy: chúng chỉ là những biểu diễn trực quan khác nhau của cùng một ký tự nền tảng, mà Unicode đặt tên chính thức là [CHỮ LATIN THƯỜNG A](http://unicode.org/charts/PDF/U0000.pdf).

Unicode [định nghĩa một ký tự](http://www.unicode.org/glossary/#character) là:

> “Thành phần nhỏ nhất của ngôn ngữ viết có giá trị ngữ nghĩa; đề cập đến ý nghĩa và/hoặc hình dạng trừu tượng, thay vì một hình dạng cụ thể...”

làm rõ ràng sự phân biệt giữa *hình thức trực quan* hình dạng cụ thể *và*.

ý nghĩa *hệ chữ*Bạn có thể xem một ký tự như đơn vị cơ bản, hoặc viên gạch xây dựng, của một ngôn ngữ hoặc, chính xác hơn, của một *và* —một chủ đề chúng tôi bàn dưới đây. Hình dáng thực tế của một ký tự khi được hiển thị bằng một phông chữ cụ thể không liên quan đến định nghĩa ký tự của Unicode: điều thực sự đáng quan tâm ở đây chỉ là *vai trò và mục đích* của mỗi ký tự như một trong những khối xây dựng từ đó cuối cùng hình thành nên các hệ chữ/ngôn ngữ.

### Hệ chữ và ngôn ngữ

Cũng đáng đề cập ngắn gọn hai khái niệm quan trọng: *các hệ chữ* và *ngôn ngữ*. Trang web Unicode cung cấp một [định nghĩa hữu ích về một hệ chữ](https://www.unicode.org/standard/supported.html):

> “Chuẩn Unicode mã hóa các hệ chữ chứ không phải ngôn ngữ. Khi các hệ thống chữ viết cho hơn một ngôn ngữ chia sẻ các bộ ký hiệu đồ họa có nguồn gốc lịch sử liên quan, thì hợp của tất cả các ký hiệu đồ họa đó được coi là một tập hợp ký tự duy nhất để mã hóa và được xác định là một hệ chữ duy nhất.”

Sử dụng một [ví dụ từ Wikipedia](https://en.wikipedia.org/wiki/Script_\(Unicode\)), hệ chữ Latinh bao gồm một [tập hợp ký tự](http://unicode.org/charts/) được dùng trên nhiều ngôn ngữ: tiếng Anh, tiếng Pháp, tiếng Đức, tiếng Ý, v.v. Tất nhiên, không phải mọi ký tự được định nghĩa trong hệ chữ Latinh đều được tất cả các ngôn ngữ dựa trên hệ chữ Latinh sử dụng — ví dụ, bảng chữ cái tiếng Anh không có các ký tự có dấu xuất hiện trong những ngôn ngữ châu Âu khác như tiếng Pháp hay tiếng Đức.

### Phông chữ OpenType: hệ chữ và ngôn ngữ

Tại đây chúng ta sẽ chuyển từ Unicode sang phông chữ OpenType vì các khái niệm hệ chữ và ngôn ngữ cũng đóng vai trò cực kỳ quan trọng trong công nghệ phông chữ OpenType.

Một tập hợp các ngôn ngữ dùng cùng một [hệ chữ](http://www.unicode.org/glossary/#script) có thể mỗi ngôn ngữ có những truyền thống kiểu chữ khác nhau khi hiển thị (dàn trang) văn bản được viết bằng một ngôn ngữ cụ thể. Một ví dụ điển hình là tiếng Thổ Nhĩ Kỳ và [hành vi của chữ i không chấm](https://en.wikipedia.org/wiki/Dotted_and_dotless_I) (xem phần ghi chú của trang đó về liên tự). Các “quy tắc” kiểu chữ liên quan đến hệ chữ/ngôn ngữ được tích hợp vào chức năng của phông chữ OpenType thông qua việc sử dụng cái gọi là các *các thẻ* mã định danh hệ chữ và ngôn ngữ [gói fontspec](https://ctan.org/pkg/fontspec?lang=en).

#### Nhìn vào bên trong một phông chữ OpenType: hệ chữ/ngôn ngữ

Để làm rõ hơn, đây là một ảnh chụp màn hình cho thấy phông chữ OpenType miễn phí [Scheherazade](http://software.sil.org/scheherazade/download/) được mở trong phần mềm chỉnh sửa phông chữ (cũng miễn phí) [Microsoft VOLT](https://www.microsoft.com/en-us/Typography/volt.aspx) Trong hình này bạn có thể thấy các hệ chữ, ngôn ngữ và tính năng kiểu chữ được tích hợp trong Scheherazade — dùng VOLT bạn có thể thêm các tính năng và chức năng bổ sung vào Scheherazade, nhưng điều đó vượt xa phạm vi của bài viết này!

![Phông chữ Scheherazade OpenType (định dạng TrueType) được mở trong Microsoft VOLT](/files/4f7470df970b91ccdbf0e932b99a0d62d5e4ffe7)

Từ ảnh chụp màn hình này, bạn có thể thấy Scheherazade hỗ trợ các hệ chữ Ả Rập và Latinh, đồng thời cung cấp hỗ trợ chuyên biệt hơn cho một số ngôn ngữ dùng hệ chữ Ả Rập — thông qua cái gọi là các tính năng OpenType, được liệt kê trong khung viền xanh phía trên. Chúng ta sẽ không đi vào chi tiết của các tính năng này, nhưng thông điệp ở đây là các phông chữ OpenType chất lượng cao có rất nhiều “trí thông minh” được tích hợp sẵn, sẵn sàng cho phần mềm dàn trang có khả năng tận dụng các quy tắc kiểu chữ được nhúng trong phông chữ.

Người đọc quan tâm có thể duyệt qua sổ đăng ký thẻ OpenType để xem [các thẻ hệ chữ](https://www.microsoft.com/typography/otspec/scripttags.htm) và [các thẻ ngôn ngữ](https://www.microsoft.com/typography/developers/opentype/languagetags.aspx) hiện đang được dùng trong đặc tả OpenType.

### Quay lại với ký tự: Các vai trò ký tự khác nhau

Tập hợp các ký tự cấu thành những yếu tố cơ bản của một hệ chữ (hoặc ngôn ngữ) không phải tất cả đều thực hiện cùng một vai trò. Ví dụ, trong hầu hết các ngôn ngữ đều có ký tự cho *dấu câu*, ký tự cho các *chữ số* số, cũng như các ký tự mà chúng ta nghĩ là *chữ cái* của bảng chữ cái, mà với một số hệ chữ, còn tồn tại ở dạng chữ hoa và chữ thường. Khái niệm ký tự khá rộng và Chuẩn Unicode bao gồm các ký tự chuyên biệt *không được thiết kế để hiển thị* nhưng nhiệm vụ của chúng là “điều khiển việc diễn giải hoặc hiển thị văn bản”. Ví dụ, khi dàn trang một số văn bản Ả Rập, bạn có thể muốn ép buộc hoặc ngăn chặn hành vi nối chữ của một số ký tự; chuẩn Unicode cung cấp các ký tự điều khiển đặc biệt để làm điều này: cái gọi là [ZERO WIDTH JOINER](https://en.wikipedia.org/wiki/Zero-width_joiner) và [ZERO WIDTH NON-JOINER](https://en.wikipedia.org/wiki/Zero-width_non-joiner). Những ký tự đó không nhằm mục đích hiển thị và sẽ được phần mềm “hấp thụ” trong quá trình xử lý văn bản để tạo ra hiệu ứng thị giác dự định.

Tất cả các ký tự được chỉ định trong chuẩn Unicode đều được gán một bộ thuộc tính, về thực chất mô tả vai trò và mục đích của từng ký tự trong mã hóa Unicode — tên ký tự, chẳng hạn như LATIN SMALL LETTER A, chỉ là một phần trong danh sách thuộc tính của ký tự. Các thuộc tính này được mô tả đầy đủ trong [Cơ sở dữ liệu ký tự Unicode (UCD)](http://www.unicode.org/reports/tr44/) và được dùng rộng rãi trong các thao tác xử lý văn bản bằng máy tính như tìm kiếm, sắp xếp, kiểm tra chính tả, v.v. Các tệp dữ liệu liệt kê thuộc tính ký tự Unicode cũng [có thể tải xuống](http://www.unicode.org/Public/UCD/latest/).

Trong các thuộc tính được gán cho mỗi ký tự, thuộc tính quan trọng nhất đối với cuộc thảo luận của chúng ta là một *mã định danh số* được gán bởi mã hóa Unicode của nó, một chủ đề mà chúng ta sẽ chuyển sang ngay bây giờ.

### Ký tự: Số và mã hóa

Nói điều hiển nhiên nhưng máy tính và các thiết bị số khác làm việc với việc lưu trữ và xử lý dữ liệu số: vậy điều này liên quan thế nào đến văn bản? Khi bạn gõ một đoạn văn bản bằng bàn phím máy tính, hoặc bằng cách chạm vào màn hình của thiết bị di động, các lần nhấn phím của bạn sẽ được chuyển thành các con số biểu thị chuỗi ký tự bạn đang nhập.

Đến một lúc nào đó bạn có thể muốn truyền đoạn văn bản đó (một dãy số) qua e-mail, tin nhắn văn bản hoặc qua các kênh liên lạc trực tuyến như Tweet hay bài đăng trên một số hình thức mạng xã hội. Rõ ràng, thiết bị mà bạn soạn văn bản và thiết bị mà người nhận dùng phải, bằng cách nào đó, thống nhất về số nào đại diện cho ký tự nào. Nếu không, văn bản của bạn có thể sẽ không được hiển thị đúng trên thiết bị của người nhận.

Để giao tiếp toàn cầu ngày nay hoạt động được, các thiết bị gửi và nhận cần một “quy ước được hai bên cùng thỏa thuận” theo đó một tập hợp số nhất định đại diện cho một tập hợp ký tự cụ thể. Quy ước này được gọi là một *mã hóa*: một tập hợp số được dùng để biểu thị một tập hợp ký tự cụ thể và mã hóa Unicode hiện nay là tiêu chuẩn toàn cầu *trên thực tế* .

## Unicode: bit và byte để lưu trữ văn bản

Unicode là một chuẩn khổng lồ bao trùm nhiều hơn rất nhiều so với chỉ mã hóa văn bản, nhưng ở đây chúng ta chỉ tập trung vào phần mã hóa mà nó cung cấp.

#### Bit, byte và có bao nhiêu ký tự?

Chúng ta đã nói rằng thiết bị lưu trữ và biểu diễn văn bản dưới dạng số — cụ thể, các ký tự sẽ được lưu dưới dạng số nguyên: các số nguyên. Để hiểu ý nghĩa của điều này đối với mã hóa Unicode, chúng ta cần có một *rất* ngắn, *rất* cơ bản, xem lại cách máy tính lưu số nguyên (chúng tôi không định đi sâu vào khoa học máy tính).

Nói ngắn gọn cho xong một câu chuyện rất dài, các thiết bị để bàn hoặc cầm tay ngày nay lưu số nguyên trong các “khối” rời rạc có thể dài 1, 2, 4 hoặc 8 byte. Mỗi đơn vị lưu trữ này có thể lưu số nguyên lên tới một giá trị dương tối đa dựa trên tổng số bit có trong mỗi đơn vị lưu trữ:

* 1 byte (8 bit): số nguyên dương tối đa là 255;
* 2 byte (16 bit): số nguyên dương tối đa là 65535;
* 4 byte (32 bit): số nguyên dương tối đa là 4,294,967,295;
* 8 byte (64 bit): số nguyên dương tối đa là 18,446,744,073,709,551,615.

Trong thực tế, chuẩn Unicode dùng các số trong phạm vi từ 0 đến 1,114,111 để mã hóa toàn bộ ký tự trên thế giới, kết quả là chỉ cần 21 bit để mã hóa toàn bộ phạm vi. Ta có thể thấy điều này bằng cách lưu ý rằng các đơn vị lưu trữ chứa n bit có thể biểu diễn bất kỳ số nguyên dương nào từ 0 đến giá trị tối đa là $$2^n -1$$; do đó:

* giá trị tối đa có thể lưu trong 20 bit là $$2^{20} -1 = 1,048,575$$ (quá nhỏ);
* giá trị tối đa có thể lưu trong 21 bit là $$2^{21} -1 = 2,097,151$$ (đủ lớn).

Chúng ta đã lưu ý rằng máy tính lưu dữ liệu (con số) trong các đơn vị 1, 2, 4 (hoặc 8) byte, vậy đơn vị lưu trữ cần lớn đến mức nào nếu chúng ta phải lưu các giá trị lên tới giá trị Unicode tối đa 1,114,111? Rõ ràng, một đơn vị lưu trữ cỡ byte chỉ có thể chứa giá trị tối đa 255 và 2 byte có thể lưu 65535: cả hai đều không đủ để lưu toàn bộ phạm vi ký tự được Unicode mã hóa. Lựa chọn tiếp theo là các đơn vị lưu trữ có kích thước 4 byte, có thể lưu số nguyên lên tới tối đa 4,294,967,295 — lớn hơn rất nhiều so với nhu cầu thực tế của chúng ta. Vì vậy, nếu chọn 4 byte làm đơn vị lưu trữ, chắc chắn chúng ta có đủ chỗ để lưu tất cả giá trị Unicode, với mỗi ký tự được lưu dưới dạng một số nguyên cần 4 byte (32 bit). Tuy nhiên, dùng 4 byte để lưu mọi thứ là rất lãng phí không gian vì ngay cả các giá trị Unicode lớn nhất cũng chỉ cần tối đa 21 bit — nếu lưu bằng 32 bit, điều đó có nghĩa là 11 trong số 32 bit ấy sẽ không bao giờ được dùng.

**Lưu ý**: Mặc dù phạm vi Unicode trải từ 0 đến 1,114,111 nhưng không phải mọi giá trị trong phạm vi đó đều thực sự được dùng: vì lý do kỹ thuật, một số giá trị được xem là không hợp lệ để sử dụng thực tế làm ký tự Unicode.

### Vậy UTF-8 là gì?

Nếu bạn đọc về XeTeX hoặc LuaTeX, bạn gần như chắc chắn sẽ gặp các giải thích nói rằng các bộ máy TeX đó đọc văn bản và tệp đầu vào LaTeX ở “định dạng UTF-8”. Vậy “định dạng UTF-8” là gì và nó liên quan thế nào đến Unicode? Theo thuật ngữ Unicode, mỗi một trong 1,114,112 giá trị của nó (từ 0 đến 1,114,111) dùng để mã hóa các ký tự trên thế giới được gọi là một [mã điểm](http://www.unicode.org/glossary/#code_point).

Chúng ta đã thấy rằng, *về mặt lý thuyết*, chúng ta sẽ cần lưu toàn bộ văn bản được mã hóa Unicode bằng 4 byte cho mỗi ký tự để biểu diễn toàn bộ phạm vi các mã điểm của Unicode. Tuy nhiên, trên thực tế, một số người rất thông minh đã nghĩ ra một cách đơn giản để biểu diễn một số Unicode đơn lẻ (mã điểm) như một *chuỗi* của các số nhỏ hơn, mỗi số nhỏ hơn đó được lưu trong một byte duy nhất: một quá trình *biến đổi* một số nguyên đơn lẻ (lớn hơn) thành một chuỗi các số nhỏ hơn (kích thước một byte). Nhờ quá trình biến đổi này, các ký tự trong tệp văn bản của chúng ta không còn mỗi ký tự được biểu diễn bằng một giá trị số duy nhất nữa: mỗi ký tự trở thành một *chuỗi nhiều byte*—bất cứ từ 1 đến 4 byte (liền nhau) trong tệp văn bản đều có thể biểu diễn một ký tự Unicode riêng lẻ (tức giá trị mã điểm của nó).

UTF là viết tắt của *Unicode Transformation Format* và từ khóa quan trọng ở đây là *Transformation*. Về bản chất, bạn có thể xem UTF-8 như một “công thức” hay thuật toán để chuyển đổi (biến đổi) một giá trị mã điểm Unicode đơn lẻ thành một chuỗi gồm 1 đến 4 phần kích thước byte. Khi giá trị mã điểm Unicode tăng lên thì số byte đơn lẻ cần để biểu diễn nó ở định dạng UTF-8 cũng tăng theo.

Có những lý do kỹ thuật và lịch sử cho việc tạo ra UTF-8 và câu chuyện đằng sau sự ra đời của UTF-8 [được ghi lại trong một email thú vị từ năm 2003](https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt), mà gần đầu email có chứa dòng:

> “Điều đó không đúng. UTF-8 đã được thiết kế, ngay trước mắt tôi, trên một tấm lót bàn trong một quán ăn ở New Jersey vào một đêm nào đó của tháng 9 năm 1992.”

#### Ví dụ: chữ Ả Rập ل

Hãy lấy ví dụ chữ Ả Rập ل (tên Unicode ARABIC LETTER LAM) được gán giá trị mã điểm Unicode là 1604 (thập phân) hoặc 0644 (thập lục phân): biểu diễn của nó trong UTF-8 là *chuỗi hai byte* D9 84 (hex) hoặc, ở hệ thập phân, 217 132. Khi dùng UTF-8 làm định dạng lưu trữ văn bản, thay vì một tệp văn bản chứa số 1604 duy nhất để biểu diễn ل, nó được chuyển thành hai giá trị kích thước byte: 217 và 132 — ký tự ل được lưu dưới dạng một *chuỗi hai byte*. Người đọc muốn tìm hiểu sâu hơn về thuật toán UTF-8 có thể tìm thấy phần giải thích chi tiết, cùng mã C, trên [trang blog cá nhân của tác giả này](http://www.readytext.co.uk/?p=1284).

Khi một phần mềm (ví dụ XeTeX hoặc LuaTeX) đọc văn bản ở định dạng UTF-8, phần mềm đó cần xác định giá trị Unicode cho từng ký tự có trong tệp, vì vậy nó dùng một thuật toán để *đảo ngược* quá trình biến đổi UTF-8. Thông qua “thuật toán đảo ngược” đó, hai byte (217 và 132) được ghép lại để tạo ra số nguyên 1604, rồi con số này có thể được nhận ra là giá trị mã điểm Unicode của chữ Ả Rập ل.

Vì vậy, kết luận lại, UTF-8 thực ra chỉ là một định dạng dữ liệu trung gian dùng để lưu trữ và truyền tải văn bản được mã hóa Unicode.

**Lưu ý**: Một số hệ thống chọn dùng/lưu văn bản với 32 bit cho mỗi ký tự; điều này được gọi là [UTF-32](https://en.wikipedia.org/wiki/UTF-32)—cũng còn có [UTF-16](https://en.wikipedia.org/wiki/UTF-16) nhưng UTF-8 là cách phổ biến nhất để lưu văn bản được mã hóa Unicode.

## Các tệp TeX đa ngôn ngữ: XeTeX và LuaTeX

Cả XeTeX và LuaTeX đều có khả năng dàn trang đa ngôn ngữ rất tinh vi, mặc dù cơ chế để đạt được điều đó khá khác nhau và phản ánh triết lý thiết kế/phát triển của từng bộ máy. Chúng tôi sẽ không đi sâu vào điều này mà chỉ lưu ý rằng bộ máy XeTeX có các thành phần phần mềm (được tích hợp trong tệp thực thi của nó) không có trong LuaTeX — nổi bật nhất là phần mềm cho một quá trình gọi là *OpenType shaping* (ví dụ, thông qua một thư viện gọi là [HarfBuzz](https://www.freedesktop.org/wiki/Software/HarfBuzz/)).

Ngược lại, LuaTeX áp dụng một cách tiếp cận khác: thay vì tích hợp trực tiếp các chức năng vào chính bộ máy TeX, LuaTeX cung cấp một bộ lệnh (các nguyên thủy TeX) vô cùng phong phú và một [API dựa trên Lua](/latex/vi/bai-viet-chuyen-sau/07-an-introduction-to-luatex-part-1-what-is-it-and-what-makes-it-so-different.md) rất mạnh mẽ, qua đó các nhà phát triển có thể xây dựng những giải pháp đa ngôn ngữ cũng tiên tiến không kém. Mặc dù triết lý của LuaTeX có thể đòi hỏi thêm công sức đối với các nhà phát triển gói LaTeX, nó mang lại rất nhiều sự linh hoạt bổ sung vì các giải pháp không được “mã cứng” vào chính bộ máy LuaTeX, mà được xây dựng từ mã TeX và Lua — hoặc các plugin viết bằng C/C++.

**Lưu ý bên lề**: Những độc giả muốn tìm hiểu thêm về thế giới hấp dẫn nhưng phức tạp của OpenType shaping có thể muốn đọc về thư viện mã nguồn mở tuyệt vời có tên là [HarfBuzz](https://www.freedesktop.org/wiki/Software/HarfBuzz/)—được nhiều ứng dụng sử dụng, bao gồm Firefox, Chrome và LibreOffice, và dĩ nhiên cả XeTeX. Tác giả của bài viết này đã dùng HarfBuzz để tạo ra [các plugin LuaTeX để dàn trang tiếng Ả Rập](http://www.readytext.co.uk/?p=3186).

Ngày nay khá phổ biến (ví dụ trên mạng xã hội) khi truyền tải văn bản chứa ký tự từ nhiều ngôn ngữ khác nhau và một tệp văn bản UTF-8 lưu văn bản đa ngôn ngữ có thể dễ dàng chứa các ký tự có biểu diễn UTF-8 dài 1, 2, 3 hoặc 4 byte. Vì vậy, về thực chất, một tệp văn bản UTF-8 chỉ là một luồng các byte đơn lẻ nhưng mỗi ký tự thực tế trong tệp đó có thể dài từ 1 đến 4 byte: các ký tự riêng lẻ đã trở thành *chuỗi nhiều byte*.

Để tiếp tục khám phá một số khía cạnh chính khi làm việc (và dàn trang) với văn bản đa ngôn ngữ, chúng ta sẽ dùng một ví dụ chứa hệ chữ Ả Rập vì tiếng Ả Rập cho chúng ta không gian để đề cập nhiều khái niệm.

#### Lưu ý bên lề: hệ chữ Ả Rập

Tính năng [Hệ chữ Ả Rập](https://en.wikipedia.org/wiki/Arabic_script) được viết theo kiểu chữ nối và được đọc, viết từ phải sang trái. Mỗi chữ cái Ả Rập về mặt tiềm năng có thể mang một trong 4 hình dạng khác nhau tùy theo:

* việc nó được hiển thị như một ký tự đơn lẻ, đứng riêng (cô lập), không nối với gì khác;
* việc nó xuất hiện trong một từ — ở đầu, giữa hoặc cuối từ: được gọi là *dạng đầu*, *dạng giữa* và *bản cuối* tương ứng.

Mỗi ký tự của hệ chữ Ả Rập có bộ quy tắc nối riêng và có thể, hoặc không, thay đổi hình dạng/diện mạo khi có một ký tự khác ở bên trái, bên phải hoặc cả bên trái lẫn bên phải. Người đọc muốn tìm hiểu thêm có thể tìm thấy một [danh sách đầy đủ trên Wikipedia](https://en.wikipedia.org/wiki/Template:Arabic_alphabet_shapes/joining).

#### Ví dụ: văn bản Ả Rập và tiếng Anh trong UTF-8

Giả sử chúng ta tạo một tệp văn bản UTF-8 chứa một dòng văn bản tiếng Anh và Ả Rập: This is العَرَبِيَّة text!

Dòng văn bản này chứa 3 ký tự khoảng trắng, 11 ký tự tiếng Anh (hệ chữ Latinh) và 12 ký tự Ả Rập (mặc dù điều đó có thể không ngay lập tức rõ ràng). Khi lưu dưới dạng tệp văn bản UTF-8, nó chiếm 38 byte dung lượng lưu trữ, tạo ra từ những phần sau:

* **Hệ chữ Latinh**: khoảng trắng cộng với văn bản tiếng Anh: 14 ✕ ký tự 1 byte = 14 byte;
* **Hệ chữ Ả Rập**: 12 ký tự Ả Rập ✕ 2 byte cho mỗi ký tự = 24 byte.

Tổng cộng là 14 + 24 = 38 byte.

#### Đi sâu hơn

Nếu chúng ta lưu văn bản ví dụ của mình trong một tệp UTF-8 có tên `arabic.txt` và mở nó bằng một trình soạn thảo thập lục phân, chúng ta có thể kiểm tra để xem các byte thực tế mà nó chứa. Từ việc xem ảnh chụp màn hình có chú thích sau, bạn có thể thấy rằng văn bản Ả Rập được lưu với 2 byte cho mỗi ký tự:

![Một tệp văn bản UTF-8 chứa văn bản tiếng Anh và Ả Rập được mở trong trình soạn thảo hex.](/files/e81c1532760996d5662f7e77e3d5cfff6a44a328)

Một tệp văn bản UTF-8 chứa văn bản tiếng Anh và Ả Rập được mở trong trình soạn thảo hex. Bạn có thể thấy rõ rằng các ký tự hệ chữ Latinh cần một byte duy nhất nhưng các ký tự hệ chữ Ả Rập được lưu bằng hai byte cho mỗi ký tự.

Bạn có thể rút ra vài nhận xét từ ảnh chụp màn hình này:

* văn bản Ả Rập được lưu theo trình tự từ trái sang phải và các ký tự là các dạng nguyên bản (đứng riêng) chưa được tạo hình của các chữ cái và nguyên âm Ả Rập;
* không có thông tin bổ sung nào theo sau phần hệ chữ Latinh “This is ” để báo cho bất kỳ phần mềm nào đọc tệp này rằng ký tự tiếp theo thuộc hệ chữ Ả Rập.

Nếu bạn đang dàn trang một tài liệu đa ngôn ngữ (ví dụ, chứa tiếng Anh và tiếng Ả Rập), thì trong quá trình đọc/xử lý tệp văn bản đầu vào (như một luồng byte) XeTeX hoặc LuaTeX phải có khả năng phát hiện điểm bắt đầu và kết thúc của từng ký tự và đọc đúng số byte cần thiết để đảo ngược quá trình biến đổi UTF-8 và tạo ra mã điểm Unicode tương ứng. Chính thuật toán UTF-8 cho phép phần mềm làm được điều này: nó cho phép phát hiện byte đầu tiên của từng ký tự riêng lẻ và số byte cần đọc để tính toán mã điểm Unicode tương ứng. UTF-8 dễ dùng, nhưng thật sự rất khéo léo.

#### Thứ tự logic, thứ tự hiển thị và OpenType shaping

Nếu bạn nhìn kỹ vào phần tiếng Ả Rập ở trên (العَرَبِيَّة) có thể khó thấy rằng tệp văn bản của chúng ta thực sự chứa 12 ký tự Ả Rập riêng lẻ — đặc biệt nếu bạn không quen với hệ chữ Ả Rập! Tuy nhiên, nếu bạn đếm cẩn thận các ký tự Ả Rập hiển thị ở bên phải của ảnh chụp màn hình ở trên, bạn có thể thấy tổng cộng là 12.

Đối với các ngôn ngữ dùng hệ chữ phức tạp, chẳng hạn như tiếng Ả Rập, điều mà tệp văn bản của chúng ta *lưu* và điều bạn *thấy trên màn hình* trông rất *rất* khác nhau! Điều bạn thấy khi xem văn bản đó trong, chẳng hạn, một trình duyệt, là (tùy thuộc vào phông chữ được dùng):

![Hình ảnh văn bản Ả Rập đã được dàn trang](/files/ea40cfc4f74a21c30ca85fa0a94227f3073b8666)

Nhưng, như ảnh chụp màn hình ở trên cho thấy, cái mà tệp văn bản UTF-8 thực sự chứa là thế này:

![Hình ảnh văn bản Ả Rập chưa được dàn trang (các ký tự cô lập)](/files/bca0ddf7b58aa5d5b711286e96a800c294c4b2aa)

Ngay cả khi bạn không quen với tính chất nối nét của hệ chữ Ả Rập, bạn vẫn có thể thấy rõ rằng “điều gì đó” đã xảy ra trong quá trình chuyển các ký tự Ả Rập có trong một tệp văn bản sang dàn trang và/hoặc hiển thị trên màn hình (dưới dạng glyph). Nếu bạn đã quen dùng TeX/LaTeX với các ngôn ngữ hệ chữ đơn giản, ví dụ các ngôn ngữ dựa trên Latinh, điều này thật sự có thể rất khó hiểu!

Một số khái niệm quan trọng đang cùng hoạt động ở đây vì các tệp văn bản Unicode làm nhiệm vụ lưu trữ… à, văn bản (Unicode), còn hệ thống dàn trang và hiển thị làm nhiệm vụ dùng phông chữ và glyph (OpenType):

* tệp văn bản đã lưu các ký tự Ả Rập theo thứ tự từ trái sang phải nhưng tiếng Ả Rập được đọc/hiển thị từ phải sang trái: các tệp văn bản lưu văn bản theo cái gọi là *thứ tự logic*;
* tệp văn bản chứa các ký tự riêng lẻ trông rất khác với hình ảnh hiển thị thực tế trên màn hình: tệp văn bản chứa các ký tự Ả Rập ở dạng cô lập, chưa nối.

#### Chuyện gì đang xảy ra vậy?

Bên trong một tệp văn bản, tiếng Ả Rập được lưu dưới dạng chuỗi các ký tự ở dạng cô lập theo thứ tự từ trái sang phải: nếu nghĩ kỹ, tệp văn bản lưu văn bản Ả Rập theo thứ tự/chuỗi *mà nó đã được gõ* (phần *thứ tự logic*). Chỉ khi văn bản đó được xử lý để hiển thị, hoặc dàn trang, thì nó mới được hiển thị theo đúng thứ tự đọc, thường được gọi là *thứ tự trực quan* hoặc *thứ tự hiển thị*; ngoài ra, các dạng cô lập của các ký tự Ả Rập được *tạo hình* thành các phiên bản hiển thị đúng về mặt kiểu chữ. Có thể hiểu điều này theo cách là một tệp văn bản đơn giản phải lưu văn bản (các ký tự Unicode) ở dạng cơ bản nhất có thể: các ký tự văn bản thô, chưa tạo hình, riêng lẻ — nhiệm vụ của phần mềm hệ thống là kết xuất các ký tự đó để hiển thị dựa trên hệ điều hành, phông chữ và phần mềm dàn trang/kết xuất có sẵn trên thiết bị hiển thị.

Khi văn bản Ả Rập trong tệp đó được dàn trang/hiển thị, nó trải qua một quá trình gọi là *dàn hình*. Các ký tự Ả Rập riêng lẻ được chuyển thành các glyph đã tạo hình, biểu thị đúng biến thể của từng ký tự theo các quy tắc nối của hệ chữ và hệ thống chữ viết Ả Rập. Ngoài ra, phần mềm dàn trang chất lượng cao (dùng các phông chữ OpenType tốt) sẽ bổ sung thêm xử lý bằng cách áp dụng sự tinh vi kiểu chữ bổ sung thông qua một quá trình gọi là *OpenType shaping*—một quá trình bao hàm một loạt các thao tác kiểu chữ có thể bao gồm:

* thay thế nhiều glyph riêng lẻ bằng một glyph liên hợp phức tạp duy nhất (rất phổ biến trong tiếng Ả Rập), hoặc
* các thao tác định vị, chẳng hạn như điều chỉnh vị trí của các nguyên âm tiếng Ả Rập dựa trên glyph mà chúng nằm phía trên hoặc phía dưới.

![Hình ảnh cho thấy sự biến đổi mà văn bản tiếng Ả Rập trải qua khi được dàn chữ](/files/13560e38e4dd29b30da022f2b3a4f8a880d01d00)

Sự khác biệt giữa thứ tự logic và thứ tự trực quan (hiển thị). Trong đồ họa này, bạn có thể thấy rằng các ký tự tiếng Ả Rập được lưu trong một tệp văn bản sẽ trải qua việc sắp xếp lại và tạo hình khi chúng được hiển thị hoặc dàn chữ.

Các nhà thiết kế và người tạo ra các phông chữ OpenType nâng cao đầu tư rất nhiều thời gian và chuyên môn để cung cấp các khả năng kiểu chữ tinh vi được tích hợp trong phông chữ của họ.

Để tắt quá trình tạo hình đang được áp dụng cho văn bản tiếng Ả Rập, chúng ta có thể dùng công cụ miễn phí tuyệt vời, [BabelPad](http://www.babelstone.co.uk/Software/BabelPad.html) Trình soạn thảo văn bản Unicode (chỉ dành cho Windows) cho phép bạn tắt quá trình tạo hình để xem các ký tự thô, riêng lẻ, không nối (chưa tạo hình) thực sự có trong tệp văn bản—xem nửa dưới của ảnh chụp màn hình kết hợp này:

![Hình ảnh cho thấy khả năng tắt quá trình tạo hình OpenType của trình soạn thảo văn bản BabelPad](/files/23b33dc5213987f36768866d486f0ccf8af100a0)

Sử dụng trình soạn thảo văn bản Unicode BabelPad để bật quá trình tạo hình OpenType (hình trên) hoặc tắt nó (hình dưới). Tắt tạo hình OpenType giúp việc chỉnh sửa văn bản tiếng Ả Rập dễ dàng hơn nhiều.

Các khái niệm về thứ tự logic và thứ tự hiển thị, kết hợp với các quá trình tạo hình, có thể khá khó hiểu khi bạn lần đầu gặp chúng trong quá trình chỉnh sửa hoặc dàn chữ với các tệp văn bản đa ngôn ngữ chứa các hệ chữ phức tạp như tiếng Ả Rập: hy vọng phần trên đã giúp tránh bớt một số nhầm lẫn ban đầu.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://overleaf-pro.ayaka.space/latex/vi/bai-viet-chuyen-sau/51-unicode-utf-8-and-multilingual-text-an-introduction.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
