Flutter从本地化JSON文件解析数组

时间:2020-10-05 03:34:00

标签: arrays json flutter dart

我正在尝试将城市名称数组添加到本地化json文件中,但在将其转换为字符串后无法将其解码回数组。

en-US.json

{
  "title" : "My account",
  "name" : "John",
  "cities" : ["Paris", "Lyon", "Nice"]
}

AppLocalization.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> _localizationStrings;

  Future<bool> load() async {
    String jsonString = await rootBundle.loadString(
        'assets/translations/${locale.languageCode}-${locale.countryCode}.json');

    Map<String, dynamic> jsonMap = json.decode(jsonString);

    _localizationStrings = jsonMap.map((key, value) {
      return MapEntry(key, value.toString());
    });
    return true;
  }

  Future<void> setLocale(Locale locale) async {
    final SharedPreferences _prefs = await SharedPreferences.getInstance();
    final _languageCode = locale.languageCode;
    await _prefs.setString('locale', _languageCode);
    print('locale saved!');
  }

  static Future<Locale> getLocale() async {
    final SharedPreferences _prefs = await SharedPreferences.getInstance();
    final String _languageCode = _prefs.getString('locale');
    if (_languageCode == null) return null;

    Locale _locale;
    _languageCode == 'en'
        ? _locale = Locale('en', 'US')
        : _locale = Locale('ar', 'EG');
    return _locale;
  }

  String translate(String key) {
    return _localizationStrings[key];
  }
}

class _AppLocalizationsDelegate
    extends LocalizationsDelegate<AppLocalizations> {
  const _AppLocalizationsDelegate();

  @override
  bool isSupported(Locale locale) {
    return ['en', 'ar'].contains(locale.languageCode);
  }

  @override
  Future<AppLocalizations> load(Locale locale) async {
    AppLocalizations localization = AppLocalizations(locale);
    await localization.load();
    return localization;
  }

  @override
  bool shouldReload(LocalizationsDelegate<AppLocalizations> old) {
    return false;
  }
}

在我的小部件中,我尝试通过List<String> _cities = AppLocalization.of(context).translate('cities');

访问数组

这有效,并且如果我打印_cities.toString(),它将打印[巴黎,里昂,尼斯]。

问题

当我尝试使用json.decode(_cities)将_cities解码为数组时,总是出现格式错误未处理的异常:FormatException:意外的字符(在字符2)。

我相信此函数会将数组转换为String

_localizationStrings = jsonMap.map((key, value) {
  return MapEntry(key, value.toString());
});

如何将其解析回数组?

我愿意接受各种建议。谢谢

2 个答案:

答案 0 :(得分:0)

如果要以数组形式访问本地化数据,请不要将数组展平为字符串。视您的用例而定,将这种数据始终存储在本地化文件中可能不合适。

但是,如果您仍然希望将列表存储在本地化文件中,那么我建议您不要展平解码的json映射并返回动态值,而不是从translate返回String。当您检索本地化的值时,必须将其类型转换为所需的类型,因此您可能需要添加一些辅助函数(请参见下文)以使其稍干。

import 'dart:convert';

var cities = '''
{
  \"cities\" : [\"Paris\", \"Lyon\", \"Nice\"]
}
''';

class Localization {
  final Map<String,dynamic> data;
  
  Localization(this.data);

  String localizedString(String key) {
    return data[key] as String;
  }

  List<String> localizedList(String key) {
    return List<String>.from(data[key]);
  }
}

void main(){
  var data = jsonDecode(cities); //  jsonDecode(cities);
  var l = Localization(data);

  for(var city in l.localizedList("cities")) {
    print("$city");
  }    
}

答案 1 :(得分:0)

我知道这可能不是执行此操作的最佳方法,但这只是我发现的一种方法。您还可以将值保存在其他json资产文件中,并通常使用json.decode()对其进行解析,但我需要使用它来通过本地化更轻松地处理它。

因此我找到了一个简单的解决方案,而不是向本地化类添加功能。

我从本地化文件中以字符串形式从数组中获取数组中的数组(就像其他任何本地化字符串一样):

var list = AppLocalization.of(context).translate('cities');//this will return [Paris, Lyon, Nice] as a string

然后我执行以下操作:

list = list.replaceAll(RegExp("\\[|\\]"), ''); //removes square brackets from the string
var cityList = list.split(','); //splits the city names by the comma as a 
print(cityList); //prints [Paris, Lyon, Nice] as List<String>

我还实现了另一种获取嵌套json数组的方法,如

{
  "title" : "My account",
  "name" : "John",
  "cities" : ["Paris", "Lyon", "Nice"],
  "areas" : 
  {
     "paris" : ["area1", "area2", "area3"], 
     "lyon": ["area1", "area2", "area3"]
  }
}

我这样做是为了获得巴黎地区...

  var areas = AppLocalization.of(context).translate('areas'); //this gets the whole map as a string.
  areas = areas.replaceAll(RegExp("\\[|\\]|\\{|\\}"), '');//this removes leading and trailing {[ ]}
  var splitValues = areas.split(':');
  var mapValues = Map.fromIterable(test, key: (item) => splitValues[0],value: (item) => item.split(','),);

    var parisAreas = mapValues.map((key, value) =>
    MapEntry<String, List<String>>(key, List<String>.from(value)));