Skip to content

Instantly share code, notes, and snippets.

@JannieT
Created May 2, 2017 06:58
Show Gist options
  • Save JannieT/8d789ca837679cbd59244564160ebe32 to your computer and use it in GitHub Desktop.
Save JannieT/8d789ca837679cbd59244564160ebe32 to your computer and use it in GitHub Desktop.
Xamarin.Forms localization when using a shared project
namespace Langham
{
public class AndroidLocale : Locale
{
public AndroidLocale() : base()
{
}
public override void ApplyLocale()
{
Thread.CurrentThread.CurrentCulture = CI;
Thread.CurrentThread.CurrentUICulture = CI;
}
protected override string GetNetLanguage()
{
var androidLocale = Java.Util.Locale.Default;
var androidLanguage = androidLocale.ToString().Replace("_", "-");
Debug.WriteLine($"Android Language: {androidLanguage}");
var netLanguage = androidLanguage;
//certain languages need to be converted to CultureInfo equivalent
switch (androidLanguage)
{
case "ms-BN": // "Malaysian (Brunei)" not supported .NET culture
case "ms-MY": // "Malaysian (Malaysia)" not supported .NET culture
case "ms-SG": // "Malaysian (Singapore)" not supported .NET culture
netLanguage = "ms"; // closest supported
break;
case "in-ID": // "Indonesian (Indonesia)" has different code in .NET
netLanguage = "id-ID"; // correct code for .NET
break;
case "gsw-CH": // "Schwiizertüütsch (Swiss German)" not supported .NET culture
netLanguage = "de-CH"; // closest supported
break;
// add more application-specific cases here (if required)
// ONLY use cultures that have been tested and known to work
}
Debug.WriteLine($".NET Language/Locale: {netLanguage}");
return netLanguage;
}
protected override string GetNetFallbackLanguage(string languageCode)
{
var netLanguage = languageCode; // use the first part of the identifier (two chars, usually);
switch (languageCode)
{
case "gsw":
netLanguage = "de-CH"; // equivalent to German (Switzerland) for this app
break;
// add more application-specific cases here (if required)
// ONLY use cultures that have been tested and known to work
}
return netLanguage;
}
}
}
namespace Langham.Model
{
public interface ILocale
{
string Native(string key);
string NativeOrKey(string key);
}
}
namespace Langham
{
public class iOSLocale : Locale
{
public iOSLocale() : base()
{
}
public override void ApplyLocale()
{
Thread.CurrentThread.CurrentCulture = CI;
Thread.CurrentThread.CurrentUICulture = CI;
}
protected override string GetNetLanguage()
{
var netLanguage = DEFAULT_LANGUAGE;
if (NSLocale.PreferredLanguages.Length == 0)
return netLanguage;
var iOSLanguage = NSLocale.PreferredLanguages[0];
Debug.WriteLine($"iOS Language: {iOSLanguage}");
netLanguage = iOSLanguage;
//certain languages need to be converted to CultureInfo equivalent
switch (iOSLanguage)
{
case "ms-MY": // "Malaysian (Malaysia)" not supported .NET culture
case "ms-SG": // "Malaysian (Singapore)" not supported .NET culture
netLanguage = "ms"; // closest supported
break;
case "gsw-CH": // "Schwiizertüütsch (Swiss German)" not supported .NET culture
netLanguage = "de-CH"; // closest supported
break;
// add more application-specific cases here (if required)
// ONLY use cultures that have been tested and known to work
}
Debug.WriteLine($".NET Language/Locale: {netLanguage}");
return netLanguage;
}
protected override string GetNetFallbackLanguage(string languageCode)
{
var netLanguage = languageCode; // use the first part of the identifier (two chars, usually);
switch (languageCode)
{
case "pt":
netLanguage = "pt-PT"; // fallback to Portuguese (Portugal)
break;
case "gsw":
netLanguage = "de-CH"; // equivalent to German (Switzerland) for this app
break;
// add more application-specific cases here (if required)
// ONLY use cultures that have been tested and known to work
}
return netLanguage;
}
}
}
namespace Langham
{
public abstract class Locale : Langham.Model.ILocale
{
protected const string DEFAULT_LANGUAGE = "en";
public CultureInfo CI { get; }
public Locale()
{
CI = GetCurrentCultureInfo();
}
public string NativeOrKey(string key)
{
string translated = Fetch(key);
if (translated == null)
return key;
return translated;
}
public string Native(string key)
{
string translated = Fetch(key);
if (translated == null)
throw new ArgumentException($"Key {key} was not found in resources", key);
return translated;
}
string Fetch(string key)
{
var manager = new ResourceManager("Langham.Resx.AppResources", typeof(Locale).GetTypeInfo().Assembly);
return manager.GetString(key, CI);
}
public abstract void ApplyLocale();
protected abstract string GetNetLanguage();
protected abstract string GetNetFallbackLanguage(string languageCode);
protected CultureInfo GetCurrentCultureInfo()
{
var netLanguage = GetNetLanguage();
CultureInfo ci = null;
try
{
ci = new CultureInfo(netLanguage);
}
catch (CultureNotFoundException)
{
// platform locale not valid .NET culture (eg. "en-ES" : English in Spain on iOS)
// fallback to first characters, in this case "en"
try
{
var fallback = GetNetFallbackLanguage(LanguageCode(netLanguage));
Debug.WriteLine($"{netLanguage} failed, trying {fallback}");
ci = new CultureInfo(fallback);
}
catch (CultureNotFoundException)
{
// fallback not valid, falling back to default language
Debug.WriteLine($"{netLanguage} couldn't be set, using '{DEFAULT_LANGUAGE}'");
ci = new CultureInfo(DEFAULT_LANGUAGE);
}
}
return ci;
}
private string LanguageCode(string platformCultureString)
{
var platformString = platformCultureString.Replace("_", "-"); // .NET expects dash, not underscore
var dashIndex = platformString.IndexOf("-", StringComparison.Ordinal);
if (dashIndex == -1) return platformString;
var parts = platformString.Split('-');
return parts[0];
}
}
}
namespace Langham
{
// You exclude the 'Extension' suffix when using in Xaml markup
[ContentProperty("Text")]
public class TranslateExtension : IMarkupExtension
{
Locale locale;
public TranslateExtension()
{
locale = Container.Current.Resolve<Locale>();
}
public string Text { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
{
if (Text == null)
return "";
return locale.Native(Text);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment