ภาษาไทยกับ Silverlight

04 Apr 2008

หลังจากที่ Silverlight 1.0 ออกมาแล้ว 11 เดือนก็ยังไม่ได้เคยลองเอามาใช้แบบจริงๆจังๆซักที จะมีลองเล่นๆก็คือตอน BarCamp ครั้งนู้น แต่ว่าช่วงนี้ได้งานมางานหนึ่งซึ่งต้องใช้ Silverlight 1.0 ในการพัฒนาเลยได้ลองใช้ของจริงเลย

ปัญหาอย่างหนึ่งที่พบตั้งแต่เมื่อ 11 เดือนก่อนแล้วไม่คิดว่ามันจะแก้ไขได้ง่ายแบบนี้คือเรื่องการแสดงผลภาษาไทย

จากปกติ ถ้าเราใส่โค้ด XAML สร้าง TextBlock แล้วกำหนดข้อความเป็นภาษาไทยดังด้านล่าง

<Canvas
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="640" Height="480"
    Background="White"
    x:Name="Page">
    <TextBlock Canvas.Left="8" Canvas.Top="8" Text="สวัสดีครับ" TextWrapping="Wrap" FontFamily="Tahoma" x:Name="myTextBlock"/>    
</Canvas>

ถึงแม้ว่าเราจะกำหนดตรงฟ้อนท์ให้เป็น Tahoma และลองดูใน Expression Blend ได้ผลดูดีแล้วก็เถอะ

Thai support in Silverlight

แต่เมื่อนำไปแสดงผลในบราวเซอร์ กลับได้ผลลัพธ์ที่ไม่ค่อยน่าพอใจซักเท่าไหร่

Thai support in Silverlight

ตรงนี้จากความเข้าใจ อาจจะเป็นเพราะว่าตัว Silverlight เองรองรับฟ้อนท์อยู่ไม่กี่แบบ ถ้าเราไม่ได้ตั้งค่าของ Font Family ให้กับ TextBlock ค่าปกติก็จะเป็น “Portable User Interface” ซึ่งก็คือ “Lucida Sans Unicode, Lucida Grande” นั่นเอง

