Flutter Localizations with variables - flutter

I'm trying to localize my Flutter app by following the documentation.
What I'm trying to achieve is that while building widgets dynamically, I wanted to translate the data which comes from my model. This is what I've tried so far
List.generate(services.length, (index) {
final Service service = services[index];
return Material(
borderRadius: BorderRadius.circular(10.0),
child: Text(
AppLocalizations.of(context).{{service.title}} // Here I wanted to translate the service title
),
);
}
How can I achieve this in Flutter? or any other possible method to translate dynamic contents.

Dynamic translation is not supported by Flutter localization packages. You can try to integrate google translation API in you app. But I strongly convinced that it should be a server-side feature and Flutter client should obtain already translated messages in your models. To achieve this, for example, you can use http-headers with your device locale to tell client's language to server.
Also you need to use arguments for Intl messages according to this guide. Here is an example of message with String argument in AppLocalizations:
String someLocalizedString(String argument) => Intl.message(
'Localized part - $argument',
name: 'someLocalizedString',
locale: localeName,
args: [argument],
);
This string inside .arb file:
"someLocalizedString": "Localized part - {argument}",
"#someLocalizedString": {
"type": "text",
"placeholders": {
"argument": {}
}
}

Related

How to pass an Argument as SerializedMessage

I'm quite new to Flutter and to learn "best practice" I loaded up the new skeleton example app.
You get three example items in a list view and when you click on one of them you go to a details view. I want to pass the object so that for every example item there is a custom details view.
So I changed the code to the following:
ListTile(
leading: const FlutterLogo(),
title: Text(myObject.name),
onTap: () {
Navigator.restorablePushNamed(
context, ObjectDetailView.routeName,
arguments: myObject);
},
trailing: const Icon(Icons.arrow_forward_ios_rounded),
But it shows the error: The arguments object must be serializable via the StandardMessageCodec.
How can I do it? This seems quite complicated for an "example app". Does it make sense to use restorablePushNamed() on a details page? Or should I switch to the "normal" push/pop-Method.
It does makes sense to use restorablePushNamed() or any other restorable push method if you want to preserve the current page and the state of the app when it's killed by the operating system while running in the background (on low memory condition, for example).
It's up to you decide if this is necessary in your app, otherwise, you can just use "normal" push methods without needing to serialize the arguments.
But to use State Restoration, you'll have to convert myObject to a Map or List in order to StandardMessageCodec serialize it, as #Apealed said in the comments.
To convert it to a map. you can do something like this in your class:
Map<String, dynamic> toMap() {
return {
"name": this.name,
"property2": this.property2,
...
};
}
You can check more info about it on documentation: flutter.dev/go/state-restoration-design

Set() is not working in Flutter when I use Flutter Hooks

I wanted to create a checklist for the programming languages I know. I have used Set() to contain the data. But when I use it in the CheckboxListTile() it is not checking the box in the UI. I wanted to do it with using flutter_hooks.
I have created an enum for ProgrammingLanguages.
enum ProgrammingLanguages { C, DART, PYTHON, JAVASCRIPT }
Then I have initialised the set in stateless Widget class like this
final _selectedLanguages = useState<Set>(Set<ProgrammingLanguages>());
In the build I have added a CheckBoxListTile like this.
CheckboxListTile(
title: Text('C'),
value: _selectedLanguages.value.contains(ProgrammingLanguages.C),
onChanged: (value) {
value
? _selectedLanguages.value.remove(ProgrammingLanguages.C)
: _selectedLanguages.value.add(ProgrammingLanguages.C);
}),
But in the final UI I am not able to activate the check box. Please help.

Can I style text in localized Flutter application?

I am using intl package (by using flutter_localizations) and I was wondering how one would go about styling portions of localized text.
Example:
{
"name": "Your name is {name}",
"#name": {
"placeholders": {
"name": {}
}
}
}
Usage:
class MyWidget extends StatelessWidget {
String _name = 'User';
// ... some Flutter widget
Text(AppLocalizations.of(context)!.name(_name),
Expectation:
Your name is User
Is there a recommended approach to solve this? I have found styled_text package but if I could avoid using 3rd party lib, I would prefer it.
I want to avoid splitting text into multiple items as that would not work because different languages might require different ordering and I do not want to deal with that inside widgets by detecting language programmatically.
Text widget has own style property
Text('Your Text' , style: TextStyle())
Also you can read this medium article

Using Platform-Specific packages in Flutter

I'm not sure if this is the appropriate stack exchange site but I think it fits more of here than the others that I can think of. Anyways, I work for a mobile app development team and we're looking into using Flutter to develop our future mobile apps as it reduces the amount of work needed when developing for both iOS and Android (we're just a small team).
I read through a bit about Flutter and checked the available packages and the Dart/Flutter Pub and there are some packages that aren't available yet for Flutter that we use for Android and iOS. Take MSAL (Microsoft Authentication Library) for example. After reading through the documentation, I read about Platform Channels and how you can run some KT/Swift etc specific code and return it through something like the MethodChannel in Kotlin but the example from the Flutter docs show an example of only returning specific data types or simple values. What if I wanted to authenticate a user using MSAL? that would involve some UI work that doesn't happen in Flutter specifically since it relies on either the browser or a webview (depending on your MSAL config)
My question here is probably gonna be in 2 main things:
If you have a package that kind of relies on the UI of either iOS or Android for something that isn't gonna take up the entirety of your app's functions, how would it be possible to still use Flutter to develop the rest of your apps while still making use of the platform-specific packages?
Is it possible to have like more than 1 Activity or ViewController that does this and then go to the Flutter part afterwards? Cuz I think thats one possible solution to the previous question.
Note:
I'm aware that there are packages for authentication in the Dart Pub but I'm just using MSAL as an example, we also use other packages that kind of rely on displaying custom views to authenticate users.
I got this to work using platform channels. To answer my specific questions:
This can still be handled by platform channels. As an example, I am using MSAL with a webview and it still returns to the original FlutterActivity after authenticating my user.
I am not 100% sure about this because I didn't create an Activity myself but the package was able to open its own webview so it should work
MainActivity
private val LOGIN_CHANNEL = "flutter.android/msal"
private val scopes = arrayOf("https://graph.microsoft.com/User.Read", "https://graph.microsoft.com/User.ReadBasic.All")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GeneratedPluginRegistrant.registerWith(this)
MyLibrary.setupClientApp(applicationContext, R.raw.auth_config, scopes)
MethodChannel(flutterView, LOGIN_CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "login") {
login{
result.success(it)
}
}
}
}
private fun login(callback: (String?) -> Unit) {
MyLibrary.instance!!.acquireToken(
this,
scopes,
MyLibrary.getAuthInteractiveCallback {
callback(MyLibrary.getUser()?.displayName)
}
)
}
MyHomePage (State)
class _MyHomePageState extends State<MyHomePage> {
String _responseFromNativeCode = "";
static const platform = const MethodChannel('flutter.android/msal');
Future _login() async {
String response = "";
try {
response = await platform.invokeMethod('login');
} on PlatformException catch (e) {
response = "Failed to Invoke: '${e.message}'.";
}
setState(() {
_responseFromNativeCode = response;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'Hi $_responseFromNativeCode',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _login,
tooltip: 'Login',
child: Icon(Icons.lock),
),
);
}
}

Is there a way to scan barcodes in Flutter?

Basically, I'm making an app that scans a QR code to connect to a server. Then, the app will scan the barcode of products and take pictures of the item and send them to the server. My question is the following :
Is there a Flutter plugin to scan QR codes and barcodes that doesn't enter in conflict with image_picker?
Here's what I found so far.
barcode_scan. Works well until you add a dependency on camera or image_picker. Issue.
BarcodeScannerPlugin
. An issue is open, which have the same problem as the previous plugin.
flutter_qrcode_reader, deprecated. Apparently, it doesn't build.
flutterZebraEmdk is an empty project without a README.md.
flutter_qr_mobile_vision, doesn't support barcodes. Issue.
I appreciate any help you can provide. Thanks!
Update
The issue with barcode_scan was resolved. I ended up using this one since it's faster than the accepted answer and its issues got resolved rather quickly. Be aware that its behaviour on iOS is modified by Apple, so you might get different results with checksum numbers or something.
I've previously had a similar problem, and after searching as you did I didn't find a whole lot. I decided that the best approach would be to write a plugin myself... so shameless plug for my plugin here =D, not that I benefit from anyone else using it at all.
You can see it here. However, I haven't had time to document it, test it all that extensively, or publish it properly on Pub. So your mileage may vary. It should however work on android 4.4+ (and maybe below), and iOS devices that flutter supports. I also haven't tested it in conjunction with the Camera plugin but I don't see why it would have a problem with it.
It takes a different approach than most of the other qr code plugins; instead of making an android or iOS window, doing the scan, then returning to flutter, it uses flutter's texture rendering capabilities to have the camera render directly into flutter.
A few more things to consider are that it uses the Google Mobile Vision SDK with the applicable licensing and capabilities that comes along with that (and requires a recent version of Play Services on Android); and that it currently only supports the most basic extraction of information from barcode scans - I only needed the raw text out so that's all I did.
To use it, add this to your pubspec.yaml:
dependencies:
qr_mobile_vision: '^0.0.7'
And implement as follows:
import 'package:qr_mobile_vision/QrCamera.dart';
...
new Container(
constraints: new BoxConstraints.loose(
new Size(cameraSize, cameraSize)),
child: new QrCamera(
qrCodeCallback: (code) {
print(code);
}
),
)
I do plan on finishing documentation/testing/etc eventually, but you're welcome to try it out in the meantime. If you decide to use it and need a feature it doesn't support I may be able to help implement it... but PRs are welcome and encouraged!
UPDATE: this does include Barcode support now. You can pass in which types of QR code / Barcode you want to support when you instantiate QrCamera. It defaults to all, which takes more processing so if you're after a certain type it's recommended that you pass it in.
I'm working on something currently as a companion to my QR generation plugin (https://github.com/lukef/qr.flutter) but I don't have a specific timeline, unfortunately.
My plan is to use the Texture object and hookup a camera (or fork / use the camera plugin) and then use the Google Vision API (https://developers.google.com/vision/android/barcodes-overview).
It should be decently trivial, I just need to find the time. Either way, that was the plan if you want to do it :)
You can use an open source SDK (e.g., ZXing) or a commercial SDK (e.g., Dynamsoft Barcode Reader SDK) in your Flutter project. Implementing the barcode scanning function is easy.
I have written an article - Flutter Programming with Android AAR File, sharing how to scan QR code in a flutter project. The source code is also available on GitHub.
Java code
private String onGetBarcode(String json) {
String filename;
try {
JSONObject message = new JSONObject(json);
filename = message.getString("filename");
} catch (JSONException e) {
Log.e(TAG, "JSON exception", e);
return null;
}
String locationProvider;
String barcodeResult = "No barcode detected";
File file = new File(filename);
if (!file.exists()) {
barcodeResult = "No file exists: " + file.toString();
Toast.makeText(BarcodeReaderActivity.this, barcodeResult, Toast.LENGTH_LONG).show();
return null;
}
else {
Bitmap bitmap = BitmapFactory.decodeFile(file.toString());
BarcodeReader reader = new BarcodeReader("license");
ReadResult result = reader.readSingle(bitmap, Barcode.QR_CODE);
Barcode[] all = result.barcodes;
if (all != null && all.length == 1) {
barcodeResult = all[0].displayValue;
}
else {
barcodeResult = "no barcode found: " + file.toString();
}
bitmap.recycle();
}
JSONObject reply = new JSONObject();
try {
if (barcodeResult != null) {
reply.put("result", barcodeResult);
} else {
reply.put("result", "No barcode detected");
}
} catch (JSONException e) {
Log.e(TAG, "JSON exception", e);
return null;
}
return reply.toString();
}
Dart code
#override
Widget build(BuildContext context) {
if (_isExisted) {
return new Material(
child: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new Text('Barcode Reader'),
new Input(
labelText: 'Please input the image path',
value: new InputValue(text: _filename),
onChanged: onTextChanged,
autofocus: true,
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new RaisedButton(
child: new Text('Read'),
onPressed: _getBarcode
),
new RaisedButton(
child: new Text('Reset'),
onPressed: _resetResult
),
]
),
new Image.file(new File(_filename)),
new Text('$_result'),
]
)
)
);
}
else {
return new Material(
child: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new Text('Barcode Reader'),
new Input(
labelText: 'Please input the image path',
onChanged: onTextChanged,
autofocus: true,
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new RaisedButton(
child: new Text('Read'),
onPressed: _getBarcode
),
new RaisedButton(
child: new Text('Reset'),
onPressed: _resetResult
),
]
),
new Text('$_result'),
]
)
)
);
}
}
Future<Null> _readBarcode() async {
final Map<String, String> message = <String, String>{'filename':_filename};
final Map<String, dynamic> reply = await HostMessages.sendJSON('getBarcode', message);
// If the widget was removed from the tree while the message was in flight,
// we want to discard the reply rather than calling setState to update our
// non-existent appearance.
if (!mounted)
return;
setState(() {
_result = reply['result'].toString();
});
}
Screenshot
So take a little bit of time and do it yourself :)
I used qr_scan. The issue was I created my flutter with objective c. I had to delete iOS and change it.
To do that delete the ios folder from the project and create it with swift.
To create use is command flutter create -i swift . dont forget the . in the end cause it took me a couple of hours to figure that out
According with my researchs there are good options for that:
flutter_barcode_scanner (reader)
barcode_scan (reader)
qr_flutter (thats is for create QR codes)
1st: barcode_scan will works as a wrapper for two commonly used iOS and Android libraries.
(iOS: https://github.com/mikebuss/MTBBarcodeScanner, Android: https://github.com/dm77/barcodescanner)
They are in version 3 already and seems like the all the major bugs were resolved.
dependencies:
barcode_scan: ^3.0.1
Here the feature list:
[x] Scan 2D barcodes
[x] Scan QR codes
[x] Control the flash while scanning
[x] Permission handling
The main warn is about https://github.com/dm77/barcodescanner that's no longer maintained.
The 2nd option is flutter_barcode_scanner thats also works for both android and ios.
https://pub.dev/packages/flutter_barcode_scanner
For android is just put the pubdev dependency and play, for iOS the only things you need to do is: 1: set minimum deployment target to 11, 2: set Swift version to 5 and 3: ask the permission to use the camera. May the flutter-bardode-scanner is best option since it will depends on just a pubdev dependency without the need of 3rd party project (no longer maintained).
When it's needed to create QR code there is: QR.Flutter also works for ios and android.
Features:
[x] Built on QR - Dart
[x] Automatic QR code version/type detection or manual entry
[x] Supports QR code versions 1 - 40
[x] Error correction / redundancy
[x] Configurable output size, padding, background and foreground colors
[x] Supports image overlays
[x] Export to image data to save to file or use in memory
[x] No internet connection required
Both of them have the best reputation on pub.dev for this propose. So may you need to give a try and check which of them will fill your project needs.
Updating the answer: To read barcode from image gallery there is an alternative package called qr_code_tools. The image could be get from ImagePicker and then decoded to data through QrCodeToolsPlugin.decodeFrom
Getting the image from galley:
ImagePicker.pickImage(source: ImageSource.gallery));
Decoding the image to data:
import 'package:qr_code_tools/qr_code_tools.dart';
String _data;
Future decode(String file) async {
String data = await QrCodeToolsPlugin.decodeFrom(file);
setState(() {
_data = data;
});
}