Эта статья является Днем № 29 в серии под названием « 31 Дней Манго» и была написана приглашенным автором Мэттом Эландом . С Мэттом можно связаться в Твиттере по адресу @integerman .
Глобализация против локализации
Люди часто путаются при обсуждении глобализации и локализации. Оба имеют дело с представлением контента в удобной для пользователя форме по всему миру, но различие состоит в том, что глобализация имеет дело с элементами форматирования, такими как время, даты, валюты и числа, так, как пользователь знаком, тогда как локализация включает в себя отображение собственного языка пользователя. язык в пользовательском интерфейсе. В этой статье будет рассказано об использовании обоих методов для создания приложений, которые могут охватить большую аудиторию наиболее удобным для пользователя способом.
В течение этой статьи мы будем создавать простое приложение, которое поддерживает как глобализацию, так и локализацию. Это приложение быстро генерирует сообщение электронной почты, которое позволяет контакту узнать, что вы опаздываете на встречу.
Настройка поддержки локализации
После создания нового проекта C # для Windows Phone нам нужно будет сделать несколько вещей, чтобы настроить приложение на поддержку локализации.
Определение нейтрального языка для сборки
Поскольку мы локализуем наше приложение, нам нужно сообщить проекту, какой язык используется по умолчанию. Для этого мы перейдем в диалоговое окно свойств проекта и нажмите «Информация о сборке…», а затем укажем нейтральный язык для нашей сборки, то есть язык, который будет использоваться, если не определены ресурсы для конкретной локали. это соответствует локали пользователя. Для этого примера мы установим нейтральный язык на английский (США).
Указание поддерживаемой культуры
Далее нам нужно сообщить проекту, какие языки поддерживаются. Visual Studio в настоящее время не предоставляет эту часть информации о проекте, но мы можем легко ее отредактировать. Убедитесь, что вы сохранили все изменения, чтобы любые изменения в файле .csproj были сохранены на диск, прежде чем мы отредактируем файл. Затем перейдите в папку проекта на диске, щелкнув правой кнопкой мыши по проекту и выбрав «Открыть папку в проводнике Windows». Выберите файл .csproj для своего приложения (будьте осторожны, не выбирайте файл .csproj.user) и откройте его с помощью Блокнота или вашего любимого текстового редактора.
Найдите элемент <SupportedCultures> </ SupportedCultures> и добавьте коды культур тех культур, которые вы хотите поддерживать, разделяя каждую культуру точкой с запятой. Этот список не должен включать нейтральный язык сборки. См. Http://msdn.microsoft.com/en-us/library/hh202918(v=VS.92).aspx для получения списка культур, поддерживаемых различными версиями Windows Phone. В этом примере мы будем поддерживать испанский, упрощенный китайский и французский в дополнение к стандартной культуре английского языка (США), поэтому наш узел SupportedCultures выглядит следующим образом:
<SupportedCultures> ES-ES; ZH-CN; FR-FR </ SupportedCultures>
После внесения изменений сохраните файл .csproj и вернитесь в Visual Studio. Нажмите перезагрузить, когда Visual Studio предложит вам изменить проект, чтобы изменения в файле проекта вступили в силу.
Создать файл базового ресурса
Теперь, когда у нас есть культура по умолчанию и список других поддерживаемых культур, мы можем начать определять ресурсы, специфичные для культуры. Мы начнем с добавления файла для ресурсов по умолчанию и перейдем к добавлению ресурсов для определенных культур. В качестве наилучшей практики локализации в эти файлы должна быть включена любая строка, обращенная к пользователю, а не жестко запрограммированная в XAML или файле кода.
Нам нужно добавить в проект файл ресурсов, который определяет языковые строки по умолчанию для приложения. Для этого щелкните правой кнопкой мыши по нашему проекту в обозревателе решений и выберите «Добавить -> Новый элемент». Отсюда мы добавим файл ресурсов. Этот файл можно называть как угодно, но для этого примера мы назовем его Strings.
Добавление файла переносит нас в редактор ресурсов для этого ресурса. Редактор ресурсов содержит таблицу с тремя столбцами: Имя, Значение и Комментарий. Имя — это автоматически генерируемое кодовое имя для ресурса, которое служит уникальным ключом для идентификации ресурса. Значение — это значение, специфичное для данной культуры, и то, что мы будем использовать для хранения пользовательского текста. Комментарий не используется приложением, но помогает отметить, что означает каждый ресурс и где он используется, и может сильно помочь при переводе на другие языки. Вы также увидите модификатор доступа в верхней части редактора ресурсов. Это внутреннее по умолчанию, но нам нужно изменить это на public, чтобы мы могли связываться с этими значениями в XAML позже.
Вот наш пример после добавления соответствующих строк и изменения модификатора доступа на public:
Создайте файлы ресурсов для конкретной культуры
Теперь, когда у нас определены ресурсы по умолчанию, мы можем начать создавать собственные ресурсы для проекта. Начнем с определения испанских ресурсов для этого приложения. Удерживая нажатой клавишу Control, перетащите Strings.resx в обозревателе решений, чтобы создать копию String.resx, а затем переименуйте «Copy of Strings.resx» в «Strings.es-ES.resx» (es-ES — это код культуры испанского языка). Важно, чтобы этот новый файл начинался с того же имени, что и ваш предыдущий файл ресурсов, но в конце имел соответствующий языковой стандарт, иначе этот файл не будет должным образом сопоставлен с предполагаемым языковым стандартом. Переименовав этот файл, откройте файл Strings.es-ES.resx и измените столбец «Значение» для каждого ресурса. Хороший источник для переводов — Bing Translator, хотя вы должны проверить переводы с кем-то, кто понимает язык перед развертыванием. Важно, чтобы столбец Имя совпадал между файлами ресурсов, чтобы ресурсы могли быть соответствующим образом отображены.
Закончив с этим, следуйте той же процедуре для любых дополнительных локалей, которые вы хотите поддерживать, следя за тем, чтобы все файлы ресурсов имели модификатор доступа Public, сохраняли одно и то же имя и содержали соответствующий код культуры. Также важно отметить, что редактор ресурсов может некорректно отображать некоторые внешние наборы символов при копировании и вставке из Bing Translator в редактор ресурсов, но эти символы должны хорошо выглядеть на реальном устройстве и эмуляторе.
Создание нелокализованного пользовательского интерфейса
Теперь, когда у нас есть набор локализованных строк, нам лучше создать пользовательский интерфейс, который может их использовать. В нашем примере приложения будет несколько полей, панель приложения и стандартный заголовок. Поскольку мы хотим включить в этот пример даты для демонстрации глобализации, мы будем ссылаться на набор инструментов Silverlight для Windows Phone и использовать элемент управления TimePicker, содержащийся в этой сборке. В этой статье не будет подробно рассказано о загрузке, установке и ссылках на инструментарий, но этот инструментарий находится в свободном доступе, а помощь доступна в Интернете.
Наш нелокализованный MainPage.xaml выглядит так:
<phone:PhoneApplicationPage x:Class="PhoneApp1.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:Controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit" mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="696" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="PortraitOrLandscape" Orientation="Portrait" shell:SystemTray.IsVisible="True"> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar IsMenuEnabled="False"> <shell:ApplicationBarIconButton IconUri="/icons/appbar.feature.email.rest.png" IsEnabled="True" Text="send" Click="HandleSendClick" /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> <!--LayoutRoot is the root grid where all page content is placed--> <Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <!--TitlePanel contains the name of the application and page title--> <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> <TextBlock x:Name="ApplicationTitle" Text="I'm Running Late" Style="{StaticResource PhoneTextNormalStyle}" /> <TextBlock x:Name="PageTitle" Text="Send Message" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}" TextWrapping="Wrap" /> </StackPanel> <ScrollViewer Margin="12,0,12,0" Grid.Row="1"> <StackPanel x:Name="ContentPanel"> <TextBlock TextWrapping="Wrap" Text="To" Style="{StaticResource PhoneTextSubtleStyle}" /> <TextBox x:Name="txtTo" TextWrapping="Wrap" InputScope="EmailUserName" /> <HyperlinkButton Content="Choose a contact" HorizontalContentAlignment="Left" Foreground="{StaticResource PhoneAccentBrush}" Click="HandleChooseContactClick" Margin="{StaticResource PhoneVerticalMargin}" /> <TextBlock TextWrapping="Wrap" Text="Subject" Style="{StaticResource PhoneTextSubtleStyle}" /> <TextBox x:Name="txtSubject" TextWrapping="Wrap" Text="I'm Running Late" InputScope="Text" /> <CheckBox x:Name="checkIncludeReason" Content="Include a reason" /> <TextBox x:Name="txtReason" TextWrapping="Wrap" Text="Traffic" InputScope="Text" IsEnabled="{Binding IsChecked, ElementName=checkIncludeReason}" /> <CheckBox x:Name="checkIncludeETA" Content="I should arrive by" /> <Controls:TimePicker x:Name="timeArrival" IsEnabled="{Binding IsChecked, ElementName=checkIncludeETA}" Margin="0,-12,0,0" /> <CheckBox x:Name="checkIncludeDiagnosticData" Content="Include extra data" /> </StackPanel> </ScrollViewer> </Grid> </phone:PhoneApplicationPage>
Очевидно, что этот XAML содержит ряд жестко закодированных строк, а это не то, что мы хотим для локализуемого приложения. Нам нужно получить пользовательский интерфейс, чтобы воспользоваться нашими строками ресурсов.
Извлечение строк ресурсов в XAML
К счастью, дизайнер ресурсов, с которым мы работали, уже автоматически создал классы для доступа к этим ресурсам. К сожалению, мы не можем легко связать их с XAML, потому что автоматически сгенерированный класс Strings имеет внутренний конструктор и статические свойства, поэтому нам нужно создать объект-оболочку ресурсов, который предоставляет их таким способом, с которым мы можем связываться.
Добавьте новый файл кода в решение с именем StringProvider.cs и включите следующий код:
namespace PhoneApp1 { public class StringProvider { private readonly Strings _resources = new Strings(); public Strings Resources { get { return _resources; } } } }
Теперь перейдите в файл App.xaml и добавьте в приложение новый ресурс с соответствующим квалификатором xmlns. Этот ресурс будет доступен во всем приложении и обеспечит легкий доступ к локализации строк. Когда это будет сделано, наш App.xaml будет выглядеть так:
<Application x:Class="PhoneApp1.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:local="clr-namespace:PhoneApp1"> <!--Application Resources--> <Application.Resources> <local:StringProvider x:Key="Strings" /> </Application.Resources> <Application.ApplicationLifetimeObjects> <!--Required object that handles lifetime events for the application--> <shell:PhoneApplicationService Launching="Application_Launching" Closing="Application_Closing" Activated="Application_Activated" Deactivated="Application_Deactivated"/> </Application.ApplicationLifetimeObjects> </Application>
Теперь, когда мы определили наш StringProvider как ресурс, мы можем привязаться к нему на главной странице. В этом случае мы привязываем к подчиненному свойству в свойстве Resources, представляющем имя ресурса, как мы определили его ранее в коллекции ресурсов, и используем объект приложения StringProvider в качестве источника привязки. Например, заголовок нашей страницы TextBlock становится:
<TextBlock x:Name="PageTitle" Text="{Binding Resources.PageTitleSendMessage, Source={StaticResource Strings}}" TextWrapping="Wrap" />
Области проектирования как Blend, так и Visual Studio должны распознавать эту привязку и отображать строку нейтрального языка (значение в Strings.resx) в конструкторе, если проект был перестроен с момента добавления ресурса.
При создании локализуемых приложений помните, что во многих языках строки ресурсов будут длиннее, чем в локали по умолчанию. По этой причине важно, чтобы вы установили TextWrapping = «Wrap», где это применимо, и использовали гибкие структуры макетов, такие как ScrollViewers и StackPanels, которые могут при необходимости адаптироваться к многострочному контенту. Из-за потенциально длинных строк ресурсов, при необходимости рекомендуется устанавливать SupportedOrientations = «PortraitOrLandscape» в элементе страницы.
Также важно знать, что не все локали поддерживают разные шрифты. Лучше всего для локализации приложения избегать ручного указания шрифтов или веса шрифтов и вместо этого полагаться на встроенные стили. См. Http://msdn.microsoft.com/en-us/library/hh202920(v=VS.92).aspx для получения дополнительной информации.
Ссылаясь на локализованные строки в коде позади
Этот подход будет работать для большинства строк, но в рекомендациях по проектированию Metro заголовок приложения в верхней части страницы должен быть написан заглавными буквами, а наша строка в файле ресурсов использует начальные заглавные буквы. Мы могли бы определить новый ресурс только для метки заголовка или написать преобразователь значения в верхний регистр для привязки, но вместо этого мы просто установим заголовок в коде, чтобы продемонстрировать доступ к локализованным ресурсам из кода, добавив следующую строку в конструктор MainPage:
ApplicationTitle.Text = Strings.AppTitle.ToUpper(CultureInfo.CurrentCulture);
Локализация панелей приложений
Элементы панели приложения в настоящее время не поддерживают привязку, поскольку они не являются действительно настраиваемым содержимым Silverlight. Вместо этого нам придется вручную устанавливать текст нашего ApplicationBarIconButton в коде, ссылаясь на автоматически сгенерированное свойство для нашего имени ресурса в ресурсе Strings следующим образом:
public MainPage() { InitializeComponent(); // Ensure that the app title uses all caps ApplicationTitle.Text = Strings.AppTitle.ToUpper(CultureInfo.CurrentCulture); // Specify the text explicitly on the app bar using our resource string. var button = (ApplicationBarIconButton)ApplicationBar.Buttons[0]; button.Text = Strings.ButtonSend; // By default, we're going to be 15 minutes later than now timeArrival.Value = DateTime.Now.AddMinutes(15); }
Теперь у нас есть локализованное приложение. Тестирование приложения в эмуляторе с использованием настроек французского языка приводит к следующему:
Поддержка глобализации
Теперь, когда у нас есть локализуемое приложение, давайте перейдем к аспекту глобализации. Поскольку глобализация связана с соблюдением культурных настроек пользователя, важно предоставить правильный IFormatProvider для различных методов форматирования строк, когда это необходимо. К счастью, .NET предоставляет CultureInfo.CurrentCulture, который представляет текущие культурные настройки пользователя и может использоваться для форматирования строк для пользовательского интерфейса. При выполнении стандартных сравнений или при работе с сериализацией или другими операциями, не связанными с пользователем, важно использовать CultureInfo.InvariantCulture, чтобы обеспечить правильную работу приложения во всех настройках культуры.
В отличие от локализации, вам не нужно ничего делать для поддержки определенной культуры, а .NET Framework позаботится о большинстве операций форматирования культуры за вас. По-прежнему рекомендуется предоставлять строки соответствующего формата и при необходимости указывать CultureInfo.CurrentCulture в качестве IFormatProvider.
Например, код, который наше приложение использует для генерации электронной почты, явно использует строки CurrentCulture и format:
private void HandleSendClick(object sender, EventArgs e) { // Build the E-Mail body from the user's selections var body = new StringBuilder(); body.AppendLine(Strings.EmailHeader); // Include reason if applicable var culture = CultureInfo.CurrentCulture; if (checkIncludeReason.IsChecked == true) { body.AppendLine(); body.AppendLine(string.Format(culture, "{0}: {1}", Strings.EmailReason, txtReason.Text)); } // Include eta if applicable if (checkIncludeETA.IsChecked == true) { body.AppendLine(); // Since we've specified our ValueFormatString for the Time Picker, we can just rely on the ValueString here. body.AppendLine(string.Format(culture, "{0}: {1}", Strings.CheckShouldArriveBy, timeArrival.ValueString)); } // Include extra globalization examples if applicable if (checkIncludeDiagnosticData.IsChecked == true) { body.AppendLine(); // this is the standardized culture name such as en-US or zh-CH body.AppendLine(culture.Name); body.AppendLine(string.Format(culture, "pi: {0}", Math.PI)); body.AppendLine(string.Format(culture, "number: {0}", -1)); body.AppendLine(string.Format(culture, "currency: {0:c}", 4200.00)); body.AppendLine(string.Format(culture, "date: {0:D}", DateTime.Today)); body.AppendLine(string.Format(culture, "time: {0:t}", DateTime.Now)); } // Now that we have our message body, do something with it. What we do depends on what we're running on. if (Microsoft.Devices.Environment.DeviceType == DeviceType.Emulator) { // The emulator doesn't currently support sending E-Mails so we'll just output the text to a message box MessageBox.Show(body.ToString()); } else { // Compose the E-Mail and show it to the user to preview before sending var task = new EmailComposeTask {Subject = txtSubject.Text, To = txtTo.Text, Body = body.ToString()}; task.Show(); } }
Поскольку глобализация отделена от локализации, запуск приложения на языке без специфичных для локали строк приведет к правильно глобализированным значениям, таким как эти немецкие настройки на изображении ниже:
Указание форматных строк в XAML
Иногда вам может потребоваться указать строку формата в XAML либо в качестве параметра для преобразователя значений, либо в качестве свойства встроенного элемента управления. В нашем примере мы явно установим строку формата нашего TimePicker в короткий формат времени для текущей культуры («t»). Чтобы сделать это, мы добавляем к нашей строке формата пару фигурных скобок, как показано здесь:
<Controls:TimePicker x:Name="timeArrival" ValueStringFormat="{}{0:t}" />
Также возможно установить это в коде либо
var info = CultureInfo.CurrentCulture.DateTimeFormat; timeArrival.ValueStringFormat = "{0:" + info.ShortTimePattern + "}";
или, более кратко:
timeArrival.ValueStringFormat = "{0:t}";
Тестирование для разных культур
К этому моменту мы создали полнофункциональное приложение, которое поддерживает глобализацию и локализацию. Вам может быть интересно, как тестировать приложения для разных локалей. Фактические устройства Windows Phone могут не позволять вам изменять язык дисплея вашего телефона, но, к счастью, Microsoft предоставила эту возможность в эмуляторе.
Чтобы получить доступ к этим настройкам, перейдите в меню приложений эмулятора на начальном экране и выберите приложение настроек. Оттуда нажмите регион + язык в системном элементе разворота.
Экран региона и языка позволяет настроить язык отображения на телефоне, установив в поле выбора языка отображения язык, который вы хотите проверить, и затем нажав гиперссылку «нажмите здесь, чтобы принять изменения». Это перезагрузит образ эмулятора операционной системы Windows Phone и применит выбранные вами настройки языка и глобализации. Использование страниц настроек на языке, который вы не знаете, может привести к путанице, чтобы изменить региональные настройки, поэтому перед применением изменений рекомендуется изучить макет экрана. После перезагрузки эмулятора запуск вашего приложения в эмуляторе позволит вам убедиться, что приложение учитывает языковые и культурные параметры пользователя.
Вопросы развертывания
При развертывании приложения, поддерживающего разные языки и культуры, обязательно включите распространение на поддерживаемых вами рынках, выбрав всемирное распространение при публикации приложения и установив цены, или выбрав отдельные локали, которые вы явно намереваетесь поддерживать.
Резюме
Теперь вы знаете, как создать приложение от начала до конца, которое предложит наилучший опыт, предоставив правильно глобализированное и локализованное приложение для глобальной аудитории, которая использует Windows Phone.
Чтобы загрузить полный проект Windows Phone, в котором используется весь код и примеры, приведенные выше, нажмите кнопку «Загрузить код» ниже.
Завтра мы вернемся к данным и расскажем, как использовать локальную базу данных в вашем приложении. Увидимся позже!
Источник: http://www.jeffblankenburg.com/2011/11/29/31-days-of-mango-day-29-globalization/