Coder Social home page Coder Social logo

globalizejs / globalize Goto Github PK

View Code? Open in Web Editor NEW
4.8K 134.0 604.0 6.59 MB

A JavaScript library for internationalization and localization that leverages the official Unicode CLDR JSON data

Home Page: https://globalizejs.com

License: MIT License

HTML 0.23% JavaScript 99.08% Shell 0.68%
cldr cldr-data cldr-json i18n intl l10n formatter parser

globalize's Introduction

Globalize

Build Status devDependency Status devDependency Status

A JavaScript library for internationalization and localization that leverage the official Unicode CLDR JSON data. The library works both for the browser and as a Node.js module.

About Globalize

Why globalization?

Each language, and the countries that speak that language, have different expectations when it comes to how numbers (including currency and percentages) and dates should appear. Obviously, each language has different names for the days of the week and the months of the year. But they also have different expectations for the structure of dates, such as what order the day, month and year are in. In number formatting, not only does the character used to delineate number groupings and the decimal portion differ, but the placement of those characters differ as well.

A user using an application should be able to read and write dates and numbers in the format they are accustomed to. This library makes this possible, providing an API to convert user-entered number and date strings - in their own format - into actual numbers and dates, and conversely, to format numbers and dates into that string format.

Even if the application deals only with the English locale, it may still need globalization to format programming language bytes into human-understandable language and vice-versa in an effective and reasonable way. For example, to display something better than "Edited 1 minutes ago".

Why Globalize?

Globalize provides number formatting and parsing, date and time formatting and parsing, currency formatting, message formatting (ICU message format pattern), and plural support.

Design Goals.

  • Leverages the Unicode CLDR data and follows its UTS#35 specification.
  • Keeps code separate from i18n content. Doesn't host or embed any locale data in the library. Empowers developers to control the loading mechanism of their choice.
  • Allows developers to load as much or as little data as they need. Avoids duplicating data if using multiple i18n libraries that leverage CLDR.
  • Keeps code modular. Allows developers to load the i18n functionalities they need.
  • Runs in browsers and Node.js, consistently across all of them.
  • Makes globalization as easy to use as jQuery.

Globalize is based on the Unicode Consortium's Common Locale Data Repository (CLDR), the largest and most extensive standard repository of locale data available. CLDR is constantly updated and is used by many large applications and operating systems, so you'll always have access to the most accurate and up-to-date locale data.

Globalize needs CLDR content to function properly, although it doesn't embed, hard-code, or host such content. Instead, Globalize empowers developers to load CLDR data the way they want. Vanilla CLDR in its official JSON format (no pre-processing) is expected to be provided. As a consequence, (a) Globalize avoids bugs caused by outdated i18n content. Developers can use up-to-date CLDR data directly from Unicode as soon as it's released, without having to wait for any pipeline on our side. (b) Developers have full control over which locale coverage they want to provide on their applications. (c) Developers are able to share the same i18n dataset between Globalize and other libraries that leverage CLDR. There's no need for duplicating data.

Globalize is systematically tested against desktop and mobile browsers and Node.js. So, using it you'll get consistent results across different browsers and across browsers and the server.

Globalize doesn't use native Ecma-402 yet, which could potentially improve date and number formatting performance. Although Ecma-402 support is improving among modern browsers and even Node.js, the functionality and locale coverage level varies between different environments (see Comparing JavaScript Libraries slide 25). Globalize needs to do more research and testings to use it reliably.

For alternative libraries and more, check out this JavaScript globalization overview.

Migrating from Globalize 0.x

Are you coming from Globalize 0.x? Read our migration guide to learn what have changed and how to migrate older 0.x code to up-to-date 1.x.

Where to use it?

Globalize is designed to work both in the browser, or in Node.js. It supports both AMD and CommonJS.

Where does the data come from?

Globalize uses the Unicode CLDR, the largest and most extensive standard repository of locale data.

We do NOT embed any i18n data within our library. However, we make it really easy to use. Read How to get and load CLDR JSON data for more information on its usage.

Pick the modules you need

File Minified + gzipped size Runtime minified + gzipped size Summary
globalize.js 1.7KB 1.1KB Core library
globalize/currency.js 3.0KB 0.7KB Currency module provides currency formatting
globalize/date.js 7.7KB 4.3KB Date module provides date formatting and parsing
globalize/message.js 5.3KB 0.7KB Message module provides ICU message format support
globalize/number.js 4.4KB 2.6KB Number module provides number formatting and parsing
globalize/plural.js 2.3KB 0.4KB Plural module provides pluralization support
globalize/relative-time.js 0.8KB 0.5KB Relative time module provides relative time formatting support
globalize/unit.js 0.9KB 0.6KB Unit module provides unit formatting support

Browser Support

Globalize 1.x supports the following browsers:

  • Chrome: (Current - 1) or Current
  • Firefox: (Current - 1) or Current
  • Safari: 5.1+
  • Opera: 12.1x, (Current - 1) or Current
  • IE9+

(Current - 1) or Current denotes that we support the current stable version of the browser and the version that preceded it. For example, if the current version of a browser is 24.x, we support the 24.x and 23.x versions.

Getting Started

npm install globalize cldr-data iana-tz-data
var Globalize = require( "globalize" );
Globalize.load( require( "cldr-data" ).entireSupplemental() );
Globalize.load( require( "cldr-data" ).entireMainFor( "en", "es" ) );
Globalize.loadTimeZone( require( "iana-tz-data" ) );

Globalize("en").formatDate(new Date());
// > "11/27/2015"

Globalize("es").formatDate(new Date());
// > "27/11/2015"

Note cldr-data is an optional module, read CLDR content section below for more information on how to get CLDR from different sources.

The iana-tz-data module is only needed when IANA time zones (via options.timeZone) are used with date functions. Read IANA time zone data below for more information.

Read the Locales section for more information about supported locales. For AMD, bower and other usage examples, see Examples section.

