chore: Localization of superset pt. 2 (#22772)
This commit is contained in:
parent
b94052e438
commit
c839d0daf5
|
|
@ -81,7 +81,7 @@ const columnWidth: ControlFormItemSpec<'InputNumber'> = {
|
|||
"Default minimal column width in pixels, actual width may still be larger than this if other columns don't need much space",
|
||||
),
|
||||
width: 120,
|
||||
placeholder: 'auto',
|
||||
placeholder: t('auto'),
|
||||
debounceDelay: 400,
|
||||
validators: [validateNumber],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { extent as d3Extent, range as d3Range } from 'd3-array';
|
||||
import { select as d3Select } from 'd3-selection';
|
||||
import { getSequentialSchemeRegistry } from '@superset-ui/core';
|
||||
import { getSequentialSchemeRegistry, t } from '@superset-ui/core';
|
||||
import CalHeatMap from './vendor/cal-heatmap';
|
||||
|
||||
const propTypes = {
|
||||
|
|
@ -85,10 +85,12 @@ function Calendar(element, props) {
|
|||
|
||||
const metricsData = data.data;
|
||||
|
||||
const METRIC_TEXT = t('Metric');
|
||||
|
||||
Object.keys(metricsData).forEach(metric => {
|
||||
const calContainer = div.append('div');
|
||||
if (showMetricName) {
|
||||
calContainer.text(`Metric: ${verboseMap[metric] || metric}`);
|
||||
calContainer.text(`${METRIC_TEXT}: ${verboseMap[metric] || metric}`);
|
||||
}
|
||||
const timestamps = metricsData[metric];
|
||||
const extents = d3Extent(Object.keys(timestamps), key => timestamps[key]);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
/* eslint-disable */
|
||||
|
||||
import d3tip from 'd3-tip';
|
||||
import { getContrastingColor } from '@superset-ui/core';
|
||||
import { getContrastingColor, t } from '@superset-ui/core';
|
||||
|
||||
var d3 = typeof require === 'function' ? require('d3') : window.d3;
|
||||
|
||||
|
|
@ -256,9 +256,9 @@ var CalHeatMap = function () {
|
|||
|
||||
// Formatting of the title displayed when hovering a legend cell
|
||||
legendTitleFormat: {
|
||||
lower: 'less than {min} {name}',
|
||||
inner: 'between {down} and {up} {name}',
|
||||
upper: 'more than {max} {name}',
|
||||
lower: t('less than {min} {name}'),
|
||||
inner: t('between {down} and {up} {name}'),
|
||||
upper: t('more than {max} {name}'),
|
||||
},
|
||||
|
||||
// Animation duration, in ms
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ class CustomHistogram extends React.PureComponent {
|
|||
renderTooltip={({ datum, color }) => (
|
||||
<div>
|
||||
<strong style={{ color }}>
|
||||
{datum.bin0} to {datum.bin1}
|
||||
{datum.bin0} {t('to')} {datum.bin1}
|
||||
</strong>
|
||||
<div>
|
||||
<strong>{t('count')} </strong>
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import {
|
|||
NumberFormats,
|
||||
CategoricalColorNamespace,
|
||||
getSequentialSchemeRegistry,
|
||||
t,
|
||||
} from '@superset-ui/core';
|
||||
import wrapSvgText from './utils/wrapSvgText';
|
||||
|
||||
|
|
@ -381,7 +382,10 @@ function Sunburst(element, props) {
|
|||
.append('text')
|
||||
.attr('class', 'path-abs-percent')
|
||||
.attr('y', yOffsets[offsetIndex])
|
||||
.text(`${absolutePercString} of total`);
|
||||
// eslint-disable-next-line prefer-template
|
||||
.text(absolutePercString + ' ' + t('of total'));
|
||||
|
||||
const OF_PARENT_TEXT = t('of parent');
|
||||
|
||||
if (conditionalPercString) {
|
||||
offsetIndex += 1;
|
||||
|
|
@ -389,7 +393,7 @@ function Sunburst(element, props) {
|
|||
.append('text')
|
||||
.attr('class', 'path-cond-percent')
|
||||
.attr('y', yOffsets[offsetIndex])
|
||||
.text(`${conditionalPercString} of parent`);
|
||||
.text(`${conditionalPercString} ${OF_PARENT_TEXT}`);
|
||||
}
|
||||
|
||||
offsetIndex += 1;
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ const radarMetricMaxValue: { name: string; config: ControlFormItemSpec } = {
|
|||
'The maximum value of metrics. It is an optional configuration',
|
||||
),
|
||||
width: 120,
|
||||
placeholder: 'auto',
|
||||
placeholder: t('auto'),
|
||||
debounceDelay: 400,
|
||||
validators: [validateNumber],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ function createAxisTitleControl(axis: 'x' | 'y'): ControlSetRow[] {
|
|||
const isXAxis = axis === 'x';
|
||||
const isVertical = (controls: ControlStateMapping) =>
|
||||
Boolean(controls?.orientation.value === OrientationType.vertical);
|
||||
const isHorizental = (controls: ControlStateMapping) =>
|
||||
const isHorizontal = (controls: ControlStateMapping) =>
|
||||
Boolean(controls?.orientation.value === OrientationType.horizontal);
|
||||
return [
|
||||
[
|
||||
|
|
@ -65,7 +65,7 @@ function createAxisTitleControl(axis: 'x' | 'y'): ControlSetRow[] {
|
|||
default: '',
|
||||
description: t('Changing this control takes effect instantly'),
|
||||
visibility: ({ controls }: ControlPanelsContainerProps) =>
|
||||
isXAxis ? isVertical(controls) : isHorizental(controls),
|
||||
isXAxis ? isVertical(controls) : isHorizontal(controls),
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
@ -82,7 +82,7 @@ function createAxisTitleControl(axis: 'x' | 'y'): ControlSetRow[] {
|
|||
choices: formatSelectOptions(sections.TITLE_MARGIN_OPTIONS),
|
||||
description: t('Changing this control takes effect instantly'),
|
||||
visibility: ({ controls }: ControlPanelsContainerProps) =>
|
||||
isXAxis ? isVertical(controls) : isHorizental(controls),
|
||||
isXAxis ? isVertical(controls) : isHorizontal(controls),
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
@ -96,7 +96,7 @@ function createAxisTitleControl(axis: 'x' | 'y'): ControlSetRow[] {
|
|||
default: '',
|
||||
description: t('Changing this control takes effect instantly'),
|
||||
visibility: ({ controls }: ControlPanelsContainerProps) =>
|
||||
isXAxis ? isHorizental(controls) : isVertical(controls),
|
||||
isXAxis ? isHorizontal(controls) : isVertical(controls),
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
@ -113,7 +113,7 @@ function createAxisTitleControl(axis: 'x' | 'y'): ControlSetRow[] {
|
|||
choices: formatSelectOptions(sections.TITLE_MARGIN_OPTIONS),
|
||||
description: t('Changing this control takes effect instantly'),
|
||||
visibility: ({ controls }: ControlPanelsContainerProps) =>
|
||||
isXAxis ? isHorizental(controls) : isVertical(controls),
|
||||
isXAxis ? isHorizontal(controls) : isVertical(controls),
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
@ -130,7 +130,7 @@ function createAxisTitleControl(axis: 'x' | 'y'): ControlSetRow[] {
|
|||
choices: sections.TITLE_POSITION_OPTIONS,
|
||||
description: t('Changing this control takes effect instantly'),
|
||||
visibility: ({ controls }: ControlPanelsContainerProps) =>
|
||||
isXAxis ? isHorizental(controls) : isVertical(controls),
|
||||
isXAxis ? isHorizontal(controls) : isVertical(controls),
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
@ -141,7 +141,7 @@ function createAxisControl(axis: 'x' | 'y'): ControlSetRow[] {
|
|||
const isXAxis = axis === 'x';
|
||||
const isVertical = (controls: ControlStateMapping) =>
|
||||
Boolean(controls?.orientation.value === OrientationType.vertical);
|
||||
const isHorizental = (controls: ControlStateMapping) =>
|
||||
const isHorizontal = (controls: ControlStateMapping) =>
|
||||
Boolean(controls?.orientation.value === OrientationType.horizontal);
|
||||
return [
|
||||
[
|
||||
|
|
@ -154,7 +154,7 @@ function createAxisControl(axis: 'x' | 'y'): ControlSetRow[] {
|
|||
'When using other than adaptive formatting, labels may overlap.',
|
||||
)}`,
|
||||
visibility: ({ controls }: ControlPanelsContainerProps) =>
|
||||
isXAxis ? isVertical(controls) : isHorizental(controls),
|
||||
isXAxis ? isVertical(controls) : isHorizontal(controls),
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
@ -176,7 +176,7 @@ function createAxisControl(axis: 'x' | 'y'): ControlSetRow[] {
|
|||
'Input field supports custom rotation. e.g. 30 for 30°',
|
||||
),
|
||||
visibility: ({ controls }: ControlPanelsContainerProps) =>
|
||||
isXAxis ? isVertical(controls) : isHorizental(controls),
|
||||
isXAxis ? isVertical(controls) : isHorizontal(controls),
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
@ -187,7 +187,7 @@ function createAxisControl(axis: 'x' | 'y'): ControlSetRow[] {
|
|||
...sharedControls.y_axis_format,
|
||||
label: t('Axis Format'),
|
||||
visibility: ({ controls }: ControlPanelsContainerProps) =>
|
||||
isXAxis ? isHorizental(controls) : isVertical(controls),
|
||||
isXAxis ? isHorizontal(controls) : isVertical(controls),
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
@ -201,7 +201,7 @@ function createAxisControl(axis: 'x' | 'y'): ControlSetRow[] {
|
|||
default: logAxis,
|
||||
description: t('Logarithmic axis'),
|
||||
visibility: ({ controls }: ControlPanelsContainerProps) =>
|
||||
isXAxis ? isHorizental(controls) : isVertical(controls),
|
||||
isXAxis ? isHorizontal(controls) : isVertical(controls),
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
@ -215,7 +215,7 @@ function createAxisControl(axis: 'x' | 'y'): ControlSetRow[] {
|
|||
default: minorSplitLine,
|
||||
description: t('Draw split lines for minor axis ticks'),
|
||||
visibility: ({ controls }: ControlPanelsContainerProps) =>
|
||||
isXAxis ? isHorizental(controls) : isVertical(controls),
|
||||
isXAxis ? isHorizontal(controls) : isVertical(controls),
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
@ -229,7 +229,7 @@ function createAxisControl(axis: 'x' | 'y'): ControlSetRow[] {
|
|||
renderTrigger: true,
|
||||
description: t('It’s not recommended to truncate axis in Bar chart.'),
|
||||
visibility: ({ controls }: ControlPanelsContainerProps) =>
|
||||
isXAxis ? isHorizental(controls) : isVertical(controls),
|
||||
isXAxis ? isHorizontal(controls) : isVertical(controls),
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
@ -249,7 +249,7 @@ function createAxisControl(axis: 'x' | 'y'): ControlSetRow[] {
|
|||
),
|
||||
visibility: ({ controls }: ControlPanelsContainerProps) =>
|
||||
Boolean(controls?.truncateYAxis?.value) &&
|
||||
(isXAxis ? isHorizental(controls) : isVertical(controls)),
|
||||
(isXAxis ? isHorizontal(controls) : isVertical(controls)),
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import {
|
|||
useTheme,
|
||||
isAdhocColumn,
|
||||
BinaryQueryObjectFilterClause,
|
||||
t,
|
||||
} from '@superset-ui/core';
|
||||
import { PivotTable, sortAs, aggregatorTemplates } from './react-pivottable';
|
||||
import {
|
||||
|
|
@ -55,7 +56,7 @@ const PivotTableWrapper = styled.div`
|
|||
overflow: auto;
|
||||
`;
|
||||
|
||||
const METRIC_KEY = 'metric';
|
||||
const METRIC_KEY = t('metric');
|
||||
const vals = ['value'];
|
||||
|
||||
const StyledPlusSquareOutlined = styled(PlusSquareOutlined)`
|
||||
|
|
|
|||
|
|
@ -487,7 +487,9 @@ export class TableRenderer extends React.Component {
|
|||
true,
|
||||
)}
|
||||
>
|
||||
{`Total (${this.props.aggregatorName})`}
|
||||
{t('Total (%(aggregatorName)s)', {
|
||||
aggregatorName: t(this.props.aggregatorName),
|
||||
})}
|
||||
</th>
|
||||
) : null;
|
||||
|
||||
|
|
@ -550,7 +552,9 @@ export class TableRenderer extends React.Component {
|
|||
)}
|
||||
>
|
||||
{colAttrs.length === 0
|
||||
? `Total (${this.props.aggregatorName})`
|
||||
? t('Total (%(aggregatorName)s)', {
|
||||
aggregatorName: t(this.props.aggregatorName),
|
||||
})
|
||||
: null}
|
||||
</th>
|
||||
</tr>
|
||||
|
|
@ -764,10 +768,9 @@ export class TableRenderer extends React.Component {
|
|||
true,
|
||||
)}
|
||||
>
|
||||
{
|
||||
// eslint-disable-next-line prefer-template
|
||||
t('Total') + ` (${this.props.aggregatorName})`
|
||||
}
|
||||
{t('Total (%(aggregatorName)s)', {
|
||||
aggregatorName: t(this.props.aggregatorName),
|
||||
})}
|
||||
</th>
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { t } from '@superset-ui/core';
|
||||
import { formatSelectOptions } from '@superset-ui/chart-controls';
|
||||
|
||||
export type SizeOption = [number, string];
|
||||
|
|
@ -34,7 +35,7 @@ function DefaultSelectRenderer({
|
|||
}: SelectPageSizeRendererProps) {
|
||||
return (
|
||||
<span className="dt-select-page-size form-inline">
|
||||
Show{' '}
|
||||
{t('Show')}{' '}
|
||||
<select
|
||||
className="form-control input-sm"
|
||||
value={current}
|
||||
|
|
@ -54,7 +55,7 @@ function DefaultSelectRenderer({
|
|||
);
|
||||
})}
|
||||
</select>{' '}
|
||||
entries
|
||||
{t('entries')}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ function SelectPageSize({
|
|||
}
|
||||
|
||||
const getNoResultsMessage = (filter: string) =>
|
||||
t(filter ? 'No matching records found' : 'No records found');
|
||||
filter ? t('No matching records found') : t('No records found');
|
||||
|
||||
export default function TableChart<D extends DataRecord = DataRecord>(
|
||||
props: TableChartTransformedProps<D> & {
|
||||
|
|
|
|||
|
|
@ -1412,7 +1412,7 @@ export function popQuery(queryId) {
|
|||
dbId: queryData.database.id,
|
||||
schema: queryData.schema,
|
||||
sql: queryData.sql,
|
||||
name: `Copy of ${queryData.tab_name}`,
|
||||
name: t('Copy of %s', queryData.tab_name),
|
||||
autorun: false,
|
||||
};
|
||||
return dispatch(addQueryEditor(queryEditorProps));
|
||||
|
|
@ -1422,6 +1422,7 @@ export function popQuery(queryId) {
|
|||
}
|
||||
export function popDatasourceQuery(datasourceKey, sql) {
|
||||
return function (dispatch) {
|
||||
const QUERY_TEXT = t('Query');
|
||||
const datasetId = datasourceKey.split('__')[0];
|
||||
return SupersetClient.get({
|
||||
endpoint: `/api/v1/dataset/${datasetId}?q=(keys:!(none))`,
|
||||
|
|
@ -1429,7 +1430,7 @@ export function popDatasourceQuery(datasourceKey, sql) {
|
|||
.then(({ json }) =>
|
||||
dispatch(
|
||||
addQueryEditor({
|
||||
name: `Query ${json.result.name}`,
|
||||
name: `${QUERY_TEXT} ${json.result.name}`,
|
||||
dbId: json.result.database.id,
|
||||
schema: json.result.schema,
|
||||
autorun: sql !== undefined,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
import React from 'react';
|
||||
import Label from 'src/components/Label';
|
||||
import { STATE_TYPE_MAP } from 'src/SqlLab/constants';
|
||||
import { STATE_TYPE_MAP, STATE_TYPE_MAP_LOCALIZED } from 'src/SqlLab/constants';
|
||||
import { styled, Query } from '@superset-ui/core';
|
||||
|
||||
interface QueryStateLabelProps {
|
||||
|
|
@ -31,6 +31,8 @@ const StyledLabel = styled(Label)`
|
|||
|
||||
export default function QueryStateLabel({ query }: QueryStateLabelProps) {
|
||||
return (
|
||||
<StyledLabel type={STATE_TYPE_MAP[query.state]}>{query.state}</StyledLabel>
|
||||
<StyledLabel type={STATE_TYPE_MAP[query.state]}>
|
||||
{STATE_TYPE_MAP_LOCALIZED[query.state]}
|
||||
</StyledLabel>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -360,8 +360,8 @@ const ResultSet = ({
|
|||
message={t('%(rows)d rows returned', { rows })}
|
||||
onClose={() => setAlertIsOpen(false)}
|
||||
description={t(
|
||||
'The number of rows displayed is limited to %s by the dropdown.',
|
||||
rows,
|
||||
'The number of rows displayed is limited to %(rows)d by the dropdown.',
|
||||
{ rows },
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import {
|
|||
STATUS_OPTIONS,
|
||||
STATE_TYPE_MAP,
|
||||
LOCALSTORAGE_MAX_QUERY_AGE_MS,
|
||||
STATUS_OPTIONS_LOCALIZED,
|
||||
} from '../../constants';
|
||||
|
||||
const TAB_HEIGHT = 140;
|
||||
|
|
@ -145,7 +146,7 @@ const SouthPane = ({
|
|||
};
|
||||
const renderOfflineStatus = () => (
|
||||
<Label className="m-r-3" type={STATE_TYPE_MAP[STATUS_OPTIONS.offline]}>
|
||||
{STATUS_OPTIONS.offline}
|
||||
{STATUS_OPTIONS_LOCALIZED.offline}
|
||||
</Label>
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { t } from '@superset-ui/core';
|
||||
|
||||
export const STATE_TYPE_MAP = {
|
||||
offline: 'danger',
|
||||
failed: 'danger',
|
||||
|
|
@ -26,6 +28,16 @@ export const STATE_TYPE_MAP = {
|
|||
success: 'success',
|
||||
};
|
||||
|
||||
export const STATE_TYPE_MAP_LOCALIZED = {
|
||||
offline: t('offline'),
|
||||
failed: t('failed'),
|
||||
pending: t('pending'),
|
||||
fetching: t('fetching'),
|
||||
running: t('running'),
|
||||
stopped: t('stopped'),
|
||||
success: t('success'),
|
||||
};
|
||||
|
||||
export const STATUS_OPTIONS = {
|
||||
success: 'success',
|
||||
failed: 'failed',
|
||||
|
|
@ -34,6 +46,14 @@ export const STATUS_OPTIONS = {
|
|||
pending: 'pending',
|
||||
};
|
||||
|
||||
export const STATUS_OPTIONS_LOCALIZED = {
|
||||
success: t('success'),
|
||||
failed: t('failed'),
|
||||
running: t('running'),
|
||||
offline: t('offline'),
|
||||
pending: t('pending'),
|
||||
};
|
||||
|
||||
export const TIME_OPTIONS = [
|
||||
'now',
|
||||
'1 hour ago',
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ export default function DatabaseSelector({
|
|||
setSchemaOptions(options);
|
||||
setLoadingSchemas(false);
|
||||
if (options.length === 1) changeSchema(options[0]);
|
||||
if (refresh > 0) addSuccessToast('List refreshed');
|
||||
if (refresh > 0) addSuccessToast(t('List refreshed'));
|
||||
})
|
||||
.catch(err => {
|
||||
setLoadingSchemas(false);
|
||||
|
|
@ -321,6 +321,7 @@ export default function DatabaseSelector({
|
|||
labelInValue
|
||||
loading={loadingSchemas}
|
||||
name="select-schema"
|
||||
notFoundContent={t('No compatible schema found')}
|
||||
placeholder={t('Select schema or type schema name')}
|
||||
onChange={item => changeSchema(item as SchemaValue)}
|
||||
options={schemaOptions}
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ const ChangeDatasourceModal: FunctionComponent<ChangeDatasourceModalProps> = ({
|
|||
);
|
||||
});
|
||||
onHide();
|
||||
addSuccessToast('Successfully changed dataset!');
|
||||
addSuccessToast(t('Successfully changed dataset!'));
|
||||
};
|
||||
|
||||
const handlerCancelConfirm = () => {
|
||||
|
|
|
|||
|
|
@ -491,7 +491,7 @@ ColumnCollectionTable.defaultProps = {
|
|||
allowAddItem: false,
|
||||
allowEditDataType: false,
|
||||
itemGenerator: () => ({
|
||||
column_name: '<new column>',
|
||||
column_name: t('<new column>'),
|
||||
filterable: true,
|
||||
groupby: true,
|
||||
}),
|
||||
|
|
@ -976,8 +976,8 @@ class DatasourceEditor extends React.PureComponent {
|
|||
tableColumns={['name', 'config']}
|
||||
onChange={this.onDatasourcePropChange.bind(this, 'spatials')}
|
||||
itemGenerator={() => ({
|
||||
name: '<new spatial>',
|
||||
type: '<no type>',
|
||||
name: t('<new spatial>'),
|
||||
type: t('<no type>'),
|
||||
config: null,
|
||||
})}
|
||||
collection={spatials}
|
||||
|
|
@ -1256,7 +1256,7 @@ class DatasourceEditor extends React.PureComponent {
|
|||
allowAddItem
|
||||
onChange={this.onDatasourcePropChange.bind(this, 'metrics')}
|
||||
itemGenerator={() => ({
|
||||
metric_name: '<new metric>',
|
||||
metric_name: t('<new metric>'),
|
||||
verbose_name: '',
|
||||
expression: '',
|
||||
})}
|
||||
|
|
@ -1418,10 +1418,10 @@ class DatasourceEditor extends React.PureComponent {
|
|||
allowAddItem
|
||||
allowEditDataType
|
||||
itemGenerator={() => ({
|
||||
column_name: '<new column>',
|
||||
column_name: t('<new column>'),
|
||||
filterable: true,
|
||||
groupby: true,
|
||||
expression: '<enter SQL expression here>',
|
||||
expression: t('<enter SQL expression here>'),
|
||||
__expanded: true,
|
||||
})}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -177,6 +177,8 @@ const DatasourceModal: FunctionComponent<DatasourceModalProps> = ({
|
|||
content: renderSaveDialog(),
|
||||
onOk: onConfirmSave,
|
||||
icon: null,
|
||||
okText: t('OK'),
|
||||
cancelText: t('Cancel'),
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import React, {
|
|||
useImperativeHandle,
|
||||
} from 'react';
|
||||
import moment, { Moment } from 'moment';
|
||||
import { styled } from '@superset-ui/core';
|
||||
import { styled, t } from '@superset-ui/core';
|
||||
import { RangePicker } from 'src/components/DatePicker';
|
||||
import { FormLabel } from 'src/components/Form';
|
||||
import { BaseFilter, FilterHandler } from './Base';
|
||||
|
|
@ -64,6 +64,7 @@ function DateRangeFilter(
|
|||
<RangeFilterContainer>
|
||||
<FormLabel>{Header}</FormLabel>
|
||||
<RangePicker
|
||||
placeholder={[t('Start date'), t('End date')]}
|
||||
showTime
|
||||
value={momentValue}
|
||||
onChange={momentRange => {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { t } from '@superset-ui/core';
|
||||
|
||||
import { BootstrapData, CommonBootstrapData } from './types/bootstrapTypes';
|
||||
|
||||
export const DATETIME_WITH_TIME_ZONE = 'YYYY-MM-DD HH:mm:ssZ';
|
||||
|
|
@ -142,7 +144,7 @@ export const SLOW_DEBOUNCE = 500;
|
|||
/**
|
||||
* Display null as `N/A`
|
||||
*/
|
||||
export const NULL_DISPLAY = 'N/A';
|
||||
export const NULL_DISPLAY = t('N/A');
|
||||
|
||||
export const DEFAULT_COMMON_BOOTSTRAP_DATA: CommonBootstrapData = {
|
||||
flash_messages: [],
|
||||
|
|
|
|||
|
|
@ -652,7 +652,10 @@ export function maxUndoHistoryToast() {
|
|||
|
||||
return dispatch(
|
||||
addWarningToast(
|
||||
`You have used all ${historyLength} undo slots and will not be able to fully undo subsequent actions. You may save your current state to reset the history.`,
|
||||
t(
|
||||
'You have used all %(historyLength)s undo slots and will not be able to fully undo subsequent actions. You may save your current state to reset the history.',
|
||||
{ historyLength },
|
||||
),
|
||||
),
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ class SaveModal extends React.PureComponent<SaveModalProps, SaveModalState> {
|
|||
super(props);
|
||||
this.state = {
|
||||
saveType: props.saveType,
|
||||
newDashName: `${props.dashboardTitle} [copy]`,
|
||||
newDashName: props.dashboardTitle + t('[copy]'),
|
||||
duplicateSlices: false,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
import React from 'react';
|
||||
import cx from 'classnames';
|
||||
import { css, styled } from '@superset-ui/core';
|
||||
import { css, styled, t } from '@superset-ui/core';
|
||||
|
||||
import backgroundStyleOptions from 'src/dashboard/util/backgroundStyleOptions';
|
||||
import PopoverDropdown, {
|
||||
|
|
@ -73,11 +73,12 @@ const BackgroundStyleOption = styled.div`
|
|||
`;
|
||||
|
||||
function renderButton(option: OptionProps) {
|
||||
const BACKGROUND_TEXT = t('background');
|
||||
return (
|
||||
<BackgroundStyleOption
|
||||
className={cx('background-style-option', option.className)}
|
||||
>
|
||||
{`${option.label} background`}
|
||||
{`${option.label} ${BACKGROUND_TEXT}`}
|
||||
</BackgroundStyleOption>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ const DatasetSelect = ({ onChange, value }: DatasetSelectProps) => {
|
|||
value={value}
|
||||
options={loadDatasetOptions}
|
||||
onChange={onChange}
|
||||
notFoundContent={t('No compatible datasets found')}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -944,7 +944,9 @@ const FiltersConfigForm = (
|
|||
<StyledRowFormItem
|
||||
name={['filters', filterId, 'time_range']}
|
||||
label={<StyledLabel>{t('Time range')}</StyledLabel>}
|
||||
initialValue={filterToEdit?.time_range || 'No filter'}
|
||||
initialValue={
|
||||
filterToEdit?.time_range || t('No filter')
|
||||
}
|
||||
required={!hasAdhoc}
|
||||
rules={[
|
||||
{
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ const typeToDefaultMetaData = {
|
|||
},
|
||||
[DIVIDER_TYPE]: null,
|
||||
[HEADER_TYPE]: {
|
||||
text: 'New header',
|
||||
text: t('New header'),
|
||||
headerSize: MEDIUM_HEADER,
|
||||
background: BACKGROUND_TRANSPARENT,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -56,33 +56,39 @@ export interface OperatorType {
|
|||
export const OPERATOR_ENUM_TO_OPERATOR_TYPE: {
|
||||
[key in Operators]: OperatorType;
|
||||
} = {
|
||||
[Operators.EQUALS]: { display: 'Equal to (=)', operation: '==' },
|
||||
[Operators.NOT_EQUALS]: { display: 'Not equal to (≠)', operation: '!=' },
|
||||
[Operators.LESS_THAN]: { display: 'Less than (<)', operation: '<' },
|
||||
[Operators.EQUALS]: { display: t('Equal to (=)'), operation: '==' },
|
||||
[Operators.NOT_EQUALS]: { display: t('Not equal to (≠)'), operation: '!=' },
|
||||
[Operators.LESS_THAN]: { display: t('Less than (<)'), operation: '<' },
|
||||
[Operators.LESS_THAN_OR_EQUAL]: {
|
||||
display: 'Less or equal (<=)',
|
||||
display: t('Less or equal (<=)'),
|
||||
operation: '<=',
|
||||
},
|
||||
[Operators.GREATER_THAN]: { display: 'Greater than (>)', operation: '>' },
|
||||
[Operators.GREATER_THAN]: { display: t('Greater than (>)'), operation: '>' },
|
||||
[Operators.GREATER_THAN_OR_EQUAL]: {
|
||||
display: 'Greater or equal (>=)',
|
||||
display: t('Greater or equal (>=)'),
|
||||
operation: '>=',
|
||||
},
|
||||
[Operators.IN]: { display: 'In', operation: 'IN' },
|
||||
[Operators.NOT_IN]: { display: 'Not in', operation: 'NOT IN' },
|
||||
[Operators.LIKE]: { display: 'Like', operation: 'LIKE' },
|
||||
[Operators.ILIKE]: { display: 'Like (case insensitive)', operation: 'ILIKE' },
|
||||
[Operators.REGEX]: { display: 'Regex', operation: 'REGEX' },
|
||||
[Operators.IS_NOT_NULL]: { display: 'Is not null', operation: 'IS NOT NULL' },
|
||||
[Operators.IS_NULL]: { display: 'Is null', operation: 'IS NULL' },
|
||||
[Operators.IN]: { display: t('In'), operation: 'IN' },
|
||||
[Operators.NOT_IN]: { display: t('Not in'), operation: 'NOT IN' },
|
||||
[Operators.LIKE]: { display: t('Like'), operation: 'LIKE' },
|
||||
[Operators.ILIKE]: {
|
||||
display: t('Like (case insensitive)'),
|
||||
operation: 'ILIKE',
|
||||
},
|
||||
[Operators.REGEX]: { display: t('Regex'), operation: 'REGEX' },
|
||||
[Operators.IS_NOT_NULL]: {
|
||||
display: t('Is not null'),
|
||||
operation: 'IS NOT NULL',
|
||||
},
|
||||
[Operators.IS_NULL]: { display: t('Is null'), operation: 'IS NULL' },
|
||||
[Operators.LATEST_PARTITION]: {
|
||||
display: 'use latest_partition template',
|
||||
display: t('use latest_partition template'),
|
||||
operation: 'LATEST PARTITION',
|
||||
},
|
||||
[Operators.IS_TRUE]: { display: 'Is true', operation: '==' },
|
||||
[Operators.IS_FALSE]: { display: 'Is false', operation: '==' },
|
||||
[Operators.IS_TRUE]: { display: t('Is true'), operation: '==' },
|
||||
[Operators.IS_FALSE]: { display: t('Is false'), operation: '==' },
|
||||
[Operators.TEMPORAL_RANGE]: {
|
||||
display: 'TEMPORAL_RANGE',
|
||||
display: t('TEMPORAL_RANGE'),
|
||||
operation: 'TEMPORAL_RANGE',
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
import React from 'react';
|
||||
import moment from 'moment';
|
||||
import { t } from '@superset-ui/core';
|
||||
import rison from 'rison';
|
||||
|
||||
import TableLoader from '../../components/TableLoader';
|
||||
|
|
@ -48,6 +49,7 @@ export default function RecentActivity({ user }: RecentActivityProps) {
|
|||
mutator={mutator}
|
||||
sortable
|
||||
dataEndpoint={`/api/v1/log/recent_activity/${user?.userId}/?q=${params}`}
|
||||
noDataText={t('No Data')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -19,8 +19,11 @@
|
|||
|
||||
import { t } from '@superset-ui/core';
|
||||
|
||||
const CREATE_CHART_TEXT = t('Create chart');
|
||||
const UPDATE_CHART_TEXT = t('Update chart');
|
||||
|
||||
export const getChartRequiredFieldsMissingMessage = (isCreating: boolean) =>
|
||||
t(
|
||||
'Select values in highlighted field(s) in the control panel. Then run the query by clicking on the %s button.',
|
||||
isCreating ? '"Create chart"' : '"Update chart"',
|
||||
`"${isCreating ? CREATE_CHART_TEXT : UPDATE_CHART_TEXT}"`,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -455,7 +455,7 @@ function AlertList({
|
|||
id: 'owners',
|
||||
input: 'select',
|
||||
operator: FilterOperator.relationManyMany,
|
||||
unfilteredLabel: 'All',
|
||||
unfilteredLabel: t('All'),
|
||||
fetchSelects: createFetchRelated(
|
||||
'report',
|
||||
'owners',
|
||||
|
|
|
|||
|
|
@ -571,7 +571,7 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
|
|||
const shouldEnableForceScreenshot = contentType === 'chart' && !isReport;
|
||||
const data: any = {
|
||||
...currentAlert,
|
||||
type: isReport ? 'Report' : 'Alert',
|
||||
type: isReport ? t('Report') : t('Alert'),
|
||||
force_screenshot: shouldEnableForceScreenshot || forceScreenshot,
|
||||
validator_type: conditionNotNull ? 'not null' : 'operator',
|
||||
validator_config_json: conditionNotNull
|
||||
|
|
|
|||
|
|
@ -159,13 +159,23 @@ function ExecutionLog({ addDangerToast, isReportEnabled }: ExecutionLogProps) {
|
|||
[isReportEnabled],
|
||||
);
|
||||
const path = `/${isReportEnabled ? 'report' : 'alert'}/list/`;
|
||||
const ALERT_TEXT = t('Alert');
|
||||
const REPORT_TEXT = t('Report');
|
||||
|
||||
return (
|
||||
<>
|
||||
<SubMenu
|
||||
name={
|
||||
<StyledHeader>
|
||||
<span>
|
||||
{alertResource?.type} {alertResource?.name}
|
||||
{alertResource
|
||||
? alertResource.type === 'Alert'
|
||||
? `${ALERT_TEXT}:`
|
||||
: alertResource.type === 'Report'
|
||||
? `${REPORT_TEXT}:`
|
||||
: null
|
||||
: null}{' '}
|
||||
{alertResource?.name}
|
||||
</span>
|
||||
<span>
|
||||
<Link to={path}>{t('Back to all')}</Link>
|
||||
|
|
|
|||
|
|
@ -304,6 +304,7 @@ const AnnotationModal: FunctionComponent<AnnotationModalProps> = ({
|
|||
<span className="required">*</span>
|
||||
</div>
|
||||
<RangePicker
|
||||
placeholder={[t('Start date'), t('End date')]}
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
onChange={onDateChange}
|
||||
showTime={{ format: 'hh:mm a' }}
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ function AnnotationLayersList({
|
|||
id: 'created_by',
|
||||
input: 'select',
|
||||
operator: FilterOperator.relationOneMany,
|
||||
unfilteredLabel: 'All',
|
||||
unfilteredLabel: t('All'),
|
||||
fetchSelects: createFetchRelated(
|
||||
'annotation_layer',
|
||||
'created_by',
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ function CssTemplatesList({
|
|||
id: 'created_by',
|
||||
input: 'select',
|
||||
operator: FilterOperator.relationOneMany,
|
||||
unfilteredLabel: 'All',
|
||||
unfilteredLabel: t('All'),
|
||||
fetchSelects: createFetchRelated(
|
||||
'css_template',
|
||||
'created_by',
|
||||
|
|
|
|||
|
|
@ -117,7 +117,9 @@ export const EncryptedField = ({
|
|||
name={encryptedField}
|
||||
value={encryptedValue}
|
||||
onChange={changeMethods.onParametersChange}
|
||||
placeholder="Paste content of service credentials JSON file here"
|
||||
placeholder={t(
|
||||
'Paste content of service credentials JSON file here',
|
||||
)}
|
||||
/>
|
||||
<span className="label-paste">
|
||||
{t('Copy and paste the entire service account .json file here')}
|
||||
|
|
|
|||
|
|
@ -26,14 +26,14 @@ const FIELD_TEXT_MAP = {
|
|||
helpText: t(
|
||||
'Copy the account name of that database you are trying to connect to.',
|
||||
),
|
||||
placeholder: 'e.g. world_population',
|
||||
placeholder: t('e.g. world_population'),
|
||||
},
|
||||
warehouse: {
|
||||
placeholder: 'e.g. compute_wh',
|
||||
placeholder: t('e.g. compute_wh'),
|
||||
className: 'form-group-w-50',
|
||||
},
|
||||
role: {
|
||||
placeholder: 'e.g. AccountAdmin',
|
||||
placeholder: t('e.g. AccountAdmin'),
|
||||
className: 'form-group-w-50',
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -193,11 +193,11 @@ const SSHTunnelForm = ({
|
|||
data-test="ssh-tunnel-password-input"
|
||||
iconRender={visible =>
|
||||
visible ? (
|
||||
<Tooltip title="Hide password.">
|
||||
<Tooltip title={t('Hide password.')}>
|
||||
<EyeInvisibleOutlined />
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Tooltip title="Show password.">
|
||||
<Tooltip title={t('Show password.')}>
|
||||
<EyeOutlined />
|
||||
</Tooltip>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1216,7 +1216,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
|
|||
required
|
||||
validationMethods={{ onBlur: () => {} }}
|
||||
errorMessage={validationErrors?.confirm_overwrite}
|
||||
label={t(`TYPE "OVERWRITE" TO CONFIRM`)}
|
||||
label={t('Type "%s" to confirm', t('OVERWRITE'))}
|
||||
onChange={confirmOverwrite}
|
||||
css={formScrollableStyles}
|
||||
/>
|
||||
|
|
@ -1615,7 +1615,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
|
|||
<Alert
|
||||
closable={false}
|
||||
css={(theme: SupersetTheme) => antDAlertStyles(theme)}
|
||||
message="Additional fields may be required"
|
||||
message={t('Additional fields may be required')}
|
||||
showIcon
|
||||
description={
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -351,7 +351,7 @@ function QueryList({ addDangerToast }: QueryListProps) {
|
|||
id: 'database',
|
||||
input: 'select',
|
||||
operator: FilterOperator.relationOneMany,
|
||||
unfilteredLabel: 'All',
|
||||
unfilteredLabel: t('All'),
|
||||
fetchSelects: createFetchRelated(
|
||||
'query',
|
||||
'database',
|
||||
|
|
|
|||
|
|
@ -427,7 +427,7 @@ function SavedQueryList({
|
|||
id: 'database',
|
||||
input: 'select',
|
||||
operator: FilterOperator.relationOneMany,
|
||||
unfilteredLabel: 'All',
|
||||
unfilteredLabel: t('All'),
|
||||
fetchSelects: createFetchRelated(
|
||||
'saved_query',
|
||||
'database',
|
||||
|
|
|
|||
|
|
@ -420,6 +420,10 @@ export function useImportResource(
|
|||
const formData = new FormData();
|
||||
formData.append('formData', bundle);
|
||||
|
||||
const RE_EXPORT_TEXT = t(
|
||||
'Please re-export your file and try importing again',
|
||||
);
|
||||
|
||||
/* The import bundle never contains database passwords; if required
|
||||
* they should be provided by the user during import.
|
||||
*/
|
||||
|
|
@ -468,7 +472,7 @@ export function useImportResource(
|
|||
resourceLabel,
|
||||
[
|
||||
...error.errors.map(payload => payload.message),
|
||||
t('Please re-export your file and try importing again.'),
|
||||
RE_EXPORT_TEXT,
|
||||
].join('.\n'),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,13 @@ const welcomeTableLabels: Record<WelcomeTable, string> = {
|
|||
[WelcomeTable.SavedQueries]: t('saved queries'),
|
||||
};
|
||||
|
||||
const welcomeTableEmpty: Record<WelcomeTable, string> = {
|
||||
[WelcomeTable.Charts]: t('No charts yet'),
|
||||
[WelcomeTable.Dashboards]: t('No dashboards yet'),
|
||||
[WelcomeTable.Recents]: t('No recents yet'),
|
||||
[WelcomeTable.SavedQueries]: t('No saved queries yet'),
|
||||
};
|
||||
|
||||
export interface EmptyStateProps {
|
||||
tableName: WelcomeTable;
|
||||
tab?: string;
|
||||
|
|
@ -75,11 +82,7 @@ export default function EmptyState({
|
|||
[WelcomeTable.Recents]: 'union.svg',
|
||||
[WelcomeTable.SavedQueries]: 'empty-queries.svg',
|
||||
};
|
||||
const mine = (
|
||||
<span>
|
||||
{t('No %(tableName)s yet', { tableName: welcomeTableLabels[tableName] })}
|
||||
</span>
|
||||
);
|
||||
const mine = <span>{welcomeTableEmpty[tableName]}</span>;
|
||||
const recent = (
|
||||
<span className="no-recents">
|
||||
{(() => {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ from io import StringIO
|
|||
from typing import Any, Dict, List, Optional, Tuple, TYPE_CHECKING
|
||||
|
||||
import pandas as pd
|
||||
from flask_babel import gettext as __
|
||||
|
||||
from superset.common.chart_data import ChartDataResultFormat
|
||||
from superset.utils.core import (
|
||||
|
|
@ -68,7 +69,7 @@ def pivot_df( # pylint: disable=too-many-locals, too-many-arguments, too-many-s
|
|||
show_columns_total: bool = False,
|
||||
apply_metrics_on_rows: bool = False,
|
||||
) -> pd.DataFrame:
|
||||
metric_name = f"Total ({aggfunc})"
|
||||
metric_name = __("Total (%(aggfunc)s)", aggfunc=aggfunc)
|
||||
|
||||
if transpose_pivot:
|
||||
rows, columns = columns, rows
|
||||
|
|
@ -156,7 +157,7 @@ def pivot_df( # pylint: disable=too-many-locals, too-many-arguments, too-many-s
|
|||
slice_ = df.columns.get_loc(subgroup)
|
||||
subtotal = pivot_v2_aggfunc_map[aggfunc](df.iloc[:, slice_], axis=1)
|
||||
depth = df.columns.nlevels - len(subgroup) - 1
|
||||
total = metric_name if level == 0 else "Subtotal"
|
||||
total = metric_name if level == 0 else __("Subtotal")
|
||||
subtotal_name = tuple([*subgroup, total, *([""] * depth)])
|
||||
# insert column after subgroup
|
||||
df.insert(int(slice_.stop), subtotal_name, subtotal)
|
||||
|
|
@ -173,7 +174,7 @@ def pivot_df( # pylint: disable=too-many-locals, too-many-arguments, too-many-s
|
|||
df.iloc[slice_, :].apply(pd.to_numeric), axis=0
|
||||
)
|
||||
depth = df.index.nlevels - len(subgroup) - 1
|
||||
total = metric_name if level == 0 else "Subtotal"
|
||||
total = metric_name if level == 0 else __("Subtotal")
|
||||
subtotal.name = tuple([*subgroup, total, *([""] * depth)])
|
||||
# insert row after subgroup
|
||||
df = pd.concat(
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ from enum import Enum
|
|||
from typing import Any, Dict, Hashable, List, Optional, Set, Type, TYPE_CHECKING, Union
|
||||
|
||||
from flask_appbuilder.security.sqla.models import User
|
||||
from flask_babel import gettext as __
|
||||
from sqlalchemy import and_, Boolean, Column, Integer, String, Text
|
||||
from sqlalchemy.ext.declarative import declared_attr
|
||||
from sqlalchemy.orm import foreign, Query, relationship, RelationshipProperty, Session
|
||||
|
|
@ -248,10 +249,10 @@ class BaseDatasource(
|
|||
for column_name in self.column_names:
|
||||
column_name = str(column_name or "")
|
||||
order_by_choices.append(
|
||||
(json.dumps([column_name, True]), column_name + " [asc]")
|
||||
(json.dumps([column_name, True]), f"{column_name} " + __("[asc]"))
|
||||
)
|
||||
order_by_choices.append(
|
||||
(json.dumps([column_name, False]), column_name + " [desc]")
|
||||
(json.dumps([column_name, False]), f"{column_name} " + __("[desc]"))
|
||||
)
|
||||
|
||||
verbose_map = {"__timestamp": "Time"}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ cache_timeout_description = (
|
|||
)
|
||||
expose_in_sqllab_description = "Expose this database to SQLLab"
|
||||
allow_run_async_description = (
|
||||
"Operate the database in asynchronous mode, meaning "
|
||||
"Operate the database in asynchronous mode, meaning "
|
||||
"that the queries are executed on remote workers as opposed "
|
||||
"to on the web server itself. "
|
||||
"This assumes that you have a Celery worker setup as well "
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@ class SupersetAppInitializer: # pylint: disable=too-many-public-methods
|
|||
)
|
||||
appbuilder.add_link(
|
||||
"SQL Editor",
|
||||
label=_("SQL Lab"),
|
||||
label=__("SQL Lab"),
|
||||
href="/superset/sqllab/",
|
||||
category_icon="fa-flask",
|
||||
icon="fa-flask",
|
||||
|
|
@ -349,7 +349,8 @@ class SupersetAppInitializer: # pylint: disable=too-many-public-methods
|
|||
category_label=__("SQL"),
|
||||
)
|
||||
appbuilder.add_link(
|
||||
__("Saved Queries"),
|
||||
"Saved Queries",
|
||||
label=__("Saved Queries"),
|
||||
href="/savedqueryview/list/",
|
||||
icon="fa-save",
|
||||
category="SQL Lab",
|
||||
|
|
@ -357,7 +358,7 @@ class SupersetAppInitializer: # pylint: disable=too-many-public-methods
|
|||
)
|
||||
appbuilder.add_link(
|
||||
"Query Search",
|
||||
label=_("Query History"),
|
||||
label=__("Query History"),
|
||||
href="/superset/sqllab/history/",
|
||||
icon="fa-search",
|
||||
category_icon="fa-flask",
|
||||
|
|
@ -396,7 +397,7 @@ class SupersetAppInitializer: # pylint: disable=too-many-public-methods
|
|||
appbuilder.add_view(
|
||||
AnnotationLayerView,
|
||||
"Annotation Layers",
|
||||
label=_("Annotation Layers"),
|
||||
label=__("Annotation Layers"),
|
||||
href="/annotationlayer/list/",
|
||||
icon="fa-comment",
|
||||
category_icon="",
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import sqlalchemy as sqla
|
|||
from flask import current_app, Markup
|
||||
from flask_appbuilder import Model
|
||||
from flask_appbuilder.models.decorators import renders
|
||||
from flask_babel import gettext as __
|
||||
from humanize import naturaltime
|
||||
from sqlalchemy import (
|
||||
Boolean,
|
||||
|
|
@ -224,10 +225,10 @@ class Query(
|
|||
for col in self.columns:
|
||||
column_name = str(col.get("column_name") or "")
|
||||
order_by_choices.append(
|
||||
(json.dumps([column_name, True]), column_name + " [asc]")
|
||||
(json.dumps([column_name, True]), f"{column_name} " + __("[asc]"))
|
||||
)
|
||||
order_by_choices.append(
|
||||
(json.dumps([column_name, False]), column_name + " [desc]")
|
||||
(json.dumps([column_name, False]), f"{column_name} " + __("[desc]"))
|
||||
)
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -485,7 +485,11 @@ def execute_sql_statements( # pylint: disable=too-many-arguments, too-many-loca
|
|||
or (query.ctas_method == CtasMethod.TABLE and i == len(statements) - 1)
|
||||
)
|
||||
# Run statement
|
||||
msg = f"Running statement {i+1} out of {statement_count}"
|
||||
msg = __(
|
||||
"Running statement %(statement_num)s out of %(statement_count)s",
|
||||
statement_num=i + 1,
|
||||
statement_count=statement_count,
|
||||
)
|
||||
logger.info("Query %s: %s", str(query_id), msg)
|
||||
query.set_extra_json_key("progress", msg)
|
||||
session.commit()
|
||||
|
|
@ -504,7 +508,11 @@ def execute_sql_statements( # pylint: disable=too-many-arguments, too-many-loca
|
|||
except Exception as ex: # pylint: disable=broad-except
|
||||
msg = str(ex)
|
||||
prefix_message = (
|
||||
f"[Statement {i+1} out of {statement_count}]"
|
||||
__(
|
||||
"Statement %(statement_num)s out of %(statement_count)s",
|
||||
statement_num=i + 1,
|
||||
statement_count=statement_count,
|
||||
)
|
||||
if statement_count > 1
|
||||
else ""
|
||||
)
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@ from __future__ import annotations
|
|||
import os
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
|
||||
from flask_babel import lazy_gettext as _
|
||||
|
||||
from superset.errors import SupersetError, SupersetErrorType
|
||||
from superset.exceptions import SupersetException
|
||||
|
||||
MSG_FORMAT = "Failed to execute {}"
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from superset.sqllab.sqllab_execution_context import SqlJsonExecutionContext
|
||||
|
||||
|
|
@ -61,7 +61,10 @@ class SqlLabException(SupersetException):
|
|||
super().__init__(self._generate_message(), exception, error_type)
|
||||
|
||||
def _generate_message(self) -> str:
|
||||
msg = MSG_FORMAT.format(self.sql_json_execution_context.get_query_details())
|
||||
msg = _(
|
||||
"Failed to execute %(query)s",
|
||||
query=self.sql_json_execution_context.get_query_details(),
|
||||
)
|
||||
if self.failed_reason_msg:
|
||||
msg = msg + self.failed_reason_msg
|
||||
if self.suggestion_help_msg is not None:
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ def get_since_until( # pylint: disable=too-many-arguments,too-many-locals,too-m
|
|||
_relative_start = relative_start if relative_start else "today"
|
||||
_relative_end = relative_end if relative_end else "today"
|
||||
|
||||
if time_range == NO_TIME_RANGE:
|
||||
if time_range == NO_TIME_RANGE or time_range == _(NO_TIME_RANGE):
|
||||
return None, None
|
||||
|
||||
if time_range and time_range.startswith("Last") and separator not in time_range:
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ from abc import ABC, abstractmethod
|
|||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from flask import Flask
|
||||
from flask_babel import lazy_gettext as _
|
||||
from sqlalchemy import text, TypeDecorator
|
||||
from sqlalchemy.engine import Connection, Dialect, Row
|
||||
from sqlalchemy_utils import EncryptedType
|
||||
|
|
@ -109,7 +110,13 @@ class SecretsMigrator:
|
|||
return bytes(value.encode("utf8"))
|
||||
|
||||
# Just bail if we haven't seen this type before...
|
||||
raise ValueError(f"DB column {col_name} has unknown type: {type(value)}")
|
||||
raise ValueError(
|
||||
_(
|
||||
"DB column %(col_name)s has unknown type: %(value_type)s",
|
||||
col_name=col_name,
|
||||
value_type=type(value),
|
||||
)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _select_columns_from_table(
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ from flask import request
|
|||
from flask_appbuilder import expose
|
||||
from flask_appbuilder.api import rison
|
||||
from flask_appbuilder.security.decorators import has_access_api
|
||||
from flask_babel import lazy_gettext as _
|
||||
|
||||
from superset import db, event_logger
|
||||
from superset.charts.commands.exceptions import (
|
||||
|
|
@ -105,7 +106,7 @@ class Api(BaseSupersetView):
|
|||
}
|
||||
return self.json_response({"result": result})
|
||||
except (ValueError, TimeRangeParseFailError, TimeRangeAmbiguousError) as error:
|
||||
error_msg = {"message": f"Unexpected time range: {error}"}
|
||||
error_msg = {"message": _("Unexpected time range: %s" % error)}
|
||||
return self.json_response(error_msg, 400)
|
||||
|
||||
def get_query_context_factory(self) -> QueryContextFactory:
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ class DashboardMixin: # pylint: disable=too-few-public-methods
|
|||
"roles": _(
|
||||
"Roles is a list which defines access to the dashboard. "
|
||||
"Granting a role access to a dashboard will bypass dataset level checks."
|
||||
"If no roles defined then the dashboard is available to all roles."
|
||||
"If no roles are defined then the dashboard is available to all roles."
|
||||
),
|
||||
"published": _(
|
||||
"Determines whether or not this dashboard is "
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ from flask import flash, g, redirect
|
|||
from flask_appbuilder import expose, SimpleFormView
|
||||
from flask_appbuilder.models.sqla.interface import SQLAInterface
|
||||
from flask_appbuilder.security.decorators import has_access
|
||||
from flask_babel import gettext as __, lazy_gettext as _
|
||||
from flask_babel import lazy_gettext as _
|
||||
from werkzeug.wrappers import Response
|
||||
from wtforms.fields import StringField
|
||||
from wtforms.validators import ValidationError
|
||||
|
|
@ -176,7 +176,7 @@ class CsvToDatabaseView(CustomFormView):
|
|||
delimiter_input = form.delimiter.data
|
||||
|
||||
if not schema_allows_file_upload(database, csv_table.schema):
|
||||
message = __(
|
||||
message = _(
|
||||
'Database "%(database_name)s" schema "%(schema_name)s" '
|
||||
"is not allowed for csv uploads. Please contact your Superset Admin.",
|
||||
database_name=database.database_name,
|
||||
|
|
@ -265,7 +265,7 @@ class CsvToDatabaseView(CustomFormView):
|
|||
db.session.commit()
|
||||
except Exception as ex: # pylint: disable=broad-except
|
||||
db.session.rollback()
|
||||
message = __(
|
||||
message = _(
|
||||
'Unable to upload CSV file "%(filename)s" to table '
|
||||
'"%(table_name)s" in database "%(db_name)s". '
|
||||
"Error message: %(error_msg)s",
|
||||
|
|
@ -280,7 +280,7 @@ class CsvToDatabaseView(CustomFormView):
|
|||
return redirect("/csvtodatabaseview/form")
|
||||
|
||||
# Go back to welcome page / splash screen
|
||||
message = __(
|
||||
message = _(
|
||||
'CSV file "%(csv_filename)s" uploaded to table "%(table_name)s" in '
|
||||
'database "%(db_name)s"',
|
||||
csv_filename=form.csv_file.data.filename,
|
||||
|
|
@ -315,7 +315,7 @@ class ExcelToDatabaseView(SimpleFormView):
|
|||
excel_table = Table(table=form.name.data, schema=form.schema.data)
|
||||
|
||||
if not schema_allows_file_upload(database, excel_table.schema):
|
||||
message = __(
|
||||
message = _(
|
||||
'Database "%(database_name)s" schema "%(schema_name)s" '
|
||||
"is not allowed for excel uploads. Please contact your Superset Admin.",
|
||||
database_name=database.database_name,
|
||||
|
|
@ -402,7 +402,7 @@ class ExcelToDatabaseView(SimpleFormView):
|
|||
db.session.commit()
|
||||
except Exception as ex: # pylint: disable=broad-except
|
||||
db.session.rollback()
|
||||
message = __(
|
||||
message = _(
|
||||
'Unable to upload Excel file "%(filename)s" to table '
|
||||
'"%(table_name)s" in database "%(db_name)s". '
|
||||
"Error message: %(error_msg)s",
|
||||
|
|
@ -417,7 +417,7 @@ class ExcelToDatabaseView(SimpleFormView):
|
|||
return redirect("/exceltodatabaseview/form")
|
||||
|
||||
# Go back to welcome page / splash screen
|
||||
message = __(
|
||||
message = _(
|
||||
'Excel file "%(excel_filename)s" uploaded to table "%(table_name)s" in '
|
||||
'database "%(db_name)s"',
|
||||
excel_filename=form.excel_file.data.filename,
|
||||
|
|
@ -462,7 +462,7 @@ class ColumnarToDatabaseView(SimpleFormView):
|
|||
]
|
||||
|
||||
if len(file_type) > 1:
|
||||
message = __(
|
||||
message = _(
|
||||
"Multiple file extensions are not allowed for columnar uploads."
|
||||
" Please make sure all files are of the same extension.",
|
||||
)
|
||||
|
|
@ -475,7 +475,7 @@ class ColumnarToDatabaseView(SimpleFormView):
|
|||
}
|
||||
|
||||
if not schema_allows_file_upload(database, columnar_table.schema):
|
||||
message = __(
|
||||
message = _(
|
||||
'Database "%(database_name)s" schema "%(schema_name)s" '
|
||||
"is not allowed for columnar uploads. "
|
||||
"Please contact your Superset Admin.",
|
||||
|
|
@ -543,7 +543,7 @@ class ColumnarToDatabaseView(SimpleFormView):
|
|||
db.session.commit()
|
||||
except Exception as ex: # pylint: disable=broad-except
|
||||
db.session.rollback()
|
||||
message = __(
|
||||
message = _(
|
||||
'Unable to upload Columnar file "%(filename)s" to table '
|
||||
'"%(table_name)s" in database "%(db_name)s". '
|
||||
"Error message: %(error_msg)s",
|
||||
|
|
@ -558,7 +558,7 @@ class ColumnarToDatabaseView(SimpleFormView):
|
|||
return redirect("/columnartodatabaseview/form")
|
||||
|
||||
# Go back to welcome page / splash screen
|
||||
message = __(
|
||||
message = _(
|
||||
'Columnar file "%(columnar_filename)s" uploaded to table "%(table_name)s" '
|
||||
'in database "%(db_name)s"',
|
||||
columnar_filename=[file.filename for file in form.columnar_file.data],
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ class TabStateView(BaseSupersetView):
|
|||
user_id=get_user_id(),
|
||||
# This is for backward compatibility
|
||||
label=query_editor.get("name")
|
||||
or query_editor.get("title", "Untitled Query"),
|
||||
or query_editor.get("title", _("Untitled Query")),
|
||||
active=True,
|
||||
database_id=query_editor["dbId"],
|
||||
schema=query_editor.get("schema"),
|
||||
|
|
|
|||
|
|
@ -3224,7 +3224,7 @@ class PartitionViz(NVD3TimeSeriesViz):
|
|||
groups = get_column_names(self.form_data.get("groupby"))
|
||||
time_op = self.form_data.get("time_series_option", "not_time")
|
||||
if not groups:
|
||||
raise ValueError("Please choose at least one groupby")
|
||||
raise ValueError(_("Please choose at least one groupby"))
|
||||
if time_op == "not_time":
|
||||
levels = self.levels_for("agg_sum", groups, df)
|
||||
elif time_op in ["agg_sum", "agg_mean"]:
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
import json
|
||||
|
||||
import pandas as pd
|
||||
from flask_babel import lazy_gettext as _
|
||||
from numpy import True_
|
||||
from pytest import raises
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
|
@ -57,10 +58,10 @@ def test_pivot_df_no_cols_no_rows_single_metric():
|
|||
)
|
||||
assert (
|
||||
pivoted.to_markdown()
|
||||
== """
|
||||
== f"""
|
||||
| | ('SUM(num)',) |
|
||||
|:-----------------|----------------:|
|
||||
| ('Total (Sum)',) | 8.06797e+07 |
|
||||
| ('{_("Total")} (Sum)',) | 8.06797e+07 |
|
||||
""".strip()
|
||||
)
|
||||
|
||||
|
|
@ -79,10 +80,10 @@ def test_pivot_df_no_cols_no_rows_single_metric():
|
|||
)
|
||||
assert (
|
||||
pivoted.to_markdown()
|
||||
== """
|
||||
== f"""
|
||||
| | ('SUM(num)',) |
|
||||
|:-----------------|----------------:|
|
||||
| ('Total (Sum)',) | 8.06797e+07 |
|
||||
| ('{_("Total")} (Sum)',) | 8.06797e+07 |
|
||||
""".strip()
|
||||
)
|
||||
|
||||
|
|
@ -102,8 +103,8 @@ def test_pivot_df_no_cols_no_rows_single_metric():
|
|||
)
|
||||
assert (
|
||||
pivoted.to_markdown()
|
||||
== """
|
||||
| | ('Total (Sum)',) |
|
||||
== f"""
|
||||
| | ('{_("Total")} (Sum)',) |
|
||||
|:--------------|-------------------:|
|
||||
| ('SUM(num)',) | 8.06797e+07 |
|
||||
""".strip()
|
||||
|
|
@ -124,10 +125,10 @@ def test_pivot_df_no_cols_no_rows_single_metric():
|
|||
)
|
||||
assert (
|
||||
pivoted.to_markdown()
|
||||
== """
|
||||
== f"""
|
||||
| | ('SUM(num)',) | ('Total (Sum)',) |
|
||||
|:-----------------|----------------:|-------------------:|
|
||||
| ('Total (Sum)',) | 8.06797e+07 | 8.06797e+07 |
|
||||
| ('{_("Total")} (Sum)',) | 8.06797e+07 | 8.06797e+07 |
|
||||
""".strip()
|
||||
)
|
||||
|
||||
|
|
@ -162,10 +163,10 @@ def test_pivot_df_no_cols_no_rows_two_metrics():
|
|||
)
|
||||
assert (
|
||||
pivoted.to_markdown()
|
||||
== """
|
||||
== f"""
|
||||
| | ('SUM(num)',) | ('MAX(num)',) |
|
||||
|:-----------------|----------------:|----------------:|
|
||||
| ('Total (Sum)',) | 8.06797e+07 | 37296 |
|
||||
| ('{_("Total")} (Sum)',) | 8.06797e+07 | 37296 |
|
||||
""".strip()
|
||||
)
|
||||
|
||||
|
|
@ -207,8 +208,8 @@ def test_pivot_df_no_cols_no_rows_two_metrics():
|
|||
)
|
||||
assert (
|
||||
pivoted.to_markdown()
|
||||
== """
|
||||
| | ('Total (Sum)',) |
|
||||
== f"""
|
||||
| | ('{_("Total")} (Sum)',) |
|
||||
|:--------------|-------------------:|
|
||||
| ('SUM(num)',) | 8.06797e+07 |
|
||||
| ('MAX(num)',) | 37296 |
|
||||
|
|
@ -231,10 +232,10 @@ def test_pivot_df_no_cols_no_rows_two_metrics():
|
|||
)
|
||||
assert (
|
||||
pivoted.to_markdown()
|
||||
== """
|
||||
| | ('SUM(num)',) | ('MAX(num)',) | ('Total (Sum)',) |
|
||||
== f"""
|
||||
| | ('SUM(num)',) | ('MAX(num)',) | ('{_("Total")} (Sum)',) |
|
||||
|:-----------------|----------------:|----------------:|-------------------:|
|
||||
| ('Total (Sum)',) | 8.06797e+07 | 37296 | 8.0717e+07 |
|
||||
| ('{_("Total")} (Sum)',) | 8.06797e+07 | 37296 | 8.0717e+07 |
|
||||
""".strip()
|
||||
)
|
||||
|
||||
|
|
@ -297,10 +298,10 @@ def test_pivot_df_single_row_two_metrics():
|
|||
)
|
||||
assert (
|
||||
pivoted.to_markdown()
|
||||
== """
|
||||
== f"""
|
||||
| | ('SUM(num)', 'boy') | ('SUM(num)', 'girl') | ('MAX(num)', 'boy') | ('MAX(num)', 'girl') |
|
||||
|:-----------------|----------------------:|-----------------------:|----------------------:|-----------------------:|
|
||||
| ('Total (Sum)',) | 47123 | 118065 | 1280 | 2588 |
|
||||
| ('{_("Total")} (Sum)',) | 47123 | 118065 | 1280 | 2588 |
|
||||
""".strip()
|
||||
)
|
||||
|
||||
|
|
@ -342,12 +343,12 @@ def test_pivot_df_single_row_two_metrics():
|
|||
)
|
||||
assert (
|
||||
pivoted.to_markdown()
|
||||
== """
|
||||
| | ('SUM(num)',) | ('MAX(num)',) | ('Total (Sum)',) |
|
||||
== f"""
|
||||
| | ('SUM(num)',) | ('MAX(num)',) | ('{_("Total")} (Sum)',) |
|
||||
|:-----------------|----------------:|----------------:|-------------------:|
|
||||
| ('boy',) | 47123 | 1280 | 48403 |
|
||||
| ('girl',) | 118065 | 2588 | 120653 |
|
||||
| ('Total (Sum)',) | 165188 | 3868 | 169056 |
|
||||
| ('{_("Total")} (Sum)',) | 165188 | 3868 | 169056 |
|
||||
""".strip()
|
||||
)
|
||||
|
||||
|
|
@ -366,8 +367,8 @@ def test_pivot_df_single_row_two_metrics():
|
|||
)
|
||||
assert (
|
||||
pivoted.to_markdown()
|
||||
== """
|
||||
| | ('Total (Sum)',) |
|
||||
== f"""
|
||||
| | ('{_("Total")} (Sum)',) |
|
||||
|:-------------------------|-------------------:|
|
||||
| ('SUM(num)', 'boy') | 47123 |
|
||||
| ('SUM(num)', 'girl') | 118065 |
|
||||
|
|
@ -375,7 +376,7 @@ def test_pivot_df_single_row_two_metrics():
|
|||
| ('MAX(num)', 'boy') | 1280 |
|
||||
| ('MAX(num)', 'girl') | 2588 |
|
||||
| ('MAX(num)', 'Subtotal') | 3868 |
|
||||
| ('Total (Sum)', '') | 169056 |
|
||||
| ('{_("Total")} (Sum)', '') | 169056 |
|
||||
""".strip()
|
||||
)
|
||||
|
||||
|
|
@ -394,8 +395,8 @@ def test_pivot_df_single_row_two_metrics():
|
|||
)
|
||||
assert (
|
||||
pivoted.to_markdown()
|
||||
== """
|
||||
| | ('Total (Sum)',) |
|
||||
== f"""
|
||||
| | ('{_("Total")} (Sum)',) |
|
||||
|:---------------------|-------------------:|
|
||||
| ('boy', 'SUM(num)') | 47123 |
|
||||
| ('boy', 'MAX(num)') | 1280 |
|
||||
|
|
@ -403,7 +404,7 @@ def test_pivot_df_single_row_two_metrics():
|
|||
| ('girl', 'SUM(num)') | 118065 |
|
||||
| ('girl', 'MAX(num)') | 2588 |
|
||||
| ('girl', 'Subtotal') | 120653 |
|
||||
| ('Total (Sum)', '') | 169056 |
|
||||
| ('{_("Total")} (Sum)', '') | 169056 |
|
||||
""".strip()
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue