mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-26 12:21:36 +03:00
Added number formatting to all pluralized counts
closes https://github.com/TryGhost/Ghost/issues/12110 - adds `{{gh-pluralize}}` helper that wraps the `{{pluralize}}` helper from `ember-inflector` but formats the number using our `{{format-number}}` helper - updates all uses of `{{pluralize}}` to `{{gh-pluralize}}`
This commit is contained in:
parent
e246b2829d
commit
fd91b593a5
@ -4,9 +4,9 @@
|
|||||||
{{else if (or @post.isPublished @post.pastScheduledTime)}}
|
{{else if (or @post.isPublished @post.pastScheduledTime)}}
|
||||||
Published
|
Published
|
||||||
{{#if (or (eq @post.email.status "submitting") (eq @post.email.status "submitting"))}}
|
{{#if (or (eq @post.email.status "submitting") (eq @post.email.status "submitting"))}}
|
||||||
and sending to {{pluralize @post.email.emailCount "member"}}
|
and sending to {{gh-pluralize @post.email.emailCount "member"}}
|
||||||
{{else if (eq @post.email.status "submitted")}}
|
{{else if (eq @post.email.status "submitted")}}
|
||||||
and sent to {{pluralize @post.email.emailCount "member"}}
|
and sent to {{gh-pluralize @post.email.emailCount "member"}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{else if @post.isScheduled}}
|
{{else if @post.isScheduled}}
|
||||||
<time datetime="{{@post.publishedAtUTC}}" class="ml1 green f8" data-test-schedule-countdown>
|
<time datetime="{{@post.publishedAtUTC}}" class="ml1 green f8" data-test-schedule-countdown>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-column justify-center">
|
<div class="flex flex-column justify-center">
|
||||||
<p class="ma0 pa0 midgrey">Post was sent by email to</p>
|
<p class="ma0 pa0 midgrey">Post was sent by email to</p>
|
||||||
<p class="ma0 pa0 f5 lh-solid">{{pluralize this.post.email.emailCount "member"}}</p>
|
<p class="ma0 pa0 f5 lh-solid">{{gh-pluralize this.post.email.emailCount "member"}}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pa5 pt3 pb3 f7 bb b--whitegrey">
|
<div class="pa5 pt3 pb3 f7 bb b--whitegrey">
|
||||||
@ -45,7 +45,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-column justify-center">
|
<div class="flex flex-column justify-center">
|
||||||
<p class="ma0 pa0 midgrey">Post failed to send to</p>
|
<p class="ma0 pa0 midgrey">Post failed to send to</p>
|
||||||
<p class="ma0 pa0 f5 lh-solid">{{pluralize this.post.email.emailCount "member"}}</p>
|
<p class="ma0 pa0 f5 lh-solid">{{gh-pluralize this.post.email.emailCount "member"}}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pa5 pt3 pb3 f7 bb b--whitegrey">
|
<div class="pa5 pt3 pb3 f7 bb b--whitegrey">
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import ModalComponent from 'ghost-admin/components/modal-base';
|
import ModalComponent from 'ghost-admin/components/modal-base';
|
||||||
import {computed} from '@ember/object';
|
import {computed} from '@ember/object';
|
||||||
import {pluralize} from 'ember-inflector';
|
import {ghPluralize} from 'ghost-admin/helpers/gh-pluralize';
|
||||||
import {inject as service} from '@ember/service';
|
import {inject as service} from '@ember/service';
|
||||||
import {task} from 'ember-concurrency';
|
import {task} from 'ember-concurrency';
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ export default ModalComponent.extend({
|
|||||||
return 'all members';
|
return 'all members';
|
||||||
}
|
}
|
||||||
|
|
||||||
return pluralize(this.get('model.memberCount'), 'member');
|
return ghPluralize(this.get('model.memberCount'), 'member');
|
||||||
}),
|
}),
|
||||||
|
|
||||||
confirmAndCheckError: task(function* () {
|
confirmAndCheckError: task(function* () {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<div class="modal-body" data-test-state="delete-unconfirmed">
|
<div class="modal-body" data-test-state="delete-unconfirmed">
|
||||||
<p>
|
<p>
|
||||||
You're about to delete
|
You're about to delete
|
||||||
<strong data-test-text="delete-count">{{pluralize this.model.memberCount "member"}}</strong>.
|
<strong data-test-text="delete-count">{{gh-pluralize this.model.memberCount "member"}}</strong>.
|
||||||
This is permanent! We warned you, k?
|
This is permanent! We warned you, k?
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -26,7 +26,7 @@
|
|||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
{{svg-jar "check-circle" class="w4 h4 stroke-green mr2"}}
|
{{svg-jar "check-circle" class="w4 h4 stroke-green mr2"}}
|
||||||
<p class="ma0 pa0">
|
<p class="ma0 pa0">
|
||||||
<span class="fw6" data-test-text="deleted-count">{{pluralize this.response.deleted.count "member"}}</span>
|
<span class="fw6" data-test-text="deleted-count">{{gh-pluralize this.response.deleted.count "member"}}</span>
|
||||||
deleted
|
deleted
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -35,7 +35,7 @@
|
|||||||
{{svg-jar "warning" class="w4 h4 fill-red mr2 nudge-top--3"}}
|
{{svg-jar "warning" class="w4 h4 fill-red mr2 nudge-top--3"}}
|
||||||
<div>
|
<div>
|
||||||
<p class="ma0 pa0">
|
<p class="ma0 pa0">
|
||||||
<span class="fw5" data-test-text="invalid-count">{{pluralize this.response.invalid.count "member"}}</span>
|
<span class="fw5" data-test-text="invalid-count">{{gh-pluralize this.response.invalid.count "member"}}</span>
|
||||||
skipped
|
skipped
|
||||||
</p>
|
</p>
|
||||||
{{#each this.response.invalid.errors as |error|}}
|
{{#each this.response.invalid.errors as |error|}}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
{{#if this.user.count.posts}}
|
{{#if this.user.count.posts}}
|
||||||
<p>
|
<p>
|
||||||
<strong>{{this.user.name}}</strong> and their <strong data-test-text="user-post-count">{{pluralize this.user.count.posts 'post'}}</strong> will be permanently deleted. If you don’t want to lose these posts, you should assign them to a different author.
|
<strong>{{this.user.name}}</strong> and their <strong data-test-text="user-post-count">{{gh-pluralize this.user.count.posts 'post'}}</strong> will be permanently deleted. If you don’t want to lose these posts, you should assign them to a different author.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
A backup will be automatically downloaded to your device before deletion.
|
A backup will be automatically downloaded to your device before deletion.
|
||||||
|
@ -100,11 +100,11 @@
|
|||||||
<div class="flex items-start">
|
<div class="flex items-start">
|
||||||
<div class="w-50 gh-member-import-result-summary">
|
<div class="w-50 gh-member-import-result-summary">
|
||||||
<h2>{{format-number this.importResponse.imported.count}}</h2>
|
<h2>{{format-number this.importResponse.imported.count}}</h2>
|
||||||
<p>{{pluralize this.importResponse.imported.count "Member" without-count=true}} added</p>
|
<p>{{gh-pluralize this.importResponse.imported.count "Member" without-count=true}} added</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="bl b--whitegrey w-50 gh-member-import-result-summary">
|
<div class="bl b--whitegrey w-50 gh-member-import-result-summary">
|
||||||
<h2>{{format-number this.importResponse.invalid.count}}</h2>
|
<h2>{{format-number this.importResponse.invalid.count}}</h2>
|
||||||
<p>{{pluralize this.importResponse.invalid.count "Error" without-count=true}}</p>
|
<p>{{gh-pluralize this.importResponse.invalid.count "Error" without-count=true}}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -114,7 +114,7 @@
|
|||||||
<div class="flex items-start">
|
<div class="flex items-start">
|
||||||
{{svg-jar "warning" class="w5 h5 fill-red nudge-top--3 mr3"}}
|
{{svg-jar "warning" class="w5 h5 fill-red nudge-top--3 mr3"}}
|
||||||
<div class="flex-grow w-100">
|
<div class="flex-grow w-100">
|
||||||
<p class="ma0 pa0">{{format-number this.importResponse.invalid.count}} {{pluralize this.importResponse.invalid.count "member" without-count=true}} were skipped due to the following errors:</p>
|
<p class="ma0 pa0">{{format-number this.importResponse.invalid.count}} {{gh-pluralize this.importResponse.invalid.count "member" without-count=true}} were skipped due to the following errors:</p>
|
||||||
<ul class="ma0 pa0 mt4 list bt b--whitegrey">
|
<ul class="ma0 pa0 mt4 list bt b--whitegrey">
|
||||||
{{#each this.importResponse.invalid.errors as |error|}}
|
{{#each this.importResponse.invalid.errors as |error|}}
|
||||||
<li class="gh-members-import-errormessage">{{error.message}} <span class="fw4">({{format-number error.count}})</span></li>
|
<li class="gh-members-import-errormessage">{{error.message}} <span class="fw4">({{format-number error.count}})</span></li>
|
||||||
@ -169,7 +169,7 @@
|
|||||||
<span>Start over</span>
|
<span>Start over</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="gh-btn gh-btn-green" {{action "upload"}} disabled={{this.importDisabled}}>
|
<button class="gh-btn gh-btn-green" {{action "upload"}} disabled={{this.importDisabled}}>
|
||||||
<span>Import{{#if this.fileData.length}} {{format-number this.fileData.length}} {{pluralize this.fileData.length 'member' without-count=true}}{{/if}}</span>
|
<span>Import{{#if this.fileData.length}} {{format-number this.fileData.length}} {{gh-pluralize this.fileData.length 'member' without-count=true}}{{/if}}</span>
|
||||||
</button>
|
</button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
|
@ -3,8 +3,7 @@ import ghostPaths from 'ghost-admin/utils/ghost-paths';
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import {A} from '@ember/array';
|
import {A} from '@ember/array';
|
||||||
import {action} from '@ember/object';
|
import {action} from '@ember/object';
|
||||||
import {formatNumber} from 'ghost-admin/helpers/format-number';
|
import {ghPluralize} from 'ghost-admin/helpers/pluralize';
|
||||||
import {pluralize} from 'ember-inflector';
|
|
||||||
import {inject as service} from '@ember/service';
|
import {inject as service} from '@ember/service';
|
||||||
import {task} from 'ember-concurrency-decorators';
|
import {task} from 'ember-concurrency-decorators';
|
||||||
import {timeout} from 'ember-concurrency';
|
import {timeout} from 'ember-concurrency';
|
||||||
@ -67,7 +66,7 @@ export default class MembersController extends Controller {
|
|||||||
return 'Search result';
|
return 'Search result';
|
||||||
}
|
}
|
||||||
|
|
||||||
let count = `${formatNumber(members.length)} ${pluralize(members.length, 'member', {withoutCount: true})}`;
|
let count = ghPluralize(members.length, 'member');
|
||||||
|
|
||||||
if (selectedLabel && selectedLabel.slug) {
|
if (selectedLabel && selectedLabel.slug) {
|
||||||
if (members.length > 1) {
|
if (members.length > 1) {
|
||||||
|
26
ghost/admin/app/helpers/gh-pluralize.js
Normal file
26
ghost/admin/app/helpers/gh-pluralize.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import {formatNumber} from './format-number';
|
||||||
|
import {helper} from '@ember/component/helper';
|
||||||
|
import {isBlank} from '@ember/utils';
|
||||||
|
import {pluralize} from 'ember-inflector';
|
||||||
|
|
||||||
|
export function ghPluralize(number, word, {'without-count': withoutCount} = {}) {
|
||||||
|
let output = [];
|
||||||
|
|
||||||
|
if (!isBlank(number) && withoutCount !== true) {
|
||||||
|
output.push(formatNumber(number));
|
||||||
|
}
|
||||||
|
|
||||||
|
// default {{pluralize}} allows for {{pluralize "word"}} with no number
|
||||||
|
if (isBlank(number)) {
|
||||||
|
output.push(pluralize(word, {withoutCount: true}));
|
||||||
|
} else {
|
||||||
|
output.push(pluralize(number, word, {withoutCount: true}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return output.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
// like {{pluralize}} but formats the number according to current locale
|
||||||
|
export default helper(function ([number, word], {'without-count': withoutCount} = {}) {
|
||||||
|
return ghPluralize(number, word, {'without-count': withoutCount});
|
||||||
|
});
|
@ -1,9 +1,8 @@
|
|||||||
import MemberImportError from 'ghost-admin/errors/member-import-error';
|
import MemberImportError from 'ghost-admin/errors/member-import-error';
|
||||||
import Service, {inject as service} from '@ember/service';
|
import Service, {inject as service} from '@ember/service';
|
||||||
import validator from 'validator';
|
import validator from 'validator';
|
||||||
import {formatNumber} from 'ghost-admin/helpers/format-number';
|
import {ghPluralize} from 'ghost-admin/helpers/gh-pluralize';
|
||||||
import {isEmpty} from '@ember/utils';
|
import {isEmpty} from '@ember/utils';
|
||||||
import {pluralize} from 'ember-inflector';
|
|
||||||
|
|
||||||
export default Service.extend({
|
export default Service.extend({
|
||||||
ajax: service(),
|
ajax: service(),
|
||||||
@ -34,7 +33,7 @@ export default Service.extend({
|
|||||||
if (!this.membersUtils.isStripeEnabled) {
|
if (!this.membersUtils.isStripeEnabled) {
|
||||||
validationErrors.push(new MemberImportError({
|
validationErrors.push(new MemberImportError({
|
||||||
message: `Missing Stripe connection`,
|
message: `Missing Stripe connection`,
|
||||||
context: `${formatNumber(totalCount)} ${pluralize(totalCount, 'Stripe customer', {withoutCount: true})} won't be imported. You need to <a href="#/settings/labs">connect to Stripe</a> to import Stripe customers.`,
|
context: `${ghPluralize(totalCount, 'Stripe customer')} won't be imported. You need to <a href="#/settings/labs">connect to Stripe</a> to import Stripe customers.`,
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
|
@ -85,7 +85,7 @@
|
|||||||
|
|
||||||
<div class="absolute flex items-center br3 bg-white {{if editor.headerClass "right-4 bottom-4" "right-6 bottom-6"}}">
|
<div class="absolute flex items-center br3 bg-white {{if editor.headerClass "right-4 bottom-4" "right-6 bottom-6"}}">
|
||||||
<div class="midgrey-l2 {{if editor.headerClass "f-supersmall pl2 pr2" "f8 pl4 pr3"}} fw4">
|
<div class="midgrey-l2 {{if editor.headerClass "f-supersmall pl2 pr2" "f8 pl4 pr3"}} fw4">
|
||||||
{{pluralize this.wordCount.wordCount "word"}}
|
{{gh-pluralize this.wordCount.wordCount "word"}}
|
||||||
</div>
|
</div>
|
||||||
<a href="https://ghost.org/faq/using-the-editor/" class="flex {{if editor.headerClass "pa2" "pa3"}}" target="_blank">{{svg-jar "help" class="w4 h4 stroke-midgrey-l2"}}</a>
|
<a href="https://ghost.org/faq/using-the-editor/" class="flex {{if editor.headerClass "pa2" "pa3"}}" target="_blank">{{svg-jar "help" class="w4 h4 stroke-midgrey-l2"}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -78,7 +78,7 @@
|
|||||||
</button>
|
</button>
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
||||||
<h3>Uploading {{pluralize upload.files.length "image"}}...</h3>
|
<h3>Uploading {{gh-pluralize upload.files.length "image"}}...</h3>
|
||||||
{{upload.progressBar}}
|
{{upload.progressBar}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user