Nội dung bài viết
Nguyễn Tấn Công Ngày nay, tiếng Anh được xem là ngôn ngữ được sử dụng phổ biến nhất thế giới. Bởi vậy, hầu hết các game hiện nay đều sử dụng tiếng Anh là ngôn ngữ chính. Tuy nhiên phát triển game đa ngôn ngữ hiện nay rất quan trọng, giúp game tiếp cận với các khách hàng mục tiêu tốt hơn và giúp nhà phát triển truyền đạt trọn vẹn tư tưởng của game đến mọi người.

Giới thiệu

Ngày nay, tiếng Anh được xem là ngôn ngữ được sử dụng phổ biến nhất thế giới. Bởi vậy, hầu hết các game, hệ thống hiện nay đều sử dụng tiếng Anh là ngôn ngữ chính. Tuy nhiên, để đưa sản phẩm gần gũi người dùng hơn, chúng ta cần thiết kế những đặc tính chuyên biệt cho từng nhóm người dùng, ngôn ngữ cũng là một đặc tính rất cần quan tâm. Nếu sử dụng "đơn" ngôn ngữ như tiếng Anh ta sẽ có ASCII, và nếu cần "đa" ngôn ngữ ta cần biết đến Unicode.

Tiền đề bài viết

Bài viết thuộc 1 phần tài liệu trong khóa đào tạo lập trình C++ Căn Bản Đến Nâng Cao của STDIO Training.

Đối tượng hướng đến

Bài viết này dành cho tất cả các lập trình viên mới làm game hoặc xử lý các vấn đề liên quan đến Unicode hoặc phần mềm đa ngôn ngữ và những người yêu thích công nghệ lập trình game. Đây là kiến thức nền cần thiết để chuẩn bị cho bước sau là hiện thực hóa dựa trên kiến thức Unicode và nền tảng lập trình cụ thể của các bạn.

Bảng mã ASCII

Bảng mã là quy ước quy định mối tương quan giữa các kí hiệu trong ngôn ngữ viết với các giá trị kiểu bit số. ASCII là một trong các bảng mã được sử dụng phổ biến nhất hiện nay. ASCII là một cách mã hoá các ký tự dựa trên các ký tự alphabet tiếng Anh. ASCII mã hoá 128 ký tự bao gồm số, 0-9, ký tự in thường a-z, ký tự in hoa A-Z, dấu chấm câu và các ký tự điều khiển sang số nguyên 7-bit.

Vì số lượng các kí hiệu thường được dùng trong ngôn ngữ tự nhiên, trong toán học (như · × ÷ ≠ ≥ ≈ π ) cũng như nhiều lĩnh vực khác lớn hơn nhiều so với bảng mã 128 ký tự nên chúng ta cần một bảng mã lớn hơn để có thể biểu diễn các ký tự còn lại. Đó là nguồn gốc ra đời bảng mã ASCII mở rộng. Bảng mã ASCII mở rộng bao gồm tất cả các kí hiệu trong bảng mã ASCII. Các bạn có thể tham khảo bảng mã ASCII và ASCII mở rộng tại Bảng Mã ASCII.

Cách thiết kế bảng mã ASCII có nhiều điểm rất hay, tôi sẽ chia sẻ cho các bạn 2 điểm mà tôi thấy được để các bạn tham khảo thêm.

Cách thiết kế

Các số 0-9 trong bảng mã ASCII được biểu diễn bằng các số có giá trị từ 48-57. Điều này sẽ không có gì đặc biệt nếu các bạn ghi giá trị sau khi biểu diễn ở dạng thập phân. Nếu ghi chúng ở dạng chuỗi nhị phân, các bạn sẽ thấy rằng giá trị sau khi biểu diễn sẽ bắt đầu bằng 3 bit 011 và nối sau đó là giá trị của số cần được biểu diễn. Xem ví dụ bảng dưới:

NHỊ PHÂN THẬP PHÂN KÝ TỰ
011 0000 48 0
011 0001 49 1
011 0010 50 2
011 0011 51 3
011 0100 52 4
011 0101 53 5
011 0110 54 6
011 0111 55 7
011 1000 56 8
011 1001 57 9

Các ký tự alphabet chữ hoa và chữ thường được biểu diễn trong 2 khoảng giá trị 65-90 và 97-122. Tại sao lại bảng mã lại được thiết kế theo cách này? Theo lẽ tự nhiên nếu xếp liên tục sẽ dễ nhớ hơn phải không? Quay lại bằng cách biểu diễn các ký tự ở dạng chuỗi nhị phân, ta sẽ thấy cặp các ký tự a-A, b-B, c-C… chỉ khác nhau 1 bit duy nhất.

KÝ TỰ THƯỜNG NHỊ PHÂN KÝ TỰ HOA NHỊ PHÂN
a 1100001 A 1000001
b 1100010 B 1000010
c 1100011 C 1000011
d 1100100 D 1000100
e 1100101 E 1000101
... ... ... ...

Bây giờ, bài toán chuyển các ký tự từ dạng chữ thường sang chữ hoa hoặc chữ hoa sang chữ thường sẽ trở nên đơn giản hơn nhiều khi chúng ta chỉ cần đảo 1 bit trong ký tự cần chuyển.

