How Change the CultureInfo Dynamically in xamarin forms - c#

i need to creata a app with support multilingual.
So i did a sample app like below.
Page.xamal
<StackLayout
VerticalOptions="CenterAndExpand">
<Label Text="{x:Static local:AppResources.Title}" TextColor="Black"
HorizontalOptions="CenterAndExpand" />
<Button Text="{x:Static local:AppResources.ClickMe}" Clicked="Button1_Clicked"/>
<Label Text="{x:Static local:AppResources.Title}" TextColor="Black"
HorizontalOptions="CenterAndExpand" />
<Button Text="{x:Static local:AppResources.ClickMe}" Clicked="Button2_Clicked"/>
</StackLayout>
page.xamal.cs
private void Button1_Clicked(object sender, EventArgs e)
{
CultureInfo culture = new CultureInfo("th");
AppResources.Culture = culture;
}
as xmarin forms documentation provide i set the AssemblyInfo.cs (Common folder)
[assembly: NeutralResourcesLanguage("en-GB")]
so my default language is "en-GB".
i have 3 AppRerources.resx
AppResources.resx
AppResources.th.resx
AppResources.en-GB.resx
but when i press first button i could not see that app is changing the language.
anything i missed here?

About changing current cultureinfo, I suggest you can try to use Plugin.Multilingual to get it.
firstly, installing Plugin.Multilingual by nuget package, define .resx file like this:
In TranslateExtension.cs file in the constant ResourceId by default it will assume your resource file is added in the root of the project and the resx file is named as AppResources. If you added it to a folder or named the resx file differently you can change it there.
public class TranslateExtension : IMarkupExtension
{
const string ResourceId = "MultilingualSample.AppResources";
static readonly Lazy<ResourceManager> resmgr = new Lazy<ResourceManager>(() => new ResourceManager(ResourceId, typeof(TranslateExtension).GetTypeInfo().Assembly));
public string Text { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
{
if (Text == null)
return "";
var ci = CrossMultilingual.Current.CurrentCultureInfo;
var translation = resmgr.Value.GetString(Text, ci);
if (translation == null)
{
#if DEBUG
throw new ArgumentException(
String.Format("Key '{0}' was not found in resources '{1}' for culture '{2}'.", Text, ResourceId, ci.Name),
"Text");
#else
translation = Text; // returns the key, which GETS DISPLAYED TO THE USER
#endif
}
return translation;
}
}
More detailed info, please take a look:
https://github.com/CrossGeeks/MultilingualPlugin

Pass argument in CultureInfo the culture you want to set , e.g. I set it to German in my example
CultureInfo ci = new CultureInfo("de-DE");
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;

Related

C# Class library - resource files not loading

I am working on adding localisation to my class library. Currently I have two resource files: Strings.resx and Strings.es.resx.
Both files are under the 'internal' access modifier, although I have tried setting both to 'public' without any help.
My problem is that the Spanish resource file (Strings.es.resx) is not being loaded; and this problem will repeat with any more resource files I add for other languages. The Strings.resx works fine as it is the default resource file.
This code is used to grab which string resource files have been loaded; currently only the default file is loaded. Spanish does not appear:
private static void LoadLanguages()
{
var cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
foreach (var culture in cultures)
{
try
{
var rs = Properties.Lang.Strings.ResourceManager.GetResourceSet(culture, true, false);
if (rs != null) SupportedLanguages.Add(culture.Name.ToLower(), culture.NativeName);
}
catch (Exception)
{
// ignored
}
}
Log.Info("Loaded languages: " + SupportedLanguages.Count); //OUT: 1
}
I have made a discovery though. In my build output, there is a folder "es", and within that folder is a DLL called Project.resources.dll. If I copy that DLL to the root folder of the build output, the resource gets loaded.
The solution to this problem is to get those resource files loaded from the folders. For some reason this is not happening. Is there a known solution to this? Thanks.
It works out the threads current culture. An example can be seen in the docs over at Microsoft https://learn.microsoft.com/en-us/dotnet/framework/resources/creating-satellite-assemblies-for-desktop-apps (check code at step 13 in the end)
Below the example from the documentation. The localized resource is StringLibrary
using System;
using System.Globalization;
using System.Threading;
public class Example
{
public static void Main()
{
string[] cultureNames = { "en-GB", "en-US", "fr-FR", "ru-RU" };
Random rnd = new Random();
string cultureName = cultureNames[rnd.Next(0, cultureNames.Length)];
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(cultureName);
Console.WriteLine("The current UI culture is {0}",
Thread.CurrentThread.CurrentUICulture.Name);
StringLibrary strLib = new StringLibrary();
string greeting = strLib.GetGreeting();
Console.WriteLine(greeting);
}
}

Xamarin.mac Resources localization doesn't change by current culture

I am trying to use .resx files for localization in xamarin.mac
Inside AppDelegate I changed current culture of the thread :
System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo ("ru");
System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo ("ru");
also I have two resource files inside my app:
But strings are always shown from the default resource file... Any solution?
I also use native language change, here is whole AppDelegate constructor :
public AppDelegate ()
{
string [] lang = { "ru", "en" };
NSUserDefaults.StandardUserDefaults.SetValueForKey (NSArray.FromObjects (lang), (Foundation.NSString)"AppleLanguages");
NSUserDefaults.StandardUserDefaults.Synchronize ();
System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo ("ru");
System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo ("ru");
Resources.Culture = GetCurrentCultureInfo ();
}
BTW , xamarin studio 6.1.1 (build 15) doesn't allow me to add resource.ru.resx if I have resource.ru in my project , kinda bug !
I have created resource-ru.resx file and than renamed it .
You need to set the app culture after retrieving it from the OS, something like this (warning, this is from Xamarin iOS, but for the documentation it works the same way, if not advice me and I will delete the post):
//Add this somewhere
public System.Globalization.CultureInfo GetCurrentCultureInfo ()
{
var netLanguage = "en";
if (NSLocale.PreferredLanguages.Length > 0) {
var pref = NSLocale.PreferredLanguages [0];
netLanguage = pref.Replace ("_", "-"); // turns en_US into en-US
}
try
{
return new System.Globalization.CultureInfo(netLanguage);
}catch{
try{
return new System.Globalization.CultureInfo(netLanguage.Substring(0, netLanguage.IndexOf("-")));
}
catch{
return new System.Globalization.CultureInfo("en");
}
}
}
//And finally add this at the start of the app
AppResources.Culture = GetCurrentCultureInfo();
Likely you are running into
https://bugzilla.xamarin.com/show_bug.cgi?id=45696
You can work around it using a custom msbuild step. Shown here (due to length):
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CreateAppBundleDependsOn>$(CreateAppBundleDependsOn);WorkAroundLocalizationBug-ES;WorkAroundLocalizationBug-FR</CreateAppBundleDependsOn>
</PropertyGroup>
<Target Name="WorkAroundLocalizationBug-ES" Inputs="$(OutputPath)es/XMLocalizationSample.resources.dll" Outputs="$(AppBundleDir)/Contents/MonoBundle/es/XMLocalizationSample.resources.dll">
<Copy SourceFiles="$(OutputPath)es/XMLocalizationSample.resources.dll" DestinationFiles="$(AppBundleDir)/Contents/MonoBundle/es/XMLocalizationSample.resources.dll" />
</Target>
<Target Name="WorkAroundLocalizationBug-FR" Inputs="$(OutputPath)fr/XMLocalizationSample.resources.dll" Outputs="$(AppBundleDir)/Contents/MonoBundle/fr/XMLocalizationSample.resources.dll">
<Copy SourceFiles="$(OutputPath)fr/XMLocalizationSample.resources.dll" DestinationFiles="$(AppBundleDir)/Contents/MonoBundle/fr/XMLocalizationSample.resources.dll" />
</Target>
</Project>
A full sample can be found here: https://github.com/xamarin/mac-samples/tree/master/XMLocalizationSample

Redirect to unique view depending on client locale

I am adding Globalization to a C# MVC 5 web application.
in most views I use Resources and it works great. For views with a lot of customization I want to seperate the views, each for different language.
I followed Brian Reiter post. I add the Globalization forlder under Views, the ISO 639-1 two-letter macro-language code, and the Home folder and Index view for the specific langague.
I understand that I need to modify the mechnisem that renders the views to take into account the client's locale. in Brian's post it is demonstrated on web forms and in my solution I don't seem to have the same WebFormViewEngine as in his example.
I will appriciate if you could direct me to how should I extand the mvc view engine so the correct view will be rendered depending the locale.
Thanks.
This how I fixed my project:
added a class that will extand the RazorViewEngine (inherit from it).
I used the code in Brian Reiter post (link above) with slight changes (from WebFormsViewEngine to RazorViewEngine, my apps culture cookie and the extraction of the two letter languge from the culture):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Text.RegularExpressions;
using System.IO;
using LeadsWize.Helpers;
using System.Globalization;
namespace System.Web.Mvc
{
public class GlobalizationViewEngine : RazorViewEngine
{
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
partialPath = GlobalizeViewPath(controllerContext, partialPath);
return new RazorView(controllerContext, partialPath, null, false, FileExtensions, ViewPageActivator);
}
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
viewPath = GlobalizeViewPath(controllerContext, viewPath);
return base.CreateView(controllerContext, viewPath, masterPath);
}
private static string GlobalizeViewPath(ControllerContext controllerContext, string viewPath)
{
var request = controllerContext.HttpContext.Request;
string cultureName = null;
HttpCookie cultureCookie = request.Cookies["_culture"];
if (cultureCookie != null)
cultureName = cultureCookie.Value;
else
cultureName = request.UserLanguages != null && request.UserLanguages.Length > 0 ?
request.UserLanguages[0] : // obtain it from HTTP header AcceptLanguages
null;
// Validate culture name
cultureName = CultureHelper.GetImplementedCulture(cultureName); // This is safe
var lang = (CultureInfo.CreateSpecificCulture(cultureName)).TwoLetterISOLanguageName; // this is to extract the two languge letters from the culture
if (lang != null &&
!string.IsNullOrEmpty(lang) &&
!string.Equals(lang, "en", StringComparison.InvariantCultureIgnoreCase))
{
string localizedViewPath = Regex.Replace(
viewPath,
"^~/Views/",
string.Format("~/Views/Globalization/{0}/",
lang
));
if (File.Exists(request.MapPath(localizedViewPath)))
{ viewPath = localizedViewPath; }
}
return viewPath;
}
}
}
added there two lines in the Application_Stat in Global.asxs.cs
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new GlobalizationViewEngine()); //this is our customized extended view engine to support the globaliztion in view folder Globalization.
** please note that the folders arangemnet for the globalized view files are exactly in the same hierarchy as in Brian's post.

