2014年9月16日 星期二

Universal Apps 如何共用 Resources 製作多語系應用程式

選擇 Universal Apps 最迷人的地方就在於整合兩個 ( 未來是三個 ) 平台的資源,這裡記錄如何利用 Shared Project 達到 Windows 及 Windows Phone 專案共享 Localization 資源的方法。

首先建立 Universal Apps,並且在在 Shared 專案依下圖建立資料夾及加入圖檔與 resw 檔案


圖中我加入了一個名為 LocalizedStrings.cs 的類別,之後示範 Binding 字串時會用到,先在這裡附上這個類別的內容

class LocalizedStrings
{
    private static ResourceLoader resourceLoader = null;
    public LocalizedStrings()
    {
    }
    public static String GetString(String strName)
    {
        if (resourceLoader == null)
        {
            resourceLoader = new ResourceLoader();
        }
        String strRes = "";
        if (!String.IsNullOrEmpty(strName))
        {
            strRes = resourceLoader.GetString(strName);
        }
        return strRes;
    }
}

接下來整理一下本地化會用到的幾個重點

1. 需要在 Package.appxmanifest 中加入計劃支援的語系
2. 使用 x:Uid 的方式為元件命名,可使用 x:Uid.attribute 的方式定義內容
3. Package.appxmanifest 裡面使用 ms-resource:resource-id 調用字串
4. 語系碼可以參考這裡:Choosing your languages

以下使用上述的方式示範如何依語系改變應用程式名稱與選擇圖片、字串,特別注意一下字串的部份,分為直接在資源檔中定義元件屬性的方式和動態指定內容的方式。在 MainPage.xaml 中使用 x:Uid 為第一個 TextBlock 命名,另外注意 Image 元件圖檔的路徑,直接乎略語系資料夾的路徑即可。

<Page
    x:Class="UAPractice.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:UAPractice"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <StackPanel Background="#666666" HorizontalAlignment="Center">
        <Image Source="Assets/Background.png" Stretch="None" Margin="0,50"/>
        <TextBlock x:Uid="txt_resource_string"/>
        <TextBlock Text="{Binding BindingText}"/>
    </StackPanel>
</Page>

因為第二個字串是使用 Binding 的方式,所以我在 MainPage.xaml.cs 中加入一個 Property 如下

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        DataContext = this;
    }

    public String BindingText
    {
        get
        {
            return LocalizedStrings.GetString("BindingStringContent");
        }
    }
}

另外應用程式的部份,在 Package.appxmanifest 中利用上方提到的 ms-resource: 的方式取字串來使用,因為這個檔案的內容很長,我只貼出 Applications 的片段。

<Applications>
  <Application Id="App"
      Executable="$targetnametoken$.exe"
      EntryPoint="UAPractice.Windows.App">
      <m2:VisualElements
          DisplayName="ms-resource:AppTitle"
          Square150x150Logo="Assets\Logo.png"
          Square30x30Logo="Assets\SmallLogo.png"
          Description="UAPractice.Windows"
          ForegroundText="light"
          BackgroundColor="#464646">
          <m2:SplashScreen Image="Assets\SplashScreen.png" />
      </m2:VisualElements>
  </Application>
</Applications>

這裡比較可惜的是應用程式並不會隨時跟著作業系統語系做變化,如果想要測試語系效果,需要移除應用程式,改變語系後重新安裝,在英文、繁中之間切換作業系統時開啟應用程式的結果就如下面的比較圖所示。



最後附上 en 及 zh-Hant 資料夾內 Resources.resw 的內容供參考。

en - Resources.resw

<?xml version="1.0" encoding="utf-8"?>
<root>
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="AppTitle" xml:space="preserve">
    <value>Universal Apps Practice</value>
  </data>
  <data name="BindingStringContent" xml:space="preserve">
    <value>Binding String</value>
  </data>
  <data name="PageTitle" xml:space="preserve">
    <value>Localization Practice</value>
  </data>
  <data name="txt_resource_string.FontSize" xml:space="preserve">
    <value>32</value>
  </data>
  <data name="txt_resource_string.Text" xml:space="preserve">
    <value>String Ascii</value>
  </data>
</root>

zh-Hant - Resources.resw

<?xml version="1.0" encoding="utf-8"?>
<root>
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="AppTitle" xml:space="preserve">
    <value>通用程式綀習</value>
  </data>
  <data name="BindingStringContent" xml:space="preserve">
    <value>Binding 字串</value>
  </data>
  <data name="PageTitle" xml:space="preserve">
    <value>語系綀習</value>
  </data>
  <data name="txt_resource_string.FontSize" xml:space="preserve">
    <value>28</value>
  </data>
  <data name="txt_resource_string.Text" xml:space="preserve">
    <value>字串 Ascii</value>
  </data>
</root>



沒有留言:

張貼留言