cah4a / dart_gettext

A Dart implementation of gettext, a localization framework.
https://pub.dartlang.org/packages/gettext
MIT License
11 stars 1 forks source link

Generate .po files for project on flutter. #6

Open bsv99000 opened 2 years ago

bsv99000 commented 2 years ago

Hello. It is not clear how to generate/update .po files automatically. I have a project on flutter with a lot of hardcoded strings. Is there way to extract string to .po files automatically? And how to update them in future?

juanluispaz commented 2 years ago

I'm interesting in this package in the context of a flutter project. But, the whole workflow around it is not documented. Please, can you indicate how to use in the Flutter (the link in the readme is broken) and how to extract the po/pot file from the source code.

jeanbaptistelab commented 2 years ago

Hi @bsv99000 & @juanluispaz

I would recommend looking at the GNU gettext documentation (https://www.gnu.org/software/gettext/manual/gettext.html), it explains in details the entire process, from extracting strings to translate from the source code all the way down to how to retrieve the translation at runtime in applications (but it is quite a mouthful, I'll give you that).

@bsv99000 extracting the strings can unfortunately not be done magically, the xgettext utility that does that needs some hints to know which strings are translatable (for example, it may not make sense to translate a URL). xgettext basically looks in the source code for specific things (in C-like languages, usually a call to the gettext function, for example somthing like gettext("Hello world");). So I guess you need to update your code to mark the strings that need translation.

I banged together a Dart command line program to run the main steps (calling xgettext, msginit, msgmerge...). It basically runs xgettext on your dart source files and generates <langCode_VARIANT>.po files in the assets/locale output directory, those can then be loaded in your app using the gettext_parser companion package to this one.

Assuming you have the Dart code below at the root of your Flutter app in a file called gen_pot.dart, you can run it like this:

jbl@XPC:~/app$ ~/flutter/bin/cache/dart-sdk/bin/dart gen-pot.dart

Output:

xgettext -o locale/template.pot --from-code=UTF-8 --no-location --no-wrap -L C --keyword=gtNoop lib/models.dart lib/actions.dart
msgmerge--backup=off --no-wrap --update assets/locale/en_US.po locale/template.pot
msgmerge--backup=off --no-wrap --update assets/locale/en_GB.po locale/template.pot
msgmerge--backup=off --no-wrap --update assets/locale/da_DK.po locale/template.pot
jbl@XPC:~/app$ 
import 'dart:io';

// The languages for which you provide a translation
const LINGUAS = [
  ['en', 'US'],
  ['en', 'GB'],
  ['da', 'DK']
];

Future main() async {
  var libDir = Directory('lib');
  var localeDir = Directory('locale');
  localeDir.createSync();
  var assetsLocaleDir = Directory('assets/locale');
  assetsLocaleDir.createSync(recursive: true);

  var contents = libDir.listSync(recursive: true);
  contents.retainWhere((entry) {
    return (
      entry.statSync().type == FileSystemEntityType.file &&
      entry.path.endsWith('.dart')
    );
  });
  var fileList = contents.map((e) => e.path).join(" ");
  var xgettextCmd = "-o locale/template.pot --from-code=UTF-8 --no-location --no-wrap -L C --keyword=gtNoop " + fileList;
  print("xgettext " + xgettextCmd);
  Process.runSync("xgettext", xgettextCmd.split(" "));
  for (var locale in LINGUAS.map((e) => "${e[0]}_${e[1]}")) {
    var poFile = File("assets/locale/$locale.po");
    if (await poFile.exists() == false) {
      var msginitCmd = "--input=locale/template.pot --locale=$locale --output=assets/locale/$locale.po";
      print("msginit" + msginitCmd);
      Process.runSync("msginit", msginitCmd.split(" "));
    }
    var msgmergeCmd = "--backup=off --no-wrap --update assets/locale/$locale.po locale/template.pot";
    print("msgmerge" + msgmergeCmd);
    Process.runSync("msgmerge", msgmergeCmd.split(" "));
  }
}
cah4a commented 2 years ago

Yeah, I was using xgettext exactly how @jeanbaptistelab described.