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

int17

v0.3.0

Published

Internationalization JavaScript library

Downloads

9

Readme

            __       _    _______  
 __        /\ \__  /' \  /\____  \ 
/\_\    ___\ \ ,_\/\_, \ \/__//' /'
\/\ \ /' _ `\ \ \/\/_/\ \    /' /' 
 \ \ \/\ \/\ \ \ \_  \ \ \  /' /'  
  \ \_\ \_\ \_\ \__\  \ \_\/\_/'   
   \/_/\/_/\/_/\/__/   \/_/\//     

int17 is a pure JavaScript library providing internationalization and localization.

Build Status

It can be used normally in any browser as well as in the node.js environment (especially with Express).

Install

Install from npm:

$ npm install int17

Examples

In the browser:

<html>
  <head>
    <script src="/path/to/int17.js"></script>
    <script>
      (function () {
        var i18n = int17.create();
        i18n.init({ locale: 'en-GB' }, function (err) {
          if (err) throw err;
          i18n.traverse();
        });
      }());
    </script>
  </head>
  <body>
    <h1 int17-args="2013" int17-content="date_header"></h1>
    <div>
      <p int17-values=".style.direction:dir;.innerHTML:main_body"></p>
      <span int17-content="my_label"></span>
      <select int17-options="default_option:-1;option1;option2"></select>
    </div>
  </body>
</html>

In node.js:

var i18n = require('int17').create();
i18n.initSync({ locale: 'en-GB' });

console.log(i18n.get('welcome'));

Both using the same JSON structure, inspired by that used by Google Chrome extensions:

{
  "date_header": {
    "message": "The date is $DATE$!",
    "placeholders": {
      "date": {
        "content": "$1",
        "example": "2012"
      }
    }
  },
  "default_option": {
    "message": "All"
  },
  "main_body": {
    "message": "This is an example of $name$'s greatness!",
    "placeholders": {
      "name": {
        "content": "int17"
      }
    }
  },
  "my_label": {
    "message": "Options example:"
  },
  "option1": {
    "message": "1st option"
  },
  "option2": {
    "message": "2nd option"
  },
  "welcome": {
    "message": "Hello, World!",
    "description": "Simple welcome message"
  }
}

API

Int17

The global int17 variable in the browser or the return value of require('int17') in node.js is an instance of Int17. This is used to expose factory functionality required to get started with globalizing your application.

Instances

create([name])

Returns a new instance of Internationalization. Optionally, if a name is specified, a shared instance can be retrieved/created which is most useful within node.js as it saves passing an object reference between modules.

var i18n1 = int17.create();
var i18n2 = int17.create('i18n');
var i18n3 = int17.create('i18n');
console.log(i18n1 == i18n2); // "false"
console.log(i18n2 == i18n3); // "true"
clearCache()

Removes all internal references to shared instances which are created by create([name]).

var i18n1 = int17.create('i18n');
var i18n2 = int17.create('i18n');
int17.clearCache();
var i18n3 = int17.create('i18n');
var i18n4 = int17.create('i18n');
console.log(i18n1 == i18n2); // "true"
console.log(i18n1 == i18n3); // "false"
console.log(i18n3 == i18n4); // "true"

Miscellaneous

noConflict()

Returns int17 in a no-conflict state, reallocating the int17 global variable name to its previous owner, where possible.

This is really just intended for use within a browser.

<head>
  <script src="/path/to/conflict-lib.js"></script>
  <script src="/path/to/int17.js"></script>
  <script>
    var int17nc = int17.noConflict();
    // Conflicting lib works again and use int17nc for this library onwards...
  </script>
</head>
version

The current version of int17.

console.log(int17.version); // "0.1.0"

Internationalization

An instance of Internationalization is returned by create([name]) and is your new best friend when it comes to all your internationalization needs.

Setup

init([options], [callback(err)])

Initializes the instance with any options provided before asynchronously loading the localalized messages from their resource file/URL.

i18n.init(options, function (err) {
  if (err) throw err;
  // Do anything...
});
initSync([options])

Initializes the instance with any options provided before synchronously (thread-blocking) loading the localized messages from their resource file/URL.

i18n.init(options);
// Do anything...
Options

The following options are recognised by these methods (all of which are optional):

Browser Only

