feat(ui): localization for utils and models (#9265)

This commit is contained in:
Chirag Madlani 2022-12-14 11:52:48 +05:30 committed by GitHub
parent 0eb49c6100
commit 0c7bf13901
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 220 additions and 105 deletions

View File

@ -15,16 +15,14 @@ import { Form, Input, Modal, Space } from 'antd';
import { AxiosError } from 'axios';
import { observer } from 'mobx-react';
import React, { FC, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import AppState from '../../../AppState';
import { postThread } from '../../../axiosAPIs/feedsAPI';
import {
CreateThread,
ThreadType,
} from '../../../generated/api/feed/createThread';
import {
announcementInvalidStartTime,
validateMessages,
} from '../../../utils/AnnouncementsUtils';
import { validateMessages } from '../../../utils/AnnouncementsUtils';
import { getEntityFeedLink } from '../../../utils/EntityUtils';
import { getTimeZone, getUTCDateTime } from '../../../utils/TimeUtils';
import { showErrorToast, showSuccessToast } from '../../../utils/ToastUtils';
@ -57,11 +55,13 @@ const AddAnnouncementModal: FC<Props> = ({
const [isLoading, setIsLoading] = useState<boolean>(false);
const { t } = useTranslation();
const handleCreateAnnouncement = async () => {
const startTime = Math.floor(getUTCDateTime(startDate) / 1000);
const endTime = Math.floor(getUTCDateTime(endDate) / 1000);
if (startTime >= endTime) {
showErrorToast(announcementInvalidStartTime);
showErrorToast(t('message.announcement-invalid-start-time'));
} else {
const announcementData: CreateThread = {
from: currentUser?.name as string,
@ -78,7 +78,7 @@ const AddAnnouncementModal: FC<Props> = ({
setIsLoading(true);
const data = await postThread(announcementData);
if (data) {
showSuccessToast('Announcement created successfully!');
showSuccessToast(t('message.announcement-created-successfully'));
}
onCancel();
} catch (error) {
@ -103,7 +103,7 @@ const AddAnnouncementModal: FC<Props> = ({
htmlType: 'submit',
}}
okText="Submit"
title="Make an announcement"
title={t('label.make-an-announcement')}
visible={open}
width={620}
onCancel={onCancel}>
@ -114,7 +114,7 @@ const AddAnnouncementModal: FC<Props> = ({
validateMessages={validateMessages}
onFinish={handleCreateAnnouncement}>
<Form.Item
label="Title:"
label={`${t('label.title')}:`}
messageVariables={{ fieldName: 'title' }}
name="title"
rules={[
@ -125,7 +125,7 @@ const AddAnnouncementModal: FC<Props> = ({
},
]}>
<Input
placeholder="Announcement title"
placeholder={t('label.announcement-title')}
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
@ -133,7 +133,9 @@ const AddAnnouncementModal: FC<Props> = ({
</Form.Item>
<Space className="announcement-date-space" size={16}>
<Form.Item
label={`Start Date: (${getTimeZone()})`}
label={t('label.start-date-time-zone', {
timeZone: getTimeZone(),
})}
messageVariables={{ fieldName: 'startDate' }}
name="startDate"
rules={[
@ -148,7 +150,9 @@ const AddAnnouncementModal: FC<Props> = ({
/>
</Form.Item>
<Form.Item
label={`End Date: (${getTimeZone()})`}
label={t('label.end-date-time-zone', {
timeZone: getTimeZone(),
})}
messageVariables={{ fieldName: 'endtDate' }}
name="endtDate"
rules={[
@ -163,10 +167,10 @@ const AddAnnouncementModal: FC<Props> = ({
/>
</Form.Item>
</Space>
<Form.Item label="Description:" name="description">
<Form.Item label={`${t('label.description')}:`} name="description">
<RichTextEditor
initialValue={description}
placeHolder="write your announcement"
placeHolder={t('label.write-your-announcement-lowercase')}
onTextChange={(value) => setDescription(value)}
/>
</Form.Item>

View File

@ -14,11 +14,9 @@
import { Form, Input, Modal, Space } from 'antd';
import { observer } from 'mobx-react';
import React, { FC, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { AnnouncementDetails } from '../../../generated/entity/feed/thread';
import {
announcementInvalidStartTime,
validateMessages,
} from '../../../utils/AnnouncementsUtils';
import { validateMessages } from '../../../utils/AnnouncementsUtils';
import {
getLocaleDateFromTimeStamp,
getTimeZone,
@ -53,12 +51,13 @@ const EditAnnouncementModal: FC<Props> = ({
const [description, setDescription] = useState<string>(
announcement.description || ''
);
const { t } = useTranslation();
const handleConfirm = () => {
const startTime = Math.floor(getUTCDateTime(startDate) / 1000);
const endTime = Math.floor(getUTCDateTime(endDate) / 1000);
if (startTime >= endTime) {
showErrorToast(announcementInvalidStartTime);
showErrorToast(t('message.announcement-invalid-start-time'));
} else {
const updatedAnnouncement = {
...announcement,
@ -82,8 +81,8 @@ const EditAnnouncementModal: FC<Props> = ({
type: 'primary',
htmlType: 'submit',
}}
okText="Save"
title="Edit an announcement"
okText={t('label.save')}
title={t('label.edit-an-announcement')}
visible={open}
width={620}
onCancel={onCancel}>
@ -95,7 +94,7 @@ const EditAnnouncementModal: FC<Props> = ({
validateMessages={validateMessages}
onFinish={handleConfirm}>
<Form.Item
label="Title:"
label={`${t('label.title')}:`}
messageVariables={{ fieldName: 'title' }}
name="title"
rules={[
@ -106,7 +105,7 @@ const EditAnnouncementModal: FC<Props> = ({
},
]}>
<Input
placeholder="Announcement title"
placeholder={t('label.announcement-title')}
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
@ -114,7 +113,9 @@ const EditAnnouncementModal: FC<Props> = ({
</Form.Item>
<Space className="announcement-date-space" size={16}>
<Form.Item
label={`Start Date: (${getTimeZone()})`}
label={t('label.start-date-time-zone', {
timeZone: getTimeZone(),
})}
messageVariables={{ fieldName: 'startDate' }}
name="startDate"
rules={[
@ -129,7 +130,9 @@ const EditAnnouncementModal: FC<Props> = ({
/>
</Form.Item>
<Form.Item
label={`End Date: (${getTimeZone()})`}
label={t('label.end-date-time-zone', {
timeZone: getTimeZone(),
})}
messageVariables={{ fieldName: 'endDate' }}
name="endDate"
rules={[
@ -144,10 +147,10 @@ const EditAnnouncementModal: FC<Props> = ({
/>
</Form.Item>
</Space>
<Form.Item label="Description:" name="description">
<Form.Item label={`${t('label.description')}:`} name="description">
<RichTextEditor
initialValue={description}
placeHolder="write your announcement"
placeHolder={t('label.write-your-announcement-lowercase')}
onTextChange={(value) => setDescription(value)}
/>
</Form.Item>

View File

@ -471,6 +471,27 @@
"retention-size": "retention-size",
"clean-up-policies": "clean-up policies",
"maximum-size": "maximum size",
"openmetadata": "OpenMetadata",
"activity-feeds": "Activity Feeds",
"search": "Search",
"enter": "Enter",
"profiler": "Profiler",
"data-profiler": "Data Profiler",
"starting": "Starting",
"idle": "Idle",
"completed": "Completed",
"active-with-error": "Active with error",
"retry": "Retry",
"claim-ownership-in-manage": "Claim ownership in Manage",
"deactivated": "Deactivated",
"username": "Username",
"make-an-announcement": "Make an announcement",
"announcement-title": "Announcement title",
"start-date-time-zone": "Start Date: ({{timeZone}})",
"end-date-time-zone": "End Date: ({{timeZone}})",
"write-your-announcement-lowercase": "write your announcement",
"title": "Title",
"edit-an-announcement": "Edit an announcement",
"no-of-test": " No. of Test",
"test-suite": "Test Suite",
"enter-entity": "Enter {{entity}}",
@ -577,7 +598,24 @@
"entity-owned-by-name": "This Entity is Owned by {{entityOwner}}",
"and-followed-owned-by-name": "and followed team owned by {{userName}}",
"field-text-is-invalid": "{{fieldText}} is invalid.",
"delete-team-message": "Any teams under \"{{teamName}}\" will be {{deleteType}} deleted as well."
"delete-team-message": "Any teams under \"{{teamName}}\" will be {{deleteType}} deleted as well.",
"tour-step-discover-all-assets-at-one-place": "Discover all your data assets in a single place with <0>{{text}}</0>, a centralized metadata store. Collaborate with your team and get a holistic picture of the data in your organization.",
"tour-step-activity-feed": "<0>{{text}}</0> help you understand how the data is changing in your organization.",
"tour-step-search-for-matching-dataset": "Search for matching data assets by \"name\", \"description\", \"column name\", and so on from the <0>{{text}}</0> box.",
"tour-step-type-search-term": "In the search box, type <0>\"{{text}}\"</0>. Hit <0>{{enterText}}.</0>",
"tour-step-explore-summary-asset": "From the <0>\"{{text}}\"</0> page, view a summary of each asset, including: title, description, owner, tier (importance), usage, and location.",
"tour-step-click-on-link-to-view-more": "Click on the <0>title of the asset</0> to view more details.",
"tour-step-get-to-know-table-schema": "Get to know the table <0>Schema</0>, including column names and data types as well as column descriptions and tags. You can even view metadata for complex types such as structs.",
"tour-step-click-on-entity-tab": "Click on the <0>\"{{text}}\"</0> tab.",
"tour-step-look-at-sample-data": "Take a look at the <0>{{text}}</0> to get a feel for what the table contains and how you might use it.",
"tour-step-trace-path-across-tables": " With <0>{{text}}</0>, trace the path of data across tables, pipelines, & dashboards.",
"tour-step-discover-data-assets-with-data-profile": "Discover assets with the <0>{{text}}</0>. Get to know the table usage stats, check for null values and duplicates, and understand the column data distributions.",
"lineage-data-is-not-available-for-deleted-entities": "Lineage data is not available for deleted entities.",
"remove-edge-between-source-and-target": "Are you sure you want to remove the edge between \"{{sourceDisplayName}} and {{targetDisplayName}}\"?.",
"announcement-invalid-start-time": "Announcement start time must be earlier than the end time",
"permanently-delete-metadata-and-dependents": "Permanently deleting this {{entityName}} will remove its metadata, as well as the metadata of {{dependents}} from OpenMetadata permanently.",
"permanently-delete-metadata": "Permanently deleting this {{entityName}} will remove its metadata from OpenMetadata permanently.",
"announcement-created-successfully": "Announcement created successfully!"
},
"server": {
"you-have-not-action-anything-yet": "You have not {{action}} anything yet.",

View File

@ -82,3 +82,10 @@ jest.mock('react-i18next', () => ({
}),
t: (key) => key,
}));
/**
* mock i18next
*/
jest.mock('i18next', () => ({
t: jest.fn().mockImplementation((key) => key),
}));

View File

@ -20,6 +20,3 @@ export const isActiveAnnouncement = (startTime: number, endTime: number) => {
return currentTime > startTime && currentTime < endTime;
};
export const announcementInvalidStartTime =
'Announcement start time must be earlier than the end time';

View File

@ -16,7 +16,7 @@ import { Popover, Space, Tag, Typography } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import { AxiosError } from 'axios';
import classNames from 'classnames';
import i18n from 'i18next';
import { t } from 'i18next';
import {
capitalize,
isEmpty,
@ -37,6 +37,7 @@ import {
RecentlyViewedData,
} from 'Models';
import React from 'react';
import { Trans } from 'react-i18next';
import { Link } from 'react-router-dom';
import { reactLocalStorage } from 'reactjs-localstorage';
import AppState from '../AppState';
@ -536,7 +537,7 @@ export const prepareLabel = (type: string, fqn: string, withQuotes = true) => {
*/
export const getEntityPlaceHolder = (value: string, isDeleted?: boolean) => {
if (isDeleted) {
return `${value} (Deactivated)`;
return `${value} (${t('label.deactivated')})`;
} else {
return value;
}
@ -586,13 +587,14 @@ export const getEntityId = (
export const getEntityDeleteMessage = (entity: string, dependents: string) => {
if (dependents) {
return `Permanently deleting this ${getTitleCase(
entity
)} will remove its metadata, as well as the metadata of ${dependents} from OpenMetadata permanently.`;
return t('message.permanently-delete-metadata-and-dependents', {
entityName: getTitleCase(entity),
dependents,
});
} else {
return `Permanently deleting this ${getTitleCase(
entity
)} will remove its metadata from OpenMetadata permanently.`;
return t('message.permanently-delete-metadata-and-dependents', {
entityName: getTitleCase(entity),
});
}
};
@ -731,7 +733,7 @@ export const getHostNameFromURL = (url: string) => {
export const commonUserDetailColumns: ColumnsType<User> = [
{
title: 'Username',
title: t('label.username'),
dataIndex: 'username',
key: 'username',
render: (_, record) => (
@ -744,7 +746,7 @@ export const commonUserDetailColumns: ColumnsType<User> = [
),
},
{
title: 'Teams',
title: t('label.teams'),
dataIndex: 'teams',
key: 'teams',
render: (_, record) => {
@ -792,7 +794,7 @@ export const commonUserDetailColumns: ColumnsType<User> = [
},
},
{
title: 'Roles',
title: t('label.roles'),
dataIndex: 'roles',
key: 'roles',
render: (_, record) => {
@ -872,7 +874,7 @@ export const getEmptyPlaceholder = () => {
return (
<ErrorPlaceHolder size={SIZE.MEDIUM}>
<Typography.Paragraph>
{i18n.t('label.no-data-available')}
{t('label.no-data-available')}
</Typography.Paragraph>
</ErrorPlaceHolder>
);
@ -952,6 +954,21 @@ export const sortTagsCaseInsensitive = (tags: TagLabel[]) => {
);
};
export const Transi18next = ({
i18nKey,
values,
renderElement,
...otherProps
}: {
i18nKey: string;
values?: {};
renderElement: JSX.Element | HTMLElement;
}): JSX.Element => (
<Trans i18nKey={i18nKey} values={values} {...otherProps}>
{renderElement}
</Trans>
);
/**
* It returns a link to the documentation for the given filter pattern type
* @param {FilterPatternEnum} type - The type of filter pattern.

View File

@ -17,6 +17,7 @@ import {
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import dagre from 'dagre';
import { t } from 'i18next';
import { isEmpty, isNil, isUndefined } from 'lodash';
import { LeafNodes, LineagePos, LoadingNodeState, LoadingState } from 'Models';
import React, { Fragment, MouseEvent as ReactMouseEvent } from 'react';
@ -431,29 +432,12 @@ export const getDataLabel = (
}
};
export const getNoLineageDataPlaceholder = () => {
return (
<div className="tw-mt-4 tw-ml-4 tw-flex tw-justify-center tw-font-medium tw-items-center tw-border tw-border-main tw-rounded-md tw-p-8">
<span>
Lineage is currently supported for Airflow. To enable lineage collection
from Airflow, please follow the documentation
</span>
<Link
className="tw-ml-1"
target="_blank"
to={{
pathname:
'https://docs.open-metadata.org/openmetadata/connectors/pipeline/airflow/lineage-backend',
}}>
here.
</Link>
</div>
);
};
export const getDeletedLineagePlaceholder = () => {
return (
<div className="tw-mt-4 tw-ml-4 tw-flex tw-justify-center tw-font-medium tw-items-center tw-border tw-border-main tw-rounded-md tw-p-8">
<span>Lineage data is not available for deleted entities.</span>
<span>
{t('message.lineage-data-is-not-available-for-deleted-entities')}
</span>
</div>
);
};
@ -527,9 +511,10 @@ export const getModalBodyText = (selectedEdge: SelectedEdge) => {
targetEntity = getPartialNameFromFQN(targetFQN || '', ['database']);
}
return `Are you sure you want to remove the edge between "${
source.displayName ? source.displayName : sourceEntity
} and ${target.displayName ? target.displayName : targetEntity}"?`;
return t('message.remove-edge-between-source-and-target', {
sourceDisplayName: source.displayName ? source.displayName : sourceEntity,
targetDisplayName: target.displayName ? target.displayName : targetEntity,
});
};
export const getUniqueFlowElements = (elements: CustomFlow[]) => {

View File

@ -11,6 +11,7 @@
* limitations under the License.
*/
import { t } from 'i18next';
import { Status } from '../generated/settings/eventPublisherJob';
import { Icons } from './SvgUtils';
@ -37,19 +38,19 @@ export const getStatusResultBadgeIcon = (status: string) => {
export const getEventPublisherStatusText = (status?: string) => {
switch (status) {
case Status.Starting:
return 'Starting';
return t('label.starting');
case Status.Idle:
return 'Idle';
return t('label.idle');
case Status.Completed:
return 'Completed';
return t('label.completed');
case Status.Active:
return 'Active';
return t('label.active');
case Status.ActiveWithError:
return 'Active with error';
return t('label.active-with-error');
case Status.Retry:
return 'Retry';
return t('label.retry');
default:
return status || '';

View File

@ -13,6 +13,7 @@
import antlr4 from 'antlr4';
import { ParseTreeWalker } from 'antlr4/src/antlr4/tree';
import i18next from 'i18next';
import SplitListener from '../antlr/SplitListener';
import FqnLexer from '../generated/antlr/FqnLexer';
import FqnParser from '../generated/antlr/FqnParser';
@ -45,7 +46,7 @@ export default class Fqn {
static quoteName(name) {
const matcher = /^(")([^"]+)(")$|^(.*)$/.exec(name);
if (!matcher || matcher[0].length != name.length) {
throw 'Invalid name ' + name;
throw new Error(`${i18next.t('label.invalid-name')} ${name}`);
}
// Name matches quoted string "sss".
@ -63,6 +64,6 @@ export default class Fqn {
return unquotedName.includes('.') ? '"' + name + '"' : unquotedName;
}
throw 'Invalid name ' + name;
throw new Error(`${i18next.t('label.invalid-name')} ${name}`);
}
}

View File

@ -59,8 +59,8 @@ describe('Test FQN', () => {
expect('"a.b"').toStrictEqual(Fqn.quoteName('"a.b"')); // Leave existing valid quotes
expect('a').toStrictEqual(Fqn.quoteName('"a"')); // Remove quotes when not needed
expect(() => Fqn.quoteName('"a')).toThrow('Invalid name "a'); // Error when ending quote is missing
expect(() => Fqn.quoteName('a"')).toThrow('Invalid name a"'); // Error when beginning quote is missing
expect(() => Fqn.quoteName('a"b')).toThrow('Invalid name a"b'); // Error when invalid quote is present in the middle of the string
expect(() => Fqn.quoteName('"a')).toThrow('label.invalid-name "a'); // Error when ending quote is missing
expect(() => Fqn.quoteName('a"')).toThrow('label.invalid-name a"'); // Error when beginning quote is missing
expect(() => Fqn.quoteName('a"b')).toThrow('label.invalid-name a"b'); // Error when invalid quote is present in the middle of the string
});
});

View File

@ -11,9 +11,11 @@
* limitations under the License.
*/
import i18next from 'i18next';
import React from 'react';
import AppState from '../AppState';
import { CurrentTourPageType } from '../enums/tour.enum';
import { Transi18next } from './CommonUtils';
import { getCurrentDatasetTab } from './DatasetDetailsUtils';
export const getSteps = (value: string, clearSearchTerm: () => void) => {
@ -21,10 +23,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
{
content: () => (
<p>
Discover all your data assets in a single place with{' '}
<strong>OpenMetadata</strong>, a centralized metadata store.
Collaborate with your team and get a holistic picture of the data in
your organization.
<Transi18next
i18nKey="message.tour-step-discover-all-assets-at-one-place"
renderElement={<strong />}
values={{
text: i18next.t('label.openmetadata'),
}}
/>
</p>
),
stepInteraction: false,
@ -33,8 +38,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
{
content: () => (
<p>
<strong>Activity Feeds</strong> help you understand how the data is
changing in your organization.
<Transi18next
i18nKey="message.tour-step-activity-feed"
renderElement={<strong />}
values={{
text: i18next.t('label.activity-feeds'),
}}
/>
</p>
),
selector: '#feedData',
@ -43,9 +53,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
{
content: () => (
<p>
Search for matching data assets by &quot;name&quot;,
&quot;description&quot;, &quot;column name&quot;, and so on from the{' '}
<strong>Search</strong> box.
<Transi18next
i18nKey="message.tour-step-search-for-matching-dataset"
renderElement={<strong />}
values={{
text: i18next.t('label.search'),
}}
/>
</p>
),
selector: '#searchBox',
@ -56,8 +70,14 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
beforePrev: clearSearchTerm,
content: () => (
<p>
In the search box, type <strong>&quot;{value}&quot;</strong>. Hit{' '}
<strong>Enter.</strong>
<Transi18next
i18nKey="message.tour-step-type-search-term"
renderElement={<strong />}
values={{
text: value,
enterText: i18next.t('label.enter'),
}}
/>
</p>
),
actionType: 'enter',
@ -74,9 +94,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
},
content: () => (
<p>
From the <strong>&quot;Explore&quot;</strong> page, view a summary of
each asset, including: title, description, owner, tier (importance),
usage, and location.
<Transi18next
i18nKey="message.tour-step-explore-summary-asset"
renderElement={<strong />}
values={{
text: i18next.t('label.explore'),
}}
/>
</p>
),
selector: '#tabledatacard0',
@ -85,7 +109,10 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
{
content: () => (
<p>
Click on the <strong>title of the asset</strong> to view more details.
<Transi18next
i18nKey="message.tour-step-click-on-link-to-view-more"
renderElement={<strong />}
/>
</p>
),
actionType: 'click',
@ -100,10 +127,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
},
content: () => (
<p>
{' '}
Get to know the table <strong>Schema</strong>, including column names
and data types as well as column descriptions and tags. You can even
view metadata for complex types such as structs.
<Transi18next
i18nKey="message.tour-step-get-to-know-table-schema"
renderElement={<strong />}
values={{
text: i18next.t('label.schema'),
}}
/>
</p>
),
stepInteraction: false,
@ -116,7 +146,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
actionType: 'click',
content: () => (
<p>
Click on the <strong>&quot;Sample Data&quot;</strong> tab.
<Transi18next
i18nKey="message.tour-step-click-on-entity-tab"
renderElement={<strong />}
values={{
text: i18next.t('label.sample-data'),
}}
/>
</p>
),
selector: '#sampleData',
@ -128,8 +164,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
{
content: () => (
<p>
Take a look at the <strong>Sample Data</strong> to get a feel for what
the table contains and how you might use it.
<Transi18next
i18nKey="message.tour-step-look-at-sample-data"
renderElement={<strong />}
values={{
text: i18next.t('label.sample-data'),
}}
/>
</p>
),
selector: '#sampleDataDetails',
@ -145,7 +186,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
actionType: 'click',
content: () => (
<p>
Click on the <strong>&quot;Profiler&quot;</strong> tab.
<Transi18next
i18nKey="message.tour-step-click-on-entity-tab"
renderElement={<strong />}
values={{
text: i18next.t('label.profiler'),
}}
/>
</p>
),
selector: '#profilerDataQuality',
@ -153,9 +200,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
{
content: () => (
<p>
Discover assets with the <strong>Data Profiler</strong>. Get to know
the table usage stats, check for null values and duplicates, and
understand the column data distributions.
<Transi18next
i18nKey="message.tour-step-discover-data-assets-with-data-profile"
renderElement={<strong />}
values={{
text: i18next.t('label.data-profiler'),
}}
/>
</p>
),
stepInteraction: false,
@ -171,7 +222,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
actionType: 'click',
content: () => (
<p>
Click on the <strong>&quot;Lineage&quot;</strong> tab
<Transi18next
i18nKey="message.tour-step-click-on-entity-tab"
renderElement={<strong />}
values={{
text: i18next.t('label.lineage'),
}}
/>
</p>
),
selector: '#lineage',
@ -179,8 +236,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
{
content: () => (
<p>
With <strong>Lineage</strong>, trace the path of data across tables,
pipelines, & dashboards.
<Transi18next
i18nKey="message.tour-step-trace-path-across-tables"
renderElement={<strong />}
values={{
text: i18next.t('label.lineage'),
}}
/>
</p>
),
stepInteraction: false,