I am new to flutter.
I apply localization in my flutter project and everything work fine until I edit my json language file to have nested object.
How to call the nested json object correctly?
I try call it by using dot, but it throwing error 'A non-null String must be provided...'
AppLocalizations.of(context).translate('Intro.Header')
Here is my json
{
"Intro": {
"Header": "Introduction",
"Content": "This is...."
},
"Test": "This is test",
}
I have no issue if I call "Test" directly.
AppLocalizations.of(context).translate('Test')
How to read Header and Content?
I know the question is pretty old, but I found it as I had the same problem and was searching for a solution. I was not able to find one on the Internet so I was trying to solve it by myself and as I made it, I want to present here my solution. This solution might not be the most nice one as I am pretty new to Dart/Flutter but at least it works.
As the Owner of the question did not provide his setup I will take the state of this Video as given.
[...]
Map<String, String> _localizeStrings;
[...]
_localizeStrings = jsonMap.map((key, value) {
return MapEntry(key, value.toString());
});
[...]
String translate(String key) {
return _localizeStrings[key];
}
[...]
That is the given state, which is totally setup for a flat json structure. To be able to work with a nested structure our Map _localizeStrings
should be of type Map<String, dynamic>
as the key will always be a String but the value could either be a String or another map. As a next step we need to remove the .toString()
from value
. As a last step we will implement a function which is splitting the given key by '.' and will climb down the map key by key. The last value it gets we will return with .toString()
as this should be the string we want to have.
So here is my solution:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class AppLocalizations {
final Locale locale;
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();
AppLocalizations(this.locale);
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
Map<String, dynamic> _localizeStrings;
Future<bool> load() async {
String jsonString =
await rootBundle.loadString('lang/${locale.languageCode}.json');
Map<String, dynamic> jsonMap = json.decode(jsonString);
_localizeStrings = jsonMap.map((key, value) {
return MapEntry(key, value);
});
return true;
}
String translate(String key) {
var nestedMap = _getNestedValue(key);
return nestedMap.toString();
}
dynamic _getNestedValue(String keyPath) {
Map keyMap = keyPath.split('.').asMap();
var nestedMap;
keyMap.forEach((index, key) {
if (index == 0) {
nestedMap = _localizeStrings[key];
} else
nestedMap = nestedMap[key];
});
return nestedMap;
}
}
class _AppLocalizationsDelegate
extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
@override
bool isSupported(Locale locale) {
return ['en', 'de'].contains(locale.languageCode);
}
@override
Future<AppLocalizations> load(Locale locale) async {
AppLocalizations localizations = new AppLocalizations(locale);
await localizations.load();
return localizations;
}
@override
bool shouldReload(LocalizationsDelegate<AppLocalizations> old) => false;
}
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