mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-30 13:00:29 +00:00
207 lines
9.7 KiB
JavaScript
207 lines
9.7 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* @ngdoc directive
|
|
* @name ng.directive:ngPluralize
|
|
* @restrict EA
|
|
*
|
|
* @description
|
|
* # Overview
|
|
* `ngPluralize` is a directive that displays messages according to en-US localization rules.
|
|
* These rules are bundled with angular.js and the rules can be overridden
|
|
* (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
|
|
* by specifying the mappings between
|
|
* {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
|
|
* plural categories} and the strings to be displayed.
|
|
*
|
|
* # Plural categories and explicit number rules
|
|
* There are two
|
|
* {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
|
|
* plural categories} in Angular's default en-US locale: "one" and "other".
|
|
*
|
|
* While a pural category may match many numbers (for example, in en-US locale, "other" can match
|
|
* any number that is not 1), an explicit number rule can only match one number. For example, the
|
|
* explicit number rule for "3" matches the number 3. You will see the use of plural categories
|
|
* and explicit number rules throughout later parts of this documentation.
|
|
*
|
|
* # Configuring ngPluralize
|
|
* You configure ngPluralize by providing 2 attributes: `count` and `when`.
|
|
* You can also provide an optional attribute, `offset`.
|
|
*
|
|
* The value of the `count` attribute can be either a string or an {@link guide/expression
|
|
* Angular expression}; these are evaluated on the current scope for its bound value.
|
|
*
|
|
* The `when` attribute specifies the mappings between plural categories and the actual
|
|
* string to be displayed. The value of the attribute should be a JSON object so that Angular
|
|
* can interpret it correctly.
|
|
*
|
|
* The following example shows how to configure ngPluralize:
|
|
*
|
|
* <pre>
|
|
* <ng-pluralize count="personCount"
|
|
when="{'0': 'Nobody is viewing.',
|
|
* 'one': '1 person is viewing.',
|
|
* 'other': '{} people are viewing.'}">
|
|
* </ng-pluralize>
|
|
*</pre>
|
|
*
|
|
* In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
|
|
* specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
|
|
* would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
|
|
* other numbers, for example 12, so that instead of showing "12 people are viewing", you can
|
|
* show "a dozen people are viewing".
|
|
*
|
|
* You can use a set of closed braces(`{}`) as a placeholder for the number that you want substituted
|
|
* into pluralized strings. In the previous example, Angular will replace `{}` with
|
|
* <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
|
|
* for <span ng-non-bindable>{{numberExpression}}</span>.
|
|
*
|
|
* # Configuring ngPluralize with offset
|
|
* The `offset` attribute allows further customization of pluralized text, which can result in
|
|
* a better user experience. For example, instead of the message "4 people are viewing this document",
|
|
* you might display "John, Kate and 2 others are viewing this document".
|
|
* The offset attribute allows you to offset a number by any desired value.
|
|
* Let's take a look at an example:
|
|
*
|
|
* <pre>
|
|
* <ng-pluralize count="personCount" offset=2
|
|
* when="{'0': 'Nobody is viewing.',
|
|
* '1': '{{person1}} is viewing.',
|
|
* '2': '{{person1}} and {{person2}} are viewing.',
|
|
* 'one': '{{person1}}, {{person2}} and one other person are viewing.',
|
|
* 'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
|
|
* </ng-pluralize>
|
|
* </pre>
|
|
*
|
|
* Notice that we are still using two plural categories(one, other), but we added
|
|
* three explicit number rules 0, 1 and 2.
|
|
* When one person, perhaps John, views the document, "John is viewing" will be shown.
|
|
* When three people view the document, no explicit number rule is found, so
|
|
* an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
|
|
* In this case, plural category 'one' is matched and "John, Marry and one other person are viewing"
|
|
* is shown.
|
|
*
|
|
* Note that when you specify offsets, you must provide explicit number rules for
|
|
* numbers from 0 up to and including the offset. If you use an offset of 3, for example,
|
|
* you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
|
|
* plural categories "one" and "other".
|
|
*
|
|
* @param {string|expression} count The variable to be bounded to.
|
|
* @param {string} when The mapping between plural category to its correspoding strings.
|
|
* @param {number=} offset Offset to deduct from the total number.
|
|
*
|
|
* @example
|
|
<doc:example>
|
|
<doc:source>
|
|
<script>
|
|
function Ctrl($scope) {
|
|
$scope.person1 = 'Igor';
|
|
$scope.person2 = 'Misko';
|
|
$scope.personCount = 1;
|
|
}
|
|
</script>
|
|
<div ng-controller="Ctrl">
|
|
Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
|
|
Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
|
|
Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
|
|
|
|
<!--- Example with simple pluralization rules for en locale --->
|
|
Without Offset:
|
|
<ng-pluralize count="personCount"
|
|
when="{'0': 'Nobody is viewing.',
|
|
'one': '1 person is viewing.',
|
|
'other': '{} people are viewing.'}">
|
|
</ng-pluralize><br>
|
|
|
|
<!--- Example with offset --->
|
|
With Offset(2):
|
|
<ng-pluralize count="personCount" offset=2
|
|
when="{'0': 'Nobody is viewing.',
|
|
'1': '{{person1}} is viewing.',
|
|
'2': '{{person1}} and {{person2}} are viewing.',
|
|
'one': '{{person1}}, {{person2}} and one other person are viewing.',
|
|
'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
|
|
</ng-pluralize>
|
|
</div>
|
|
</doc:source>
|
|
<doc:scenario>
|
|
it('should show correct pluralized string', function() {
|
|
expect(element('.doc-example-live ng-pluralize:first').text()).
|
|
toBe('1 person is viewing.');
|
|
expect(element('.doc-example-live ng-pluralize:last').text()).
|
|
toBe('Igor is viewing.');
|
|
|
|
using('.doc-example-live').input('personCount').enter('0');
|
|
expect(element('.doc-example-live ng-pluralize:first').text()).
|
|
toBe('Nobody is viewing.');
|
|
expect(element('.doc-example-live ng-pluralize:last').text()).
|
|
toBe('Nobody is viewing.');
|
|
|
|
using('.doc-example-live').input('personCount').enter('2');
|
|
expect(element('.doc-example-live ng-pluralize:first').text()).
|
|
toBe('2 people are viewing.');
|
|
expect(element('.doc-example-live ng-pluralize:last').text()).
|
|
toBe('Igor and Misko are viewing.');
|
|
|
|
using('.doc-example-live').input('personCount').enter('3');
|
|
expect(element('.doc-example-live ng-pluralize:first').text()).
|
|
toBe('3 people are viewing.');
|
|
expect(element('.doc-example-live ng-pluralize:last').text()).
|
|
toBe('Igor, Misko and one other person are viewing.');
|
|
|
|
using('.doc-example-live').input('personCount').enter('4');
|
|
expect(element('.doc-example-live ng-pluralize:first').text()).
|
|
toBe('4 people are viewing.');
|
|
expect(element('.doc-example-live ng-pluralize:last').text()).
|
|
toBe('Igor, Misko and 2 other people are viewing.');
|
|
});
|
|
|
|
it('should show data-binded names', function() {
|
|
using('.doc-example-live').input('personCount').enter('4');
|
|
expect(element('.doc-example-live ng-pluralize:last').text()).
|
|
toBe('Igor, Misko and 2 other people are viewing.');
|
|
|
|
using('.doc-example-live').input('person1').enter('Di');
|
|
using('.doc-example-live').input('person2').enter('Vojta');
|
|
expect(element('.doc-example-live ng-pluralize:last').text()).
|
|
toBe('Di, Vojta and 2 other people are viewing.');
|
|
});
|
|
</doc:scenario>
|
|
</doc:example>
|
|
*/
|
|
var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
|
|
var BRACE = /{}/g;
|
|
return {
|
|
restrict: 'EA',
|
|
link: function(scope, element, attr) {
|
|
var numberExp = attr.count,
|
|
whenExp = element.attr(attr.$attr.when), // this is because we have {{}} in attrs
|
|
offset = attr.offset || 0,
|
|
whens = scope.$eval(whenExp),
|
|
whensExpFns = {},
|
|
startSymbol = $interpolate.startSymbol(),
|
|
endSymbol = $interpolate.endSymbol();
|
|
|
|
forEach(whens, function(expression, key) {
|
|
whensExpFns[key] =
|
|
$interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
|
|
offset + endSymbol));
|
|
});
|
|
|
|
scope.$watch(function ngPluralizeWatch() {
|
|
var value = parseFloat(scope.$eval(numberExp));
|
|
|
|
if (!isNaN(value)) {
|
|
//if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
|
|
//check it against pluralization rules in $locale service
|
|
if (!whens[value]) value = $locale.pluralCat(value - offset);
|
|
return whensExpFns[value](scope, element, true);
|
|
} else {
|
|
return '';
|
|
}
|
|
}, function ngPluralizeWatchAction(newVal) {
|
|
element.text(newVal);
|
|
});
|
|
}
|
|
};
|
|
}];
|