Font support in Silverlight
รูปจาก [Silverlight SDK](http://blogs.msdn.com/silverlight_sdk/archive/2007/05/02/downloading-fonts-using-the-downloader-object.aspx)

ถ้าลองเปิดเข้าไปดูที่นี่ จะเห็นว่าเราสามารถนำ Downloader ซึ่งเป็นตัวช่วยดาวน์โหลดใน Silverlight มาใช้ในการโหลดฟ้อนท์อื่นๆเพิ่มมาใช้กับ Silverlight ของเราได้

ก็เลยลองซะ


if (!window.SilverlightSite2)
    SilverlightSite2 = {};

SilverlightSite2.Page = function() 
{
}

SilverlightSite2.Page.prototype =
{
    handleLoad: function(control, userContext, rootElement) 
    {
        this.control = control;
        var downloader = control.createObject('Downloader');
        // Add Completed event.
        downloader.addEventListener("Completed", Silverlight.createDelegate(this, this.downloadCompleted));

         // Initialize the Downloader request.       
        downloader.open("GET", "font.zip");
         // Execute the Downloader request.
        downloader.send();
        
    },  
    downloadCompleted : function(sender, eventArgs){
         var myTextBlock = sender.findName('myTextBlock');

         // Add the fonts to the typeface collection.
         myTextBlock.setFontSource(sender);

         // Specify the desired font.
         myTextBlock.fontFamily = "Tahoma";
    }
}

ในกรณีนี้จะเก็บฟ้อนท์ Tahoma.ttf ไว้ในไฟล์ชื่อ font.zip เมื่อ Silverlight โหลด font.zip เสร็จก็จะไปตั้งค่า FontSource และ FontFamily ให้กับ myTextBlock ลองรันดูก็ได้ผลลัพธ์ตามต้องการ แสดงผลเป็นภาษาไทยด้วยฟ้อนท์ Tahoma แล้วล่ะ

Thai support in Silverlight

แล้วถ้าเกิดมีจำนวน TextBlock เยอะมาก แล้วต้องมานั่งตั้งแบบนี้ทุกอันเหรอ

คำตอบคือ ถูกต้อง ต้องทำแบบนี้แหละ

แต่!!!

ในเมื่อ Silverlight เก็บข้อมูลของ Element ต่างๆในลักษณะของต้นไม้ เราก็แค่วิ่งไปตามกิ่งต่างๆเพื่อตั้งค่าได้นี่

if (!window.SilverlightSite2)
    SilverlightSite2 = {};

SilverlightSite2.Page = function() 
{
}

SilverlightSite2.Page.prototype =
{
    handleLoad: function(control, userContext, rootElement) 
    {
        this.control = control;
        this.root = rootElement;
        var downloader = control.createObject('Downloader');
        // Add Completed event.
        downloader.addEventListener("Completed", Silverlight.createDelegate(this, this.downloadCompleted));

         // Initialize the Downloader request.
         // Zip file contains: Britanic.ttf, Erasbd.ttf, Showg.ttf
        downloader.open("GET", "font.zip"    );
         // Execute the Downloader request.
        downloader.send();

    },  
    downloadCompleted : function(sender, eventArgs){
        this.setupFont(sender, this.root);
    },
    setupFont : function (sender, element){
        // Check element type to detect child node
        if (element.toString() != "Canvas")
            return;
        var children = element.children;
        for(var i = 0; i < children.count; i++)
        {
            var child = children.getItem(i);
            this.setupFont(sender, child);
            setFont(child, sender);
        }       
    }
}


function setFont(textElement, fontSource)
{
  if (textElement.toString() != "TextBlock")
    return;
  textElement.setFontSource(fontSource);
}

ตรงการตรวจสอบ Type ตรงนี้มีลูกเล่นนิดนึงคือใช้วิธีแปลงเป็นสตริงออกมาก่อนแล้วค่อยดูว่าเป็น Canvas หรือไม่ เหตุผลที่ตรวจสอบว่าเป็น Canvas รึเปล่าเพราะใน Silverlight 1.0 มีคอนโทรลประเภท Container ตัวเดียวคือ Canvas ซึ่งหกมีหลายตัวก็คือดูจากคุณสมบัติ Children ได้เช่นกัน แต่ปัญหาก็คือใน IE ไม่มี เมธอด hasProperty เลยต้องใช้วิธีนี้แทน

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

ลองเอามาใช้ร่วมกับฟ้อนท์อื่นดูบ้างอย่างฟ้อนท์ 2005_iannnnnTKO ดู โดยการใส่ฟ้อนท์นี้เพิ่มลงไปใน font.zip แล้วใช้โค้ด XAML เป็น

font set
    <Canvas
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="640" Height="480"
    Background="White"
    x:Name="Page">
    <TextBlock Canvas.Left="8" Canvas.Top="8" Text="สวัสดีครับ" TextWrapping="Wrap" FontFamily="Tahoma" x:Name="myTextBlock"/>
    <TextBlock x:Name="myTextBlock_Copy" Canvas.Left="8" Canvas.Top="19" FontFamily="Tahoma" Text="สวัสดีครับ" TextWrapping="Wrap"/>
    <TextBlock x:Name="myTextBlock_Copy1" Canvas.Left="134.52" Canvas.Top="33" FontFamily="Tahoma" Text="สวัสดีครับ" TextWrapping="Wrap"/>
    <TextBlock x:Name="myTextBlock_Copy2" Canvas.Left="8" Canvas.Top="33" FontFamily="Tahoma" Text="สวัสดีครับ" TextWrapping="Wrap"/>
    <TextBlock x:Name="myTextBlock_Copy3" Canvas.Left="72" Canvas.Top="8" FontFamily="Tahoma" Text="สวัสดีครับ" TextWrapping="Wrap"/>
    <Canvas Width="151.48" Height="93.594" Canvas.Left="8" Canvas.Top="54.703" Background="#BDD8D8D8">
        <TextBlock x:Name="myTextBlock_Copy4" FontFamily="2005_iannnnnTKO" Text="สวัสดีครับ" TextWrapping="Wrap" FontSize="24"/>
        <TextBlock x:Name="myTextBlock_Copy5" FontFamily="2005_iannnnnTKO" Text="สวัสดีครับ" TextWrapping="Wrap" Canvas.Top="75.891" FontSize="24"/>
        <TextBlock x:Name="myTextBlock_Copy6" FontFamily="2005_iannnnnTKO" Text="สวัสดีครับ" TextWrapping="Wrap" Canvas.Top="4" Canvas.Left="84.96" FontSize="24"/>
        <TextBlock x:Name="myTextBlock_Copy7" FontFamily="2005_iannnnnTKO" Text="สวัสดีครับ" TextWrapping="Wrap" Canvas.Top="67.891" Canvas.Left="84.96" FontSize="24"/>
        <TextBlock x:Name="myTextBlock_Copy8" FontFamily="2005_iannnnnTKO" Text="สวัสดีครับ" TextWrapping="Wrap" Canvas.Top="43.406" FontSize="24"/>
        <TextBlock x:Name="myTextBlock_Copy9" FontFamily="2005_iannnnnTKO" Text="สวัสดีครับ" TextWrapping="Wrap" Canvas.Top="21.703" Canvas.Left="52" FontSize="24"/>
    </Canvas>
</Canvas>
Thai support in Silverlight

เย่ ใช้ภาษาไทยได้แล้ว
ปล. ยังไม่ได้ลองกับ Silverlight 2.0
ปล.2 Silverlight ยังตัดคำไม่ค่อยดี รวมไปถึงการขึ้นบรรทัดใหม่ยังยุ่งยากด้วย
ปล.3 Flash รองรับเรื่องฟ้อนท์ได้ดีกว่าเพราะฝังลงไปในไฟล์ swf เลย

Comments

Post new comment

The content of this field is kept private and will not be shown publicly.