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

в 11:25, , рубрики: .net, metro, windows, Windows 8, локализация, метки: , ,

В статье вкратце расскажу о том, как применить локализацию к вашему приложению и о некоторых советах и трюках. Начну с того, что больше нет привычного нам RESX файла с самогенерируемым code behind и возможностью хранить не только строки – вместо этого имеем RESW (RESJSON) файлы. Не буду лить воду и переводить MSDN – просто покажу всё на картинках и листингах.

Локализация текста в XAML

Создадим простой проект, в котором надо просто выводить “Hello world” со следующей структурой:

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

В MainPage.xaml поместим наш TextBlock, который и будет выводить приветствие, и который будем локализовывать:

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

В Resources.resw для папок en и ru добавим следующее содержимое соответственно:

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

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

После всей этой магии при запуске в en-локали выведет “Hello world”, а в русской – “Приветствую тебя, мир!» но с меньшим размером шрифта. Думаю, уже понятно, что связь идет через x:Uid у элементов, а в словаре записываются ключи в формате [Uid].[Property]. Стоит заметить, что одинаковый Uid не обязан быть уникальным для каждого контрола.

Локализация изображений

Иногда возникает необходимость локализовать изображения. Картинку с русским текстом поместим в папку ru, с английским – в en.
Локализация для Windows 8 приложений

Магия состоит в том, что в Uri к изображению вам не надо указывать локаль – подставится автоматически.

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

Обращение из кода

Microsoft предлагает следующий код:

ResourceLoader loader = new ResourceLoader();
String title = loader.GetString(“AppTitle/Text”); /*обратите внимание, что вместо точки нужно писать слэш*/

Что? Но я же раньше делал так:

String title = Resources.AppTitle;

Эх, но раз Microsoft не порадовал нас кодогенерацией обращений к ресурсам, придется написать свою. Для этого хочу поделиться скриптом на t4 — просто добавьте в проект файл с названием StringsGenerator.tt (убедитесь, что в свойствах проекта Custom Tool = TextTemplatingFileGenerator) и следующим содержанием:

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core.dll" #>
<#@ assembly name="System.Xml.dll" #>
<#@ assembly name="System.Xml.Linq.dll" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Xml.Linq" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.IO" #>
<#@ output extension=".cs" #>
using Windows.ApplicationModel.Resources;

namespace LocalizationSample 
{
	public static class Strings 
	{
		private static readonly ResourceLoader Loader = new ResourceLoader();

	<#  
		string stringsDir = Path.GetDirectoryName(this.Host.TemplateFile);
		string reswFile = Path.Combine(stringsDir, @"ResourcesenResources.resw");
		var doc = XDocument.Load(reswFile);
		var data = doc.Element("root").Elements("data").Select(i => new Tuple<string, string>(i.Attribute("name").Value, i.Element("value").Value)).ToArray();
		foreach (var tuple in data.OrderBy(i=> i.Item1))
		{
			#>
	public static string <#= tuple.Item1.Replace(".","") #> { get { return Loader.GetString("<#=tuple.Item1.Replace(".","/")#>"); } } //<#=tuple.Item2#>
	<# } #>
}
}

На выходе получим класс Strings и возможность безопасно обращаться к ресурсам как было при Сталине resx-файлах.

Заключение

В целом идея локализации через Uid, при которой можно менять свойства контролов и не надо городить огромных байндингов типа Text=”{Binding Resources.Text, Source={StaticResource ResourceWrapper}}” и подстановка в Uri локали выглядит весьма интересно. Для себя нашел несколько неприятных моментов:

  • В Design-time значения из словаря не подхватываются – хочется верить, что просто я где-то ошибся или это поправят.
  • Если вам нужно указать одно и тоже значения из словаря для TextBlock и скажем для кнопки – вам придется либо создавать две почти одинаковые записи в словаре AppTitle.Text и AppTitle.Content либо явно вставлять в Content кнопки TextBlock. Было бы удобно, если можно было бы указать несколько свойств в одном ключе.

Ну и напоследок пару советов:

  • resxtranslatorbing.codeplex.com — тулза для автоматического перевода ресурсных файлов при помощи Bing translation. В мэйнлайне не поддерживает resw (только resx), но добрые люди уже запилили .
  • Теперь нет необходимости ручками писать поддерживаемые культуры в csproj в тэг SupportedCultures — всё делается автоматически
  • Очень удобно словари хранить в виде Google Docs – там же можно переводить через Google translate и шарить между людьми, ответственными за переводы.

Автор: Nagg

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js