Статьи

Мгновенное обновление языка в приложении Windows Phone 7 с использованием MVVM

Поскольку в экосистему Windows Phone добавляется все больше и больше торговых площадок, глобализация вашего приложения становится все более важной. Я рад, что в наши дни многие приложения поддерживают несколько языков. Я обычно использую решение, описанное в моей статье Выбор языка на основе MVVMLight для Windows Phone 7 — оно автоматически выбирает язык с телефона и по умолчанию выбирает английский / американский, если приложение по умолчанию не поддерживает язык. Но я также хотел бы дать пользователю возможность переопределить автоматически выбранный язык. Я, например, запускаю телефонную ОС на английском / американском языках, но я бы хотел, чтобы определенные голландские приложения работали на голландском, спасибо. Если вы следуете примеру глобализации, как описано в MSDNиспользуя мой код, который, к сожалению, требует перезапуска приложения после применения изменения языка. Ну не надо больше!

Пример, предоставленный MSDN, предоставляет помощника локализованной строки, который выглядит примерно так:

namespace InstantLanguage.Resources
{
  public class LocalizedStrings
  {
    public LocalizedStrings()
    {
    }
  
    private static AppResources localizedResources = new AppResources();

    public AppResources LocalizedResources 
    { 
      get { return localizedResources; } 
    }
  }
}

Я использовал его с момента своего первого локализованного приложения и обычно помещал его в тот же каталог, что и мои файлы ресурсов. Вы объявляете это в своем App.xaml следующим образом:

<Application.Resources>
    <!-- More resources -->
    <Resources:LocalizedStrings x:Key="LocalizedStrings"/>
</Application.Resources>

Конечно, сначала нужно объявить пространство имен для LocalizedResources, поэтому в верхней части вы добавите что-то вроде

xmlns:Resources="clr-namespace:InstantLanguage.Resources"

И теперь вы можете использовать его для отображения локализованных строк, привязавшись к нему следующим образом:

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

Но, к сожалению, как я уже сказал, если вы меняете язык, например, вызывая этот код, ничего не происходит.

Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-DE");
Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture;

Причина этого довольно проста: приложение не может информировать GUI , так как LocalizedStrings не поддерживает INotifyPropertyChanged . Но это легко исправить, взяв MVVMLight и реализуя LocalizedStrings как дочерний класс ViewModelBase:

using System.Windows;

namespace InstantLanguage.Resources
{
  using GalaSoft.MvvmLight;

  public class LocalizedStrings : ViewModelBase
  {
    private static AppResources localizedresources = new AppResources();

    public AppResources LocalizedResources
    {
      get { return localizedresources; }
    }

    public void UpdateLanguage()
    {
      localizedresources = new AppResources();
      RaisePropertyChanged(() => LocalizedResources);
    }

    public static LocalizedStrings LocalizedStringsResource
    {
      get
      {
        return Application.Current.Resources["LocalizedStrings"]
            as LocalizedStrings;
      }
    }
  }
}

и затем есть другой вопрос: у приложения должен быть способ запустить событие RaisePropertyChanged для класса, используемого в качестве StaticResource . Вот для чего нужны UpdateLanguage и статический LocalizedStringsResource. Обратите внимание, что для этого вам нужно определить ресурс с ключом LocalizedStrings:

<Resources:LocalizedStrings x:Key="LocalizedStrings"/>

Ключи, которые должны совпадать, отмечены красным в обеих частях кода. В любом случае, после того, как вы изменили язык, позвоните:

LocalizedStrings.LocalizedStringsResource.UpdateLanguage();

И бум — все ваши тексты, поступающие из файла ресурсов, будут обновляться мгновенно.

InstantLanuage

Здесь вы можете найти пример решения, демонстрирующего этот принцип, используя новейшую версию моей библиотеки # wp7nl для codeplex и технику, о которой я упоминал ранее . Существует простая подклассификация модели представления LanguageSettingsViewModel, и вы можете увидеть вызов UpdateLanguage непосредственно после изменения языкового параметра:

using System.ComponentModel;
using InstantLanguage.Resources;
using Wp7nl.Globalization;

namespace InstantLanguage.ViewModel
{
  /// <summary>
  /// Main view model. By subclassing LanguageSettingsViewModel we get properties 
  /// "SupportedLanguages" and "CurrentLanguage" for free. 
  /// </summary>
  public class MainViewModel : LanguageSettingsViewModel
  {

    public MainViewModel()
    {
      // Note: en-US is added by default
      AddLanguages(new Language 
	    { Description = "Deutsch", Locale = "de-DE" });
      AddLanguages(new Language 
	   { Description = "Nederlands", Locale = "nl-NL" });
      PropertyChanged += MainViewModelPropertyChanged;
    }

    void MainViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
      if (e.PropertyName == "CurrentLanguage")
      {
        SetLanguageFromCurrentLocale();
        LocalizedStrings.LocalizedStringsResource.UpdateLanguage();
      }
    }
  }
}

В конце концов, это всегда довольно просто.

Обратите внимание, что для того, чтобы эта глобализация и код работали правильно, вам необходимо принять во внимание следующее:

  • Вам нужно будет изменить свойство «Custom Tool» для каждого файла ресурсов на «PublicResXFileCodeGenerator» (по умолчанию ResXFileCodeGenerator)
  • Вам потребуется файл .resx для каждого языка, который вы поддерживаете. Для языка по умолчанию я называю мой обычно AppResources.resx, для немецкого я тогда должен определить AppResources.de-DE.resx и т. Д.
  • Вам также нужно будет добавить поддерживаемые дополнительные языки в тег SupportedCultures в вашем основном проекте. Это нужно сделать вручную , открыв файл проекта, например, в блокноте. Почему это не может быть сделано из Visual Studio — не спрашивайте меня, я просто посланник здесь ;-). Например, для поддержки голландского и немецкого языков вы меняете содержимое тега на:
<SupportedCultures>nl-NL;de-DE</SupportedCultures>

Примечание: я получил идею от джентльмена, которого я встретил на выпуске Microsoft Techdays 2012 года в Гааге, когда работал на стенде «Спросите эксперта». Он показал мне, что это можно сделать, но лишь кратко показал мне часть кода и, конечно, не все. Как только я понял, что это можно сделать, я более или менее собрал это воедино в моменты, когда меня не засыпали вопросы от зашедших разработчиков. К сожалению, я не помню имя джентльмена, иначе я бы добавил несколько кредитов.

Повеселись! Я надеюсь, что это поможет вам штурмовать новые торговые площадки! 😉