Reputation: 1247
I want to know how to access to nested data in json.
AppLocalizations.of(context).translate('Information.about');
en.json
{
"Information" : {
"about": "About"
}
}
I tried like the way above but it cannot access to the nested data.
And here is translate method.
class AppLocalizations {
final Locale locale;
AppLocalizations(this.locale);
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
// Static member to get access to the delegate from 'main.dart' file
static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate();
Map<String, String> _localizedValues;
Future<bool> load() async {
// Load a language JSON file from the 'i18n' folder
String value = await rootBundle.loadString('i18n/${locale.languageCode}.json');
Map<String, dynamic> jsonMap = jsonDecode(value);
_localizedValues = jsonMap.map((key, value) {
return MapEntry(key, value.toString());
});
return true;
}
String translate(String key) {
// Returns a localized text
return _localizedValues[key];
}
}
Upvotes: 5
Views: 7133
Reputation: 31
Here is my answer, it looks like @Morez answer but it works for me:
Map<String,dynamic> _localizedValues;
Map<String,dynamic> _localizedValues2;
Future<void> load() async {
String jsonStringValues = await rootBundle.loadString('lib/jsonLanguages/${locale.languageCode}.json');
//print(jsonStringValues);
Map<String,dynamic> mappedJson = json.decode(jsonStringValues);
_localizedValues = mappedJson.map((key, value) => MapEntry(key, value));
}
String translate(String key,String subkey){
String test = _localizedValues[key].toString();
test = test.replaceAllMapped(RegExp(r'(\b\w+( +\w+)*\b)|(\b\w+\b)'), (match) {return '"${match.group(0)}"';});
//print(test);
Map<String,dynamic> mappedJson2 = json.decode(test);
_localizedValues2 = mappedJson2.map((subkey, value) => MapEntry(subkey, value));
return _localizedValues2[subkey];
}
Upvotes: 0
Reputation: 7105
If you are using easy_localization
flutter package for localization you can access object value from JSON like below with dot notation
"Information.about".tr()
Upvotes: 0
Reputation: 321
This is my solution based on https://stackoverflow.com/a/60924513
Map flattenTranslations(Map<String, dynamic> json, [String prefix = '']) {
final Map<String, String> translations = {};
json.forEach((String key, dynamic value) {
if (value is Map) {
translations.addAll(flattenTranslations(value, '$prefix$key.'));
} else {
translations['$prefix$key'] = value.toString();
}
});
return translations;
}
Future<bool> load() async {
String jsonString = await rootBundle.loadString('assets/i18n/${locale.languageCode}.json');
Map<String, dynamic> jsonMap = jsonDecode(jsonString);
_localizedStrings = flattenTranslations(jsonMap);
return true;
}
And this is all app_localizations.dart file
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class AppLocalizations {
final Locale locale;
AppLocalizations(this.locale);
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate();
Map<String, String> _localizedStrings;
Map flattenTranslations(Map<String, dynamic> json, [String prefix = '']) {
final Map<String, String> translations = {};
json.forEach((String key, dynamic value) {
if (value is Map) {
translations.addAll(flattenTranslations(value, '$prefix$key.'));
} else {
translations['$prefix$key'] = value.toString();
}
});
return translations;
}
Future<bool> load() async {
String jsonString = await rootBundle.loadString('assets/i18n/${locale.languageCode}.json');
Map<String, dynamic> jsonMap = jsonDecode(jsonString);
_localizedStrings = flattenTranslations(jsonMap);
return true;
}
String translate(String key) {
return _localizedStrings[key] ?? key;
}
}
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
@override
bool isSupported(Locale locale) {
return ['en', 'pl'].contains(locale.languageCode);
}
@override
Future<AppLocalizations> load(Locale locale) async {
AppLocalizations localizations = new AppLocalizations(locale);
await localizations.load();
return localizations;
}
@override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
Upvotes: 3
Reputation: 99
This will allow you to access nested JSON regardless of depth. Just modify your translate method like so:
String translate(String key) {
List<dynamic> keys = key.split('.');
var value = keys.fold(_localizedValues, (obj, key) => obj[key]);
return value;
}
Then you are able to access your nested JSON in your code like this:
AppLocalizations.of(context).translate('key1.key2.key3');
Just make sure there won't be any periods in your JSON keys
Upvotes: 2
Reputation: 2229
Try this:
First Method:
AppLocalizations.of(context).translate(“about”);
And change your translate function to this:
String translate(String key) {
// Returns a localized text
return _localizedValues[“Information”][key];
}
Or you can do this:
Second Method:
AppLocalizations.of(context).translate(”Information”,“about”);
And change your translate function to this:
String translate(String parentkey, String nestedKey) {
// Returns a localized text
return _localizedValues[parentKey][nestedKey];
}
This might help.
Also, This is a good article to learn how to parse complex json files
UPDATED ANSWER:
After trying the code, I could understand the problem.
The problem is your _localizedValues["Information"] will be a String not a map becuase we converted the value to value.toString() and that's why you cannot use a second key because the returned object is not a Map but it's a String.
So _localizedValues["Information"] is "{about: About}".
To solve the problem, use the code below:
Map<String, dynamic> _localizedValues; //your values are not String anymore and we use dynamic instead
Future<bool> load() async {
// Load a language JSON file from the 'i18n' folder
String value = await rootBundle.loadString('i18n/${locale.languageCode}.json');
Map<String, dynamic> jsonMap = jsonDecode(value);
_localizedValues = jsonMap.map((key, value) {
return MapEntry(key, value); //not value.toString() so the value will be a map
});
return true;
}
String translate(String parentkey, String nestedKey) {
// Returns a localized text
return _localizedValues[parentKey][nestedKey];
}
And then you have to get "About" from the code below:
AppLocalizations.of(context).translate('Information','about');
Upvotes: 2