New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(plural): add plural and select pipes #7268
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
* | ||
* ``` | ||
* <div> | ||
* {{ messages.length | i18nPlural: messageMapping }} | ||
* </div> | ||
* | ||
* 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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried to do so, but the compiler didn't like it |
||
var key: string; | ||
var valueStr: string; | ||
var pluralMap: {[count: string]: string} = args[0]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if you are aware, but it will be compiled into:
This will throw in the checked mode in Dart. So the next if statement will never execute. Is it your intent? |
||
|
||
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); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
* | ||
* ``` | ||
* <div> | ||
* {{ gender | i18nSelect: inviteMap }} | ||
* </div> | ||
* | ||
* 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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use |
||
var mapping: {[key: string]: string} = args[0]; | ||
if (!isStringMap(mapping)) { | ||
throw new InvalidPipeArgumentException(I18nSelectPipe, mapping); | ||
} | ||
|
||
return StringMapWrapper.contains(mapping, value) ? mapping[value] : mapping['other']; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); }); | ||
}); | ||
|
||
}); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); }); | ||
}); | ||
|
||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make it a const
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(we discussed and decided to leave as is)