@ndla/ui 30.8.3 → 30.9.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/es/Article/Article.js +3 -3
- package/es/Article/ArticleSideBar.js +5 -5
- package/es/AudioPlayer/Controls.js +26 -26
- package/es/AudioPlayer/SpeechControl.js +1 -1
- package/es/Frontpage/FrontpageSearch.js +2 -9
- package/es/MediaList/MediaList.js +1 -0
- package/es/Messages/MessageBox.js +10 -10
- package/es/NDLAFilm/AllMoviesAlphabetically.js +11 -11
- package/es/NDLAFilm/FilmSlideshow.js +7 -7
- package/es/NDLAFilm/MovieGrid.js +4 -4
- package/es/Programme/Programme.js +5 -5
- package/es/ResourceGroup/ResourceItem.js +12 -13
- package/es/ResourceGroup/ResourceList.js +3 -4
- package/es/Search/SearchField.js +2 -3
- package/es/Subject/SubjectNewContent.js +10 -10
- package/es/TreeStructure/AddFolderButton.js +9 -9
- package/es/TreeStructure/ComboboxButton.js +30 -5
- package/es/TreeStructure/TreeStructure.js +9 -7
- package/es/i18n/index.js +1 -2
- package/es/index.js +1 -1
- package/lib/Article/Article.js +3 -3
- package/lib/Article/ArticleSideBar.js +5 -5
- package/lib/AudioPlayer/Controls.js +26 -26
- package/lib/AudioPlayer/SpeechControl.js +1 -1
- package/lib/Frontpage/FrontpageSearch.js +2 -9
- package/lib/MediaList/MediaList.js +1 -0
- package/lib/Messages/MessageBox.js +10 -10
- package/lib/NDLAFilm/AllMoviesAlphabetically.js +11 -11
- package/lib/NDLAFilm/FilmSlideshow.js +7 -7
- package/lib/NDLAFilm/MovieGrid.js +4 -4
- package/lib/Programme/Programme.js +5 -5
- package/lib/ResourceGroup/ResourceItem.js +11 -11
- package/lib/ResourceGroup/ResourceList.js +2 -2
- package/lib/Search/SearchField.js +2 -3
- package/lib/Subject/SubjectNewContent.js +10 -10
- package/lib/TreeStructure/AddFolderButton.d.ts +2 -1
- package/lib/TreeStructure/AddFolderButton.js +9 -9
- package/lib/TreeStructure/ComboboxButton.d.ts +1 -0
- package/lib/TreeStructure/ComboboxButton.js +29 -3
- package/lib/TreeStructure/TreeStructure.js +9 -7
- package/lib/i18n/index.d.ts +0 -1
- package/lib/i18n/index.js +1 -8
- package/lib/index.d.ts +1 -1
- package/lib/index.js +0 -7
- package/package.json +10 -12
- package/src/Article/Article.tsx +1 -1
- package/src/Article/ArticleSideBar.tsx +1 -1
- package/src/AudioPlayer/Controls.tsx +1 -0
- package/src/AudioPlayer/SpeechControl.tsx +1 -0
- package/src/Frontpage/FrontpageSearch.tsx +0 -7
- package/src/MediaList/MediaList.tsx +1 -0
- package/src/Messages/MessageBox.tsx +1 -1
- package/src/NDLAFilm/AllMoviesAlphabetically.tsx +1 -1
- package/src/NDLAFilm/FilmSlideshow.tsx +1 -1
- package/src/NDLAFilm/MovieGrid.tsx +2 -1
- package/src/Programme/Programme.tsx +1 -2
- package/src/ResourceGroup/ResourceItem.tsx +1 -2
- package/src/ResourceGroup/ResourceList.tsx +1 -2
- package/src/Search/SearchField.tsx +1 -2
- package/src/Subject/SubjectNewContent.tsx +2 -2
- package/src/TreeStructure/AddFolderButton.tsx +16 -17
- package/src/TreeStructure/ComboboxButton.tsx +45 -20
- package/src/TreeStructure/TreeStructure.tsx +2 -0
- package/src/i18n/index.ts +0 -1
- package/src/index.ts +1 -1
- package/es/i18n/formatMessage.js +0 -45
- package/lib/i18n/formatMessage.d.ts +0 -14
- package/lib/i18n/formatMessage.js +0 -53
- package/src/i18n/__tests__/formatMessage-test.ts +0 -34
- package/src/i18n/formatMessage.ts +0 -61
|
@@ -66,8 +66,9 @@ const MovieGrid = ({
|
|
|
66
66
|
<MovieListing marginLeft={autoSizedProps.margin}>
|
|
67
67
|
{fetchingMoviesByType && <LoadingPlaceholder height={loadingPlaceholderHeight} />}
|
|
68
68
|
{!fetchingMoviesByType &&
|
|
69
|
-
moviesByType.map((movie) => (
|
|
69
|
+
moviesByType.map((movie, index) => (
|
|
70
70
|
<FilmContentCard
|
|
71
|
+
key={index}
|
|
71
72
|
hideTags
|
|
72
73
|
movie={movie}
|
|
73
74
|
columnWidth={autoSizedProps.columnWidth}
|
|
@@ -3,8 +3,7 @@ import styled from '@emotion/styled';
|
|
|
3
3
|
import { breakpoints, mq, spacing } from '@ndla/core';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
import LayoutItem, { OneColumn } from '../Layout';
|
|
6
|
-
import ProgrammeSubjects from './ProgrammeSubjects';
|
|
7
|
-
import { GradesProps } from './ProgrammeSubjects';
|
|
6
|
+
import ProgrammeSubjects, { GradesProps } from './ProgrammeSubjects';
|
|
8
7
|
import MessageBox from '../Messages/MessageBox';
|
|
9
8
|
import { NavigationHeading } from '..';
|
|
10
9
|
const StyledWrapper = styled.div`
|
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
import React, { ReactNode } from 'react';
|
|
10
10
|
import { useTranslation } from 'react-i18next';
|
|
11
11
|
import styled from '@emotion/styled';
|
|
12
|
-
import { css } from '@emotion/react';
|
|
13
|
-
import { keyframes } from '@emotion/react';
|
|
12
|
+
import { css, keyframes } from '@emotion/react';
|
|
14
13
|
import SafeLink from '@ndla/safelink';
|
|
15
14
|
import { Additional, Core, HumanMaleBoard } from '@ndla/icons/common';
|
|
16
15
|
import { breakpoints, colors, fonts, mq, spacing } from '@ndla/core';
|
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import React, { ReactNode } from 'react';
|
|
10
10
|
import styled from '@emotion/styled';
|
|
11
|
-
import { css } from '@emotion/react';
|
|
12
|
-
import { keyframes } from '@emotion/react';
|
|
11
|
+
import { css, keyframes } from '@emotion/react';
|
|
13
12
|
import { useTranslation } from 'react-i18next';
|
|
14
13
|
import NoContentBox from '../NoContentBox';
|
|
15
14
|
import ResourceItem from './ResourceItem';
|
|
@@ -91,8 +91,8 @@ const SubjectNewContent = ({ heading, content }: Props) => (
|
|
|
91
91
|
<StyledSubjectSectionTitle>{heading}</StyledSubjectSectionTitle>
|
|
92
92
|
<nav>
|
|
93
93
|
<StyledUl>
|
|
94
|
-
{content.map((item) => (
|
|
95
|
-
<StyledListItem>
|
|
94
|
+
{content.map((item, index) => (
|
|
95
|
+
<StyledListItem key={index}>
|
|
96
96
|
<LeftWrapper>
|
|
97
97
|
<ContentTypeBadge type={item.contentType} size="x-small" background border />
|
|
98
98
|
<ContentLinkWrapper>
|
|
@@ -19,6 +19,7 @@ interface AddFolderButtonProps {
|
|
|
19
19
|
focusedFolder?: FolderType;
|
|
20
20
|
setNewFolderParentId: (id?: string) => void;
|
|
21
21
|
setShowTree: (value: boolean) => void;
|
|
22
|
+
loading?: boolean;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
const StyledAddFolderButton = styled(Button)`
|
|
@@ -33,30 +34,28 @@ const StyledPlus = styled(Plus)`
|
|
|
33
34
|
width: 24px;
|
|
34
35
|
`;
|
|
35
36
|
|
|
36
|
-
const AddFolderButton = ({
|
|
37
|
+
const AddFolderButton = ({
|
|
38
|
+
canAddFolder,
|
|
39
|
+
loading,
|
|
40
|
+
setNewFolderParentId,
|
|
41
|
+
focusedFolder,
|
|
42
|
+
setShowTree,
|
|
43
|
+
}: AddFolderButtonProps) => {
|
|
37
44
|
const { t } = useTranslation();
|
|
38
45
|
const ref = useRef<HTMLButtonElement>(null);
|
|
46
|
+
const tooltip = loading
|
|
47
|
+
? t('loading')
|
|
48
|
+
: canAddFolder
|
|
49
|
+
? t('myNdla.newFolderUnder', { folderName: focusedFolder?.name })
|
|
50
|
+
: t('treeStructure.maxFoldersAlreadyAdded');
|
|
39
51
|
return (
|
|
40
|
-
<Tooltip
|
|
41
|
-
tooltip={
|
|
42
|
-
canAddFolder
|
|
43
|
-
? t('myNdla.newFolderUnder', {
|
|
44
|
-
folderName: focusedFolder?.name,
|
|
45
|
-
})
|
|
46
|
-
: t('treeStructure.maxFoldersAlreadyAdded')
|
|
47
|
-
}>
|
|
52
|
+
<Tooltip tooltip={tooltip}>
|
|
48
53
|
<StyledAddFolderButton
|
|
49
54
|
ref={ref}
|
|
50
55
|
variant="outline"
|
|
51
56
|
shape="pill"
|
|
52
|
-
disabled={!canAddFolder}
|
|
53
|
-
aria-label={
|
|
54
|
-
canAddFolder
|
|
55
|
-
? t('myNdla.newFolderUnder', {
|
|
56
|
-
folderName: focusedFolder?.name,
|
|
57
|
-
})
|
|
58
|
-
: t('treeStructure.maxFoldersAlreadyAdded')
|
|
59
|
-
}
|
|
57
|
+
disabled={loading || !canAddFolder}
|
|
58
|
+
aria-label={tooltip}
|
|
60
59
|
onMouseDown={(e) => {
|
|
61
60
|
e.preventDefault();
|
|
62
61
|
e.stopPropagation();
|
|
@@ -6,16 +6,16 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import React, { KeyboardEvent } from 'react';
|
|
9
|
+
import React, { KeyboardEvent, forwardRef } from 'react';
|
|
10
10
|
import styled from '@emotion/styled';
|
|
11
11
|
import { useForwardedRef } from '@ndla/util';
|
|
12
12
|
import { breakpoints, colors, mq, spacing } from '@ndla/core';
|
|
13
13
|
import { ChevronUp, ChevronDown } from '@ndla/icons/common';
|
|
14
|
-
import { forwardRef } from 'react';
|
|
15
14
|
import { ButtonV2 as Button, IconButtonV2 as IconButton } from '@ndla/button';
|
|
16
15
|
import { treestructureId } from './helperFunctions';
|
|
17
16
|
import { FolderType, TreeStructureType } from './types';
|
|
18
17
|
import { arrowNavigation } from './arrowNavigation';
|
|
18
|
+
import ContentLoader from '../ContentLoader';
|
|
19
19
|
|
|
20
20
|
interface StyledRowProps {
|
|
21
21
|
isOpen: boolean;
|
|
@@ -52,6 +52,7 @@ interface Props {
|
|
|
52
52
|
showTree: boolean;
|
|
53
53
|
type: TreeStructureType;
|
|
54
54
|
label?: string;
|
|
55
|
+
loading?: boolean;
|
|
55
56
|
focusedFolder?: FolderType;
|
|
56
57
|
selectedFolder?: FolderType;
|
|
57
58
|
setSelectedFolder: (folder: FolderType) => void;
|
|
@@ -77,6 +78,7 @@ const ComboboxButton = forwardRef<HTMLButtonElement, Props>(
|
|
|
77
78
|
setFocusedFolder,
|
|
78
79
|
onOpenFolder,
|
|
79
80
|
onCloseFolder,
|
|
81
|
+
loading,
|
|
80
82
|
ariaDescribedby,
|
|
81
83
|
},
|
|
82
84
|
ref,
|
|
@@ -116,25 +118,48 @@ const ComboboxButton = forwardRef<HTMLButtonElement, Props>(
|
|
|
116
118
|
innerRef.current?.focus();
|
|
117
119
|
}
|
|
118
120
|
}}>
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
121
|
+
{loading && (
|
|
122
|
+
<ContentLoader width={1000} height={40}>
|
|
123
|
+
<rect x="15" y="0" width="1000" rx="3" ry="3" r="15" height="40" />
|
|
124
|
+
</ContentLoader>
|
|
125
|
+
)}
|
|
126
|
+
{!loading && (
|
|
127
|
+
<StyledSelectedFolder
|
|
128
|
+
ref={innerRef}
|
|
129
|
+
tabIndex={0}
|
|
130
|
+
id={treestructureId(type, 'combobox')}
|
|
131
|
+
role="combobox"
|
|
132
|
+
aria-controls={treestructureId(type, 'popup')}
|
|
133
|
+
aria-haspopup="tree"
|
|
134
|
+
aria-expanded={showTree}
|
|
135
|
+
aria-labelledby={label ? treestructureId(type, 'label') : undefined}
|
|
136
|
+
aria-activedescendant={focusedFolder ? treestructureId(type, focusedFolder.id) : undefined}
|
|
137
|
+
aria-describedby={ariaDescribedby}
|
|
138
|
+
variant="ghost"
|
|
139
|
+
colorTheme="light"
|
|
140
|
+
fontWeight="normal"
|
|
141
|
+
shape="sharp"
|
|
142
|
+
onKeyDown={onKeyDown}
|
|
143
|
+
onClick={() => {
|
|
144
|
+
innerRef.current?.focus();
|
|
145
|
+
onToggleTree(!showTree);
|
|
146
|
+
}}>
|
|
147
|
+
{selectedFolder?.name}
|
|
148
|
+
</StyledSelectedFolder>
|
|
149
|
+
)}
|
|
150
|
+
<IconButton
|
|
151
|
+
disabled={loading}
|
|
152
|
+
aria-busy={loading}
|
|
153
|
+
aria-hidden
|
|
154
|
+
aria-label=""
|
|
155
|
+
tabIndex={-1}
|
|
130
156
|
variant="ghost"
|
|
131
|
-
colorTheme="
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
<IconButton aria-hidden aria-label="" tabIndex={-1} variant="ghost" colorTheme="greyLighter" size="small">
|
|
157
|
+
colorTheme="greyLighter"
|
|
158
|
+
size="small"
|
|
159
|
+
onClick={() => {
|
|
160
|
+
innerRef.current?.focus();
|
|
161
|
+
onToggleTree(!showTree);
|
|
162
|
+
}}>
|
|
138
163
|
{showTree ? <ChevronUp /> : <ChevronDown />}
|
|
139
164
|
</IconButton>
|
|
140
165
|
</StyledRow>
|
|
@@ -189,6 +189,7 @@ const TreeStructure = ({
|
|
|
189
189
|
{label && <StyledLabel id={treestructureId(type, 'label')}>{label}</StyledLabel>}
|
|
190
190
|
{type === 'picker' && (
|
|
191
191
|
<AddFolderButton
|
|
192
|
+
loading={loading}
|
|
192
193
|
canAddFolder={!!canAddFolder}
|
|
193
194
|
focusedFolder={focusedFolder}
|
|
194
195
|
setNewFolderParentId={setNewFolderParentId}
|
|
@@ -203,6 +204,7 @@ const TreeStructure = ({
|
|
|
203
204
|
showTree={showTree}
|
|
204
205
|
type={type}
|
|
205
206
|
label={label}
|
|
207
|
+
loading={loading}
|
|
206
208
|
focusedFolder={focusedFolder}
|
|
207
209
|
selectedFolder={selectedFolder}
|
|
208
210
|
setSelectedFolder={setSelectedFolder}
|
package/src/i18n/index.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -174,7 +174,7 @@ export { default as Breadcrumb, HeaderBreadcrumb, HomeBreadcrumb, ActionBreadcru
|
|
|
174
174
|
export type { SimpleBreadcrumbItem, IndexedBreadcrumbItem } from './Breadcrumb';
|
|
175
175
|
|
|
176
176
|
export type { BreadcrumbItemProps } from './Breadcrumblist';
|
|
177
|
-
export { i18nInstance, formatNestedMessages
|
|
177
|
+
export { i18nInstance, formatNestedMessages } from './i18n';
|
|
178
178
|
export { default as ResourceGroup } from './ResourceGroup';
|
|
179
179
|
|
|
180
180
|
export { default as LayoutItem, OneColumn, PageContainer, Content } from './Layout';
|
package/es/i18n/formatMessage.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2017-present, NDLA.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the GPLv3 license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import invariant from 'invariant';
|
|
10
|
-
export var formatMessage = function formatMessage(locale, messages, getMessageFormat, id) {
|
|
11
|
-
var values = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
|
|
12
|
-
// `id` is a required parameter.
|
|
13
|
-
invariant(id, 'An `id` must be provided to format a message.');
|
|
14
|
-
var message = messages && messages[id];
|
|
15
|
-
var hasValues = Object.keys(values).length > 0;
|
|
16
|
-
|
|
17
|
-
// Avoid expensive message formatting for simple messages without values. In
|
|
18
|
-
// development messages will always be formatted in case of missing values.
|
|
19
|
-
if (!hasValues && process.env.NODE_ENV === 'production') {
|
|
20
|
-
return message || id;
|
|
21
|
-
}
|
|
22
|
-
var formattedMessage;
|
|
23
|
-
if (message) {
|
|
24
|
-
try {
|
|
25
|
-
var formatter = getMessageFormat(message, locale, {});
|
|
26
|
-
formattedMessage = formatter.format(values);
|
|
27
|
-
} catch (e) {
|
|
28
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
29
|
-
// eslint-disable-next-line no-console
|
|
30
|
-
console.error("Error formatting message: \"".concat(id, "\" for locale: \"").concat(locale, "\"\n").concat(e));
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
} else if (process.env.NODE_ENV !== 'production') {
|
|
34
|
-
// eslint-disable-next-line no-console
|
|
35
|
-
console.error("Missing message: \"".concat(id, "\" for locale: \"").concat(locale, "\", using id as fallback"));
|
|
36
|
-
return id;
|
|
37
|
-
}
|
|
38
|
-
if (!formattedMessage) {
|
|
39
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
40
|
-
// eslint-disable-next-line no-console
|
|
41
|
-
console.error("Cannot format message: \"".concat(id, "\", using message source as fallback."));
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return formattedMessage || message || id;
|
|
45
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2017-present, NDLA.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the GPLv3 license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
interface Messages {
|
|
9
|
-
[key: string]: string;
|
|
10
|
-
}
|
|
11
|
-
export declare const formatMessage: (locale: string, messages: Messages, getMessageFormat: any, id: string, values?: {
|
|
12
|
-
[key: string]: any;
|
|
13
|
-
}) => string;
|
|
14
|
-
export {};
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.formatMessage = void 0;
|
|
7
|
-
var _invariant = _interopRequireDefault(require("invariant"));
|
|
8
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
|
|
9
|
-
/**
|
|
10
|
-
* Copyright (c) 2017-present, NDLA.
|
|
11
|
-
*
|
|
12
|
-
* This source code is licensed under the GPLv3 license found in the
|
|
13
|
-
* LICENSE file in the root directory of this source tree.
|
|
14
|
-
*
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
var formatMessage = function formatMessage(locale, messages, getMessageFormat, id) {
|
|
18
|
-
var values = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
|
|
19
|
-
// `id` is a required parameter.
|
|
20
|
-
(0, _invariant["default"])(id, 'An `id` must be provided to format a message.');
|
|
21
|
-
var message = messages && messages[id];
|
|
22
|
-
var hasValues = Object.keys(values).length > 0;
|
|
23
|
-
|
|
24
|
-
// Avoid expensive message formatting for simple messages without values. In
|
|
25
|
-
// development messages will always be formatted in case of missing values.
|
|
26
|
-
if (!hasValues && process.env.NODE_ENV === 'production') {
|
|
27
|
-
return message || id;
|
|
28
|
-
}
|
|
29
|
-
var formattedMessage;
|
|
30
|
-
if (message) {
|
|
31
|
-
try {
|
|
32
|
-
var formatter = getMessageFormat(message, locale, {});
|
|
33
|
-
formattedMessage = formatter.format(values);
|
|
34
|
-
} catch (e) {
|
|
35
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
36
|
-
// eslint-disable-next-line no-console
|
|
37
|
-
console.error("Error formatting message: \"".concat(id, "\" for locale: \"").concat(locale, "\"\n").concat(e));
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
} else if (process.env.NODE_ENV !== 'production') {
|
|
41
|
-
// eslint-disable-next-line no-console
|
|
42
|
-
console.error("Missing message: \"".concat(id, "\" for locale: \"").concat(locale, "\", using id as fallback"));
|
|
43
|
-
return id;
|
|
44
|
-
}
|
|
45
|
-
if (!formattedMessage) {
|
|
46
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
47
|
-
// eslint-disable-next-line no-console
|
|
48
|
-
console.error("Cannot format message: \"".concat(id, "\", using message source as fallback."));
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return formattedMessage || message || id;
|
|
52
|
-
};
|
|
53
|
-
exports.formatMessage = formatMessage;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2016-present, NDLA.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the GPLv3 license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/* eslint-env jest */
|
|
10
|
-
import IntlMessageFormat from 'intl-messageformat';
|
|
11
|
-
import memoizeIntlConstructor from 'intl-format-cache';
|
|
12
|
-
import { formatMessage } from '../formatMessage';
|
|
13
|
-
|
|
14
|
-
const getMessageFormat = memoizeIntlConstructor(IntlMessageFormat);
|
|
15
|
-
const locale = 'nb';
|
|
16
|
-
const messages = {
|
|
17
|
-
helloworld: 'Hello world',
|
|
18
|
-
'test.me': 'Test me {test}',
|
|
19
|
-
'welcome.to.my.unittest': 'Welcome to my unittest',
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
test('@ndla/i18n/formatMessage message with matching ID', () => {
|
|
23
|
-
expect(formatMessage(locale, messages, getMessageFormat, 'helloworld')).toBe('Hello world');
|
|
24
|
-
});
|
|
25
|
-
test('@ndla/i18n/formatMessage message without matching ID', () => {
|
|
26
|
-
expect(formatMessage(locale, messages, getMessageFormat, 'does.not.exists')).toBe('does.not.exists');
|
|
27
|
-
});
|
|
28
|
-
test('@ndla/i18n/formatMessage matching message with value', () => {
|
|
29
|
-
expect(
|
|
30
|
-
formatMessage(locale, messages, getMessageFormat, 'test.me', {
|
|
31
|
-
test: '1337',
|
|
32
|
-
}),
|
|
33
|
-
).toBe('Test me 1337');
|
|
34
|
-
});
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2017-present, NDLA.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the GPLv3 license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import invariant from 'invariant';
|
|
10
|
-
|
|
11
|
-
interface Messages {
|
|
12
|
-
[key: string]: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export const formatMessage = (
|
|
16
|
-
locale: string,
|
|
17
|
-
messages: Messages,
|
|
18
|
-
getMessageFormat: any,
|
|
19
|
-
id: string,
|
|
20
|
-
values: { [key: string]: any } = {},
|
|
21
|
-
): string => {
|
|
22
|
-
// `id` is a required parameter.
|
|
23
|
-
invariant(id, 'An `id` must be provided to format a message.');
|
|
24
|
-
|
|
25
|
-
const message = messages && messages[id];
|
|
26
|
-
const hasValues = Object.keys(values).length > 0;
|
|
27
|
-
|
|
28
|
-
// Avoid expensive message formatting for simple messages without values. In
|
|
29
|
-
// development messages will always be formatted in case of missing values.
|
|
30
|
-
if (!hasValues && process.env.NODE_ENV === 'production') {
|
|
31
|
-
return message || id;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
let formattedMessage;
|
|
35
|
-
|
|
36
|
-
if (message) {
|
|
37
|
-
try {
|
|
38
|
-
const formatter = getMessageFormat(message, locale, {});
|
|
39
|
-
|
|
40
|
-
formattedMessage = formatter.format(values);
|
|
41
|
-
} catch (e) {
|
|
42
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
43
|
-
// eslint-disable-next-line no-console
|
|
44
|
-
console.error(`Error formatting message: "${id}" for locale: "${locale}"\n${e}`);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
} else if (process.env.NODE_ENV !== 'production') {
|
|
48
|
-
// eslint-disable-next-line no-console
|
|
49
|
-
console.error(`Missing message: "${id}" for locale: "${locale}", using id as fallback`);
|
|
50
|
-
return id;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (!formattedMessage) {
|
|
54
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
55
|
-
// eslint-disable-next-line no-console
|
|
56
|
-
console.error(`Cannot format message: "${id}", using message source as fallback.`);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return formattedMessage || message || id;
|
|
61
|
-
};
|