Pull to refresh

Портирование и локализация приложения на Windows Phone 8

Reading time 7 min
Views 14K
В предыдущей статье я рассказал как разработать судоку для windows 8.1, в этой расскажу как портировать приложение на Windows Phone 8 и локализовать его на несколько языков.

image

Для начала создаем проект шаблона Windows Phone

Windows Phone Application Template

В этом решении я скопировал необходимые элементы управления из проекта 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 Phone 8

Локализация названия приложения


В отличии от 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.

Локализация названия приложения Windows Phone 8

В файле 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.

WP localization

Сам файл выглядит следующим образом:

файл локализации

Важное отличие, что здесь это конкретно файл текстовых ресурсов, а не объектов. Т.к. происходит связывание (биндинг) и генерация кода ресурсов — разделитель точка использоваться не может. Далее необходимо настроить связку для текстовых элементов к ресурсам.

<TextBlock Text="{Binding LocalizedResources.ApplicationTitle, Source={StaticResource LocalizedStrings}}" Style="{StaticResource PhoneTextNormalStyle}"/>


Для страницы Новая игра:

Создание локализованной разметки

Локализация поддерживается и в режиме верстки (в Expression Blend все правильно подхватывается)

Локализация из кода


ApplicationBar не поддерживает локализацию на биндингах. Для этого при создании проекта создается закомментированный код метода BuildLocalizedApplicationBar. Но нет ничего сложного написать несколько строк для построения меню приложения.

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.

InitializeLanguage
// Language display initialization
InitializeLanguage();
//Сам метод (может быть уже создан студией).
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. Однако ничего сложного в этом нет. Важно иметь полную инструкцию перед созданием локализации или добавления поддержки нового языка. Надеюсь эта статья поможет при создании мультиязычного приложения. Посмотреть на результат можно здесь:

Судоку+

Источники


Tags:
Hubs:
+26
Comments 15
Comments Comments 15

Articles