Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read nested json in flutter localization?

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?

like image 662
crabbear Avatar asked Aug 02 '19 09:08

crabbear


1 Answers

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;
}
like image 164
itskajo Avatar answered Nov 08 '22 02:11

itskajo