i18n-abide
Advanced tools
Comparing version 0.0.9 to 0.0.10
@@ -1,21 +0,30 @@ | ||
# i18n Support | ||
# i18n-abide Usage | ||
Working with a localized version of BrowserID is totally optional for | ||
casual development. | ||
Adding localization to your project, | ||
should not get in the way of your developers from a day to day perspective. | ||
To get started, please [read the l10n locale doc](http://svn.mozilla.org/projects/l10n-misc/trunk/browserid/README). | ||
You will add this module, but if you don't have any localization files, | ||
it is okay and there won't be any errors. | ||
## Development | ||
Any copy, label, or error message that will be shown to users **should** be wrapped in a gettext function. | ||
Any copy, label, or error message that will be shown to users **should** be | ||
wrapped in a gettext function. | ||
These strings must be evaluated in the scope of a request, so we know which locale the user has. | ||
These strings must be evaluated in the scope of a request, | ||
so we know which locale the user has. | ||
In JavaScript or EJS templates use `gettext`. If you need to do string interpolation, use the | ||
[format](../lib/i18n.js) function, which is kind of like node.js' util.format, except crappier. | ||
In JavaScript or EJS templates use `gettext`. | ||
If you need to do string interpolation, use the | ||
[format](../lib/i18n.js) function, | ||
which is kind of like node.js' util.format, except crappier. | ||
Using `_` is more idiomatic, but conflicts with `underscore.js` on the client side JS and EJS files. | ||
Using `_` is more idiomatic, | ||
but conflicts with `underscore.js` on the client side JS and EJS files. | ||
Technically, you can alias gettext to _ and use util.format, etc in node.js code... but for development consistency, | ||
we should keep EJS templates looking similar, regardless of if they are evaluated client or server-side. | ||
Technically, you can alias gettext to _ and use util.format in node.js code... | ||
but for development consistency, | ||
Mozilla codebases should keep EJS templates looking similar, | ||
regardless of if they are evaluated client or server-side. | ||
So we don't use `_` which can be confused with `underscore.js`. | ||
@@ -32,25 +41,11 @@ ## Variables | ||
## Tools | ||
``scripts/every-locale.js`` - will output a list of every locale under the locale directory. This can | ||
be copied into ``config/l10n-all.json``. | ||
``scripts/check-l10n-config.js`` - Run with the ``CONFIG_FILES`` environment variable set to the one json | ||
config file which you'll like to validate. Examples: | ||
CONFIG_FILES=/home/ozten/Projects/browserid/config/l10n-prod.json node ./scripts/check-l10n-config.js | ||
CONFIG_FILES=/home/ozten/Projects/browserid/config/l10n-all.json node ./scripts/check-l10n-config.js | ||
## Contributions | ||
``scripts/check-po.sh`` - Prints statistics on various .po files, assumes `locale` directory. | ||
## Debugging | ||
If code is evaluated in node.js (server-side) then translation is provided from the | ||
`i18n/{locale}/messages.json` file which contains the translation. These JSON files come | ||
from PO files. | ||
If code is evaluated in node.js (server-side) then translation is provided from | ||
the `i18n/{locale}/messages.json` file which contains the translation. | ||
These JSON files come from the `message.po` PO files. | ||
If code is evaluated on the client-side, then `static/gettext.js` is in | ||
the house... strings are `i18n/{locale}/client.json` files. | ||
If code is evaluated on the client-side, then `static/gettext.js` is *in | ||
the house*... | ||
strings are from the `i18n/{locale}/client.js` files. | ||
@@ -60,25 +55,11 @@ If code is evaluated in your head, then clearly we are post-singularity. Why are you | ||
You can change `i18n` in the above to examples by setting the `translation_directory` in your | ||
options to i18n-abide. If you do server side and client side strings, it is recommended that you | ||
put your translation_directory under a web accessible directory like `static`. | ||
You can change `i18n` in the above to examples by setting the | ||
`translation_directory` in your options to i18n-abide. | ||
If you do server side and client side strings, | ||
it is recommended that you put your translation_directory under a web | ||
accessible directory like `static`. | ||
Use the eo locale for development and debugging. It is auto-translated with: | ||
for catalog in messages client; do | ||
echo "Translating ${catalog}.po" | ||
podebug --rewrite=flipped -i locale/templates/LC_MESSAGES/${catalog}.pot -o locale/eo/LC_MESSAGES/${catalog}.po | ||
done | ||
Of course you can integrate gettext.js and client.js via your existing | ||
JavaScript build to compress, minify, etc. | ||
## New Locales | ||
To add a new language, and thus a new locale to BrowserID, do the following: | ||
Assuming you want to add eo for Esperanto support... | ||
mkdir -p locale/eo/LC_MESSAGES | ||
msginit --input=./locale/templates/LC_MESSAGES/messages.pot \ | ||
--output-file=./locale/eo/LC_MESSAGES/messages.po \ | ||
-l eo | ||
msginit --input=./locale/templates/LC_MESSAGES/client.pot \ | ||
--output-file=./locale/eo/LC_MESSAGES/client.po \ | ||
-l eo | ||
See [API.md](API.md) for more advanced uses of `i18n-abide`. |
@@ -61,4 +61,4 @@ /* This Source Code Form is subject to the terms of the Mozilla Public | ||
// We expect to use PO->json files, unless configured to use plist. | ||
options.translation_type = options.translation_type === 'plist' ? 'plist' : 'json'; | ||
// We expect to use PO->json files, unless configured to use another format. | ||
options.translation_type = options.translation_type || 'po'; | ||
// Only check URL for locale if told to do so. | ||
@@ -70,3 +70,5 @@ options.locale_on_url = options.locale_on_url === true; | ||
function messages_file_path(locale) { | ||
var filename = 'messages.' + options.translation_type; | ||
// check if the option is 'key-value-json' if so the file format would be 'json' instead | ||
var file_format = options.translation_type == 'plist' ? 'plist' : 'json' | ||
var filename = 'messages.' + file_format; | ||
return path.resolve(path.join(__dirname, '..', '..', '..'), | ||
@@ -83,2 +85,5 @@ options.translation_directory, | ||
} | ||
else if (options.translation_type === 'key-value-json') { | ||
return require(filepath); | ||
} | ||
// PO->json file | ||
@@ -216,3 +221,3 @@ else { | ||
// The plist and PO->json files are in a slightly different format. | ||
if (options.translation_type === 'plist') { | ||
if (options.translation_type === 'plist' || options.translation_type === 'key-value-json') { | ||
if (translations[locale][sid] && translations[locale][sid].length) { | ||
@@ -219,0 +224,0 @@ return translations[locale][sid]; |
@@ -5,3 +5,3 @@ { | ||
"description": "Express/connect module for Node i18n and l10n support", | ||
"version": "0.0.9", | ||
"version": "0.0.10", | ||
"homepage": "https://github.com/mozilla/i18n-abide", | ||
@@ -8,0 +8,0 @@ "repository": { |
201
README.md
# i18n-abide | ||
This module **abides by the user's language preferences** and makes it | ||
available throughout the app. | ||
This module **abides by the user's language preferences** and makes it available | ||
throughout the app. | ||
@@ -12,22 +12,18 @@ This module **abides by the Mozilla L10n way of doing things**. | ||
This module is under development, but frozen parts of it power the [Mozilla Persona](https://github.com/mozilla/browserid) service in 40+ languages. | ||
Used in production systems, such as the | ||
[Mozilla Persona](https://github.com/mozilla/browserid) service in 40+ | ||
languages. | ||
# Tutorial | ||
Also used on other websites including: | ||
* Mozilla Webmaker | ||
Mozilla Hacks blog has a three part introduction. | ||
# Supported Localization Technologies | ||
* [Localize Your Node.js Service](https://hacks.mozilla.org/2013/04/localize-your-node-js-service-part-1-of-3-a-node-js-holiday-season-part-9/) | ||
* [Localization community, tools & process](https://hacks.mozilla.org/2013/04/localization-community-tools-process-part-2-of-3-a-node-js-holiday-season-part-10/) | ||
* [Localization in Action](https://hacks.mozilla.org/2013/04/localization-in-action-part-3-of-3-a-node-js-holiday-season-part-11/) | ||
This module supports several localization backends: | ||
* Gettext PO files (default and documented below) | ||
* Plist files | ||
* Transflex key-value-JSON files | ||
# Pre-requisites for Developers | ||
This module supports client side as well as server side localization. | ||
`npm install` has got your back | ||
# Pre-requisites for String Wranglers | ||
You should install Gnu gettext to get msginit, xgettext, and other tools. | ||
What is a string wrangler? A person or an automated build process that will merge and delete strings between releases. | ||
# Usage | ||
@@ -37,4 +33,7 @@ | ||
In your app where you setup express or connect: | ||
In this README, we'll use express and EJS templates, but other | ||
integrations are possible. | ||
In your app where you setup express: | ||
var i18n = require('i18n-abide'); | ||
@@ -49,6 +48,7 @@ | ||
This block sets up the middleware and views with gettext support. We declare | ||
support for English, German, Spanish, and two debug locales (more on this later). | ||
This block sets up the middleware and views with gettext support. | ||
We declare support for English, German, Spanish, and two debug locales | ||
In your routes, you can use the gettext function in ``.js`` files. | ||
In your routes, you can use the gettext function in `.js` files. | ||
@@ -59,9 +59,2 @@ exports.homepage = function(req, resp) { | ||
You can set locale in the scope of per-request instead of letting ``i18n-abide`` decide the locale for you. The following example shows how to set the locale of the request to ``zh_TW`` (Traditional Chinese): | ||
exports.homepage = function(req, resp) { | ||
req.setLocale('zh_TW'); | ||
resp.render('home', {title: "my title"}); | ||
}; | ||
In your layout files, you can add | ||
@@ -75,139 +68,81 @@ | ||
In your templates files, you can use the gettext function in ``.ejs`` files: | ||
In your templates files, you can use the gettext function in `.ejs` files: | ||
<p><%= gettext("This will not stand, ya know, this aggression will not stand, man.") %></p> | ||
i18n-abide also provides a ``format`` function for string interpolation. | ||
i18n-abide also provides a `format` function for string interpolation. | ||
These are both server side translations and client side translations. Server side works out of the box | ||
and is the most common use case. | ||
This module provides both server side translations and client side translations. | ||
Server side works out of the box and is the most common use case. | ||
If you also want to do client-side translations, | ||
i18n-abide provides ``lib/gettext.js`` and you can do the same in ``.js`` and ``.ejs`` files. | ||
i18n-abide provides `lib/gettext.js` and you can do the same in `.js` and | ||
`.ejs` files. | ||
## Setting Language via HTTP Header and URL | ||
## Setting Language via HTTP Header | ||
The ``i18n-abide`` module uses the [`accept-language` HTTP header](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4) to determine which language to use. It is also possible to have language tags parsed on the URL with an option at setup: | ||
The `i18n-abide` module uses the | ||
[`accept-language` HTTP header](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4) | ||
to determine which language to use. | ||
```javascript | ||
app.use(i18n.abide({ | ||
supported_languages: ['en-US', 'de', 'es', 'db-LB', 'it-CH'], | ||
default_lang: 'en-US', | ||
debug_lang: 'it-CH', | ||
translation_directory: 'i18n', | ||
locale_on_url: true | ||
})); | ||
``` | ||
See [API docs](./docs/API.md) for overriding this via URL or the API directly. | ||
Here the `locale_on_url` option has been set to `true`, which causes ``i18n-abide`` to perform an extra step with every request: each time a request comes to the server, the URL is examined for an optional language tag. Some examples include: | ||
* http://app.com/ | ||
* http://app.com/en-US/ | ||
* http://app.com/de/ | ||
If a URL includes a language tag for one of the supported languages specified at setup, the request's `accept-language` header is overridden by the URL's language. The URL is then rewritten to no longer include this language tag, such that routes further down in the middleware chain are unaffected. | ||
Given the URLs listed above, the following would happen in the ``i18n-abide`` middleware with `locale_on_url` set to `true`: | ||
* http://app.com/ --> http://app.com/ | ||
* http://app.com/en-US/ --> locale is now `en-US`, url is http://app.com/ | ||
* http://app.com/de --> locale is now `de`, url is http://app.com/ | ||
The `locale_on_url` option is off by default. | ||
## Translation files | ||
The ``i18n-abide`` module can use either PO/POT files, which get transformed to JSON via provided command line tools, or [PLIST](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man5/plist.5.html) (i.e., XML) files, which require no transformation prior to use. | ||
The `i18n-abide` module currently supports three file formats. | ||
By default PO/POT files are used. This can be changed during setup: | ||
1) PO/POT files, which get transformed to JSON via provided command line tools. | ||
```javascript | ||
app.use(i18n.abide({ | ||
supported_languages: ['en-US', 'de', 'es', 'db-LB', 'it-CH'], | ||
default_lang: 'en-US', | ||
debug_lang: 'it-CH', | ||
translation_directory: 'i18n', | ||
translation_type: 'plist' | ||
})); | ||
``` | ||
2) [PLIST](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man5/plist.5.html) (i.e., XML) | ||
files, which require no transformation prior to use. | ||
This will cause ``i18n-abide`` to look for files named `messages.plist` in locale directories beneath your `translation_directory` root. For example, the `es` language listed above should be located at `i18n/es/messages.plist`. | ||
3) [Transflex](http://support.transifex.com/customer/portal/articles/1223004-key-value-json-files) [JSON](https://developer.mozilla.org/en/docs/JSON) | ||
(JavaScript Object Notation) a key-value JSON type, | ||
which require no transformation prior to use. | ||
## Working with PO/POT files, and gettext | ||
### PO/POT files | ||
If using the default of PO/POT files instead of plist, you must transform your strings such that ``i18n-abide`` can work with them. | ||
This is the default and assumed for documentation in this README. | ||
### Setup Gettext | ||
PO files can be compiled to .json or Gettext binary `.mo` files. | ||
$ mkdir -p locale/templates/LC_MESSAGES | ||
$ ./node_modules/.bin/extract-pot --locale locale . | ||
For use on the client side, | ||
PO files are compiled to JavaScript for easy inclusion into your page or build | ||
script. | ||
If you look in ``locale/templates/LC_MESSAGES/messages.pot`` you will see your strings have been extracted. | ||
Edit this file and make sure ``charset`` is set to ``UTF-8``. | ||
NOTE: The PO/POT files are also transformed into .JSON, | ||
but do not follow the same layout as the Transflex JSON files. | ||
If there are certain files or directories you want to exclude, use `--exclude` one or more times. Example: | ||
See [GETTEXT.md](docs/GETTEXT.md) for more details. | ||
$ extract-pot --locale locale . --exclude tests --exclude examples | ||
### Other file formats | ||
Example messages.pot: | ||
See [API](docs/API.md) for configuration and details around using Plist or Transflex localization files. | ||
"Content-Type: text/plain; charset=UTF-8\n" | ||
"Content-Transfer-Encoding: 8bit\n" | ||
#: ./routes.js:81 | ||
msgid "Hey, careful, man, there's a beverage here!" | ||
msgstr "" | ||
# Debugging and Testing | ||
#: views/404.ejs:5 | ||
msgid "This will not stand, ya know, this aggression will not stand, man." | ||
msgstr "" | ||
`db-LB` is a special **debug** locale. | ||
To trigger it, set your Browser or Operating System language to Italian | ||
(Switzerland) which is `it-CH`. | ||
This fake locale `db-LB` will be triggered, | ||
it is David Bowie speak for the region of Labyrinth. | ||
To create ``po`` files in bulk, do: | ||
$ for l in en_US de es db_LB; do | ||
mkdir -p locale/${l}/LC_MESSAGES/ | ||
msginit --input=./locale/templates/LC_MESSAGES/messages.pot \ | ||
--output-file=./locale/${l}/LC_MESSAGES/messages.po \ | ||
-l ${l} | ||
done | ||
If you look at ``locale/en_US/LC_MESSAGES/messages.po``, it will be very similar to your template messages.pot file. | ||
This creates ``.po`` files which you can give to localizers to translate your copy. | ||
Let's put the i18n-abide tools in our path: | ||
$ export PATH=$PATH:node_modules/i18n-abide/bin | ||
And run a string merge: | ||
$ merge_po.sh ./locale | ||
A merge takes strings from our ``.pot`` files and pushes them into our ``.po`` files. If you have ``podebug`` installed, it also automatically translates ``db-LB``. | ||
# Debugging and Testing | ||
``db-LB`` is a special | ||
**debug** locale. To trigger it, set your Browser or Operating System language to Italian (Switzerland) which is ``it-CH``. This fake locale ``db-LB`` will be triggered, it is David Bowie speak for the region of Labyrinth. Oh, hell ya a Dude / Bowie Mashup. | ||
Oh, hell ya a "The Dude" / Bowie Mashup. | ||
That just happened. | ||
Example: ``locale/db_LB/LC_MESSAGES/messages.po`` | ||
Now, | ||
start up your Node server and visit a page you've wrapped strings in Gettext... | ||
"Content-Type: text/plain; charset=UTF-8\n" | ||
"Content-Transfer-Encoding: 8bit\n" | ||
# Tutorial | ||
#: routes.js:81 | ||
msgid "Hey, careful, man, there's a beverage here!" | ||
msgstr "Hǝʎ´ ɔɐɹǝɟnʅ´ ɯɐu´ ʇɥǝɹǝ,s ɐ qǝʌǝɹɐƃǝ ɥǝɹǝ¡" | ||
Mozilla Hacks blog has a three part introduction. | ||
#: views/404.ejs:5 | ||
msgid "This will not stand, ya know, this aggression will not stand, man." | ||
msgstr "⊥ɥıs ʍıʅʅ uoʇ sʇɐup´ ʎɐ ʞuoʍ´ ʇɥıs ɐƃƃɹǝssıou ʍıʅʅ uoʇ sʇɐup´ ɯɐu·" | ||
* [Localize Your Node.js Service](https://hacks.mozilla.org/2013/04/localize-your-node-js-service-part-1-of-3-a-node-js-holiday-season-part-9/) | ||
* [Localization community, tools & process](https://hacks.mozilla.org/2013/04/localization-community-tools-process-part-2-of-3-a-node-js-holiday-season-part-10/) | ||
* [Localization in Action](https://hacks.mozilla.org/2013/04/localization-in-action-part-3-of-3-a-node-js-holiday-season-part-11/) | ||
And we will compile ``.po`` files into ``.mo`` files. | ||
$ compile_mo.sh locale/ | ||
Now, start up your Node server and visit a page you've wrapped strings in Gettext... | ||
See docs/USAGE.md for full details. | ||
# Docs | ||
* See [USAGE](./docs/USAGE.md) for full details. | ||
* [API docs](./docs/API.md) has more advanced config options and APIs | ||
* [GETTEXT](./dcos/GETTEXT.md) documents how to use PO/POT files |
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
1678702
714
37649
143
161