#c# #xaml #windows-phone-8.1
#c# #xaml #windows-phone-8.1
Вопрос:
Из-за спецификаций проектирования архитектуры у меня есть приложение, которое заполняет свои представления из ClassLibraries
. Само приложение ведет себя как своего рода интегратор.
Теперь мне нужно добавить ресурсы локализации, и я могу успешно достичь этого, добавив *.resw
файлы, но только в том случае, если элемент управления объявлен внутри проекта приложения.
Что мне действительно нужно, так это возможность каким-то образом распределять эти ресурсы по ВСЕМУ РЕШЕНИЮ.
Затем речь идет о возможности перевода содержимого любого элемента управления решения с использованием ресурсов локализации, предпочтительно с использованием структуры, описанной выше.
Например, у меня есть следующее представление, которое заполняет TextBlocks
‘ содержимое в зависимости от выбранного языка:
<ComboBox x:Name="Languages"
ItemsSource="{Binding Languages}"
SelectedItem="{Binding SelectedLanguage, Mode=TwoWay}">
<i:Interaction.Behaviors>
<iCore:EventTriggerBehavior EventName="SelectionChanged">
<iCore:InvokeCommandAction Command="{Binding ChangeLanguage}" />
</iCore:EventTriggerBehavior>
</i:Interaction.Behaviors>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding LanguageName}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Text="{Binding Model.HelloText}" FontSize="50" Foreground="Red"/>
<TextBlock Text="{Binding Model.HowAreYouText}" FontSize="50" Foreground="Red"/>
<BFview:BFView />
</StackPanel>
Где BFView
находится представление, хранящееся в другом проекте (также имеет два фиктивных текстовых блока)
Model
Этого представления:
public class MainModel : TranslatableStrings
{
private string helloText, howareuText;
public string HelloText
{
get { return this.helloText; }
set { SetProperty(ref this.helloText, value); }
}
public string HowAreYouText
{
get { return this.howareuText; }
set { SetProperty(ref this.howareuText, value); }
}
}
И базовый класс Model
— это просто договорной класс, поскольку у него нет реализации, но есть базовый тип:
public abstract class TranslatableStrings : BindableBase { }
Тогда View
контекст данных будет следующим:
public class MainViewModel : BaseViewModel
{
private ObservableCollection<MainViewListRscs> languages = new ObservableCollection<MainViewListRscs>();
private ICommand changeLang;
private MainModel model = new MainModel();
public MainViewModel()
{
Languages = new ObservableCollection<MainViewListRscs>()
{
new MainViewListRscs { LanguageCode = "es-ES", LanguageName = "Español" },
new MainViewListRscs { LanguageCode = "en-EN", LanguageName = "English" },
new MainViewListRscs { LanguageCode = "fr-FR", LanguageName = "Français" },
new MainViewListRscs { LanguageCode = "de-DE", LanguageName = "Deutsch" }
};
}
public ICommand ChangeLanguage
{
get { return changeLang = changeLang ?? new DelegateCommand(OnChangeLanguageRequested); }
}
public ObservableCollection<MainViewListRscs> Languages
{
get { return this.languages; }
set
{
this.languages = value;
OnPropertyChanged();
}
}
public MainViewListRscs SelectedLanguage { get; set; }
public MainModel Model
{
get { return this.model; }
set { this.model = value; }
}
private void OnChangeLanguageRequested()
{
Logger.Debug("MAINVIEW", SelectedLanguage.LanguageName " selected.");
TranslateManager.UpdateStrings<TranslatableStrings>(SelectedLanguage.LanguageCode, this.Model);
}
public override Task OnNavigatedFrom(NavigationEventArgs args)
{
return null;
}
public override Task OnNavigatedTo(NavigationEventArgs args)
{
return null;
}
}
И TranslateManager
:
public class TranslateManager
{
public async static void UpdateStrings<T>(string langCode, T instance) where T : TranslatableStrings
{
//Get all the classes that implement TranslatableStrings
var currentAssembly = instance.GetType().GetTypeInfo().Assembly;
var translatableClasses = currentAssembly.DefinedTypes.Where(type => type.BaseType == typeof(T)).ToList();
//Open RESX file
ResourceLoader resx = ResourceLoader.GetForCurrentView(langCode);
foreach(var Class in translatableClasses)
{
foreach(var property in Class.DeclaredProperties)
{
string value = resx.GetString(property.Name);
var vmProp = instance.GetType().GetTypeInfo().GetDeclaredProperty(property.Name);
vmProp.SetValue(instance, value);
}
}
}
}
Я добился изменения двух TextBlocks
из MainView
, но не представления в другом проекте. Что мне нужно было бы сделать, так это получить список сборок, содержащихся в решении. Я думаю, что получение только этого заставило бы все работать, поскольку я использую общую реализацию.
Любое предложение будет высоко оценено.
Спасибо!
Ответ №1:
Ваши файлы перевода загружаются как ресурсы. Таким образом, вы можете получить к ним доступ в любом месте, даже в других проектах, выполнив что-то вроде
private ResourceLoader _resourceLoader = new ResourceLoader();
var someTranslation =_resourceLoader.GetString("your_localization_key");
Красиво оберните этот код в библиотеку, чтобы у вас был легкий доступ к нему отовсюду, и готово!
Комментарии:
1. Спасибо за ответ! Я работал над решением, реализующим перевод так, как вы мне предложили, но теперь я думаю, что у меня есть ментальный блок… Смотрите обновленный вопрос