Skip to content

Commit

Permalink
feature: xgettext is Depreciated - mkl10n writes the POT-File
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeMitterer committed Aug 25, 2017
1 parent 81a6137 commit 8727b6e
Show file tree
Hide file tree
Showing 29 changed files with 1,029 additions and 734 deletions.
10 changes: 7 additions & 3 deletions README.md
Expand Up @@ -2,10 +2,14 @@ l10n / (gettext-oriented) PO-File Generator
-------------------------------------------
> Helps to localize your application
Before your start:
## Important
Since v1.x xgettext creates `locale/templates/LC_MESSAGES/messages.gettext.pot` for testing purposes only!!!
`mkl10n` doesnt use xgettext anymore - instead the `l10n.parser`-package creates it's own `.pot`-File!

## Before your start:
- [A Quick Gettext Tutorial](http://www.labri.fr/perso/fleury/posts/programming/a-quick-gettext-tutorial.html)

## Windows
### Windows
**Sorry guys** - this is App is tested under Mac-OSX but should work on Linux without problems.

## Install
Expand All @@ -15,7 +19,7 @@ $ pub global activate l10n

## System requirements
Install the following cmdline-Applications:
* xgettext
* xgettext (**Depreciated** since 1.x!)
* msginit
* msgmerge

Expand Down
209 changes: 209 additions & 0 deletions bin/argparser/Config.dart
@@ -0,0 +1,209 @@
part of l10n.app;

/**
* Defines default-configurations.
* Most of these configs can be overwritten by commandline args.
*/
class Config {
final Logger _logger = new Logger("mkl10llocale.Config");

static const String _KEY_LOCALE_DIR = "localeDir";
static const String _KEY_TEMPLATES_DIR = "templatesDir";
static const String _KEY_HEADER_TEMPLATE = "headertemplate";
static const String _KEY_POT_DIR = "potdir";
static const String _KEY_POT_FILENAME = "potfile";
static const String _KEY_PO_FILENAME = "pofile";
static const String _KEY_JSON_FILENAME = "jsonfilename";
static const String _KEY_DART_FILENAME = "dartfilename";
static const String _KEY_LIB_PREFIX = "libprefix";
static const String _KEY_LOGLEVEL = "loglevel";
static const String _KEY_LOCALES = "locales";
static const String _KEY_DART_PATH = "dartpath";
static const String _KEY_SYSTEM_LOCALE = "systemlocale";
static const String _KEY_EXCLUDE_DIRS = "exclude_dirs";

final ArgResults _argResults;
final Map<String,String> _settings = new Map<String,String>();

Config(this._argResults,final String systemLocale) {

_settings[_KEY_LOCALE_DIR] = 'locale';
_settings[_KEY_TEMPLATES_DIR] = 'templates';
_settings[_KEY_HEADER_TEMPLATE] = 'potheader.tpl';
_settings[_KEY_POT_DIR] = 'templates/LC_MESSAGES';

_settings[_KEY_POT_FILENAME] = 'messages.pot';
_settings[_KEY_PO_FILENAME] = 'messages.po';

_settings[_KEY_JSON_FILENAME] = 'messages.json';
_settings[_KEY_DART_FILENAME] = 'messages.dart';

_settings[_KEY_LIB_PREFIX] = 'l10n';
_settings[_KEY_LOGLEVEL] = 'info';


_settings[_KEY_DART_PATH] = 'lib';

_settings[_KEY_LOCALES] = Intl.shortLocale(systemLocale);
_settings[_KEY_SYSTEM_LOCALE] = systemLocale;

_settings[_KEY_EXCLUDE_DIRS] = '';

initializeDateFormatting(_settings[_KEY_SYSTEM_LOCALE],null);

_overwriteSettingsWithConfigFile();
_overwriteSettingsWithArgResults();
}

List<String> get dirstoscan => _argResults.rest;

/// Something like: locale/templates/LC_MESSAGES
String get potdir => "${_settings[_KEY_LOCALE_DIR]}/${_settings[_KEY_POT_DIR]}";

/// Where the pot-header-template is stored
String get templatesdir => "${_settings[_KEY_LOCALE_DIR]}/${_settings[_KEY_TEMPLATES_DIR]}";

/// Filename for Header-Template
String get headerTemplateFile => "$templatesdir/${_settings[_KEY_HEADER_TEMPLATE]}";

/// Something like: locale/templates/LC_MESSAGES/messages.pot
String get potfile => "$potdir/${_settings[_KEY_POT_FILENAME]}";

/// Something like: locale/en/LC_MESSAGES/messages.po
String getPOFile(final String locale) => "${_settings[_KEY_LOCALE_DIR]}/$locale/LC_MESSAGES/${_settings[_KEY_PO_FILENAME]}";

/// Something like: locale/messages.json
String get jsonfile => "${_settings[_KEY_LOCALE_DIR]}/${_settings[_KEY_JSON_FILENAME]}";

/// Something like: locale/messages.dart
String get dartfile => "${_settings[_KEY_DART_PATH]}/${_settings[_KEY_LOCALE_DIR]}/${_settings[_KEY_DART_FILENAME]}";

String get libprefix => _settings[_KEY_LIB_PREFIX];

String get loglevel => _settings[_KEY_LOGLEVEL];

String get locales => _settings[_KEY_LOCALES];

String get systemLocale => _settings[_KEY_SYSTEM_LOCALE];

List<String> get excludeDirs => _settings[_KEY_EXCLUDE_DIRS].split(new RegExp(r",\s*"));

String get configfile => ".mkl10n.yaml";

Map<String,String> get settings {
final Map<String,String> settings = new Map<String,String>();

settings[translate(l10n("Config-File"))] = configfile;

settings["POT-File"] = potfile;
settings["Header-Template"] = headerTemplateFile;
settings["PO-File"] = getPOFile("<locale>");
settings["JSON-File"] = jsonfile;
settings["DART-File"] = dartfile;
settings["libprefix (${Config._KEY_LIB_PREFIX})"] = libprefix;
settings["loglevel"] = loglevel;
settings["locales"] = locales;
settings["System-Locale"] = systemLocale;

if(dirstoscan.length > 0) {
settings[translate(l10n("Dirs to scan"))] = dirstoscan.join(", ");
}
settings[translate(l10n("Dirs to exclude"))
+ " (${Config._KEY_EXCLUDE_DIRS})"] = excludeDirs.join(", ");

return settings;
}

void printSettings(final Map<String,String> settings) {
Validate.notEmpty(settings);

int getMaxKeyLength() {
int length = 0;
settings.keys.forEach((final String key) => length = max(length,key.length));
return length;
}

final int maxKeyLength = getMaxKeyLength();

String prepareKey(final String key) {
return "${key[0].toUpperCase()}${key.substring(1)}:".padRight(maxKeyLength + 1);
}

print(translate(l10n("Settings:")));
settings.forEach((final String key,final String value) {
print(" ${prepareKey(key)} $value");
});

print("");

// You will see this comment in the .po/.pot-File
print(translate(l10n("External commands:")));
[ xgettext, msginit, msgmerge ].forEach((final ShellCommand command) {
String exe = translate(l10n("not installed!"));
try {
exe = command.executable;

} on StateError catch(_) {}

print(" ${(command.name + ':').padRight(maxKeyLength + 1)} ${exe}");
});
}

// -- private -------------------------------------------------------------

_overwriteSettingsWithArgResults() {

/// Makes sure that path does not end with a /
String checkPath(final String arg) {
String path = arg;
if(path.endsWith("/")) {
path = path.replaceFirst(new RegExp("/\$"),"");
}
return path;
}

if(_argResults[Options._ARG_LOGLEVEL] != null) {
_settings[_KEY_LOGLEVEL] = _argResults[Options._ARG_LOGLEVEL];
}

if(_argResults[Options._ARG_LIB_PREFIX] != null) {
_settings[_KEY_LIB_PREFIX] = _argResults[Options._ARG_LIB_PREFIX];
}

if(_argResults[Options._ARG_LOCALE_DIR] != null) {
_settings[_KEY_LOCALE_DIR] = "${checkPath(_argResults[Options._ARG_LOCALE_DIR])}/${_settings[_KEY_LOCALE_DIR]}";
}

if(_argResults[Options._ARG_LOCALES] != null) {
_settings[_KEY_LOCALES] = _argResults[Options._ARG_LOCALES];
}

if(_argResults[Options._ARG_DART_PATH] != null) {
_settings[_KEY_DART_PATH] = checkPath(_argResults[Options._ARG_DART_PATH]);
}

if(_argResults[Options._ARG_DART_PATH] != null) {
_settings[_KEY_DART_PATH] = checkPath(_argResults[Options._ARG_DART_PATH]);
}

if(_argResults[Options._ARG_EXCLUDE] != null) {
_settings[_KEY_EXCLUDE_DIRS] = checkPath(_argResults[Options._ARG_EXCLUDE]);
}
}

void _overwriteSettingsWithConfigFile() {
final File file = new File(configfile);
if(!file.existsSync()) {
return;
}
final yaml.YamlMap map = yaml.loadYaml(file.readAsStringSync());
_settings.keys.forEach((final String key) {
if(map != null && map.containsKey(key)) {
_settings[key] = map[key];
print("Found $key in $configfile: ${map[key]}");
}
});
}


}
55 changes: 55 additions & 0 deletions bin/argparser/Options.dart
@@ -0,0 +1,55 @@
part of l10n.app;

/// Commandline params for this [Application]
class Options {
static const _ARG_LOCALES = 'locales';
static const _ARG_HELP = 'help';
static const _ARG_LOGLEVEL = 'loglevel';
static const _ARG_SETTINGS = 'settings';
static const _ARG_LIB_PREFIX = 'libprefix';
static const _ARG_LOCALE_DIR = 'localedir';
static const _ARG_DART_PATH = 'dartpath';
static const _ARG_EXCLUDE = 'exclude';

final ArgParser _parser;

Options() : _parser = Options._createOptions();

ArgResults parse(final List<String> args) {
Validate.notNull(args);
return _parser.parse(args);
}

void showUsage() {
print(translate(l10n("Usage: mkl10n [options] <dir(s) to scan>")));
_parser.usage.split("\n").forEach((final String line) {
print(" $line");
});

print("");
print(translate(l10n("Example:")));
print(" " + translate(l10n("mkl10n . - Generates lib/locale/messages.dart")));
print(" " + translate(l10n("mkl10n -l en,de . - Generates translation for en + de")));
print("");
}

// -- private -------------------------------------------------------------

static ArgParser _createOptions() {
final ArgParser parser = new ArgParser()

..addFlag(_ARG_HELP, abbr: 'h', negatable: false, help: translate(l10n("Shows this message")))
..addFlag(_ARG_SETTINGS, abbr: 's', negatable: false, help: translate(l10n("Prints settings")))

..addOption(_ARG_LOCALES, abbr: 'l', help: translate(l10n("locales - separated by colon, Sample: --locales en,de,es")))
..addOption(_ARG_LOGLEVEL, abbr: 'v', help: "[ finer | debug | info | warning ]")
..addOption(_ARG_LIB_PREFIX, abbr: 'p', help: translate(l10n("Libprefix for generated DART-File (library <prefix>.locale;)")))
..addOption(_ARG_LOCALE_DIR, abbr: 'd', help: translate(l10n("Defines where to place your locale-Dir")))
..addOption(_ARG_DART_PATH, abbr: 'a', help: translate(l10n("Where should the DART-File go? (<path>/locale/messages.dart)")))
..addOption(_ARG_EXCLUDE, abbr: 'x', help: translate(l10n("Exclude folders from scaning")))
;

return parser;
}

}

0 comments on commit 8727b6e

Please sign in to comment.