Localize DatePicker - xamarin

I need to localize DatePicker. From what I read the dialog uses system locale instead of current thread locale. Is there a workaround?
As of now, my application supports three languages user can choose from (ResourceManagers in the .NETStandard project). If the device uses different language, the whole application will be in English except for DatePicker which will be in the system language.
Both of the following are acceptable solutions:
User can choose which language they wish to use throughout the lifetime of the application
Application uses the system language if it's supported, English otherwise
Edit:
Custom renderer implementation as suggested by Raimo
public class LocaleAwareDatePickerRenderer : DatePickerRenderer{
public LocaleAwareDatePickerRenderer( Context context ) : base(context) { }
protected override EditText CreateNativeControl() {
return new EditText(Context) {TextLocale = new Locale("cs"), Focusable = false, Clickable = true, Tag = this};
}
}

Use a custom DatePickerRenderer and add these two lines to set your control's Locale:
Locale locale = new Locale(LocalizationService.GetCurrentThreadCultureInfo().TwoLetterISOLanguageName);
Control.TextLocale = locale;

Related

Customize DatePickerDialog Xamarin Android (Days Line)

I need to localize the letters of the days above the datepickerdialog in android.
I already fully localized the application to the desired language. Changed the background etc. For some reason though, the letters of the days ain't changing.
I'm currently trying to alter the dialog via a CustomDatepickRenderer, but haven't found the right properties.
You could use the custom renderer to set the current configuration.
Custom Renderer:
[assembly: ExportRenderer(typeof(Xamarin.Forms.DatePicker), typeof(DatePickerDialogCustomRenderer))]
namespace App2.Droid
{
class DatePickerDialogCustomRenderer : DatePickerRenderer
{
public DatePickerDialogCustomRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.DatePicker> e)
{
base.OnElementChanged(e);
var locale = Locale.English;
this.Control.TextLocale = locale;
Resources.Configuration.SetLocale(locale);
}
}
}
The Language of the device is Chinese. Use the code to set the language of the Days Line to English.
Before:
After:

How can I code a class to receive a property for use with custom renderers?

I have seen this coding style:
public CustomTextCell()
{
}
public static readonly BindableProperty IsCheckedProperty =
BindableProperty.Create(
"IsChecked", typeof(bool), typeof(CustomTextCell),
defaultValue: false);
public bool IsChecked
{
get { return (bool)GetValue(IsCheckedProperty); }
set { SetValue(IsCheckedProperty, value); }
}
}
and this:
public class ExtViewCell : ViewCell
{
public bool NoTap { get; set; }
}
Can someone help explain the difference. Is one serving a different function from the other? In my case all I need is to pass to a custom renderer the value of NoTap. Should I code it like in the first or second example?
The second one is a POCO - a plain old C# object - that is relatively self-explanatory, but serves not much more purpose that holding data - and not that much in this case.
The first one is a bit more interesting, especially in the context of MVVM. SetValue does more than just setting the value, but will (in most cases) raise PropertyChanged event (see INotifyPropertyChanged), to notify subscribers that, well, a property has changed.
Now how does this relate to your custom renderer? You could implement the property in your view as a plain property - i.e. without notifications - and it might work (cannot tell, though, since I do not know your custom renderer) when setting IsChecked initially (and without binding). Anyway, imagine you'll update the value of IsChecked. You do so from your code and wonder, why this change is not reflected in your custom renderer. But how is your renderer supposed to know? Polling each and every property might be possible for smaller forms, but is a terrible waste of resources. (And Xamarin.Forms just does not work this way.) You'll page/view has to tell your custom renderer, that something has changed. INotifyPropertyChanged to the rescue. In your custom renderer you can subscribe to PropertyChanged event and react to IsChecked being changed, updating your native view.

Using Properties[] in Xamarin Applications

