Как стать автором
Обновить

Комментарии 35

Как по мне так не очень большая разница с более простым методом без всяких наследований и работает одинаково на WP и WS.
<TextBlock Text="{Binding Path=AppResources.LoginTitle, Source={StaticResource LocalizedStrings}}"/>

А на мой взгляд разница огромна, особенно при наличии не тривиальной «Hello World» разметки.
Если у вас в приложении такая запись встречается несколько раз, то, вероятно, разницы вы не ощутите, но когда нужно локализовывать сотни элементов, то банальный выигрыш во времени набора текста прочувсвуете хорошо.

Кроме того, применение расширений привязки не ограничивается одной лишь локализацией, а позволяет делать гораздо более интересные вещи… Чтобы много не говорить, рекомендую просто ознакомиться с примером.
На самом деле статья уже была причем не так давно.
Главным недостатком этой реализации является, отсутствие поддержки со стороны IntelliSense и невозможность использовать рефакторинг.
Да, сравнительно недавно была обзорная и довольно насыщенная статья об Aero Framework, где этот вопрос поднимался. Но из-за насыщенности не всем хватило терпения её изучить, поэтому было решено разобрать некоторые аспекты детальнее и в более доступном виде.
=) Эта совсем старая, в ней ещё только зарождались некоторые идеи. Окончательную форму они приобрели уже в Aero Framework…
Любопытно.
К сожалению, одними текстами локализация не ограничивается. Для разных языков, например, потребуется разная ширина полей, другое форматирование (например, для иерографического письма сделать шрифт крупнее) и пр. Это можно было сделать в WinForms. Может, кто знает нормальный инструмент для WPF?
Для таких вещей прекрасно подходят стили (Styles). С их помощью запросто можно создавать различные темы приложения, в том числе и для определённых языковых локализаций.
С помощью них нельзя «точечно» изменить определённый контрол в приложении, не корректируя сам контрол.
Чем плох такой способ для точечных изменений?

<Button Style={StaticResource CustomButtonStyle}/>
Нужно корректировать сам XAML-файл, а не отдельные сущности для локализации. В WinForms был отдельный файл ресурсов к каждой форме, в которых можно было делать «override» практически любого значения параметра контролов в ассоциированной форме. И один файл — один язык.
<Button Style={StaticResource CustomButtonStyle}/>

Эту запись достаточно сделать один раз. Для каждого же языка можно создать отдельный файл ресурсов и редактировать тему в нём, не затрагивая само представление. В простейшем случае потребуется перезагрузка представления для смены темы, но с помощью тех же Binding Extensions очень просто реализовать «горячую» смену во время работы программы.

<Button Style={Theme Key=CustomButtonStyle}/>

WPF отличается от WinPhone и тяжелее для изучения, но он на порядок мощнее и гораздо более гибкий, чем кажется сразу.
Вы предлагаете для каждого контрола генерировать свой уникальный стиль, помноженный на количество языков? Не всем Button-ам при локализации нужно изменить размер. Некоторым понадобится изменить ширину на 10, некоторым на 20.
Это ещё очень много лишнего текста добавить в итак до предела перегруженный xaml потребуется.
Да и в конце концов, стили не для локализации нужны. Они сами по себе довольно сложный и комплексный инструмент, чтобы на них ещё локализацию подвешивать.
Не нужно делать отдельных стилей на каждый контрол да и ещё для каждого языка. Вы забываете о наследовании свойств в стилях и их переопределении. В вашем случае достаточно всего лишь трёх: первый самый общий — для большинства кнопок, второй — для кнопок с шириной 10, третий — с шириной 20. В зависимости от языка вы применяете нужную тему, например, через MergedDictionaries. Это всё делается достаточно просто.

Стили во-многом нужны для создания разных тем интерфейса. В вашем примере так и получается, что для некоторых языков темы разные (например, отличаются отступы или шрифты), поэтому их применение вполне логично и оправдано.
Хм. Видимо, я чего-то недопонимаю. Вот приходит переводчик и говорит, что текстовое поле Text1 на форме Form1 нужно слегка расширить на 10 у. е., кнопку Button1 на форме Form2 подвинуть немного вправо, а колонку Column1 на форме Form3 в таблице Table1 немного уменьшить в размерах (на сколько он сам пока не знает — ему нужно самому попробовать подвигать её). И не забудьте, что текст на контролах нужно менять тоже адресно — на каждом контроле свой. Как Вы это решите с помощью стилей?
Локализация — это совсем не то, что темки навешивать. Это, по сути, индивидуальный подход к каждому контролу.
Мне не доводилось заниматься локализацией на WinForms, поэтому благоразумнее об этом не спорить. Но с разработкой на этой платформе раньше сталкивался более-менее плотно, и, когда начал изучать WPF, вторая вызвала во мне ощутимое сопротивление обилием нетривиальных идей и подходов к разработке. Просто не понимал, зачем всё так сложно, ведь раньше хватало WinForms. Со временем же, когда проникся всеми этими мыслями и пришло их осознание, понял, что по мощности своей WPF очень далеко впереди и если что-то кажется трудноосуществимым, то это, скорее всего, от незнания или плохого понимания какого-либо механизма.

