npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

picklanguage

v1.0.3

Published

Parse accept-language header and pick a preferred language

Downloads

125

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 options
  • availableLanguages 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 an accept-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:

  1. The object property chosen for translation matches the tag you passed as an implemented language.
  2. 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
}

Front-End Use in React

See NPM: usetranslate for a React hook that uses this package for simple and elegant translation of messages in components.