Looking at a sample Xamarin application I see this code:
protected override void OnSleep()
{
Debug.WriteLine("OnSleep saving ResumeAtTodoId = " + ResumeAtTodoId);
// the app should keep updating this value, to
// keep the "state" in case of a sleep/resume
Properties["ResumeAtTodoId"] = ResumeAtTodoId;
}
In particular Properties["ResumeAtTodoId"]
In my application I have been using a static class like this to hold constants. But would it be better to user Properties. Is this what is normally used?
namespace Japanese
{
public static class AS
{
public static bool sac; // Score All Cards
public static bool swt; // Show Word Type
The Application Properties dictionary is used for storing persistent data. If you want to use data only during one session you should most likely use static class. If you want to persist the data even when the application closes you should use persistent data storage. Read more about the Application Properties here: https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/application-class/#Properties_Dictionary
A good alternative to Xamarin Forms Properties dictionary is James Montemagnos Settings plugin which works on Xamarin native versions as well: https://github.com/jamesmontemagno/SettingsPlugin

Change Application language configuration based on user selection

I'm trying to make my Xamarin Forms application support multiple language like English and Arabic which is based on user selection not based on phone language.
The following code shows how I change my language to Arabic or English.
The following code is a part of the TranslateExtension from the Xamarin Forms Samples:
public object ProvideValue(IServiceProvider serviceProvider)
{
if (Text == null)
return "";
ResourceManager resmgr = new ResourceManager(ResourceId, typeof(TranslateExtension).GetTypeInfo().Assembly);
var translation = resmgr.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; // HACK: returns the key, which GETS DISPLAYED TO THE USER
#endif
}
return translation;
}
Can anyone help me and tell me how to make this work based on user selection not based on device language. Thanks for help.
Apparently the code you pasted came from this example. Based on that example, you can see there is a variable ci which contains the CultureInfo on which the extension works.
So the solution to your problem is setting that ci variable correctly. If the user selects a locale, you probably save that somewhere. In the TranslateExtension constructor, you can then retrieve that locale from where you saved it.
Something like:
public TranslateExtension() {
var userlocaleSvc = DependencyService.Get<IUserLocale>();
if (userlocaleSvc.CustomCultureInfoSet()) // this method is made up
{
ci = userlocaleSvc.GetCultureInfo(); // this method is made up
} else {
ci = DependencyService.Get<ILocalize>().GetCurrentCultureInfo(); // fallback
}
}
You can also set the CultureInfo on the Resource, so resources that don't use the TranslateExtension also get translated properly (AppResources is the name you give your resource file, you can use any name you want):
AppResources.Culture = new CultureInfo ("<shortcode of selected locale>");
Refer to the Xamarin documentation on localization here

Localization and binding don't work together

I'm developing my first app and I'm trying to make it multilanguage.
Using AppHub example and some other link I created my resource files, fixed binding strings on my components and set a settings page.
First problem I had was that menu items and appbar buttons couldn't use localization strings (project complained when launched) so I have:
TextBlocks and other components binded with localized strings
Appbar buttons and items localized manually with a procedure loading localized strings
Now that I have my settings page, one item user can change is language.
Well, correct CultureInfo is selected according to user selection and then I use
Thread.CurrentThread.CurrentUICulture = Settings.Language;
When I press back button and return to main page, appbar items are localized correctly, while everything else is not.
The only workaround (that I really don't like, it's just to understand) is this:
public MainPage()
{
Thread.CurrentThread.CurrentUICulture = Settings.Language;
InitializeComponent();
// Everything else I need here
}
so I have to set language before components are created to make it work.
What's wrong? Which is the correct way to make a page refresh after changing language using binded strings?
I did not put a lot of code because I used basically the one provided in the link, but if you need more info I will edit my question.
I finally found a solution to automatically update my application components reacting to language change.
A good tutorial can be found here; briefly you must find a way to notify your app that localized resource is changed.
public class LocalizedStrings : ViewModelBase
{
private static AppResources localizedresources = new AppResources();
public AppResources LocalizedResources
{
get { return localizedresources; }
}
public void UpdateLanguage()
{
localizedresources = new AppResources();
RaisePropertyChanged(() => LocalizedResources);
}
public static LocalizedStrings LocalizedStringsResource
{
get
{
return Application.Current.Resources["LocalizedStrings"]
as LocalizedStrings;
}
}
}
With this when user change language, you should simply run
LocalizedStrings.LocalizedStringsResource.UpdateLanguage();
and the job is done.

Resources