Конечно, всякие каверзные примеры можно усложнять сколько угодно, но в вашем случае мне бы хватило функцональности стилей.

По-моему, если не ошибаюсь, существует и другой способ: задать каждому визуальному элементу уникальный ключ и по нему точечно менять его параметры. По крайней мере, с помощью attached property такое достаточно просто самому реализовать. Но к такому методу сам не прибегал, поскольку стилей всегда хватало.
> Вот приходит переводчик и говорит, что текстовое поле Text1 на форме Form1 нужно слегка расширить на 10 у. е.

А зачем так?
Почему поля двигает переводчик, а не дизайнер?
Зачем поле надо расширить для какого-то языка, почему не хватает Alignment, Margin, Padding, MaxWidth?
У меня ощущение, что вы что-то не так делаете.
Перевод UI тесно связан с дизайном. Если Вам будет проще, то пусть приходит дизайнер после получения перевода от переводчика.
Проблема в том, что языки очень разные. Одна фраза на русском может быть размером в один символ на китайском и в одно длиннющее слово (которое нельзя будет разнести на пару строк) на немецком. Не говоря уже о том, что при переводе на арабский нужно будет всё переделывать на концепцию «справа налево» — в том числе и всякие выплывающие менюшки. Никогда нельзя в процессе локализации ограничиваться только текстом.
У меня ощущение, что Вы просто не адаптировали сложные формы на несколько весьма разных языков.
> Одна фраза на русском может быть размером в один символ на китайском

Так и почему не хватает Alignment, Margin, Padding, MaxWidth?

> Не говоря уже о том, что при переводе на арабский нужно будет всё переделывать на концепцию «справа налево»

Ну да, ещё выставить FlowDirection
В качестве дополнения, хочу указать вот на этот репозиторий, в котором есть объемный, хотя и немного устаревший (но имеет ли смысл это замечание к WPF), документ о способах локализации в WPF.
Так и не смог победить это:

[assembly: XmlnsDefinition(«clr-namespace:Aero.Markup;assembly=Aero.Phone», «Aero.Markup»)]
[assembly: XmlnsPrefix(«clr-namespace:Aero.Markup;assembly=Aero.Phone», «m»)]

Для универсальных проектов, а использовать расширение с явным указанием неймспейса, не дает компилятор :(
Спасибо, немного позже посмотрю. По крайней мере, для WP8.1 расширения привязки у меня работали с префиксом local, то есть когда находились в основной сборке. Для WP7 и WP8 всё точно работает, это хорошо проверял.
Ещё на Windows Store и Windows Phone 8.1, к сожалению, допустим только такой вариант декларации из-за ограничений парсера разметки

<TextBlock>
    <TextBlock.Text>
        <local:Localizing Key=AppDescription>
    </TextBlock.Text>
</TextBlock>
Да это работает, но теряет всякий смысл. Поправьте статью, что бы не вводила в заблуждение.
Про ограничения парсеров разметки на некоторых платформах упоминалось в статье. Соглашусь с тем, что в ряде случаев такой способ локализации теряет лаконичность и практическую ценность. Но тем не менее сам механизм расширений привязки сохраняет смысл, поскольку оставляет возможность реализации принципа прямых инжекций, который рассмотрен в следующей статье, и ряда других удобных усовершенствований.

Конечно, стоит признать многословность, но обычно интерфейс и разметка в мобильных Windows Store и Windows Phone 8.1 приложениях проще, чем на десктоп-платформах, поэтому на этот недостаток ещё можно закрыть глаза в виду тех преимуществ, которые можно реализовать.
Главный недостаток такого решения отсутствие поддержки интеллисенса со стороны VS, привязав модель к датаконтексту через расширения я лишился подсказок по содержанию модели, а для меня это критично, модели сложные.

Для локализации это было терпимо, но для свойств модели нет, так как при рефакторинге нет автоматического контроля ссылок :(

Хотя согласен лаконично :)
Попробуйте починить примерно так <Grid d:DataContext="{d:DesignInstance viewModels:AppViewModel}">, возможно, подсказки появятся (сам не пробовал, поскольку обхожусь без них).

А решарперовский Find Usages прекрасно работает и по умолчанию.
Решарперовский FU на попытке найти использование AppViewModel не находит его инджекцию.
Я тоже обходился до определенного момента, когда размер проекта превысил объем который я могу удержать в памяти.
У меня, похоже, находит инжекции, или вы что-то другое имеете в виду?

image

d:DesignInstance тоже работает и подсказки появляются.

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    d:DataContext="{d:DesignInstance viewModels:AppViewModel, IsDesignTimeCreatable=True}"
Как интересно, почему я в пролете.
Посмотрел подробнее, ключ тип, поэтому работает поиск типа, отлично!
В общем сделать расширение решарперу, позволяющее собирать информацию о контекстах и будет отлично.
Кстати как раз с R# связана была идея написать расширение которое бы предоставляло информацию интеллисенсу, при использовании {l:Localize Path=SMTH}.
Но начав переход на WRT где этот подход локализации не работает, идея останется не реализованной :)
Я пробовал изменить это создав свою реализацию IXamlMetadataProvider, но увы компилятор не использует определения пространств имен из пользовательской реализации провейдера.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.