diff --git a/package.json b/package.json
index 7267e04bf..28130d88c 100644
--- a/package.json
+++ b/package.json
@@ -128,7 +128,7 @@
"eslint-plugin-react": "^7.20.0",
"eslint-plugin-react-hooks": "^4.0.4",
"express": "^4.17.1",
- "gettext-extractor": "^3.5.2",
+ "glob": "^7.1.6",
"moxios": "^0.4.0",
"npm-run-all": "^4.1.5",
"prettier": "^2.0.5",
diff --git a/public/locales/en-US.json b/public/locales/en-US.json
index 492f927b6..21959bf06 100644
--- a/public/locales/en-US.json
+++ b/public/locales/en-US.json
@@ -19,21 +19,26 @@
"noDataErrorLabel": "No data",
"dateLabel": "Date",
"coresLabel": "Cores",
- "coresLegendTooltip": "Lorem ipsum dolor sit, cores.",
+ "coresLegendTooltip": "{{product}} CPU usage, per CPU core.",
"socketsLabel": "Sockets",
- "socketsLegendTooltip": "Lorem ipsum dolor sit, sockets.",
+ "socketsLegendTooltip": "{{product}} CPU usage, per CPU socket pair.",
"cloudSocketsLabel": "Public cloud",
- "cloudSocketsLegendTooltip": "Lorem ipsum dolor sit, cloudSockets.",
+ "cloudSocketsLegendTooltip": "Public cloud {{product}} CPU usage, 1 CPU socket per instance.",
"hypervisorCoresLabel": "Virtualized cores",
- "hypervisorCoresLegendTooltip": "Lorem ipsum dolor sit, hypervisorCores.",
+ "hypervisorCoresLegendTooltip": "{{product}} CPU usage, per CPU core.",
"hypervisorSocketsLabel": "Virtualized {{product}}",
- "hypervisorSocketsLegendTooltip": "Lorem ipsum dolor sit, hypervisorSockets.",
+ "hypervisorSocketsLegendTooltip": "{{product}} CPU socket usage, per socket pair.",
+ "hypervisorSocketsLegendTooltip_RHEL": "Virtualized {{product}} CPU usage, per socket. Hypervisor guest usage with known host-guest mappings (such as multi-guest VDC subscriptions), per socket pair of the hypervisor host, using the same method as physical {{product}}.",
"physicalCoresLabel": "Physical cores",
- "physicalCoresLegendTooltip": "Lorem ipsum dolor sit, physicalCores.",
+ "physicalCoresLegendTooltip": "{{product}} CPU usage, per CPU core.",
"physicalSocketsLabel": "Physical {{product}}",
- "physicalSocketsLegendTooltip": "Lorem ipsum dolor sit, physicalSockets.",
+ "physicalSocketsLegendTooltip": "{{product}} CPU socket usage, per socket pair.",
+ "physicalSocketsLegendTooltip_RHEL": "Physical {{product}} CPU usage, per socket pair. Each system's socket count is rounded upwards to the next even number.",
"thresholdLabel": "Subscription threshold",
- "thresholdLegendTooltip": "Lorem ipsum dolor sit, threshold.",
+ "thresholdLegendTooltip": "Maximum capacity, based on total {{product}} subscriptions in this account.",
+ "thresholdLegendTooltip_RHEL": "Maximum capacity, as CPU sockets, based on total {{product}} subscriptions in this account.",
+ "thresholdCoresLegendTooltip_OpenShift": "Maximum capacity, as CPU cores, based on total {{product}} subscriptions in this account.",
+ "thresholdSocketsLegendTooltip_OpenShift": "Maximum capacity, as CPU sockets, based on total {{product}} subscriptions in this account.",
"tooltipSummary": "Your subscription data facets. With one level of column and row headers."
},
"curiosity-toolbar": {
diff --git a/src/components/graphCard/__tests__/__snapshots__/graphCardChartLegend.test.js.snap b/src/components/graphCard/__tests__/__snapshots__/graphCardChartLegend.test.js.snap
index c0dda8b5c..19a2c3673 100644
--- a/src/components/graphCard/__tests__/__snapshots__/graphCardChartLegend.test.js.snap
+++ b/src/components/graphCard/__tests__/__snapshots__/graphCardChartLegend.test.js.snap
@@ -23,7 +23,7 @@ exports[`GraphCardChartLegend Component should handle a click event: click event
tabIndex={0}
variant="link"
>
- t(curiosity-graph.loremIpsumLabel, [object Object])
+ t(curiosity-graph.loremIpsumLabel,curiosity-graph.noLabel, [object Object])
`;
@@ -50,7 +50,7 @@ exports[`GraphCardChartLegend Component should handle a click event: click event
tabIndex={0}
variant="link"
>
- t(curiosity-graph.loremIpsumLabel, [object Object])
+ t(curiosity-graph.loremIpsumLabel,curiosity-graph.noLabel, [object Object])
`;
@@ -73,7 +73,7 @@ exports[`GraphCardChartLegend Component should handle a click event: click event
tabIndex={0}
variant="link"
>
- t(curiosity-graph.loremIpsumLabel, [object Object])
+ t(curiosity-graph.loremIpsumLabel,curiosity-graph.noLabel, [object Object])
`;
@@ -189,126 +189,311 @@ exports[`GraphCardChartLegend Component should handle variations in data when re
exports[`GraphCardChartLegend Component should render a basic component: basic 1`] = `
-
+
+ t(curiosity-graph.loremIpsumLegendTooltip, [object Object])
+
}
- isDisabled={false}
- key="curiosity-button-loremIpsum"
- onClick={[Function]}
- onKeyPress={[Function]}
- tabIndex={0}
- variant="link"
+ distance={-10}
+ enableFlip={true}
+ entryDelay={100}
+ exitDelay={0}
+ flipBehavior={
+ Array [
+ "top",
+ "right",
+ "bottom",
+ "left",
+ "top",
+ "right",
+ "bottom",
+ ]
+ }
+ id=""
+ isAppLauncher={false}
+ isContentLeftAligned={false}
+ isVisible={false}
+ key="curiosity-tooltip-loremIpsum"
+ maxWidth="18.75rem"
+ position="top"
+ tippyProps={Object {}}
+ trigger="mouseenter focus"
+ zIndex={9999}
>
- t(curiosity-graph.loremIpsumLabel, [object Object])
-
+
+ }
+ isDisabled={false}
+ key="curiosity-button-loremIpsum"
+ onClick={[Function]}
+ onKeyPress={[Function]}
+ tabIndex={0}
+ variant="link"
+ >
+ t(curiosity-graph.loremIpsumLabel,curiosity-graph.noLabel, [object Object])
+
+
`;
exports[`GraphCardChartLegend Component should render basic data: data 1`] = `
-
+
+ t(curiosity-graph.loremIpsumLegendTooltip, [object Object])
+
}
- isDisabled={false}
- key="curiosity-button-loremIpsum"
- onClick={[Function]}
- onKeyPress={[Function]}
- tabIndex={0}
- variant="link"
- >
- t(curiosity-graph.loremIpsumLabel, [object Object])
-
-
+ distance={-10}
+ enableFlip={true}
+ entryDelay={100}
+ exitDelay={0}
+ flipBehavior={
+ Array [
+ "top",
+ "right",
+ "bottom",
+ "left",
+ "top",
+ "right",
+ "bottom",
+ ]
}
- isDisabled={true}
- key="curiosity-button-ametConsectetur"
- onClick={[Function]}
- onKeyPress={[Function]}
- tabIndex={0}
- variant="link"
+ id=""
+ isAppLauncher={false}
+ isContentLeftAligned={false}
+ isVisible={false}
+ key="curiosity-tooltip-loremIpsum"
+ maxWidth="18.75rem"
+ position="top"
+ tippyProps={Object {}}
+ trigger="mouseenter focus"
+ zIndex={9999}
>
- t(curiosity-graph.ametConsecteturLabel, [object Object])
-
-
+ />
+ }
+ isDisabled={false}
+ key="curiosity-button-loremIpsum"
+ onClick={[Function]}
+ onKeyPress={[Function]}
+ tabIndex={0}
+ variant="link"
+ >
+ t(curiosity-graph.loremIpsumLabel,curiosity-graph.noLabel, [object Object])
+
+
+
+ t(curiosity-graph.ametConsecteturLegendTooltip, [object Object])
+
}
- isDisabled={false}
- key="curiosity-button-dolorSit"
- onClick={[Function]}
- onKeyPress={[Function]}
- tabIndex={0}
- variant="link"
+ distance={-10}
+ enableFlip={true}
+ entryDelay={100}
+ exitDelay={0}
+ flipBehavior={
+ Array [
+ "top",
+ "right",
+ "bottom",
+ "left",
+ "top",
+ "right",
+ "bottom",
+ ]
+ }
+ id=""
+ isAppLauncher={false}
+ isContentLeftAligned={false}
+ isVisible={false}
+ key="curiosity-tooltip-ametConsectetur"
+ maxWidth="18.75rem"
+ position="top"
+ tippyProps={Object {}}
+ trigger="mouseenter focus"
+ zIndex={9999}
>
- t(curiosity-graph.thresholdLabel)
-
-
+ }
+ isDisabled={true}
+ key="curiosity-button-ametConsectetur"
+ onClick={[Function]}
+ onKeyPress={[Function]}
+ tabIndex={0}
+ variant="link"
+ >
+ t(curiosity-graph.ametConsecteturLabel,curiosity-graph.noLabel, [object Object])
+
+
+
+ t(curiosity-graph.dolorSitLegendTooltip,curiosity-graph.thresholdLegendTooltip, [object Object])
+
+ }
+ distance={-10}
+ enableFlip={true}
+ entryDelay={100}
+ exitDelay={0}
+ flipBehavior={
+ Array [
+ "top",
+ "right",
+ "bottom",
+ "left",
+ "top",
+ "right",
+ "bottom",
+ ]
+ }
+ id=""
+ isAppLauncher={false}
+ isContentLeftAligned={false}
+ isVisible={false}
+ key="curiosity-tooltip-dolorSit"
+ maxWidth="18.75rem"
+ position="top"
+ tippyProps={Object {}}
+ trigger="mouseenter focus"
+ zIndex={9999}
+ >
+
+ />
+ }
+ isDisabled={false}
+ key="curiosity-button-dolorSit"
+ onClick={[Function]}
+ onKeyPress={[Function]}
+ tabIndex={0}
+ variant="link"
+ >
+ t(curiosity-graph.dolorSitLabel,curiosity-graph.thresholdLabel, [object Object])
+
+
+
+ t(curiosity-graph.nonCursusLegendTooltip,curiosity-graph.thresholdLegendTooltip, [object Object])
+
}
- isDisabled={false}
- key="curiosity-button-nonCursus"
- onClick={[Function]}
- onKeyPress={[Function]}
- tabIndex={0}
- variant="link"
+ distance={-10}
+ enableFlip={true}
+ entryDelay={100}
+ exitDelay={0}
+ flipBehavior={
+ Array [
+ "top",
+ "right",
+ "bottom",
+ "left",
+ "top",
+ "right",
+ "bottom",
+ ]
+ }
+ id=""
+ isAppLauncher={false}
+ isContentLeftAligned={false}
+ isVisible={false}
+ key="curiosity-tooltip-nonCursus"
+ maxWidth="18.75rem"
+ position="top"
+ tippyProps={Object {}}
+ trigger="mouseenter focus"
+ zIndex={9999}
>
- t(curiosity-graph.thresholdLabel)
-
+
+ }
+ isDisabled={false}
+ key="curiosity-button-nonCursus"
+ onClick={[Function]}
+ onKeyPress={[Function]}
+ tabIndex={0}
+ variant="link"
+ >
+ t(curiosity-graph.nonCursusLabel,curiosity-graph.thresholdLabel, [object Object])
+
+
`;
diff --git a/src/components/graphCard/graphCardChartLegend.js b/src/components/graphCard/graphCardChartLegend.js
index ce47d1a62..80ab796d6 100644
--- a/src/components/graphCard/graphCardChartLegend.js
+++ b/src/components/graphCard/graphCardChartLegend.js
@@ -127,21 +127,25 @@ class GraphCardChartLegend extends React.Component {
!data.find(({ y, hasData }) => (y >= 0 && hasData === true) || (y >= 0 && isThreshold === true)) || false;
const labelContent =
- (isThreshold && t(`curiosity-graph.thresholdLabel`)) ||
- t(`curiosity-graph.${id}Label`, { product }) ||
- t(`curiosity-graph.noLabel`, { product });
-
- // ToDo: Disabled tooltip content, reactivate accordingly, issues/158
- // const tooltipContent =
- // (isThreshold && t(`curiosity-graph.thresholdLegendTooltip`)) || t(`curiosity-graph.${id}LegendTooltip`);
+ (isThreshold &&
+ t([`curiosity-graph.${id}Label`, `curiosity-graph.thresholdLabel`], { product, context: product })) ||
+ t([`curiosity-graph.${id}Label`, `curiosity-graph.noLabel`], { product, context: product });
+
+ const tooltipContent =
+ (isThreshold &&
+ t([`curiosity-graph.${id}LegendTooltip`, `curiosity-graph.thresholdLegendTooltip`], {
+ product,
+ context: product
+ })) ||
+ t(`curiosity-graph.${id}LegendTooltip`, { product, context: product });
return this.renderLegendItem({
chartId: id,
color: stroke,
labelContent,
isDisabled,
- isThreshold
- // tooltipContent
+ isThreshold,
+ tooltipContent
});
})}
diff --git a/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap b/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap
index caf72dba4..acc9cb285 100644
--- a/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap
+++ b/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap
@@ -11,240 +11,384 @@ Object {
exports[`I18n Component should attempt to perform translate with a node: translated node 1`] = `"t(lorem.ipsum, [object Object], [object Object])
"`;
-exports[`I18n Component should generate a predictable pot output snapshot: pot output 1`] = `
-"msgid \\"\\"
-msgstr \\"\\"
-\\"Content-Type: text/plain; charset=UTF-8\\\\n\\"
-
-#: src/components/authentication/authentication.js:74
-msgid \\"curiosity-auth.authorizedTitle\\"
-msgstr \\"\\"
-
-#: src/components/openshiftView/openshiftView.js:105
-#: src/components/openshiftView/openshiftView.js:93
-msgid \\"curiosity-graph.cardHeading\\"
-msgstr \\"\\"
-
-#: src/components/graphCard/graphCardTypes.js:15
-msgid \\"curiosity-graph.dropdownDaily\\"
-msgstr \\"\\"
-
-#: src/components/graphCard/graphCardTypes.js:17
-msgid \\"curiosity-graph.dropdownMonthly\\"
-msgstr \\"\\"
-
-#: src/components/c3GraphCard/c3GraphCard.js:189
-#: src/components/c3GraphCard/c3GraphCard.js:193
-#: src/components/graphCard/graphCard.js:176
-#: src/components/graphCard/graphCard.js:180
-msgid \\"curiosity-graph.dropdownPlaceholder\\"
-msgstr \\"\\"
-
-#: src/components/graphCard/graphCardTypes.js:18
-msgid \\"curiosity-graph.dropdownQuarterly\\"
-msgstr \\"\\"
-
-#: src/components/graphCard/graphCardTypes.js:16
-msgid \\"curiosity-graph.dropdownWeekly\\"
-msgstr \\"\\"
-
-#: src/components/c3GraphCard/c3GraphCardHelpers.js:179
-#: src/components/graphCard/graphCardChartTooltip.js:36
-msgid \\"curiosity-graph.infiniteThresholdLabel\\"
-msgstr \\"\\"
-
-#: src/components/graphCard/graphCardChartTooltip.js:84
-msgid \\"curiosity-graph.noDataErrorLabel\\"
-msgstr \\"\\"
-
-#: src/components/c3GraphCard/c3GraphCardHelpers.js:180
-#: src/components/c3GraphCard/c3GraphCardHelpers.js:183
-#: src/components/graphCard/graphCardChartTooltip.js:37
-#: src/components/graphCard/graphCardChartTooltip.js:43
-msgid \\"curiosity-graph.noDataLabel\\"
-msgstr \\"\\"
-
-#: src/components/graphCard/graphCardChartLegend.js:132
-msgid \\"curiosity-graph.noLabel\\"
-msgstr \\"\\"
-
-#: src/components/rhelView/rhelView.js:50
-#: src/components/rhelView/rhelView.js:60
-msgid \\"curiosity-graph.socketsHeading\\"
-msgstr \\"\\"
-
-#: src/components/c3GraphCard/c3GraphCard.js:110
-#: src/components/c3GraphCard/c3GraphCardHelpers.js:136
-#: src/components/graphCard/graphCardChartLegend.js:130
-#: src/components/graphCard/graphCardChartTooltip.js:39
-msgid \\"curiosity-graph.thresholdLabel\\"
-msgstr \\"\\"
-
-#: src/components/c3GraphCard/c3GraphCard.js:93
-msgid \\"curiosity-graph.thresholdLegendTooltip\\"
-msgstr \\"\\"
-
-#: src/components/graphCard/graphCardChartTooltip.js:54
-msgid \\"curiosity-graph.tooltipSummary\\"
-msgstr \\"\\"
-
-#: src/components/optinView/optinView.js:59
-#: src/components/optinView/optinView.js:99
-msgid \\"curiosity-optin.buttonActivate\\"
-msgstr \\"\\"
-
-#: src/components/optinView/optinView.js:87
-msgid \\"curiosity-optin.buttonIsActive\\"
-msgstr \\"\\"
-
-#: src/components/optinView/optinView.js:135
-msgid \\"curiosity-optin.buttonTour\\"
-msgstr \\"\\"
-
-#: src/components/optinView/optinView.js:165
-msgid \\"curiosity-optin.cardDescription\\"
-msgstr \\"\\"
-
-#: src/components/optinView/optinView.js:187
-msgid \\"curiosity-optin.cardFilterDescription\\"
-msgstr \\"\\"
-
-#: src/components/optinView/optinView.js:184
-msgid \\"curiosity-optin.cardFilterTitle\\"
-msgstr \\"\\"
-
-#: src/components/optinView/optinView.js:90
-msgid \\"curiosity-optin.cardIsActiveDescription\\"
-msgstr \\"\\"
-
-#: src/components/optinView/optinView.js:69
-msgid \\"curiosity-optin.cardIsErrorDescription\\"
-msgstr \\"\\"
-
-#: src/components/optinView/optinView.js:180
-msgid \\"curiosity-optin.cardReportDescription\\"
-msgstr \\"\\"
-
-#: src/components/optinView/optinView.js:177
-msgid \\"curiosity-optin.cardReportTitle\\"
-msgstr \\"\\"
-
-#: src/components/optinView/optinView.js:173
-msgid \\"curiosity-optin.cardSeeDescription\\"
-msgstr \\"\\"
-
-#: src/components/optinView/optinView.js:170
-msgid \\"curiosity-optin.cardSeeTitle\\"
-msgstr \\"\\"
-
-#: src/components/optinView/optinView.js:162
-msgid \\"curiosity-optin.cardTitle\\"
-msgstr \\"\\"
-
-#: src/redux/actions/userActions.js:71
-msgid \\"curiosity-optin.notificationsErrorDescription\\"
-msgstr \\"\\"
-
-#: src/redux/actions/userActions.js:70
-msgid \\"curiosity-optin.notificationsErrorTitle\\"
-msgstr \\"\\"
-
-#: src/redux/actions/userActions.js:77
-msgid \\"curiosity-optin.notificationsSuccessDescription\\"
-msgstr \\"\\"
-
-#: src/redux/actions/userActions.js:76
-msgid \\"curiosity-optin.notificationsSuccessTitle\\"
-msgstr \\"\\"
-
-#: src/components/optinView/optinView.js:132
-msgid \\"curiosity-optin.tourDescription\\"
-msgstr \\"\\"
-
-#: src/components/optinView/optinView.js:129
-msgid \\"curiosity-optin.tourTitle\\"
-msgstr \\"\\"
-
-#: src/components/optinView/optinView.js:121
-msgid \\"curiosity-optin.tourTitleImageAlt\\"
-msgstr \\"\\"
-
-#: src/components/toolbar/toolbar.js:104
-#: src/components/toolbar/toolbar.js:107
-msgid \\"curiosity-toolbar.slaCategory\\"
-msgstr \\"\\"
-
-#: src/components/toolbar/toolbarTypes.js:28
-msgid \\"curiosity-toolbar.slaNone\\"
-msgstr \\"\\"
-
-#: src/components/toolbar/toolbar.js:110
-msgid \\"curiosity-toolbar.slaPlaceholder\\"
-msgstr \\"\\"
-
-#: src/components/toolbar/toolbarTypes.js:16
-msgid \\"curiosity-toolbar.slaPremium\\"
-msgstr \\"\\"
-
-#: src/components/toolbar/toolbarTypes.js:24
-msgid \\"curiosity-toolbar.slaSelfSupport\\"
-msgstr \\"\\"
-
-#: src/components/toolbar/toolbarTypes.js:20
-msgid \\"curiosity-toolbar.slaStandard\\"
-msgstr \\"\\"
-
-#: src/components/tourView/tourView.js:72
-msgid \\"curiosity-tour.emptyStateButton\\"
-msgstr \\"\\"
-
-#: src/components/tourView/tourView.js:50
-msgid \\"curiosity-tour.emptyStateDescription\\"
-msgstr \\"\\"
-
-#: src/components/tourView/tourView.js:57
-msgid \\"curiosity-tour.emptyStateDescriptionExtended\\"
-msgstr \\"\\"
-
-#: src/components/tourView/tourView.js:52
-msgid \\"curiosity-tour.emptyStateDescriptionTour\\"
-msgstr \\"\\"
-
-#: src/components/tourView/tourView.js:40
-msgid \\"curiosity-tour.emptyStateIconAlt\\"
-msgstr \\"\\"
-
-#: src/components/tourView/tourView.js:87
-msgid \\"curiosity-tour.emptyStateLinkContactUs\\"
-msgstr \\"\\"
-
-#: src/components/tourView/tourView.js:68
-#: src/components/tourView/tourView.js:83
-msgid \\"curiosity-tour.emptyStateLinkLearnMore\\"
-msgstr \\"\\"
-
-#: src/components/tourView/tourView.js:45
-msgid \\"curiosity-tour.emptyStateTitle\\"
-msgstr \\"\\"
-
-#: src/components/openshiftView/openshiftView.js:81
-msgid \\"curiosity-view.openshift\\"
-msgstr \\"\\"
-
-#: src/components/rhelView/rhelView.js:38
-msgid \\"curiosity-view.rhel\\"
-msgstr \\"\\"
-
-#: src/components/authentication/authentication.js:75
-msgctxt \\"...\\"
-msgid \\"curiosity-auth.authorizedCopy\\"
-msgstr \\"\\"
-
-#: src/components/authentication/authentication.js:59
-msgctxt \\"...\\"
-msgid \\"curiosity-auth.pending\\"
-msgstr \\"\\"
-"
+exports[`I18n Component should generate a predictable locale key output snapshot: key output 1`] = `
+Array [
+ Object {
+ "file": "./src/common/helpers.js",
+ "keys": Array [
+ Object {
+ "key": "",
+ "match": "t(\${key}\${(value && \`, \${value}\`)",
+ },
+ ],
+ },
+ Object {
+ "file": "./src/components/authentication/authentication.js",
+ "keys": Array [
+ Object {
+ "key": "curiosity-auth.pending",
+ "match": "t('curiosity-auth.pending', '...')",
+ },
+ Object {
+ "key": "curiosity-auth.authorizedTitle",
+ "match": "t('curiosity-auth.authorizedTitle', { appName: helpers.UI_DISPLAY_NAME })",
+ },
+ Object {
+ "key": "curiosity-auth.authorizedCopy",
+ "match": "t('curiosity-auth.authorizedCopy', '...')",
+ },
+ ],
+ },
+ Object {
+ "file": "./src/components/c3GraphCard/c3GraphCard.js",
+ "keys": Array [
+ Object {
+ "key": "curiosity-graph.thresholdLegendTooltip",
+ "match": "t(\`curiosity-graph.thresholdLegendTooltip\`)",
+ },
+ Object {
+ "key": "",
+ "match": "t(\`curiosity-graph.\${id}LegendTooltip\`)",
+ },
+ Object {
+ "key": "curiosity-graph.thresholdLabel",
+ "match": "t(\`curiosity-graph.thresholdLabel\`)",
+ },
+ Object {
+ "key": "",
+ "match": "t(\`curiosity-graph.\${id}Label\`, { product: productShortLabel })",
+ },
+ Object {
+ "key": "curiosity-graph.dropdownPlaceholder",
+ "match": "t('curiosity-graph.dropdownPlaceholder')",
+ },
+ Object {
+ "key": "curiosity-graph.dropdownPlaceholder",
+ "match": "t('curiosity-graph.dropdownPlaceholder')",
+ },
+ ],
+ },
+ Object {
+ "file": "./src/components/c3GraphCard/c3GraphCardHelpers.js",
+ "keys": Array [
+ Object {
+ "key": "curiosity-graph.thresholdLabel",
+ "match": "translate(\`curiosity-graph.thresholdLabel\`)",
+ },
+ Object {
+ "key": "",
+ "match": "translate(\`curiosity-graph.\${value.id}Label\`, { product: productShortLabel })",
+ },
+ Object {
+ "key": "curiosity-graph.infiniteThresholdLabel",
+ "match": "translate('curiosity-graph.infiniteThresholdLabel')",
+ },
+ Object {
+ "key": "curiosity-graph.noDataLabel",
+ "match": "translate('curiosity-graph.noDataLabel')",
+ },
+ Object {
+ "key": "curiosity-graph.noDataLabel",
+ "match": "translate('curiosity-graph.noDataLabel')",
+ },
+ ],
+ },
+ Object {
+ "file": "./src/components/graphCard/graphCard.js",
+ "keys": Array [
+ Object {
+ "key": "curiosity-graph.dropdownPlaceholder",
+ "match": "t('curiosity-graph.dropdownPlaceholder')",
+ },
+ Object {
+ "key": "curiosity-graph.dropdownPlaceholder",
+ "match": "t('curiosity-graph.dropdownPlaceholder')",
+ },
+ ],
+ },
+ Object {
+ "file": "./src/components/graphCard/graphCardChartLegend.js",
+ "keys": Array [
+ Object {
+ "key": "",
+ "match": "t([\`curiosity-graph.\${id}Label\`, \`curiosity-graph.thresholdLabel\`], { product, context: product })",
+ },
+ Object {
+ "key": "",
+ "match": "t([\`curiosity-graph.\${id}Label\`, \`curiosity-graph.noLabel\`], { product, context: product })",
+ },
+ Object {
+ "key": "",
+ "match": "t([\`curiosity-graph.\${id}LegendTooltip\`, \`curiosity-graph.thresholdLegendTooltip\`], { product, context: product })",
+ },
+ Object {
+ "key": "",
+ "match": "t(\`curiosity-graph.\${id}LegendTooltip\`, { product, context: product })",
+ },
+ ],
+ },
+ Object {
+ "file": "./src/components/graphCard/graphCardChartTooltip.js",
+ "keys": Array [
+ Object {
+ "key": "curiosity-graph.infiniteThresholdLabel",
+ "match": "t('curiosity-graph.infiniteThresholdLabel')",
+ },
+ Object {
+ "key": "curiosity-graph.noDataLabel",
+ "match": "t('curiosity-graph.noDataLabel')",
+ },
+ Object {
+ "key": "curiosity-graph.thresholdLabel",
+ "match": "t(\`curiosity-graph.thresholdLabel\`)",
+ },
+ Object {
+ "key": "curiosity-graph.noDataLabel",
+ "match": "t('curiosity-graph.noDataLabel')",
+ },
+ Object {
+ "key": "",
+ "match": "t(\`curiosity-graph.\${key}Label\`, { product })",
+ },
+ Object {
+ "key": "curiosity-graph.tooltipSummary",
+ "match": "t('curiosity-graph.tooltipSummary')",
+ },
+ Object {
+ "key": "curiosity-graph.noDataErrorLabel",
+ "match": "t('curiosity-graph.noDataErrorLabel')",
+ },
+ ],
+ },
+ Object {
+ "file": "./src/components/graphCard/graphCardTypes.js",
+ "keys": Array [
+ Object {
+ "key": "curiosity-graph.dropdownDaily",
+ "match": "translate('curiosity-graph.dropdownDaily')",
+ },
+ Object {
+ "key": "curiosity-graph.dropdownWeekly",
+ "match": "translate('curiosity-graph.dropdownWeekly')",
+ },
+ Object {
+ "key": "curiosity-graph.dropdownMonthly",
+ "match": "translate('curiosity-graph.dropdownMonthly')",
+ },
+ Object {
+ "key": "curiosity-graph.dropdownQuarterly",
+ "match": "translate('curiosity-graph.dropdownQuarterly')",
+ },
+ ],
+ },
+ Object {
+ "file": "./src/components/openshiftView/openshiftView.js",
+ "keys": Array [
+ Object {
+ "key": "curiosity-view.openshift",
+ "match": "t('curiosity-view.openshift', helpers.UI_DISPLAY_CONFIG_NAME)",
+ },
+ Object {
+ "key": "curiosity-graph.cardHeading",
+ "match": "t('curiosity-graph.cardHeading')",
+ },
+ Object {
+ "key": "curiosity-graph.cardHeading",
+ "match": "t('curiosity-graph.cardHeading')",
+ },
+ ],
+ },
+ Object {
+ "file": "./src/components/optinView/optinView.js",
+ "keys": Array [
+ Object {
+ "key": "curiosity-optin.buttonActivate",
+ "match": "t('curiosity-optin.buttonActivate', { appName: helpers.UI_DISPLAY_NAME })",
+ },
+ Object {
+ "key": "curiosity-optin.cardIsErrorDescription",
+ "match": "translate('curiosity-optin.cardIsErrorDescription', { appName: helpers.UI_DISPLAY_NAME }, [ ])",
+ },
+ Object {
+ "key": "curiosity-optin.buttonIsActive",
+ "match": "t('curiosity-optin.buttonIsActive', { appName: helpers.UI_DISPLAY_NAME })",
+ },
+ Object {
+ "key": "curiosity-optin.cardIsActiveDescription",
+ "match": "t('curiosity-optin.cardIsActiveDescription')",
+ },
+ Object {
+ "key": "curiosity-optin.buttonActivate",
+ "match": "t('curiosity-optin.buttonActivate', { appName: helpers.UI_DISPLAY_NAME })",
+ },
+ Object {
+ "key": "curiosity-optin.tourTitleImageAlt",
+ "match": "t('curiosity-optin.tourTitleImageAlt')",
+ },
+ Object {
+ "key": "curiosity-optin.tourTitle",
+ "match": "t('curiosity-optin.tourTitle')",
+ },
+ Object {
+ "key": "curiosity-optin.tourDescription",
+ "match": "t('curiosity-optin.tourDescription')",
+ },
+ Object {
+ "key": "curiosity-optin.buttonTour",
+ "match": "t('curiosity-optin.buttonTour')",
+ },
+ Object {
+ "key": "curiosity-optin.cardTitle",
+ "match": "t('curiosity-optin.cardTitle', { appName: helpers.UI_DISPLAY_NAME })",
+ },
+ Object {
+ "key": "curiosity-optin.cardDescription",
+ "match": "t('curiosity-optin.cardDescription', { appName: helpers.UI_DISPLAY_NAME })",
+ },
+ Object {
+ "key": "curiosity-optin.cardSeeTitle",
+ "match": "t('curiosity-optin.cardSeeTitle')",
+ },
+ Object {
+ "key": "curiosity-optin.cardSeeDescription",
+ "match": "t('curiosity-optin.cardSeeDescription')",
+ },
+ Object {
+ "key": "curiosity-optin.cardReportTitle",
+ "match": "t('curiosity-optin.cardReportTitle')",
+ },
+ Object {
+ "key": "curiosity-optin.cardReportDescription",
+ "match": "t('curiosity-optin.cardReportDescription')",
+ },
+ Object {
+ "key": "curiosity-optin.cardFilterTitle",
+ "match": "t('curiosity-optin.cardFilterTitle')",
+ },
+ Object {
+ "key": "curiosity-optin.cardFilterDescription",
+ "match": "t('curiosity-optin.cardFilterDescription')",
+ },
+ ],
+ },
+ Object {
+ "file": "./src/components/rhelView/rhelView.js",
+ "keys": Array [
+ Object {
+ "key": "curiosity-view.rhel",
+ "match": "t('curiosity-view.rhel', helpers.UI_DISPLAY_CONFIG_NAME)",
+ },
+ Object {
+ "key": "curiosity-graph.socketsHeading",
+ "match": "t('curiosity-graph.socketsHeading')",
+ },
+ Object {
+ "key": "curiosity-graph.socketsHeading",
+ "match": "t('curiosity-graph.socketsHeading')",
+ },
+ ],
+ },
+ Object {
+ "file": "./src/components/toolbar/toolbar.js",
+ "keys": Array [
+ Object {
+ "key": "curiosity-toolbar.slaCategory",
+ "match": "t('curiosity-toolbar.slaCategory')",
+ },
+ Object {
+ "key": "curiosity-toolbar.slaCategory",
+ "match": "t('curiosity-toolbar.slaCategory')",
+ },
+ Object {
+ "key": "curiosity-toolbar.slaPlaceholder",
+ "match": "t('curiosity-toolbar.slaPlaceholder')",
+ },
+ ],
+ },
+ Object {
+ "file": "./src/components/toolbar/toolbarTypes.js",
+ "keys": Array [
+ Object {
+ "key": "curiosity-toolbar.slaPremium",
+ "match": "translate('curiosity-toolbar.slaPremium')",
+ },
+ Object {
+ "key": "curiosity-toolbar.slaStandard",
+ "match": "translate('curiosity-toolbar.slaStandard')",
+ },
+ Object {
+ "key": "curiosity-toolbar.slaSelfSupport",
+ "match": "translate('curiosity-toolbar.slaSelfSupport')",
+ },
+ Object {
+ "key": "curiosity-toolbar.slaNone",
+ "match": "translate('curiosity-toolbar.slaNone')",
+ },
+ ],
+ },
+ Object {
+ "file": "./src/components/tourView/tourView.js",
+ "keys": Array [
+ Object {
+ "key": "curiosity-tour.emptyStateIconAlt",
+ "match": "t('curiosity-tour.emptyStateIconAlt', { appName: helpers.UI_DISPLAY_CONFIG_NAME })",
+ },
+ Object {
+ "key": "curiosity-tour.emptyStateTitle",
+ "match": "t('curiosity-tour.emptyStateTitle', { appName: helpers.UI_DISPLAY_CONFIG_NAME })",
+ },
+ Object {
+ "key": "curiosity-tour.emptyStateDescription",
+ "match": "t('curiosity-tour.emptyStateDescription', { appName: helpers.UI_DISPLAY_CONFIG_NAME })",
+ },
+ Object {
+ "key": "curiosity-tour.emptyStateDescriptionTour",
+ "match": "t('curiosity-tour.emptyStateDescriptionTour', { appName: helpers.UI_DISPLAY_CONFIG_NAME })",
+ },
+ Object {
+ "key": "curiosity-tour.emptyStateDescriptionExtended",
+ "match": "t('curiosity-tour.emptyStateDescriptionExtended', { appName: helpers.UI_DISPLAY_CONFIG_NAME })",
+ },
+ Object {
+ "key": "curiosity-tour.emptyStateLinkLearnMore",
+ "match": "t('curiosity-tour.emptyStateLinkLearnMore')",
+ },
+ Object {
+ "key": "curiosity-tour.emptyStateButton",
+ "match": "t('curiosity-tour.emptyStateButton')",
+ },
+ Object {
+ "key": "curiosity-tour.emptyStateLinkLearnMore",
+ "match": "t('curiosity-tour.emptyStateLinkLearnMore')",
+ },
+ Object {
+ "key": "curiosity-tour.emptyStateLinkContactUs",
+ "match": "t('curiosity-tour.emptyStateLinkContactUs')",
+ },
+ ],
+ },
+ Object {
+ "file": "./src/redux/actions/userActions.js",
+ "keys": Array [
+ Object {
+ "key": "curiosity-optin.notificationsErrorTitle",
+ "match": "translate('curiosity-optin.notificationsErrorTitle', { appName: helpers.UI_DISPLAY_NAME })",
+ },
+ Object {
+ "key": "curiosity-optin.notificationsErrorDescription",
+ "match": "translate('curiosity-optin.notificationsErrorDescription')",
+ },
+ Object {
+ "key": "curiosity-optin.notificationsSuccessTitle",
+ "match": "translate('curiosity-optin.notificationsSuccessTitle', { appName: helpers.UI_DISPLAY_NAME })",
+ },
+ Object {
+ "key": "curiosity-optin.notificationsSuccessDescription",
+ "match": "translate('curiosity-optin.notificationsSuccessDescription')",
+ },
+ ],
+ },
+]
`;
exports[`I18n Component should have locale keys that exist in the default language JSON: missing locale keys 1`] = `Array []`;
diff --git a/src/components/i18n/__tests__/i18n.test.js b/src/components/i18n/__tests__/i18n.test.js
index 797d67551..98250bcbd 100644
--- a/src/components/i18n/__tests__/i18n.test.js
+++ b/src/components/i18n/__tests__/i18n.test.js
@@ -1,8 +1,9 @@
+import { readFileSync } from 'fs';
+import glob from 'glob';
import React from 'react';
import PropTypes from 'prop-types';
import { mount, shallow } from 'enzyme';
import _get from 'lodash/get';
-import { GettextExtractor, JsExtractors } from 'gettext-extractor';
import { I18n, translate, translateComponent } from '../i18n';
import { helpers } from '../../../common';
import enLocales from '../../../../public/locales/en-US';
@@ -13,28 +14,49 @@ import enLocales from '../../../../public/locales/en-US';
jest.mock('i18next');
/**
- * Help generate a POT output.
+ * Get translation keys.
*
- * @returns {Function}
+ * @param {object} params
+ * @param {string} params.files
+ * @param {Array} params.list
+ * @returns {Array}
*/
-const textExtractor = () => {
- const extractor = new GettextExtractor();
- extractor
- .createJsParser([
- JsExtractors.callExpression(['t', '[this].t', 'translate'], {
- arguments: {
- text: 0,
- context: 1
- }
- })
- ])
- .parseFilesGlob('./src/**/!(*.test|*.spec).@(js|jsx)');
+const getTranslationKeys = ({ files = './src/**/!(*.test|*.spec).@(js|jsx)', list = ['t', 'translate'] }) => {
+ const keys = [];
+ const updatedFiles = glob.sync(files);
+
+ updatedFiles.forEach(file => {
+ const fileContent = readFileSync(file, 'utf-8');
+ const generateRegExp = list.map(f => `\\b${f}\\([\\d\\D]+?\\)`).join('|');
+ const matches = fileContent.match(new RegExp(generateRegExp, 'g'));
+
+ if (matches && matches.length) {
+ const filterKeys = matches
+ .map(match => {
+ const key = match.match(/['`"]([\d\D]+?)['`"][,)]/);
+
+ if (key) {
+ return {
+ key: (!/\${/.test(key) && key[1]) || '',
+ match: match.replace(/\n/g, '').replace(/\s+/g, ' ').trim()
+ };
+ }
+
+ return null;
+ })
+ .filter(key => key !== null);
+
+ if (filterKeys.length) {
+ keys.push({ file, keys: filterKeys });
+ }
+ }
+ });
- return extractor;
+ return keys;
};
describe('I18n Component', () => {
- const getText = textExtractor();
+ const getKeys = getTranslationKeys({});
it('should render a basic component', () => {
const props = {
@@ -98,20 +120,20 @@ describe('I18n Component', () => {
}).toMatchSnapshot('translate');
});
- it('should generate a predictable pot output snapshot', () => {
- expect(getText.getPotString()).toMatchSnapshot('pot output');
+ it('should generate a predictable locale key output snapshot', () => {
+ expect(getKeys).toMatchSnapshot('key output');
});
it('should have locale keys that exist in the default language JSON', () => {
- const messages = (getText.getMessages && getText.getMessages()) || [];
+ const keys = getKeys;
const missingKeys = [];
- messages.forEach(value => {
- const keyCheck = (value && value.text) || '';
-
- if (keyCheck && !_get(enLocales, keyCheck, null)) {
- missingKeys.push(keyCheck);
- }
+ keys.forEach(value => {
+ value.keys.forEach(subValue => {
+ if (subValue.key && !_get(enLocales, subValue.key, null)) {
+ missingKeys.push({ file: value.file, key: subValue.key });
+ }
+ });
});
expect(missingKeys).toMatchSnapshot('missing locale keys');
diff --git a/yarn.lock b/yarn.lock
index faa32ff02..2c13749dd 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1850,7 +1850,7 @@
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
-"@types/glob@5 - 7", "@types/glob@^7.1.1":
+"@types/glob@^7.1.1":
version "7.1.1"
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==
@@ -1904,11 +1904,6 @@
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
-"@types/parse5@^5":
- version "5.0.2"
- resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.2.tgz#a877a4658f8238c8266faef300ae41c84d72ec8a"
- integrity sha512-BOl+6KDs4ItndUWUFchy3aEqGdHhw0BC4Uu+qoDonN/f0rbUnJbm71Ulj8Tt9jLFRaAxPLKvdS1bBLfx1qXR9g==
-
"@types/q@^1.5.1":
version "1.5.2"
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8"
@@ -4150,11 +4145,6 @@ css-select@^2.0.0:
domutils "^1.7.0"
nth-check "^1.0.2"
-css-selector-parser@^1.3:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/css-selector-parser/-/css-selector-parser-1.3.0.tgz#5f1ad43e2d8eefbfdc304fcd39a521664943e3eb"
- integrity sha1-XxrUPi2O77/cME/NOaUhZklD4+s=
-
css-tree@1.0.0-alpha.37:
version "1.0.0-alpha.37"
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22"
@@ -6300,19 +6290,6 @@ getpass@^0.1.1:
dependencies:
assert-plus "^1.0.0"
-gettext-extractor@^3.5.2:
- version "3.5.2"
- resolved "https://registry.yarnpkg.com/gettext-extractor/-/gettext-extractor-3.5.2.tgz#485afb27362e128d33a7947c505e7da7a75a0609"
- integrity sha512-4fJViJvAkWBUV8BHwAaY2T1oirsIEAYgYfYm/+x/gF2xWxOXgn4f7Cjsdq+xuuoA9HZga+fx2PIDP+07zbmP6g==
- dependencies:
- "@types/glob" "5 - 7"
- "@types/parse5" "^5"
- css-selector-parser "^1.3"
- glob "5 - 7"
- parse5 "^5"
- pofile "1.0.x"
- typescript "2 - 3"
-
git-raw-commits@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.0.tgz#d92addf74440c14bcc5c83ecce3fb7f8a79118b5"
@@ -6367,7 +6344,7 @@ glob-to-regexp@^0.3.0:
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
-"glob@5 - 7", glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.1:
+glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.1:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
@@ -9571,11 +9548,6 @@ parse5@^3.0.1:
dependencies:
"@types/node" "*"
-parse5@^5:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178"
- integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==
-
parseurl@~1.3.2, parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
@@ -9800,11 +9772,6 @@ pnp-webpack-plugin@1.6.4:
dependencies:
ts-pnp "^1.1.6"
-pofile@1.0.x:
- version "1.0.11"
- resolved "https://registry.yarnpkg.com/pofile/-/pofile-1.0.11.tgz#35aff58c17491d127a07336d5522ebc9df57c954"
- integrity sha512-Vy9eH1dRD9wHjYt/QqXcTz+RnX/zg53xK+KljFSX30PvdDMb2z+c6uDUeblUGqqJgz3QFsdlA0IJvHziPmWtQg==
-
popper.js@^1.16.0:
version "1.16.1"
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
@@ -12871,11 +12838,6 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
-"typescript@2 - 3":
- version "3.8.2"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.2.tgz#91d6868aaead7da74f493c553aeff76c0c0b1d5a"
- integrity sha512-EgOVgL/4xfVrCMbhYKUQTdF37SQn4Iw73H5BgCrF1Abdun7Kwy/QZsE/ssAy0y4LxBbvua3PIbFsbRczWWnDdQ==
-
uc.micro@^1.0.1, uc.micro@^1.0.5:
version "1.0.6"
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"