Cannot get localization working in MVC 4

I've been trying to follow the blog post found here. I've added a new assembly that hosts my resource files (I used a separate assembly as the resources may need to be shared between multiple projects). I have added the following to my web.config:
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="MyResources.Resources"/> <!-- New entry for resources -->
</namespaces>
</pages>
</system.web.webPages.razor>
And I have gone though and added resource strings to a few files for testing purposes. Now the problem that I seem to be running into, is that I cannot set the resource to be anything other than the default. So for example, in the generated resource file designer there is the following:
/// <summary>
/// Looks up a localized string similar to Log in was unsuccessful. Please correct the errors and try again..
/// </summary>
public static string Account_LoginUnsuccessful {
get {
return ResourceManager.GetString("Account_LoginUnsuccessful", resourceCulture);
}
}
If I set a breakpoint in this method, resourceCulture is NEVER anything but null. Even though I have tried the following:
In Global.asax.ca:
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
var culture = new System.Globalization.CultureInfo("fr");
// Modify current thread's cultures
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(culture.Name);
} // End of Application_AcquireRequestState
In a base mvc controller that all of my other controller inherit:
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
SetCulture(requestContext.HttpContext.Request);
base.Initialize(requestContext);
}
protected override void ExecuteCore()
{
SetCulture(Request);
base.ExecuteCore();
}
protected override void Execute(System.Web.Routing.RequestContext requestContext)
{
SetCulture(requestContext.HttpContext.Request);
base.Execute(requestContext);
}
protected override IAsyncResult BeginExecute(System.Web.Routing.RequestContext requestContext, AsyncCallback callback, object state)
{
SetCulture(requestContext.HttpContext.Request);
metrics = Metrics.BeginTimer();
return base.BeginExecute(requestContext, callback, state);
}
private void SetCulture(HttpRequestBase Request)
{
string cultureName = "fr";
// Validate culture name
cultureName = CultureHelper.GetImplementedCulture(cultureName); // This is safe
// Modify current thread's cultures
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
}
Now, to my understanding setting the threading current culture should be causing my resource files culture to change. I can't seem to get this working of the life of me (hence why I have tried setting the cultire in about ten different locations).
Any suggestions on what I am doing wrong here?
Just to verify, try setting the language in a ActionFilterAttribute:
public class ChangeLanguageAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(
ActionExecutingContext filterContext)
{
string languageCode = "fr";
CultureInfo info =
CultureInfo.CreateSpecificCulture(languageCode.ToString());
Thread.CurrentThread.CurrentCulture = info;
Thread.CurrentThread.CurrentUICulture = info;
}
}
This is the exact code Im using, so I know this works.
this is the code i came up with, it should be on Application_OnBeginRequest :
public void Application_OnBeginRequest(object sender, EventArgs e)
{
System.Globalization.CultureInfo NC = new System.Globalization.CultureInfo(1036, true);
NC.NumberFormat.CurrencyDecimalDigits = 2;
NC.NumberFormat.CurrencySymbol = "euro";
NC.NumberFormat.CurrencyDecimalSeparator = ".";
NC.NumberFormat.PercentDecimalSeparator = ".";
NC.NumberFormat.NumberDecimalSeparator = ".";
NC.NumberFormat.CurrencyGroupSeparator = "";
NC.NumberFormat.PercentGroupSeparator = "";
NC.NumberFormat.NumberGroupSeparator = "";
System.Threading.Thread.CurrentThread.CurrentCulture = NC;
}

