l10n / (gettext-oriented) PO-File Generator

Helps to localize your application

Install

$ pub global activate l10n

System requirements

  • xgettext
  • msginit
  • msgmerge

(only if you want to generate PO/POT files)

To verify it they are on your system type:

    $ type xgettext 

If you get an error message - do the following:

    $ brew install gettext
    # on Linux: apt-get install gettext

Edit ~/.bashrc and add:

    # mkl10nlocale
    export PATH=${PATH}:/usr/local/opt/gettext/bin

To activate your settings:

    $ source ~/.bashrc

How to use it

Screenshot)
(You have to watch it in 1080p - sorry! Better screencast will follow)

Sample code

import 'package:intl/intl.dart';
import 'package:intl/intl_standalone.dart';
import 'package:intl/date_symbol_data_local.dart';

import 'package:l10n/l10n.dart';

// This file will be generated by the framework (l10n)
// Uncomment in Step 3
//import 'package:<your package>/locale/messages.dart';

void main(List<String> arguments) {
    final Application application = new Application();

    findSystemLocale().then((final String locale) {
        // Uncomment in Step 3
        // translate.locale = Intl.shortLocale(locale);

        // Step 1 - sourround your text with l10n(...)
        // Try this: print(l10n("This is a test").message);
        print(l10n("This is a test"));  
               
        // Step 2 - run mkl10nlocale -l de,en example/
        
        // Step 3 - add the import-statement for locale/messages.dart
        // + set the locale
        
        // Step 4 - add 'translate' to your print statement
        print(translate(l10n("This is a test")));  
        
        // Step 5 - Translate the entry in your 
        // PO (for example local/de/messages.po
        
        // Step 6 - run mkl10nlocale -l de,en
        
        // Step 7 - run your program 
    });
}
$ dart mini.dart 
SystemLocale: de_AT
Dies ist ein TEST!

How to use it with AngularDart

  • Write your Filter for Angular
library your.lib;

import 'package:logging/logging.dart';

import "package:angular/angular.dart";
import 'package:angular/core/annotation_src.dart';

import 'package:l10n/l10n.dart';

/// Filter for L10N
@Formatter(name: "translate")
class TranslateFilter implements Function {
    final _logger = new Logger('your.lib.TranslateFilter');

    final L10NTranslate _translator;

    TranslateFilter(this._translator) {
        Validate.notNull(_translator);
    }

    dynamic call(l10n) {
        if (l10n is L10N) {
            return _translator(l10n);
        }
        else {
            return l10n;
        }
    }
}
  • Implement it into your main.dart
library your.main.lib

import 'package:angular/angular.dart';
import 'package:angular/application_factory.dart';
import 'package:l10n/l10n.dart';

//---------------------------------------------------------
// Filter
import 'package:webapp_base_ui/angular/filter/TranslateFilter.dart';

/// Entry point into app.
main() {
    applicationFactory().addModule(new SampleModule()).run();
}

/// only for this sample - usually use the Map from lib/locale/messages.dart
final L10NTranslate _translater = new L10NTranslate.withTranslation( {
    "Could not find Job-ID: {{jobid}}" : "Konnte die JOB-ID {{jobid}} nicht finden..."
});

class SampleModule extends Module {
    SampleModule() {

        // -- filter
        bind(TranslateFilter,toValue: new TranslateFilter(_translater));
    }
}
  • Your HTML-Template (Component in this case) in Angular
<!DOCTYPE html>
<div ng-if="cmp.job != null">
    ID: {{cmp.id}}  {{cmp.job.description}}
</div>
<div ng-if="cmp.job == null">
    {{cmp.lasterror | translate}}
</div>

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: ""
    
    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}}.");

    // No translation for en - so fallback to msgid
    expect(translate(l),"Servermessage {{statuscode-400}}.");

    // 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
    */

Drawback
You have to add the msgid "Servermessage {{statuscode-400}}." by hand to your POT-File.
The rest is done be the nice merging-feature of l10n/msgmerge

If you have problems

History

  • 0.15.12 - toJson converts vars not to "encodable" values
  • 0.11.0 - Sub-Translations are possible, msginit gets initialized with utf-8 per default
  • 0.9.0 - Released on pub

License

Copyright 2016 Michael Mitterer ([email protected]), 
IT-Consulting and Development Limited, Austrian Branch

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, 
software distributed under the License is distributed on an 
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
either express or implied. See the License for the specific language 
governing permissions and limitations under the License.


If this plugin is helpful for you - please (Circle) me.

Libraries

l10n

l10n.locale