Installation

Downloading a ZIP or tarball archive

Click the GitHub releases tab and download the latest available Globalize package.

Using a package manager

You can use either npm or bower:

  • npm install globalize
  • bower install globalize

Building from source

  1. git clone https://github.com/globalizejs/globalize.git
  2. Build the distribution files

Requirements

1. Dependencies

If you use module loading like ES6 import, CommonJS, or AMD and fetch your code using package managers like npm or bower, you don't need to worry about this and can skip reading this section. Otherwise, you need to satisfy Globalize dependencies prior to using it. There is only one external dependency: cldr.js, which is a CLDR low level manipulation tool. Additionally, you need to satisfy the cross-dependencies between modules.

Module Dependencies (load in order)
Core module cldr.js
Currency module globalize.js (core), globalize/number.js, and globalize/plural.js (only required for "code" or "name" styles)
Date module globalize.js (core) and globalize/number.js
Message module globalize.js (core) and globalize/plural.js (if using messages that need pluralization support)
Number module globalize.js (core)
Plural globalize.js (core)
Relative time module globalize.js (core), globalize/number.js, and globalize/plural.js
Unit module globalize.js (core), globalize/number.js, and globalize/plural.js

As an alternative to deducing this yourself, use this online tool. The tool allows you to select the modules you're interested in using and tells you the Globalize files and CLDR JSON that you need.

2. CLDR content

Globalize is the i18n software (the engine). Unicode CLDR is the i18n content (the fuel). You need to feed Globalize on the appropriate portions of CLDR prior to using it.

(a) How do I figure out which CLDR portions are appropriate for my needs?

Each Globalize function requires a special set of CLDR portions. Once you know which Globalize functionalities you need, you can deduce its respective CLDR requirements. See table below.

Module Required CLDR JSON files
Core module cldr/supplemental/likelySubtags.json
Currency module cldr/main/locale/currencies.json
cldr/supplemental/currencyData.json
+CLDR JSON files from number module
+CLDR JSON files from plural module for name style support
Date module cldr/main/locale/ca-gregorian.json
cldr/main/locale/timeZoneNames.json
cldr/supplemental/metaZones.json
cldr/supplemental/timeData.json
cldr/supplemental/weekData.json
+CLDR JSON files from number module
Number module cldr/main/locale/numbers.json
cldr/supplemental/numberingSystems.json
Plural module cldr/supplemental/plurals.json (for cardinals)
cldr/supplemental/ordinals.json (for ordinals)
Relative time module cldr/main/locale/dateFields.json
+CLDR JSON files from number and plural modules
Unit module cldr/main/locale/units.json
+CLDR JSON files from number and plural module

As an alternative to deducing this yourself, use this online tool. The tool allows you to select the modules you're interested in using and tells you the Globalize files and CLDR JSON that you need.

(b) How am I supposed to get and load CLDR content?

Learn how to get and load CLDR content... and use Globalize.load() to load it.

3. IANA time zone data

The IANA time zone (tz) database, sometimes called the Olson database, is the standard data used by Unicode CLDR, ECMA-402, Linux, UNIX, Java, ICU, and others. It's used by Globalize to circumvent the JavaScript limitations with respect to manipulating date in time zones other than the user's environment.

In short, feed Globalize on IANA time zone data if you need to format or parse dates in a specific time zone, independently of the user's environment, e.g., America/Los_Angeles.

It's important to note there's no official IANA time zone data in the JSON format. Therefore, iana-tz-data has been adopted for convenience.

Learn more on Globalize.loadTimeZone().

Usage

Globalize's consumable-files are located in the ./dist directory. If you don't find it, it's because you are using a development branch. You should either use a tagged version or build the distribution files yourself. Read installation above if you need more information on how to download.

Globalize can be used for a variety of different i18n tasks, eg. formatting or parsing dates, formatting or parsing numbers, formatting messages, etc. You may NOT need Globalize in its entirety. For that reason, we made it modular. So, you can cherry-pick the pieces you need, eg. load dist/globalize.js to get Globalize core, load dist/globalize/date.js to extend Globalize with Date functionalities, etc.

An example is worth a thousand words. Check out our Examples section below.

Performance

When formatting or parsing, there's actually a two-step process: (a) the formatter (or parser) creation and (b) its execution, where creation takes an order of magnitude more time (more expensive) than execution. In the creation phase, Globalize traverses the CLDR tree, processes data (e.g., expands date patterns, parses plural rules, etc), and returns a function that actually executes the formatting or parsing.

// Formatter creation.
var formatter = Globalize.numberFormatter();

// Formatter execution (roughly 10x faster than above).
formatter( Math.PI );
// > 3.141

As a rule of thumb for optimal performance, cache your formatters and parsers. For example: (a) on iterations, generate them outside the loop and reuse while looping; (b) on server applications, generate them in advance and execute when requests arrive.

Compilation and the Runtime modules

Take advantage of compiling your formatters and/or parsers during build time when deploying to production. It's much faster than generating them in real-time and it's also much smaller (i.e., better loading performance).

Your compiled formatters and parsers allow you to skip a big part of the library and also allow you to skip loading CLDR data, because they have already been created (see Performance above for more information).

To illustrate, see our Basic Globalize Compiler example.

Globalize Compiler

For information about the Globalize Compiler CLI or its JavaScript API, see the Globalize Compiler documentation.

Examples

The fastest and easiest way to use Globalize is by integrating it into your existing tools.

If you're using a different tool than the one above, but you're comfortable using JavaScript modules (such as ES6 modules, CommonJS, or AMD) and package managers like npm or bower, you may want to check out the following examples. Note you'll need to compile your code for production yourself.

If you're using none of the tools above, but instead you're using the plain and old script tags only, the following example may interest you. Note Globalize allows you to go low level like this. But, acknowledge that you'll need to handle dependencies and CLDR loading manually yourself.

