Skip to content

Instantly share code, notes, and snippets.

@francipvb
Created October 7, 2019 16:04
Show Gist options
  • Save francipvb/ee3c1f121513bcc9154f49397be85fb5 to your computer and use it in GitHub Desktop.
Save francipvb/ee3c1f121513bcc9154f49397be85fb5 to your computer and use it in GitHub Desktop.
Localize xaml markup extension

This is how I'm doing localization for my first real mobile project. I'm using the Microsoft's localization library. It's a nice library that takes resources from reflected object under the assembly.

Note that I'm using also prism library for xamarin.forms, I found that it is very good tool to have.

Happy coding!

<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Menu" xml:space="preserve">
<value>Menú</value>
</data>
</root>
using Prism;
using Prism.Ioc;
using PersonalCompany.ViewModels;
using PersonalCompany.Views;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using PersonalCompany.Views.Stocks;
using PersonalCompany.ViewModels.Stocks;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using DryIoc;
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace PersonalCompany
{
public partial class App
{
public App() : this(null) { }
public App(IPlatformInitializer initializer) : base(initializer) { }
protected override async void OnInitialized()
{
InitializeComponent();
await NavigationService.NavigateAsync("MasterPage/NavigationPage/MainPage");
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
// Services:
containerRegistry.RegisterInstance<IOptions<LocalizationOptions>>(Options.Create(new LocalizationOptions()));
containerRegistry.RegisterSingleton<ILoggerFactory, NullLoggerFactory>();
containerRegistry.RegisterSingleton<IStringLocalizerFactory, ResourceManagerStringLocalizerFactory>();
// We must register a factory for localizers and loggers:
containerRegistry.Register(typeof(IStringLocalizer<>), typeof(StringLocalizer<>));
containerRegistry.RegisterSingleton<IStringLocalizer, StringLocalizer<App>>();
containerRegistry.RegisterForNavigation<MasterPage, MasterPageViewModel>();
containerRegistry.RegisterForNavigation<NavigationPage>();
containerRegistry.RegisterForNavigation<MainPage, MainPageViewModel>();
containerRegistry.RegisterForNavigation<AboutPage, AboutPageViewModel>();
containerRegistry.RegisterForNavigation<StocksPage, StocksPageViewModel>();
}
}
}
using Microsoft.Extensions.Localization;
using System;
using Xamarin.Forms.Xaml;
using Prism.Ioc;
using Xamarin.Forms;
namespace PersonalCompany.Extensions
{
/// <summary>
/// Returns a localized string from the input, or the original ones if it was not found.
/// </summary>
[ContentProperty(nameof(Message))]
public class LocalizeExtension : IMarkupExtension<string>
{
/// <summary>
/// Empty constructor required by Xaml
/// </summary>
public LocalizeExtension()
{
}
/// <summary>
/// Returns a localized version of the string.
/// </summary>
/// <param name="serviceProvider">A provider that contains XAML specific services.</param>
/// <returns>The localized message.</returns>
public string ProvideValue(IServiceProvider serviceProvider)
{
var localizer = Prism.PrismApplicationBase.Current?.Container.Resolve<IStringLocalizer>();
return localizer[Message] ?? Message;
}
/// <summary>
/// Derives this call to <see cref="ProvideValue(IServiceProvider)"/> and returns it's result.
/// </summary>
/// <param name="serviceProvider"></param>
/// <returns></returns>
object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
{
return ProvideValue(serviceProvider);
}
/// <summary>
/// The message to be translated.
/// </summary>
public string Message { get; set; }
}
}
<?xml version="1.0" encoding="utf-8" ?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="http://prismlibrary.com"
xmlns:ext="clr-namespace:PersonalCompany.Extensions"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="PersonalCompany.Views.MasterPage">
<MasterDetailPage.Master>
<ContentPage Title="{ext:Localize 'Menu'}">
<StackLayout Padding="20">
<Button Text="ext:Localize 'About'" Command="{prism:NavigateTo 'NavigationPage/MainPage/AboutPage', SourcePage={x:Reference mdp}}" />
</StackLayout>
</ContentPage>
</MasterDetailPage.Master>
</MasterDetailPage>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment