diff --git a/modules/angular2/src/common/pipes.ts b/modules/angular2/src/common/pipes.ts
index 0f7f9a9952..b829810dfb 100644
--- a/modules/angular2/src/common/pipes.ts
+++ b/modules/angular2/src/common/pipes.ts
@@ -3,15 +3,6 @@
* @description
* This module provides a set of common Pipes.
*/
-import {AsyncPipe} from './pipes/async_pipe';
-import {UpperCasePipe} from './pipes/uppercase_pipe';
-import {LowerCasePipe} from './pipes/lowercase_pipe';
-import {JsonPipe} from './pipes/json_pipe';
-import {SlicePipe} from './pipes/slice_pipe';
-import {DatePipe} from './pipes/date_pipe';
-import {DecimalPipe, PercentPipe, CurrencyPipe} from './pipes/number_pipe';
-import {ReplacePipe} from './pipes/replace_pipe';
-import {CONST_EXPR} from 'angular2/src/facade/lang';
export {AsyncPipe} from './pipes/async_pipe';
export {DatePipe} from './pipes/date_pipe';
@@ -21,23 +12,6 @@ export {LowerCasePipe} from './pipes/lowercase_pipe';
export {NumberPipe, DecimalPipe, PercentPipe, CurrencyPipe} from './pipes/number_pipe';
export {UpperCasePipe} from './pipes/uppercase_pipe';
export {ReplacePipe} from './pipes/replace_pipe';
-
-/**
- * A collection of Angular core pipes that are likely to be used in each and every
- * application.
- *
- * This collection can be used to quickly enumerate all the built-in pipes in the `pipes`
- * property of the `@Component` or `@View` decorators.
- */
-export const COMMON_PIPES = CONST_EXPR([
- AsyncPipe,
- UpperCasePipe,
- LowerCasePipe,
- JsonPipe,
- SlicePipe,
- DecimalPipe,
- PercentPipe,
- CurrencyPipe,
- DatePipe,
- ReplacePipe
-]);
+export {I18nPluralPipe} from './pipes/i18n_plural_pipe';
+export {I18nSelectPipe} from './pipes/i18n_select_pipe';
+export {COMMON_PIPES} from './pipes/common_pipes';
diff --git a/modules/angular2/src/common/pipes/common_pipes.ts b/modules/angular2/src/common/pipes/common_pipes.ts
index 2bc6eeed07..810b1e0eb4 100644
--- a/modules/angular2/src/common/pipes/common_pipes.ts
+++ b/modules/angular2/src/common/pipes/common_pipes.ts
@@ -11,6 +11,8 @@ import {SlicePipe} from './slice_pipe';
import {DatePipe} from './date_pipe';
import {DecimalPipe, PercentPipe, CurrencyPipe} from './number_pipe';
import {ReplacePipe} from './replace_pipe';
+import {I18nPluralPipe} from './i18n_plural_pipe';
+import {I18nSelectPipe} from './i18n_select_pipe';
import {CONST_EXPR} from 'angular2/src/facade/lang';
/**
@@ -30,5 +32,7 @@ export const COMMON_PIPES = CONST_EXPR([
PercentPipe,
CurrencyPipe,
DatePipe,
- ReplacePipe
+ ReplacePipe,
+ I18nPluralPipe,
+ I18nSelectPipe
]);
diff --git a/modules/angular2/src/common/pipes/i18n_plural_pipe.ts b/modules/angular2/src/common/pipes/i18n_plural_pipe.ts
new file mode 100644
index 0000000000..8cf45e82dc
--- /dev/null
+++ b/modules/angular2/src/common/pipes/i18n_plural_pipe.ts
@@ -0,0 +1,62 @@
+import {
+ CONST,
+ isStringMap,
+ StringWrapper,
+ isPresent,
+ RegExpWrapper
+} from 'angular2/src/facade/lang';
+import {Injectable, PipeTransform, Pipe} from 'angular2/core';
+import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
+
+var interpolationExp: RegExp = RegExpWrapper.create('#');
+
+/**
+ *
+ * Maps a value to a string that pluralizes the value properly.
+ *
+ * ## Usage
+ *
+ * expression | i18nPlural:mapping
+ *
+ * where `expression` is a number and `mapping` is an object that indicates the proper text for
+ * when the `expression` evaluates to 0, 1, or some other number. You can interpolate the actual
+ * value into the text using the `#` sign.
+ *
+ * ## Example
+ *
+ * ```
+ *
+ * {{ messages.length | i18nPlural: messageMapping }}
+ *
+ *
+ * class MyApp {
+ * messages: any[];
+ * messageMapping: any = {
+ * '=0': 'No messages.',
+ * '=1': 'One message.',
+ * 'other': '# messages.'
+ * }
+ * ...
+ * }
+ * ```
+ *
+ */
+@CONST()
+@Pipe({name: 'i18nPlural', pure: true})
+@Injectable()
+export class I18nPluralPipe implements PipeTransform {
+ transform(value: number, args: any[] = null): string {
+ var key: string;
+ var valueStr: string;
+ var pluralMap: {[count: string]: string} = args[0];
+
+ if (!isStringMap(pluralMap)) {
+ throw new InvalidPipeArgumentException(I18nPluralPipe, pluralMap);
+ }
+
+ key = value === 0 || value === 1 ? `=${value}` : 'other';
+ valueStr = isPresent(value) ? value.toString() : '';
+
+ return StringWrapper.replaceAll(pluralMap[key], interpolationExp, valueStr);
+ }
+}
diff --git a/modules/angular2/src/common/pipes/i18n_select_pipe.ts b/modules/angular2/src/common/pipes/i18n_select_pipe.ts
new file mode 100644
index 0000000000..619b38c9dc
--- /dev/null
+++ b/modules/angular2/src/common/pipes/i18n_select_pipe.ts
@@ -0,0 +1,47 @@
+import {CONST, isStringMap} from 'angular2/src/facade/lang';
+import {StringMapWrapper} from 'angular2/src/facade/collection';
+import {Injectable, PipeTransform, Pipe} from 'angular2/core';
+import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
+
+/**
+ *
+ * Generic selector that displays the string that matches the current value.
+ *
+ * ## Usage
+ *
+ * expression | i18nSelect:mapping
+ *
+ * where `mapping` is an object that indicates the text that should be displayed
+ * for different values of the provided `expression`.
+ *
+ * ## Example
+ *
+ * ```
+ *
+ * {{ gender | i18nSelect: inviteMap }}
+ *
+ *
+ * class MyApp {
+ * gender: string = 'male';
+ * inviteMap: any = {
+ * 'male': 'Invite her.',
+ * 'female': 'Invite him.',
+ * 'other': 'Invite them.'
+ * }
+ * ...
+ * }
+ * ```
+ */
+@CONST()
+@Pipe({name: 'i18nSelect', pure: true})
+@Injectable()
+export class I18nSelectPipe implements PipeTransform {
+ transform(value: string, args: any[] = null): string {
+ var mapping: {[key: string]: string} = args[0];
+ if (!isStringMap(mapping)) {
+ throw new InvalidPipeArgumentException(I18nSelectPipe, mapping);
+ }
+
+ return StringMapWrapper.contains(mapping, value) ? mapping[value] : mapping['other'];
+ }
+}
diff --git a/modules/angular2/test/common/pipes/i18n_plural_pipe_spec.ts b/modules/angular2/test/common/pipes/i18n_plural_pipe_spec.ts
new file mode 100644
index 0000000000..6a220afd1e
--- /dev/null
+++ b/modules/angular2/test/common/pipes/i18n_plural_pipe_spec.ts
@@ -0,0 +1,59 @@
+import {
+ ddescribe,
+ describe,
+ it,
+ iit,
+ xit,
+ expect,
+ beforeEach,
+ afterEach
+} from 'angular2/testing_internal';
+
+import {I18nPluralPipe} from 'angular2/common';
+import {PipeResolver} from 'angular2/src/core/linker/pipe_resolver';
+
+export function main() {
+ describe("I18nPluralPipe", () => {
+ var pipe;
+ var mapping = {'=0': 'No messages.', '=1': 'One message.', 'other': 'There are some messages.'};
+ var interpolatedMapping =
+ {'=0': 'No messages.', '=1': 'One message.', 'other': 'There are # messages, that is #.'};
+
+ beforeEach(() => { pipe = new I18nPluralPipe(); });
+
+ it('should be marked as pure',
+ () => { expect(new PipeResolver().resolve(I18nPluralPipe).pure).toEqual(true); });
+
+ describe("transform", () => {
+ it("should return 0 text if value is 0", () => {
+ var val = pipe.transform(0, [mapping]);
+ expect(val).toEqual('No messages.');
+ });
+
+ it("should return 1 text if value is 1", () => {
+ var val = pipe.transform(1, [mapping]);
+ expect(val).toEqual('One message.');
+ });
+
+ it("should return other text if value is anything other than 0 or 1", () => {
+ var val = pipe.transform(6, [mapping]);
+ expect(val).toEqual('There are some messages.');
+ });
+
+ it("should interpolate the value into the text where indicated", () => {
+ var val = pipe.transform(6, [interpolatedMapping]);
+ expect(val).toEqual('There are 6 messages, that is 6.');
+ });
+
+ it("should use 'other' if value is undefined", () => {
+ var messageLength;
+ var val = pipe.transform(messageLength, [interpolatedMapping]);
+ expect(val).toEqual('There are messages, that is .');
+ });
+
+ it("should not support bad arguments",
+ () => { expect(() => pipe.transform(0, ['hey'])).toThrowError(); });
+ });
+
+ });
+}
diff --git a/modules/angular2/test/common/pipes/i18n_select_pipe_spec.ts b/modules/angular2/test/common/pipes/i18n_select_pipe_spec.ts
new file mode 100644
index 0000000000..7a9e7f21cd
--- /dev/null
+++ b/modules/angular2/test/common/pipes/i18n_select_pipe_spec.ts
@@ -0,0 +1,52 @@
+import {
+ ddescribe,
+ describe,
+ it,
+ iit,
+ xit,
+ expect,
+ beforeEach,
+ afterEach
+} from 'angular2/testing_internal';
+
+import {I18nSelectPipe} from 'angular2/common';
+import {PipeResolver} from 'angular2/src/core/linker/pipe_resolver';
+
+export function main() {
+ describe("I18nSelectPipe", () => {
+ var pipe;
+ var mapping = {'male': 'Invite him.', 'female': 'Invite her.', 'other': 'Invite them.'};
+
+ beforeEach(() => { pipe = new I18nSelectPipe(); });
+
+ it('should be marked as pure',
+ () => { expect(new PipeResolver().resolve(I18nSelectPipe).pure).toEqual(true); });
+
+ describe("transform", () => {
+ it("should return male text if value is male", () => {
+ var val = pipe.transform('male', [mapping]);
+ expect(val).toEqual('Invite him.');
+ });
+
+ it("should return female text if value is female", () => {
+ var val = pipe.transform('female', [mapping]);
+ expect(val).toEqual('Invite her.');
+ });
+
+ it("should return other text if value is anything other than male or female", () => {
+ var val = pipe.transform('Anything else', [mapping]);
+ expect(val).toEqual('Invite them.');
+ });
+
+ it("should use 'other' if value is undefined", () => {
+ var gender;
+ var val = pipe.transform(gender, [mapping]);
+ expect(val).toEqual('Invite them.');
+ });
+
+ it("should not support bad arguments",
+ () => { expect(() => pipe.transform('male', ['hey'])).toThrowError(); });
+ });
+
+ });
+}
diff --git a/modules/angular2/test/public_api_spec.ts b/modules/angular2/test/public_api_spec.ts
index 7fb93690b0..29ba7129cc 100644
--- a/modules/angular2/test/public_api_spec.ts
+++ b/modules/angular2/test/public_api_spec.ts
@@ -208,6 +208,10 @@ var NG_COMMON = [
'FormBuilder.array()',
'FormBuilder.control()',
'FormBuilder.group()',
+ 'I18nPluralPipe',
+ 'I18nPluralPipe.transform()',
+ 'I18nSelectPipe',
+ 'I18nSelectPipe.transform()',
'JsonPipe',
'JsonPipe.transform()',
'LowerCasePipe',
diff --git a/tools/public_api_guard/public_api_spec.ts b/tools/public_api_guard/public_api_spec.ts
index 09a0e044c6..a725b7c2df 100644
--- a/tools/public_api_guard/public_api_spec.ts
+++ b/tools/public_api_guard/public_api_spec.ts
@@ -641,6 +641,10 @@ const COMMON = [
'FormBuilder.array(controlsConfig:any[], validator:Function, asyncValidator:Function):ControlArray',
'FormBuilder.control(value:Object, validator:Function, asyncValidator:Function):Control',
'FormBuilder.group(controlsConfig:{[key:string]:any}, extra:{[key:string]:any}):ControlGroup',
+ 'I18nPluralPipe',
+ 'I18nPluralPipe.transform(value:number, args:any[]):string',
+ 'I18nSelectPipe',
+ 'I18nSelectPipe.transform(value:string, args:any[]):string',
'JsonPipe',
'JsonPipe.transform(value:any, args:any[]):string',
'LowerCasePipe',