attribute(selector, attr, name, [...])

Sets the value of the specified attribute on all of the selected elements with the message for the specified name. All remaining arguments are used to replace indexed placeholders within the message before it is returned.

i18n.attribute('a', 'title', 'link_title');
i18n.attribute('a.download', 'title', 'open_file');
content(selector, name, [...])

Replaces the contents of all of the selected elements with the message for the specified name. All remaining arguments are used to replace indexed placeholders within the message before it is returned.

i18n.content('h1', 'page_header');
i18n.content('p', 'welcome', 'World');
node

The element whose children are within scope of all browser only methods. By default this references window.document but this can be changed to reduce the scope of internationalization and improve performance of some of these methods.

console.log(i18n.node); // "HTMLDocument"
options(selector, names, [...])

Creates option elements containing the messages for the specified names and appends the to all of the selected elements. All remaining arguments are used to replace indexed placeholders within the message before it is returned.

names can consist of a mix of strings and objects containing a name string and, optionally, an args list as well as a value. When used, the optional args property of a name object overrides any replacement arguments passed to the method when that particular message is processed while the value property is transfered to that option.

i18n.options('select', [
  { name: 'default_option', value: '-1' },
  'option1',
  { name: 'option2' },
  { name: 'option2', args: ['2'] }
], 'Two');
property(selector, prop, name, [...])

Sets the value of the specified property on all of the selected elements with the message for the specified name. All remaining arguments are used to replace indexed placeholders within the message before it is returned.

prop can be identified using paths to change the values of deep properties. If the property is innerHTML, the contents of each element are traversed once being processed to ensure any newly inserted attributes are processed.

i18n.property('p', 'style.direction', 'dir');
i18n.property('p', 'innerHTML', 'welcome', 'World');
traverse([element])

Searches the children of the specified element (defaulting to node) for elements with any of the recognized HTML attributes and then processes each child accordingly.

element can either be an HTML element node or a query selector string which, when used, will be used to query the children of node for the actual element to be traversed.

// Traverses the children of i18n.node
i18n.traverse();
// Both of these do the same thing: traverses the children of <body> element
i18n.traverse(document.body);
i18n.traverse('body');

Locales

languages([parent], [callback(err, languages)])

Retrieves a list of available languages for the current environment. Optionally, this can be filtered to only include languages that extend from a specific parent locale, excluding the parent itself.

The languages are initially fetched asynchronously so a callback function must be provided in order to use the results. However, this does not really happen in the browser where languagesSync([parent]) is called while still supporting the callback pattern.

// Fetch all available languages
i18n.languages(function (err, languages) {
  if (err) throw err;
  doSomething(languages);     // e.g. "en", "en-GB", "en-US", "fr"
});
// Fetch available languages that extend from "en"
i18n.languages('en', function (err, languages) {
  if (err) throw err;
  doSomethingElse(languages); // e.g. "en-GB", "en-US"
});
languagesSync([parent])

Returns a list of available languages for the current environment. Optionally, this can be filtered to only include languages that extend from a specific parent locale, excluding the parent itself.

The languages are initially fetched synchronously (thread-blocking).

// Return all available languages
doSomething(i18n.languagesSync());         // e.g. "en", "en-GB", "en-US", "fr"
// Return available languages that extend from "en"
doSomethingElse(i18n.languagesSync('en')); // e.g. "en-GB", "en-US"
Languages

The list of available languages is populated only with the current locale in the browser but, in node.js, the locale root directory is scanned and detects locales from the children file/folder names.

Alternatively, the languages option can be used to pre-populate the list. This is extremely beneficial in a browser as there's no other way of int17 knowing what languages are available in your configuration.

