i18n-abide
Advanced tools
Comparing version 0.0.8 to 0.0.9
@@ -21,3 +21,4 @@ /* This Source Code Form is subject to the terms of the Mozilla Public | ||
path = require('path'), | ||
util = require('util'); | ||
util = require('util'), | ||
plist = require('plist'); | ||
@@ -48,3 +49,3 @@ const DAVID_B_LABYRN = 'db-LB'; | ||
* Other valid options: gettext_alias, debug_lang, disable_locale_check, | ||
* or logger | ||
* translation_type, locale_on_url, or logger | ||
*/ | ||
@@ -62,10 +63,29 @@ exports.abide = function(options) { | ||
// We expect to use PO->json files, unless configured to use plist. | ||
options.translation_type = options.translation_type === 'plist' ? 'plist' : 'json'; | ||
// Only check URL for locale if told to do so. | ||
options.locale_on_url = options.locale_on_url === true; | ||
logger = options.logger; | ||
function json_file_path(locale) { | ||
function messages_file_path(locale) { | ||
var filename = 'messages.' + options.translation_type; | ||
return path.resolve(path.join(__dirname, '..', '..', '..'), | ||
options.translation_directory, | ||
path.join(locale, 'messages.json')); | ||
path.join(locale, filename)); | ||
} | ||
function parse_messages_file(locale) { | ||
var filepath = messages_file_path(locale); | ||
if (options.translation_type === 'plist') { | ||
return plist.parseFileSync(filepath); | ||
} | ||
// PO->json file | ||
else { | ||
var rawMessages = fs.readFileSync(filepath).toString(); | ||
return JSON.parse(rawMessages).messages; | ||
} | ||
} | ||
options.supported_languages.forEach(function(lang) { | ||
@@ -77,4 +97,3 @@ var l = localeFrom(lang); | ||
try { | ||
var rawMessages = fs.readFileSync(json_file_path(l)).toString(); | ||
translations[l] = JSON.parse(rawMessages).messages; | ||
translations[l] = parse_messages_file(l); | ||
} catch (e) { | ||
@@ -86,4 +105,4 @@ // an exception here means that there was a problem with the translation | ||
var msg = util.format( | ||
'Bad locale=[%s] missing .json files in [%s]. See locale/README (%s)', | ||
l, json_file_path(l), e); | ||
'Bad locale=[%s] missing .%s files in [%s]. See locale/README (%s)', | ||
l, options.translation_type, messages_file_path(l), e); | ||
if (!options.disable_locale_check) { | ||
@@ -98,3 +117,36 @@ logger.warn(msg); | ||
function checkUrlLocale(req) { | ||
if (!options.locale_on_url) { | ||
return; | ||
} | ||
// Given a URL, http://foo.com/ab/xyz/, we check to see if the first directory | ||
// is actually a locale we know about, and if so, we strip it out of the URL | ||
// (i.e., URL becomes http://foo.com/xyz/) and store that locale info on the | ||
// request's accept-header. | ||
var matches = req.url.match(/^\/([^\/]+)(\/|$)/); | ||
if (!(matches && matches[1])) { | ||
return; | ||
} | ||
var lang = bestLanguage(parseAcceptLanguage(matches[1]), | ||
options.supported_languages, | ||
options.default_lang); | ||
// If we get back the default lang, we need to be careful about stripping | ||
// the URL, since it might also mean we didn't find one we know about. | ||
// Check for the URL actually containing the default lang and allow, | ||
// otherwise bail, and don't strip URL or override header. | ||
if (lang === options.default_lang && | ||
localeFrom(matches[1]) !== options.default_lang) { | ||
return; | ||
} | ||
req.url = req.url.replace(matches[0], '/'); | ||
req.headers['accept-language'] = lang; | ||
} | ||
return function(req, resp, next) { | ||
checkUrlLocale(req); | ||
var langs = parseAcceptLanguage(req.headers['accept-language']), | ||
@@ -145,3 +197,3 @@ lang_dir, | ||
var newLocals = {} | ||
var newLocals = {}; | ||
@@ -167,5 +219,17 @@ newLocals.locale = assignedLocale; | ||
gt = function(sid) { | ||
if (translations[locale][sid] && translations[locale][sid][1].length) { | ||
sid = translations[locale][sid][1]; | ||
// The plist and PO->json files are in a slightly different format. | ||
if (options.translation_type === 'plist') { | ||
if (translations[locale][sid] && translations[locale][sid].length) { | ||
return translations[locale][sid]; | ||
} else { | ||
// Return the default lang's string if missing in the translation. | ||
return (translations[options.default_lang][sid] || sid); | ||
} | ||
} | ||
// PO->json file | ||
else { | ||
if (translations[locale][sid] && translations[locale][sid][1].length) { | ||
return translations[locale][sid][1]; | ||
} | ||
} | ||
return sid; | ||
@@ -313,1 +377,8 @@ }; | ||
}; | ||
/** | ||
* Returns the list of translations abide is currently configured to support. | ||
*/ | ||
exports.getLocales = function() { | ||
return Object.keys(translations); | ||
}; |
@@ -5,3 +5,3 @@ { | ||
"description": "Express/connect module for Node i18n and l10n support", | ||
"version": "0.0.8", | ||
"version": "0.0.9", | ||
"homepage": "https://github.com/mozilla/i18n-abide", | ||
@@ -23,3 +23,4 @@ "repository": { | ||
"jsxgettext": "0.1.3", | ||
"optimist": "0.3.4" | ||
"optimist": "0.3.4", | ||
"plist": "0.4.3" | ||
}, | ||
@@ -26,0 +27,0 @@ "devDependencies": { |
@@ -83,4 +83,56 @@ # i18n-abide | ||
## Setup Gettext | ||
## Setting Language via HTTP Header and URL | ||
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: | ||
```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 | ||
})); | ||
``` | ||
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. | ||
By default PO/POT files are used. This can be changed during setup: | ||
```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' | ||
})); | ||
``` | ||
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`. | ||
## Working with PO/POT files, and gettext | ||
If using the default of PO/POT files instead of plist, you must transform your strings such that ``i18n-abide`` can work with them. | ||
### Setup Gettext | ||
$ mkdir -p locale/templates/LC_MESSAGES | ||
@@ -87,0 +139,0 @@ $ ./node_modules/.bin/extract-pot --locale locale . |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
1667994
37644
209
40
5
+ Addedplist@0.4.3
+ Addedplist@0.4.3(transitive)
+ Addedxmlbuilder@0.4.3(transitive)
+ Addedxmldom@0.1.31(transitive)