Flutter 从本地化 JSON 文件解析数组
Posted
技术标签:
【中文标题】Flutter 从本地化 JSON 文件解析数组【英文标题】:Flutter parse array from localization JSON file 【发布时间】: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<String> _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());
);
如何将其解析回数组??
我愿意接受各种建议。谢谢
【问题讨论】:
【参考方案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] 的类型是 ListMap<String, dynamic> _localizationStrings; instead of Map<String, String> _localizationStrings;
在这里我删除了 toString on value _localizationStrings = jsonMap.map((key, value) return MapEntry(key, value); );
List<dynamic> localizedList(String key) return _localizationStrings[key] as List<String>;
在我的小部件中我现在必须将返回的 Listlist = list.cast<String>().toList();
以上是关于Flutter 从本地化 JSON 文件解析数组的主要内容,如果未能解决你的问题,请参考以下文章