@eeacms/volto-eea-design-system 1.16.0 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/docker-compose.yml +5 -1
- package/locales/en/LC_MESSAGES/volto.po +14 -0
- package/package.json +1 -1
- package/src/helpers/index.js +4 -4
- package/src/helpers/useClickOutside.test.js +63 -0
- package/src/helpers/useFirstVisited.test.js +54 -0
- package/src/ui/Accordion/Accordion.stories.js +3 -1
- package/src/ui/Accordion/Accordion.stories.test.js +45 -0
- package/src/ui/Banner/Banner.test.jsx +292 -0
- package/src/ui/CallToAction/CallToAction.stories.test.jsx +69 -0
- package/src/ui/Card/Card.stories.test.jsx +82 -0
- package/src/ui/Card/IconCard/IconCard.stories.test.jsx +64 -0
- package/src/ui/Card/RelatedContent/RelatedContent.jsx +1 -1
- package/src/ui/Card/RelatedContent/RelatedContent.stories.jsx +2 -2
- package/src/ui/Card/RelatedContent/RelatedContent.stories.test.jsx +65 -0
- package/src/ui/Confirm/Confirm.stories.test.js +27 -0
- package/src/ui/ContextNavigation/ContextNavigation.stories.test.jsx +170 -0
- package/src/ui/Divider/Divider.stories.test.jsx +44 -0
- package/src/ui/DownloadLabeledIcon/DownloadLabeledIcon.stories.test.jsx +24 -0
- package/src/ui/Footer/Description.test.jsx +11 -0
- package/src/ui/Footer/Footer.stories.test.js +131 -0
- package/src/ui/Footer/Social.test.jsx +11 -0
- package/src/ui/Form/Button/Button.stories.test.jsx +55 -0
- package/src/ui/Form/Checkbox.stories.test.js +79 -0
- package/src/ui/Form/Dropdown.stories.test.js +24 -0
- package/src/ui/Form/Radio.stories.test.js +55 -0
- package/src/ui/Form/Textarea.stories.test.js +41 -0
- package/src/ui/Form/input.stories.test.js +52 -0
- package/src/ui/Grid/ComponentGrid.stories.test.js +21 -0
- package/src/ui/Header/Header.stories.test.js +158 -0
- package/src/ui/Header/Header.test.jsx +293 -0
- package/src/ui/Header/HeaderMenuPopUp.js +12 -4
- package/src/ui/Header/HeaderSearchPopUp.test.js +113 -0
- package/src/ui/Hero/Hero.stories.test.jsx +67 -0
- package/src/ui/InpageNavigation/InpageNavigation.stories.test.jsx +10 -0
- package/src/ui/InpageNavigation/InpageNavigation.test.jsx +87 -0
- package/src/ui/Item/Item.stories.test.js +39 -0
- package/src/ui/Item/ItemGroupWithIcons.stories.test.js +119 -0
- package/src/ui/Label/Label.stories.test.js +76 -0
- package/src/ui/LabeledIconGroup/LabeledIconGroup.stories.test.jsx +19 -0
- package/src/ui/LanguageLabeledIcon/LanguageLabeledIcon.jsx +3 -2
- package/src/ui/LanguageLabeledIcon/LanguangeLabeledIcon.test.jsx +60 -0
- package/src/ui/Loader/Loader.stories.test.jsx +30 -0
- package/src/ui/Logo/Logo.stories.test.jsx +81 -0
- package/src/ui/Media/Image.stories.test.js +35 -0
- package/src/ui/Message/Message.stories.test.js +44 -0
- package/src/ui/Modal/Modal.stories.test.js +45 -0
- package/src/ui/Popup/Popup.jsx +24 -17
- package/src/ui/Popup/Popup.test.jsx +60 -0
- package/src/ui/Progress/Progress.stories.test.js +30 -0
- package/src/ui/Quote/Testimonial/Testimonial.stories.test.jsx +18 -0
- package/src/ui/Statistic/Statistic.stories.test.js +69 -0
- package/src/ui/Table/Table.stories.js +8 -0
- package/src/ui/Table/Table.stories.test.js +54 -0
- package/src/ui/Timeline/Timeline.stories.test.jsx +43 -0
- package/src/ui/index.js +21 -41
- package/theme/themes/eea/extras/banner.less +3 -3
- package/src/i18n.js +0 -180
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import { Default, ProgressWithValue, CustomColor } from './Progress.stories';
|
|
4
|
+
import '@testing-library/jest-dom/extend-expect';
|
|
5
|
+
|
|
6
|
+
describe('CustomColor component', () => {
|
|
7
|
+
it('renders correctly', () => {
|
|
8
|
+
const { getByText } = render(<CustomColor {...CustomColor.args} />);
|
|
9
|
+
expect(getByText(`${CustomColor.args.value}%`)).toBeInTheDocument();
|
|
10
|
+
expect(getByText(`${CustomColor.args.children}`)).toBeInTheDocument();
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('ProgressWithValue component', () => {
|
|
15
|
+
it('renders correctly', () => {
|
|
16
|
+
const { getByText } = render(
|
|
17
|
+
<ProgressWithValue {...ProgressWithValue.args} />,
|
|
18
|
+
);
|
|
19
|
+
expect(getByText(`${ProgressWithValue.args.value}%`)).toBeInTheDocument();
|
|
20
|
+
expect(getByText(`${ProgressWithValue.args.children}`)).toBeInTheDocument();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('Default component', () => {
|
|
25
|
+
it('renders correctly', () => {
|
|
26
|
+
const { getByText } = render(<Default {...Default.args} />);
|
|
27
|
+
expect(getByText(`${Default.args.percent}%`)).toBeInTheDocument();
|
|
28
|
+
expect(getByText(`${Default.args.children}`)).toBeInTheDocument();
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import { Inline } from './Testimonial.stories';
|
|
4
|
+
import '@testing-library/jest-dom/extend-expect';
|
|
5
|
+
|
|
6
|
+
describe('Inline component', () => {
|
|
7
|
+
it('renders corectly', () => {
|
|
8
|
+
const { container, getByText } = render(<Inline {...Inline.args} />);
|
|
9
|
+
|
|
10
|
+
expect(
|
|
11
|
+
container.querySelector(`div[quote="${Inline.args.quote}"]`),
|
|
12
|
+
).toBeInTheDocument();
|
|
13
|
+
expect(getByText(Inline.args.avatartitle)).toBeInTheDocument();
|
|
14
|
+
expect(getByText(Inline.args.avatarinfo)).toBeInTheDocument();
|
|
15
|
+
expect(getByText(Inline.args.title)).toBeInTheDocument();
|
|
16
|
+
expect(getByText(Inline.args.quote)).toBeInTheDocument();
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import {
|
|
4
|
+
Default,
|
|
5
|
+
Group,
|
|
6
|
+
Custom,
|
|
7
|
+
Animation,
|
|
8
|
+
AnimationGroup,
|
|
9
|
+
} from './Statistic.stories';
|
|
10
|
+
import '@testing-library/jest-dom/extend-expect';
|
|
11
|
+
|
|
12
|
+
describe('AnimationGroup component', () => {
|
|
13
|
+
it('renders a button with label', () => {
|
|
14
|
+
const { getByText } = render(<AnimationGroup {...AnimationGroup.args} />);
|
|
15
|
+
|
|
16
|
+
expect(
|
|
17
|
+
getByText(AnimationGroup.args.elements[0].label),
|
|
18
|
+
).toBeInTheDocument();
|
|
19
|
+
expect(
|
|
20
|
+
getByText(AnimationGroup.args.elements[1].label),
|
|
21
|
+
).toBeInTheDocument();
|
|
22
|
+
expect(
|
|
23
|
+
getByText(AnimationGroup.args.elements[2].label),
|
|
24
|
+
).toBeInTheDocument();
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('Animation component', () => {
|
|
29
|
+
it('renders a button with label', () => {
|
|
30
|
+
const { getByText } = render(<Animation {...Animation.args} />);
|
|
31
|
+
|
|
32
|
+
expect(getByText('Count up label')).toBeInTheDocument();
|
|
33
|
+
expect(getByText('Start')).toBeInTheDocument();
|
|
34
|
+
expect(getByText('Reset')).toBeInTheDocument();
|
|
35
|
+
expect(getByText('Pause/Resume')).toBeInTheDocument();
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe('Custom component', () => {
|
|
40
|
+
it('renders a button with label', () => {
|
|
41
|
+
const { getByText, getAllByText } = render(<Custom {...Custom.args} />);
|
|
42
|
+
|
|
43
|
+
Custom.args.elements.forEach((element) => {
|
|
44
|
+
expect(getByText(element.value)).toBeInTheDocument();
|
|
45
|
+
expect(getByText(element.label)).toBeInTheDocument();
|
|
46
|
+
});
|
|
47
|
+
expect(getAllByText('Text from slate')).toHaveLength(3);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('Group component', () => {
|
|
52
|
+
it('renders a button with label', () => {
|
|
53
|
+
const { getByText } = render(<Group {...Group.args} />);
|
|
54
|
+
|
|
55
|
+
Group.args.elements.forEach((element) => {
|
|
56
|
+
expect(getByText(element.value)).toBeInTheDocument();
|
|
57
|
+
expect(getByText(element.label)).toBeInTheDocument();
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('Default component', () => {
|
|
63
|
+
it('renders a button with label', () => {
|
|
64
|
+
const { getByText } = render(<Default {...Default.args} />);
|
|
65
|
+
|
|
66
|
+
expect(getByText(Default.args.label)).toBeInTheDocument();
|
|
67
|
+
expect(getByText(Default.args.value)).toBeInTheDocument();
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -270,9 +270,17 @@ function SortableTableContent({
|
|
|
270
270
|
key={item.key}
|
|
271
271
|
textAlign="center"
|
|
272
272
|
sorted={column === item.key ? direction : null}
|
|
273
|
+
tabIndex={0}
|
|
273
274
|
onClick={() =>
|
|
274
275
|
dispatch({ type: 'CHANGE_SORT', column: item.key })
|
|
275
276
|
}
|
|
277
|
+
onKeyDown={(event) => {
|
|
278
|
+
if (event.key === 'Enter') {
|
|
279
|
+
event.preventDefault();
|
|
280
|
+
event.target.click();
|
|
281
|
+
}
|
|
282
|
+
}}
|
|
283
|
+
aria-label={direction ? direction + ` sorted ` : ''}
|
|
276
284
|
>
|
|
277
285
|
{item.name}
|
|
278
286
|
</Table.HeaderCell>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, fireEvent } from '@testing-library/react';
|
|
3
|
+
import { Default, Sortable, Responsive } from './Table.stories';
|
|
4
|
+
import '@testing-library/jest-dom/extend-expect';
|
|
5
|
+
|
|
6
|
+
describe('Responsive component', () => {
|
|
7
|
+
it('renders corectly', () => {
|
|
8
|
+
const { getByText } = render(<Responsive {...Responsive.args} />);
|
|
9
|
+
|
|
10
|
+
Responsive.args.headers.forEach((element) => {
|
|
11
|
+
expect(getByText(element.name)).toBeInTheDocument();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
Responsive.args.tableData.forEach((element) => {
|
|
15
|
+
expect(getByText(element.col1)).toBeInTheDocument();
|
|
16
|
+
expect(getByText(element.col2)).toBeInTheDocument();
|
|
17
|
+
expect(getByText(element.col3)).toBeInTheDocument();
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('Sortable component', () => {
|
|
23
|
+
it('renders corectly', () => {
|
|
24
|
+
const { getByText } = render(<Sortable {...Sortable.args} />);
|
|
25
|
+
|
|
26
|
+
Sortable.args.headers.forEach((element) => {
|
|
27
|
+
expect(getByText(element.name)).toBeInTheDocument();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
Sortable.args.tableData.forEach((element) => {
|
|
31
|
+
expect(getByText(element.col1)).toBeInTheDocument();
|
|
32
|
+
expect(getByText(element.col2)).toBeInTheDocument();
|
|
33
|
+
expect(getByText(element.col3)).toBeInTheDocument();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
fireEvent.click(getByText(Sortable.args.headers[0].name));
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe('Default component', () => {
|
|
41
|
+
it('renders corectly', () => {
|
|
42
|
+
const { getByText } = render(<Default {...Default.args} />);
|
|
43
|
+
|
|
44
|
+
Default.args.headers.forEach((element) => {
|
|
45
|
+
expect(getByText(element.name)).toBeInTheDocument();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
Default.args.tableData.forEach((element) => {
|
|
49
|
+
expect(getByText(element.col1)).toBeInTheDocument();
|
|
50
|
+
expect(getByText(element.col2)).toBeInTheDocument();
|
|
51
|
+
expect(getByText(element.col3)).toBeInTheDocument();
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import {
|
|
4
|
+
Default,
|
|
5
|
+
DefaultReversed,
|
|
6
|
+
Multiple,
|
|
7
|
+
MultipleReversed,
|
|
8
|
+
} from './Timeline.stories';
|
|
9
|
+
import '@testing-library/jest-dom/extend-expect';
|
|
10
|
+
|
|
11
|
+
describe('MultipleReversed component', () => {
|
|
12
|
+
it('renders corectly', () => {
|
|
13
|
+
const { getAllByText } = render(
|
|
14
|
+
<MultipleReversed {...MultipleReversed.args} />,
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
expect(getAllByText(MultipleReversed.args.items[0].time)).toHaveLength(3);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('Multiple component', () => {
|
|
22
|
+
it('renders corectly', () => {
|
|
23
|
+
const { getAllByText } = render(<Multiple {...Multiple.args} />);
|
|
24
|
+
|
|
25
|
+
expect(getAllByText(Multiple.args.items[0].time)).toHaveLength(3);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('DefaultReversed component', () => {
|
|
30
|
+
it('renders corectly', () => {
|
|
31
|
+
const { getByText } = render(<DefaultReversed {...DefaultReversed.args} />);
|
|
32
|
+
|
|
33
|
+
expect(getByText(DefaultReversed.args.time)).toBeInTheDocument();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe('Default component', () => {
|
|
38
|
+
it('renders corectly', () => {
|
|
39
|
+
const { getByText } = render(<Default {...Default.args} />);
|
|
40
|
+
|
|
41
|
+
expect(getByText(Default.args.time)).toBeInTheDocument();
|
|
42
|
+
});
|
|
43
|
+
});
|
package/src/ui/index.js
CHANGED
|
@@ -1,41 +1,21 @@
|
|
|
1
|
-
export Banner from './Banner/Banner';
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
-
export
|
|
20
|
-
|
|
21
|
-
export
|
|
22
|
-
|
|
23
|
-
export Testimonial from './Quote/Testimonial/Testimonial';
|
|
24
|
-
|
|
25
|
-
export KeyContent from './KeyContent/KeyContent';
|
|
26
|
-
|
|
27
|
-
export DownloadLabeledIcon from './DownloadLabeledIcon/DownloadLabeledIcon';
|
|
28
|
-
|
|
29
|
-
export NewTabLabeledIcon from './NewTabLabeledIcon/NewTabLabeledIcon';
|
|
30
|
-
|
|
31
|
-
export LabeledIconGroup from './LabeledIconGroup/LabeledIconGroup';
|
|
32
|
-
|
|
33
|
-
export LanguageLabeledIcon from './LanguageLabeledIcon/LanguageLabeledIcon';
|
|
34
|
-
|
|
35
|
-
export RelatedContent from './Card/RelatedContent/RelatedContent';
|
|
36
|
-
|
|
37
|
-
export Hero from './Hero/Hero';
|
|
38
|
-
|
|
39
|
-
export Copyright from './Copyright/Copyright';
|
|
40
|
-
|
|
41
|
-
export Video from './Video/Video';
|
|
1
|
+
export { default as Banner } from './Banner/Banner';
|
|
2
|
+
export { default as Callout } from './Callout/Callout';
|
|
3
|
+
export { default as Breadcrumbs } from './Breadcrumbs/Breadcrumbs';
|
|
4
|
+
export { default as Tag } from './Tag/Tag';
|
|
5
|
+
export { default as TagList } from './TagList/TagList';
|
|
6
|
+
export { default as Footer } from './Footer/Footer';
|
|
7
|
+
export { default as Header } from './Header/Header';
|
|
8
|
+
export { default as InpageNavigation } from './InpageNavigation/InpageNavigation';
|
|
9
|
+
export { default as Logo } from './Logo/Logo';
|
|
10
|
+
export { default as Quote } from './Quote/Quote';
|
|
11
|
+
export { default as Timeline } from './Timeline/Timeline';
|
|
12
|
+
export { default as Testimonial } from './Quote/Testimonial/Testimonial';
|
|
13
|
+
export { default as KeyContent } from './KeyContent/KeyContent';
|
|
14
|
+
export { default as DownloadLabeledIcon } from './DownloadLabeledIcon/DownloadLabeledIcon';
|
|
15
|
+
export { default as NewTabLabeledIcon } from './NewTabLabeledIcon/NewTabLabeledIcon';
|
|
16
|
+
export { default as LabeledIconGroup } from './LabeledIconGroup/LabeledIconGroup';
|
|
17
|
+
export { default as LanguageLabeledIcon } from './LanguageLabeledIcon/LanguageLabeledIcon';
|
|
18
|
+
export { default as RelatedContent } from './Card/RelatedContent/RelatedContent';
|
|
19
|
+
export { default as Hero } from './Hero/Hero';
|
|
20
|
+
export { default as Copyright } from './Copyright/Copyright';
|
|
21
|
+
export { default as Video } from './Video/Video';
|
|
@@ -59,9 +59,9 @@
|
|
|
59
59
|
align-items: @mobileActionsAlignItems;
|
|
60
60
|
justify-content: flex-end;
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
.action {
|
|
63
63
|
.ui.basic.inverted.button {
|
|
64
|
-
/* used basic inverted button for
|
|
64
|
+
/* used basic inverted button for minimum overrides on box-shadow and active state background */
|
|
65
65
|
box-shadow: @bannerActionButtonBoxShadow !important;
|
|
66
66
|
|
|
67
67
|
&:active {
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
flex-direction: @tabletActionsFlexDirection;
|
|
167
167
|
align-items: @tabletActionsAlignItems;
|
|
168
168
|
|
|
169
|
-
|
|
169
|
+
.action {
|
|
170
170
|
min-width: @tabletActionsActionMinWidth;
|
|
171
171
|
|
|
172
172
|
.ui.basic.inverted.button i.icon {
|
package/src/i18n.js
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
/* eslint no-console: 0 */
|
|
2
|
-
/**
|
|
3
|
-
* i18n script.
|
|
4
|
-
* @module scripts/i18n
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const { find, keys, map, concat, reduce } = require('lodash');
|
|
8
|
-
const glob = require('glob').sync;
|
|
9
|
-
const fs = require('fs');
|
|
10
|
-
const Pofile = require('pofile');
|
|
11
|
-
const babel = require('@babel/core');
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Extract messages into separate JSON files
|
|
15
|
-
* @function extractMessages
|
|
16
|
-
* @return {undefined}
|
|
17
|
-
*/
|
|
18
|
-
function extractMessages() {
|
|
19
|
-
map(glob('src/**/*.js?(x)'), (filename) => {
|
|
20
|
-
babel.transformFileSync(filename, {}, (err) => {
|
|
21
|
-
if (err) {
|
|
22
|
-
console.log(err);
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Get messages from separate JSON files
|
|
30
|
-
* @function getMessages
|
|
31
|
-
* @return {Object} Object with messages
|
|
32
|
-
*/
|
|
33
|
-
function getMessages() {
|
|
34
|
-
return reduce(
|
|
35
|
-
concat(
|
|
36
|
-
{},
|
|
37
|
-
...map(
|
|
38
|
-
// We ignore the existing customized shadowed components ones, since most
|
|
39
|
-
// probably we won't be overriding them
|
|
40
|
-
// If so, we should do it in the config object or somewhere else
|
|
41
|
-
glob('build/messages/src/**/*.json', {
|
|
42
|
-
ignore: 'build/messages/src/customizations/**',
|
|
43
|
-
}),
|
|
44
|
-
(filename) =>
|
|
45
|
-
map(JSON.parse(fs.readFileSync(filename, 'utf8')), (message) => ({
|
|
46
|
-
...message,
|
|
47
|
-
filename: filename.match(/build\/messages\/src\/(.*).json$/)[1],
|
|
48
|
-
})),
|
|
49
|
-
),
|
|
50
|
-
),
|
|
51
|
-
(current, value) => {
|
|
52
|
-
let result = current;
|
|
53
|
-
if (current.id) {
|
|
54
|
-
result = {
|
|
55
|
-
[current.id]: {
|
|
56
|
-
defaultMessage: current.defaultMessage,
|
|
57
|
-
filenames: [current.filename],
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (result[value.id]) {
|
|
63
|
-
result[value.id].filenames.push(value.filename);
|
|
64
|
-
} else {
|
|
65
|
-
result[value.id] = {
|
|
66
|
-
defaultMessage: value.defaultMessage,
|
|
67
|
-
filenames: [value.filename],
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
return result;
|
|
71
|
-
},
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Convert messages to pot format
|
|
77
|
-
* @function messagesToPot
|
|
78
|
-
* @param {Object} messages Messages
|
|
79
|
-
* @return {string} Formatted pot string
|
|
80
|
-
*/
|
|
81
|
-
function messagesToPot(messages) {
|
|
82
|
-
return map(keys(messages).sort(), (key) =>
|
|
83
|
-
[
|
|
84
|
-
...map(messages[key].filenames, (filename) => `#: ${filename}`),
|
|
85
|
-
`# defaultMessage: ${messages[key].defaultMessage}`,
|
|
86
|
-
`msgid "${key}"`,
|
|
87
|
-
'msgstr ""',
|
|
88
|
-
].join('\n'),
|
|
89
|
-
).join('\n\n');
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Pot header
|
|
94
|
-
* @function potHeader
|
|
95
|
-
* @return {string} Formatted pot header
|
|
96
|
-
*/
|
|
97
|
-
function potHeader() {
|
|
98
|
-
return `msgid ""
|
|
99
|
-
msgstr ""
|
|
100
|
-
"Project-Id-Version: Plone\\n"
|
|
101
|
-
"POT-Creation-Date: ${new Date().toISOString()}\\n"
|
|
102
|
-
"Last-Translator: Plone i18n <plone-i18n@lists.sourceforge.net>\\n"
|
|
103
|
-
"Language-Team: Plone i18n <plone-i18n@lists.sourceforge.net>\\n"
|
|
104
|
-
"MIME-Version: 1.0\\n"
|
|
105
|
-
"Content-Type: text/plain; charset=utf-8\\n"
|
|
106
|
-
"Content-Transfer-Encoding: 8bit\\n"
|
|
107
|
-
"Plural-Forms: nplurals=1; plural=0;\\n"
|
|
108
|
-
"Language-Code: en\\n"
|
|
109
|
-
"Language-Name: English\\n"
|
|
110
|
-
"Preferred-Encodings: utf-8\\n"
|
|
111
|
-
"Domain: volto\\n"
|
|
112
|
-
|
|
113
|
-
`;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Format header
|
|
118
|
-
* @function formatHeader
|
|
119
|
-
* @param {Array} comments Array of comments
|
|
120
|
-
* @param {Object} headers Object of header items
|
|
121
|
-
* @return {string} Formatted header
|
|
122
|
-
*/
|
|
123
|
-
function formatHeader(comments, headers) {
|
|
124
|
-
return [
|
|
125
|
-
...map(comments, (comment) => `# ${comment}`),
|
|
126
|
-
'msgid ""',
|
|
127
|
-
'msgstr ""',
|
|
128
|
-
...map(keys(headers), (key) => `"${key}: ${headers[key]}\\n"`),
|
|
129
|
-
'',
|
|
130
|
-
].join('\n');
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Sync po by the pot file
|
|
135
|
-
* @function syncPoByPot
|
|
136
|
-
* @return {undefined}
|
|
137
|
-
*/
|
|
138
|
-
function syncPoByPot() {
|
|
139
|
-
const pot = Pofile.parse(fs.readFileSync('locales/volto.pot', 'utf8'));
|
|
140
|
-
|
|
141
|
-
map(glob('locales/**/*.po'), (filename) => {
|
|
142
|
-
const po = Pofile.parse(fs.readFileSync(filename, 'utf8'));
|
|
143
|
-
|
|
144
|
-
fs.writeFileSync(
|
|
145
|
-
filename,
|
|
146
|
-
`${formatHeader(po.comments, po.headers)}
|
|
147
|
-
${map(pot.items, (item) => {
|
|
148
|
-
const poItem = find(po.items, { msgid: item.msgid });
|
|
149
|
-
return [
|
|
150
|
-
`${map(item.references, (ref) => `#: ${ref}`).join('\n')}`,
|
|
151
|
-
`msgid "${item.msgid}"`,
|
|
152
|
-
`msgstr "${poItem ? poItem.msgstr : ''}"`,
|
|
153
|
-
].join('\n');
|
|
154
|
-
}).join('\n\n')}\n`,
|
|
155
|
-
);
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Main tasks
|
|
160
|
-
console.log('Extracting messages from source files...');
|
|
161
|
-
extractMessages();
|
|
162
|
-
console.log('Synchronizing messages to pot file...');
|
|
163
|
-
// We only write the pot file if it's really different
|
|
164
|
-
const newPot = `${potHeader()}${messagesToPot(getMessages())}\n`.replace(
|
|
165
|
-
/"POT-Creation-Date:(.*)\\n"/,
|
|
166
|
-
'',
|
|
167
|
-
);
|
|
168
|
-
const oldPot = fs
|
|
169
|
-
.readFileSync('locales/volto.pot', 'utf8')
|
|
170
|
-
.replace(/"POT-Creation-Date:(.*)\\n"/, '');
|
|
171
|
-
|
|
172
|
-
if (newPot !== oldPot) {
|
|
173
|
-
fs.writeFileSync(
|
|
174
|
-
'locales/volto.pot',
|
|
175
|
-
`${potHeader()}${messagesToPot(getMessages())}\n`,
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
console.log('Synchronizing messages to po files...');
|
|
179
|
-
syncPoByPot();
|
|
180
|
-
console.log('done!');
|