Internationalize HelloWorld program .NET

I have small test app which has 2 resource files (Resources.resx & Resources.de-DE.resx) with the same exact string names, but one has the strings converted to German.
For my form I set the Localize property to ture.
In my application I am getting the strings as such:
this.Text = Properties.Resources.frmCaption;
In my release folder I get a de-DE folder with a dll named International_test.resources.dll.
I try to distribute this to a machine which is set to German and all of the strings pulled are still english.
I tried keeping the International_test.resources.dll in the de-DE folder or just put in in my apps directory.
What am I doing wrong or what do I need to do to get the German resource file to be used?
As luck would have it, I use hello world prototype project to test a whole bunch of stuff in our build pipeline.
Assuming you have setup your resource files correctly, here's some example code that may help. Code documentation removed for brevity.
public class HelloWorld
{
public CultureInfo CultureInfo { get; private set; }
public HelloWorld()
{
CultureInfo = CultureInfo.CurrentCulture;
}
public HelloWorld(string culture)
{
CultureInfo = CultureInfo.GetCultureInfo(culture);
}
public string SayHelloWorld()
{
return Resources.ResourceManager.GetString("HelloWorld", CultureInfo);
}
}
[TestFixture]
public class HelloWorldFixture
{
HelloWorld helloWorld;
[Test]
public void Ctor_SetsCultureInfo_ToCurrentCultureForParameterlessCtor()
{
helloWorld = new HelloWorld();
Assert.AreEqual(helloWorld.CultureInfo, CultureInfo.CurrentCulture,
"Expected CultureInfo to be set as CurrentCulture");
}
[Test]
public void Ctor_SetsCultureInfo_ToAustralianCulture()
{
helloWorld = new HelloWorld("en-AU");
Assert.AreEqual(helloWorld.CultureInfo.Name, "en-AU",
"Expected CultureInfo to be set to Australian culture");
}
[Test]
[ExpectedException(typeof(ArgumentException))]
public void Ctor_ThrowsException_InvalidCultureName()
{
helloWorld = new HelloWorld("Bogus");
}
[Test]
public void SayHelloWorld_ReturnsFallbackResource_OnUndefinedResource()
{
helloWorld = new HelloWorld("en-JM");
string result = helloWorld.SayHelloWorld();
Assert.AreEqual("Hello, World.", result, "Expected fallback resource string to be used");
}
[Test]
public void SayHelloWorld_ReturnsAustralianResource_OnAustralianResource()
{
helloWorld = new HelloWorld("en-AU");
string result = helloWorld.SayHelloWorld();
Assert.AreEqual("G'Day, World.", result, "Expected australian resource string to be used");
}
}
This project has Resources.resx file with HelloWorld string key item and "Hello, World" value, along with corresponding Resources.en-AU.resx with HelloWorld string key item and "G'Day, World" value, plus others such as zh-CH (我隻氣墊船裝滿晒鱔.:) to test display of non-English characters, as it gets displayed in the associated hello world web project.
Finally, Add some logging to show the culture being used (I took it out of this example for brevity), and also check your compiler output to ensure AL.exe is being invoked to link your resource assemblies (sounds like it's OK though).
I think my problem is that I am using a US version of XP with its language set to German as well other culture settings. The CurrentCulture and CurrentUICulture still appear to be still be "en-US"
I guess the best way to test then is to manually set the cultures at the start of the program like:
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("de-DE");
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture("de-DE");
thanks a ton Si.
I finally got my problem figured out.
My Resource files are in the Properties folder so I need to put the following
//using embedded resources
ResourceManager rm = new ResourceManager("International_test.Properties.Resources", Assembly.GetExecutingAssembly());

Categories

Resources