I'm make a multi language application in flutter (ar/en), so i want to display my content in these languages, my problem is the text direction is based on the ui language, i want to change the direction dynamically based on the content if ar should be rtl, other wise ltr.
My current view My current view
desired effect desired effect
class ArticleCard extends StatelessWidget {
const ArticleCard({
Key key,
@required this.article,
@required this.isAuthor,
@required this.onDelete,
@required this.onEdit,
this.allowComments = true,
}) : super(key: key);
final ArticleModel article;
final bool isAuthor;
final bool allowComments;
final VoidCallback onDelete;
final VoidCallback onEdit;
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.only(bottom: 10),
child: Column(
children: <Widget>[
InkWell(
onTap: () {
ExtendedNavigator.ofRouter<Router>().pushNamed(
Routes.article,
arguments: ArticleScreenArguments(article: article),
);
},
child: Column(
children: <Widget>[
ListTile(
leading: CircleAvatar(
backgroundImage:
CachedNetworkImageProvider(article.owner.avatar),
),
title: Text(article.title),
subtitle: Text(
article.owner.name,
textScaleFactor: .75,
),
trailing: Text(
'${DateFormat('d, MMMM y h:mm a', 'ar').format(article.createdAt)}',
textScaleFactor: .7,
),
),
SizedBox(
width: MediaQuery.of(context).size.width,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 8),
child: Text(
article.content,
textAlign: TextAlign.start,
),
),
),
],
),
),
SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
FavoriteButton(
isFavorite: article.isFavorite,
count: article.favoriteCount,
type: FavoriteType.article,
targetId: article.id,
),
_buildLabeledIcon(
icon: Icon(Icons.message),
label: '${article.commentsCount}',
),
_buildLabeledIcon(
icon: Icon(Icons.share),
label: '${article.shares}',
),
_buildLabeledIcon(
icon: Icon(Icons.remove_red_eye),
label: '${article.views}',
),
],
),
SizedBox(height: 10),
Container(
height: 1.5,
color: Colors.black12,
),
if (isAuthor)
_buildAuthorRow(),
// Divider(),
if (allowComments) ...[
SizedBox(height: 10),
_buildCommentsSection(context),
]
],
),
);
}
Row _buildAuthorRow() {
return Row(
children: <Widget>[
Expanded(
child: InkWell(
onTap: onEdit,
child: Container(
height: 50,
alignment: Alignment.center,
child: Text(
'تعديل',
style: TextStyle(
color: appTheme.accentColor,
fontWeight: FontWeight.bold,
),
),
),
),
),
Container(
width: 1.5,
height: 50,
color: Colors.black12,
),
Expanded(
child: InkWell(
onTap: onDelete,
child: Container(
height: 50,
alignment: Alignment.center,
child: Text(
'حذف',
style: TextStyle(
color: appTheme.errorColor,
fontWeight: FontWeight.bold,
),
),
),
),
),
],
);
}
Row _buildLabeledIcon({Widget icon, String label}) {
return Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
icon,
SizedBox(width: 5),
Text(
label,
textScaleFactor: .75,
),
],
);
}
Widget _buildCommentsSection(BuildContext context) {
return Column(
children: [
if (article.comments.isNotEmpty)
CommentTile(comment: article.comments.first),
_buildCommentTextInput(context),
],
);
}
Widget _buildCommentTextInput(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
IconButton(
icon: Icon(FontAwesomeIcons.paperPlane),
onPressed: () {},
),
Flexible(
child: TextField(
decoration: InputDecoration(
hintText: 'كتابة تعليق',
filled: true,
fillColor: Color(0xFFEFEFEF),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(50)),
borderSide: BorderSide.none,
),
contentPadding: EdgeInsets.all(12),
),
onSubmitted: (_) {},
onTap: () {},
),
),
],
),
);
}
}
class CommentTile extends StatelessWidget {
final CommentModel comment;
const CommentTile({Key key, this.comment}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
ListTile(
leading: CircleAvatar(
backgroundImage: CachedNetworkImageProvider(comment.user.avatar),
),
title: Text(comment.user.name),
subtitle: Text(
DateFormat.yMEd().format(comment.createdAt),
textScaleFactor: .75,
),
),
SizedBox(
width: MediaQuery.of(context).size.width,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 8),
child: Text(
comment.text,
textAlign: TextAlign.end,
),
),
),
],
);
}
}
You must add intl package to your project, and use this code as AppTextField whole of your app:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart' as intl;
class AppTextField extends StatefulWidget {
final int maxLines;
final String title;
final TextInputType? textInput;
final bool autoFocus;
final TextInputAction inputAction;
AppTextField(this.title,
{this.maxLines: 1,
this.textInput,
this.autoFocus: false,
this.inputAction: TextInputAction.next});
@override
State<StatefulWidget> createState() => AppTextFieldSate();
}
class AppTextFieldSate extends State<AppTextField> {
String? text = '';
bool isRTL(String text) {
return intl.Bidi.detectRtlDirectionality(text);
}
@override
Widget build(BuildContext context) => Container(
margin: EdgeInsets.symmetric(vertical: 10),
child: TextField(
textDirection: isRTL(text!) ? TextDirection.rtl : TextDirection.ltr,
textInputAction: widget.inputAction,
keyboardType: widget.textInput,
autofocus: widget.autoFocus,
maxLines: widget.maxLines,
decoration: InputDecoration(
labelText: widget.title,
),
onChanged: (value) {
setState(() {
text = value;
});
}));
}
I hope it is useful :)
If you have no way of detecting the current language the user of the app is using, you can try the firebase ml lnaguage detection kit which will help you detect the language of the post
With that based on the detected language you set the textAlign
property of the Text
widget to TextAlign.left
or TextAlign.right
i.e
Text("$content", textAlign: lang=='ar'?TextAlign.right:TextAlign.left )
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With