Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
yohanboniface committed May 15, 2013
0 parents commit 845b867
Show file tree
Hide file tree
Showing 8 changed files with 275 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/*
21 changes: 21 additions & 0 deletions Leaflet.i18n.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
L.locales = {};
L.locale = null;
L.registerLocale = function registerLocale(code, locale) {
L.locales[code] = L.Util.extend({}, L.locales[code], locale);
};
L.setLocale = function setLocale(code) {
L.locale = code;
};
L.i18n = L._ = function translate(string, data) {
if (L.locale && L.locales[L.locale] && L.locales[L.locale][string]) {
string = L.locales[L.locale][string];
}
try {
// Do not fail if some data is missing
// a bad translation should not break the app
string = L.Util.template(string, data);
}
catch (err) {/*pass*/}

return string;
};
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test:
karma start spec/karma.conf.js
59 changes: 59 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Leaflet.i18n

Internationalisation module for Leaflet plugins.

This module has been extracted from [Leaflet.Storage](https://github.com/yohanboniface/Leaflet.Storage), in case in can be useful for others.

See https://github.com/Leaflet/Leaflet/pull/1232 for a discussion on the history of this.



## API

* to make a string translatable, just call `L._` (shortcut for `L.i18n`), like this:
```
L._("The phrase I want to be translatable");
L._("A complex sentence with a {variable}", {variable: "my value"});
```

* one or more `locale/{locale_code}.js` should be provided, something like:
```
var mylocale = {
"Simple phrase to translate": "Une simple phrase à traduire",
"A sentence with a {variable}": "Une phrase avec une {variable}",
};
```

* the locale must register itself, doing something like:
```
L.registerLocale('fr', mylocale);
```

This can be done more than once. For example, every plugin can add it's translations for some locale without overriding all the already registered strings. However, if the same string for the same locale is registered twice, the last wins.

* end user must load the `locale/` files provided by Leaflet, or plugins

* end user must set his locale, doing so:
```
L.setLocale('fr');
```

## Generating locales files

A util script is provided in this module for extracting strings to translate from Leaflet plugins code and generating the locales files.

Example of use:

```
node bin/i18n.js --dir_path={somepath} --locale_dir_path={somepath} --locale_codes={nl,fr,es}
```

This will generate the locale files for `nl`, `fr` and `es`. Note: if the locale files already exist, they will be updated (and the previous translated strings will be kept).

## Tests

To run the unittests, just do, from the root of the module:

```
make test
```
60 changes: 60 additions & 0 deletions bin/i18n.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env node

var argv = require('optimist')
.usage('node i18n.js --dir_path={somepath} --locale_dir_path={somepath} --locale_codes={nl,fr,es}')
.demand(['dir_path','locale_dir_path', 'locale_codes'])
.argv;
var UglifyJS = require("uglify-js");
var fs = require("fs");
var path = require("path");
var dir_path = argv.dir_path,
locale_dir = argv.locale_dir_path,
locale_codes = argv.locale_codes.split(','),
locales = {},
files = fs.readdirSync(dir_path),
ast = null,
code = "",
strings = [];
files.forEach(function(file){
code += fs.readFileSync(path.join(dir_path, file), "utf8");
});
ast = UglifyJS.parse(code);

ast.walk(new UglifyJS.TreeWalker(function (node) {
if (node instanceof UglifyJS.AST_Call && node.expression.property == "_") {
if (typeof node.args[0].value !== "undefined") {
strings.push(node.args[0].value);
}
}
}));
strings.sort();

L = {
S: {
registerLocale: function (name, strings) {
locales[name] = strings;
}
}
};
locale_codes.forEach(function (locale_code) {
locales[locale_code] = {};
var locale_path = path.join(locale_dir, locale_code + ".js");
if (fs.existsSync(locale_path)) {
// Will call our monkeypatched registerLocale
eval(fs.readFileSync(locale_path, "utf8"));
}
var translations = locales[locale_code],
missing = {},
locale_raw_content = "var " + locale_code + " = ";
strings.forEach(function (str) {
if (!translations[str]) {
translations[str] = "";
missing[str] = "";
}
});
locale_raw_content += JSON.stringify(translations, null, 4);
locale_raw_content += ";\n\n";
locale_raw_content += 'L.registerLocale("' + locale_code + '", '+ locale_code + ');';
process.stdout.write('Writing file for locale "' + locale_code + '"\n');
fs.writeFileSync(locale_path, locale_raw_content, 'utf8');
});
20 changes: 20 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "Leaflet.i18n",
"version": "0.0.1",
"description": "Internationalization for Leaflet plugins",
"devDependencies": {
"Leaflet": "0.6.0",
"mocha": "~1.9.0",
"karma": "~0.8.0",
"uglify-js": "~2.3.2"
},
"main": "./Leaflet.i18n.js",
"scripts": {
"test": "make test"
},
"repository": {
"type": "git",
"url": "git://github.com/yohanboniface/Leaflet.i18n.git"
},
"keywords": ["Leaflet", "map", "i18n"]
}
68 changes: 68 additions & 0 deletions spec/karma.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Karma configuration
// Generated on Wed May 15 2013 11:59:59 GMT+0200 (CEST)

