BirjuVachhani / spider

A small dart library to generate Assets dart code from assets folder.
https://spider.birju.dev/
Apache License 2.0
190 stars 19 forks source link

Json to translation strings support #71

Open Tkko opened 1 year ago

Tkko commented 1 year ago

Is your feature request related to a problem? Please describe. The ability to generate icon asset paths is fabulous but it would be great to also generate app_string.dart file from json For example:

assets/translations/*

en.json
{
  "appTitle": "Title",
  "continueButton": "Continue"
}
ka.json
{
  "appTitle": "სათაური",
  "back": "უკან"
}

Output:

class Strings {
  const Strings._();

  static const appTitle = 'appTitle';
  static const continueButton = 'continueButton';
  static const back = 'back';

}

This is helpful if you are using json based localizations, checkout the article for reference.

In short, you have translation files, en.json, ka.json, ... and you are accessing the translated string by the key, and with this request keys will be extracted as constants.

Describe the solution you'd like Scan the specific directory assets/translations/ merge all the json keys and export them as a class containing static const instances of retrieved keys.

Describe alternatives you've considered I'm tried adding the feature to flutter_gen package but the author is holding back.

BirjuVachhani commented 1 year ago

@Tkko I don't know much about localization in Flutter but this seems like a job that can be handled better by json_serialization.

So instead of generating a Strings class for json keys and using that for retrieving value, you should generate a data class from the JSON and parse json with it. Store instance of it in your AppLocalizations class.

Your data class

You can generate this using any json to dart generator.

@JsonSerializable()
class AppStrings {
  final String appTitle;
  final String continueButton;
  final String back;

  const AppStrings({
    required this.appTitle,
    required this.continueButton,
    required this.back,
  });

  factory AppStrings.fromJson(Map<String, dynamic> json) => _$AppStringsFromJson(json);

  Map<String, dynamic> toJson() => _$AppStringsToJson(this);
}

Loading from JSON

AppStrings strings;

Future<bool> load() async {
  // Load the language JSON file from the "lang" folder
  String jsonString =
  await rootBundle.loadString('assets/i18n/${locale.languageCode}-${locale.countryCode}-${locale.countryCode}.json');
  Map<String, dynamic> jsonMap = json.decode(jsonString);
  strings = AppStrings.fromJson(jsonMap);
  return true;
}

How to Use

Before

AppLocalizations.of(context).translate('title');

After

AppLocalizations.of(context).strings.appTitle;

This way it achieves what you wanted to achieve with Spider and it is much cleaner too. I hope this is helpful.

Tkko commented 1 year ago

That would work but everytime I add new translation I have to use external package or online tool to convert the Json to data class, wouldn't it be nicer if spider makes all of that?