Skip to content

Commit

Permalink
[i18n] Translate ML - explorer (elastic#27805)
Browse files Browse the repository at this point in the history
* Translate explorer

* Update snapshot

* Update test

* Resolve comments from review

* Resolve issues from review comments

* Translate additional files

* Fix issues from review comments

* Update test
  • Loading branch information
Nox911 authored Jan 4, 2019
1 parent e7e8d48 commit fc94bb1
Show file tree
Hide file tree
Showing 16 changed files with 281 additions and 106 deletions.
107 changes: 79 additions & 28 deletions x-pack/plugins/ml/public/explorer/explorer.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,38 @@
</filter-bar>

<ml-loading-indicator
label="Loading"
label="{{ ::'xpack.ml.explorer.loadingLabel' | i18n: {defaultMessage: 'Loading'} }}"
is-loading="loading === true"
/>

<div class="no-results-container" ng-if="jobs.length === 0 && loading === false">
<div class="no-results euiText">
<div><i class="fa fa-exclamation-triangle" ></i>No jobs found</div>
<div><a href="ml#/jobs">Create new job</a></div>
<div
i18n-id="xpack.ml.explorer.noJobsFoundLabel"
i18n-default-message="{icon} No jobs found"
i18n-values="{ html_icon: '<i class=\'fa fa-exclamation-triangle\' ></i>' }"
></div>
<div>
<a
href="ml#/jobs"
i18n-id="xpack.ml.explorer.createNewJobLinkText"
i18n-default-message="Create new job"
></a>
</div>
</div>
</div>

<div class="no-results-container" ng-show="jobs.length > 0 && loading === false && hasResults === false">
<div class="no-results euiText">
<div><i class="fa fa-info-circle" ></i>No results found</div>
<div>Try widening the time selection or moving further back in time</div>
<div
i18n-id="xpack.ml.explorer.noResultsFoundLabel"
i18n-default-message="{icon} No results found"
i18n-values="{ html_icon: '<i class=\'fa fa-info-circle\' ></i>' }"
></div>
<div
i18n-id="xpack.ml.explorer.tryWideningTimeSelectionLabel"
i18n-default-message="Try widening the time selection or moving further back in time"
></div>
</div>
</div>

Expand All @@ -34,22 +51,25 @@

<div ng-if="noInfluencersConfigured === true" class="no-influencers-warning">
<i aria-hidden="true" class="fa fa-info-circle" tooltip-placement="right" tooltip-append-to-body="true"
tooltip-html-unsafe="The Top Influencers list is hidden because no influencers have been configured for the selected jobs." ></i>
tooltip-html-unsafe="{{ ::'xpack.ml.explorer.noConfiguredInfluencersTooltip' | i18n: {defaultMessage: 'The Top Influencers list is hidden because no influencers have been configured for the selected jobs.'} }}" ></i>
</div>

<div ng-if="noInfluencersConfigured === false" class="column col-xs-2 euiText">
<span class="panel-title">
Top Influencers
</span>
<span
class="panel-title"
i18n-id="xpack.ml.explorer.topInfuencersTitle"
i18n-default-message="Top Influencers"
></span>
<ml-influencers-list
influencers="influencers"
/>
</div>

<div class="column" ng-class="noInfluencersConfigured === true ? 'col-xs-12' : 'col-xs-10'">
<span class="panel-title euiText">
Anomaly timeline
</span>
<span class="panel-title euiText"
i18n-id="xpack.ml.explorer.anomalyTimelineTitle"
i18n-default-message="Anomaly timeline"
></span>
<div
class="ml-explorer-swimlane euiText"
ng-mouseenter="setSwimlaneSelectActive(true)"
Expand All @@ -60,7 +80,12 @@

<div ng-if="viewBySwimlaneOptions.length > 0">
<div class="ml-controls">
<label for="selectViewBy" class="kuiLabel">View by:</label>
<label
for="selectViewBy"
class="kuiLabel"
i18n-id="xpack.ml.explorer.viewByLabel"
i18n-default-message="View by:"
></label>
<div class="kuiButtonGroup" dropdown>
<button id="selectViewBy" type="button" class="form-control dropdown-toggle" dropdown-toggle ng-disabled="disabled">
<span>{{swimlaneViewByFieldName}}</span> <span class="caret"></span>
Expand All @@ -74,12 +99,19 @@

<ml-select-limit />

<span ng-if="viewByLoadedForTimeFormatted" class="panel-sub-title">
(Sorted by max anomaly score for {{viewByLoadedForTimeFormatted}})
</span>
<span ng-if="!viewByLoadedForTimeFormatted" class="panel-sub-title">
(Sorted by max anomaly score)
</span>
<span
ng-if="viewByLoadedForTimeFormatted"
class="panel-sub-title"
i18n-id="xpack.ml.explorer.sortedByMaxAnomalyScoreForTimeFormattedLabel"
i18n-default-message="(Sorted by max anomaly score for {viewByLoadedForTimeFormatted})"
i18n-values="{ viewByLoadedForTimeFormatted }"
></span>
<span
ng-if="!viewByLoadedForTimeFormatted"
class="panel-sub-title"
i18n-id="xpack.ml.explorer.sortedByMaxAnomalyScoreLabel"
i18n-default-message="(Sorted by max anomaly score)"
></span>
</div>

<div
Expand All @@ -94,17 +126,24 @@
<div ng-if="!showViewBySwimlane" class="text-center visError euiText">
<div class="item top"></div>
<div class="item">
<h4 class="euiTitle euiTitle--small">No {{swimlaneViewByFieldName}} influencers found</h4>
<h4
class="euiTitle euiTitle--small"
i18n-id="xpack.ml.explorer.noInfluencersFoundTitle"
i18n-default-message="No {swimlaneViewByFieldName} influencers found"
i18n-values="{ swimlaneViewByFieldName }"
></h4>
</div>
<div class="item bottom"></div>
</div>

</div>

<div ng-show="annotationsData.length > 0">
<span class="panel-title euiText">
Annotations
</span>
<span
class="panel-title euiText"
i18n-id="xpack.ml.explorer.annotationsTitle"
i18n-default-message="Annotations"
></span>

<ml-annotation-table
annotations="annotationsData"
Expand All @@ -115,22 +154,34 @@ <h4 class="euiTitle euiTitle--small">No {{swimlaneViewByFieldName}} influencers
<br /><br />
</div>

<span class="panel-title euiText">
Anomalies
</span>
<span
class="panel-title euiText"
i18n-id="xpack.ml.explorer.anomaliesTitle"
i18n-default-message="Anomalies"
></span>

<div class="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--directionRow euiFlexGroup--responsive ml-anomalies-controls">
<div class="euiFlexItem euiFlexItem--flexGrowZero" style="width:170px">
<div class="euiFormRow" id="select_severity_control">
<label class="euiFormLabel" for="select_severity">Severity threshold</label>
<label
class="euiFormLabel"
for="select_severity"
i18n-id="xpack.ml.explorer.severityThresholdLabel"
i18n-default-message="Severity threshold"
></label>
<div class="euiFormControlLayout">
<ml-select-severity id="select_severity" />
</div>
</div>
</div>
<div class="euiFlexItem euiFlexItem--flexGrowZero" style="width:170px">
<div class="euiFormRow" id="select_interval_control">
<label class="euiFormLabel" for="select_interval">Interval</label>
<label
class="euiFormLabel"
for="select_interval"
i18n-id="xpack.ml.explorer.intervalLabel"
i18n-default-message="Interval"
></label>
<div class="euiFormControlLayout">
<ml-select-interval id="select_interval" />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ exports[`ExplorerChartLabelBadge Render the chart label in one line. 1`] = `
aria-label="Info"
className="ml-explorer-chart-eui-icon-tip"
content={
<ExplorerChartInfoTooltip
<InjectIntl(ExplorerChartInfoTooltip)
aggregationInterval="1h"
chartFunction="sum nginx.access.body_sent.bytes"
entityFields={
Expand Down Expand Up @@ -80,7 +80,7 @@ exports[`ExplorerChartLabelBadge Render the chart label in two lines. 1`] = `
aria-label="Info"
className="ml-explorer-chart-eui-icon-tip"
content={
<ExplorerChartInfoTooltip
<InjectIntl(ExplorerChartInfoTooltip)
aggregationInterval="1h"
chartFunction="sum nginx.access.body_sent.bytes"
entityFields={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import { mlChartTooltipService } from '../../components/chart_tooltip/chart_tool

import { CHART_TYPE } from '../explorer_constants';

import { injectI18n } from '@kbn/i18n/react';

const CONTENT_WRAPPER_HEIGHT = 215;

// If a rare/event-distribution chart has a cardinality of 10 or less,
Expand All @@ -45,7 +47,7 @@ const CONTENT_WRAPPER_HEIGHT = 215;
// not the cardinality of the full source data set.
const Y_AXIS_LABEL_THRESHOLD = 10;

export class ExplorerChartDistribution extends React.Component {
export const ExplorerChartDistribution = injectI18n(class ExplorerChartDistribution extends React.Component {
static propTypes = {
seriesConfig: PropTypes.object,
mlSelectSeverityService: PropTypes.object.isRequired
Expand All @@ -62,7 +64,8 @@ export class ExplorerChartDistribution extends React.Component {
renderChart() {
const {
tooManyBuckets,
mlSelectSeverityService
mlSelectSeverityService,
intl,
} = this.props;

const element = this.rootNode;
Expand Down Expand Up @@ -414,31 +417,60 @@ export class ExplorerChartDistribution extends React.Component {
if (_.has(marker, 'anomalyScore')) {
const score = parseInt(marker.anomalyScore);
const displayScore = (score > 0 ? score : '< 1');
contents += `anomaly score: ${displayScore}`;
contents += intl.formatMessage({
id: 'xpack.ml.explorer.distributionChart.anomalyScoreLabel',
defaultMessage: 'anomaly score: {displayScore}'
}, { displayScore });
if (chartType !== CHART_TYPE.EVENT_DISTRIBUTION) {
contents += (`<br/>value: ${formatValue(marker.value, config.functionDescription, fieldFormat)}`);
contents += intl.formatMessage({
id: 'xpack.ml.explorer.distributionChart.valueLabel',
defaultMessage: '{br}value: {value}'
}, {
br: '<br />',
value: formatValue(marker.value, config.functionDescription, fieldFormat)
});
if (typeof marker.numberOfCauses === 'undefined' || marker.numberOfCauses === 1) {
contents += (`<br/>typical: ${formatValue(marker.typical, config.functionDescription, fieldFormat)}`);
contents += intl.formatMessage({
id: 'xpack.ml.explorer.distributionChart.typicalLabel',
defaultMessage: '{br}typical: {typicalValue}'
}, {
br: '<br />',
typicalValue: formatValue(marker.typical, config.functionDescription, fieldFormat)
});
}
if (typeof marker.byFieldName !== 'undefined' && _.has(marker, 'numberOfCauses')) {
const numberOfCauses = marker.numberOfCauses;
const byFieldName = mlEscape(marker.byFieldName);
if (numberOfCauses === 1) {
contents += `<br/> 1 unusual ${byFieldName} value`;
} else if (numberOfCauses < 10) {
contents += `<br/> ${numberOfCauses} unusual ${byFieldName} values`;
} else {
contents += intl.formatMessage({
id: 'xpack.ml.explorer.distributionChart.unusualByFieldValuesLabel',
defaultMessage:
'{br} { numberOfCauses, plural, one {# unusual {byFieldName} value} other {#{plusSign} unusual {byFieldName} values}}'
}, {
br: '<br />',
numberOfCauses,
byFieldName,
// Maximum of 10 causes are stored in the record, so '10' may mean more than 10.
contents += `<br/> ${numberOfCauses}+ unusual ${byFieldName} values`;
}
plusSign: numberOfCauses < 10 ? '' : '+',
});
}
}
} else if (chartType !== CHART_TYPE.EVENT_DISTRIBUTION) {
contents += `value: ${formatValue(marker.value, config.functionDescription, fieldFormat)}`;
contents += intl.formatMessage({
id: 'xpack.ml.explorer.distributionChart.valueWithoutAnomalyScoreLabel',
defaultMessage: 'value: {value}'
}, {
value: formatValue(marker.value, config.functionDescription, fieldFormat)
});
}

if (_.has(marker, 'scheduledEvents')) {
contents += `<div><hr/>Scheduled events:<br/>${marker.scheduledEvents.map(mlEscape).join('<br/>')}</div>`;
contents += '<div><hr/>' + intl.formatMessage({
id: 'xpack.ml.explorer.distributionChart.scheduledEventsLabel',
defaultMessage: 'Scheduled events:{br}{scheduledEventsValue}'
}, {
br: '<br />',
scheduledEventsValue: marker.scheduledEvents.map(mlEscape).join('<br/>')
}) + '</div>';
}

mlChartTooltipService.show(contents, circle, {
Expand Down Expand Up @@ -481,4 +513,4 @@ export class ExplorerChartDistribution extends React.Component {
</div>
);
}
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jest.mock('ui/chrome', () => ({
}),
}));

import { mount } from 'enzyme';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
import React from 'react';

import { ExplorerChartDistribution } from './explorer_chart_distribution';
Expand All @@ -49,7 +49,7 @@ describe('ExplorerChart', () => {
afterEach(() => (SVGElement.prototype.getBBox = originalGetBBox));

test('Initialize', () => {
const wrapper = mount(<ExplorerChartDistribution mlSelectSeverityService={mlSelectSeverityServiceMock} />);
const wrapper = mountWithIntl(<ExplorerChartDistribution.WrappedComponent mlSelectSeverityService={mlSelectSeverityServiceMock} />);

// without setting any attributes and corresponding data
// the directive just ends up being empty.
Expand All @@ -63,7 +63,9 @@ describe('ExplorerChart', () => {
loading: true
};

const wrapper = mount(<ExplorerChartDistribution seriesConfig={config} mlSelectSeverityService={mlSelectSeverityServiceMock} />);
const wrapper = mountWithIntl(
<ExplorerChartDistribution.WrappedComponent seriesConfig={config} mlSelectSeverityService={mlSelectSeverityServiceMock} />
);

// test if the loading indicator is shown
expect(wrapper.find('.ml-loading-indicator .loading-spinner')).toHaveLength(1);
Expand All @@ -83,9 +85,9 @@ describe('ExplorerChart', () => {
};

// We create the element including a wrapper which sets the width:
return mount(
return mountWithIntl(
<div style={{ width: '500px' }}>
<ExplorerChartDistribution seriesConfig={config} mlSelectSeverityService={mlSelectSeverityServiceMock} />
<ExplorerChartDistribution.WrappedComponent seriesConfig={config} mlSelectSeverityService={mlSelectSeverityServiceMock} />
</div>
);
}
Expand Down
Loading

0 comments on commit fc94bb1

Please sign in to comment.