Community

You can find us on Slack. If you're new, join here.

API

Core module

Globalize.load( cldrJSONData, ... )

This method allows you to load CLDR JSON locale data. Globalize.load() is a proxy to Cldr.load(). Read more...

Globalize.locale( [locale|cldr] )

Set default locale, or get it if locale argument is omitted. Read more...

[new] Globalize( locale|cldr )

Create a Globalize instance. Read more...

Locales

A locale is an identifier (id) that refers to a set of user preferences that tend to be shared across significant swaths of the world. In technical terms, it's a String composed of three parts: language, script, and region. For example:

locale description
en-Latn-US English as spoken in the Unites States in the Latin script.
en-US English as spoken in the Unites States (Latin script is deduced given it's the most likely script used in this place).
en English (United States region and Latin script are deduced given they are respectively the most likely region and script used in this place).
en-GB English as spoken in the United Kingdom (Latin script is deduced given it's the most likely script used in this place).
en-IN English as spoken in India (Latin script is deduced).
es Spanish (Spain region and Latin script are deduced).
es-MX Spanish as spoken in Mexico (Latin script is deduced).
zh Chinese (China region and Simplified Han script are deduced).
zh-TW Chinese as spoken in Taiwan (Traditional Han script is deduced).
ja Japanese (Japan region and Japanese script are deduced).
de German (Germany region and Latin script are deduced).
pt Portuguese (Brazil region and Latin script are deduced).
pt-PT Portuguese as spoken in Portugal (Latin script is deduced).
fr French (France region and Latin script are deduced).
ru Russian (Russia region and Cyrillic script are deduced).
ar Arabic (Egypt region and Arabic script are deduced).

The likely deductibility is computed by using CLDR data, which is based on the population and the suppress-script data in BCP47 (among others). The data is heuristically derived, and may change over time.

Figure out the deduced information by looking at the cldr.attributes.maxLanguageId property of a Globalize instance:

var Globalize = require( "globalize" );
Globalize.load( require( "cldr-data" ).entireSupplemental() );
Globalize( "en" ).cldr.attributes.maxLanguageId;
// > "en-Latn-US"

Globalize supports all the locales available in CLDR, which are around 740. For more information, search for coverage charts at the downloads section of http://cldr.unicode.org/.

Read more details about locale at UTS#35 locale.

Date module

Globalize.loadTimeZone( ianaTzData )

This method allows you to load IANA time zone data to enable options.timeZone feature on date formatters and parsers.

Read more...

.dateFormatter( [options] )

Return a function that formats a date according to the given options. The default formatting is numeric year, month, and day (i.e., { skeleton: "yMd" }.

.dateFormatter()( new Date() )
// > "11/30/2010"

.dateFormatter({ skeleton: "GyMMMd" })( new Date() )
// > "Nov 30, 2010 AD"

.dateFormatter({ date: "medium" })( new Date() )
// > "Nov 1, 2010"

.dateFormatter({ time: "medium" })( new Date() )
// > "5:55:00 PM"

.dateFormatter({ datetime: "medium" })( new Date() )
// > "Nov 1, 2010, 5:55:00 PM"

.dateFormatter({ datetime: "full", timeZone: "America/New_York" })( new Date() );
// > "Monday, November 1, 2010 at 3:55:00 AM Eastern Daylight Time"

.dateFormatter({ datetime: "full", timeZone: "America/Los_Angeles" })( new Date() );
// > "Monday, November 1, 2010 at 12:55:00 AM Pacific Daylight Time"

Read more...

.dateToPartsFormatter( [options] )

Return a function that formats a date into parts tokens according to the given options. The default formatting is numeric year, month, and day (i.e., { skeleton: "yMd" }.

.dateToPartsFormatter()( new Date() )
// > [
//   { "type": "month", "value": "3" },
//   { "type": "literal", "value": "/" },
//   { "type": "day", "value": "17" },
//   { "type": "literal", "value": "/" },
//   { "type": "year", "value": "2017" }
// ]

Read more...

.dateParser( [options] )

Return a function that parses a string representing a date into a JavaScript Date object according to the given options. The default parsing assumes numeric year, month, and day (i.e., { skeleton: "yMd" }).

.dateParser()( "11/30/2010" )
// > new Date( 2010, 10, 30, 0, 0, 0 )

.dateParser({ skeleton: "GyMMMd" })( "Nov 30, 2010 AD" )
// > new Date( 2010, 10, 30, 0, 0, 0 )

.dateParser({ date: "medium" })( "Nov 1, 2010" )
// > new Date( 2010, 10, 30, 0, 0, 0 )

.dateParser({ time: "medium" })( "5:55:00 PM" )
// > new Date( 2015, 3, 22, 17, 55, 0 ) // i.e., today @ 5:55PM

.dateParser({ datetime: "medium" })( "Nov 1, 2010, 5:55:00 PM" )
// > new Date( 2010, 10, 30, 17, 55, 0 )

Read more...

.formatDate( value [, options] )

Alias for .dateFormatter( [options] )( value ).

.formatDateToParts( value [, options] )

Alias for .dateToPartsFormatter( [options] )( value ).

.parseDate( value [, options] )

Alias for .dateParser( [options] )( value ).

Message module

Globalize.loadMessages( json )

Load messages data. Read more...

.messageFormatter( path ) ➡ function( [variables] )

Return a function that formats a message (using ICU message format pattern) given its path and a set of variables into a user-readable string. It supports pluralization and gender inflections.

.messageFormatter( "task" )( 1000 )
// > "You have 1,000 tasks remaining"

.messageFormatter( "like" )( 3 )
// > "You and 2 others liked this"

Read more...

.formatMessage( path [, variables ] )

Alias for .messageFormatter( path )([ variables ]).

Number module

.numberFormatter( [options] )

Return a function that formats a number according to the given options or locale's defaults.

.numberFormatter()( pi )
// > "3.142"

.numberFormatter({ maximumFractionDigits: 5 })( pi )
// > "3.14159"

.numberFormatter({ round: "floor" })( pi )
// > "3.141"

.numberFormatter({ minimumFractionDigits: 2 })( 10000 )
// > "10,000.00"

.numberFormatter({ style: "percent" })( 0.5 )
// > "50%"

.numberFormatter({ compact: "short", maximumFractionDigits: 0 })( 14305 )
// > "14K"

Read more...

.numberToPartsFormatter( [options] )

Return a function that formats a number into parts tokens according to the given options or locale's defaults.

.numberToPartsFormatter()( new Date() )
// > [
//   { "type": "integer", "value": "3" },
//   { "type": "decimal", "value": "." },
//   { "type": "fraction", "value": "142" }
// ]

Read more...

.numberParser( [options] )

Return a function that parses a string representing a number according to the given options or locale's defaults.

.numberParser()( "3.14159" )
// > 3.14159

.numberParser()( "10,000.00" )
// > 10000

.numberParser({ style: "percent" })( "50%" )
// > 0.5

Read more...

.formatNumber( value [, options] )

Alias for .numberFormatter( [options] )( value ).

.formatNumberToParts( value [, options] )

Alias for .numberToPartsFormatter( [options] )( value ).

.parseNumber( value [, options] )

Alias for .numberParser( [options] )( value ).

Currency module

.currencyFormatter( currency [, options] )

Return a function that formats a currency according to the given options or locale's defaults.

.currencyFormatter( "USD" )( 1 )
// > "$1.00"

.currencyFormatter( "USD", { style: "accounting" })( -1 )
// > "($1.00)"

.currencyFormatter( "USD", { style: "name" })( 69900 )
// > "69,900.00 US dollars"

.currencyFormatter( "USD", { style: "code" })( 69900 )
// > "69,900.00 USD"

.currencyFormatter( "USD", { round: "ceil" })( 1.491 )
// > "$1.50"

Read more...

.currencyToPartsFormatter( currency [, options] )

Return a function that formats a currency into parts tokens according to the given options or locale's defaults.

.currencyToPartsFormatter()( new Date() )
// > [
//   { "type": "currency", "value": "USD" },
//   { "type": "literal", "value": " " },
//   { "type": "integer", "value": "69" },
//   { "type": "group", "value": "," },
//   { "type": "integer", "value": "900" },
//   { "type": "decimal", "value": "." },
//   { "type": "fraction", "value": "00" }
// ]

Read more...

.formatCurrency( value, currency [, options] )

Alias for .currencyFormatter( currency [, options] )( value ).

.formatCurrencyToParts( value, currency [, options] )

Alias for .currencyToPartsFormatter( currency [, options] )( value ).

Plural module

.pluralGenerator( [options] )

Return a function that returns the value's corresponding plural group: zero, one, two, few, many, or other.

The function may be used for cardinals or ordinals.

.pluralGenerator()( 0 )
// > "other"

.pluralGenerator()( 1 )
// > "one"

.pluralGenerator({ type: "ordinal" })( 1 )
// > "one"

.pluralGenerator({ type: "ordinal" })( 2 )
// > "two"

Read more...

.plural( value[, options ] )

Alias for .pluralGenerator( [options] )( value ).

Relative time module

.relativeTimeFormatter( unit [, options] )

Returns a function that formats a relative time according to the given unit, options, and the default/instance locale.

.relativeTimeFormatter( "day" )( 1 )
// > "tomorrow"

.relativeTimeFormatter( "month" )( -1 )
// > "last month"

.relativeTimeFormatter( "month" )( 3 )
// > "in 3 months"

Read more...

.formatRelativeTime( value, unit [, options] )

Alias for .relativeTimeFormatter( unit, options )( value ).

Unit module

.unitFormatter( unit [, options] )

Returns a function that formats a unit according to the given unit, options, and the default/instance locale.

.unitFormatter( "second" )( 10 )
// > "10 seconds"

.unitFormatter( "second", { form: "short" } )( 10 )
// > "10 secs"

.unitFormatter( "second", { form: "narrow" } )( 10 )
// > "10s"

Read more...

.formatUnit( value, unit [, options] )

Alias for .unitFormatter( unit, options )( value ).

Error reference

CLDR Errors

  • E_INVALID_CLDR

    Thrown when a CLDR item has an invalid or unexpected value.

Read more...

  • E_MISSING_CLDR

    Thrown when any required CLDR item is NOT found.

    Read more...

Parameter Errors

  • E_INVALID_PAR_TYPE

    Thrown when a parameter has an invalid type on any static or instance methods.

    Read more...

  • E_INVALID_PAR_VALUE

    Thrown for certain parameters when the type is correct, but the value is invalid.

    Read more...

  • E_MISSING_PARAMETER

    Thrown when a required parameter is missing on any static or instance methods.

    Read more...

  • E_PAR_OUT_OF_RANGE

    Thrown when a parameter is not within a valid range of values.

    Read more...

Other Errors

  • E_DEFAULT_LOCALE_NOT_DEFINED

    Thrown when any static method, eg. Globalize.formatNumber() is used prior to setting the Global locale with Globalize.locale( <locale> ).

    Read more...

  • E_MISSING_PLURAL_MODULE

    Thrown when plural module is needed, but not loaded, eg. to format currencies using the named form.

    Read more...

  • E_UNSUPPORTED

    Thrown for unsupported features, eg. to format unsupported date patterns.

    Read more...

Contributing

If you are having trouble using Globalize after reading the documentation carefully, please post a question to StackOverflow with the "javascript-globalize" tag. Questions that include a minimal demo are more likely to receive responses.

In the spirit of open source software development, we always encourage community code contribution. To help you get started and before you jump into writing code, be sure to read CONTRIBUTING.md.

For ideas where to start contributing, see the following queries to find what best suites your interest: quick change, new features, bug fixes, documentation improvements, date module, currency module, message module, number module, plural module, relative time module. Last but not least, feel free to get in touch.

Roadmap

Our roadmap is the collection of all open issues and pull requests where you can find:

  • Ongoing work lists our current sprint. Here you find where we're actively working on at this very moment. Priority is determined by the community needs and volunteering. If there is anything you want to be done, share your thoughts with us on any existing or new issue and especially volunteer to do it.
  • Everything else is potential next work that you could help us to accomplish now. Releases are published following semver rules as often as possible.

Development

File structure

├── bower.json (metadata file)
├── CONTRIBUTING.md (doc file)
├── dist/ (consumable files, the built files)
├── external/ (external dependencies, eg. cldr.js, QUnit, RequireJS)
├── Gruntfile.js (Grunt tasks)
├── LICENSE (license file)
├── package.json (metadata file)
├── README.md (doc file)
├── src/ (source code)
│   ├── build/ (build helpers, eg. intro, and outro)
│   ├── common/ (common function helpers across modules)
│   ├── core.js (core module)
│   ├── date/ (date source code)
│   ├── date.js (date module)
│   ├── message.js (message module)
│   ├── number.js (number module)
│   ├── number/ (number source code)
│   ├── plural.js (plural module)
│   ├── plural/ (plural source code)
│   ├── relative-time.js (relative time module)
│   ├── relative-time/ (relative time source code)
│   ├── unit.js (unit module)
│   ├── unit/ (unit source code)
│   └── util/ (basic JavaScript helpers polyfills, eg array.map)
└── test/ (unit and functional test files)
    ├── fixtures/ (CLDR fixture data)
    ├── functional/ (functional tests)
    ├── functional.html
    ├── functional.js
    ├── unit/ (unit tests)
    ├── unit.html
    └── unit.js

Source files

The source files are as granular as possible. When combined to generate the build file, all the excessive/overhead wrappers are cut off. It's following the same build model of jQuery and Modernizr.

Core, and all modules' public APIs are located in the src/ directory, ie. core.js, date.js, message.js, number.js, and plural.js.

Install development external dependencies

Install Grunt and external dependencies. First, install the grunt-cli and bower packages if you haven't before. These should be installed globally (like this: npm install -g grunt-cli bower). Then:

npm install && bower install

Tests

Tests can be run either in the browser or using Node.js (via Grunt) after having installed the external development dependencies (for more details, see above).

Unit tests

To run the unit tests, run grunt test:unit, or run grunt connect:keepalive and open http://localhost:9001/test/unit.html in a browser. It tests the very specific functionality of each function (sometimes internal/private).

The goal of the unit tests is to make it easy to spot bugs, easy to debug.

Functional tests

To run the functional tests, create the dist files by running grunt. Then, run grunt test:functional, or open http://localhost:9001/test/functional.html in a browser. Note that grunt will automatically run unit and functional tests for you to ensure the built files are safe.

The goal of the functional tests is to ensure that everything works as expected when it is combined.

Build

Build the distribution files after having installed the external development dependencies (for more details, see above).

grunt

globalize's People

Contributors

agcolom avatar alunny avatar ambrons avatar apsdehal avatar arthurvr avatar blixt avatar hippich avatar hmizutanitsi avatar johnnyreilly avatar jzaefferer avatar karan1276 avatar kborchers avatar kflorence avatar krinkle avatar manrajgrover avatar mottie avatar nkovacs avatar nschonni avatar patch avatar rdworth avatar rxaviers avatar scottgonzalez avatar shivijais avatar slexaxton avatar strate avatar stukalin avatar tobie avatar trejgun avatar wescravens avatar yasuhiroyoshida avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

globalize's Issues

Globalize.culture( selector ) appears to work but does not set culture

Trying to use Globalize.culture() with a parameter that is a valid code for country variant of a language, like "es-AO", seemingly works in the sense that the function returns a culture corresponding to the language generically, like "es":

alert(Globalize.culture("es-AO").name)
shows "es".

But using format() with the culture defaulted, like

alert(Globalize.format(new Date(),"D"));

fails to use the "es" culture and uses "en" settings instead. For comparison, the operation with an explicit culture parameter works (Spanish date presentation appears):

alert(Globalize.format(new Date(),"D","es-AO"));

Globalization.parseDate 'd' and 'dd' (leading zeroes) treated the same

parseDate calls parseExact which in turn calls getParseRegExp. The following is used to build part of the validation regex:
case 'dd': case 'd':
case 'MM': case 'M':
case 'yy': case 'y':
case 'HH': case 'H':
case 'hh': case 'h':
case 'mm': case 'm':
case 'ss': case 's':
add = "(\d\d?)";
break;
Shouldn't this be split between formats requiring a leading zero and those that don't? Currently this allows 2011-4-4 to be parsed with a yyyy-mm-dd format, which seems odd.

parsing doesn't work in the demo

the parseDate and parseNumber input boxes in the demo are currently non-functional.
Instead of calling $.parseX they should call $.global.parseX

// Fredrik Blomqvist

en-US 'englishName' is wrong

The 'englishName' property for the en-US culture is 'English'. This should be English (United States), just as en-GB is English (United Kingdom)

Misleading: "culture"

Not sure where you got your definition of "culture" from, but in programming the de-facto standard term for managing I18n-ish data is "locale"/"locales". Why reinvent the wheel and make things confusing like this? "Culture" is so misleading. =S

Move currency symbol and number formatting out to a separate object.

Number formatting of a currency is generally not cultural. It is an aspect of the data itself. Cultures do have one or more commonly used currencies, however the display of the currency needs to be tied to the data. For example, just because I am an American working with Yen in Japan, I don't expect my bank account to look like "¥1,000,000.00"... Yen should never be written with decimals, regardless of what your browser or application's culture is set to.

I'd suggest the creation of a separate object to encapsulate all currencies and reference that in the culture. For instance, remove the currency out of the number formatting section and add a commonCurrencies: ["USD"] field for each culture. Then you could have a parseCurrency(value, radix, currency) that accepts these objects.

Since I'm currently working on extending the python-money code, I could generate the javascript structure for you using ISO-4217 data pretty easily. Something like this:

[
    {
        symbol: "",
        countries: [
        "ALGERIA"
        ]
        code: "DZD",
        decimals: 2,
        numeric: "012",
        name: "Algerian Dinar",
    },
    ...

    {
        symbol: "$",
        countries: [
        "AMERICAN SAMOA","BRITISH INDIAN OCEAN TERRITORY","ECUADOR","GUAM","MARSHALL ISLANDS","MICRONESIA","NORTHERN MARIANA ISLANDS","PALAU","PUERTO RICO","TIMOR-LESTE","TURKS AND CAICOS ISLANDS","UNITED STATES MINOR OUTLYING ISLANDS","VIRGIN ISLANDS (BRITISH)","VIRGIN ISLANDS (U.S.)"
        ]
        code: "USD",
        decimals: 2,
        numeric: "840",
        name: "US Dollar",
    },
    ...

]

It might be that the common case is web-apps where the currency is consistent with the user's culture. I don't want to overly complicate the library. I do think that this kind of structure more accurately reflects the real world. Would anyone be interested in something like this?

Number formatting with “d” code – needs explanation & example fix

The description of ”d” number formatting code as ”for decimal digits” sounds very odd. It seems that the format code ”d” really means using the non-localized JavaScript number format, just with left-padding the string with zeros to get a minimum width specified by number after the format character ”d”.

So Globalize.format( 123.45, "d" ) yields 123.45 (not 123 as currently in the documentation). Maybe the documentation is meant to use 123 as the first parameter, on the grounds that the ”d” format is really meant for integers only, isn’t it? Moreover, it should perhaps be emphasized that the result is not localized, e.g. Globalize.format( 1234, "d") yields 1234 independently of locale, not a localized presentation with a thousands separator (1,234 or 1 234 or something like that).

Alternate date/number formatting

I was looking into using this library and I wasn't sure where these date formatting tokens came from. Many libraries (date.js, django, etc...) use a PHP-like formatting for input an output. Sometimes the strftime format is used. For instance, the Django documentation explains how to get the framework to provide a js file with this in it:

formats['DATETIME_FORMAT'] = 'N j, Y, P';
formats['DATE_FORMAT'] = 'N j, Y';
formats['DECIMAL_SEPARATOR'] = '.';
formats['MONTH_DAY_FORMAT'] = 'F j';
formats['NUMBER_GROUPING'] = '3';
formats['TIME_FORMAT'] = 'P';
formats['FIRST_DAY_OF_WEEK'] = '0';
formats['TIME_INPUT_FORMATS'] = ['%H:%M:%S', '%H:%M'];
formats['THOUSAND_SEPARATOR'] = ',';
formats['DATE_INPUT_FORMATS'] = ['%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y'];
formats['YEAR_MONTH_FORMAT'] = 'F Y';
formats['SHORT_DATE_FORMAT'] = 'm/d/Y';
formats['SHORT_DATETIME_FORMAT'] = 'm/d/Y P';
formats['DATETIME_INPUT_FORMATS'] = ['%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M', '%Y-%m-%d', '%m/%d/%Y %H:%M:%S', '%m/%d/%Y %H:%M', '%m/%d/%Y', '%m/%d/%y %H:%M:%S', '%m/%d/%y %H:%M', '%m/%d/%y'];

These values are pulled from the application settings. It would be really nice to be able to pass these settings directly into jquery.global to keep the server side and javascript in sync. The only issue is that I don't see the "j" option here. In jquery.global the "day of week without leading 0's" would be done with "d"

Are the formatting options used here taken from somewhere in particular? The date.js library allowed you to pull in an "extra" PHP compatible formatting lib. Would something like that be possible?

Make radix argument optional

parseInt and parseFloat both have 10 as a default for the radix argument, but when specifying a culture, the radix argument has to be provided again. There should be some internal argument shufflich to allow specifying the culture (string) without the radix (number).

Date formatting fails on single chars not in calendar.patterns

It doesn't seem like any one character date formats are valid right now unless they are contained in the calendar.patterns object (lines 431-437):

if ( len === 1 ) {
    pattern = patterns[ format ];
    if ( !pattern ) {
        throw "Invalid date format string \'" + format + "\'.";
    }
    format = pattern;
}

Seems like there should be some way at getting at single date properties, like month or hour.

Add jQuery-independent build

We don't want two version of the plugin in the repository, but there should be a build to create a jQuery-independent version for releases.

12 vs. 24 hour issue, inconsistency of en-GB

(This relates to issue #41 at least in the sense that considering it, I noticed this discrepancy.)

The en-GB culture uses the H formatting code (24-hour times) for times in the definitions for codes like "t". Yet, it has no explicit setting for the calendar.AM and calendar.PM properties, which means defaulting them to the en (default) locale, which in turn effectively means using 12-hour times.

This means that there's no global way of requesting for, say, a format that consists of hours only, in the locale's hour notation. If the locale definitions were consistent, we could use

function hour(d) {
return Globalize.format(d, Globalize.culture().calendar.AM !== null ? 'h tt' : "''H" );
}

(That is, use 12-hour number followed by AM/PM designator if the locale uses 12-hour times, 24-hour number otherwise.)

Globalize.localize doesn't return a message from the default culture

Hi,

I need to store some messages in default culture (to use them when localized one are not stored in the specific culture). But Globalize.localize returns "undefined" if a message is placed in the default culture only.

It seems that this method contains mistake.

Globalize.localize = function( key, cultureSelector ) {
return (
this.findClosestCulture( cultureSelector ).messages[ key ]
||
this.cultures[ "default" ].messages[ "key" ]
);
};

For the specific culture messages are taken using key parameter that is passed to function, but for the default culture messages are taken using "key" string.

Could you please correct this if it is a mistake or explain why hard-coded "key" string is used for the default culture?

24 hour usage in nl

In the NL culture, and other European cultures as well (except for the UK).
We use the 24 hour (HH) time notation instead of the 12 (h) time notation.

Without something like am/pm its unclear what part of the day it is.

Documentation error: Globalize.culture needs to be Globaliza.culture()

In the documentation, right before the heading "Number Formatting", there is the following code sample:

// switch to a non-standard calendar
Globalize.culture.calendar = Globalize.culture.calendars.SomeOtherCalendar;
// back to the standard calendar
Globalize.culture.calendar = Globalize.culture.calendars.standard;

That won't work, since Globalize.culture is a function and has no property called calendar. To fix this, add the parentheses () to make it a function call.

It might be a good idea to add the following to the documentation:
Called with an empty parameter list, Globalize.culture() returns the current culture.

parseFloat too permissive, e.g. 4,0 taken as 40

Globalize.parseFloat("4,0",10,"en") yields 40, which is unacceptable. It should either work the same way as the standard parseFloat, parsing a number at the start of its first parameter (yielding 4) or parse the entire attribute as a number, recognizing that it does not fit into the number patterns of the locale (yielding NaN). The latter is preferable, as it would help in detecting data errors (like input "4,0" when a number in the English locale is expected).

It is highly probable that input like 4,0 in English locale is data error. It is extremely improbable that the user really meant the number 40

Technically, parseFloat, upon encountering a group separator, should test that there is a correct number of digits after it, as defined by numberFormat.groupSizes.

Similar considerations apply to parseInt, of course.

Number formatting with ”d” code – needs explanation & example fix

The description of ”d” number formatting code as ”for decimal digits” sounds very odd. It seems that the format code ”d” really means using the non-localized JavaScript number format, just with left-padding the string with zeros to get a minimum width specified by number after the format character ”d”.

So Globalize.format( 123.45, "d" ) yields 123.45 (not 123 as currently in the documentation). Maybe the documentation is meant to use 123 as the first parameter, on the grounds that the ”d” format is really meant for integers only, isn’t it? Moreover, it should perhaps be emphasized that the result is not localized, e.g. Globalize.format( 1234, "d") yields 1234 independently of locale, not a localized presentation with a thousands separator (1,234 or 1 234 or something like that).

Add parseCurrency method

parseFloat doesn't crok any currency symbols, so in order to parse currencies correctly we need a seperate parseCurrency method. It needs to be able to handle anything output by format(123, "c")

Minified version of the fr-FR settings is buggy

Hello,

I don't know which minifier you use but the minified version of the fr-FR settings is buggy (jquery.glob.fr-FR.min.js). It just won't load correctly, throwing an error in Firebug. The non-minified version is OK.

Accidental global variable

jquery-global.js, method formatDate(), about line 1240.
The variable "names" is missing the "var" keyword thus creating an accidental global.

findClosestCulture("de") should match de-DE

When a specific culture is loaded, but not the generic language culture preferring the language should match that culture.

So when de-DE is available, but nothing else, findClosestCulture("de") should match "de-DE".

parseInt and parseFloat fail (NaN) with negative currency

// Expected
Globalize.parseInt( Globalize.format(-3.91, "c") ); // -3
Globalize.parseFloat( Globalize.format(-3.91, "c") ); // -3.91

// Actual
Globalize.parseInt( Globalize.format(-3.91, "c") ); // NaN
Globalize.parseFloat( Globalize.format(-3.91, "c") ); // NaN

The expected values are returned if the original value is positive rather than negative.

No "invariant" culture?

What was the motivation for dropping the "invariant" culture? (commit 099e13a)

Even if not being set as the default culture, I think it would be useful to maintain symmetry with for example .NET that exposes it.

// Fredrik Blomqvist

UTC support

There does not seem to be any option to specify that dates should be formatted as UTC, instead of in the local timezone.

Globalization files

Why not just make the globalization files into JSON files? This way it is independent of any namespace and it would reduce the redundancy of code in each file (defining "cultures", etc). Plus, this makes it more portable in case some other plugin needs to tap into a culture definition. The exception to this would be, of course, if a culture definition contained a function, but I don't see that anywhere.

Of course this would mean the inclusion of an additional function which handles loaded culture definition files, but it seems more intuitive that way. The only potential downside to loading files in this manor is that you can't simply have a list of script includes for individual culture definitions, but if they are going to be static anyways, it would be very easy for the developer to compile the needed definitions into a single file that extends the cultures object itself.

ParseFloat: tests 3 and 4 fail

Test 3: equal( Globalize.parseInt("($5.51)"), -5 );
Expected: -5
Result: 0

Test 4: equal( Globalize.parseFloat("($5.51)"), -5.51 );
Expected: -5.51
Result: NaN

I might have some time to look into this later, if nobody else gets to it.

EDIT: I see this in Chrome, too. Maybe it is cross-browser.

What's "Globalization"?

Trying to use the revamped jQuery Global, i.e. Globalization, in the most obvious way...

<script src="jquery/lib/globalize.cultures.js"></script> <script src="jquery/globinfo/Globalization.all.js"></script> <script>alert(Globalize.format(new Date(),"D","fi"))</script>

I get the error message "Globalization is not defined". Apparently the reason is that Globalization.all.js uses the identifier "Globalization".

So there's presumably something not quite finished yet in the transition or there is something one should do (define "Globalization"?) before calling the methods, but what? (The documentation is silent about this.)

Cleanup to remove warnings?

Currently, when using Globalize, the following warnings are displayed in the error log:

  1. variable deep redeclares argument
    (in private utility functions)

  2. function getPart does not always return a value

  3. assignment to undeclared variable culture
    in:
    Globalize.format = function( value, format, cultureSelector ) {
    culture = this.findClosestCulture( cultureSelector );

Although these are not serious, it would be better to have them removed, partly to avoid questions "why these warnings?", partly to make it a little easier to deal with other warnings (so that when you see that there are warnings, you would knoiw that there is something else than these routine warnings).

I'm not sure I see the point of item 1. Why declare something as a parameter if you start by setting its value to false? The code accesses the parameters in other ways, so I don't see why it has a dummy parameter list at all and why it uses the name "deep".

Item 2 is about a function that ends with a switch statement without a default branch. I guess putting just "return undefined" after the switch statement would silence the warning, though it might be preceded by raising an error (as we don't expect to come there).

Item 3 is just about forgetting to declare "var culture" in the function, right?

Better operation in function expandYear

function expandYear( cal, year ) {
   // expands 2-digit year into 4 digits.   
    //var now = new Date(), era = getEra( now );//this line should move into the if... block
    if ( year < 100 ) {
         var now = new Date(), era = getEra( now );
        //....
    }
    return year;
}

Globalization data: why do all cultures extend Neutral English?

This results in a lot of duplicate definitions. It would seem more logical to base extensions on the hierarchy of languages.

For example, both jquery.glob.fr-FR.js (French/France) and jquery.glob.fr-CA.js (French/Canada) should extend jquery.glob.fr.js (French). Currently, the same properties are repeated in the three files.

Globalize.parseint("foo") returns 0, should return NaN

When the string does not contain a recognizable number, Globalize.parseInt returns 0, as opposite to parseInt, which returns NaN. It is essential to return NaN, since otherwise the caller cannot distinguish between invalid data and input data representing the number zero.

The problem is in the function

truncate = function( value ) {
return value | 0;
};

which is currently used in two contexts: 1) to define Globalize.parseInt so that it truncates the return value of Globalize.parseFloat, and 2) in formatNumber when using the "d" format code.

Minimal fix: change the statement to

truncate = function( value ) {
return isNaN(value) ? NaN : value | 0 ;
}

$.format(Infinity, 'n0', 'nl-NL') yields "In.fin.ity"

$.format formats Infinity in a very peculiar way: "In.fin.ity". I haven't checked it in other cultures, but I suspect $.format(Infinity, 'n0', 'en-GB') would yield "In,fin,ity".

Although I don't think a lot of people will have to deal with values as Inifinity or -Inifinity (which also yields "In.fin.ity"), this is still a bug.

More erroneous behavior:

> $.format(-Infinity, 'n2')
"In.fin.ity,00"

Lack of integration with jQuery

The Globalization plugin defines methods, both public and private, that are already part of jQuery:

  • Globalization.extend() -> jQuery.extend()
  • trim() -> jQuery.trim()
  • isArray() -> jQuery.isArray()
  • isObject() -> jQuery.isPlainObject() or jQuery.type(obj) === 'object'
  • arrayIndexOf -> jQuery.inArray()

Is there something specific in these implementations that prevents calling jQuery methods instead?

Timezone formatting needs to be localized

In Globalize.format() for dates, the formatting codes 'z', 'zz', 'zzz' currently use representations where the separator between hours and minutes is ':' (colon) and the minus sign is '-' (hyphen-minus, i.e. ASCII hyphen). These characters should be localized according to calendar[:'] and numberFormat['-'].

Demo code (the second part needs to be tested in an environment where the system's time zone is GMT minus something):

var d = new Date();
var p = document.getElementById('p');
Globalize.culture('bn');
p.innerHTML = Globalize.format(d,'F') +
'
' + Globalize.format(d,'zzz');
Globalize.culture('en');
Globalize.culture().numberFormat['-'] = '\u2212'; // Unicode MINUS SIGN
p.innerHTML += '
' +
Globalize.format(-42) + '
' +
Globalize.format(d,'zzz'); // should show MINUS SIGN (longer than ASCII hyphen)

The first line of output shows that in the 'bn' culture, the 'F' format uses a time denotation with "." (period) between hours and minutes, as well as between minutes and seconds. Yet the second line shows that 'zz' is implemented so that ':' (colon) is used.

A lot of website are linking the old nje github repository

Hello,

Following a link on a Scott Guthrie blog post (but I have also seen others) I browsed the old nje (https://github.com/nje/jquery-glob) github repository. Believe it or not but it took me TWO HOURS to notice something was wrong (the fact that all files had not been commited since july 2010 helped).

I know you have probably no power on those sites and blogs, but can't you do some redirection, or just shut down the old repository, or at least put a big "OBSOLETE, GO HERE" message on the homepage?

Huge need for a bridge between jquery.global and jquery.validate

Hello,

My team is developing an e-commerce framework in ASP.Net MVC. Recently we upgraded it to MVC 3, and I have spent a large part of the day testing the new jquery.validate/unobtrusive javascript goodness.

All in all, it went pretty smooth, but our framework is intended to be multi-language oriented (or at least french oriented), and the need for a localization library came quickly. Previously we were using the Ajax.GlobalizationScript and the MicrosoftAjaxMvcValidation libraries, which were a little bit limited, but worked well.

I was excited by the possibility to use jquery.validate and all its neat features, but... it's proving very difficult to use it on an international website. Of course I expected jquery.global to come to the rescue, but it's not very easy. For example : validation of comma separated decimal numbers (which are default in french). A lot of forums like StackOverflow are giving this little trick :
jQuery.validator.methods.number = function (value, element) {
return !isNaN(jQuery.global.parseFloat(value));
}

It works quite well, but actually you need to do that kind of "bridging" with all methods that parse possible decimal numbers (like range validation).

I'm perfectly aware that this concerns jquery.validation as much as jquery.global (if not more), but I think it's really REALLY time for those two excellent official plugins to hold their hands and work together. Even more goodness will come from it.

In the meantime, keep up the good work!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.