picklanguage
v1.0.3
Published
Parse accept-language header and pick a preferred language
Downloads
146
Readme
pickLanguage - Parse and Pick Language Header
Quick Start:
const pickLanguage = require('picklanguage');
const {langTag} = pickLanguage(['en', 'fr-CA'], 'zh,de;q=0.8,fr;');
console.log(langTag);
/*
'fr-CA'
*/
Quick Start—as Express Middleware:
const express = require('express');
const pickLanguage = require('picklanguage');
const app = express();
app.use(pickLanguage(['en', 'fr-CA'])); // implemented languages
const HelloMessage = {en: `Hello, my friend!`, frCA: `Bonjour, mon ami!`};
app.get(`/`, (req, res)=>{
res.send(res.translate(HelloMessage)); // 'Hello, ...' or 'Bonjour, ...'
});
app.listen(3000);
Import the package and then app.use
it before any routes that need to use it, telling it which languages have been implemented. It will add the res.translate
function for convenient use in other middleware functions.
If available, pickLanguage
picks up the user's language preference from any of several places before falling back to parsing the accept-language
header.
API
pickLanguage(availableLanguages, options, userLanguagePref)
options
is an options object; see below for available optionsavailableLanguages
is an array of language tags that you have implemented in your app (e.g., 'en', 'en-US', etc.)userLanguagePref
is the user's preferred language and can be a single tag, or formatted as anaccept-language
request header- These three arguments can be passed in any order.
Picking a Language Directly
If passed a string, pickLanguage
will assume it's a language tag or list of languages (formatted like an accept-language
header), and will pick the best of the available languages, returning both the chosen tag and a function that can be used to translate message objects:
const pickLanguage = require('picklanguage');
const {langTag, translate} = pickLanguage(['en', 'es'], 'en-US');
console.log(langTag); // 'en'
console.log(translate(Message)); // English translation
pickLanguage
always returns one of the tags specified as implemented languages. Specifying your implemented languages is mandatory.
The translate(Message)
Function
The translate
function accepts an object, and returns the property on that object matching the user's preferred language. The property name is selected as the chosen language tag, with any hyphens removed. 'en-US'
will map to enUS:
, 'fr'
will map to fr:
, 'ES'
will map to ES:
, etc. Note that although language tags are case insensitive, the object properties used are case sensitive, and pickLanguage
will use typecase as you provided in your implemented-languages array. To illustrate:
const pickLanguage = require('picklanguage')({strict: false});
const { translate } = pickLanguage(['en', 'fr-CA'], `EN-US`);
const GoodMessage = {en: "Hello", frCA: "Bonjour"};
const BrokenMessage = {EN: "Hello", frCA: "Bonjour"};
console.log(
translate(GoodMessage), // 'Hello'
translate(BrokenMessage) // '(no translation)'
);
Two things you can see here:
- The object property chosen for translation matches the tag you passed as an implemented language.
- The type case in the user's preferred language ('EN-US') is ignored, providing correct case-insensitive behavior for language tag interpretation.
By default, translate
will throw an error if it ever attempts to translate a message object that is missing an implemented language, even if not attempting to translate to that language. To disable this, pass {strict: false}
to pickLanguage
. (The BrokenMessage
object in the example above would have thrown an error if pickLanguage
had not been initialized with {strict: false}
.)
Setting {strict: false}
(or setting options in general) can be done in several places:
const pickLanguage = require('picklanguage')({strict: false});
const { translate } = pickLanguage(['en', 'fr-CA']);
or:
const pickLanguage = require('picklanguage');
const { translate } = pickLanguage(['en', 'fr-CA'], {strict: false}));
or: (notice the use of let
in this next one)
let pickLanguage = require('picklanguage');
pickLanguage = pickLanguage({strict: false, fallback: 'fr-CA'});
const { translate } = pickLanguage(['en', 'fr-CA']));
Passing as Express Middleware
If passed to Express using app.use
, pickLanguage
will recognize that it's being used as middleware, and add res.translate
and res.langTag
to the response object. It looks in several places for the user's preferred language, and then parses the 'accept-language' request header if no preference is found.
const express = require('express');
const pickLanguage = require('picklanguage');
const app = express();
app.use(pickLanguage(['en', 'fr-CA'])); // implemented languages
app.get(`/`, (req, res)=>{
const HelloFriend = {
en: `Hello, my friend!`,
frCA: `Bonjour, mon ami!`
};
res.send(res.translate(HelloFriend));
// 'Hello, ...' or 'Bonjour, ...'
console.log(res.langTag)
// 'en' or 'fr-CA'
});
app.listen(3000);
If you store the user's preferred language on the session or in their profile, then use pickLanguage
after your session middleware, and pickLanguage
can pick it up from any of the following, in this order: req.session.user.language
, req.session.user.lang
, req.session.language
, req.session.lang
, req.user.language
, req.user.lang
, req.language
, req.lang
. Otherwise, you can add the user's language preference manually in any of these locations:
app.use((req, res, next)=>{
req.lang = 'en'; // add user's preferred language
next();
});
app.use(pickLanguage(['en', 'fr-CA']));
(If you don't do this, pickLanguage
will still fall back to picking it up from the accept-language header, providing for a very simple basic use case.)
Options
strict
(defaults to true
)
Setting strict: true
will cause pickLanguage
to throw an error you attempt to translate an object that is missing one of the languages you said you would support. Useful for development environments to ensure you have not missed any translations. Set it to false
for more graceful behavior in production. Falsey values won't work— the value must be "strictly" false
.
A sensible value for the strict:
setting in a node project might be:
const options = {
strict: process.env.NODE_ENV === 'development'
}
message
Specifies a string to act as a stand-in for missing messages, when using strict: false
. Any value "${tagName}"
in the string is replaced with the missing language tag:
const options = {
strict: false,
message: 'MISSING: ${tagName}' //this is not a template literal
}
fallback
Specifies a fallback language to be used, when using strict: false
and a translation is missing:
const options = {
strict: false,
fallback: 'en-US'
}
flagMissing
Places [¿«funny characters»?]
when a fallback is used:
const options = {
strict: false,
fallback: 'en',
flagMissing: true
}
silent
Outputs an empty string when a translation is missing. Default behavior is to output '(no translation)'.
const options = {
strict: false,
silent: true
}