From e317e751d1a78b03d528ec406d45c9256a08419d Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Wed, 22 Oct 2025 13:17:34 +0100 Subject: [PATCH] Internationalisation: Translate time ranges (#112745) * translations for time ranges * provide default single value --- .../grafana-data/src/datetime/rangeutil.ts | 391 +++++++++++++++--- public/locales/en-US/grafana.json | 46 +++ 2 files changed, 378 insertions(+), 59 deletions(-) diff --git a/packages/grafana-data/src/datetime/rangeutil.ts b/packages/grafana-data/src/datetime/rangeutil.ts index d3d24de56e8..e88eb325408 100644 --- a/packages/grafana-data/src/datetime/rangeutil.ts +++ b/packages/grafana-data/src/datetime/rangeutil.ts @@ -1,4 +1,4 @@ -import { formatDateRange } from '@grafana/i18n'; +import { formatDateRange, t } from '@grafana/i18n'; import { RawTimeRange, TimeRange, TimeZone, IntervalValues, RelativeTimeRange, TimeOption } from '../types/time'; import { getFeatureToggle } from '../utils/featureToggles'; @@ -18,76 +18,349 @@ const spans: { [key: string]: { display: string; section?: number } } = { y: { display: 'year' }, }; -const BASE_RANGE_OPTIONS: TimeOption[] = [ - { from: 'now/d', to: 'now/d', display: 'Today' }, - { from: 'now/d', to: 'now', display: 'Today so far' }, - { from: 'now/w', to: 'now/w', display: 'This week' }, - { from: 'now/w', to: 'now', display: 'This week so far' }, - { from: 'now/M', to: 'now/M', display: 'This month' }, - { from: 'now/M', to: 'now', display: 'This month so far' }, - { from: 'now/y', to: 'now/y', display: 'This year' }, - { from: 'now/y', to: 'now', display: 'This year so far' }, +const getLastNMinutesDisplay = (count: number) => { + return t('grafana-data.datetime.rangeutils.lastNMinutes', 'Last {{count}} minutes', { + count, + defaultValue_one: 'Last {{count}} minute', + }); +}; - { from: 'now-1d/d', to: 'now-1d/d', display: 'Yesterday' }, +const getLastNHoursDisplay = (count: number) => { + return t('grafana-data.datetime.rangeutils.lastNHours', 'Last {{count}} hours', { + count, + defaultValue_one: 'Last {{count}} hour', + }); +}; + +const getLastNDaysDisplay = (count: number) => { + return t('grafana-data.datetime.rangeutils.lastNDays', 'Last {{count}} days', { + count, + defaultValue_one: 'Last {{count}} day', + }); +}; + +const getLastNMonthsDisplay = (count: number) => { + return t('grafana-data.datetime.rangeutils.lastNMonths', 'Last {{count}} months', { + count, + defaultValue_one: 'Last {{count}} month', + }); +}; + +const getLastNYearsDisplay = (count: number) => { + return t('grafana-data.datetime.rangeutils.lastNYears', 'Last {{count}} years', { + count, + defaultValue_one: 'Last {{count}} year', + }); +}; + +const getNextNMinutesDisplay = (count: number) => { + return t('grafana-data.datetime.rangeutils.nextNMinutes', 'Next {{count}} minutes', { + count, + defaultValue_one: 'Next {{count}} minute', + }); +}; + +const getNextNHoursDisplay = (count: number) => { + return t('grafana-data.datetime.rangeutils.nextNHours', 'Next {{count}} hours', { + count, + defaultValue_one: 'Next {{count}} hour', + }); +}; + +const getNextNDaysDisplay = (count: number) => { + return t('grafana-data.datetime.rangeutils.nextNDays', 'Next {{count}} days', { + count, + defaultValue_one: 'Next {{count}} day', + }); +}; + +const getNextNMonthsDisplay = (count: number) => { + return t('grafana-data.datetime.rangeutils.nextNMonths', 'Next {{count}} months', { + count, + defaultValue_one: 'Next {{count}} month', + }); +}; + +const getNextNYearsDisplay = (count: number) => { + return t('grafana-data.datetime.rangeutils.nextNYears', 'Next {{count}} years', { + count, + defaultValue_one: 'Next {{count}} year', + }); +}; + +const getBaseRangeOptions: () => TimeOption[] = () => [ + { from: 'now/d', to: 'now/d', display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.today', 'Today') }, + { + from: 'now/d', + to: 'now', + display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.todaySoFar', 'Today so far'), + }, + { + from: 'now/w', + to: 'now/w', + display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.thisWeek', 'This week'), + }, + { + from: 'now/w', + to: 'now', + display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.thisWeekSoFar', 'This week so far'), + }, + { + from: 'now/M', + to: 'now/M', + display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.thisMonth', 'This month'), + }, + { + from: 'now/M', + to: 'now', + display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.thisMonthSoFar', 'This month so far'), + }, + { + from: 'now/y', + to: 'now/y', + display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.thisYear', 'This year'), + }, + { + from: 'now/y', + to: 'now', + display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.thisYearSoFar', 'This year so far'), + }, + + { + from: 'now-1d/d', + to: 'now-1d/d', + display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.yesterday', 'Yesterday'), + }, { from: 'now-2d/d', to: 'now-2d/d', - display: 'Day before yesterday', + display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.dayBeforeYesterday', 'Day before yesterday'), }, { from: 'now-7d/d', to: 'now-7d/d', - display: 'This day last week', + display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.thisDayLastWeek', 'This day last week'), + }, + { + from: 'now-1w/w', + to: 'now-1w/w', + display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.previousWeek', 'Previous week'), + }, + { + from: 'now-1M/M', + to: 'now-1M/M', + display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.previousMonth', 'Previous month'), + }, + { + from: 'now-1Q/fQ', + to: 'now-1Q/fQ', + display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.previousFiscalQuarter', 'Previous fiscal quarter'), + }, + { + from: 'now-1y/y', + to: 'now-1y/y', + display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.previousYear', 'Previous year'), + }, + { + from: 'now-1y/fy', + to: 'now-1y/fy', + display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.previousFiscalYear', 'Previous fiscal year'), }, - { from: 'now-1w/w', to: 'now-1w/w', display: 'Previous week' }, - { from: 'now-1M/M', to: 'now-1M/M', display: 'Previous month' }, - { from: 'now-1Q/fQ', to: 'now-1Q/fQ', display: 'Previous fiscal quarter' }, - { from: 'now-1y/y', to: 'now-1y/y', display: 'Previous year' }, - { from: 'now-1y/fy', to: 'now-1y/fy', display: 'Previous fiscal year' }, - { from: 'now-5m', to: 'now', display: 'Last 5 minutes' }, - { from: 'now-15m', to: 'now', display: 'Last 15 minutes' }, - { from: 'now-30m', to: 'now', display: 'Last 30 minutes' }, - { from: 'now-1h', to: 'now', display: 'Last 1 hour' }, - { from: 'now-3h', to: 'now', display: 'Last 3 hours' }, - { from: 'now-6h', to: 'now', display: 'Last 6 hours' }, - { from: 'now-12h', to: 'now', display: 'Last 12 hours' }, - { from: 'now-24h', to: 'now', display: 'Last 24 hours' }, - { from: 'now-2d', to: 'now', display: 'Last 2 days' }, - { from: 'now-7d', to: 'now', display: 'Last 7 days' }, - { from: 'now-30d', to: 'now', display: 'Last 30 days' }, - { from: 'now-90d', to: 'now', display: 'Last 90 days' }, - { from: 'now-6M', to: 'now', display: 'Last 6 months' }, - { from: 'now-1y', to: 'now', display: 'Last 1 year' }, - { from: 'now-2y', to: 'now', display: 'Last 2 years' }, - { from: 'now-5y', to: 'now', display: 'Last 5 years' }, - { from: 'now/fQ', to: 'now', display: 'This fiscal quarter so far' }, - { from: 'now/fQ', to: 'now/fQ', display: 'This fiscal quarter' }, - { from: 'now/fy', to: 'now', display: 'This fiscal year so far' }, - { from: 'now/fy', to: 'now/fy', display: 'This fiscal year' }, + { + from: 'now-5m', + to: 'now', + display: getLastNMinutesDisplay(5), + }, + { + from: 'now-15m', + to: 'now', + display: getLastNMinutesDisplay(15), + }, + { + from: 'now-30m', + to: 'now', + display: getLastNMinutesDisplay(30), + }, + { + from: 'now-1h', + to: 'now', + display: getLastNHoursDisplay(1), + }, + { + from: 'now-3h', + to: 'now', + display: getLastNHoursDisplay(3), + }, + { + from: 'now-6h', + to: 'now', + display: getLastNHoursDisplay(6), + }, + { + from: 'now-12h', + to: 'now', + display: getLastNHoursDisplay(12), + }, + { + from: 'now-24h', + to: 'now', + display: getLastNHoursDisplay(24), + }, + { + from: 'now-2d', + to: 'now', + display: getLastNDaysDisplay(2), + }, + { + from: 'now-7d', + to: 'now', + display: getLastNDaysDisplay(7), + }, + { + from: 'now-30d', + to: 'now', + display: getLastNDaysDisplay(30), + }, + { + from: 'now-90d', + to: 'now', + display: getLastNDaysDisplay(90), + }, + { + from: 'now-6M', + to: 'now', + display: getLastNMonthsDisplay(6), + }, + { + from: 'now-1y', + to: 'now', + display: getLastNYearsDisplay(1), + }, + { + from: 'now-2y', + to: 'now', + display: getLastNYearsDisplay(2), + }, + { + from: 'now-5y', + to: 'now', + display: getLastNYearsDisplay(5), + }, + { + from: 'now/fQ', + to: 'now', + display: t( + 'grafana-data.datetime.rangeutils.getBaseRangeOptions.thisFiscalQuarterSoFar', + 'This fiscal quarter so far' + ), + }, + { + from: 'now/fQ', + to: 'now/fQ', + display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.thisFiscalQuarter', 'This fiscal quarter'), + }, + { + from: 'now/fy', + to: 'now', + display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.thisFiscalYearSoFar', 'This fiscal year so far'), + }, + { + from: 'now/fy', + to: 'now/fy', + display: t('grafana-data.datetime.rangeutils.getBaseRangeOptions.thisFiscalYear', 'This fiscal year'), + }, ]; -const HIDDEN_RANGE_OPTIONS: TimeOption[] = [ - { from: 'now', to: 'now+1m', display: 'Next minute' }, - { from: 'now', to: 'now+5m', display: 'Next 5 minutes' }, - { from: 'now', to: 'now+15m', display: 'Next 15 minutes' }, - { from: 'now', to: 'now+30m', display: 'Next 30 minutes' }, - { from: 'now', to: 'now+1h', display: 'Next hour' }, - { from: 'now', to: 'now+3h', display: 'Next 3 hours' }, - { from: 'now', to: 'now+6h', display: 'Next 6 hours' }, - { from: 'now', to: 'now+12h', display: 'Next 12 hours' }, - { from: 'now', to: 'now+24h', display: 'Next 24 hours' }, - { from: 'now', to: 'now+2d', display: 'Next 2 days' }, - { from: 'now', to: 'now+7d', display: 'Next 7 days' }, - { from: 'now', to: 'now+30d', display: 'Next 30 days' }, - { from: 'now', to: 'now+90d', display: 'Next 90 days' }, - { from: 'now', to: 'now+6M', display: 'Next 6 months' }, - { from: 'now', to: 'now+1y', display: 'Next year' }, - { from: 'now', to: 'now+2y', display: 'Next 2 years' }, - { from: 'now', to: 'now+5y', display: 'Next 5 years' }, +const getHiddenRangeOptions: () => TimeOption[] = () => [ + { + from: 'now', + to: 'now+1m', + display: getNextNMinutesDisplay(1), + }, + { + from: 'now', + to: 'now+5m', + display: getNextNMinutesDisplay(5), + }, + { + from: 'now', + to: 'now+15m', + display: getNextNMinutesDisplay(15), + }, + { + from: 'now', + to: 'now+30m', + display: getNextNMinutesDisplay(30), + }, + { + from: 'now', + to: 'now+1h', + display: getNextNHoursDisplay(1), + }, + { + from: 'now', + to: 'now+3h', + display: getNextNHoursDisplay(3), + }, + { + from: 'now', + to: 'now+6h', + display: getNextNHoursDisplay(6), + }, + { + from: 'now', + to: 'now+12h', + display: getNextNHoursDisplay(12), + }, + { + from: 'now', + to: 'now+24h', + display: getNextNHoursDisplay(24), + }, + { + from: 'now', + to: 'now+2d', + display: getNextNDaysDisplay(2), + }, + { + from: 'now', + to: 'now+7d', + display: getNextNDaysDisplay(7), + }, + { + from: 'now', + to: 'now+30d', + display: getNextNDaysDisplay(30), + }, + { + from: 'now', + to: 'now+90d', + display: getNextNDaysDisplay(90), + }, + { + from: 'now', + to: 'now+6M', + display: getNextNMonthsDisplay(6), + }, + { + from: 'now', + to: 'now+1y', + display: getNextNYearsDisplay(1), + }, + { + from: 'now', + to: 'now+2y', + display: getNextNYearsDisplay(2), + }, + { + from: 'now', + to: 'now+5y', + display: getNextNYearsDisplay(5), + }, ]; -const STANDARD_RANGE_OPTIONS = BASE_RANGE_OPTIONS.concat(HIDDEN_RANGE_OPTIONS); +const getStandardRangeOptions = () => [...getBaseRangeOptions(), ...getHiddenRangeOptions()]; function findRangeInOptions(range: RawTimeRange, options: TimeOption[]) { return options.find((option) => option.from === range.from && option.to === range.to); @@ -105,7 +378,7 @@ export function describeTextRange(expr: string): TimeOption { expr = (isLast ? 'now-' : 'now') + expr; } - let opt = findRangeInOptions({ from: expr, to: 'now' }, STANDARD_RANGE_OPTIONS); + let opt = findRangeInOptions({ from: expr, to: 'now' }, getStandardRangeOptions()); if (opt) { return opt; } @@ -158,7 +431,7 @@ const rangeFormatFull: Intl.DateTimeFormatOptions = { * @alpha */ export function describeTimeRange(range: RawTimeRange, timeZone?: TimeZone, quickRanges?: TimeOption[]): string { - const rangeOptions = quickRanges ? quickRanges.concat(STANDARD_RANGE_OPTIONS) : STANDARD_RANGE_OPTIONS; + const rangeOptions = quickRanges ? quickRanges.concat(getStandardRangeOptions()) : getStandardRangeOptions(); const option = findRangeInOptions(range, rangeOptions); if (option) { diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 662711d4270..db2c3935b3e 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -8006,6 +8006,52 @@ "select-group": "Select group" }, "grafana-data": { + "datetime": { + "rangeutils": { + "getBaseRangeOptions": { + "dayBeforeYesterday": "Day before yesterday", + "previousFiscalQuarter": "Previous fiscal quarter", + "previousFiscalYear": "Previous fiscal year", + "previousMonth": "Previous month", + "previousWeek": "Previous week", + "previousYear": "Previous year", + "thisDayLastWeek": "This day last week", + "thisFiscalQuarter": "This fiscal quarter", + "thisFiscalQuarterSoFar": "This fiscal quarter so far", + "thisFiscalYear": "This fiscal year", + "thisFiscalYearSoFar": "This fiscal year so far", + "thisMonth": "This month", + "thisMonthSoFar": "This month so far", + "thisWeek": "This week", + "thisWeekSoFar": "This week so far", + "thisYear": "This year", + "thisYearSoFar": "This year so far", + "today": "Today", + "todaySoFar": "Today so far", + "yesterday": "Yesterday" + }, + "lastNDays_one": "Last {{count}} day", + "lastNDays_other": "Last {{count}} days", + "lastNHours_one": "Last {{count}} hour", + "lastNHours_other": "Last {{count}} hours", + "lastNMinutes_one": "Last {{count}} minute", + "lastNMinutes_other": "Last {{count}} minutes", + "lastNMonths_one": "Last {{count}} month", + "lastNMonths_other": "Last {{count}} months", + "lastNYears_one": "Last {{count}} year", + "lastNYears_other": "Last {{count}} years", + "nextNDays_one": "Next {{count}} day", + "nextNDays_other": "Next {{count}} days", + "nextNHours_one": "Next {{count}} hour", + "nextNHours_other": "Next {{count}} hours", + "nextNMinutes_one": "Next {{count}} minute", + "nextNMinutes_other": "Next {{count}} minutes", + "nextNMonths_one": "Next {{count}} month", + "nextNMonths_other": "Next {{count}} months", + "nextNYears_one": "Next {{count}} year", + "nextNYears_other": "Next {{count}} years" + } + }, "valueFormats": { "categories": { "acceleration": {