human friendly i18n for javascript (node.js + browser)

Overview

BabelFish - human friendly i18n for JS

Build Status NPM version Coverage Status

Internationalisation with easy syntax for node.js and browser.

Classic solutions use multiple phrases for plurals. Babelfish defines plurals inline instead - that's more compact, and easy for programmers. Also, phrases are grouped into nested scopes, like in Ruby.

BabelFish supports all plural rules from unicode CLDR (via plurals-cldr).

Installation

node.js:

$ npm install babelfish

browser:

$ bower install babelfish

Use es5-shim for old browsers compatibility.

Phrases Syntax

  • #{varname} Echoes value of variable
  • ((Singular|Plural1|Plural2)):count Plural form

example:

  • А у меня в кармане #{nails_count} ((гвоздь|гвоздя|гвоздей)):nails_count

You can also omit anchor variable for plurals, by default it will be count. Thus following variants are equal:

  • I have #{count} ((nail|nails))
  • I have #{count} ((nail|nails)):count

Also you can use variables in plural parts:

  • I have ((#{count} nail|#{count} nails))

Need special zero form or overwrite any specific value? No problems:

  • I have ((=0 no nails|#{count} nail|#{count} nails))
Escape chars

If you need #{, ((, | or )) somewhere in text, where it can be considered as markup part - just escape them with \.

Example with YAML

As BabelFish flatten scopes, it's really fun and nice to store translations in YAML files:

---
ru-RU:
  profile: Профиль
  forums: Форумы
  apps:
    forums:
      new_topic: Новая тема
      last_post:
        title : Последнее сообщение
        by : от
  demo:
    apples: "На столе лежит #{count} ((яблоко|яблока|яблок))"

Usage

// Create new instance of BabelFish with default language/locale: 'en-GB'
var BabelFish = require('babelfish');
var i18n = new BabelFish('en-GB');


// Fill in some phrases
i18n.addPhrase('en-GB', 'demo.hello',         'Hello, #{user.name}.');
i18n.addPhrase('en-GB', 'demo.conv.wazup',    'Whats up?');
i18n.addPhrase('en-GB', 'demo.conv.alright',  'Alright, man!');
i18n.addPhrase('en-GB', 'demo.coerce',        'Total: #{count}.');

i18n.addPhrase('ru-RU', 'demo.hello',         'Привет, #{user.name}.');
i18n.addPhrase('ru-RU', 'demo.conv.wazup',    'Как дела?');

i18n.addPhrase('uk-UA', 'demo.hello',         'Здоровенькі були, #{user.name}.');


// Set locale fallback to use the most appropriate translation when possible
i18n.setFallback('uk-UA', 'ru-RU');


// Translate
var params = {user: {name: 'ixti'}};

i18n.t('ru-RU', 'demo.hello', params);  // -> 'Привет, ixti.'
i18n.t('ru-RU', 'demo.conv.wazup');     // -> 'Как дела?'
i18n.t('ru-RU', 'demo.conv.alright');   // -> 'Alright, man!'

i18n.t('uk-UA', 'demo.hello', params);  // -> 'Здоровенькі були, ixti.'
i18n.t('uk-UA', 'demo.conv.wazup');     // -> 'Как дела?'
i18n.t('uk-UA', 'demo.conv.alright');   // -> 'Alright, man!'

// When params is number or strings, it will be coerced to
// `{ count: XXX, value: XXX }` - use any of those in phrase.
i18n.t('en-GB', 'demo.coerce', 5);      // -> 'Total: 5.'


// You may wish to "dump" translations to load in browser later
// Dump will include all fallback translations and fallback rules
var locale_dump = i18n.stringify('ru-RU');

var i18n_new = require('babelfish')('en-GB'); // init without `new` also works
i18n_new.load(locale_dump);


// Use objects instead of strings (object/array/number/boolean) - can be
// useful to prepare bulk data for external libraries.
// Note, only JSON-supported types are ok (no date & regex)
i18n.addPhrase('en-GB', 'demo.boolean',  true);
i18n.addPhrase('en-GB', 'demo.number',   123);
i18n.addPhrase('en-GB', 'demo.array',    [1, 2, 3]);
// fourth param required for hashes (objects) to disable flattening,
// other types are autodetected
i18n.addPhrase('en-GB', 'demo.array',    { foo:1, bar:"2" }, false);

Implementations in other languages

License

View the LICENSE file (MIT).

Comments
  • Support for complex types

    Support for complex types

    Many internationalization engines like Rails i18n support complex value types.

    We need to support something like t('en_US', 'date.abbr_day_names') with:

    date:
      abbr_day_names:
      - Sun
      - Mon
      - Tue
      - Wed
      - Thu
      - Fri
      - Sat
    

    But when we try to compile it using Babelfish errors thrown.

    opened by akzhan 30
  • Support for pluralization-based keys

    Support for pluralization-based keys

    Take a look at this dictionary entries:

    datetime:
      distance_in_words:
        less_than_x_minutes:
          one: "less than a minute"
          other: "less than #{count} minutes"
    

    Rails pluralization backend supports selection of key based on count value.

    In addition to typical one, few, manu and other suffixes it supports optional zero suffix.

    This cannot be repeated by Babelfish syntax because here a case when no value should be printed.

    opened by akzhan 6
  • fix: #7: Zero-count in plurals.

    fix: #7: Zero-count in plurals.

    Fixes #7: Zero-count in plurals.

    Since achor was already checked for being undefined, I see no reason to use String(anchor || '') instead of just String(anchor). Otherwise, it will produce wrong result with values like false, null and, mostly important, 0.

    I also want to discuss changing check from typeof to .hasOwnProperty() since undefined could also be wanted in the translated string (imo, it's also more semantically correct since we are not intrested in variable type or value, but presence):

    // lib/babelfish.js:100
    if ('variable' === node.type) {
      translator.push(
        "str += ( !params.hasOwnProperty('" + node.anchor + "') )" +  // here
        " ? '[missed variable: " + node.anchor + "]'" +
        " : String(" + anchor + ");"
      );
      return;
    }
    
    opened by elmigranto 6
  • Question: Default fallback for country variant

    Question: Default fallback for country variant

    Hello.

    I would like to ask question about using country variants:

    var BabelFish = require('babelfish');
    var i18n = new BabelFish('en-GB');
    i18n.addPhrase('pt', 'test.a', 'Apelido')
    i18n.addPhrase('pt-BR', 'test.a', 'Sobrenome')
    i18n.addPhrase('pt', 'test.b', 'Título')
    > i18n.t('pt', 'test.a')
    'Apelido'
    > i18n.t('pt-BR', 'test.a')
    'Sobrenome'
    > i18n.t('pt-BR', 'test.b')
    'pt-BR: No translation for [test.b]'
    

    Shouldn't last line fallback to 'pt' ? Or i should manually add every possible fallback with .setFallback?

    Thanks.

    opened by btd 4
  • .getTranslation

    .getTranslation

    README.md contains examples which call getTranslation() on BabelFish instance. This is probably an artefact left from some previous version(s) and should be changed to translation() or t() call.

    opened by elmigranto 4
  • `locale` in `.getCompiledData()` should default to fallback locale

    `locale` in `.getCompiledData()` should default to fallback locale

    locale in .getCompiledData() should default to fallback locale, but following adds store['undefined']:

    var BabelFish = require('babelfish');
    var i18n = new BabelFish('ru');
    
    i18n.addPhrase('ru', 'i', 'я');
    
    console.dir(i18n.getCompiledData());
    console.dir(i18n._storage);
    

    Outputs:

    { ru: 
       { i: 
          { type: 'string',
            locale: 'ru',
            translation: 'я' } },
      undefined: 
       { i: 
          { type: 'string',
            locale: 'ru',
            translation: 'я' } } }
    
    opened by elmigranto 3
  • Zero-count in plurals

    Zero-count in plurals

    Following

    var translator = require('babelfish').create('ru');
    translator.addPhrase('ru', 'nailsCount', 'У меня #{n} ((гвоздь|гвоздя|гвоздей)):n');
    [0, 1, 2, 5].forEach(function (count) {
      console.log(translator.t('ru', 'nailsCount', {n: count}));
    });
    

    outputs

    У меня  гвоздей
    У меня 1 гвоздь
    У меня 2 гвоздя
    У меня 5 гвоздей
    

    I also think that ability to define different form for zero-count should be added. ("No items" instead of "0 items".) Same for singular ("One item"). That could be optional last two forms inside (()).

    opened by elmigranto 3
  • angular babelfish

    angular babelfish

    This library worth to be wrap into angular module with directive, service, filter stuff. Is there any wip in that way? Maybe someone from community started to develop such module for its own.

    NB There is already some angular i18n modules but I wasn't able find one which fit me. At least it lacks of normal namespacing and such powerfull stringify method.

    opened by Guria 2
  • Move pluralizer to separate package with autogenerated src

    Move pluralizer to separate package with autogenerated src

    Pluralizer rules can be autogenerated automatically from CLDR data.

    References:

    • CLDR downloads: http://cldr.unicode.org/index/downloads (json.zip -> supplemental -> plurals)
    • Latest chart: http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html
    • Syntax description http://www.unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules

    More to investigate:

    • search by "CLDR" & "LDML"
    • https://www.npmjs.com/packages/make-plural
    • https://www.npmjs.com/package/cldr-data
    opened by puzrin 2
  • Babelfish Perl module

    Babelfish Perl module

    Just note that we plan to release CPAN (open source) Perl module as counterpart for your's one.

    Release date planned to ~11 Jun 2014.

    Also this pair will be disputed on YAPC::Russia 2014 conference (Spb, 13-14 Jun 2014).

    opened by akzhan 2
  • Improve compatibility with old browser & es5-shims

    Improve compatibility with old browser & es5-shims

    https://github.com/nodeca/babelfish/blob/master/lib/babelfish.js#L236

    1. Check, if we really need that property in public?
    2. Can we replace it with getter?
    3. Do we need to add fallback, or use es5-shams?
    opened by puzrin 2
  • syntax extention: formats

    syntax extention: formats

    If one need piped processing for variables to do additional l10n, it's possible to use this notation:

    #{variable:processor|param1|param2|...}

    Examples:

    • #{count:localize_number}
    • #{date:format|short}
    • #{another.translation:phrase} - insert another translation by this key

    The same can be done for selector notation, to change selection rule:

    • ((male|female))[:gender]
    • ((male|female))[:ordinal]

    That's not planned right now, because no real requests exist. Also syntax is subject to discuss.

    Probably, that should not be done at all, because data can be prepared before passing to translate()

    idea 
    opened by puzrin 1
Owner
Nodeca
rcopen.com sources and node.js libraries
Nodeca
ICU MessageFormat for Javascript - i18n Plural and Gender Capable Messages

messageformat The experience and subtlety of your program's text can be important. Messageformat is a mechanism for handling both pluralization and ge

null 1.6k Dec 23, 2022
Gettext Style i18n for Modern JavaScript Apps

Jed Gettext Style i18n for Modern JavaScript Apps For more info

null 879 Dec 14, 2022
Internationalization for react done right. Using the i18next i18n ecosystem.

react-i18next IMPORTANT: Master Branch is the new v10 using hooks. $ v10.0.0 npm i react-i18next react-native: To use hooks within react-native, you m

i18next 7.9k Dec 30, 2022
Extract and merge i18n xliff translation files for angular projects.

Angular extract i18n and merge This extends Angular CLI to improve the i18n extraction and merge workflow. New/removed translations are added/removed

Daniel Schreiber 86 Jan 5, 2023
Merges XLIFF 1.2/2.0 files. Usable for Angular i18n automation.

XLIFF Simple Merge This program automates the merging of XLIFF files (version 1.2 and 2.0). New translations from the input file (e.g. "messages.xlf")

Daniel Schreiber 9 Dec 15, 2022
The alternative internationalization (i18n) library for Angular

NGX Locutus The alternative Angular Translation Library used for large scale microfrontend translations. No more worrying about shared translation ass

Stefan Haas 9 May 31, 2022
Type-safe internationalization (i18n) for Next.js

Type-safe internationalization (i18n) for Next.js Features Usage Examples Scoped translations Change current locale Use JSON files instead of TS for l

Tom Lienard 251 Dec 22, 2022
Give your JavaScript the ability to speak many languages.

Polyglot.js Polyglot.js is a tiny I18n helper library written in JavaScript, made to work both in the browser and in CommonJS environments (Node). It

Airbnb 3.6k Jan 2, 2023
:orange_book: simple approach for javascript localization

ttag ⚠️ This project was previously named c-3po. Some of the talks, presentations, and documentation may reference it with both names. Modern javascri

ttag 307 Jan 2, 2023
lightweight jQuery plugin for providing internationalization to javascript from ‘.properties’ files

jQuery.i18n.properties About jQuery.i18n.properties is a lightweight jQuery plugin for providing internationalization to javascript from ‘.properties’

null 408 Dec 25, 2022
A JavaScript Internationalization Framework

FBT is an internationalization framework for JavaScript designed to be not just powerful and flexible, but also simple and intuitive. It helps with th

Facebook 3.8k Jan 8, 2023
🌍📖 A readable, automated, and optimized (5 kb) internationalization for JavaScript

Linguijs ?? ?? A readable, automated, and optimized (5 kb) internationalization for JavaScript Documentation · Documentation 2.x · Quickstart · Exampl

Lingui 3.5k Jan 2, 2023
i18n-language.js is Simple i18n language with Vanilla Javascript

i18n-language.js i18n-language.js is Simple i18n language with Vanilla Javascript Write by Hyun SHIN Demo Page: http://i18n-language.s3-website.ap-nor

Shin Hyun 21 Jul 12, 2022
Bree is the best job scheduler for Node.js and JavaScript with cron, dates, ms, later, and human-friendly support.

The best job scheduler for Node.js and JavaScript with cron, dates, ms, later, and human-friendly support. Works in Node v10+ and browsers, uses workers to spawn sandboxed processes, and supports async/await, retries, throttling, concurrency, and graceful shutdown. Simple, fast, and lightweight. Made for @ForwardEmail and @ladjs.

Bree - The Best Node.js and JavaScript Job Scheduler 2.5k Dec 30, 2022
🌐 Human-friendly and powerful HTTP request library for Node.js

Sindre's open source work is supported by the community. Special thanks to: Human-friendly and powerful HTTP request library for Node.js Moving from R

Sindre Sorhus 12.5k Jan 9, 2023
Workshop: Crafting Human Friendly CLIs with Node.js Core

$ Crafting Human Friendly CLIs with Node.js Core █ A workshop by Simon Plenderleith & Kevin Cunningham. Getting ready for the workshop 1. Required sof

Simon Plenderleith 13 Dec 26, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
⚡ A powerful, human-friendly database library for JavaScript using SQLite.

great.db ⚡ A powerful, human-friendly database library for JavaScript using SQLite. Elegant way to set and retrieve data Queries are executed through

null 54 Nov 29, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023