【问题标题】:Flutter parse array from localization JSON fileFlutter 从本地化 JSON 文件解析数组
【发布时间】:2021-01-19 22:26:50
【问题描述】:

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

zh-CN.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&lt;String&gt; _cities = AppLocalization.of(context).translate('cities'); 访问数组

这可行,如果我打印 _cities.toString() 它会打印 [Paris, Lyon, Nice]。

问题

当我尝试使用 json.decode(_cities) 将 _cities 解码为数组时,我总是收到格式错误 Unhandled Exception: FormatException: Unexpected character (at character 2)。

我相信数组在这个函数中被转换为字符串

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

如何将其解析回数组??

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

【问题讨论】:

    标签: arrays json flutter dart


    【解决方案1】:

    我知道这可能不是最好的方法,但这只是我找到的一种方法。您还可以将您的值保存在不同的 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)));
    

    【讨论】:

      【解决方案2】:

      如果您想以数组的形式访问本地化数据,请不要将数组展平为字符串。根据您的用例,将此类数据存储在本地化文件中可能并不合适。

      但是,如果您仍想将列表存储在本地化文件中,那么我建议您不要将解码后的 json 映射展平并返回动态值而不是 translate 中的字符串。当您检索本地化值时,您必须将其类型转换为您期望的类型,因此您可能需要添加一些辅助函数(见下文)来稍微干燥它。

      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");
        }    
      }
      

      【讨论】:

      • 解决方案不起作用,因为 _localizationStrings[key] 的类型是 List 所以我得到一个错误,但为了让它工作我做了以下Map&lt;String, dynamic&gt; _localizationStrings; instead of Map&lt;String, String&gt; _localizationStrings; 在这里我删除了 toString on value _localizationStrings = jsonMap.map((key, value) { return MapEntry(key, value); }); List&lt;dynamic&gt; localizedList(String key) { return _localizationStrings[key] as List&lt;String&gt;; } 在我的小部件中我现在必须将返回的 List 转换为 Listlist = list.cast&lt;String&gt;().toList();
      • 但是我对本地化类中的所有这些变化感到不自在。我的用例是使用列表来填充下拉菜单(两种语言的城市名称),但列表比示例中的要大得多,所以我不想对其进行硬编码。也许有更好的解决方案?
      • 感谢您的帮助,但新答案也不能解决问题,因为我从本地化 JSON 文件中获取了数组字符串。我找到了一个更优雅的解决方案,我会发布它。
      猜你喜欢
      • 2020-06-26
      • 2019-06-03
      • 1970-01-01
      • 1970-01-01
      • 2013-09-07
      • 2021-11-04
      • 2019-06-28
      • 2020-09-30
      • 1970-01-01
      相关资源
      最近更新 更多