"
86 | ],
87 | "license": "BSD",
88 | "bugs": {
89 | "url": "https://github.com/yahoo/formatjs-site/issues"
90 | },
91 | "homepage": "https://formatjs.io/",
92 | "jshintConfig": {
93 | "node": true,
94 | "browser": true,
95 | "esnext": true,
96 | "predef": [
97 | "DustIntl",
98 | "dust"
99 | ],
100 | "excludes": [
101 | "examples/",
102 | "build/",
103 | "tmp/",
104 | "tests/functional/includes/"
105 | ]
106 | },
107 | "yahoo": {
108 | "bugzilla": {
109 | "product": "yui utilities",
110 | "component": "Intl"
111 | },
112 | "custodian": {
113 | "email": "jlecomte@yahoo-inc.com",
114 | "url": "https://formatjs.io"
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/public/css/syntax.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --black : rgb(65, 57, 70);
3 | --gray : rgb(95, 90, 99);
4 | --gray-medium : rgb(150, 150, 150);
5 | --gainsboro : rgb(220, 220, 220);
6 | --gray-light : rgb(247, 247, 247);
7 | --white : rgb(255, 255, 255);
8 | --white-alpha : rgba(255, 255, 255, 0.44);
9 | --pink : rgb(173, 104, 216);
10 | --pink-light : rgb(178, 155, 194);
11 | --pink-alpha3 : rgba(208, 146, 247, 0.20);
12 | --pink-alpha2 : rgba(208, 146, 247, 0.15);
13 | --pink-alpha1 : rgba(208, 146, 247, 0.10);
14 | --purple : rgb(131, 57, 194);
15 | --purple-medium: rgb(94, 67, 112);
16 | --purple-dark : rgb(103, 58, 131);
17 | --yellow-js : rgb(247, 223, 30);
18 | --yellow-dark : rgb(197, 166, 0);
19 | }
20 |
21 | .hljs {
22 | color: var(--black);
23 | }
24 |
25 | .hljs-comment,
26 | .hljs-template_comment {
27 | color: var(--gray-medium);
28 | font-style: italic;
29 | }
30 |
31 | .hljs-keyword,
32 | .css .rule .hljs-keyword,
33 | .javascript .hljs-title,
34 | .hljs-subst,
35 | .hljs-request,
36 | .hljs-status {
37 | font-weight: bold;
38 | }
39 |
40 | .hljs-number,
41 | .hljs-hexcolor {
42 | color: var(--yellow-dark)
43 | }
44 |
45 | .hljs-string,
46 | .hljs-tag .hljs-value {
47 | color: var(--purple-dark);
48 | }
49 |
50 | .hljs-title,
51 | .hljs-id {
52 | color: var(--purple);
53 | font-weight: bold;
54 | }
55 |
56 | .javascript .hljs-title,
57 | .hljs-list .hljs-keyword,
58 | .hljs-subst {
59 | font-weight: bold;
60 | }
61 |
62 | .hljs-class .hljs-title,
63 | .hljs-type {
64 | font-weight: bold;
65 | }
66 |
67 | .hljs-attribute,
68 | .hljs-variable {
69 | color: var(--pink);
70 | }
71 |
72 | .hljs-regexp {
73 | color: var(--yellow-dark);
74 | }
75 |
76 | .hljs-built_in {
77 | color: var(--purple);
78 | }
79 |
80 | .hljs-preprocessor,
81 | .hljs-pragma,
82 | .hljs-pi,
83 | .hljs-doctype,
84 | .hljs-shebang,
85 | .hljs-cdata {
86 | font-weight: bold;
87 | }
88 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/formatjs/formatjs-site/666a3a0e40b6006e1e20a423cdba087356d4e1f8/public/favicon.ico
--------------------------------------------------------------------------------
/public/img/arrow-down.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/public/img/arrow-right.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/public/img/dust.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/public/img/ember.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
10 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/public/img/handlebars.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/public/img/js.svg:
--------------------------------------------------------------------------------
1 |
2 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/public/img/logo-element.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/public/img/react.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/public/img/splash-head.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/formatjs/formatjs-site/666a3a0e40b6006e1e20a423cdba087356d4e1f8/public/img/splash-head.jpg
--------------------------------------------------------------------------------
/public/js/components/table-of-contents.jsx:
--------------------------------------------------------------------------------
1 | export default React.createClass({
2 | displayName: 'TableOfContents',
3 |
4 | selectors: [
5 | '.secs > h2',
6 | '.secs > h3',
7 | '.secs > h4'
8 | ],
9 |
10 | getLists: function (target, selectorIndex, maxDepth) {
11 | var data = [];
12 | var headers = target.querySelectorAll(this.selectors[selectorIndex]);
13 | var header;
14 | var anchor;
15 | var section;
16 | var childHeaders;
17 | var nextSelector = selectorIndex + 1;
18 |
19 | for (var i = 0, l = headers.length; i < l; i++) {
20 | header = headers[i];
21 | anchor = {header.textContent} ;
22 | section = header.parentNode;
23 | childHeaders = section.querySelectorAll(this.selectors[nextSelector]);
24 | if (childHeaders.length > 0 && nextSelector < maxDepth) {
25 | data.push(
26 |
27 | {anchor}
28 |
29 | {this.getLists(section, nextSelector, maxDepth)}
30 |
31 |
32 | );
33 | } else {
34 | data.push(
35 |
36 | {anchor}
37 |
38 | );
39 | }
40 | }
41 |
42 | return data;
43 | },
44 |
45 | render: function () {
46 | var lists = this.getLists(this.props.contents, 0, this.props.maxDepth);
47 | return (
48 | {lists}
49 | );
50 | }
51 | });
52 |
--------------------------------------------------------------------------------
/public/js/home.jsx:
--------------------------------------------------------------------------------
1 | /* global React */
2 |
3 | import SplashExample from './components/splash-example';
4 |
5 | export default function init(state) {
6 | var splashProps = Object.assign({}, state.intl, state.examples.splash);
7 | var containerNode = document.querySelector('.splash-example-container');
8 |
9 | // Expose React component on its DOM node for testing.
10 | containerNode.component = React.render(
11 | ,
12 | containerNode
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/public/js/integration.jsx:
--------------------------------------------------------------------------------
1 | /* global React */
2 |
3 | import ExampleContainer from './components/example-container';
4 |
5 | export default function init(state) {
6 | state.examples.forEach(function (example) {
7 | hydrateExample(example.id, {
8 | example: example,
9 | intl : state.intl
10 | });
11 | });
12 | }
13 |
14 | function hydrateExample(id, props) {
15 | var exampleNode = document.getElementById(id);
16 | if (!exampleNode) { return; }
17 |
18 | var containerNode = exampleNode.parentNode;
19 |
20 | containerNode.component = React.render(
21 | ,
22 | containerNode
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/public/js/main.js:
--------------------------------------------------------------------------------
1 | /* global APP */
2 |
3 | import homePage from './home';
4 | import integrationPage from './integration';
5 | import tableOfContents from './toc';
6 |
7 | switch (APP.pageType) {
8 | case 'home':
9 | homePage(APP);
10 | break;
11 |
12 | case 'guide':
13 | tableOfContents(2);
14 | break;
15 |
16 | case 'integration':
17 | integrationPage(APP);
18 | break;
19 | }
20 |
--------------------------------------------------------------------------------
/public/js/toc.jsx:
--------------------------------------------------------------------------------
1 | /* global React */
2 |
3 | import TableOfContents from './components/table-of-contents';
4 |
5 | export default function init(maxDepth) {
6 | var tocNode = document.getElementById('toc');
7 | if (!tocNode) {
8 | return;
9 | }
10 |
11 | React.render(
12 | ,
16 | tocNode
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/public/vendor/highlight/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2006, Ivan Sagalaev
2 | All rights reserved.
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are met:
5 |
6 | * Redistributions of source code must retain the above copyright
7 | notice, this list of conditions and the following disclaimer.
8 | * Redistributions in binary form must reproduce the above copyright
9 | notice, this list of conditions and the following disclaimer in the
10 | documentation and/or other materials provided with the distribution.
11 | * Neither the name of highlight.js nor the names of its contributors
12 | may be used to endorse or promote products derived from this software
13 | without specific prior written permission.
14 |
15 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
16 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 | DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 |
--------------------------------------------------------------------------------
/public/vendor/highlight/README.md:
--------------------------------------------------------------------------------
1 | # Highlight.js
2 |
3 | [](https://travis-ci.org/isagalaev/highlight.js)
4 |
5 | Highlight.js is a syntax highlighter written in JavaScript. It works in the
6 | browser as well as on the server. It works with pretty much any markup,
7 | doesn't depend on any framework and has automatic language detection.
8 |
9 |
10 | ## Getting Started
11 |
12 | The bare minimum for using highlight.js on a web page is linking to the library
13 | along with one of the styles and calling [`initHighlightingOnLoad`][1]:
14 |
15 | ```html
16 |
17 |
18 |
19 | ```
20 |
21 | This will find and highlight code inside of `` tags trying to detect
22 | the language automatically. If automatic detection doesn't work for you, you can
23 | specify the language in the class attribute:
24 |
25 | ```html
26 | ...
27 | ```
28 |
29 | The list of supported language classes is available in the [class reference][8].
30 | Classes can also be prefixed with either `language-` or `lang-`.
31 |
32 | To disable highlighting altogether use the `nohighlight` class:
33 |
34 | ```html
35 | ...
36 | ```
37 |
38 | ## Custom Initialization
39 |
40 | When you need a bit more control over the initialization of
41 | highlight.js, you can use the [`highlightBlock`][2] and [`configure`][3]
42 | functions. This allows you to control *what* to highlight and *when*.
43 |
44 | Here's an equivalent way to calling [`initHighlightingOnLoad`][1] using jQuery:
45 |
46 | ```javascript
47 | $(document).ready(function() {
48 | $('pre code').each(function(i, block) {
49 | hljs.highlightBlock(block);
50 | });
51 | });
52 | ```
53 |
54 | You can use any tags instead of `` to mark up your code. If you don't
55 | use a container that preserve line breaks you will need to configure
56 | highlight.js to use the ` ` tag:
57 |
58 | ```javascript
59 | hljs.configure({useBR: true});
60 |
61 | $('div.code').each(function(i, block) {
62 | hljs.highlightBlock(block);
63 | });
64 | ```
65 |
66 | For other options refer to the documentation for [`configure`][3].
67 |
68 |
69 | ## Getting the Library
70 |
71 | You can get highlight.js as a hosted or custom-build browser script or as a
72 | server module. Head over to the [download page][4] for all the options.
73 |
74 | Note, that the library is not supposed to work straight from the source on
75 | GitHub, it requires building. If none of the pre-packaged options work for you
76 | refer to the [building documentation][5].
77 |
78 |
79 | ## License
80 |
81 | Highlight.js is released under the BSD License. See [LICENSE][10] file for
82 | details.
83 |
84 |
85 | ## Links
86 |
87 | The official site for the library is at .
88 |
89 | Further in-depth documentation for the API and other topics is at
90 | .
91 |
92 | Authors and contributors are listed in the [AUTHORS.en.txt][9] file.
93 |
94 | [1]: http://highlightjs.readthedocs.org/en/latest/api.html#inithighlightingonload
95 | [2]: http://highlightjs.readthedocs.org/en/latest/api.html#highlightblock-block
96 | [3]: http://highlightjs.readthedocs.org/en/latest/api.html#configure-options
97 | [4]: https://highlightjs.org/download/
98 | [5]: http://highlightjs.readthedocs.org/en/latest/building-testing.html
99 | [8]: http://highlightjs.readthedocs.org/en/latest/css-classes-reference.html
100 | [9]: https://github.com/isagalaev/highlight.js/blob/master/AUTHORS.en.txt
101 | [10]: https://github.com/isagalaev/highlight.js/blob/master/LICENSE
102 |
--------------------------------------------------------------------------------
/public/vendor/highlight/README.ru.md:
--------------------------------------------------------------------------------
1 | # Highlight.js
2 |
3 | Highlight.js — это подсветчик синтаксиса, написанный на JavaScript. Он работает
4 | и в браузере, и на сервере. Он работает с практически любой HTML разметкой, не
5 | зависит от каких-либо фреймворков и умеет автоматически определять язык.
6 |
7 |
8 | ## Начало работы
9 |
10 | Минимум, что нужно сделать для использования highlight.js на веб-странице — это
11 | подключить библиотеку, CSS-стили и вызывать [`initHighlightingOnLoad`][1]:
12 |
13 | ```html
14 |
15 |
16 |
17 | ```
18 |
19 | Библиотека найдёт и раскрасит код внутри тегов ``, попытавшись
20 | автоматически определить язык. Когда автоопределение не срабатывает, можно явно
21 | указать язык в атрибуте class:
22 |
23 | ```html
24 | ...
25 | ```
26 |
27 | Список поддерживаемых классов языков доступен в [справочнике по классам][8].
28 | Класс также можно предваоить префиксами `language-` или `lang-`.
29 |
30 | Чтобы отключить подсветку для какого-то блока, используйте класс `nohighlight`:
31 |
32 | ```html
33 | ...
34 | ```
35 |
36 | ## Инициализация вручную
37 |
38 | Чтобы иметь чуть больше контроля за инициализацией подсветки, вы можете
39 | использовать функции [`highlightBlock`][2] и [`configure`][3]. Таким образом
40 | можно управлять тем, *что* подсвечивать и *когда*.
41 |
42 | Вот пример инициализация, эквивалентной вызову [`initHighlightingOnLoad`][1], но
43 | с использованием jQuery:
44 |
45 | ```javascript
46 | $(document).ready(function() {
47 | $('pre code').each(function(i, block) {
48 | hljs.highlightBlock(block);
49 | });
50 | });
51 | ```
52 |
53 | Вы можете использовать любые теги разметки вместо ``. Если
54 | используете контейнер, не сохраняющий переводы строк, вам нужно сказать
55 | highlight.js использовать для них тег ` `:
56 |
57 | ```javascript
58 | hljs.configure({useBR: true});
59 |
60 | $('div.code').each(function(i, block) {
61 | hljs.highlightBlock(block);
62 | });
63 | ```
64 |
65 | Другие опции можно найти в документации функции [`configure`][3].
66 |
67 |
68 | ## Установка библиотеки
69 |
70 | Highlight.js можно использовать в браузере прямо с CDN хостинга или скачать
71 | индивидуальную сборку, а также установив модуль на сервере. На
72 | [страница загрузки][4] подробно описаны все варианты.
73 |
74 | Обратите внимание, что библиотека не предназначена для использования в виде
75 | исходного кода на GitHub, а требует отдельной сборки. Если вам не подходит ни
76 | один из готовых вариантов, читайте [документацию по сборке][5].
77 |
78 |
79 | ## Лицензия
80 |
81 | Highlight.js распространяется под лицензией BSD. Подробнее читайте файл
82 | [LICENSE][10].
83 |
84 |
85 | ## Ссылки
86 |
87 | Официальный сайт билиотеки расположен по адресу .
88 |
89 | Более подробная документация по API и другим темам расположена на
90 | .
91 |
92 | Авторы и контрибьютора перечислена в файле [AUTHORS.ru.txt][9] file.
93 |
94 | [1]: http://highlightjs.readthedocs.org/en/latest/api.html#inithighlightingonload
95 | [2]: http://highlightjs.readthedocs.org/en/latest/api.html#highlightblock-block
96 | [3]: http://highlightjs.readthedocs.org/en/latest/api.html#configure-options
97 | [4]: https://highlightjs.org/download/
98 | [5]: http://highlightjs.readthedocs.org/en/latest/building-testing.html
99 | [8]: http://highlightjs.readthedocs.org/en/latest/css-classes-reference.html
100 | [9]: https://github.com/isagalaev/highlight.js/blob/master/AUTHORS.ru.txt
101 | [10]: https://github.com/isagalaev/highlight.js/blob/master/LICENSE
102 |
--------------------------------------------------------------------------------
/routes/about.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function (route) {
4 | route.name = 'about';
5 | route.label = 'About';
6 |
7 | route.get(function (req, res) {
8 | res.render('about', {
9 | activeMenuItem: route.name
10 | });
11 | });
12 | };
13 |
--------------------------------------------------------------------------------
/routes/dust.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var getExamples = require('../lib/examples').get;
4 | var renderExamples = require('../lib/examples').render;
5 | var pkgMeta = require('../lib/package-meta')('dust-intl');
6 |
7 | module.exports = function (route) {
8 | route.name = 'dust';
9 |
10 | route.get(function (req, res, next) {
11 | var isProduction = req.app.get('env') === 'production';
12 |
13 | getExamples('dust', {cache: isProduction}).then(function (examples) {
14 | res.expose(examples, 'examples');
15 | res.expose('integration', 'pageType');
16 |
17 | res.render('dust', {
18 | activeMenuItem: route.name,
19 | usesDustIntl : true,
20 | package : pkgMeta,
21 | examples : renderExamples(examples, res.intl)
22 | });
23 | }).catch(next);
24 | });
25 | };
26 |
--------------------------------------------------------------------------------
/routes/github.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function (route) {
4 | route.name = 'github';
5 | route.label = 'GitHub';
6 |
7 | route.get(function (req, res) {
8 | res.render('github', {
9 | activeMenuItem: route.name
10 | });
11 | });
12 | };
13 |
--------------------------------------------------------------------------------
/routes/guides.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var path = require('path');
4 |
5 | module.exports = function (route) {
6 | route.name = 'guides';
7 | route.label = 'Guides';
8 |
9 | route.get(function (req, res) {
10 | var guide = req.params.guide || 'index';
11 |
12 | res.expose('guide', 'pageType');
13 | res.render(path.join('guides', guide), {
14 | activeMenuItem: route.name
15 | });
16 | });
17 | };
18 |
--------------------------------------------------------------------------------
/routes/handlebars.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var getExamples = require('../lib/examples').get;
4 | var renderExamples = require('../lib/examples').render;
5 | var pkgMeta = require('../lib/package-meta')('handlebars-intl');
6 |
7 | module.exports = function (route) {
8 | route.name = 'handlebars';
9 |
10 | route.get(function (req, res, next) {
11 | var isProduction = req.app.get('env') === 'production';
12 |
13 | getExamples('handlebars', {cache: isProduction})
14 | .then(function (examples) {
15 | res.expose(examples, 'examples');
16 | res.expose('integration', 'pageType');
17 |
18 | res.render('handlebars', {
19 | activeMenuItem : route.name,
20 | usesHandlebarsIntl: true,
21 | package : pkgMeta,
22 | examples : renderExamples(examples, res.intl)
23 | });
24 | }).catch(next);
25 | });
26 | };
27 |
--------------------------------------------------------------------------------
/routes/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var renderComponent = require('../lib/component').render;
4 |
5 | module.exports = function (route) {
6 | route.name = 'home';
7 | route.label = 'Home';
8 |
9 | route.get(function (req, res) {
10 | var splashExample = {
11 | availableNumPhotos: [0, 1, 3, 1000],
12 |
13 | name : 'Annie',
14 | numPhotos: 1000,
15 | takenDate: Date.now()
16 | };
17 |
18 | var now = Date.now();
19 | var lastMonth = new Date(now - (30 * 24 * 60 * 60 * 1000));
20 |
21 | res.expose('home', 'pageType');
22 | res.expose(splashExample, 'examples.splash');
23 |
24 | res.render('home', {
25 | activeMenuItem: route.name,
26 | usesReactIntl : true,
27 |
28 | examples: {
29 | splash: renderComponent('splash-example',
30 | Object.assign({}, res.intl, splashExample)
31 | )
32 | },
33 |
34 | now: now,
35 |
36 | // Had to do this since the Intl.js polyfill doesn't seem to work
37 | // correctly when you _just_ want the year or month. I should follow
38 | // a bug.
39 | lastMonth: [
40 | lastMonth.getFullYear(),
41 | lastMonth.getMonth() + 1,
42 | lastMonth.getDate()
43 | ].join('-')
44 | });
45 | });
46 | };
47 |
--------------------------------------------------------------------------------
/routes/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var utils = require('../lib/utils');
4 |
5 | exports = module.exports = utils.requireDir(__dirname);
6 |
7 | exports.redirect = redirect;
8 |
9 | // -----------------------------------------------------------------------------
10 |
11 | function redirect(url, status) {
12 | return function (req, res) {
13 | res.redirect(status || 302, url);
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/routes/integrations.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function (route) {
4 | route.name = 'integrations';
5 | route.label = 'Integrations';
6 |
7 | route.get(function (req, res) {
8 | res.render('integrations', {
9 | activeMenuItem: route.name
10 | });
11 | });
12 | };
13 |
--------------------------------------------------------------------------------
/routes/react.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var getExamples = require('../lib/examples').get;
4 | var renderExamples = require('../lib/examples').render;
5 | var pkgMeta = require('../lib/package-meta')('react-intl');
6 |
7 | module.exports = function (route) {
8 | route.name = 'react';
9 |
10 | route.get(function (req, res, next) {
11 | var isProduction = req.app.get('env') === 'production';
12 |
13 | getExamples('react', {cache: isProduction}).then(function (examples) {
14 | res.expose(examples, 'examples');
15 | res.expose('integration', 'pageType');
16 |
17 | res.render('react', {
18 | activeMenuItem: route.name,
19 | usesReactIntl : true,
20 | package : pkgMeta,
21 | examples : renderExamples(examples, res.intl)
22 | });
23 | }).catch(next);
24 | });
25 | };
26 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // TODO: Remove this when it is no longer required for Express to work in the
4 | // Manhattan Node.js hosting environment.
5 | process.chdir(__dirname);
6 |
7 | var http = require('http'),
8 | app = require('./app');
9 |
10 | http.createServer(app).listen(app.get('port'), function () {
11 | console.log('%s server listening on: %d', app.get('name'), app.get('port'));
12 | });
13 |
--------------------------------------------------------------------------------
/shared/components/code-block.jsx:
--------------------------------------------------------------------------------
1 | /* global hljs, React */
2 |
3 | export default React.createClass({
4 | displayName: 'CodeBlock',
5 |
6 | propTypes: {
7 | highlight: React.PropTypes.bool,
8 | lang : React.PropTypes.string,
9 | wrap : React.PropTypes.bool
10 | },
11 |
12 | getDefaultProps: function () {
13 | return {highlight: true};
14 | },
15 |
16 | shouldComponentUpdate: function (nextProps) {
17 | // This prevents double syntax highlighting of unchanged content.
18 | return this.props.children !== nextProps.children;
19 | },
20 |
21 | componentDidUpdate: function () {
22 | if (this.props.highlight) {
23 | hljs.highlightBlock(this.refs.code.getDOMNode());
24 | }
25 | },
26 |
27 | render: function () {
28 | var classNames = this.props.wrap ? 'code code-wrap': 'code';
29 | var lang = this.props.highlight ? this.props.lang : 'nohighlight';
30 |
31 | return (
32 |
33 |
34 | {this.props.children}
35 |
36 |
37 | );
38 | }
39 | });
40 |
--------------------------------------------------------------------------------
/shared/components/dust-example.jsx:
--------------------------------------------------------------------------------
1 | /* global React */
2 |
3 | import Example from './example';
4 | import CodeBlock from './code-block';
5 | import DustOutput from './dust-output';
6 | import {Tabs, Tab} from './tabs';
7 |
8 | export default React.createClass({
9 | displayName: 'DustExample',
10 |
11 | propTypes: {
12 | id: React.PropTypes.string.isRequired,
13 |
14 | source: React.PropTypes.shape({
15 | template: React.PropTypes.string.isRequired,
16 | context : React.PropTypes.string.isRequired,
17 | intlData: React.PropTypes.string.isRequired
18 | }).isRequired,
19 |
20 | context : React.PropTypes.object.isRequired,
21 | message : React.PropTypes.string,
22 | formats : React.PropTypes.object,
23 | messages: React.PropTypes.object,
24 |
25 | currentLocale : React.PropTypes.string.isRequired,
26 | availableLocales: React.PropTypes.array.isRequired,
27 | onLocaleChange : React.PropTypes.func.isRequired,
28 | },
29 |
30 | render: function () {
31 | var props = this.props;
32 |
33 | var tabs = [
34 |
35 |
36 | {props.source.template}
37 |
38 | ,
39 |
40 |
41 |
42 | {props.source.context}
43 |
44 | ,
45 |
46 |
47 |
48 | {`context.intl = ${props.source.intlData};
49 |
50 | dust.render(template, context, function (err, html) {
51 | // Put \`html\` into the DOM or use it otherwise...
52 | });`}
53 |
54 |
55 | ];
56 |
57 | // Insert a "Message" tab if the example uses an i18n message.
58 | if (props.message) {
59 | tabs.splice(1, 0,
60 |
61 |
62 | {props.message}
63 |
64 |
65 | );
66 | }
67 |
68 | return (
69 | {tabs}}
75 | output={
76 |
83 | } />
84 | );
85 | }
86 | });
87 |
--------------------------------------------------------------------------------
/shared/components/dust-output.jsx:
--------------------------------------------------------------------------------
1 | /* global React, dust */
2 |
3 | export default React.createClass({
4 | displayName: 'DustOutput',
5 |
6 | propTypes: {
7 | id: React.PropTypes.string.isRequired,
8 | source : React.PropTypes.string.isRequired,
9 | context: React.PropTypes.object.isRequired,
10 |
11 | locales : React.PropTypes.oneOfType([
12 | React.PropTypes.string,
13 | React.PropTypes.array,
14 | ]).isRequired,
15 |
16 | formats : React.PropTypes.object,
17 | messages: React.PropTypes.object
18 | },
19 |
20 | getInitialState: function () {
21 | var tmpl = dust.compile(this.props.source, this.props.id);
22 | dust.loadSource(tmpl);
23 | // The state that we have is the compiled template, but alas this is
24 | // passed through in a side channel (registered inside of dust).
25 | return {};
26 | },
27 |
28 | componentWillReceiveProps: function (nextProps) {
29 | var tmpl;
30 | if (nextProps.source !== this.props.source) {
31 | tmpl = dust.compile(nextProps.source, this.props.id);
32 | dust.loadSource(tmpl);
33 | // The state that we have is the compiled template, but alas this is
34 | // passed through in a side channel (registered inside of dust).
35 | this.setState({});
36 | }
37 | },
38 |
39 | render: function () {
40 | var context = {},
41 | html,
42 | nextTick;
43 |
44 | Object.assign(context, this.props.context, {
45 | intl: {
46 | locales : this.props.locales,
47 | formats : this.props.formats,
48 | messages: this.props.messages
49 | }
50 | });
51 |
52 | // This de-async is hacky, and only works because our example templates
53 | // are simple (don't reference external resources such as partials).
54 | nextTick = dust.nextTick;
55 | dust.nextTick = function(cb) { cb(); };
56 | dust.render(this.props.id, context, function(err, out) {
57 | dust.nextTick = nextTick;
58 | if (!err && out) {
59 | html = out;
60 | }
61 | });
62 |
63 | if (html) {
64 | return (
65 |
68 | );
69 | }
70 | }
71 | });
72 |
--------------------------------------------------------------------------------
/shared/components/example-container.jsx:
--------------------------------------------------------------------------------
1 | /* global React */
2 |
3 | import HandlebarsExample from './handlebars-example';
4 | import ReactExample from './react-example';
5 | import DustExample from './dust-example';
6 |
7 | var INTEGRATION_COMPONENTS = {
8 | handlebars: HandlebarsExample,
9 | react : ReactExample,
10 | dust : DustExample
11 | };
12 |
13 | export default React.createClass({
14 | displayName: 'ExampleContainer',
15 |
16 | propTypes: {
17 | example: React.PropTypes.shape({
18 | id : React.PropTypes.string.isRequired,
19 | name: React.PropTypes.string.isRequired,
20 | meta: React.PropTypes.object.isRequired,
21 |
22 | type: React.PropTypes.oneOf(
23 | Object.keys(INTEGRATION_COMPONENTS)
24 | ).isRequired,
25 |
26 | source: React.PropTypes.shape({
27 | template : React.PropTypes.string,
28 | context : React.PropTypes.string,
29 | component: React.PropTypes.string
30 | }).isRequired,
31 |
32 | // Optional.
33 | getComponent: React.PropTypes.func
34 | }).isRequired,
35 |
36 | intl: React.PropTypes.shape({
37 | availableLocales: React.PropTypes.array.isRequired,
38 |
39 | locales : React.PropTypes.array.isRequired,
40 | messages: React.PropTypes.object.isRequired
41 | }).isRequired
42 | },
43 |
44 | getInitialState: function () {
45 | var intl = this.props.intl;
46 | var preferredLocale = intl.locales[0];
47 | var availableLocales = this.props.intl.availableLocales;
48 | var messageId = this.props.example.meta.messageId;
49 |
50 | // For examples that use messages, limit `availableLocales` to those for
51 | // which there are translations.
52 | if (messageId) {
53 | availableLocales = availableLocales.filter(function (locale) {
54 | return intl.messages[locale].hasOwnProperty(messageId);
55 | });
56 | }
57 |
58 | // Make sure the user's preferredLocale in available, otherwise default
59 | // to "en-US".
60 | var currentLocale = availableLocales.find(function (locale) {
61 | return locale === preferredLocale;
62 | });
63 |
64 | return {
65 | currentLocale : currentLocale || 'en-US',
66 | availableLocales: availableLocales
67 | };
68 | },
69 |
70 | evalContext: function (contextSource) {
71 | if (contextSource) {
72 | // Why? Oh! Why!?
73 | // Ah yes, because we're normalizing template engines
74 | /*jslint evil: true*/
75 | return (new Function(contextSource + '\nreturn context;'))();
76 | /*jslint evil: false*/
77 | }
78 |
79 | return {};
80 | },
81 |
82 | generateIntlData: function () {
83 | var currentLocale = this.state.currentLocale;
84 | var formats = this.props.example.meta.formats;
85 | var messages = this.props.intl.messages[currentLocale];
86 | var messageId = this.props.example.meta.messageId;
87 | var message = messages[messageId];
88 |
89 | if (message) {
90 | messages = {};
91 | messages[messageId] = message;
92 | } else {
93 | messages = null;
94 | }
95 |
96 | var intlData = {
97 | locales: currentLocale
98 | };
99 |
100 | if (messages) { intlData.messages = messages; }
101 | if (formats) { intlData.formats = formats; }
102 |
103 | return intlData;
104 | },
105 |
106 | updateLocale: function (newLocale) {
107 | this.setState({currentLocale: newLocale});
108 | },
109 |
110 | render: function () {
111 | var props = this.props;
112 | var state = this.state;
113 |
114 | var example = props.example;
115 | var ExampleComponent = INTEGRATION_COMPONENTS[example.type];
116 |
117 | var source = Object.assign({}, example.source, {
118 | intlData: JSON.stringify(this.generateIntlData(), null, 4)
119 | });
120 |
121 | var messages = props.intl.messages[state.currentLocale];
122 |
123 | return (
124 |
135 | );
136 | }
137 | });
138 |
--------------------------------------------------------------------------------
/shared/components/example.jsx:
--------------------------------------------------------------------------------
1 | /* global React */
2 |
3 | import LocaleSelect from './locale-select';
4 |
5 | export default React.createClass({
6 | displayName: 'Example',
7 |
8 | propTypes: {
9 | id: React.PropTypes.string.isRequired,
10 |
11 | currentLocale : React.PropTypes.string.isRequired,
12 | availableLocales: React.PropTypes.array.isRequired,
13 | onLocaleChange : React.PropTypes.func.isRequired,
14 |
15 | source: React.PropTypes.element.isRequired,
16 | output: React.PropTypes.element.isRequired,
17 | },
18 |
19 | render: function () {
20 | var props = this.props;
21 |
22 | return (
23 |
24 |
25 | {props.source}
26 |
27 |
28 |
29 |
Rendered
30 |
31 | {props.output}
32 |
33 |
34 |
35 | Locale:
36 |
40 |
41 |
42 |
43 |
44 | );
45 | }
46 | });
47 |
--------------------------------------------------------------------------------
/shared/components/handlebars-example.jsx:
--------------------------------------------------------------------------------
1 | /* global React */
2 |
3 | import Example from './example';
4 | import CodeBlock from './code-block';
5 | import HandlebarsOutput from './handlebars-output';
6 | import {Tabs, Tab} from './tabs';
7 |
8 | export default React.createClass({
9 | displayName: 'HandlebarsExample',
10 |
11 | propTypes: {
12 | id: React.PropTypes.string.isRequired,
13 |
14 | source: React.PropTypes.shape({
15 | template: React.PropTypes.string.isRequired,
16 | context : React.PropTypes.string.isRequired,
17 | intlData: React.PropTypes.string.isRequired
18 | }).isRequired,
19 |
20 | context : React.PropTypes.object.isRequired,
21 | message : React.PropTypes.string,
22 | formats : React.PropTypes.object,
23 | messages: React.PropTypes.object,
24 |
25 | currentLocale : React.PropTypes.string.isRequired,
26 | availableLocales: React.PropTypes.array.isRequired,
27 | onLocaleChange : React.PropTypes.func.isRequired,
28 | },
29 |
30 | render: function () {
31 | var props = this.props;
32 |
33 | var tabs = [
34 |
35 |
36 | {props.source.template}
37 |
38 | ,
39 |
40 |
41 |
42 | {props.source.context}
43 |
44 | ,
45 |
46 |
47 |
48 | {`var intlData = ${props.source.intlData};
49 |
50 | var html = template(context, {
51 | data: {intl: intlData}
52 | });`}
53 |
54 |
55 | ];
56 |
57 | // Insert a "Message" tab if the example uses an i18n message.
58 | if (props.message) {
59 | tabs.splice(1, 0,
60 |
61 |
62 | {props.message}
63 |
64 |
65 | );
66 | }
67 |
68 | return (
69 | {tabs}}
75 | output={
76 |
82 | } />
83 | );
84 | }
85 | });
86 |
--------------------------------------------------------------------------------
/shared/components/handlebars-output.jsx:
--------------------------------------------------------------------------------
1 | /* global React, Handlebars */
2 |
3 | export default React.createClass({
4 | displayName: 'HandlebarsOutput',
5 |
6 | propTypes: {
7 | source : React.PropTypes.string.isRequired,
8 | context : React.PropTypes.object.isRequired,
9 |
10 | locales : React.PropTypes.oneOfType([
11 | React.PropTypes.string,
12 | React.PropTypes.array,
13 | ]).isRequired,
14 |
15 | formats : React.PropTypes.object,
16 | messages: React.PropTypes.object
17 | },
18 |
19 | getInitialState: function () {
20 | return {
21 | template: Handlebars.compile(this.props.source)
22 | };
23 | },
24 |
25 | componentWillReceiveProps: function (nextProps) {
26 | if (nextProps.source !== this.props.source) {
27 | this.setState({
28 | template: Handlebars.compile(nextProps.source)
29 | });
30 | }
31 | },
32 |
33 | render: function () {
34 | var html = this.state.template(this.props.context, {
35 | data: {
36 | intl: {
37 | locales : this.props.locales,
38 | formats : this.props.formats,
39 | messages: this.props.messages
40 | }
41 | }
42 | });
43 |
44 | return (
45 |
48 | );
49 | }
50 | });
51 |
--------------------------------------------------------------------------------
/shared/components/locale-select.jsx:
--------------------------------------------------------------------------------
1 | /* global React */
2 |
3 | export default React.createClass({
4 | displayName: 'LocaleSelect',
5 |
6 | propTypes: {
7 | availableLocales: React.PropTypes.array.isRequired,
8 |
9 | value : React.PropTypes.string,
10 | onChange: React.PropTypes.func,
11 |
12 | valueLink: React.PropTypes.shape({
13 | value : React.PropTypes.string.isRequired,
14 | requestChange: React.PropTypes.func.isRequired
15 | })
16 | },
17 |
18 | getValueLink: function (props) {
19 | return props.valueLink || {
20 | value : props.value,
21 | requestChange: props.onChange
22 | };
23 | },
24 |
25 | handleChange: function (e) {
26 | this.getValueLink(this.props).requestChange(e.target.value);
27 | },
28 |
29 | render: function () {
30 | var value = this.getValueLink(this.props).value;
31 |
32 | return (
33 |
36 |
37 | {this.props.availableLocales.map(function (locale) {
38 | return {locale} ;
39 | })}
40 |
41 | );
42 | }
43 | });
44 |
--------------------------------------------------------------------------------
/shared/components/react-example.jsx:
--------------------------------------------------------------------------------
1 | /* global React */
2 |
3 | import Example from './example';
4 | import CodeBlock from './code-block';
5 | import {Tabs, Tab} from './tabs';
6 |
7 | export default React.createClass({
8 | displayName: 'ReactExample',
9 |
10 | propTypes: {
11 | id : React.PropTypes.string.isRequired,
12 | component: React.PropTypes.func.isRequired,
13 |
14 | source: React.PropTypes.shape({
15 | component: React.PropTypes.string.isRequired,
16 | intlData : React.PropTypes.string.isRequired
17 | }).isRequired,
18 |
19 | message : React.PropTypes.string,
20 | formats : React.PropTypes.object,
21 | messages: React.PropTypes.object,
22 |
23 | currentLocale : React.PropTypes.string.isRequired,
24 | availableLocales: React.PropTypes.array.isRequired,
25 | onLocaleChange : React.PropTypes.func.isRequired,
26 | },
27 |
28 | render: function () {
29 | var props = this.props;
30 | var ExampleComponent = props.component;
31 |
32 | var tabs = [
33 |
34 |
35 | {props.source.component}
36 |
37 | ,
38 |
39 |
40 |
41 | {`var intlData = ${props.source.intlData};
42 |
43 | React.render(
44 | ,
45 | document.getElementById('example')
46 | );`}
47 |
48 |
49 | ];
50 |
51 | // Insert a "Message" tab if the example uses an i18n message.
52 | if (props.message) {
53 | tabs.splice(1, 0,
54 |
55 |
56 | {props.message}
57 |
58 |
59 | );
60 | }
61 |
62 | return (
63 | {tabs}}
69 | output={
70 |
71 |
75 |
76 | } />
77 | );
78 | }
79 | });
80 |
--------------------------------------------------------------------------------
/shared/components/splash-example.jsx:
--------------------------------------------------------------------------------
1 | /* global React, ReactIntl */
2 |
3 | import LocaleSelect from './locale-select';
4 |
5 | var CSSTransitionGroup = React.addons.CSSTransitionGroup;
6 |
7 | export default React.createClass({
8 | displayName: 'SplashExample',
9 |
10 | propTypes: {
11 | name : React.PropTypes.string.isRequired,
12 | numPhotos: React.PropTypes.number.isRequired,
13 | takenDate: React.PropTypes.number.isRequired,
14 |
15 | locales : React.PropTypes.oneOfType([
16 | React.PropTypes.string,
17 | React.PropTypes.array,
18 | ]).isRequired,
19 |
20 | messages: React.PropTypes.object.isRequired,
21 |
22 | availableLocales : React.PropTypes.array.isRequired,
23 | availableNumPhotos: React.PropTypes.array.isRequired
24 | },
25 |
26 | getInitialState: function () {
27 | var locales = this.props.locales;
28 |
29 | return {
30 | currentLocale : Array.isArray(locales) ? locales[0] : locales,
31 | currentNumPhotos: this.props.numPhotos
32 | };
33 | },
34 |
35 | updateLocale: function (newLocale) {
36 | this.setState({currentLocale: newLocale});
37 | },
38 |
39 | handleNumPhotosChange: function (e) {
40 | this.setState({currentNumPhotos: parseInt(e.target.value, 10)});
41 | },
42 |
43 | render: function () {
44 | // This this ref to be lazy.
45 | var {FormattedMessage} = ReactIntl;
46 |
47 | var currentLocale = this.state.currentLocale;
48 | var photosMessage = this.props.messages[currentLocale].photos;
49 |
50 | var numPhotosOptions = this.props.availableNumPhotos.map(function (num) {
51 | return {num} ;
52 | });
53 |
54 | return (
55 |
56 |
Example
57 |
58 |
59 |
62 |
63 |
70 |
71 |
72 |
73 |
98 |
99 | );
100 | }
101 | });
102 |
--------------------------------------------------------------------------------
/shared/components/tabs.jsx:
--------------------------------------------------------------------------------
1 | /* global React */
2 |
3 | export {Tabs, Tab};
4 |
5 | var Tabs = React.createClass({
6 | displayName: 'Tabs',
7 |
8 | getInitialState: function () {
9 | var selectedIndex;
10 |
11 | React.Children.forEach(this.props.children, (tab, index) => {
12 | if (tab.props.selected) {
13 | selectedIndex = index;
14 | }
15 | });
16 |
17 | return {
18 | selectedIndex: selectedIndex || 0
19 | };
20 | },
21 |
22 | getTabPanels: function (tabs) {
23 | return React.Children.map(tabs, (tab, index) => {
24 | return React.cloneElement(tab, {
25 | selected: index === this.state.selectedIndex
26 | });
27 | });
28 | },
29 |
30 | getTabListItems: function (tabs) {
31 | return React.Children.map(tabs, (tab, index) => {
32 | var isSelected = index === this.state.selectedIndex;
33 | var className = 'tabs-tab' + (isSelected ? ' is-selected' : '');
34 |
35 | return (
36 |
41 |
42 | {tab.props.label}
43 |
44 | );
45 | });
46 | },
47 |
48 | handleTabClick: function (e) {
49 | var controlsId;
50 | var index;
51 |
52 | if (e.target.getAttribute('role') === 'tab') {
53 | controlsId = e.target.getAttribute('aria-controls');
54 |
55 | index = this.props.children.findIndex((tab) => {
56 | return tab.props.id === controlsId;
57 | });
58 |
59 | if (index !== this.state.selectedIndex) {
60 | this.setState({
61 | selectedIndex: index
62 | });
63 | }
64 | }
65 | },
66 |
67 | render: function () {
68 | return (
69 |
70 |
73 |
74 | {this.getTabListItems(this.props.children)}
75 |
76 |
77 | {this.getTabPanels(this.props.children)}
78 |
79 | );
80 | }
81 | });
82 |
83 | var Tab = React.createClass({
84 | displayName: 'Tab',
85 |
86 | propTypes: {
87 | id : React.PropTypes.string.isRequired,
88 | label : React.PropTypes.string.isRequired,
89 | selected: React.PropTypes.bool.isRequired
90 | },
91 |
92 | getDefaultProps: function () {
93 | return {
94 | selected: false
95 | };
96 | },
97 |
98 | render: function () {
99 | return (
100 |
105 |
106 | {this.props.children}
107 |
108 | );
109 | }
110 | });
111 |
--------------------------------------------------------------------------------
/tasks/filesize.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint -W079 */
4 | var Promise = global.Promise || require('promise');
5 | /* jshint +W079 */
6 |
7 | var path = require('path'),
8 | utils = require('../lib/utils'),
9 | zlib = require('zlib');
10 |
11 | var gzip = utils.promisify(zlib.gzip);
12 |
13 | function getLength(compressed) {
14 | return compressed.length;
15 | }
16 |
17 | module.exports = function (grunt) {
18 | grunt.registerMultiTask('filesize', 'Calculates the size of gzipped files', function () {
19 | var done = this.async();
20 |
21 | Promise.all(this.files.map(function(file) {
22 | var src = file.src.filter(function(filepath) {
23 | return grunt.file.exists(path.join(file.cwd, filepath));
24 | });
25 |
26 | var sizes = Promise.all(src.map(function(filepath) {
27 | filepath = path.join(file.cwd, filepath);
28 | return gzip(grunt.file.read(filepath)).then(getLength);
29 | }));
30 |
31 | return sizes.then(function (values) {
32 | var result = {};
33 |
34 | values.forEach(function (value, i) {
35 | result[src[i]] = {
36 | bytes: value,
37 | kbs: Math.round(value * 10 / 1024) / 10
38 | };
39 | });
40 |
41 | var output = JSON.stringify(result, null, 4) + '\n';
42 |
43 | // Write joined contents to destination filepath.
44 | grunt.file.write(file.dest, output);
45 | // Print a success message.
46 | grunt.log.writeln('File "' + file.dest + '" created.');
47 |
48 | return result;
49 | });
50 | })).then(function () {
51 | done();
52 | }, done);
53 | });
54 | };
55 |
--------------------------------------------------------------------------------
/tests/fixtures/modules/bar.js:
--------------------------------------------------------------------------------
1 | exports.baz = 'baz';
2 |
--------------------------------------------------------------------------------
/tests/fixtures/modules/foo.js:
--------------------------------------------------------------------------------
1 | module.exports = function () {};
2 |
--------------------------------------------------------------------------------
/tests/fixtures/modules/index.js:
--------------------------------------------------------------------------------
1 | exports.bar = 'bar';
2 |
--------------------------------------------------------------------------------
/tests/functional/includes/date.mock.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | // Create a date object for a specific instant in time (my 36th birthday...)
5 |
6 | var d = new Date();
7 | d.setUTCFullYear(2014, 11, 8);
8 | d.setUTCHours(12, 34, 0, 0);
9 |
10 | // Adjust it based on the time zone offset, so that formatted date/time
11 | // will be what we expect, independent of the time zone (minus the time
12 | // zone name, which is a different story)
13 |
14 | d.setUTCMinutes(d.getUTCMinutes() + d.getTimezoneOffset());
15 |
16 | // Highjack the Date object, and make sure that `new Date()` (without param)
17 | // and `Date.now()` return the time computed above. This will guarantee that
18 | // date/time formatted absolutely does not keep changing, and we can test it
19 | // against a static value.
20 |
21 | var __Date__ = Date;
22 |
23 | Date = function (value) {
24 | return new __Date__(value !== undefined ? value : d.getTime());
25 | };
26 |
27 | Date.now = function () {
28 | return d.getTime();
29 | };
30 | }());
31 |
--------------------------------------------------------------------------------
/tests/functional/includes/fn.bind.polyfill.js:
--------------------------------------------------------------------------------
1 | // Needed for PhantomJS < 2.0
2 |
3 | if (!Function.prototype.bind) {
4 | var Empty = function () {};
5 |
6 | Function.prototype.bind = function bind(that) { // .length is 1
7 | var target = this;
8 |
9 | if (typeof target != 'function') {
10 | throw new TypeError('Function.prototype.bind called on incompatible ' + target);
11 | }
12 |
13 | var args = Array.prototype.slice.call(arguments, 1);
14 |
15 | var binder = function() {
16 | if (this instanceof bound) {
17 | var result = target.apply(
18 | this,
19 | args.concat(Array.prototype.slice.call(arguments))
20 | );
21 | if (Object(result) === result) {
22 | return result;
23 | }
24 | return this;
25 | } else {
26 | return target.apply(
27 | that,
28 | args.concat(Array.prototype.slice.call(arguments))
29 | );
30 | }
31 | };
32 |
33 | var boundLength = Math.max(0, target.length - args.length);
34 | var boundArgs = [];
35 |
36 | for (var i = 0; i < boundLength; i++) {
37 | boundArgs.push('$' + i);
38 | }
39 |
40 | var bound = Function('binder', 'return function(' + boundArgs.join(',') + '){return binder.apply(this,arguments)}')(binder);
41 |
42 | if (target.prototype) {
43 | Empty.prototype = target.prototype;
44 | bound.prototype = new Empty();
45 | // Clean up dangling references.
46 | Empty.prototype = null;
47 | }
48 |
49 | return bound;
50 | };
51 | }
--------------------------------------------------------------------------------
/tests/functional/includes/html.event.polyfill.js:
--------------------------------------------------------------------------------
1 | // Needed for PhantomJS < 2.0
2 |
3 | if (!window.Event || typeof Event !== 'function') {
4 | Event = function (type, cfg) {
5 | var evt = document.createEvent('HTMLEvents');
6 | evt.initEvent(type, cfg.bubbles, cfg.cancelable);
7 | return evt;
8 | };
9 | }
10 |
--------------------------------------------------------------------------------
/tests/functional/integration-tests.js:
--------------------------------------------------------------------------------
1 | /*globals casper */
2 |
3 | // Test the various integration pages.
4 | //
5 | // We limit ourselves to one test per integration page. This may seem low,
6 | // but keep in mind that functional tests are not supposed to be as exhaustive
7 | // as unit tests. Instead, their role is to look at the system as a whole.
8 | // Nevertheless, we test a variety of features of FormatJS and multiple locales
9 | // to try and get the highest possible coverage and confidence that the site is
10 | // working properly.
11 | //
12 | // All the tests basically do the same thing. Load a page, modify the value
13 | // of the locale selection combo box, and check the output of the corresponding
14 | // example with a static value. Because these tests are all the same, they are
15 | // parameterized below.
16 |
17 | 'use strict';
18 |
19 | var testData = {
20 | 'Test React integration example': {
21 | comment: 'Test React integration - Relative time formatting example using ja-JP',
22 | type: 'react',
23 | path: '/react/v1/',
24 | locale: 'ja-JP',
25 | id: 'ex-react-relative',
26 | output_selector: 'li:nth-child(2)',
27 | expected_output: '2 時間前'
28 | },
29 | 'Test Handlebars integration example': {
30 | comment: 'Test Handlebars integration - Number formatting example using es-AR',
31 | type: 'handlebars',
32 | path: '/handlebars/',
33 | locale: 'fr-FR',
34 | id: 'ex-handlebars-number',
35 | output_selector: 'li:nth-child(3)',
36 | expected_output: '100,95\xA0$US'
37 | },
38 | 'Test Dust integration example': {
39 | comment: 'Test Dust integration - Time custom formatting example using cs-CZ',
40 | type: 'dust',
41 | path: '/dust/',
42 | locale: 'cs-CZ',
43 | id: 'ex-dust-custom',
44 | output_selector: 'li:nth-child(3)',
45 | expected_output: '12:34'
46 | }
47 | };
48 |
49 | Object.keys(testData).forEach(function (name) {
50 | var data = testData[name];
51 |
52 | casper.test.begin(name, function (test) {
53 |
54 | test.comment('Loading page...');
55 | casper.start(casper.host + data.path, function () {
56 | test.pass('Page was loaded successfully!');
57 | });
58 |
59 | casper.then(function () {
60 | casper.test.comment(data.comment);
61 |
62 | casper.evaluate(function (id, locale) {
63 | // Change the value of the locale selection combo box...
64 | var el = document.querySelector('#' + id + ' .locale-select');
65 | el.value = locale;
66 |
67 | var evt = new Event('change', { bubbles: true });
68 | el.dispatchEvent(evt);
69 | }, data.id, data.locale);
70 |
71 | // Some tests (example: Ember) run asynchronously...
72 | casper.wait(100, function () {
73 | // Retrieve the example's output...
74 | var output = casper.evaluate(function (selector_output) {
75 | var outputElement = document.querySelector(selector_output);
76 | return outputElement.textContent.trim();
77 | }, '#' + data.id + ' .' + data.type + '-output ' + (data.output_selector || ''));
78 |
79 | test.assertEquals(output, data.expected_output);
80 | });
81 | });
82 |
83 | casper.run(function() {
84 | test.done();
85 | });
86 | });
87 | });
88 |
--------------------------------------------------------------------------------
/tests/functional/splash-example.js:
--------------------------------------------------------------------------------
1 | /*globals casper */
2 |
3 | 'use strict';
4 |
5 | casper.test.begin('Test FormatJS home page splash example', function (test) {
6 |
7 | test.comment('Load home page');
8 | casper.start(casper.host + '/', function () {
9 | test.pass('Page was loaded');
10 | });
11 |
12 | casper.then(function () {
13 | test.comment('Test splash example');
14 |
15 | test.assertExists('.splash-example-container', 'Found splash example container');
16 | test.assertExists('.num-photos-select', 'Found number select');
17 | test.assertExists('.locale-select', 'Found locale select');
18 | test.assertExists('.splash-example-output', 'Found splash example output');
19 |
20 | casper.evaluate(function (numPhotos, locale) {
21 | // Start by setting the takenDate prop to a known value so that we
22 | // can compare the example's output to a static value.
23 | var container = document.querySelector('.splash-example-container');
24 | var component = container.component;
25 | component.setProps({ takenDate: 1423852666565 });
26 |
27 | // Change the value of the # photos combo box...
28 | var numPhotosSelect = document.querySelector('.num-photos-select');
29 | numPhotosSelect.value = numPhotos;
30 |
31 | var chgEvt1 = new Event('change', { bubbles: true });
32 | numPhotosSelect.dispatchEvent(chgEvt1);
33 |
34 | // Change the value of the locale selection combo box...
35 | var localeSelect = document.querySelector('.locale-select');
36 | localeSelect.value = locale;
37 |
38 | var chgEvt2 = new Event('change', { bubbles: true });
39 | localeSelect.dispatchEvent(chgEvt2);
40 | }, 3, 'fr-FR');
41 |
42 | this.wait(1000, function () {
43 | var output = this.evaluate(function () {
44 | // Retrieve the example's output...
45 | var outputElement = document.querySelector('.splash-example-output');
46 | return outputElement.textContent.trim();
47 | });
48 |
49 | test.assertEquals(output, 'Le 13 février 2015, Annie a pris 3 photographies.');
50 | });
51 | });
52 |
53 | casper.run(function () {
54 | test.done();
55 | });
56 | });
57 |
--------------------------------------------------------------------------------
/tests/functional/utils/casper-setup.js:
--------------------------------------------------------------------------------
1 | /*globals casper */
2 |
3 | 'use strict';
4 |
5 | casper.host = 'http://' + casper.cli.options.host;
6 |
7 | casper.on('page.initialized', function () {
8 | casper.page.injectJs('tests/functional/includes/fn.bind.polyfill.js');
9 | casper.page.injectJs('tests/functional/includes/html.event.polyfill.js');
10 | casper.page.injectJs('tests/functional/includes/date.mock.js');
11 | });
12 |
13 | casper.on('page.error', function (msg, trace) {
14 | this.echo('Error: ' + msg, 'ERROR');
15 | this.echo('file: ' + trace[0].file, 'WARNING');
16 | this.echo('line: ' + trace[0].line, 'WARNING');
17 | this.echo('function: ' + trace[0]['function'], 'WARNING');
18 | this.die('Aborted due to JavaScript exception');
19 | });
20 |
21 | // Log any browser console.log messages to grunt
22 | casper.on('remote.message', function(message) {
23 | this.echo('remote message caught: ' + message);
24 | });
25 |
--------------------------------------------------------------------------------
/tests/health-check.js:
--------------------------------------------------------------------------------
1 | // This file checks that we get a HTTP 200 status code and the appropriate
2 | // content type for all the routes defined in the app.
3 |
4 | 'use strict';
5 |
6 | /*global describe, it */
7 |
8 | var path = require('path');
9 | var request = require('supertest');
10 | var utils = require('../lib/utils');
11 | var app = require('../app');
12 | var routes = utils.requireDir(path.join(__dirname, '../routes/'));
13 |
14 | var opt = process.argv[process.argv.length - 1];
15 | var m = opt.match(/^--host=(.*)/);
16 | if (!m) {
17 | throw new Error('Missing required --host parameter');
18 | }
19 |
20 | var host = m[1];
21 |
22 | console.log('Testing host: ' + host);
23 |
24 | request = request(host);
25 |
26 | describe('Functional tests', function () {
27 | Object.keys(routes)
28 | .map(app.getPathTo)
29 | .forEach(function (routePath) {
30 | it('correctly responds on the ' + routePath + ' route', function (done) {
31 | request.get(routePath)
32 | .expect(200)
33 | .expect('Content-Type', 'text/html; charset=utf-8')
34 | .end(done);
35 | });
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/tests/istanbul-hook.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var istanbul = require('istanbul');
4 | var minimatch = require('minimatch');
5 |
6 | // Set of files we want Istanbul to _really_ ignore.
7 | var IGNORE_FILES = [
8 | '**/node_modules/**'
9 | ];
10 |
11 | function isIgnoredFile(file) {
12 | return IGNORE_FILES.some(function (pattern) {
13 | return minimatch(file, pattern);
14 | });
15 | }
16 |
17 | // Override Istanbul's `require()` hook, so that certain modules, like
18 | // polyfills, can be _really_ ignored from Istanbul coverage numbers.
19 | var istanbulRequireHook = istanbul.hook.hookRequire;
20 | istanbul.hook.hookRequire = function (matcher, transformer, options) {
21 | istanbulRequireHook(matcher, function (code, filename) {
22 | if (isIgnoredFile(filename)) {
23 | console.log('Ignoring from code coverage: %s', filename);
24 | return code;
25 | }
26 |
27 | return transformer(code, filename);
28 | }, options);
29 | };
30 |
31 | // Satisfy post-require-hook interface.
32 | module.exports = function () {};
33 |
--------------------------------------------------------------------------------
/tests/unit/lib.component.js:
--------------------------------------------------------------------------------
1 | /*global describe, it*/
2 | var components = require('../../lib/component');
3 | var expect = require('chai').expect;
4 |
5 | if (!global.React) {
6 | global.React = require('react');
7 | }
8 |
9 | describe('Component', function () {
10 | describe('require()', function () {
11 | it('returns an object', function () {
12 | expect(components.require('code-block'))
13 | .to.be.a('function');
14 | });
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/tests/unit/lib.examples.js:
--------------------------------------------------------------------------------
1 | /*global describe, it*/
2 | if (!global.Promise) {
3 | global.Promise = require('promise');
4 | }
5 |
6 | var examples = require('../../lib/examples');
7 | var chai = require('chai');
8 | var chaiAsPromised = require("chai-as-promised");
9 | var expect = chai.use(chaiAsPromised).expect;
10 |
11 | describe('Examples', function () {
12 | describe('get()', function () {
13 | it('throws when no type is provided', function () {
14 | expect(function () {
15 | return examples.get();
16 | }).to.throw();
17 | });
18 | it('gets all the Dust examples', function () {
19 | return expect(examples.get('dust'))
20 | .to.eventually.be.an('array');
21 | });
22 | it('gets all the Handlebars examples', function () {
23 | return expect(examples.get('handlebars'))
24 | .to.eventually.be.an('array');
25 | });
26 | it('throws for unknown example types', function () {
27 | return expect(examples.get('unknown template engine'))
28 | .to.eventually.be.rejected;
29 | });
30 | it('gets all the React examples', function () {
31 | return expect(examples.get('react', { cache: true }))
32 | .to.eventually.be.an('array');
33 | });
34 | it('gets all the cached React examplex', function () {
35 | return expect(examples.get('react', { cache: true }))
36 | .to.eventually.be.an('array');
37 | });
38 | });
39 | describe('render', function () {
40 | it('throws when no examples are provided', function () {
41 | expect(function () {
42 | return examples.render();
43 | }).to.throw();
44 | });
45 | it('throws when no intl object is provided', function () {
46 | expect(function () {
47 | examples.render([]);
48 | }).to.throw();
49 | expect(function () {
50 | examples.render([], 'hello');
51 | }).to.throw();
52 | });
53 | });
54 | });
55 |
--------------------------------------------------------------------------------
/tests/unit/lib.helpers.js:
--------------------------------------------------------------------------------
1 | /*global describe, it, before, after*/
2 | var helpers = require('../../lib/helpers');
3 | var chai = require('chai');
4 | var Handlebars = require('handlebars');
5 |
6 | chai.use(require("chai-as-promised"));
7 |
8 | var expect = chai.expect;
9 |
10 | describe('Helpers', function () {
11 | describe('isEqual', function () {
12 | it('should work as triple equals', function () {
13 | var foo = {};
14 | var bar = {};
15 | expect(helpers.isEqual(foo, foo)).to.equal(true);
16 | expect(helpers.isEqual(foo, bar)).to.equal(false);
17 | });
18 | });
19 |
20 | describe('setTitle', function () {
21 | it('should update the `title` property', function () {
22 | var obj = {};
23 | helpers.setTitle.call(obj, 'hello');
24 | expect(obj).to.have.property('title')
25 | .that.equals('hello');
26 | });
27 | });
28 |
29 | describe('title', function () {
30 | it('returns either the title or the brand', function () {
31 | var obj = {
32 | brand: 'qwer'
33 | };
34 | expect(helpers.title.call(obj) + '').to.equal(obj.brand);
35 | helpers.setTitle.call(obj, 'hello');
36 | expect(helpers.title.call(obj) + '').to.equal('hello — qwer');
37 | });
38 | });
39 |
40 | describe('setDescription', function () {
41 | it('should update the `description` property', function () {
42 | var obj = {};
43 | helpers.setDescription.call(obj, 'hello', 'world', {});
44 | expect(obj).to.have.property('description')
45 | .that.equals('helloworld');
46 | });
47 | });
48 |
49 | describe('description', function () {
50 | it('returns either the tagline or the description', function () {
51 | var obj = {
52 | tagline: 'cachai'
53 | };
54 | expect(helpers.description.call(obj)).to.equal(obj.tagline);
55 | helpers.setDescription.call(obj, 'hello', {});
56 | expect(helpers.description.call(obj)).to.equal('hello');
57 | });
58 | });
59 |
60 | describe('code', function () {
61 | before(function () {
62 | Handlebars.registerHelper('code', helpers.code);
63 | });
64 | after(function () {
65 | Handlebars.unregisterHelper('code');
66 | });
67 |
68 | it('throws when a string is not passed', function () {
69 | expect(function () {
70 | return helpers.code();
71 | }).to.throw();
72 | });
73 | it('wraps inline clode', function () {
74 | expect(helpers.code('asdf', {}) + '').to.equal('asdf
');
75 | });
76 | it('trims and wraps code blocks', function () {
77 | var template = Handlebars.compile('{{#code "js"}}\n\thello();\n{{/code}}');
78 | var result = template({});
79 |
80 | expect(result).to.equal('hello();
');
81 | });
82 | it('optionally disables highlight', function () {
83 | var template = Handlebars.compile('{{#code highlight=false}}\n\thello();\n{{/code}}');
84 | var result = template({});
85 |
86 | expect(result).to.equal('hello();
');
87 | });
88 | it('optionally adds a wrap class', function () {
89 | var template = Handlebars.compile('{{#code "js" wrap=true}}\n\thello();\n{{/code}}');
90 | var result = template({});
91 |
92 | expect(result).to.equal('hello();
');
93 | });
94 | });
95 |
96 | describe('npmLink', function () {
97 | it('points to npm correctly', function () {
98 | expect(helpers.npmLink('asdf') + '').to.equal(
99 | 'asdf
'
100 | );
101 | });
102 | });
103 |
104 | describe('releaseDownloadUrl', function () {
105 | it('points to github correctly', function () {
106 | expect(helpers.releaseDownloadUrl('dust-intl', '1.0.0'))
107 | .to.equal('https://github.com/yahoo/dust-intl/archive/v1.0.0.tar.gz');
108 | });
109 | });
110 |
111 | describe('size', function () {
112 | it('should throw for unrecognized modules', function () {
113 | expect(function () {
114 | return helpers.size(Math.random());
115 | }).to.throw();
116 | });
117 |
118 | it('should use the values config.libSizes', function () {
119 | var sizes = require('../../config').libSizes;
120 | sizes['fake-foo-bar'] = {
121 | "bytes": 999,
122 | "kbs": 0.98
123 | };
124 | Object.keys(sizes).forEach(function (module) {
125 | var size = helpers.size(module);
126 |
127 | if (sizes[module].bytes < 1024) {
128 | expect(size).to.equal(sizes[module].bytes + ' bytes');
129 | } else {
130 | expect(size).to.equal(sizes[module].kbs + ' KB');
131 | }
132 | });
133 | });
134 | });
135 |
136 | describe('cdnUrl', function () {
137 | it('returns a rawgit url', function () {
138 | var version = require('dust-intl/package.json').version;
139 |
140 | expect(helpers.cdnUrl('dust-intl/'))
141 | .to.equal('https://cdn.rawgit.com/yahoo/dust-intl/v' + version + '//');
142 | });
143 | });
144 | });
145 |
--------------------------------------------------------------------------------
/tests/unit/lib.messages.js:
--------------------------------------------------------------------------------
1 | /*global describe, it*/
2 | if (!global.Promise) {
3 | global.Promise = require('promise');
4 | }
5 |
6 | var messages = require('../../lib/messages');
7 | var chai = require('chai');
8 | var chaiAsPromised = require("chai-as-promised");
9 | var fs = require('fs');
10 | var path = require('path');
11 | var expect = chai.use(chaiAsPromised).expect;
12 |
13 | describe('Messages', function () {
14 | describe('getMessages', function () {
15 | it('returns an object with one key for each language in /i18n', function () {
16 | var languages = fs.readdirSync('./i18n')
17 | .filter(function (filename) {
18 | return path.extname(filename) === '.yaml';
19 | })
20 | .map(function (filename) {
21 | return path.basename(filename, '.yaml');
22 | });
23 | return expect(messages())
24 | .to.eventually.have.keys(languages);
25 | });
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/tests/unit/lib.package-meta.js:
--------------------------------------------------------------------------------
1 | /*global describe, it*/
2 | var pkgMeta = require('../../lib/package-meta');
3 | var expect = require('chai').expect;
4 |
5 | describe('Package Meta', function () {
6 | it('returns the meta information for installed packages', function () {
7 | expect(pkgMeta('dust-intl'))
8 | .to.have.keys([
9 | 'name',
10 | 'version',
11 | 'description',
12 | 'dist',
13 | 'hasDownload'
14 | ])
15 | .and.to.have.property('dist')
16 | .that.is.an('object')
17 | .with.keys(['main', 'withLocales', 'localeData']);
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/tests/unit/lib.utils.js:
--------------------------------------------------------------------------------
1 | /*global describe, it*/
2 | var fs = require('fs');
3 | var path = require('path');
4 | var utils = require('../../lib/utils');
5 | var chai = require('chai');
6 | var chaiAsPromised = require("chai-as-promised");
7 | var expect = chai.use(chaiAsPromised).expect;
8 |
9 | describe('Utils', function () {
10 | describe('error()', function () {
11 | it('constructs an error object', function () {
12 | expect(utils.error(400))
13 | .to.be.instanceof(Error)
14 | .and.to.have.property('status')
15 | .that.equals(400);
16 | });
17 | });
18 | describe('requireDir', function () {
19 | it('returns an object with a key for each module', function () {
20 | var dirPath = path.resolve('./tests/fixtures/modules/');
21 |
22 | var files = fs.readdirSync(dirPath)
23 | .filter(function (file) {
24 | return file !== 'index.js' && path.extname(file) === '.js';
25 | })
26 | .map(function (file) {
27 | return path.basename(file, '.js');
28 | });
29 |
30 | expect(utils.requireDir(dirPath))
31 | .to.be.an('object')
32 | .with.keys(files);
33 | });
34 | });
35 | describe('promisify', function () {
36 | it('returns a function that fulfills promises', function () {
37 | function delay(ms, value, callback) {
38 | setTimeout(function () {
39 | callback(undefined, value);
40 | }, ms);
41 | }
42 |
43 | expect(utils.promisify(delay)).to.be.a('function');
44 |
45 | var fn = utils.promisify(delay);
46 |
47 | return expect(fn(1, true))
48 | .to.eventually.equal(true);
49 | });
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/tests/unit/middleware.intl.js:
--------------------------------------------------------------------------------
1 | /*global describe, it*/
2 | var express = require('express');
3 | var request = require('supertest');
4 | var expstate = require('express-state');
5 | var expect = require('chai').expect;
6 | var intl = require('../../middleware/intl');
7 |
8 | var app = express();
9 | expstate.extend(app);
10 | app.use(intl);
11 |
12 | app.get('/', function (req, res) {
13 | res.end(JSON.stringify({
14 | intl: res.intl,
15 | locals: res.locals
16 | }));
17 | });
18 |
19 | describe('Intl middleware', function () {
20 | it.skip('exposes an intl object', function (done) {
21 | request(app).get('/')
22 | .expect(200)
23 | .expect(function (res) {
24 | var data = JSON.parse(res.text.trim());
25 |
26 | expect(data).to.have.property('intl')
27 | .that.is.an('object')
28 | .with.ownProperty('locales')
29 | .and.with.ownProperty('messages');
30 | expect(data.intl.locales).to.be.an('array');
31 | expect(data.locals).to.have.property('data')
32 | .that.is.an('object')
33 | .with.property('intl');
34 | })
35 | .end(done);
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/views/examples/dust/custom/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | price : 1400.34,
3 | timestamp: 1390518044403,
4 | now : new Date(),
5 | yesterday: Date.now() - (1000 * 60 * 60 * 24)
6 | };
7 |
--------------------------------------------------------------------------------
/views/examples/dust/custom/meta.yaml:
--------------------------------------------------------------------------------
1 | formats:
2 | date:
3 | short:
4 | day: numeric
5 | month: long
6 | year: numeric
7 |
8 | time:
9 | hhmm:
10 | hour: numeric
11 | minute: numeric
12 |
13 | number:
14 | USD:
15 | style: currency
16 | currency: USD
17 |
18 | relative:
19 | hours:
20 | units: hour
21 | style: numeric
22 |
--------------------------------------------------------------------------------
/views/examples/dust/custom/template.dust:
--------------------------------------------------------------------------------
1 |
2 | {@formatNumber val=price formatName="USD"/}
3 | {@formatDate val=timestamp formatName="short"/}
4 | {@formatTime val=now formatName="hhmm"/}
5 | {@formatRelative val=yesterday formatName="hours"/}
6 |
7 |
--------------------------------------------------------------------------------
/views/examples/dust/date/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | date: new Date()
3 | };
4 |
--------------------------------------------------------------------------------
/views/examples/dust/date/template.dust:
--------------------------------------------------------------------------------
1 | {@formatDate val=date month="long" day="numeric" year="numeric"/}
2 |
--------------------------------------------------------------------------------
/views/examples/dust/dateCustom/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | date: new Date()
3 | };
4 |
--------------------------------------------------------------------------------
/views/examples/dust/dateCustom/meta.yaml:
--------------------------------------------------------------------------------
1 | formats:
2 | date:
3 | short:
4 | day: numeric
5 | month: long
6 | year: numeric
7 |
--------------------------------------------------------------------------------
/views/examples/dust/dateCustom/template.dust:
--------------------------------------------------------------------------------
1 | {@formatDate val=date formatName="short"/}
2 |
--------------------------------------------------------------------------------
/views/examples/dust/intl/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | date: new Date()
3 | };
4 |
--------------------------------------------------------------------------------
/views/examples/dust/intl/template.dust:
--------------------------------------------------------------------------------
1 |
2 | {@formatDate val=date day="numeric" month="long"/}
3 | (current locale)
4 |
5 |
6 | {@intl locales="fr-FR"}
7 |
8 | {@formatDate val=date day="numeric" month="long"/}
9 | ("fr-FR" locale)
10 |
11 | {/intl}
12 |
--------------------------------------------------------------------------------
/views/examples/dust/message/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | name : 'Annie',
3 | numPhotos: 1000,
4 | takenDate: Date.now()
5 | };
6 |
--------------------------------------------------------------------------------
/views/examples/dust/message/meta.yaml:
--------------------------------------------------------------------------------
1 | messageId: photos
2 |
--------------------------------------------------------------------------------
/views/examples/dust/message/template.dust:
--------------------------------------------------------------------------------
1 |
2 | {@formatMessage _key="photos"
3 | name=name
4 | numPhotos=numPhotos
5 | takenDate=takenDate/}
6 |
7 |
--------------------------------------------------------------------------------
/views/examples/dust/number/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | num : 42000,
3 | completed: 0.9,
4 | price : 100.95
5 | };
6 |
--------------------------------------------------------------------------------
/views/examples/dust/number/template.dust:
--------------------------------------------------------------------------------
1 |
2 | {@formatNumber val=num/}
3 | {@formatNumber val=completed style="percent"/}
4 | {@formatNumber val=price style="currency" currency="USD"/}
5 |
6 |
--------------------------------------------------------------------------------
/views/examples/dust/numberCustom/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | num : 42000,
3 | completed: 0.9,
4 | price : 100.95
5 | };
6 |
--------------------------------------------------------------------------------
/views/examples/dust/numberCustom/meta.yaml:
--------------------------------------------------------------------------------
1 | formats:
2 | number:
3 | USD:
4 | style: currency
5 | currency: USD
6 | percentage:
7 | style: percent
8 |
--------------------------------------------------------------------------------
/views/examples/dust/numberCustom/template.dust:
--------------------------------------------------------------------------------
1 |
2 | {@formatNumber val=num/}
3 | {@formatNumber val=completed formatName="percentage"/}
4 | {@formatNumber val=price formatName="USD"/}
5 |
6 |
--------------------------------------------------------------------------------
/views/examples/dust/relative/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | postDate : Date.now() - (1000 * 60 * 60 * 24),
3 | commentDate: Date.now() - (1000 * 60 * 60 * 2),
4 | meetingDate: Date.now() + (1000 * 60 * 51)
5 | };
6 |
--------------------------------------------------------------------------------
/views/examples/dust/relative/template.dust:
--------------------------------------------------------------------------------
1 |
2 | {@formatRelative val=postDate/}
3 | {@formatRelative val=commentDate/}
4 | {@formatRelative val=meetingDate/}
5 |
6 |
--------------------------------------------------------------------------------
/views/examples/dust/relativeCustom/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | postDate: Date.now() - (1000 * 60 * 60 * 24),
3 | lastTrip: Date.now() - (1000 * 60 * 60 * 24 * 2)
4 | };
5 |
--------------------------------------------------------------------------------
/views/examples/dust/relativeCustom/meta.yaml:
--------------------------------------------------------------------------------
1 | formats:
2 | relative:
3 | hours:
4 | units: hour
5 | style: numeric
6 |
--------------------------------------------------------------------------------
/views/examples/dust/relativeCustom/template.dust:
--------------------------------------------------------------------------------
1 |
2 | {@formatRelative val=postDate/} (best fit)
3 | {@formatRelative val=postDate formatName="hours"/} (hours, numeric)
4 |
5 |
6 | {@formatRelative val=lastTrip/} (best fit)
7 | {@formatRelative val=lastTrip formatName="hours"/} (hours, numeric)
8 |
9 |
--------------------------------------------------------------------------------
/views/examples/dust/relativeStyle/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | postDate: Date.now() - (1000 * 60 * 60 * 24),
3 | lastTrip: Date.now() - (1000 * 60 * 60 * 24 * 380)
4 | };
5 |
--------------------------------------------------------------------------------
/views/examples/dust/relativeStyle/template.dust:
--------------------------------------------------------------------------------
1 |
2 | {@formatRelative val=postDate/} (best fit)
3 | {@formatRelative val=postDate style="numeric"/} (numeric)
4 |
5 |
6 | {@formatRelative val=lastTrip/} (best fit)
7 | {@formatRelative val=lastTrip style="numeric"/} (numeric)
8 |
9 |
--------------------------------------------------------------------------------
/views/examples/dust/relativeUnits/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | postDate: Date.now() - (1000 * 60 * 60 * 22),
3 | lastTrip: Date.now() - (1000 * 60 * 60 * 24 * 70)
4 | };
5 |
--------------------------------------------------------------------------------
/views/examples/dust/relativeUnits/template.dust:
--------------------------------------------------------------------------------
1 |
2 | {@formatRelative val=postDate/} (best fit)
3 | {@formatRelative val=postDate units="minute"/} (in minutes)
4 |
5 |
6 | {@formatRelative val=lastTrip/} (best fit)
7 | {@formatRelative val=lastTrip units="day"/} (in days)
8 |
9 |
--------------------------------------------------------------------------------
/views/examples/dust/time/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | date: new Date()
3 | };
4 |
--------------------------------------------------------------------------------
/views/examples/dust/time/template.dust:
--------------------------------------------------------------------------------
1 | {@formatTime val=date hour="numeric" minute="numeric" timeZone="UTC"/}
2 |
--------------------------------------------------------------------------------
/views/examples/ember/date/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | date: new Date()
3 | };
4 |
--------------------------------------------------------------------------------
/views/examples/ember/date/template.hbs:
--------------------------------------------------------------------------------
1 | {{format-date date day="numeric" month="long" year="numeric"}}
2 |
--------------------------------------------------------------------------------
/views/examples/ember/message/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | name : 'Annie',
3 | numPhotos: 1000,
4 | takenDate: Date.now()
5 | };
6 |
--------------------------------------------------------------------------------
/views/examples/ember/message/meta.yaml:
--------------------------------------------------------------------------------
1 | messageId: photos
2 |
--------------------------------------------------------------------------------
/views/examples/ember/message/template.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{format-message (intl-get "messages.photos")
3 | name=name
4 | numPhotos=numPhotos
5 | takenDate=takenDate}}
6 |
7 |
--------------------------------------------------------------------------------
/views/examples/ember/number/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | num : 42000,
3 | completed: 0.9,
4 | price : 100.95
5 | };
6 |
--------------------------------------------------------------------------------
/views/examples/ember/number/template.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{format-number num}}
3 | {{format-number completed style="percent"}}
4 | {{format-number price style="currency" currency="USD"}}
5 |
6 |
--------------------------------------------------------------------------------
/views/examples/ember/relative/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | postDate : Date.now() - (1000 * 60 * 60 * 24),
3 | commentDate: Date.now() - (1000 * 60 * 60 * 2),
4 | meetingDate: Date.now() + (1000 * 60 * 51)
5 | };
6 |
--------------------------------------------------------------------------------
/views/examples/ember/relative/template.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{format-relative postDate}}
3 | {{format-relative commentDate}}
4 | {{format-relative meetingDate}}
5 |
6 |
--------------------------------------------------------------------------------
/views/examples/ember/relativeStyle/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | postDate: Date.now() - (1000 * 60 * 60 * 24),
3 | lastTrip: Date.now() - (1000 * 60 * 60 * 24 * 380)
4 | };
5 |
--------------------------------------------------------------------------------
/views/examples/ember/relativeStyle/template.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{format-relative postDate}} (best fit)
3 | {{format-relative postDate style="numeric"}} (numeric)
4 |
5 |
6 | {{format-relative lastTrip}} (best fit)
7 | {{format-relative lastTrip style="numeric"}} (numeric)
8 |
9 |
--------------------------------------------------------------------------------
/views/examples/ember/relativeUnits/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | postDate: Date.now() - (1000 * 60 * 60 * 22),
3 | lastTrip: Date.now() - (1000 * 60 * 60 * 24 * 70)
4 | };
5 |
--------------------------------------------------------------------------------
/views/examples/ember/relativeUnits/template.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{format-relative postDate}} (best fit)
3 | {{format-relative postDate units="minute"}} (in minutes)
4 |
5 |
6 | {{format-relative lastTrip}} (best fit)
7 | {{format-relative lastTrip units="day"}} (in days)
8 |
9 |
--------------------------------------------------------------------------------
/views/examples/handlebars/custom/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | price : 1400.34,
3 | timestamp: 1390518044403,
4 | now : new Date(),
5 | yesterday: Date.now() - (1000 * 60 * 60 * 24)
6 | };
7 |
--------------------------------------------------------------------------------
/views/examples/handlebars/custom/meta.yaml:
--------------------------------------------------------------------------------
1 | formats:
2 | date:
3 | short:
4 | day: numeric
5 | month: long
6 | year: numeric
7 |
8 | time:
9 | hhmm:
10 | hour: numeric
11 | minute: numeric
12 |
13 | number:
14 | USD:
15 | style: currency
16 | currency: USD
17 |
18 | relative:
19 | hours:
20 | units: hour
21 | style: numeric
22 |
--------------------------------------------------------------------------------
/views/examples/handlebars/custom/template.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{formatNumber price "USD"}}
3 | {{formatDate timestamp "short"}}
4 | {{formatTime now "hhmm"}}
5 | {{formatRelative yesterday "hours"}}
6 |
7 |
--------------------------------------------------------------------------------
/views/examples/handlebars/date/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | date: new Date()
3 | };
4 |
--------------------------------------------------------------------------------
/views/examples/handlebars/date/template.hbs:
--------------------------------------------------------------------------------
1 | {{formatDate date day="numeric" month="long" year="numeric"}}
2 |
--------------------------------------------------------------------------------
/views/examples/handlebars/dateCustom/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | date: new Date()
3 | };
4 |
--------------------------------------------------------------------------------
/views/examples/handlebars/dateCustom/meta.yaml:
--------------------------------------------------------------------------------
1 | formats:
2 | date:
3 | short:
4 | day: numeric
5 | month: long
6 | year: numeric
7 |
--------------------------------------------------------------------------------
/views/examples/handlebars/dateCustom/template.hbs:
--------------------------------------------------------------------------------
1 | {{formatDate date "short"}}
2 |
--------------------------------------------------------------------------------
/views/examples/handlebars/intl/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | date: new Date()
3 | };
4 |
--------------------------------------------------------------------------------
/views/examples/handlebars/intl/template.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{formatDate date day="numeric" month="long"}}
3 | (current locale)
4 |
5 |
6 | {{#intl locales="fr-FR"}}
7 |
8 | {{formatDate date day="numeric" month="long"}}
9 | ("fr-FR" locale)
10 |
11 | {{/intl}}
12 |
--------------------------------------------------------------------------------
/views/examples/handlebars/message/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | name : 'Annie',
3 | numPhotos: 1000,
4 | takenDate: Date.now()
5 | };
6 |
--------------------------------------------------------------------------------
/views/examples/handlebars/message/meta.yaml:
--------------------------------------------------------------------------------
1 | messageId: photos
2 |
--------------------------------------------------------------------------------
/views/examples/handlebars/message/template.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{formatMessage (intlGet "messages.photos")
3 | name=name
4 | numPhotos=numPhotos
5 | takenDate=takenDate}}
6 |
7 |
--------------------------------------------------------------------------------
/views/examples/handlebars/number/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | num : 42000,
3 | completed: 0.9,
4 | price : 100.95
5 | };
6 |
--------------------------------------------------------------------------------
/views/examples/handlebars/number/template.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{formatNumber num}}
3 | {{formatNumber completed style="percent"}}
4 | {{formatNumber price style="currency" currency="USD"}}
5 |
6 |
--------------------------------------------------------------------------------
/views/examples/handlebars/numberCustom/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | num : 42000,
3 | completed: 0.9,
4 | price : 100.95
5 | };
6 |
--------------------------------------------------------------------------------
/views/examples/handlebars/numberCustom/meta.yaml:
--------------------------------------------------------------------------------
1 | formats:
2 | number:
3 | USD:
4 | style: currency
5 | currency: USD
6 | percentage:
7 | style: percent
8 |
--------------------------------------------------------------------------------
/views/examples/handlebars/numberCustom/template.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{formatNumber num}}
3 | {{formatNumber completed "percentage"}}
4 | {{formatNumber price "USD"}}
5 |
6 |
--------------------------------------------------------------------------------
/views/examples/handlebars/relative/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | postDate : Date.now() - (1000 * 60 * 60 * 24),
3 | commentDate: Date.now() - (1000 * 60 * 60 * 2),
4 | meetingDate: Date.now() + (1000 * 60 * 51)
5 | };
6 |
--------------------------------------------------------------------------------
/views/examples/handlebars/relative/template.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{formatRelative postDate}}
3 | {{formatRelative commentDate}}
4 | {{formatRelative meetingDate}}
5 |
6 |
--------------------------------------------------------------------------------
/views/examples/handlebars/relativeCustom/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | postDate: Date.now() - (1000 * 60 * 60 * 24),
3 | lastTrip: Date.now() - (1000 * 60 * 60 * 24 * 2)
4 | };
5 |
--------------------------------------------------------------------------------
/views/examples/handlebars/relativeCustom/meta.yaml:
--------------------------------------------------------------------------------
1 | formats:
2 | relative:
3 | hours:
4 | units: hour
5 | style: numeric
6 |
--------------------------------------------------------------------------------
/views/examples/handlebars/relativeCustom/template.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{formatRelative postDate}} (best fit)
3 | {{formatRelative postDate "hours"}} (hours, numeric)
4 |
5 |
6 | {{formatRelative lastTrip}} (best fit)
7 | {{formatRelative lastTrip "hours"}} (hours, numeric)
8 |
9 |
--------------------------------------------------------------------------------
/views/examples/handlebars/relativeStyle/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | postDate: Date.now() - (1000 * 60 * 60 * 24),
3 | lastTrip: Date.now() - (1000 * 60 * 60 * 24 * 380)
4 | };
5 |
--------------------------------------------------------------------------------
/views/examples/handlebars/relativeStyle/template.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{formatRelative postDate}} (best fit)
3 | {{formatRelative postDate style="numeric"}} (numeric)
4 |
5 |
6 | {{formatRelative lastTrip}} (best fit)
7 | {{formatRelative lastTrip style="numeric"}} (numeric)
8 |
9 |
--------------------------------------------------------------------------------
/views/examples/handlebars/relativeUnits/context.js:
--------------------------------------------------------------------------------
1 | var context = {
2 | postDate: Date.now() - (1000 * 60 * 60 * 22),
3 | lastTrip: Date.now() - (1000 * 60 * 60 * 24 * 70)
4 | };
5 |
--------------------------------------------------------------------------------
/views/examples/handlebars/relativeUnits/template.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{formatRelative postDate}} (best fit)
3 | {{formatRelative postDate units="minute"}} (in minutes)
4 |
5 |
6 | {{formatRelative lastTrip}} (best fit)
7 | {{formatRelative lastTrip units="day"}} (in days)
8 |
9 |
--------------------------------------------------------------------------------
/views/examples/react/custom/component.jsx:
--------------------------------------------------------------------------------
1 | var IntlMixin = ReactIntl.IntlMixin;
2 | var FormattedNumber = ReactIntl.FormattedNumber;
3 | var FormattedDate = ReactIntl.FormattedDate;
4 | var FormattedTime = ReactIntl.FormattedTime;
5 | var FormattedRelative = ReactIntl.FormattedRelative;
6 |
7 | var Component = React.createClass({
8 | mixins: [IntlMixin],
9 |
10 | render: function () {
11 | var yesterday = Date.now() - (1000 * 60 * 60 * 24);
12 |
13 | return (
14 |
20 | );
21 | }
22 | });
23 |
--------------------------------------------------------------------------------
/views/examples/react/custom/meta.yaml:
--------------------------------------------------------------------------------
1 | formats:
2 | date:
3 | short:
4 | day: numeric
5 | month: long
6 | year: numeric
7 |
8 | time:
9 | hhmm:
10 | hour: numeric
11 | minute: numeric
12 |
13 | number:
14 | USD:
15 | style: currency
16 | currency: USD
17 | minimumFractionDigits: 2
18 |
19 | relative:
20 | hours:
21 | units: hour
22 | style: numeric
23 |
--------------------------------------------------------------------------------
/views/examples/react/date/component.jsx:
--------------------------------------------------------------------------------
1 | var IntlMixin = ReactIntl.IntlMixin;
2 | var FormattedDate = ReactIntl.FormattedDate;
3 |
4 | var Component = React.createClass({
5 | mixins: [IntlMixin],
6 |
7 | render: function () {
8 | return (
9 |
10 |
15 |
16 | );
17 | }
18 | });
19 |
--------------------------------------------------------------------------------
/views/examples/react/dateCustom/component.jsx:
--------------------------------------------------------------------------------
1 | var IntlMixin = ReactIntl.IntlMixin;
2 | var FormattedDate = ReactIntl.FormattedDate;
3 |
4 | var Component = React.createClass({
5 | mixins: [IntlMixin],
6 |
7 | render: function () {
8 | return (
9 |
10 |
11 |
12 | );
13 | }
14 | });
15 |
--------------------------------------------------------------------------------
/views/examples/react/dateCustom/meta.yaml:
--------------------------------------------------------------------------------
1 | formats:
2 | date:
3 | short:
4 | day: numeric
5 | month: long
6 | year: numeric
7 |
--------------------------------------------------------------------------------
/views/examples/react/message/component.jsx:
--------------------------------------------------------------------------------
1 | var IntlMixin = ReactIntl.IntlMixin;
2 | var FormattedMessage = ReactIntl.FormattedMessage;
3 |
4 | var Component = React.createClass({
5 | mixins: [IntlMixin],
6 |
7 | render: function () {
8 | return (
9 |
10 |
15 |
16 | );
17 | }
18 | });
19 |
--------------------------------------------------------------------------------
/views/examples/react/message/meta.yaml:
--------------------------------------------------------------------------------
1 | messageId: photos
2 |
--------------------------------------------------------------------------------
/views/examples/react/messageHTML/component.jsx:
--------------------------------------------------------------------------------
1 | var IntlMixin = ReactIntl.IntlMixin;
2 | var FormattedHTMLMessage = ReactIntl.FormattedHTMLMessage;
3 |
4 | var Component = React.createClass({
5 | mixins: [IntlMixin],
6 |
7 | render: function () {
8 | return (
9 |
10 |
13 |
14 | );
15 | }
16 | });
17 |
--------------------------------------------------------------------------------
/views/examples/react/messageHTML/meta.yaml:
--------------------------------------------------------------------------------
1 | messageId: commentsHTML
2 |
--------------------------------------------------------------------------------
/views/examples/react/messageNested/component.jsx:
--------------------------------------------------------------------------------
1 | var IntlMixin = ReactIntl.IntlMixin;
2 | var FormattedMessage = ReactIntl.FormattedMessage;
3 | var FormattedRelative = ReactIntl.FormattedRelative;
4 |
5 | var Component = React.createClass({
6 | mixins: [IntlMixin],
7 |
8 | render: function () {
9 | var takenDate = 1421881732917;
10 |
11 | return (
12 |
13 | Annie}
16 | numPhotos={1000}
17 | takenAgo={
18 |
19 |
20 |
21 | } />
22 |
23 | );
24 | }
25 | });
26 |
--------------------------------------------------------------------------------
/views/examples/react/messageNested/meta.yaml:
--------------------------------------------------------------------------------
1 | messageId: photosNested
2 |
--------------------------------------------------------------------------------
/views/examples/react/number/component.jsx:
--------------------------------------------------------------------------------
1 | var IntlMixin = ReactIntl.IntlMixin;
2 | var FormattedNumber = ReactIntl.FormattedNumber;
3 |
4 | var Component = React.createClass({
5 | mixins: [IntlMixin],
6 |
7 | render: function () {
8 | return (
9 |
10 |
11 |
12 |
13 |
17 |
18 |
19 | );
20 | }
21 | });
22 |
--------------------------------------------------------------------------------
/views/examples/react/numberCustom/component.jsx:
--------------------------------------------------------------------------------
1 | var IntlMixin = ReactIntl.IntlMixin;
2 | var FormattedNumber = ReactIntl.FormattedNumber;
3 |
4 | var Component = React.createClass({
5 | mixins: [IntlMixin],
6 |
7 | render: function () {
8 | return (
9 |
14 | );
15 | }
16 | });
17 |
--------------------------------------------------------------------------------
/views/examples/react/numberCustom/meta.yaml:
--------------------------------------------------------------------------------
1 | formats:
2 | number:
3 | USD:
4 | style: currency
5 | currency: USD
6 | minimumFractionDigits: 2
7 |
8 | percentage:
9 | style: percent
10 |
--------------------------------------------------------------------------------
/views/examples/react/relative/component.jsx:
--------------------------------------------------------------------------------
1 | var IntlMixin = ReactIntl.IntlMixin;
2 | var FormattedRelative = ReactIntl.FormattedRelative;
3 |
4 | var Component = React.createClass({
5 | mixins: [IntlMixin],
6 |
7 | render: function () {
8 | var postDate = Date.now() - (1000 * 60 * 60 * 24);
9 | var commentDate = Date.now() - (1000 * 60 * 60 * 2);
10 | var meetingDate = Date.now() + (1000 * 60 * 51);
11 |
12 | return (
13 |
18 | );
19 | }
20 | });
21 |
--------------------------------------------------------------------------------
/views/examples/react/relativeCustom/component.jsx:
--------------------------------------------------------------------------------
1 | var IntlMixin = ReactIntl.IntlMixin;
2 | var FormattedRelative = ReactIntl.FormattedRelative;
3 |
4 | var Component = React.createClass({
5 | mixins: [IntlMixin],
6 |
7 | render: function () {
8 | var postDate = Date.now() - (1000 * 60 * 60 * 24);
9 | var lastTrip = Date.now() - (1000 * 60 * 60 * 24 * 2);
10 |
11 | return (
12 |
13 |
14 |
15 | (best fit)
16 |
17 |
18 | (hours, numeric)
19 |
20 |
21 |
22 | (best fit)
23 |
24 |
25 | (hours, numeric)
26 |
27 |
28 | );
29 | }
30 | });
31 |
--------------------------------------------------------------------------------
/views/examples/react/relativeCustom/meta.yaml:
--------------------------------------------------------------------------------
1 | formats:
2 | relative:
3 | hours:
4 | units: hour
5 | style: numeric
6 |
--------------------------------------------------------------------------------
/views/examples/react/relativeStyle/component.jsx:
--------------------------------------------------------------------------------
1 | var IntlMixin = ReactIntl.IntlMixin;
2 | var FormattedRelative = ReactIntl.FormattedRelative;
3 |
4 | var Component = React.createClass({
5 | mixins: [IntlMixin],
6 |
7 | render: function () {
8 | var postDate = Date.now() - (1000 * 60 * 60 * 24);
9 | var lastTrip = Date.now() - (1000 * 60 * 60 * 24 * 380);
10 |
11 | return (
12 |
13 |
14 |
15 | (best fit)
16 |
17 |
18 | (numeric)
19 |
20 |
21 |
22 | (best fit)
23 |
24 |
25 | (numeric)
26 |
27 |
28 | );
29 | }
30 | });
31 |
--------------------------------------------------------------------------------
/views/examples/react/relativeUnits/component.jsx:
--------------------------------------------------------------------------------
1 | var IntlMixin = ReactIntl.IntlMixin;
2 | var FormattedRelative = ReactIntl.FormattedRelative;
3 |
4 | var Component = React.createClass({
5 | mixins: [IntlMixin],
6 |
7 | render: function () {
8 | var postDate = Date.now() - (1000 * 60 * 60 * 22);
9 | var lastTrip = Date.now() - (1000 * 60 * 60 * 24 * 70);
10 |
11 | return (
12 |
13 |
14 |
15 | (best fit)
16 |
17 |
18 | (in minutes)
19 |
20 |
21 |
22 | (best fit)
23 |
24 |
25 | (in days)
26 |
27 |
28 | );
29 | }
30 | });
31 |
--------------------------------------------------------------------------------
/views/layouts/main.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{title}}
6 |
7 |
8 |
9 |
10 | {{> purecss}}
11 |
12 |
13 |
14 | {{> analytics}}
15 |
16 |
17 |
18 | {{{body}}}
19 |
20 | {{> foot}}
21 |
22 |
23 |
24 | {{> polyfills}}
25 | {{> react}}
26 | {{> formatjs}}
27 | {{> syntax-highlighting}}
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/views/pages/about.hbs:
--------------------------------------------------------------------------------
1 | {{setTitle "About"}}
2 | {{setDescription "Authorship, credits, and security info for " brand ", the libraries, and this website."}}
3 |
4 |
7 |
8 |
9 | About {{brand}}
10 |
11 | Authorship
12 |
13 |
14 | {{brand}} was created by the Yahoo Presentation Technologies (YPT) team, with special thanks to Andy Earnshaw and Norbert Lindenberg .
15 |
16 |
17 | Industry Standards
18 |
19 |
20 | {{brand}} builds on the ECMAScript Internationalization API (ECMA-402), uses locale data from the CLDR , and works with the industry standard ICU Message syntax used by professional translators.
21 |
22 |
23 | Credits
24 |
25 | {{brand}}, the libraries and website, builds on the work of others:
26 |
27 |
50 |
51 | Security
52 |
53 | Please report security issues to the Yahoo Bug Bounty Program .
54 |
55 |
56 |
--------------------------------------------------------------------------------
/views/pages/github.hbs:
--------------------------------------------------------------------------------
1 | {{setTitle "GitHub"}}
2 | {{setDescription "Overview and details on all the open source repositories on GitHub that make up this project."}}
3 |
4 |
7 |
8 |
9 | Everything is on GitHub
10 |
11 |
12 | All of the packages that make up {{brand}} are open-source and available on GitHub. Instead of having one large repository, there are several smaller repositories; one per package.
13 |
14 |
15 | Integration Libraries
16 |
17 |
18 | These are the main packages that web apps will depend on since they contain all of the Core Libraries plus an integration layer with a template or component system.
19 |
20 |
21 |
22 |
23 |
26 |
27 | {{#with "react-intl"}}
28 | {{> npm-badge}}
29 | {{/with}}
30 |
31 |
32 | ReactJS mixin for internationalization.
33 |
34 |
35 |
36 |
37 |
40 |
41 | {{#with "ember-intl"}}
42 | {{> npm-badge}}
43 | {{/with}}
44 |
45 |
46 | Ember toolbox for internationalization.
47 |
48 |
49 |
50 |
51 |
54 |
55 | {{#with "handlebars-intl"}}
56 | {{> npm-badge}}
57 | {{/with}}
58 |
59 |
60 | Handlebars helpers for internationalization.
61 |
62 |
63 |
64 |
65 |
68 |
69 | {{#with "dust-intl"}}
70 | {{> npm-badge}}
71 | {{/with}}
72 |
73 |
74 | Dust helpers for internationalization.
75 |
76 |
77 |
78 |
79 |
82 |
83 | {{#with "app-localize-behavior"}}
84 | {{> npm-badge}}
85 | {{/with}}
86 |
87 |
88 | Polymer helpers for internationalization.
89 |
90 |
91 |
92 |
93 | Core Libraries
94 |
95 |
96 | This set of libraries makes up the core of the {{brand}} system. These packages provide features beyond what's built into the modern JavaScript runtimes. While the features these packages provide aren't specified in ECMA-402, they were developed on top of ECMAScript, ICU, and CLDR standards in a future-focused way.
97 |
98 |
99 |
100 |
101 |
104 |
105 | {{#with "intl-messageformat"}}
106 | {{> npm-badge}}
107 | {{/with}}
108 |
109 |
110 | Format a string with placeholders, including plural and select support to create localized messages.
111 |
112 |
113 |
114 |
115 |
118 |
119 | {{#with "intl-messageformat-parser"}}
120 | {{> npm-badge}}
121 | {{/with}}
122 |
123 |
124 | Parses ICU message strings to an AST that can be used to format the messages for a person's locale.
125 |
126 |
127 |
128 |
129 |
132 |
133 | {{#with "intl-relativeformat"}}
134 | {{> npm-badge}}
135 | {{/with}}
136 |
137 |
138 | Formats JavaScript dates to relative time strings.
139 |
140 |
141 |
142 |
143 |
146 |
147 | {{#with "intl-format-cache"}}
148 | {{> npm-badge}}
149 | {{/with}}
150 |
151 |
152 | Produces instances of JavaScript Intl formats, and caches them for reuse.
153 |
154 |
155 |
156 |
157 | Polyfills
158 |
159 |
160 | These libraries provide polyfills to "patch" the runtime in older JavaScript environments which don't have implementations of the latest ECMAScript standards.
161 |
162 |
163 |
164 |
165 |
168 |
169 | {{#with "intl"}}
170 | {{> npm-badge}}
171 | {{/with}}
172 |
173 |
174 | Compatibility implementation of the ECMAScript Internationalization API (ECMA-402) for JavaScript. Developed by Andy Earnshaw
175 |
176 |
177 |
178 |
179 |
182 |
183 | {{#with "intl-locales-supported"}}
184 | {{> npm-badge}}
185 | {{/with}}
186 |
187 |
188 | Utility to help you polyfill the Node.js runtime when the Intl APIs are missing, or if the built-in Intl is missing locale data that you need.
189 |
190 |
191 |
192 |
193 | Website
194 |
195 |
196 | This website itself is open source and uses all parts of the {{brand}} system that it documents! We are always looking for help in making the documentation better, adding new examples, and translating examples.
197 |
198 |
199 |
200 |
201 |
204 |
205 | Documentation for client/server internationalization in JavaScript.
206 |
207 |
208 |
209 |
210 |
211 |
Filing Issues
212 |
213 |
214 | If you wish to file an issue, you can do so on the specific package's GitHub repository. Try to be descriptive when filing issues, as it makes it easier for us to debug.
215 |
216 |
217 |
Submitting Pull Requests
218 |
219 |
220 | Pull requests are very welcome, but should be within the scope of the project, and follow the repository's code conventions. Before submitting a pull request, it's always good to file an issue, so we can discuss the details of the PR.
221 |
222 |
223 |
The Yahoo CLA
224 |
225 |
226 | At Yahoo, we have a single Yahoo Open Source Contributor License Agreement that we ask contributors to electronically sign before merging in their Pull Requests. Here's the CLA's human-readable summary:
227 |
228 |
229 |
230 | You are saying that you have the right to give us this code, which is either your own code, or code that your company allows you to publish. You want to give us this code. We may decide to use this code. You are not going to sue people who use this code, because, after all, you are giving it to an open source project! And if you include code that you didn't write, you'll tell us about it by including the open source license to such code in your contribution so we'll know about it. You are not promising that this code works well, or that you will support it, and we're OK with that.
231 |
232 |
233 |
234 |
235 |
--------------------------------------------------------------------------------
/views/pages/guides/basic-i18n.hbs:
--------------------------------------------------------------------------------
1 | {{setTitle "Basic Internationalization Principles"}}
2 | {{setDescription "General information on getting started internationalization web apps client and server in JavaScript."}}
3 |
4 |
7 |
8 |
9 | Basic Internationalization Principles
10 |
11 |
12 |
13 |
14 |
15 | What Is Internationalization and Why Does It Matter?
16 |
17 |
18 |
19 | Internationalized software supports the languages and cultural customs of people throughout the world. The Web reaches all parts of the world. Internationalized web apps provide a great user experience for people everywhere.
20 |
21 |
22 |
23 | Localized software adapts to a specific language and culture by translating text into the user's language and formatting data in accordance with the user's expectations. An app is typically localized for a small set of locales .
24 |
25 |
26 |
27 | The ECMA-402 JavaScript internalization specification has an excellent overview.
28 |
29 |
30 |
31 |
32 |
33 | Locales: Language and Region
34 |
35 |
36 |
37 | A "locale" refers to the lingual and cultural expectations for a region. It is represented using a "locale code" defined in BCP 47 .
38 |
39 |
40 |
41 | This code is comprised of several parts separated by hyphens ({{code "-"}}). The first part is a short string representing the language.
42 | The second, optional, part is a short string representing the region. Additionally, various extensions and variants can be specified.
43 |
44 |
45 |
46 | Typically, web apps are localized to just the language or language-region combination. Examples of such locale codes are:
47 |
48 |
49 |
50 |
51 | {{code "en"}} for English
52 |
53 |
54 | {{code "en-US"}} for English as spoken in the United States
55 |
56 |
57 | {{code "en-GB"}} for English as spoken in the United Kingdom
58 |
59 |
60 | {{code "es-AR"}} for Spanish as spoken in Argentina
61 |
62 |
63 | {{code "ar-001"}} for Arabic as spoken throughout the world
64 |
65 |
66 | {{code "ar-AE"}} for Arabic as spoken in United Arab Emirates
67 |
68 |
69 |
70 |
71 | Most internationalized apps only support a small list of locales.
72 |
73 |
74 |
75 |
76 |
77 | Translating Strings
78 |
79 |
80 |
81 | You likely have some text in your application that is in a natural language such as English or Japanese. In order to support other locales, you will need to translate these strings.
82 |
83 |
84 |
85 | {{brand}} provides a mechanism to let you write the core "software" of your application without special code for different translations. The considerations for each locale are encapsulated in your translated strings and our libraries.
86 |
87 |
88 | {{#code "js"}}
89 | var messages = {
90 | en: {
91 | GREETING: 'Hello {name}'
92 | },
93 | fr: {
94 | GREETING: 'Bonjour {name}'
95 | }
96 | };
97 | {{/code}}
98 |
99 |
100 | We use the ICU Message syntax which is also used in Java and PHP .
101 |
102 |
103 |
104 |
105 |
106 | Bundling Translated Strings
107 |
108 |
109 |
110 | It is common to organize your translations primarily by locale, because you only need the translations for the user's current locale. Our template and component library integrations are designed to work with the translations for a single locale. If your app is complex, you can further subdivide your translations, such as by page or section of the site.
111 |
112 |
113 |
114 |
115 |
116 | Structure of Code
117 |
118 |
119 |
120 | The actual formatting and presentation of data and translated strings typically takes these steps:
121 |
122 |
123 |
124 |
125 | Determine the user's locale, as described in Runtime Environments guide.
126 |
127 |
128 |
129 | Setup one of {{brand}}'s integrations with the following data:
130 |
131 |
132 | the user's current locale
133 |
134 |
135 | translated strings for that locale
136 |
137 |
138 | optionally, any custom formats
139 |
140 |
141 |
142 |
143 |
144 | Call the template engine, passing the data that needs formatting.
145 |
146 |
147 |
148 |
149 |
150 | {{brand}} Guides
151 |
152 | {{> guides-list}}
153 |
154 |
155 |
--------------------------------------------------------------------------------
/views/pages/guides/index.hbs:
--------------------------------------------------------------------------------
1 | {{setTitle "Getting Started"}}
2 | {{setDescription "General information on getting started internationalization web apps client and server in JavaScript."}}
3 |
4 |
7 |
8 |
9 | Getting Started
10 |
11 | Start with the Guides to Internationalization
12 |
13 |
14 |
15 | Internationalizing web apps is an involved and complex task. We created the following guides to document the process:
16 |
17 |
18 | {{> guides-list}}
19 |
20 | {{brand}} Integrations
21 |
22 |
23 | We've also integrated internationalization support into a few common template and component libraries. The documentation pages for these integrations is also a good place to start:
24 |
25 |
26 | {{> integrations-list}}
27 |
28 |
--------------------------------------------------------------------------------
/views/pages/home.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{> nav}}
3 |
4 |
5 |
{{tagline}}
6 |
7 |
{{{examples.splash}}}
8 |
9 |
10 |
11 | Get Started
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
{{brand}} is a set of JavaScript libraries.
20 |
21 |
22 |
23 | {{brand}} is a modular collection of JavaScript libraries for internationalization that are focused on formatting numbers, dates, and strings for displaying to people. It includes a set of core libraries that build on the JavaScript {{code "Intl"}} built-ins and industry-wide i18n standards, plus a set of integrations for common template and component libraries.
24 |
25 |
26 |
27 |
{{brand}} Integrations
28 |
{{brand}} Core Libs
29 |
Standards
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
Integrates with other libraries.
38 |
39 |
40 | {{> integrations-list}}
41 |
42 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
Formats numbers, dates, and string messages.
60 |
61 |
62 |
63 |
Display numbers with separators.
64 |
65 |
66 | 1000.95
67 |
68 |
69 |
70 | {{#intl locales="en-US"}}
71 | {{formatNumber 1000.95}}
72 | English
73 | {{/intl}}
74 |
75 |
76 | {{#intl locales="fr-FR"}}
77 | {{formatNumber 1000.95}}
78 | French
79 | {{/intl}}
80 |
81 |
82 |
83 |
84 |
85 |
86 |
Display dates and times correctly.
87 |
88 |
89 | new Date()
90 |
91 |
92 |
93 | {{#intl locales="en-US"}}
94 | {{formatDate now}}
95 | English (US)
96 | {{/intl}}
97 |
98 |
99 | {{#intl locales="fr-FR"}}
100 | {{formatDate now}}
101 | French
102 | {{/intl}}
103 |
104 |
105 |
106 |
107 |
108 |
109 |
Display dates relative to "now".
110 |
111 |
112 | {{#intl locales="en-US"}}
113 |
114 | "{{lastMonth}}"
115 |
116 |
117 |
118 |
119 | {{formatRelative lastMonth}}
120 |
121 |
122 | {{formatRelative lastMonth style="numeric"}}
123 |
124 |
125 | {{formatRelative lastMonth units="day"}}
126 |
127 |
128 | {{/intl}}
129 |
130 |
131 |
132 |
133 |
Pluralize labels in strings.
134 |
135 |
136 | numComments
137 |
138 |
139 | {{#intl locales="en-US"}}
140 | {{formatMessage (intlGet "messages.en-US.comments") numComments=0}}
141 | {{formatMessage (intlGet "messages.en-US.comments") numComments=1}}
142 | {{formatMessage (intlGet "messages.en-US.comments") numComments=1000}}
143 | {{/intl}}
144 |
145 |
146 |
147 |
148 |
149 | {{!--
150 |
Modular, and ready to use.
151 | --}}
152 |
153 |
Runs in the browser and Node.js.
154 |
155 |
156 |
157 | {{brand}} has been tested in all the major browsers on both desktop and mobile devices. Careful attention has been applied to make sure the libraries work in ES3 browsers all the way down to IE 6.
158 |
159 |
160 |
161 | For many web apps rendering happens on the server, so we made sure {{brand}} works perfectly in Node.js. This allows developers to use {{brand}} on both the server and client-side of their apps.
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
Built on standards.
170 |
171 |
172 |
173 | {{brand}} is aligned with: ECMAScript Internationalization API (ECMA-402), Unicode CLDR , and ICU Message syntax . By building on these industry standards, {{brand}} leverages APIs in modern browsers and works with the message syntax used by professional translators.
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
190 |
--------------------------------------------------------------------------------
/views/pages/integrations.hbs:
--------------------------------------------------------------------------------
1 | {{setTitle "Integrations"}}
2 | {{setDescription "Overview of integrations layer with common template and component libraries."}}
3 |
4 |
7 |
8 |
9 | Integrations
10 |
11 | Start using {{brand}} via one of our integrations:
12 |
13 |
14 | {{> integrations-list}}
15 |
16 |
17 | {{brand}} has integrations with common template and component libraries, since that's the place where developers need to format numbers, dates, and string messages for their web app UIs.
18 |
19 |
20 | Using {{brand}} Anywhere
21 |
22 |
23 | If your web project isn't using one of the template/component engines with which we have integrations, don't worry; there's also the core Intl libraries with JavaScript APIs .
24 |
25 |
26 | Core JavaScript Intl Libraries
27 |
28 |
29 | All of the {{brand}} integrations build and depend on our core JavaScript Intl libraries . This modular approach allows for maximum code reuse, and the ability to use these core Intl APIs directly or build new integrations.
30 |
31 |
32 | Building an Integration
33 |
34 |
35 | We're interested in integrations with other popular template/component libraries. At Yahoo, teams use Handlebars, React, and Dust, which is why {{brand}} has integrations for these libraries. If you've built or are interested in building a {{brand}} integration with another library, feel free to reach out to us!
36 |
37 |
38 |
39 | The existing {{brand}} integrations are great models for building a new integration. All of them leverage the same dependencies and build process to create a library that runs on the server and client.
40 |
41 |
42 | Principles Behind Integrations
43 |
44 |
45 |
46 |
47 | The integration library should run everywhere the template/component library runs (e.g. Node.js and the browser).
48 |
49 |
50 |
51 |
52 | Author library as ES6 Modules, compiled to CommonJS for Node.js, and a single, bundled file with all of its dependencies for the browser. We use the ES6 Module Transpiler .
53 |
54 |
55 |
56 |
57 | Build on and use the built-in {{code "Intl"}} JavaScript APIs .
58 |
59 |
60 |
61 |
62 | Aggressively cache and reuse format instances using the Intl Format Cache package.
63 |
64 |
65 |
66 |
67 | Propagate Intl data through template/component hierarchy to avoid placing burden on user.
68 |
69 |
70 |
71 |
72 | Publish integration library on npm.
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/views/partials/analytics.hbs:
--------------------------------------------------------------------------------
1 | {{#if analytics}}
2 |
11 | {{/if}}
12 |
--------------------------------------------------------------------------------
/views/partials/example.hbs:
--------------------------------------------------------------------------------
1 | {{{this}}}
2 |
--------------------------------------------------------------------------------
/views/partials/foot.hbs:
--------------------------------------------------------------------------------
1 |
31 |
--------------------------------------------------------------------------------
/views/partials/formatjs.hbs:
--------------------------------------------------------------------------------
1 | {{#if usesReactIntl}}
2 |
3 |
4 | {{/if}}
5 |
6 | {{#if usesDustIntl}}
7 |
8 |
9 |
10 |
13 | {{/if}}
14 |
15 | {{#if usesHandlebarsIntl}}
16 |
17 |
18 |
19 |
22 | {{/if}}
23 |
--------------------------------------------------------------------------------
/views/partials/guides-list.hbs:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/views/partials/integrations-list.hbs:
--------------------------------------------------------------------------------
1 |
38 |
--------------------------------------------------------------------------------
/views/partials/integrations/features.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | Formats numbers and dates/times , including those in complex messages.
4 |
5 |
6 | Formats relative times (e.g., "3 hours ago").
7 |
8 |
9 | Formats complex messages, including plural and select arguments using ICU Message syntax .
10 |
11 |
12 | Supports custom formatters for numbers and dates/times .
13 |
14 |
15 |
--------------------------------------------------------------------------------
/views/partials/integrations/load-locale-data-browser.hbs:
--------------------------------------------------------------------------------
1 |
2 | By default, {{package.name}}
ships with the locale data for English built-in to the library's runtime. When you need to format data in another locale, include its data; e.g., for French:
3 |
4 |
5 | {{#code "html"}}
6 |
7 | {{/code}}
8 |
9 |
10 | All 150+ languages supported by this library use their root BCP 47 language tag; i.e., the part before the first hyphen (if any).
11 |
12 |
--------------------------------------------------------------------------------
/views/partials/integrations/load-locale-data-node.hbs:
--------------------------------------------------------------------------------
1 |
2 | In Node.js, the data for all 150+ languages is pre-loaded and does not need to be loaded manually.
3 |
4 |
--------------------------------------------------------------------------------
/views/partials/integrations/note-intl-browser.hbs:
--------------------------------------------------------------------------------
1 |
2 | Note: Older browsers do not have the built-in {{code "Intl"}} APIs (ECMA-402). Read more on how to patch the browser runtime using a polyfill.
3 |
4 |
--------------------------------------------------------------------------------
/views/partials/integrations/note-intl-node.hbs:
--------------------------------------------------------------------------------
1 |
2 | Note: Node.js <= 0.10 doesn't have the built-in Intl
APIs (ECMA-402). Node.js 0.12 does, but the default build/distribution only supports English. Read more on how to patch Node.js using a polyfill.
3 |
4 |
--------------------------------------------------------------------------------
/views/partials/integrations/package-install.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{#code highlight=false wrap=true}}
3 | npm install {{package.name}}
4 | {{/code}}
5 |
6 |
--------------------------------------------------------------------------------
/views/partials/integrations/package-meta.hbs:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/views/partials/integrations/see-custom-formats.hbs:
--------------------------------------------------------------------------------
1 |
2 | See the custom formats section for more information.
3 |
4 |
--------------------------------------------------------------------------------
/views/partials/integrations/see-guide.hbs:
--------------------------------------------------------------------------------
1 |
2 | See the Guide for details on how to write those messages using the ICU Message syntax.
3 |
4 |
--------------------------------------------------------------------------------
/views/partials/nav.hbs:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/views/partials/npm-badge.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/views/partials/polyfills.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/views/partials/purecss.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/views/partials/react.hbs:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/views/partials/syntax-highlighting.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
--------------------------------------------------------------------------------