Bảng mã Unicode

Vì giới hạn số lượng các kí hiệu của các bảng mã trước đây (128 kí hiệu đối với bảng mã ASCII và 256 kí hiệu đối với bảng mã ASCII mở rộng) nên chúng không thể biểu diễn được tất cả các ký hiệu trong các ngôn ngữ khác như tiếng Việt, tiếng Nhật, tiếng Trung... Hiểu được giới hạn này, hiệp hội Unicode ở California đã cho ra đời bảng mã chuẩn quốc tế Unicode. Unicode được thiết kế để có thể biểu diễn hầu hết các ký hiệu trên thế giới hiện nay. Để mã hoá và lưu trữ các ký hiệu/ký tự trên bộ nhớ, Unicode đã đưa ra 3 chuẩn để mã hoá là UTF-8, UTF-16 và UTF-32. UTF-32 là chuẩn mã hoá đơn giản nhất để lưu trữ code point (mỗi kí hiệu/kí tự tương ứng với một con số trong bảng mã, con số này gọi là code point) trên bộ nhớ vì nó sử dụng 32-bit cho mỗi ký tự được biểu diễn. Nhược điểm của UTF-32 là dung lương lưu trữ quá lớn, những văn bản bằng tiếng Anh mã hoá bằng UTF-32 có thể có dung lượng gấp 4 lần so với văn bản tương đương được mã hoá bằng ASCII. Vì lý do đó, UTF-8 và UTF-16 hiện nay được sử dụng phổ biến hơn. Mỗi ký tự được mã hoá theo UTF-8 có độ lớn từ 1 byte đến 4 byte, mã hoá theo UTF-16 có độ lớn 2 byte hoặc 4 byte. UTF-8 thường được sử dụng trong các ứng dụng Web. UTF-16 little-endian là chuẩn mã hoá được sử dụng tại Microsoft (và trong hệ điều hành Windows).Vì dự án của tôi sử dụng UTF-16 nên tôi sẽ đi vào chi tiết của chuẩn này, các chuẩn còn lại các bạn có thể tự tìm hiểu thêm.

UTF-16

Mã hóa

Không quá nặng về lý thuyết, tôi sẽ đi thẳng vào các bước thực hiện quá trình mã hoá UTF-16 và cho ví dụ để các bạn có thể dễ dàng nắm bắt vấn đề. Giả sử U là giá trị của ký tự cần được mã hoá (giá trị này được quy định theo chuẩn ISO 10646), giá trị này không vượt quá 0x10FFFF. Các bước để mã hoá ký tự trên như sau:

  • Nếu U < 0x10000, mã hoá U như một số nguyên không dấu 16-bit và kết thúc quá trình.
  • Cho U’ = U – 0x10000. Vì U nhỏ hơn hoặc bằng 0x10FFFF nên U’ phải nhỏ hơn hoặc bằng 0xFFFFF. Vì vậy, U’ có thể được biểu diễn trong 20 bit.
  • Khởi tạo 2 số nguyên không dấu 16-bit W1, W2 có giá trị lần lượt là 0xD800 và 0xDC00. Mỗi số nguyên này có 10 bit cuối có thể dùng để lưu trữ giá trị của ký tự sau khi mã hoá, tổng cộng chúng ta có 20 bit, vừa đủ để lưu trữ U’.
  • Gán 10 bit có trọng số cao của U’ cho 10 bit có trọng số thấp của W1, 10 bit có trọng số thấp của U’ cho 10 bit có trọng số thấp của W2. W1 và W2 là 2 byte sau khi mã hoá của ký tự sử dụng UTF-16.

Giải mã

Quá trình giải mã UTF-16 hoàn toàn ngược lại với quá trình mã hoá UTF-16. Giả sử W1, W2 là 2 số nguyên 16-bit tương ứng với 16 bit đầu và 16 bit cuối của chuỗi byte được biểu diễn trên bộ nhớ. Các  bước thực hiện quá trình giải mã như sau:

  • Nếu W1 < 0xD800 hoặc W1 > 0xDFFF, giá trị của U chính là giá trị của W1.
  • Xác định xem W1 có nằm trong khoảng 0xD800 và 0xDBFF không. Nếu không, chuỗi byte này không hợp lệ.
  • Nếu không tồn tại W2 (W1 kết thúc chuỗi byte) hoặc W2 không nằm giữa khoảng 0xDC00 và 0xDFFF, chuỗi byte này không hợp lệ.
  • Xây dựng U’ bằng cách lấy 10 bit có trọng số thấp của W1 và 10 bit có trọng số thấp của W2.
  • Xây dựng U = U’ + 0x10000.

Lời kết

Phát triển game đa ngôn ngữ hiện nay rất quan trọng, giúp game tiếp cận với các khách hàng mục tiêu tốt hơn và giúp nhà phát triển truyền đạt trọn vẹn tư tưởng của game đến mọi người. Do đó việc hiện thực game trên nhiều ngôn ngữ là thật sự cần thiết. Hy vọng qua bài viết này, tôi có thể giúp những bạn mới bước chân vào lĩnh vực phát triển game không còn phải bỡ ngỡ khi phát triển game nhiều ngôn ngữ.

THẢO LUẬN
ĐÓNG