web analytics

Flutter : การทำแอปให้รองรับหลายภาษา

cover2

สวัสดีครับ ตอนนี้ผมลองเล่น Flutter แล้วก็เขียนแอปของผมจนถึงฟีเจอร์เกี่ยวกับภาษาแล้ว เลยมีโอกาสได้ลองเล่นเรื่องการทำแอปให้รองรับหลายภาษาใน Flutter ครับ ซึ่งจริงๆมีคนทำ library ให้ใช้งานได้ง่ายๆ แต่ว่าผมอยากจะเข้าใจหลักการทำงานแบบที่ Flutter เตรียมไว้ให้ก่อน ดังนั้นในตอนแรกเราจะทำแบบไม่ใช้ library ข้างนอกช่วยครับ

 

บล็อกก่อนหน้านี้ครับ เกี่ยวกับเรื่อง Multi-screen

Flutter : ทำให้แอปรองรับ Layout ในทุกขนาดหน้าจอ

 

เริ่มต้น

ตัวของ Flutter มีเรื่อง locale มาให้ใช้ง่ายๆ มันติดมากับ MaterialApp สิ่งที่เราต้องทำคือ กำหนด Locale ที่รองรับ
กำหนด Locale เริ่มต้น , แล้วก็คลาสสำหรับเก็บคำศัพท์ของ Locale ต่างๆ

 

วิธีเช็คว่า Locale ของผู้ใช้ตอนนี้ คืออะไรใช้คำสั่งนี้

 

ลองแสดงผลค่า Locale

 

จะได้ locale.languageCode มีค่าเท่ากับ en ก็คือ ภาษาอังกฤษ

1

 

 

Custom Localization

เรามาทำคลาส Localization ของเราบ้าง
ก่อนอื่นสร้างคลาสสำหรับเก็บคำศัพท์ ให้ extends MessageLookupByLibrary ข้างในมีตัวแปรนึงชื่อว่า messages เป็น Map เก็บค่าคำศัพท์ ต้องใช้ชื่อนี้เท่านั้นนะ เพราะมันต้องไป override กับ MessageLookupByLibrary

 

ส่วนของภาษาไทยก็ ทำอีก 1 คลาส

 

จากนั้น สร้างอีกคลาสนึง เป็นคลาสตัวกลางที่คอยเช็ค locale ว่าควรจะใช้คำศัพท์จากภาษาไหน

 

ซึ่งคลาส MyLocalizations นี้ก็เขียนหลักการทำงานของมันนิดหน่อย หลักๆคือเช็คว่ามีคลาสสำหรับภาษาที่เราเตรียมไว้หรือไม่ ถ้ามีก้เช็ค locale แล้ว ไปสร้าง class MessageLookup ของภาษานั้นๆ

 

จุดสังเกต คือ วิธีการเรียกใช้คำศัพท์ Intl.message
โดยพารามิเตอร์แรกคือ ค่า default ส่วน name คือ key ที่อยู่ในคลาสเก็บคำศัพท์ (messages)

 

 

ต่อมาการนำ Localization ของเราไปใช้นั้น ต้องใช้ผ่านคลาส Delegate เพราะว่า Localization ก็มี Life cycle ของตัวเอง คลาส LocalizationsDelegate จะเป็นตัวจัดการ
ก็ให้เราสร้างคลาส MyLocalizationsDelegate extends LocalizationsDelegate<MyLocalizations>

 

จากนั้น เพิ่ม MyLocalizationsDelegate ใน MaterialApp

 

สังเกตว่า .delegate ก็เป็นแค่ get ตัวนึง จริงๆแล้วเราเขียนแบบสร้าง instance ปกติก็ได้

แต่เพราะ มีตัวอย่างจาก GlobalMaterialLocalizations เขาใช้ .delegate ผมก็เลยใช้ตาม ซึ่งก็ดูเป็นแบบแผนดี เท่ดีด้วย

 

พอเรานิยาม คำศัพท์ครบหมดแล้ว และเขียนใน Localization ของเราแล้ว
การเรียกใช้ คือ

 

เช่น

3 4

 

ปุ่มเปลี่ยนภาษา

ลองมาทำปุ่มเปลี่ยนภาษากันบ้างครับ

สร้างปุ่ม 2 ปุ่ม สำหรับภาษาไทย และภาษาอังกฤษ

5 6

 

เพิ่มตัวแปรฟังชันก์ callback สำหรับการเปลี่ยนภาษา โดยมันจะมาพร้อมกับ Locale อันใหม่

 

แล้วที่ปุ่มกดเปลี่ยนภาษาก็เรียก callback function นี้

 

ทีนี้ พอเรากดเปลี่ยนภาษาจะได้ Locale ใหม่ เราก็ต้องนำ Locale ใหม่ไปกำหนดให้กับ MaterialApp
ดังนั้น คลาส MyApp ที่ build MaterialApp ก็ต้องเป็น StatefulWidget ไม่ใช่ StatelessWidget

จากนั้นพอ เราได้ callback จากหน้าเปลี่ยนภาษามาแล้วก็แค่ setState กำหนดค่า locale ใหม่

 