Regardless, the list is only populated when no languages have previously been fetched (or provided

  • in the previous statement's case) and results are cached to improve the performance of subsequent requests.
locale()

Returns the current locale.

console.log(i18n.locale()); // e.g. "en", "en-GB"

Messages

all(names, [...])

Returns a list of messages for each of the specified names. All remaining arguments are used to replace indexed placeholders within each message before they are returned.

names can consist of a mix of strings and objects containing a name string and, optionally, an args list as well. When used, the optional args property of a name object overrides any replacement arguments passed to the method when that particular message is processed.

doSomething(i18n.all([
  'my_message',
  { name: 'welcome' },
  { name: 'welcome', args: [] },
  { name: 'welcome', args: ['Universe'] }
], 'World'));
// [
//   'Lorem ipsum',
//   'Hello, World!',
//   'Hello, $1!',
//   'Hello, Universe!'
// ]
get(name, [...])

Returns the message for the specified name. All remaining arguments are used to replace indexed placeholders within the message before it is returned.

console.log(i18n.get('welcome'));          // "Hello, $1!"
console.log(i18n.get('welcome', 'World')); // "Hello, World!"
map(names, [...])

Maps each of the specified names to their corresponding message. All remaining arguments are used to replace indexed placeholders within each message before they are returned.

names can consist of a mix of strings and objects containing a name string and, optionally, an args list as well. When used, the optional args property of a name object overrides any replacement arguments passed to the method when that particular message is processed.

doSomething(i18n.map([
  'my_message',
  { name: 'welcome' },
  { name: 'welcome', args: ['Universe'] }
], 'World'));
// {
//   my_message: 'Lorem ipsum',
//   welcome:    'Hello, Universe!'
// }

Miscellaneous

express(app, [namespace])

Extends the app provided to expose the instance to Express. Optionally, a namespace can be specified to customize what property name is used to access the int17 functionality via requests and responses.

See the Express section for more information and examples.

Locale Files

int17 can be configured to use one of two different file structures using options:

Flat

  • locales
    • en.json
    • en_GB.json
    • en_US.json
    • fr_BE.json

Folders

  • locales
    • en
      • messages.json
    • en_GB
      • messages.json
    • en_US
      • messages.json
    • fr_BE
      • messages.json

Regardless of which file structure is used, the contents of each files should be in a JSON format while adhering to the following structure:

{
  "<message_name>": {
    "message": "<message_content>",
    "description": "<optional_description>",
    "placeholders": {
      "<placeholder_name>": {
        "content": "<example_content>",
        "example": "<optional_example>"
      }
    }
  }
}

Attributes

The traverse([element]) method automatically recognizes int17-specific HTML attributes and handles each element they're attached to accordingly.

int17-args

Specifies replacements for indexed placeholders within the messages looked up while processing the other attributes.

The attribute value contains semi-colon separated values.

<p int17-args="World" int17-content="welcome"></p>
int17-content

Replaces the HTML contents of the element with message for the attribute's value.

<h1 int17-content="page_header"></h1>
int17-options

Creates option elements containg the message for each name in the attribute's value.

The attribute value contains semi-colon separated names which can themselves be separated by colons to specify values.

<select int17-options="default_value:-1;option1;option2;option3"></select>
int17-values

Sets the attribute/property values to their corresponding messages as definied in the attribute's value.

The attribute value contains semi-colon separated names which are themselves separated by colons to specify their message names. To identify property paths (useful for changing deep properties) it must begin with a decimal point (.). If the property is .innerHTML, the contents of each element are traversed once being processed to ensure any newly inserted attributes are processed.

<p int17-values=".innerHTML:page_content;.style.direction:dir;title:main_title"></p>

Express

If you love Express as much as I do, you'll be happy to know that you don't have to do any fancy hacking to get it to work well with int17.

Just configure it:

var express = require('express'),
    i18n    = require('int17').create();

// ...

// During app's configuration...
app.configure(function () {
  // ...

  // Binds the int17 instance to requests and responses handled by app
  i18n.express(app);

  // ...
});

That's it! Now you can use it in your view:

app.get('/', function (req, res) {
  res.render('index', {
      header: req.int17.get('page_header'),
      intro:  req.int17.get('welcome_message')
  });
});

And just as easily in your templates:

<% include header %>
<h1><%- int17.get('page_header_prefix') %> <%- header %></h1>
<p><%- intro %></p>
<% include footer %>

Note: This example is using the ejs template engine.

Bugs

If you have any problems with this library or would like to see the changes currently in development you can do so here;

https://github.com/neocotic/int17/issues

Questions?

Take a look at docs/int17.html to get a better understanding of what the code is doing.

If that doesn't help, feel free to follow me on Twitter, @neocotic.

However, if you want more information or examples of using this library please visit the project's homepage;

http://neocotic.com/int17