Для начала создаем проект шаблона Windows Phone
В этом решении я скопировал необходимые элементы управления из проекта Windows 8.1 в проект Windows Phone. Это решение не является лучшим, но оно самое быстрое. В следующих статьях я покажу как делать кроссплатформенные решения.
Сейчас же вернемся к портированию приложения. В игре на телефоне решено было сделать постраничную навигацию. Создано 4 страницы:
Игра начинается со страницы GamePage. Если нет сохраненной игры — необходимо отправить пользователя на экран создания новой игры:
protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); GameState game = SettingsProvider.LoadSavedGame(); if (game == null) { NavigationService.Navigate(new Uri("/Pages/NewGame.xaml", UriKind.Relative)); } else { //... } }
Работа с файлами и сессиям в Windows 8.1
В шаблоне Windows 8.1 автоматически будет создан класс SuspensionManager
, который реализует механизм сохранения сессий. Тогда в классе страницы необходимо определить метод NavigationHelperLoadState
и NavigationHelperSaveState
. Код NavigationHelperLoadState
показан ниже, сохранения состояния происходит похожим образом.
private async void NavigationHelperLoadState(object sender, LoadStateEventArgs e) { try { if (SuspensionManager.SessionState.ContainsKey("game-data")) { string previousGame = SuspensionManager.SessionState["game-data"] as string; if (!string.IsNullOrEmpty(previousGame)) { GameStateModel game = GameStateModel.FromJson(previousGame); if (game != null) { LoadGameToBoard(game.ToGameState()); } } } } catch (FileNotFoundException fileNotFound) { } catch (Exception) { } }
Работа с файлами и сессиям в Windows Phone 8
На телефоне работа с файлами немного отличается. Есть такое понятия, как IsolatedStorageSettings. Понятие это пришло из Silverlight версии 2. Как понятно из названия этот тип предназначен для хранения файлов и данных изолированно на локальной файловой системе. Это значит, что другое приложение, помимо вашего не получит доступ к этим данным.
public static GameState LoadSavedGame() { try { IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings; if (settings.Contains(SavedGame)) { string previousGame = settings[SavedGame] as string; if (!string.IsNullOrEmpty(previousGame)) { GameStateModel game = GameStateModel.FromJson(previousGame); if (game != null) { return game.ToGameState(); } } } } catch (Exception exception) { } return null; }
Найденные особенности
Windows Phone 8 не позволяет сохранять шрифты в ресурсах xaml. Такой код на платформе WP8 не валиден:
<!-- Fonts --> <FontFamily x:Key="ThemeFontFamily">Segoe UI Light</FontFamily> <FontWeight x:Key="ThemeFontWeight">SemiLight</FontWeight>
Поэтому пришлось разделить файлы ресурсов и очистить лишнее из WP8.
Работа с разметкой
Очень порадовала работа с разметкой. Во-первых нет необходимости делать верстку приложения для 3-х видов как в Win 8.1 (Full, Filled, Snapped). Важно правильно сделать верстку для экрана в целом. В судоку поддерживается только вертикальное положение экрана (горизонтальное поддерживаться на 99% не будет).
После адаптации верстки, стилей и размеров объектов необходимо протестировать на различных устройствах и экранах.
Локализация названия приложения
В отличии от Windows 8.1, описание приложений производится на сайте https://dev.windowsphone.com при настройки публикации. А название хранится в приложении. Но не все так просто 🙂
Есть такое понятие как Display Name и Tile Title. Первое будет использоваться в маркете и списке приложений на телефоне. Второе используется как надпись на тайле, если такая опция выбрана.
Как описано в MSDN How to localize an app title for Windows Phone (ссылки в конце) — нам нужно создать C++ DLL, в которой будет файл ресурсов, содержащий 2 поля: название и название для тайла. Для каждого языка нужно создать свою dll. Да, это грустно. Но на помощь приходит проект WP8 Localize. Скачиваем инструмент, заполняем поля и автоматически создаем dll для всех необходимых языков. Пару часов этим мы сэкономили точно.
После создания всех dll, их необходимо добавить в проект. Мне удобнее, чтобы они все были в отдельной папке. Я назвал ее Langs и поместил их все туда. Не забываем изменить BuildAction=Content.
В файле WPAppManifest.xml изменяем название и тайл на @Langs/AppResLib.dll,-100 и @Langs/AppResLib.dll,-200 соответственно.
На этом этап локализации названия приложения и тайла закончен. Приступаем к изменению языка для контента приложения.
Локализация Xaml
В Windows Phone 8 инструменты для локализации стали гораздо лучше чем в 7-й версии. Создаем или находим класс LocalizedStrings.
/// <summary> /// Provides access to string resources. /// </summary> public class LocalizedStrings { private static AppResources _localizedResources = new AppResources(); public AppResources LocalizedResources { get { return _localizedResources; } } }
Создаем папку Resources в проекте. Для каждого поддерживаемого языка создаем файл ресурсов AppResources.LOCALE.resx (например AppResources.resx и AppResources.ru.resx). Второй шаг — создание ресурсов в файле App.xaml:
<Application.Resources> <winPhone8:LocalizedStrings xmlns:local="clr-namespace:Oxozle.Sudoku.WinPhone8" x:Key="LocalizedStrings"/> </Application.Resources>
Тем самым даем возможность биндинга в xaml.
Сам файл выглядит следующим образом:
Важное отличие, что здесь это конкретно файл текстовых ресурсов, а не объектов. Т.к. происходит связывание (биндинг) и генерация кода ресурсов — разделитель точка использоваться не может. Далее необходимо настроить связку для текстовых элементов к ресурсам.
<TextBlock Text="{Binding LocalizedResources.ApplicationTitle, Source={StaticResource LocalizedStrings}}" Style="{StaticResource PhoneTextNormalStyle}"/>
Для страницы Новая игра:
Локализация поддерживается и в режиме верстки (в Expression Blend все правильно подхватывается)
Локализация из кода
ApplicationBar не поддерживает локализацию на биндингах. Для этого при создании проекта создается закомментированный код метода BuildLocalizedApplicationBar
. Но нет ничего сложного написать несколько строк для построения меню приложения.
private void BuildLocalizedApplicationBar() { // Set the page's ApplicationBar to a new instance of ApplicationBar. ApplicationBar = new ApplicationBar(); //// Create a new button and set the text value to the localized string from AppResources. //ApplicationBarIconButton appBarButton = new ApplicationBarIconButton(new Uri("/Assets/AppBar/edit.png", UriKind.Relative)); //appBarButton.Text = AppResources.GamePage_Pencil; //ApplicationBar.Buttons.Add(appBarButton); // Create a new menu item with the localized string from AppResources. ApplicationBarMenuItem appBarNewGame = new ApplicationBarMenuItem(AppResources.NewGameTitle); appBarNewGame.Click += delegate { NavigationService.Navigate(new Uri("/Pages/NewGame.xaml", UriKind.Relative)); }; ApplicationBar.MenuItems.Add(appBarNewGame); ApplicationBarMenuItem appBarMenuItem = new ApplicationBarMenuItem(AppResources.GamePage_ButtonAbout); appBarMenuItem.Click += delegate { NavigationService.Navigate(new Uri("/Pages/AboutPage.xaml", UriKind.Relative)); }; ApplicationBar.MenuItems.Add(appBarMenuItem); ApplicationBarMenuItem appBarRate = new ApplicationBarMenuItem(AppResources.WinGame_Rate); appBarRate.Click += delegate { MarketplaceReviewTask marketplaceReviewTask = new MarketplaceReviewTask(); marketplaceReviewTask.Show(); }; ApplicationBar.MenuItems.Add(appBarRate); }
Включение локализации
В отличии от Windows 8.1 локализацию нужно включить вручную. Для этого в app.xaml.cs в метод App добавляем вызов метода InitializeLanguage
.
// Language display initialization InitializeLanguage();</code></pre> <p>Сам метод (может быть уже создан студией).</p> <pre><code class="cs"> private void InitializeLanguage() { try { // Set the font to match the display language defined by the // ResourceLanguage resource string for each supported language. // // Fall back to the font of the neutral language if the Display // language of the phone is not supported. // // If a compiler error is hit then ResourceLanguage is missing from // the resource file. RootFrame.Language = XmlLanguage.GetLanguage(AppResources.ResourceLanguage); // Set the FlowDirection of all elements under the root frame based // on the ResourceFlowDirection resource string for each // supported language. // // If a compiler error is hit then ResourceFlowDirection is missing from // the resource file. FlowDirection flow = (FlowDirection)Enum.Parse(typeof(FlowDirection), AppResources.ResourceFlowDirection); RootFrame.FlowDirection = flow; } catch { // If an exception is caught here it is most likely due to either // ResourceLangauge not being correctly set to a supported language // code or ResourceFlowDirection is set to a value other than LeftToRight // or RightToLeft. if (Debugger.IsAttached) { Debugger.Break(); } throw; } }
В AssemblyInfo указываем культуру по умолчанию:
[assembly: NeutralResourcesLanguageAttribute("en-US")]
В файле WPAppManifest.xml на вкладке Packaging указываем настройки приложения: список поддерживаемых языков, язык по умолчанию.
Выводы
Локализация приложения Windows Phone 8 в некоторых местах кардинально отличается от той же локализации в Windows 8.1. Однако ничего сложного в этом нет. Важно иметь полную инструкцию перед созданием локализации или добавления поддержки нового языка. Надеюсь эта статья поможет при создании мультиязычного приложения. Посмотреть на результат можно здесь:
Первый блин не бывает не комом 🙂 Есть некоторые недочеты в логике игры, новая версия на модерации, если есть возможность можно установить 1.1 версию из xap файла: oxozle.sudoku.1.1.xap.
Источники
ссылка на оригинал статьи http://habrahabr.ru/post/206852/
Добавить комментарий