Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add text direction write up #69

Merged
merged 10 commits into from
Sep 12, 2024
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"Augeas",
"Batchfile",
"Befunge",
"Bidirectionality",
"Bluespec",
"Brightscript",
"Carto",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
99 changes: 99 additions & 0 deletions src/content/docs/internationalization/text_directionality.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
title: Text Directionality
description: Handling left-to-right and right-to-left content in Flutter.
---

import { Image } from "astro:assets";
import directionExample from "./images/text_direction_figure_1.png";
import bikeBidirectional from "./images/bike_bidirectional.png";

Supporting variable text directions is a critical component of internationalization. While many languages such as English are read left-to-right (LTR), a great number including Arabic, Hebrew, and Farsi are read right-to-left (RTL). Text directionality impacts not only how text itself is displayed, but the layout and design of your app as a whole.

Fortunately, Flutter provides robust capabilities for handling variable text directions. Utilizing these correctly will allow your application to make visual sense to all users.

Let's explore how Flutter handles text directionality and discuss important guidelines for ensuring your app supports both LTR and RTL text flawlessly.

### How Flutter Handles Text Directionality

The [`Directionality`](https://api.flutter.dev/flutter/widgets/Directionality-class.html) widget is the basis of direction handling in Flutter. Its `textDirection` property controls how direction is assigned and can have a value of `TextDirection.ltr` or `TextDirection.rtl`, which will be furnished as a default text direction to all of the widget's children.

A default global `Directionality` exists across the widget layer in Flutter and is determined by the user's locale. See the [Internationalizing Flutter Apps](https://docs.flutter.dev/ui/accessibility-and-internationalization/internationalization) documentation for more information on locales in Flutter.

:::note
`Directionality.of(context)` will return the directionality of a given `BuildContext`.
:::

Directionality can also be explicitly supplied to widgets through use of the `Directionality` widget as a parent.

Let's observe how directionality impacts the display of various elements in a flutter app. Here we have a `Directionality` widget which furnishes a variable text direction to a row and its children:

```dart
Directionality(
textDirection: textDirectionLTR ? TextDirection.ltr : TextDirection.rtl,
child: Row(
children: [
// children
],
),
),
```

<Image
src={directionExample}
alt="Table comparing directional variants of one text widget, two text widgets, and two container widgets."
/>

As you can see in the first 'hello world' example, the text becomes right-aligned once `textDirection` is RTL, but the string remains displayed as typed. RTL strings are entered right-to-left and thus are handled the same way.

Note that in the second, 'hello', 'world', example that the order of _elements_ will be flipped for ordered, direction-sensitive widgets such as this `Row`. This applies to non-text elements as well, as illustrated by the third example displaying colored boxes in a row.

:::note
Flutter uses the [Unicode Bidirectional Algorithm](https://unicode.org/reports/tr9/) to determine the visual representation order of text. Read more about the algorithm to understand how text elements like mixed-directionality strings, unicode control characters, and punctuation are displayed.
:::

### Tips for Handling Directionality in Flutter Like a Pro

1. **Know when to use visual versus directional widgets.**

The mirroring behavior exhibited by text-direction-sensitive widgets presents a unique challenge for developers. For example, how are text-aligned elements supposed to maintain their relative position when the alignment of the text itself is being flipped? What about widgets that require an _absolute_ position independent of any text direction changes?

Flutter has introduced a powerful system for expressing the precise behavior you want for many direction-sensitive widgets, but it's important to understand its details in order to get the most out of your bidirectional app.

Flutter offers both visually- and directionally-demarcated versions of many relevant widgets and values. Visually-based values are defined in absolute directions such as `top`, `left`, `right`, and `bottom`. Directionally-based widgets, by contrast, are defined in terms relative to the widget's directional alignment: `top`, `start`, `end`, and `bottom`.

This distinction is illustrated by comparing the `EdgeInsets` and `EdgeInsetsDirectional` classes. If we want to introduce a padding value that always comes before the beginning of a text widget, `EdgeInsetsDirectional` allows us to maintain that relative position regardless of the text's orientation:

```dart
Padding(
padding: EdgeInsetsDirectional.only(start: 12),
child: Text('Whether RTL or LTR, padding will always be at the start of this string!'),
),
Padding(
padding: EdgeInsets.only(left: 10),
child: Text('Padding will always be to the left of this string!'),
)
```

Many Flutter widgets, including `Positioned` and `Border`, have `Directional` variants that will allow you to specify the exact relationship you want them to have with directionality.

2. **Account for non-text elements.**

Text isn't the only content in your app that changes with directionality! Many Flutter icons will also by default be mirrored when the text direction flips:

<Image
src={bikeBidirectional}
alt="Left-to-right and right-to-left variants of a bicycle icon."
/>
*Icons.directions_bike in LTR and RTL alignments (source: [material.io)](https://m2.material.io/design/usability/bidirectionality.html#mirroring-elements)*

:::note
If you want an icon to retain a static direction, set it in the `Icon`'s `textDirection` field.
:::

Images may need to be flipped as well. `Image` and most other default graphics widgets have a `matchTextDirection` property which is `false` by default. When set to `true`, the image will be drawn starting from the top left (default behavior) in LTR environments, and from the top right in RTL environments, mirroring the image.

3. **Follow bidirectional mirroring standards.**

There are established guidelines for which elements should and should not be mirrored when switching between LTR and RTL layouts. For example, visual references to a forward direction or future time (e.g. an arrow pointing right in an LTR layout) should be mirrored, whereas media progress indicators should remain oriented LTR as they model the direction of a tape being played.

There are similar conventions in place for negation symbols, physical objects, and other potentially bidirectional components. Adhering to these standards is essential for a clear and globally comprehensible user interface. For an overview of bidirectional design conventions, read Material Design's [Bidirectionality](https://m2.material.io/design/usability/bidirectionality.html) guide.