I'm trying to support Arabic language right to left layout support but turns out there is no way you can support right to left in Xamarin Forms.
I even tried dependency service and called right to left layout by myself. Here is the code:
public CultureInfo SetLocale(string locale)
{
var netLocale = locale.Replace("_", "-");
var ci = new CultureInfo(netLocale);
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.JellyBeanMr1)
{
// Change locale settings in the app.
var dm = Forms.Context.Resources.DisplayMetrics;
var conf = Forms.Context.Resources.Configuration;
conf.Locale = new Java.Util.Locale(locale);
Forms.Context.Resources.UpdateConfiguration(conf, dm);
if (locale == "en")
(Forms.Context as MainActivity).Window.DecorView.LayoutDirection = Android.Views.View.LayoutDirectionLtr;
else
(Forms.Context as MainActivity).Window.DecorView.LayoutDirection = Android.Views.View.LayoutDirectionRtl;
}
return ci;
}
I hope I'm not too late, here are some links:
there is layoutDirection and on this forum they have answered it:
To detect when RTL is required, I use this bit of code (I found reflection was required, as the IsRightToLeft property was unexpectedly inaccessible):
bool rightToLeft = false;
PropertyInfo propertyInfo = thisCulture.TextInfo.GetType().GetRuntimeProperty("IsRightToLeft");
object value = propertyInfo?.GetValue(thisCulture.TextInfo);
if (value is bool)
rightToLeft = (bool) value;
After that, it was mostly a case of switching a few properties:
HorizontalOptions = rightToLeft ? LayoutOptions.EndAndExpand : LayoutOptions.StartAndExpand,
HorizontalTextAlignment = rightToLeft ? TextAlignment.End : TextAlignment.Start;
more links
Adjust layout and fonts, and support RTL
You could set the dir property of html if language is arabic.
<html dir="rtl">
Related
I am using MaterialDesignThemes in my WPF project and I am able to see MaterialDesign styles being used by various WPF controls I am using. In one particular situation, however, I'm having a great bit of difficulty trying to get a DatePicker to use the MaterialDesign styling. When I render DatePickers in a XAML view, it works as expected. The difference is that in the case that it does not work, the date picker is rendered in code behind. Below is my code. Can anyone help?
var dp = new DateControl()
{
Margin = new Thickness(0, 0, _fontSize, 0),
HorizontalAlignment = HorizontalAlignment.Left,
Question = q,
IsReadOnly = IsReadOnly || q.IsReadOnly
};
if (dataValue != null)
{
DateTime dt = DateTime.MinValue;
if (DateTime.TryParse(dataValue, out dt) && dt > DateTime.MinValue)
{
dp.SetSelectedDate((DateTime?)dt);
}
else
{
dp.Text = dataValue;
}
}
if (!IsReadOnly)
dp.AddHandler(DateControl.LostFocusEvent, new RoutedEventHandler(HandleUserResponse));
MaterialDesignThemes.Wpf.ColorZoneAssist.SetMode(dp, ColorZoneMode.PrimaryDark);
return dp;
You should set the Style property of your custom control:
dp.Style = FindResource("MaterialDesignDatePicker") as Style;
MaterialDesignThemes doesn't know what a DateControl is and won't automatically apply any style to such a control. The implicit style that is applied to DatePicker controls is not inherited.
I am creating charts programmatically in a manner similiar to this example on the DevExpress website. I see where you can identify series data to be formatted as currency, but the reporting tool is globally based and needs to be able to format the various chart labels using a passed in currency.
Here is an example of code used to generate a typical SeriesView:
private void FormatBarSeries (SideBySideBarSeriesView bar)
{
bar.AxisY.NumericOptions.Format = NumericFormat.Currency;
bar.AxisY.NumericOptions.Precision = 0;
bar.AxisY.Title.Text = "Sample Bar";
bar.AxisY.Title.Font = new Font(GetChartFontFamily(), 10.0f, FontStyle.Regular);
bar.AxisY.Title.Visible = true;
bar.AxisY.Tickmarks.Visible = false;
bar.AxisY.Tickmarks.MinorVisible = false;
bar.AxisX.Tickmarks.MinorVisible = false;
}
I cannot seem to find any manner of defining the culture for the specific chart. Each report may contain multiple charts, but all the charts on a report would be the same currency format.
Can this perhaps be set at the report level and have all charts inherit it? Or how can I set this on a chart by chart basis?
Found the answer, as demonstrated here:
You have to hook into a CustomDrawAxisLabel event:
Chart.CustomDrawAxisLabel += Chart_CustomDrawAxisLabel;
where you can override the code with a function like this:
void Chart_CustomDrawAxisLabel (object sender, CustomDrawAxisLabelEventArgs e)
{
AxisBase axis = e.Item.Axis;
if(axis.NumericOptions.Format == NumericFormat.Currency)
{
decimal value = 0.00M;
e.Item.Text = decimal.TryParse(e.Item.AxisValue.ToString(),
out value)
? value.ToString("C0", _culture)
: e.Item.AxisValue.ToString();
}
}
using a culture variable defined elsewhere in the class.
I have project and it supports 4 languages but now customer wants one more language. It is Arabic. I have no idea how to display Arabic in Labels and TextBoxes.
I know Arabic is written from right to left and its starting point is the right side of the label ord textview.
here is my sample code. this code show english,german and arabic....
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedItem.ToString().Equals("en-GB"))
{
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-GB");
label1.Text= FormLabels.test1;
label2.Text = FormLabels.test2;
}
else if (comboBox1.SelectedItem.ToString().Equals("de-DE"))
{
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("de-DE");
label1.Text = FormLabels.test1;
label2.Text = FormLabels.test2;
}
else if (comboBox1.SelectedItem.ToString().Equals("ar"))
{
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("ar");
label1.Text = FormLabels.test1;
label2.Text = FormLabels.test2;
}
}
How am I supposed to display Arabic characters and display the test from right to left?
//...
else if (comboBox1.SelectedItem.ToString().Equals("ar"))
{
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("ar");
label1.RightToLeft = label2.RightToLeft = RightToLeft.Yes;
label1.Text = FormLabels.test1;
label2.Text = FormLabels.test2;
}
UPDATE
if you have many many labels, there are some solutions here:
You can define a class such as called RighToLeftLabel and use it to declare all your labels:
public class RightToLeftLabel : Label {
public RightToLeftLabel(){
RightToLeft = RightToLeft.Yes;
}
}
//Then declare your labels:
RightToLeftLabel label1 = new RightToLeftLabel();
RightToLeftLabel label2 = new RightToLeftLabel();
RightToLeftLabel label3 = new RightToLeftLabel();
//you can also drag-n-drop this custom Label from the ToolBox (remember to place the class in your project namespace and build first, after that you will see there is a RightToLeftLabel control at the very top in the ToolBox)
You can loop though the collection of your Labels and change RightToLeft to Yes for each one:
foreach(Label lbl in yourLabels)
lbl.RightToLeft = RightToLeft.Yes;
//I think this is right for you because the project language may change...
i want to add on kingKing answer, which is excellent as always, that you should consider making all the form RightToLeft, because when you read the form you can't read the form RightToLeft and have the control in a reverse way.
here is an example of what i mean: if it was an arabic form translated to english:
I'm working on a SL5 app with C# and I'm looking to internationalize it. I found the following to set the UI culture:
var culture = new CultureInfo(Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName);
Thread.CurrentThread.CurrentUICulture = culture;
Thread.CurrentThread.CurrentCulture = culture;
Some controls like the DatePicker seem to pick this up. If I format any datetime by using the 'd' format string, I still get the default format "M/dd/yyyy" however.
Exactly how does SL interpret culture and how can I set it correctly for the entire application?
Thanks
UPDATE:
Found the answer:
First of all, set the appropriate cultures in the Application_Startup:
var culture = new CultureInfo("nl-BE");
Thread.CurrentThread.CurrentUICulture = culture;
Thread.CurrentThread.CurrentCulture = culture;
The key element however is to add the following to force the RootVisual's culture/language:
var root = RootVisual as Page;
if (root != null)
{
root.Language = XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.Name);
}
Edit: Updated with the information that #Rumble found.
You need to do it like this to apply it to your UI objects as well.
First set the appropriate cultures when your application is loading up.
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-IN");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-IN");
Next you need to set the XML Language property.
For Silverlight
var root = RootVisual as Page;
if (root != null)
{
root.Language = XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.Name);
}
For WPF
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(
XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
You can find an explanation for WPF here.
Thanks to eandersson
I came up with this extension for specific controls.
I had a problem with my decimal input, parsing and validation. Somewhere in the way there was this InvariantCulture with '.' as separator instead of ','.
It can be easily modifed to set up specific culture.
public class ElementCultureExtension
{
public static bool GetForceCurrentCulture( DependencyObject obj )
{
return (bool)obj.GetValue( ForceCurrentCultureProperty );
}
public static void SetForceCurrentCulture( DependencyObject obj, bool value )
{
obj.SetValue( ForceCurrentCultureProperty, value );
}
public static readonly DependencyProperty ForceCurrentCultureProperty =
DependencyProperty.RegisterAttached(
"ForceCurrentCulture", typeof( bool ), typeof( ElementCultureExtension ), new PropertyMetadata( false, OnForceCurrentCulturePropertyChanged ) );
private static void OnForceCurrentCulturePropertyChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e )
{
var control = (FrameworkElement)d;
if( (bool)e.NewValue )
{
control.Language = XmlLanguage.GetLanguage( Thread.CurrentThread.CurrentCulture.Name );
}
}
}
In Xaml:
<TextBox Text="{Binding Path=DecimalValue, Mode=TwoWay}"
tools:ElementCultureExtension.ForceCurrentCulture="True" />
I am experimenting with the WPF RichTextBox and notice that I can itterate through the blocks that make up its document by looping through RichTextBox.Document.Blocks.
What is the best way to get the Block that surrounds the caret?
I can get the CaretPosition and the ElementStart and ElementEnd properties of each block but can't see how to compare them because the actual character offsets are not exposed unless I am missing something obvious.
var curCaret = richTextBox1.CaretPosition;
var curBlock = richTextBox1.Document.Blocks.Where(x => x.ContentStart.CompareTo(curCaret) == -1 && x.ContentEnd.CompareTo(curCaret) == 1).FirstOrDefault();
Answer above probably works in WPF RTB but not in Silverlight 4.0. Most likely SL doesn't allow access to the Document protion of the RTB. So you have to do it via Reflection....
Something like this:
Set up a TextSelectionChanged Event Handler
Grab the TextSelection Pointer and find the Start TextPointer
Grab the TextSelection.Start.Parent item
Find out if it is of type paragraph
Parse the Paragraph.Inlines
Look for type of InlineUIContainer you need a cast it accordingly.
In Silverlight5 get the properties to be used to update a toolbar:
private void rtb_SelectionChanged(object sender, RoutedEventArgs e)
{
TextSelection ts = rtb.Selection;
object property;
property = ts.GetPropertyValue(Run.FontWeightProperty);
System.Windows.FontWeight fontWeight = property is System.Windows.FontWeight ? (FontWeight)property : FontWeights.Normal;
property = ts.GetPropertyValue(Run.FontStyleProperty);
System.Windows.FontStyle fontStyle = property is System.Windows.FontStyle ? (FontStyle)property : FontStyles.Normal;
TextDecorationCollection textDecorations = ts.GetPropertyValue(Run.TextDecorationsProperty) as TextDecorationCollection;
bool isUnderlined = textDecorations != null;
double? fontSize = ts.GetPropertyValue(Run.FontSizeProperty) as double?;
SolidColorBrush foreground = ts.GetPropertyValue(Run.ForegroundProperty) as SolidColorBrush;
Color foregroundColor = foreground != null ? foreground.Color : Colors.Black;
System.Diagnostics.Debug.WriteLine("fontweight:{0}, fontStyle:{1}, Underline:{2}, size:{3}, color:{4}",
fontWeight,
fontStyle,
isUnderlined,
fontSize,
foregroundColor);
if (fontSize.HasValue)
SetToolbarFontSize(fontSize.Value);
SetToolbarFontColor(foregroundColor);
}
Paragraph currentParagraph = richTextBox1.CaretPosition.Paragraph;
This code will return a Paragaph object and instead of a Block object but because the blocks in a RichTextBox are typically paragraphs this will not pose any problem.
MS Docs:
The Blocks property is the content property of RichTextBox. It is a collection of Paragraph elements.