Permalink
Browse files

feature: Easy translation with mkl10n

  • Loading branch information...
MikeMitterer committed Sep 13, 2018
1 parent 6f639f6 commit 7c6f264dc53270db6bcd84e9748c0e0ff195e141
Showing with 174 additions and 219 deletions.
  1. +2 −1 README.arb.md
  2. +78 −133 README.md
  3. +6 −6 bin/argparser/Config.dart
  4. +1 −1 bin/argparser/Options.dart
  5. +3 −6 bin/mkl10n.dart
  6. +38 −33 l10n/intl_de.arb
  7. +12 −7 l10n/intl_messages.arb
  8. +30 −30 lib/_l10n/messages_de.dart
  9. +4 −2 lib/arb.dart
View
@@ -14,7 +14,8 @@
# Creates .arb-files for Tests
# -a Folder for generated .ARB-Files
# -g Folder for generated .dart-Files
# -i Inore excluded Folders (by default 'test' is excluded!)
# -i Inore excluded Folders (by default 'test' is excluded!)
# -f [optional] Overwrites generated intl_<locale>-File
# test/unit/l10n/ - This folder get's scanned
mkl10n -a test/unit/_resources/l10n -g test/unit/_resources -i test/unit/l10n/
View
211 README.md
@@ -1,171 +1,112 @@
l10n / (gettext-oriented) PO-File Generator
-------------------------------------------
> Translate With GetText PO and POT Files
# l10n
> Easy to use generator for .arb-Files
> Helps if you want to translate your application
## Important
Since v1.x xgettext creates `locale/templates/LC_MESSAGES/messages.gettext.pot` for testing purposes only!!!
## l10n >= v2.x
This is a complete rewrite. **l10n** now fully supports `Intl.message` and .ARB-Files
**`mkl10n` does'nt use xgettext anymore - instead the `l10n.parser`-package creates it's own `.pot`-File!**
## Usage
## Before your start:
- [A Quick Gettext Tutorial](http://www.labri.fr/perso/fleury/posts/programming/a-quick-gettext-tutorial.html)
- First install l10n with `pub global activate l10n`
### Windows
**Sorry guys** - this is App is tested under Mac-OSX but should work on Linux without problems.
Now `mkl10n` should be available on the command-line.
## Supported syntax (.dart + .html)
`.dart`-File:
```dart
// Translator: Comment I
_("String to translate");
l10n("String to translate");
Go to your package you want to translate - say to 'German'
// Translator: Comment II
_("String to translate", "Plural form of String");
l10n("String to translate", "Plural form of String");
// Translator: Comment III
print("Hallo ${_('world')}!");
// Translator: Comment IV
print("Hallo ${translate(_('world'))}!");
template = """
<span translate='yes'>
<!-- Translator: Comment V -->
_("String to translate", "Plural form of String");
l10n("String to translate", "Plural form of String");
</span>
"""
```
The last option has to be used for HTML-"String-Blocks" (`"""` | `'''`)
## Install
```bash
$ pub global activate l10n
mkl10n -l de .
```
## System requirements
Install the following cmdline-Applications:
* xgettext (**Depreciated** since 1.x!)
* msginit
* msgmerge
*Yes - that's it!*
To verify it they are on your system type:
```bash
mkl10n -s
```
If you get an error message - do the following:
```bash
$ brew install gettext
# on Linux: apt-get install gettext
```
Your .arb-Files are in `l10n`. You should see `intl_messages.arb` and `intl_de.arb`
## How to use it
[![Screenshot][1])](https://youtu.be/qj4W-iPKP7s)
(You have to watch it in 1080p - sorry! Better screencast will follow)
*Translate `intl_de.arb`*
- Download the example from `samples/cmdline`
- Run `pub update`
- Run `mkl10n .`
Generates the required .po,.pot files and the lib/locale/messages.dart
- Translate the generated .po-File (`locale/<your localr>/messages.po`)
- Run `mkl10n .` again
Run `dart bin/cmdline.dart -s` - you should see the translated strings
```bash
# Run this command again
mkl10n -l de .
```
Play with `dart bin/cmdline.dart -l de -s` and `dart bin/cmdline.dart -l en -s`
Your generated dart-Files are in `lib/_l10`. You should see `messages_all.dart` and `messages_de.dart`
**This is the most important code-part:**
_cmdline/Config.dart_
Import `messages_all.dart` in your app.
```dart
Map<String,String> get settings {
final Map<String,String> settings = new Map<String,String>();
// Include this if you run your app in the browser
import 'package:intl/intl_browser.dart';
// Everything within l10n(...) will be in your .po File
settings[translate(l10n("loglevel"))] = loglevel;
// Include this if you run your app on the cmdline
import 'package:intl/intl_standalone.dart';
// 'translate' will translate your ID/String
settings[translate(l10n("Config folder"))] = configfolder;
settings[translate(l10n("Config file"))] = configfile;
settings[translate(l10n("Locale"))] = locale;
import 'package:l10n/l10n.dart';
import 'package:<your package>/_l10n/messages_all.dart';
Future main() async {
// Determine your locale
final String locale = await findSystemLocale();
final String shortLocale = Intl.shortLocale(locale);
if(dirstoscan.length > 0) {
settings[translate(l10n("Dirs to scan"))] = dirstoscan.join(", ");
}
// Avoids error message:
// LocaleDataException: Locale data has not been initialized,
// call initializeDateFormatting(<locale>).
await initializeDateFormatting(locale);
return settings;
}
// Initialize translation-table
await initializeMessages(shortLocale);
// Here comes you app-code
// ...
}
```
### How to use it with Material Design 4 Dart
On [GitHub](https://github.com/MikeMitterer/dart-l10n-gettext/tree/master/example) you can find a
cmdline-example and a browser-example.
Check out this sample on GitHub:
- [mdld_translate](https://github.com/MikeMitterer/dart-material-design-lite-site/tree/master/samples/mdld_translate)
This sample also shows the usage with Dice - the dependency injection framework
HTML-Translation: (_index.html_)
```html
<!-- /* Comment added from HTML-File */ -->
<span translate>_('Translate me')</span>
```
[Browser-Example Live-Version](http://l10n4dart.example.mikemitterer.at/)
This is the most simple version of a translated HTML-page I could think of...
## Sub-Translations
Since 0.11.0 Sub-Translations are possible - here is the explanation:
```
locale/de/.../messages.po:
msgid: "Servermessage {{statuscode-400}}."
msgstr: "Fehlerhafte Anfrage"
locale/en/.../messages.po:
msgid: "Servermessage {{statuscode-400}}."
msgstr: ""
```
## More details
As mentioned above `Intl.message` is fully supported. More infos can be found on [pub](https://pub.dartlang.org/packages/intl#messages)
### Hey but there is more!
In my opinion `Intl.message` is to complex for most situations so I also support my own `l10n` syntax.
```dart
final int major = 400;
// This produces a msgid "Servermessage {{status}}." in your PO-File.
// You can translate it as usual
final L10N l = new L10N( "Servermessage {{status}}.", { "status" : "{{statuscode-${major}}}" });
expect(l.message,"Servermessage {{statuscode-400}}.");
// Yup - this prints 'Second test'
// And after you have translated the intl_de.arb to German it print 'Zweiter Test'
print(l10n("Second test"));
```
// No translation for en - so fallback to msgid
expect(translate(l),"Servermessage {{statuscode-400}}.");
Check out the source on [GitHub](https://github.com/MikeMitterer/dart-l10n-gettext/blob/master/example/cmdline/bin/cmdline.dart)
// But what we really want is what I call Sub-Translation
translate.locale = "de";
expect(translate(l),"Fehlerhafte Anfrage");
/*
Internal way of sub-translation:
Replace vars in L10N message -> Servermessage {{statuscode-400}}.
Check if there is a translation - return it, if not, return the msgid
*/
But hey - we also have `HTML-Files`...
Sure!
```html
<main class="cols">
<div>
<div class="translate">_("Hi Mike")</div>
<div class="translate">_("My cat's name is 'Pebbles'")</div>
</div>
</main>
```
That's how it works in HTML. Wrap the string you want to translate with `_(...)`
(You can also wrap it in `l10n(...)`)
<b>Drawback</b><br>
You have to add the msgid "Servermessage {{statuscode-400}}." by hand to your <strong>POT</strong>-File.<br>
The rest is done be the nice merging-feature of l10n/msgmerge
It get's even better - if you have a dart-File with HTML-Included like [so](https://github.com/MikeMitterer/dart-l10n-gettext/blob/master/test/unit/_resources/test-l10n-login.dart#L93-L130):
it's also fully scanned by `mkl10n`
## Flutter
This *should* seamlessly work with Flutter. *Should* because I haven't tested it with Flutter
If it fails please write file an issue report.
## If you have problems
* [Issues][2]
* [Issues](https://github.com/MikeMitterer/dart-l10n-gettext/issues)
## Links
- [GNU gettext utilities](https://www.gnu.org/software/gettext/manual/gettext.html)
- [POEditor](https://poeditor.com/)
### License
Copyright 2017 Michael Mitterer (office@mikemitterer.at),
Copyright 2018 Michael Mitterer (office@mikemitterer.at),
IT-Consulting and Development Limited, Austrian Branch
Licensed under the Apache License, Version 2.0 (the "License");
@@ -181,8 +122,12 @@ The rest is done be the nice merging-feature of l10n/msgmerge
governing permissions and limitations under the License.
If this plugin is helpful for you - please [(Circle)](http://gplus.mikemitterer.at/) me.
### Links
[1]: https://raw.githubusercontent.com/MikeMitterer/dart-l10n-gettext/master/doc/_resources/screenshot.png
[2]: https://github.com/MikeMitterer/dart-l10n-gettext/issues
- [ARB Specs](https://github.com/googlei18n/app-resource-bundle/wiki/ApplicationResourceBundleSpecification)
- [Localize Flutter](https://proandroiddev.com/flutter-localization-step-by-step-30f95d06018d)
- [Application Resource Bundle Specification](https://github.com/googlei18n/app-resource-bundle/wiki/ApplicationResourceBundleSpecification)
- [Gen from ARB](https://github.com/dart-lang/intl_translation/blob/master/bin/generate_from_arb.dart)
- [Extract to ARB](https://github.com/dart-lang/intl_translation/blob/master/bin/extract_to_arb.dart)
View
@@ -16,7 +16,7 @@ class Config {
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_LOCALES_TO_GENERATE = "locales";
// static const String _KEY_DART_PATH = "dartpath";
static const String _KEY_SYSTEM_LOCALE = "systemlocale";
static const String _KEY_EXCLUDE_DIRS = Options._ARG_EXCLUDE;
@@ -51,7 +51,7 @@ class Config {
// _settings[_KEY_DART_PATH] = 'lib';
_settings[_KEY_LOCALES] = Intl.shortLocale(systemLocale);
_settings[_KEY_LOCALES_TO_GENERATE] = Intl.shortLocale(systemLocale);
_settings[_KEY_SYSTEM_LOCALE] = systemLocale;
_settings[_KEY_EXCLUDE_DIRS] = 'test';
@@ -80,7 +80,7 @@ class Config {
String get loglevel => _settings[_KEY_LOGLEVEL];
String get locales => _settings[_KEY_LOCALES];
String get localesToGenerate => _settings[_KEY_LOCALES_TO_GENERATE];
String get systemLocale => _settings[_KEY_SYSTEM_LOCALE];
@@ -113,7 +113,7 @@ class Config {
settings[l10n("libprefix (${Config._KEY_LIB_PREFIX})")] = libprefix;
settings[l10n("loglevel")] = loglevel;
settings[l10n("locales")] = locales;
settings[l10n("locales to generate")] = localesToGenerate;
settings[l10n("System-Locale")] = systemLocale;
settings[l10n("Suppress Warnings")] = suppressWarnings ? l10n('yes') : l10n('no');
settings[l10n("Output dir for .ARB-Files")] = outputDir;
@@ -175,7 +175,7 @@ class Config {
}
if(_argResults[Options._ARG_LOCALES] != null) {
_settings[_KEY_LOCALES] = _argResults[Options._ARG_LOCALES];
_settings[_KEY_LOCALES_TO_GENERATE] = _argResults[Options._ARG_LOCALES];
}
if(_argResults[Options._ARG_EXCLUDE] != null) {
@@ -225,7 +225,7 @@ class Config {
else {
_settings[key] = map[key].toString();
}
print(l10n("Found '[key]' in [file]: [value]",
print(l10n("Found [key] in [file]: [value]",
{"key" : key, "file" : configfile, "value" : map[key] }));
foundSetting = true;
@@ -31,7 +31,7 @@ class Options {
print("");
print(l10n("Example:"));
print(" " + l10n("mkl10n . - Generates lib/locale/messages.dart"));
print(" " + l10n("mkl10n . - Erstellt lib/_l10/messages_*.dart"));
print(" " + l10n("mkl10n -l es,de . - Generates translation for es + de"));
print("");
}
View
@@ -41,7 +41,7 @@ class Application {
try {
final ArgResults argResults = _options.parse(args);
final Config config = new Config(argResults,locale);
_configLogging(config.loglevel);
if (argResults[Options._ARG_HELP]) {
@@ -66,7 +66,7 @@ class Application {
arb.writeMessagesToOutputFile(Directory(config.outputDir), File(config.outputFile), allMessages);
final List<String> locales = config.locales.split(',')
final List<String> locales = config.localesToGenerate.split(',')
.map((final String locale) => locale.trim()).toList();
locales.forEach((final String locale) {
@@ -136,10 +136,7 @@ void main(List<String> arguments) {
await initializeMessages(Intl.shortLocale(locale));
final Application application = new Application();
application.run( arguments, locale );
await application.run( arguments, locale );
});
/// only for testing
// final L10N l1 = const L10N("Ein TEST - 290714 1648");
}
Oops, something went wrong.

0 comments on commit 7c6f264

Please sign in to comment.