กดเปลี่ยนภาษาได้แล้ว

a1

 

 

การใส่ Parameter

ในหลายๆครั้ง คำศัพท์คำนึง เราก็อยากจะเพิ่มค่าตัวแปร แทรกไประหว่างประโยค
วิธีการไม่อยาก คือ ที่ MyLocalizations ที่ Intl.message() เราก็เพิ่ม args เข้าไป เป็น arguments

 

แล้วที่ MessageLookup ก็ใส่ key ตามปกติ แต่ค่าของมันจะเป็น Function ที่มี parameter

 

หรือจะเขียนสั้นๆแบบนี้ก็ได้

 

จากนั้นตอนเรียกใช้จริง ก็แค่เพิ่ม parameter เข้าไป

 

จะได้แบบนี้

7

 

การใช้คำพหูพจน์ (Phural)

ในภาษาอังกฤษมีการใช้คำพหูพจน์เยอะมาก เช่น เติม s  หรือไม่เติม s
วิธีการคือใช้คำสั่ง Intl.phural(…)

 

และในภาษาไทย ถ้าไม่มีรูปพหูจน์แปลกๆก็ใช้คำเดิมทุกกณี

 

ลองเพิ่ม Text แสดงค่าทั้งสามแบบ ค่า 0 , 1 จะไม่มี s
ส่วน 2 ขึ้นไปก็เติม s

8

 

ลองรัน

a2

 

 

 

Flutter Localizations Library

Flutter เองมี library เก็บคำศัพท์พื้นฐานมาให้อยู่บ้าง รองรับ 20 ภาษา+ โดยใช้หลักการตามที่กล่าวไปข้างต้น
library ชื่อว่า flutter_localizations ซึ่งก็ติดมากับ flutter sdk อยู่แล้ว

เพิ่ม dependency ของ flutter_localizations ใน pubspec.yaml

 

จากนั้นที่ main.dart ให้ import เข้ามา

 

โดย library ตัวนี้จะมี คลาส 2 ตัวที่มากับมันคือ GlobalMaterialLocalizations , GlobalWidgetsLocalizations
GlobalMaterialLocalizations เก็บคำศัพท์ที่ใช้กับ Widget ของ Material Widget ซึ่งรองรับ 20 ภาษา+
GlobalWidgetsLocalizations จัดการเกี่ยวกับหลักภาษาเบื้องต้น เช่น ภาษากลุ่มอาหรับ จะเขียนแบบชิดขวา ดังนั้นถ้า locale ของผู้ใช้เป็นภาษาที่ชิดขวา คลาสนี้จะจัดการให้อัตโนมัติ

ก็ให้เราเพิ่ม 2 คลาสนี้ใน localizationsDelegates ของ MaterialApp
และที่ supportedLocales ก็ใส่ลิสของภาษาที่เรารองรับ

 

ลองเรียกใช้คำศัพท์จากคลาส MaterialLocalizations ซึ่งก็มีแต่คำพื้นฐาน

9

 

คำศัพท์ในภาษาไทย
https://github.com/flutter/flutter/blob/master/packages/flutter_localizations/lib/src/l10n/material_th.arb

 

ลองแสดงผล

2 3

 

Easy Localization

Library อีกตัวที่น่าสนใจ เพราะว่าช่วยให้เราเก็บค่าของคำศัพท์เป็น json แล้วใส่ใน Asset แทน ส่วนวิธีใช้ง่านก็ง่าย ไม่ต่างกับวิธีด้านบน

https://pub.dartlang.org/packages/easy_localization

 

ก่อนจะจบ

ถ้าผู้อ่านเคยเขียน Android Native มาก่อน น่าจะรู้จักกับ Configuration Qualifier ซึ่งจะช่วยจัดการเก็บ resource ต่างๆ เช่น คำศัพท์ ในรูปแบบ XML ซึ่งสามารถนำไปใช้ร่วมกับ Configuration อื่นๆได้ เช่น ขนาดหน้าจอ ,  Oreitation , API version ทำให้สามารถสร้าง resource ที่หลากหลายได้มากๆ ตามเงื่อนที่ต้องการ คำถามที่เกิดขึ้นในตอนนี้ คือ Flutter มีคาวมสามารถแบบนี่ไหม ถ้าดูจากตอนนี้ดูเหมือนจะเป็นเรื่องยาก

 

สรุป

ในบล็อกนี้ได้อธิบายเกี่ยวกับการทำแอปให้รองรับหลายภาษา หลักๆ คือการ Custom Localization แล้วเอามาทำเป็น Delegate ก่อนที่จะใส่ใน MaterialApp ส่วนการเก็บคำศัพท์นั้นทำได้หลายวิธี จะใช้ MessageLookUp ก็ได้ หรือจะใช้วิธีเก็บเป็น json asset ก็ได้ ซึ่งปัจจุบันก็มี library มาช่วยให้จัดการง่ายๆแล้ว

โค้ดตัวอย่างอยู่ที่ Github ของผมแล้วครับ
https://github.com/benznest/flutter_multi_language_app