// base path, that will be used to resolve files and exclude
basePath = '.';

var leafletSources = require(__dirname + '/../node_modules/Leaflet/build/build.js').getFiles();
for (var i=0; i < leafletSources.length; i++) {
leafletSources[i] = "../node_modules/Leaflet/" + leafletSources[i];
}

// list of files / patterns to load in the browser
files = [].concat([
"../node_modules/mocha/mocha.js",
"../node_modules/Leaflet/spec/expect.js",
MOCHA_ADAPTER
], leafletSources, ['../Leaflet.i18n.js', 'specs.js']);


// list of files to exclude
exclude = [

];


// test results reporter to use
// possible values: 'dots', 'progress', 'junit'
reporters = ['dots'];


// web server port
port = 9876;


// cli runner port
runnerPort = 9100;


// enable / disable colors in the output (reporters and logs)
colors = true;


// level of logging
// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
logLevel = LOG_INFO;


// enable / disable watching file and executing tests whenever any file changes
autoWatch = false;

// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers = ['PhantomJS'];


// If browser does not capture in given timeout [ms], kill it
captureTimeout = 60000;


// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun = true;
44 changes: 44 additions & 0 deletions spec/specs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
describe('L.i18n', function(){
beforeEach(function(){
var fr = {
"Simple phrase to translate": "Une simple phrase à traduire",
"A phrase with a {variable} to translate": "Une phrase à traduire avec une {variable}"
};
L.registerLocale('fr', fr);
L.setLocale('fr');
});

it('expects L.i18n to be defined', function (){
expect(L.i18n).to.be.ok();
});

it('expects L._ to be defined', function (){
expect(L._).to.be.ok();
});

it('expects current locale to be fr', function (){
expect(L.locale).to.eql('fr');
});

it("should translate simple sentences", function() {
expect(L._("Simple phrase to translate")).to.eql("Une simple phrase à traduire");
});

it("should translate sentences with a variable", function() {
expect(L._("A phrase with a {variable} to translate", {variable: "foo"})).to.eql("Une phrase à traduire avec une foo");
});

it("should not fail if a variable is missing", function() {
expect(L._("A phrase with a {variable} to translate")).to.eql("Une phrase à traduire avec une {variable}");
});

it("should not fail if the translation is missing", function() {
expect(L._("A missing translation")).to.eql("A missing translation");
});

it("should not fail if the locale is missing", function() {
L.setLocale('foo');
expect(L._("Simple phrase to translate")).to.eql("Simple phrase to translate");
});

});

0 comments on commit 845b867

Please sign in to comment.