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

mlingual

v2.0.0

Published

An opinionated build tool for making apps multilingual

Downloads

4

Readme

mlingual

An opinionated build tool for making apps multilingual

npm

mlingual offers a highly opinionated way of making apps multilingual. It rests on the following basic ideas:

  1. There must be only one variant of codebase in VCS. All the multilinguality must appear on the build phase. mlingual is a utility which might be used with any build tool supporting javascript.

  2. Dictionaries should be maintainable separately from the app codebase. As a developer, you only build the structure of a dictionary, then pass it to a professional translator.

  3. Dictionary entries are grouped by there keys. Each key includes all the languages you are to support. This makes maintenance easier.

{
  "title": {
    "en": "Welcome to our website",
    "de": "Willkommen auf unserer Webseite",
    "es": "Bienvenido a nuestro sitio web"
  },
  "helloMessage": {
    "en": "Hello, everybody!",
    "de": "Hallo, alle zusammen!",
    "es": "¡Hola todos!"
  }
}
  1. There should be a way of progressive translation with default language option. In the following example, Spanish translation of the helloMessage key will default to the first language option en:
{
  "title": {
    "en": "Welcome to our website",
    "de": "Willkommen auf unserer Webseite",
    "es": "Bienvenido a nuestro sitio web"
  },
  "helloMessage": {
    "en": "Hello, everybody!",
    "de": "Hallo, alle zusammen!"
  }
}
  1. Dictionaries should be maintained in a friendly folder hierarchy. Like this:
-- dict
   |
   |-- pages
   |   |-- blog
   |   |   |
   |   |   |-- post1.json
   |   |   |-- post2.json
   |   |
   |   |-- header.json
   |   |-- footer.json
   |   
   |
   |-- global.json

Then in you templates, you reference dictionary entries like this:

$$pages.header.helloMessage$$
$$pages.blog.post2.title$$
$$global.userNameLabel$$

Installation

$ npm install --save-dev mlingual

Usage Scenarios

In all examples below, we assume your dictionaries have two languages: en and de, and the structure of your source dictionary folder is as shown above.

Dictionaries

Basic output format

const mlingual = require('mlingual');

await mlingual({
  dict: {
    src: './src/dict',
    dest: './public/dict'
  }
});

This will produce the following output folder structure:

-- public/dict
   |
   |-- pages
   |   |
   |   |-- blog
   |   |   |
   |   |   |-- en
   |   |   |   |
   |   |   |   |-- post1.json
   |   |   |   |-- post2.json
   |   |   |
   |   |   |-- de
   |   |       |
   |   |       |-- post1.json
   |   |       |-- post2.json
   |   |
   |   |--en
   |   |  |
   |   |  |-- header.json
   |   |  |-- footer.json
   |   |
   |   |--de
   |      |
   |      |-- header.json
   |      |-- footer.json
   |   
   |--en
   |  |
   |  |--global.json
   |
   |--de
      |
      |--global.json

Flat output format

const mlingual = require('mlingual');

await mlingual({
  dict: {
    src: './src/dict',
    dest: './public/dict',
    isFlat: true
  }
});

This will produce the following output folder structure:

-- public/dict
   |
   |-- pages.blog.post1.en.json
   |-- pages.blog.post1.de.json
   |-- pages.blog.post2.en.json
   |-- pages.blog.post2.de.json
   |-- pages.header.en.json
   |-- pages.header.de.json
   |-- pages.footer.en.json
   |-- pages.footer.de.json
   |-- global.en.json
   |-- global.de.json

Dictionary Output Summary

const mlingual = require('mlingual');

await mlingual({
  dict: {
    src: './src/dict',
    dest: './public/dict',
    summaryDest: './build/dict-summary'
  }
});

Then a JSON file containing an array of names of all output dictionary files will be put in the ./build/dict-summary folder. The file names contain paths relative to ./public/dict.

This might be useful for cache-busting dictionary files with hashes.

Processing templates

Create templates in any textual format with placeholders which are to be replaced with strings in different languages. E.g.,

<p>$$homepage.header.greeting$$ $$homepage.header.greetingNext$$</p>
<button>$$global.saveBtnLabel$$</button>
<button>$$global.cancelBtnLabel$$</button>

The only restriction is that between any two placeholders must be a space or a line break.

Examples below assume the following structure of the folder with templates:

-- src/html
   |
   |-- pages
   |   |-- blog
   |   |   |
   |   |   |-- post1.html
   |   |   |-- post2.html
   |   |
   |   |-- signup.html
   |
   |-- index.html

Basic output format

const mlingual = require('mlingual');

await mlingual({
  dict: {
    src: './src/dict'
  },
  template: {
    src: './src/html',
    dest: './public/html'
  }
});

This will produce the following output folder structure:

-- public/html
   |
   |-- pages
   |   |-- blog
   |   |   |
   |   |   |-- en
   |   |   |   |
   |   |   |   |-- post1.html
   |   |   |   |-- post2.html
   |   |   |  
   |   |   |-- de
   |   |       |
   |   |       |-- post1.html
   |   |       |-- post2.html
   |   |
   |   |-- en
   |   |   |
   |   |   |-- signup.html
   |   |
   |   |-- de
   |       |
   |       |-- signup.html
   |
   |--en
   |  |
   |  |-- index.html
   |
   |--de
      |
      |-- index.html

Flat output format

const mlingual = require('mlingual');

await mlingual({
  dict: {
    src: './src/dict'
  },
  template: {
    src: './src/html',
    dest: './public/html',
    isFlat: true
  }
});

This will produce the following output folder structure:

-- public/html
   |
   |-- pages.blog.post1.en.html
   |-- pages.blog.post1.de.html
   |-- pages.blog.post2.en.html
   |-- pages.blog.post2.de.html
   |-- pages.signup.en.html
   |-- pages.signup.de.html
   |-- index.en.html
   |-- index.de.html

API Reference

{Function} mlingual(dict, [template])

Returns {Promise<void>}

{Object} dict

Dictionary related options. Required.

Properties:

  • {String} src - Absolute or relative to process.cwd() path to the folder containing dictionaries. Required.

  • {String} dest - Absolute or relative to process.cwd() path to the destination folder for converted dictionaries. Optional. If not provided, converted dictionaries are not saved.

  • {Boolean} isFlat - If true, converted dictionaries are flatly output to the dest folder in the format [subfolder1].[subfolderN].[filename].[langCode].json instead of preserving subfolder structure. Optional. Defaults to false. This prop has no effect if dest prop is not provided.

  • {String} summaryDest - Absolute or relative to process.cwd() path to the folder to save a json-file containing an array of generated dictionaries filenames. Optional. If not provided, the summary file is not created. This prop has no effect if dest prop is not provided.

  • {String} summaryFileName - Name of the summary file without extension. File extension is always .json. Optional. Defaults to dict-summary.

{Object} template

Template related options. Optional. If not provided, templates are not processed.

  • {String} src - Absolute or relative to process.cwd() path to the folder containing source templates to be processed.

  • {String} dest - Absolute or relative to process.cwd() path to the destination folder for processed templates.

  • {String} delimiter - Placeholder delimiter symbol(s) for templates processing. Optional. Defaults to $$.

  • {Boolean} isFlat - If true, output files are saved in the dest folder in relative subfolder in the format [filename].[langCode].[ext] instead of creating additional subfolders for each language code. Optional. Defaults to false.