Add grammar util
This contains the function `toNounSeriesText` which can be used to build i18n noun series fragments (i.e. "A, B, and C").
This commit is contained in:
parent
11f9edec0c
commit
9cfb253ed4
3 changed files with 84 additions and 0 deletions
40
app/assets/javascripts/lib/utils/grammar.js
Normal file
40
app/assets/javascripts/lib/utils/grammar.js
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import { sprintf, s__ } from '~/locale';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines each given item into a noun series sentence fragment. It does this
|
||||||
|
* in a way that supports i18n by giving context and punctuation to the locale
|
||||||
|
* functions.
|
||||||
|
*
|
||||||
|
* **Examples:**
|
||||||
|
*
|
||||||
|
* - `["A", "B"] => "A and B"`
|
||||||
|
* - `["A", "B", "C"] => "A, B, and C"`
|
||||||
|
*
|
||||||
|
* **Why only nouns?**
|
||||||
|
*
|
||||||
|
* Some languages need a bit more context to translate other series.
|
||||||
|
*
|
||||||
|
* @param {String[]} items
|
||||||
|
*/
|
||||||
|
export const toNounSeriesText = items => {
|
||||||
|
if (items.length === 0) {
|
||||||
|
return '';
|
||||||
|
} else if (items.length === 1) {
|
||||||
|
return items[0];
|
||||||
|
} else if (items.length === 2) {
|
||||||
|
return sprintf(s__('nounSeries|%{firstItem} and %{lastItem}'), {
|
||||||
|
firstItem: items[0],
|
||||||
|
lastItem: items[1],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return items.reduce((item, nextItem, idx) =>
|
||||||
|
idx === items.length - 1
|
||||||
|
? sprintf(s__('nounSeries|%{item}, and %{lastItem}'), { item, lastItem: nextItem })
|
||||||
|
: sprintf(s__('nounSeries|%{item}, %{nextItem}'), { item, nextItem }),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
toNounSeriesText,
|
||||||
|
};
|
|
@ -8706,6 +8706,15 @@ msgstr ""
|
||||||
msgid "notification emails"
|
msgid "notification emails"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "nounSeries|%{firstItem} and %{lastItem}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "nounSeries|%{item}, %{nextItem}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "nounSeries|%{item}, and %{lastItem}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "or"
|
msgid "or"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
35
spec/javascripts/lib/utils/grammar_spec.js
Normal file
35
spec/javascripts/lib/utils/grammar_spec.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import * as grammar from '~/lib/utils/grammar';
|
||||||
|
|
||||||
|
describe('utils/grammar', () => {
|
||||||
|
describe('toNounSeriesText', () => {
|
||||||
|
it('with empty items returns empty string', () => {
|
||||||
|
expect(grammar.toNounSeriesText([])).toBe('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with single item returns item', () => {
|
||||||
|
const items = ['Lorem Ipsum'];
|
||||||
|
|
||||||
|
expect(grammar.toNounSeriesText(items)).toBe(items[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with 2 items returns item1 and item2', () => {
|
||||||
|
const items = ['Dolar', 'Sit Amit'];
|
||||||
|
|
||||||
|
expect(grammar.toNounSeriesText(items)).toBe(`${items[0]} and ${items[1]}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with 3 items returns comma separated series', () => {
|
||||||
|
const items = ['Lorem', 'Ipsum', 'dolar'];
|
||||||
|
const expected = 'Lorem, Ipsum, and dolar';
|
||||||
|
|
||||||
|
expect(grammar.toNounSeriesText(items)).toBe(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with 6 items returns comma separated series', () => {
|
||||||
|
const items = ['Lorem', 'ipsum', 'dolar', 'sit', 'amit', 'consectetur'];
|
||||||
|
const expected = 'Lorem, ipsum, dolar, sit, amit, and consectetur';
|
||||||
|
|
||||||
|
expect(grammar.toNounSeriesText(items)).toBe(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue