From d0938d09074cedf2cdcc6aaa46bf68faac851cc5 Mon Sep 17 00:00:00 2001 From: Liza Katz Date: Tue, 29 Jan 2019 09:39:23 -0800 Subject: [PATCH] Timepicker i18n support (#29397) (#29518) Support i18n for datepicker component --- .../kibana/ui_setting_defaults.js | 66 ++++++++++++------ .../kbn_timepicker_absolute_panel.html | 48 ++++++++++--- .../timepicker/kbn_global_timepicker.html | 15 +++-- src/ui/public/timepicker/pretty_duration.js | 42 +++++++++--- src/ui/public/timepicker/pretty_interval.js | 51 ++++++++++---- src/ui/public/timepicker/relative_options.js | 32 ++++----- .../kbn_timepicker_relative_panel.html | 67 ++++++++++++++----- src/ui/public/timepicker/timepicker.html | 25 ++++--- src/ui/public/timepicker/timepicker.js | 3 +- 9 files changed, 247 insertions(+), 102 deletions(-) diff --git a/src/legacy/core_plugins/kibana/ui_setting_defaults.js b/src/legacy/core_plugins/kibana/ui_setting_defaults.js index 7b93d88810cd..b253b32ae587 100644 --- a/src/legacy/core_plugins/kibana/ui_setting_defaults.js +++ b/src/legacy/core_plugins/kibana/ui_setting_defaults.js @@ -777,30 +777,52 @@ export function getUiSettingDefaults() { defaultMessage: 'Time picker quick ranges', }), value: JSON.stringify([ - { from: 'now/d', to: 'now/d', display: 'Today', section: 0 }, - { from: 'now/w', to: 'now/w', display: 'This week', section: 0 }, - { from: 'now/M', to: 'now/M', display: 'This month', section: 0 }, - { from: 'now/y', to: 'now/y', display: 'This year', section: 0 }, - { from: 'now/d', to: 'now', display: 'Today so far', section: 0 }, - { from: 'now/w', to: 'now', display: 'Week to date', section: 0 }, - { from: 'now/M', to: 'now', display: 'Month to date', section: 0 }, - { from: 'now/y', to: 'now', display: 'Year to date', section: 0 }, + { from: 'now/d', to: 'now/d', + display: i18n.translate('kbn.advancedSettings.timepicker.today', { defaultMessage: 'Today' }), section: 0 }, + { from: 'now/w', to: 'now/w', + display: i18n.translate('kbn.advancedSettings.timepicker.thisWeek', { defaultMessage: 'This week' }), section: 0 }, + { from: 'now/M', to: 'now/M', + display: i18n.translate('kbn.advancedSettings.timepicker.thisMonth', { defaultMessage: 'This month' }), section: 0 }, + { from: 'now/y', to: 'now/y', + display: i18n.translate('kbn.advancedSettings.timepicker.thisYear', { defaultMessage: 'This year' }), section: 0 }, + { from: 'now/d', to: 'now', + display: i18n.translate('kbn.advancedSettings.timepicker.todaySoFar', { defaultMessage: 'Today so far' }), section: 0 }, + { from: 'now/w', to: 'now', + display: i18n.translate('kbn.advancedSettings.timepicker.weekToDate', { defaultMessage: 'Week to date' }), section: 0 }, + { from: 'now/M', to: 'now', + display: i18n.translate('kbn.advancedSettings.timepicker.monthToDate', { defaultMessage: 'Month to date' }), section: 0 }, + { from: 'now/y', to: 'now', + display: i18n.translate('kbn.advancedSettings.timepicker.yearToDate', { defaultMessage: 'Year to date' }), section: 0 }, - { from: 'now-15m', to: 'now', display: 'Last 15 minutes', section: 1 }, - { from: 'now-30m', to: 'now', display: 'Last 30 minutes', section: 1 }, - { from: 'now-1h', to: 'now', display: 'Last 1 hour', section: 1 }, - { from: 'now-4h', to: 'now', display: 'Last 4 hours', section: 1 }, - { from: 'now-12h', to: 'now', display: 'Last 12 hours', section: 1 }, - { from: 'now-24h', to: 'now', display: 'Last 24 hours', section: 1 }, - { from: 'now-7d', to: 'now', display: 'Last 7 days', section: 1 }, + { from: 'now-15m', to: 'now', + display: i18n.translate('kbn.advancedSettings.timepicker.last15Minutes', { defaultMessage: 'Last 15 minutes' }), section: 1 }, + { from: 'now-30m', to: 'now', + display: i18n.translate('kbn.advancedSettings.timepicker.last30Minutes', { defaultMessage: 'Last 30 minutes' }), section: 1 }, + { from: 'now-1h', to: 'now', + display: i18n.translate('kbn.advancedSettings.timepicker.last1Hour', { defaultMessage: 'Last 1 hour' }), section: 1 }, + { from: 'now-4h', to: 'now', + display: i18n.translate('kbn.advancedSettings.timepicker.last4Hours', { defaultMessage: 'Last 4 hours' }), section: 1 }, + { from: 'now-12h', to: 'now', + display: i18n.translate('kbn.advancedSettings.timepicker.last12Hours', { defaultMessage: 'Last 12 hours' }), section: 1 }, + { from: 'now-24h', to: 'now', + display: i18n.translate('kbn.advancedSettings.timepicker.last24Hours', { defaultMessage: 'Last 24 hours' }), section: 1 }, + { from: 'now-7d', to: 'now', + display: i18n.translate('kbn.advancedSettings.timepicker.last7Days', { defaultMessage: 'Last 7 days' }), section: 1 }, - { from: 'now-30d', to: 'now', display: 'Last 30 days', section: 2 }, - { from: 'now-60d', to: 'now', display: 'Last 60 days', section: 2 }, - { from: 'now-90d', to: 'now', display: 'Last 90 days', section: 2 }, - { from: 'now-6M', to: 'now', display: 'Last 6 months', section: 2 }, - { from: 'now-1y', to: 'now', display: 'Last 1 year', section: 2 }, - { from: 'now-2y', to: 'now', display: 'Last 2 years', section: 2 }, - { from: 'now-5y', to: 'now', display: 'Last 5 years', section: 2 }, + { from: 'now-30d', to: 'now', + display: i18n.translate('kbn.advancedSettings.timepicker.last30Days', { defaultMessage: 'Last 30 days' }), section: 2 }, + { from: 'now-60d', to: 'now', + display: i18n.translate('kbn.advancedSettings.timepicker.last60Days', { defaultMessage: 'Last 60 days' }), section: 2 }, + { from: 'now-90d', to: 'now', + display: i18n.translate('kbn.advancedSettings.timepicker.last90Days', { defaultMessage: 'Last 90 days' }), section: 2 }, + { from: 'now-6M', to: 'now', + display: i18n.translate('kbn.advancedSettings.timepicker.last6Months', { defaultMessage: 'Last 6 months' }), section: 2 }, + { from: 'now-1y', to: 'now', + display: i18n.translate('kbn.advancedSettings.timepicker.last1Year', { defaultMessage: 'Last 1 year' }), section: 2 }, + { from: 'now-2y', to: 'now', + display: i18n.translate('kbn.advancedSettings.timepicker.last2Years', { defaultMessage: 'Last 2 years' }), section: 2 }, + { from: 'now-5y', to: 'now', + display: i18n.translate('kbn.advancedSettings.timepicker.last5Years', { defaultMessage: 'Last 5 years' }), section: 2 }, ], null, 2), type: 'json', diff --git a/src/ui/public/timepicker/absolute_panel/kbn_timepicker_absolute_panel.html b/src/ui/public/timepicker/absolute_panel/kbn_timepicker_absolute_panel.html index e72b13feae71..d12e78c1c14f 100644 --- a/src/ui/public/timepicker/absolute_panel/kbn_timepicker_absolute_panel.html +++ b/src/ui/public/timepicker/absolute_panel/kbn_timepicker_absolute_panel.html @@ -2,8 +2,10 @@
-
@@ -24,7 +29,13 @@ input-datetime="{{format}}" ng-model="absolute.from" > -
Invalid Date
+
+ + +
@@ -33,8 +44,10 @@
-
- Invalid Date + + + + - From must occur before To
diff --git a/src/ui/public/timepicker/kbn_global_timepicker.html b/src/ui/public/timepicker/kbn_global_timepicker.html index 0c867d906982..9413ef4f35ad 100644 --- a/src/ui/public/timepicker/kbn_global_timepicker.html +++ b/src/ui/public/timepicker/kbn_global_timepicker.html @@ -28,7 +28,12 @@ data-test-subj="globalRefreshButton" > - Auto-refresh + + + @@ -74,12 +79,12 @@ ng-show="timefilterValues.isTimeRangeSelectorEnabled" class="kuiLocalMenuItem" ng-click="forward()" - aria-label="Move forward in time" + aria-label="{{ ::'common.ui.timepicker.moveForwardInTime' | i18n: { defaultMessage: 'Move forward in time' } }}" >
diff --git a/src/ui/public/timepicker/pretty_duration.js b/src/ui/public/timepicker/pretty_duration.js index f2279cdea721..0ce945cdb08b 100644 --- a/src/ui/public/timepicker/pretty_duration.js +++ b/src/ui/public/timepicker/pretty_duration.js @@ -20,19 +20,28 @@ import dateMath from '@elastic/datemath'; import moment from 'moment'; import { timeUnits } from './time_units'; +import { i18n } from '@kbn/i18n'; + +const TIME_NOW = 'now'; function cantLookup(timeFrom, timeTo, dateFormat) { const displayFrom = formatTimeString(timeFrom, dateFormat); const displayTo = formatTimeString(timeTo, dateFormat, true); - return `${displayFrom} to ${displayTo}`; + return i18n.translate('common.ui.timepicker.fullTimeRange', { + defaultMessage: '{displayFrom} to {displayTo}', + values: { + displayFrom, + displayTo + } + }); } function formatTimeString(timeString, dateFormat, roundUp = false) { if (moment(timeString).isValid()) { return moment(timeString).format(dateFormat); } else { - if (timeString === 'now') { - return 'now'; + if (timeString === TIME_NOW) { + return i18n.translate('common.ui.timepicker.timeNow', { defaultMessage: 'now' }); } else { const tryParse = dateMath.parse(timeString, { roundUp: roundUp }); return moment.isMoment(tryParse) ? '~ ' + tryParse.fromNow() : timeString; @@ -40,27 +49,38 @@ function formatTimeString(timeString, dateFormat, roundUp = false) { } } +function getDateLookupKey(startDate, endDate) { + return startDate + ' to ' + endDate; +} + export function prettyDuration(timeFrom, timeTo, getConfig) { const quickRanges = getConfig('timepicker:quickRanges'); const dateFormat = getConfig('dateFormat'); const lookupByRange = {}; quickRanges.forEach((frame) => { - lookupByRange[frame.from + ' to ' + frame.to] = frame; + lookupByRange[getDateLookupKey(frame.from, frame.to)] = frame; }); // If both parts are date math, try to look up a reasonable string if (timeFrom && timeTo && !moment.isMoment(timeFrom) && !moment.isMoment(timeTo)) { - const tryLookup = lookupByRange[timeFrom.toString() + ' to ' + timeTo.toString()]; + const tryLookup = lookupByRange[getDateLookupKey(timeFrom, timeTo)]; if (tryLookup) { return tryLookup.display; } else { - const fromParts = timeFrom.toString().split('-'); - if (timeTo.toString() === 'now' && fromParts[0] === 'now' && fromParts[1]) { - const rounded = fromParts[1].split('/'); - let text = 'Last ' + rounded[0]; - if (rounded[1]) { - text = text + ' rounded to the ' + timeUnits[rounded[1]]; + const [start, end] = timeFrom.toString().split('-'); + if (timeTo.toString() === TIME_NOW && start === TIME_NOW && end) { + const [amount, unitId] = end.split('/'); + let text = i18n.translate('common.ui.timepicker.timeUntilNowStr', { + defaultMessage: 'Last {amount}', + values: { amount } + }); + + if (unitId) { + text = text + ' ' + i18n.translate('common.ui.timepicker.roundedTo', { + defaultMessage: 'rounded to the {unit}', + values: { unit: timeUnits[unitId] } + }); } return text; } else { diff --git a/src/ui/public/timepicker/pretty_interval.js b/src/ui/public/timepicker/pretty_interval.js index 0d2465ee77d8..57ba6340ed33 100644 --- a/src/ui/public/timepicker/pretty_interval.js +++ b/src/ui/public/timepicker/pretty_interval.js @@ -17,29 +17,52 @@ * under the License. */ +import { i18n } from '@kbn/i18n'; + const MS_IN_SECOND = 1000; const MS_IN_MINUTE = 60 * MS_IN_SECOND; const MS_IN_HOUR = 60 * MS_IN_MINUTE; const MS_IN_DAY = 24 * MS_IN_HOUR; export function prettyInterval(intervalInMs) { + let interval; if (intervalInMs === 0) { - return 'Off'; + return i18n.translate('common.ui.timepicker.off', { defaultMessage: 'Off' }); } else if (intervalInMs < MS_IN_MINUTE) { - const intervalInSeconds = Math.round(intervalInMs / MS_IN_SECOND); - const units = intervalInSeconds > 1 ? 'seconds' : 'second'; - return `${intervalInSeconds} ${units}`; + interval = Math.round(intervalInMs / MS_IN_SECOND); + return i18n.translate('common.ui.timepicker.totalSeconds', { + defaultMessage: `{interval} {interval, plural, + one {second} + other {seconds} + }`, + values: { interval }, + }); } else if (intervalInMs < MS_IN_HOUR) { - const intervalInMinutes = Math.round(intervalInMs / MS_IN_MINUTE); - const units = intervalInMinutes > 1 ? 'minutes' : 'minute'; - return `${intervalInMinutes} ${units}`; + interval = Math.round(intervalInMs / MS_IN_MINUTE); + return i18n.translate('common.ui.timepicker.totalMinutes', { + defaultMessage: `{interval} {interval, plural, + one {minute} + other {minutes} + }`, + values: { interval }, + }); } else if (intervalInMs < MS_IN_DAY) { - const intervalInHours = Math.round(intervalInMs / MS_IN_HOUR); - const units = intervalInHours > 1 ? 'hours' : 'hour'; - return `${intervalInHours} ${units}`; + interval = Math.round(intervalInMs / MS_IN_HOUR); + return i18n.translate('common.ui.timepicker.totalHours', { + defaultMessage: `{interval} {interval, plural, + one {hour} + other {hours} + }`, + values: { interval }, + }); + } else { + interval = Math.round(intervalInMs / MS_IN_DAY); + return i18n.translate('common.ui.timepicker.totalDays', { + defaultMessage: `{interval} {interval, plural, + one {day} + other {days} + }`, + values: { interval }, + }); } - - const intervalInDays = Math.round(intervalInMs / MS_IN_DAY); - const units = intervalInDays > 1 ? 'days' : 'day'; - return `${intervalInDays} ${units}`; } diff --git a/src/ui/public/timepicker/relative_options.js b/src/ui/public/timepicker/relative_options.js index 6718dd4bc9ef..097eb13b8327 100644 --- a/src/ui/public/timepicker/relative_options.js +++ b/src/ui/public/timepicker/relative_options.js @@ -17,21 +17,23 @@ * under the License. */ -export const relativeOptions = [ - { text: 'Seconds ago', value: 's' }, - { text: 'Minutes ago', value: 'm' }, - { text: 'Hours ago', value: 'h' }, - { text: 'Days ago', value: 'd' }, - { text: 'Weeks ago', value: 'w' }, - { text: 'Months ago', value: 'M' }, - { text: 'Years ago', value: 'y' }, +import { i18n } from '@kbn/i18n'; - { text: 'Seconds from now', value: 's+' }, - { text: 'Minutes from now', value: 'm+' }, - { text: 'Hours from now', value: 'h+' }, - { text: 'Days from now', value: 'd+' }, - { text: 'Weeks from now', value: 'w+' }, - { text: 'Months from now', value: 'M+' }, - { text: 'Years from now', value: 'y+' }, +export const relativeOptions = [ + { text: i18n.translate('common.ui.timepicker.relOpts.secondsAgo', { defaultMessage: 'Seconds ago' }), value: 's' }, + { text: i18n.translate('common.ui.timepicker.relOpts.minutesAgo', { defaultMessage: 'Minutes ago' }), value: 'm' }, + { text: i18n.translate('common.ui.timepicker.relOpts.hoursAgo', { defaultMessage: 'Hours ago' }), value: 'h' }, + { text: i18n.translate('common.ui.timepicker.relOpts.daysAgo', { defaultMessage: 'Days ago' }), value: 'd' }, + { text: i18n.translate('common.ui.timepicker.relOpts.weeksAgo', { defaultMessage: 'Weeks ago' }), value: 'w' }, + { text: i18n.translate('common.ui.timepicker.relOpts.monthsAgo', { defaultMessage: 'Months ago' }), value: 'M' }, + { text: i18n.translate('common.ui.timepicker.relOpts.yearsAgo', { defaultMessage: 'Years ago' }), value: 'y' }, + + { text: i18n.translate('common.ui.timepicker.relOpts.secondsFromNow', { defaultMessage: 'Seconds from now' }), value: 's+' }, + { text: i18n.translate('common.ui.timepicker.relOpts.minutesFromNow', { defaultMessage: 'Minutes from now' }), value: 'm+' }, + { text: i18n.translate('common.ui.timepicker.relOpts.hoursFromNow', { defaultMessage: 'Hours from now' }), value: 'h+' }, + { text: i18n.translate('common.ui.timepicker.relOpts.daysFromNow', { defaultMessage: 'Days from now' }), value: 'd+' }, + { text: i18n.translate('common.ui.timepicker.relOpts.weeksFromNow', { defaultMessage: 'Weeks from now' }), value: 'w+' }, + { text: i18n.translate('common.ui.timepicker.relOpts.monthsFromNow', { defaultMessage: 'Months from now' }), value: 'M+' }, + { text: i18n.translate('common.ui.timepicker.relOpts.yearsFromNow', { defaultMessage: 'Years from now' }), value: 'y+' }, ]; diff --git a/src/ui/public/timepicker/relative_panel/kbn_timepicker_relative_panel.html b/src/ui/public/timepicker/relative_panel/kbn_timepicker_relative_panel.html index acf2a2ebebdb..3a36461734a3 100644 --- a/src/ui/public/timepicker/relative_panel/kbn_timepicker_relative_panel.html +++ b/src/ui/public/timepicker/relative_panel/kbn_timepicker_relative_panel.html @@ -2,8 +2,10 @@
-
@@ -22,7 +27,11 @@ {{relative.from.preview}} - Invalid Expression + +
@@ -61,8 +70,14 @@ ng-checked="relative.from.round" ng-change="formatRelative({key:'from'})" > - - round to the {{units[relative.from.unit.substring(0,1)]}} +
@@ -70,8 +85,10 @@
-
@@ -90,7 +110,11 @@ {{relative.to.preview}} - Invalid Expression + +
@@ -129,8 +153,14 @@ ng-checked="relative.to.round" ng-change="formatRelative({key:'to'})" > - - round to the {{units[relative.to.unit.substring(0,1)]}} + +
@@ -141,16 +171,21 @@ - From must occur before To + i18n-id="common.ui.timepicker.fromToError" + i18n-default-message="{strongStr}From{strongEnd} must occur before {strongStr}To{strongEnd}" + i18n-values="{ + html_strongStr: '', + html_strongEnd: '' + }"> +
diff --git a/src/ui/public/timepicker/timepicker.html b/src/ui/public/timepicker/timepicker.html index 5f98c14a3f2e..563491e8dd74 100644 --- a/src/ui/public/timepicker/timepicker.html +++ b/src/ui/public/timepicker/timepicker.html @@ -4,8 +4,10 @@
-

- Time Range +

@@ -19,8 +21,9 @@ ng-click="setMode('quick')" aria-selected="{{mode === 'quick'}}" data-test-subj="timepicker-quick-button" + i18n-id="common.ui.timepicker.categoryquick" + i18n-default-message="Quick" > - Quick
@@ -109,8 +115,11 @@
-

- Refresh Interval +

+

diff --git a/src/ui/public/timepicker/timepicker.js b/src/ui/public/timepicker/timepicker.js index 87d92022d4d6..b88e666e0e74 100644 --- a/src/ui/public/timepicker/timepicker.js +++ b/src/ui/public/timepicker/timepicker.js @@ -36,6 +36,7 @@ import { uiModules } from '../modules'; import { TIME_MODES } from './modes'; import { timeUnits } from './time_units'; import { prettyInterval } from './pretty_interval'; +import { i18n } from '@kbn/i18n'; const module = uiModules.get('ui/timepicker'); module.directive('kbnTimepicker', function (refreshIntervals) { @@ -197,7 +198,7 @@ module.directive('kbnTimepicker', function (refreshIntervals) { const parsed = dateMath.parse(relativeString, { roundUp: key === 'to' }); let preview; if (relativeString === 'now') { - preview = 'Now'; + preview = i18n.translate('common.ui.timepicker.now', { defaultMessage: 'Now' }); } else { preview = parsed ? parsed.format($scope.format) : undefined; }