chore(ui) : Add missing localization (#10205)

* chore(ui) : Add missing localization

* fix : unit test

* chore : add missing locale keys

* chore : add missing locale keys

* fix: cy failures

* fix : cy test

* address comments
This commit is contained in:
Sachin Chaurasiya 2023-02-16 17:28:00 +05:30 committed by GitHub
parent 57093e583a
commit 5b94f5ae70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 224 additions and 130 deletions

View File

@ -622,7 +622,7 @@ export const restoreUser = (username) => {
.should('be.visible')
.click();
verifyResponseStatusCode('@restoreUser', 200);
toastNotification('User restored successfully!');
toastNotification('User restored successfully');
// Verifying the restored user
cy.get('.ant-switch').should('exist').should('be.visible').click();

View File

@ -241,7 +241,7 @@ describe('Data Quality and Profiler should work properly', () => {
cy.get('.ant-modal-footer').contains('Submit').click();
verifyResponseStatusCode('@updateTest', 200);
cy.get('.Toastify__toast-body')
.contains('Test case updated successfully!')
.contains('Test case updated successfully.')
.should('be.visible')
.wait(200);
cy.get(`[data-testid="${testName}"]`).should('be.visible').click();
@ -407,7 +407,7 @@ describe('Data Quality and Profiler should work properly', () => {
cy.get('.ant-modal-footer').contains('Submit').click();
verifyResponseStatusCode('@updateTest', 200);
cy.get('.Toastify__toast-body')
.contains('Test case updated successfully!')
.contains('Test case updated successfully.')
.should('be.visible')
.wait(200);
cy.get(`[data-testid="${columnTestName}"]`).should('be.visible').click();

View File

@ -119,7 +119,7 @@ const AddDataQualityTestV1: React.FC<AddDataQualityTestProps> = ({
url: getTableTabPath(entityTypeFQN, 'profiler'),
},
{
name: 'Add Column Test',
name: t('message.add-entity-test', { entity: t('label.column') }),
url: '',
activeTitle: true,
},
@ -127,7 +127,7 @@ const AddDataQualityTestV1: React.FC<AddDataQualityTestProps> = ({
data.push(...colVal);
} else {
data.push({
name: 'Add Table Test',
name: t('message.add-entity-test', { entity: t('label.table') }),
url: '',
activeTitle: true,
});
@ -216,7 +216,7 @@ const AddDataQualityTestV1: React.FC<AddDataQualityTestProps> = ({
} else if (activeServiceStep > 2) {
const successName = selectedTestSuite?.isNewTestSuite
? `${testSuiteData?.name} & ${testCaseRes?.name}`
: testCaseRes?.name || 'Test case';
: testCaseRes?.name || t('label.test-case') || '';
const successMessage = selectedTestSuite?.isNewTestSuite ? undefined : (
<span>
@ -237,7 +237,7 @@ const AddDataQualityTestV1: React.FC<AddDataQualityTestProps> = ({
showIngestionButton={selectedTestSuite?.isNewTestSuite || false}
state={FormSubmitType.ADD}
successMessage={successMessage}
viewServiceText="View Test Suite"
viewServiceText={t('message.view-test-suite')}
/>
);
}
@ -286,7 +286,9 @@ const AddDataQualityTestV1: React.FC<AddDataQualityTestProps> = ({
<Typography.Paragraph
className="tw-heading tw-text-base"
data-testid="header">
{`Add ${isColumnFqn ? 'Column' : 'Table'} Test`}
{t('message.add-entity-test', {
entity: isColumnFqn ? t('label.column') : t('label.table'),
})}
</Typography.Paragraph>
</Col>
<Col span={24}>

View File

@ -30,7 +30,6 @@ import {
TestDataType,
TestDefinition,
} from '../../generated/tests/testDefinition';
import jsonData from '../../jsons/en';
import { getNameFromFQN } from '../../utils/CommonUtils';
import { getEntityFqnFromEntityLink } from '../../utils/TableUtils';
import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils';
@ -149,7 +148,7 @@ const EditTestCaseModal: React.FC<EditTestCaseModalProps> = ({
await updateTestCaseById(testCase.id || '', jsonPatch);
onUpdate && onUpdate();
showSuccessToast(
jsonData['api-success-messages']['update-test-case-success']
t('server.update-entity-success', { entity: t('label.test-case') })
);
onCancel();
form.resetFields();

View File

@ -15,6 +15,7 @@ import { PlusOutlined } from '@ant-design/icons';
import { Button, Form, Input, InputNumber, Switch } from 'antd';
import 'codemirror/addon/fold/foldgutter.css';
import React from 'react';
import { useTranslation } from 'react-i18next';
import {
TestCaseParameterDefinition,
TestDataType,
@ -24,11 +25,25 @@ import '../../TableProfiler/tableProfiler.less';
import { ParameterFormProps } from '../AddDataQualityTest.interface';
const ParameterForm: React.FC<ParameterFormProps> = ({ definition }) => {
const { t } = useTranslation();
const prepareForm = (data: TestCaseParameterDefinition) => {
let Field = <Input placeholder={`Enter ${data.displayName}`} />;
let Field = (
<Input
placeholder={`${t('message.enter-a-field', {
field: data.displayName,
})}`}
/>
);
switch (data.dataType) {
case TestDataType.String:
Field = <Input placeholder={`Enter ${data.displayName}`} />;
Field = (
<Input
placeholder={`${t('message.enter-a-field', {
field: data.displayName,
})}`}
/>
);
break;
case TestDataType.Number:
@ -39,7 +54,9 @@ const ParameterForm: React.FC<ParameterFormProps> = ({ definition }) => {
Field = (
<InputNumber
className="tw-w-full"
placeholder={`Enter ${data.displayName}`}
placeholder={`${t('message.enter-a-field', {
field: data.displayName,
})}`}
/>
);
@ -51,7 +68,11 @@ const ParameterForm: React.FC<ParameterFormProps> = ({ definition }) => {
case TestDataType.Array:
case TestDataType.Set:
Field = (
<Input placeholder={`Enter comma(,) separated ${data.displayName}`} />
<Input
placeholder={`${t('message.enter-comma-separated-field', {
field: data.displayName,
})}`}
/>
);
return (
@ -84,10 +105,16 @@ const ParameterForm: React.FC<ParameterFormProps> = ({ definition }) => {
rules={[
{
required: data.required,
message: `${data.displayName} is required!`,
message: `${t('message.field-text-is-required', {
fieldText: data.displayName,
})}`,
},
]}>
<Input placeholder={`Enter ${data.displayName}`} />
<Input
placeholder={`${t('message.enter-a-field', {
field: data.displayName,
})}`}
/>
</Form.Item>
<Button
icon={
@ -116,7 +143,9 @@ const ParameterForm: React.FC<ParameterFormProps> = ({ definition }) => {
rules={[
{
required: data.required,
message: `${data.displayName} is required!`,
message: `${t('message.field-text-is-required', {
fieldText: data.displayName,
})}`,
},
]}
tooltip={data.description}>

View File

@ -35,7 +35,6 @@ import {
} from '../../../constants/constants';
import { TestSuite } from '../../../generated/tests/testSuite';
import { useAuth } from '../../../hooks/authHooks';
import jsonData from '../../../jsons/en';
import SVGIcons, { Icons } from '../../../utils/SvgUtils';
import { showErrorToast } from '../../../utils/ToastUtils';
import { useAuthContext } from '../../authentication/auth-provider/AuthProvider';
@ -133,13 +132,15 @@ const SelectTestSuite: React.FC<SelectTestSuiteProps> = ({
}
}}>
<Form.Item
label="Test Suite:"
label={`${t('label.test-suite')}:`}
name="testSuiteId"
rules={[
{
required:
!isNewTestSuite || !isEmpty(form.getFieldValue('testSuiteId')),
message: 'Test suite is required',
message: `${t('message.field-text-is-required', {
fieldText: t('label.test-suite'),
})}`,
},
]}>
<Select
@ -147,7 +148,9 @@ const SelectTestSuite: React.FC<SelectTestSuiteProps> = ({
label: suite.name,
value: suite.id,
}))}
placeholder="Select test suite"
placeholder={t('label.select-field', {
field: t('label.test-suite'),
})}
/>
</Form.Item>
{hasAccess && (
@ -162,21 +165,27 @@ const SelectTestSuite: React.FC<SelectTestSuiteProps> = ({
{t('label.new-test-suite')}
</Typography.Paragraph>
<Form.Item
label="Name:"
label={`${t('label.name')}:`}
name="testSuiteName"
rules={[
{
required: isEmpty(form.getFieldValue('testSuiteId')),
message: 'Name is required!',
message: `${t('message.field-text-is-required', {
fieldText: t('label.name'),
})}`,
},
{
pattern: /^[A-Za-z0-9_]*$/g,
message: jsonData.label['special-character-error'],
message: t('message.special-character-not-allowed'),
},
{
validator: (_, value) => {
if (testSuites.some((suite) => suite.name === value)) {
return Promise.reject('Name already exist!');
return Promise.reject(
t('message.entity-already-exists', {
entity: t('label.name'),
})
);
}
return Promise.resolve();
@ -185,11 +194,11 @@ const SelectTestSuite: React.FC<SelectTestSuiteProps> = ({
]}>
<Input
data-testid="test-suite-name"
placeholder="Enter test suite name"
placeholder={t('message.enter-test-suite-name')}
/>
</Form.Item>
<Form.Item
label="Description:"
label={`${t('label.description')}:`}
name="description"
rules={[
{
@ -199,7 +208,11 @@ const SelectTestSuite: React.FC<SelectTestSuiteProps> = ({
isEmpty(getDescription()) &&
isEmpty(form.getFieldValue('testSuiteId'))
) {
return Promise.reject('Description is required!');
return Promise.reject(
`${t('message.field-text-is-required', {
fieldText: t('label.description'),
})}`
);
}
return Promise.resolve();

View File

@ -115,9 +115,9 @@ const TestCaseForm: React.FC<TestCaseFormProps> = ({
<Form.Item
data-testid="sql-editor-container"
key={name}
label="SQL Query"
label={t('label.sql-query')}
name={name}
tooltip="Queries returning 1 or more rows will result in the test failing.">
tooltip={t('message.queries-result-test')}>
<SchemaEditor
className="profiler-setting-sql-editor"
mode={{ name: CSMode.SQL }}
@ -242,45 +242,56 @@ const TestCaseForm: React.FC<TestCaseFormProps> = ({
onFinish={handleFormSubmit}
onValuesChange={handleValueChange}>
<Form.Item
label="Name:"
label={`${t('label.name')}:`}
name="testName"
rules={[
{
required: true,
message: 'Name is required!',
message: `${t('label.field-required', { field: t('label.name') })}`,
},
{
pattern: /^[A-Za-z0-9_]*$/g,
message: 'Spacial character is not allowed!',
message: t('message.special-character-not-allowed'),
},
{
validator: (_, value) => {
if (testCases.some((test) => test.name === value)) {
return Promise.reject('Name already exist!');
return Promise.reject(
t('message.entity-already-exists', {
entity: t('label.name'),
})
);
}
return Promise.resolve();
},
},
]}>
<Input placeholder="Enter test case name" />
<Input placeholder={t('message.enter-test-case-name')} />
</Form.Item>
<Form.Item
label="Test Type:"
label={`${t('label.test-type')}`}
name="testTypeId"
rules={[{ required: true, message: 'Test type is required' }]}>
rules={[
{
required: true,
message: `${t('label.field-required', {
field: t('label.test-type'),
})}`,
},
]}>
<Select
options={testDefinitions.map((suite) => ({
label: suite.name,
value: suite.fullyQualifiedName,
}))}
placeholder="Select test type"
placeholder={t('label.select-field', { field: t('label.test-type') })}
/>
</Form.Item>
{GenerateParamsField()}
<Form.Item label="Description:" name="description">
<Form.Item label={`${t('label.description')}`} name="description">
<RichTextEditor
initialValue={initialValue?.description || ''}
ref={markdownRef}

View File

@ -210,10 +210,10 @@ const AddGlossaryTerm = ({
.filter((ref) => !isEmpty(ref.endpoint) && !isEmpty(ref.name));
const updatedTerms = relatedTerms.map(function (term) {
return term.fullyQualifiedName!;
return term.fullyQualifiedName || '';
});
const updatedReviewers = reviewer.map(function (r) {
return r.fullyQualifiedName!;
return r.fullyQualifiedName || '';
});
if (validateForm(updatedReference)) {
@ -375,7 +375,7 @@ const AddGlossaryTerm = ({
data-testid="synonyms"
id="synonyms"
name="synonyms"
placeholder="Enter comma seprated keywords"
placeholder={t('message.enter-comma-separated-keywords')}
type="text"
value={synonyms}
onChange={handleValidation}

View File

@ -39,7 +39,6 @@ import { EntityReference } from '../../generated/type/entityReference';
import { Paging } from '../../generated/type/paging';
import { LabelType, State, TagLabel } from '../../generated/type/tagLabel';
import { useInfiniteScroll } from '../../hooks/useInfiniteScroll';
import jsonData from '../../jsons/en';
import {
getCurrentUserId,
getEntityName,
@ -159,7 +158,9 @@ const DashboardDetails = ({
setDashboardPermissions(entityPermission);
} catch (error) {
showErrorToast(
jsonData['api-error-messages']['fetch-entity-permissions-error']
t('server.fetch-entity-permissions-error', {
entity: t('label.dashboard'),
})
);
}
}, [dashboardDetails.id, getEntityPermission, setDashboardPermissions]);
@ -178,7 +179,7 @@ const DashboardDetails = ({
};
const tabs = [
{
name: 'Details',
name: t('label.detail-plural'),
icon: {
alt: 'schema',
name: 'icon-schema',
@ -189,7 +190,7 @@ const DashboardDetails = ({
position: 1,
},
{
name: 'Activity Feeds & Tasks',
name: t('label.activity-feed-and-task-plural'),
icon: {
alt: 'activity_feed',
name: 'activity_feed',
@ -201,7 +202,7 @@ const DashboardDetails = ({
count: feedCount,
},
{
name: 'Lineage',
name: t('label.lineage'),
icon: {
alt: 'lineage',
name: 'icon-lineage',
@ -212,7 +213,7 @@ const DashboardDetails = ({
position: 3,
},
{
name: 'Custom Properties',
name: t('label.custom-property-plural'),
isProtected: false,
position: 4,
},

View File

@ -208,9 +208,12 @@ describe('Test DashboardDetails component', () => {
const EntityPageInfo = await findByText(container, /EntityPageInfo/i);
const description = await findByText(container, /Description Component/i);
const tabs = await findByTestId(container, 'tabs');
const detailsTab = await findByTestId(tabs, 'Details');
const activityFeedTab = await findByTestId(tabs, 'Activity Feeds & Tasks');
const lineageTab = await findByTestId(tabs, 'Lineage');
const detailsTab = await findByTestId(tabs, 'label.detail-plural');
const activityFeedTab = await findByTestId(
tabs,
'label.activity-feed-and-task-plural'
);
const lineageTab = await findByTestId(tabs, 'label.lineage');
expect(EntityPageInfo).toBeInTheDocument();
expect(description).toBeInTheDocument();

View File

@ -732,7 +732,7 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
<Col offset={1} span={6}>
<div className="border-1 border-main rounded-6">
<FrequentlyJoinedTables
header="Frequently Joined Tables"
header={t('label.frequently-joined-tables')}
tableList={getFrequentlyJoinedWithTables()}
/>
</div>

View File

@ -72,7 +72,7 @@ const EntityInfoDrawer = ({
.catch((err: AxiosError) => {
showErrorToast(
err,
`Error while getting ${selectedNode.name} details`
t('server.entity-fetch-error', { entity: selectedNode.name })
);
})
.finally(() => {
@ -92,7 +92,7 @@ const EntityInfoDrawer = ({
.catch((err: AxiosError) => {
showErrorToast(
err,
`Error while getting ${selectedNode.name} service`
t('server.entity-fetch-error', { entity: selectedNode.name })
);
});
setEntityDetail(res);
@ -101,7 +101,7 @@ const EntityInfoDrawer = ({
.catch((err: AxiosError) => {
showErrorToast(
err,
`Error while getting ${selectedNode.name} details`
t('server.entity-fetch-error', { entity: selectedNode.name })
);
})
.finally(() => {
@ -121,7 +121,7 @@ const EntityInfoDrawer = ({
.catch((err: AxiosError) => {
showErrorToast(
err,
`Error while getting ${selectedNode.name} service`
t('server.entity-fetch-error', { entity: selectedNode.name })
);
});
setEntityDetail(res);
@ -130,7 +130,7 @@ const EntityInfoDrawer = ({
.catch((err: AxiosError) => {
showErrorToast(
err,
`Error while getting ${selectedNode.name} details`
t('server.entity-fetch-error', { entity: selectedNode.name })
);
})
.finally(() => {

View File

@ -71,7 +71,6 @@ import {
} from '../../generated/type/entityLineage';
import { EntityReference } from '../../generated/type/entityReference';
import { withLoader } from '../../hoc/withLoader';
import jsonData from '../../jsons/en';
import { getEntityName } from '../../utils/CommonUtils';
import {
createNewEdge,
@ -1261,10 +1260,7 @@ const EntityLineageComponent: FunctionComponent<EntityLineageProp> = ({
)
);
} catch (error) {
showErrorToast(
error as AxiosError,
jsonData['api-error-messages']['fetch-suggestions-error']
);
showErrorToast(error as AxiosError, t('server.fetch-suggestions-error'));
}
};
@ -1469,12 +1465,12 @@ const EntityLineageComponent: FunctionComponent<EntityLineageProp> = ({
{showDeleteModal && (
<Modal
okText={getLoadingStatusValue(
'Confirm',
t('label.confirm'),
deletionState.loading,
deletionState.status
)}
open={showDeleteModal}
title="Remove lineage edge"
title={t('message.remove-lineage-edge')}
onCancel={() => {
setShowDeleteModal(false);
}}

View File

@ -139,7 +139,9 @@ const NodeSuggestions: FC<EntitySuggestionProps> = ({
<input
className="tw-form-inputs tw-form-inputs-padding tw-w-full"
data-testid="node-search-box"
placeholder={`Search for ${capitalize(entityType)}s...`}
placeholder={`${t('label.search-for-type', {
type: capitalize(entityType),
})}s...`}
type="search"
value={searchValue}
onChange={handleChange}
@ -187,7 +189,7 @@ const NodeSuggestions: FC<EntitySuggestionProps> = ({
searchValue && (
<div className="tw-origin-top-right tw-absolute tw-z-20 tw-w-max tw-mt-1 tw-rounded-md tw-shadow-lg tw-bg-white tw-ring-1 tw-ring-black tw-ring-opacity-5 focus:tw-outline-none">
<Empty
description="No data found"
description={t('label.no-data-found')}
image={Empty.PRESENTED_IMAGE_SIMPLE}
style={{
width: '326px',

View File

@ -101,7 +101,7 @@ const GlobalSearchSuggestions = ({
let icon = '';
switch (index) {
case SearchIndex.TOPIC:
label = t('label.topics');
label = t('label.topic-plural');
icon = Icons.TOPIC_GREY;
break;

View File

@ -325,8 +325,10 @@ const GlossaryV1 = ({
title={
glossaryPermission.Delete || glossaryTermPermission.Delete
? isGlossaryActive
? 'Manage Glossary'
: 'Manage GlossaryTerm'
? t('label.manage-entity', { entity: t('label.glossary') })
: t('label.manage-entity', {
entity: t('label.glossary-term'),
})
: NO_PERMISSION_FOR_ACTION
}>
<Button

View File

@ -66,7 +66,8 @@ const SummaryDetail = ({
)}
</div>
{showIcon ? (
<Tooltip title={hasAccess ? 'Edit' : NO_PERMISSION_FOR_ACTION}>
<Tooltip
title={hasAccess ? t('label.edit') : NO_PERMISSION_FOR_ACTION}>
<Button
className="cursor-pointer m--t-xss"
data-testid="edit-button"

View File

@ -74,7 +74,7 @@ const GlossaryTermReferences = ({
key="references"
setShow={() => setIsViewMode(false)}
showIcon={isViewMode}
title="References">
title={t('label.reference-plural')}>
<div className="flex">
{references.length > 0 ? (
references.map((ref, i) => (
@ -126,7 +126,7 @@ const GlossaryTermReferences = ({
key="references"
setShow={() => setIsViewMode(false)}
showIcon={isViewMode}
title="References"
title={t('label.reference-plural')}
onAddClick={() => add()}
onSave={handleReferencesSave}>
<>
@ -137,7 +137,7 @@ const GlossaryTermReferences = ({
className="w-full"
{...restField}
name={[name, 'name']}>
<Input placeholder="Name" />
<Input placeholder={t('label.name')} />
</Form.Item>
</Col>
<Col span={11}>
@ -148,10 +148,10 @@ const GlossaryTermReferences = ({
rules={[
{
type: 'url',
message: 'Endpoint should be valid URL.',
message: t('message.endpoint-should-be-valid'),
},
]}>
<Input placeholder="End point" />
<Input placeholder={t('label.end-point')} />
</Form.Item>
</Col>
<Col span={1}>

View File

@ -73,7 +73,7 @@ const GlossaryTermSynonyms = ({
key="synonyms"
setShow={() => setIsViewMode(false)}
showIcon={isViewMode}
title="Synonyms"
title={t('label.synonyms')}
onSave={handleSynonymsSave}>
<div className="flex" data-testid="synonyms-container">
{isViewMode ? (
@ -83,7 +83,7 @@ const GlossaryTermSynonyms = ({
allowClear
id="synonyms-select"
mode="tags"
placeholder="Add Synonyms"
placeholder={t('label.add-entity', { entity: t('label.synonyms') })}
style={{ width: '100%' }}
value={synonyms}
onChange={(value) => setSynonyms(value)}

View File

@ -126,7 +126,7 @@ const RelatedTerms = ({
key="related_term"
setShow={() => setIsIconVisible(false)}
showIcon={isIconVisible}
title="Related Terms"
title={t('label.related-terms')}
onSave={handleRelatedTermsSave}>
<div className="flex" data-testid="related-term-container">
{isIconVisible ? (
@ -161,7 +161,9 @@ const RelatedTerms = ({
mode="multiple"
notFoundContent={isLoading ? <Spin size="small" /> : null}
options={formatOptions(options)}
placeholder="Add Related Terms"
placeholder={t('label.add-entity', {
entity: t('label.related-terms'),
})}
style={{ width: '100%' }}
value={selectedOption}
onChange={(_, data) => {

View File

@ -14,6 +14,7 @@
import { PlusOutlined } from '@ant-design/icons';
import { ArrayFieldTemplateProps } from '@rjsf/core';
import classNames from 'classnames';
import { t } from 'i18next';
import React, { Fragment, FunctionComponent } from 'react';
import SVGIcons, { Icons } from '../../utils/SvgUtils';
import { Button } from '../buttons/Button/Button';
@ -57,7 +58,7 @@ export const ArrayFieldTemplate: FunctionComponent<ArrayFieldTemplateProps> = (
<SVGIcons
alt="delete"
icon={Icons.DELETE}
title="Delete"
title={t('label.delete')}
width="16px"
/>
</button>

View File

@ -48,7 +48,6 @@ import { EntityReference } from '../../generated/type/entityReference';
import { Paging } from '../../generated/type/paging';
import { LabelType, State, TagLabel } from '../../generated/type/tagLabel';
import { useInfiniteScroll } from '../../hooks/useInfiniteScroll';
import jsonData from '../../jsons/en';
import {
getEmptyPlaceholder,
getEntityName,
@ -131,7 +130,9 @@ const MlModelDetail: FC<MlModelDetailProp> = ({
setPipelinePermissions(entityPermission);
} catch (error) {
showErrorToast(
jsonData['api-error-messages']['fetch-entity-permissions-error']
t('server.fetch-entity-permissions-error', {
entity: t('label.ml-model'),
})
);
}
}, [mlModelDetail.id, getEntityPermission, setPipelinePermissions]);

View File

@ -14,6 +14,7 @@
import { Button, Card } from 'antd';
import { isNil } from 'lodash';
import React, { FunctionComponent, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import { getExplorePathWithSearch, ROUTES } from '../../constants/constants';
import {
@ -31,55 +32,56 @@ import { MyAssetStatsProps } from './MyAssetStats.interface';
const MyAssetStats: FunctionComponent<MyAssetStatsProps> = ({
entityState,
}: MyAssetStatsProps) => {
const { t } = useTranslation();
const { entityCounts, entityCountLoading } = entityState;
const dataSummary = useMemo(
() => ({
tables: {
icon: Icons.TABLE_GREY,
data: 'Tables',
data: t('label.table-plural'),
count: entityCounts.tableCount,
link: getExplorePathWithSearch(undefined, 'tables'),
dataTestId: 'tables',
},
topics: {
icon: Icons.TOPIC_GREY,
data: 'Topics',
data: t('label.topic-plural'),
count: entityCounts.topicCount,
link: getExplorePathWithSearch(undefined, 'topics'),
dataTestId: 'topics',
},
dashboards: {
icon: Icons.DASHBOARD_GREY,
data: 'Dashboards',
data: t('label.dashboard-plural'),
count: entityCounts.dashboardCount,
link: getExplorePathWithSearch(undefined, 'dashboards'),
dataTestId: 'dashboards',
},
pipelines: {
icon: Icons.PIPELINE_GREY,
data: 'Pipelines',
data: t('label.pipeline-plural'),
count: entityCounts.pipelineCount,
link: getExplorePathWithSearch(undefined, 'pipelines'),
dataTestId: 'pipelines',
},
mlModal: {
icon: Icons.MLMODAL,
data: 'ML Models',
data: t('label.ml-model-plural'),
count: entityCounts.mlmodelCount,
link: getExplorePathWithSearch(undefined, 'mlmodels'),
dataTestId: 'mlmodels',
},
testSuite: {
icon: Icons.TEST_SUITE,
data: 'Test Suites',
data: t('label.test-suite-plural'),
count: entityCounts.testSuiteCount,
link: ROUTES.TEST_SUITES,
dataTestId: 'test-suite',
},
service: {
icon: Icons.SERVICE,
data: 'Services',
data: t('label.service-plural'),
count: entityCounts.servicesCount,
link: getSettingPath(
GlobalSettingsMenuCategory.SERVICES,
@ -89,7 +91,7 @@ const MyAssetStats: FunctionComponent<MyAssetStatsProps> = ({
},
user: {
icon: Icons.USERS,
data: 'Users',
data: t('label.user-plural'),
count: entityCounts.userCount,
link: getSettingPath(
GlobalSettingsMenuCategory.MEMBERS,
@ -100,7 +102,7 @@ const MyAssetStats: FunctionComponent<MyAssetStatsProps> = ({
},
teams: {
icon: Icons.TEAMS_GREY,
data: 'Teams',
data: t('label.team-plural'),
count: entityCounts.teamCount,
link: getTeamsWithFqnPath(TeamType.Organization),
dataTestId: 'terms',

View File

@ -62,7 +62,7 @@ const PipelineVersion: FC<PipelineVersionProp> = ({
);
const tabs = [
{
name: 'Details',
name: t('label.detail-plural'),
icon: {
alt: 'schema',
name: 'icon-schema',
@ -133,7 +133,7 @@ const PipelineVersion: FC<PipelineVersionProp> = ({
const extraInfo: Array<ExtraInfo> = [
{
key: 'Owner',
key: t('label.owner'),
value:
!isUndefined(ownerDiff.added) ||
!isUndefined(ownerDiff.deleted) ||
@ -149,7 +149,7 @@ const PipelineVersion: FC<PipelineVersionProp> = ({
newOwner?.type === OwnerType.USER ? newOwner?.name : undefined,
},
{
key: 'Tier',
key: t('label.tier'),
value:
!isUndefined(newTier) || !isUndefined(oldTier)
? getDiffValue(
@ -218,7 +218,7 @@ const PipelineVersion: FC<PipelineVersionProp> = ({
const tableColumn: ColumnsType<Task> = useMemo(
() => [
{
title: 'Task Name',
title: t('label.task-name'),
dataIndex: 'displayName',
key: 'displayName',
render: (text, record) => (
@ -236,7 +236,7 @@ const PipelineVersion: FC<PipelineVersionProp> = ({
),
},
{
title: 'Description',
title: t('label.description'),
dataIndex: 'description',
key: 'description',
render: (text) =>
@ -249,7 +249,7 @@ const PipelineVersion: FC<PipelineVersionProp> = ({
),
},
{
title: 'Task Type',
title: t('label.task-type'),
dataIndex: 'taskType',
key: 'taskType',
},

View File

@ -11,6 +11,7 @@
* limitations under the License.
*/
import { t } from 'i18next';
import { lowerCase } from 'lodash';
import React, { Fragment, FunctionComponent, useState } from 'react';
import Searchbar from '../common/searchbar/Searchbar';
@ -43,7 +44,7 @@ const SchemaTab: FunctionComponent<Props> = ({
<div className="tw-grid tw-grid-cols-3 tw-gap-x-2">
<div>
<Searchbar
placeholder="Find in table..."
placeholder={`${t('message.find-in-table')}..`}
searchValue={searchText}
typingInterval={500}
onSearch={handleSearchAction}

View File

@ -33,7 +33,9 @@ const TeamsSelectable = ({
showTeamsAlert,
onSelectionChange,
filterJoinable,
placeholder = 'Search for teams',
placeholder = t('label.search-for-type', {
type: t('label.team-plural-lowercase'),
}),
}: Props) => {
const [value, setValue] = useState<Array<string>>();
const [noTeam, setNoTeam] = useState<boolean>(false);

View File

@ -65,7 +65,7 @@ const TestCasesTab = ({
return (
<TestCaseCommonTabContainer
isPaging
buttonName="Add Test"
buttonName={t('label.add-entity', { entity: t('label.test') })}
currentPage={currentPage}
hasAccess={createPermission}
paging={testCasesPaging}

View File

@ -35,7 +35,6 @@ import { EntityReference } from '../../generated/type/entityReference';
import { Paging } from '../../generated/type/paging';
import { LabelType, State } from '../../generated/type/tagLabel';
import { useInfiniteScroll } from '../../hooks/useInfiniteScroll';
import jsonData from '../../jsons/en';
import {
getCurrentUserId,
getEntityName,
@ -137,7 +136,7 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
setTopicPermissions(permissions);
} catch (error) {
showErrorToast(
jsonData['api-error-messages']['fetch-entity-permissions-error']
t('server.fetch-entity-permissions-error', { entity: t('label.topic') })
);
}
}, [topicDetails.id, getEntityPermission, setTopicPermissions]);
@ -562,7 +561,7 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
<Fragment>
{getInfoBadge([
{
key: 'Schema',
key: t('label.schema'),
value: topicDetails.messageSchema?.schemaType ?? '',
},
])}

View File

@ -26,7 +26,6 @@ import { CreateUser } from '../../generated/api/teams/createUser';
import { User } from '../../generated/entity/teams/user';
import { Paging } from '../../generated/type/paging';
import { useAuth } from '../../hooks/authHooks';
import jsonData from '../../jsons/en';
import { getEntityName } from '../../utils/CommonUtils';
import SVGIcons, { Icons } from '../../utils/SvgUtils';
import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils';
@ -100,16 +99,16 @@ const UserListV1: FC<UserListV1Props> = ({
if (data) {
afterDeleteAction();
showSuccessToast(
jsonData['api-success-messages']['user-restored-success']
t('message.entity-restored-success', { entity: t('label.user') })
);
setShowReactiveModal(false);
} else {
throw jsonData['api-error-messages']['update-user-error'];
throw t('server.entity-updating-error', { entity: t('label.user') });
}
} catch (error) {
showErrorToast(
error as AxiosError,
jsonData['api-error-messages']['update-user-error']
t('server.entity-updating-error', { entity: t('label.user') })
);
} finally {
setIsLoading(false);
@ -254,7 +253,9 @@ const UserListV1: FC<UserListV1Props> = ({
<Col span={8}>
<Searchbar
removeMargin
placeholder="Search for user..."
placeholder={`${t('label.search-for-type', {
type: t('label.user'),
})}...`}
searchValue={searchTerm}
typingInterval={500}
onSearch={onSearch}

View File

@ -171,12 +171,12 @@ const Users = ({
if (response.data) {
setTeams(response.data);
} else {
throw jsonData['api-error-messages']['unexpected-server-response'];
throw t('server.unexpected-response');
}
} catch (error) {
showErrorToast(
error as AxiosError,
jsonData['api-error-messages']['fetch-teams-error']
t('server.entity-fetch-error', { entity: t('label.team') })
);
} finally {
setIsTeamsLoading(false);
@ -268,7 +268,7 @@ const Users = ({
await changePassword(sendData);
setIsChangePassword(false);
showSuccessToast(
jsonData['api-success-messages']['update-password-success']
t('server.update-entity-success', { entity: t('label.password') })
);
} catch (err) {
showErrorToast(err as AxiosError);
@ -292,7 +292,7 @@ const Users = ({
data-testid="displayName"
id="displayName"
name="displayName"
placeholder="displayName"
placeholder={t('label.display-name')}
type="text"
value={displayName}
onChange={onDisplayNameChange}
@ -321,7 +321,8 @@ const Users = ({
) : (
<Fragment>
<span className="tw-text-base tw-font-medium tw-mr-2 tw-overflow-auto">
{userData.displayName || 'Add display name'}
{userData.displayName ||
t('label.add-entity', { entity: t('label.display-name') })}
</span>
<button
className="tw-ml-2 focus:tw-outline-none"

View File

@ -30,7 +30,7 @@ import SVGIcons, { Icons } from '../../utils/SvgUtils';
export const userPageFilterList = [
{
name: 'My Data',
name: t('label.my-data'),
value: 'OWNER',
icon: (
<SVGIcons
@ -42,7 +42,7 @@ export const userPageFilterList = [
),
},
{
name: 'Mentions',
name: t('label.mention-plural'),
value: 'MENTIONS',
icon: (
<SVGIcons
@ -54,7 +54,7 @@ export const userPageFilterList = [
),
},
{
name: 'Following',
name: t('label.following'),
value: 'FOLLOWS',
icon: (
<SVGIcons

View File

@ -99,14 +99,14 @@ const Description: FC<DescriptionProps> = ({
destroyTooltipOnHide
content={
hasDescription
? 'Request update description'
: 'Request description'
? t('message.request-update-description')
: t('message.request-description')
}
overlayClassName="ant-popover-request-description"
trigger="hover"
zIndex={9999}>
<SVGIcons
alt="request-description"
alt={t('message.request-description')}
icon={Icons.REQUEST}
width="16px"
/>

View File

@ -65,14 +65,18 @@ const DescriptionV1 = ({
const editButton = () => {
return !isReadOnly ? (
<Tooltip
title={hasEditAccess ? 'Edit Description' : NO_PERMISSION_FOR_ACTION}>
title={
hasEditAccess
? t('label.edit-entity', { entity: t('label.description') })
: NO_PERMISSION_FOR_ACTION
}>
<button
className="focus:tw-outline-none tw-text-primary"
data-testid="edit-description"
disabled={!hasEditAccess}
onClick={onDescriptionEdit}>
<SVGIcons
alt="edit"
alt={t('label.edit')}
icon={Icons.IC_EDIT_PRIMARY}
title="Edit"
width="16px"
@ -130,10 +134,10 @@ const DescriptionV1 = ({
onClick={() => onEntityFieldSelect?.(EntityField.DESCRIPTION)}>
<Tooltip
placement="top"
title="Request description"
title={t('message.request-description')}
trigger="hover">
<SVGIcons
alt="request-description"
alt={t('message.request-description')}
className="tw-mt-2"
icon={Icons.REQUEST}
/>

View File

@ -11,6 +11,7 @@
* limitations under the License.
*/
import i18n from 'utils/i18next/LocalUtil';
import MarkdownIcon from '../../../assets/svg/markdown.svg';
/**
@ -52,8 +53,8 @@ export const EDITOR_TOOLBAR_ITEMS = [
'code',
'codeblock',
{
name: 'Markdown Guide',
name: i18n.t('label.markdown-guide'),
el: markdownButton(),
tooltip: 'Markdown Guide',
tooltip: i18n.t('label.markdown-guide'),
},
];

View File

@ -48,10 +48,10 @@ const RecentlyViewed: FunctionComponent = () => {
return (
<EntityListWithAntd
entityList={data}
headerTextLabel="Recent Views"
headerTextLabel={t('label.recent-views')}
loading={isLoading}
noDataPlaceholder={<>{t('message.no-recently-viewed-date')}</>}
testIDText="Recently Viewed"
testIDText={t('label.recently-viewed')}
/>
);
};

View File

@ -61,7 +61,7 @@ export const tabsInfo: { [K in ExploreSearchIndex]: ExploreTabInfo } = {
selectedIcon: Icons.TABLE,
},
[SearchIndex.TOPIC]: {
label: t('label.topics'),
label: t('label.topic-plural'),
sortingFields: entitySortingFields,
sortField: INITIAL_SORT_FIELD,
path: 'topics',

View File

@ -248,6 +248,7 @@
"enable-partition": "Enable Partition",
"end-date": "End Date",
"end-date-time-zone": "End Date: ({{timeZone}})",
"end-point": "End point",
"endpoint": "Endpoint",
"endpoint-url": "Endpoint URL",
"endpoint-url-for-aws": "EndPoint URL for the AWS",
@ -303,6 +304,7 @@
"forgot-password": "Forgot Password",
"fqn-uppercase": "FQN",
"frequently-joined-column-plural": "Frequently Joined Columns",
"frequently-joined-tables": "Frequently Joined Tables",
"from-lowercase": "from",
"full-name": "Full name",
"function": "Function",
@ -388,9 +390,11 @@
"login": "Login",
"logout": "Logout",
"major": "Major",
"manage-entity": "Manage {{entity}}",
"manage-rule": "Manage Rule",
"mark-all-deleted-table-plural": "Mark All Deleted Tables",
"mark-deleted-table-plural": "Mark Deleted Tables",
"markdown-guide": "Markdown Guide",
"matches": "Matches",
"max": "Max",
"maximum-size-lowercase": "maximum size",
@ -534,6 +538,8 @@
"receiver-plural": "Receivers",
"recent-run-plural": "Recent Runs",
"recent-search-term-plural": "Recent Search Terms",
"recent-views": "Recent Views",
"recently-viewed": "Recently Viewed",
"recreate-index-plural": "Recreate Indexes",
"refer-to-our": "Refer to our",
"reference-plural": "References",
@ -542,6 +548,7 @@
"region-name": "Region Name",
"registry": "Registry",
"related-term-plural": "Related Terms",
"related-terms": "Related Terms",
"remove": "Remove",
"remove-edge": "Remove edge",
"remove-entity": "Remove {{entity}}",
@ -671,8 +678,10 @@
"task": "Task",
"task-entity": "Task {{entity}}",
"task-lowercase": "task",
"task-name": "Task name",
"task-plural": "Tasks",
"task-title": "Task #{{title}}",
"task-type": "Task type",
"team": "Team",
"team-plural": "Teams",
"team-plural-lowercase": "teams",
@ -681,12 +690,14 @@
"term-lowercase": "term",
"term-plural": "Terms",
"test": "Test",
"test-case": "Test case",
"test-connection": "Test Connection",
"test-entity": "Test {{entity}}",
"test-plural": "Tests",
"test-suite": "Test Suite",
"test-suite-plural": "Test Suites",
"test-suite-status": "Test Suite Status",
"test-type": "Test type",
"testing-connection": "Testing Connection",
"tests-summary": "Tests Summary",
"thread": "Thread",
@ -773,6 +784,7 @@
"action-has-been-done-but-deploy-successfully": "has been {{action}} and deployed successfully",
"action-has-been-done-but-failed-to-deploy": "has been {{action}}, but failed to deploy",
"active-users": "Display the number of active users.",
"add-entity-test": "Add {{entity}} test",
"add-kpi-message": "Identify the Key Performance Indicators (KPI) that best reflect the health of your data assets. Review your data assets based on Description, Ownership, and Tier. Define your target metrics in absolute or percentage to track your progress. Finally, set a start and end date to achieve your data goals.",
"add-new-service-description": "Choose from the range of services that OpenMetadata integrates with. To add a new service, start by selecting a Service Category (Database, Messaging, Dashboard, or Pipeline). From the list of available services, select the one you'd want to integrate with.",
"add-policy-message": "Policies are assigned to teams. In OpenMetadata, a policy is a collection of rules, which define access based on certain conditions. We support rich SpEL (Spring Expression Language) based conditions. All the operations supported by an entity are published. Use these fine grained operations to define the conditional rules for each policy. Create well-defined policies based on conditional rules to build rich access control roles.",
@ -846,14 +858,18 @@
"enable-column-profile": "Enable column profile",
"enable-debug-logging": "Enable debug logging",
"enables-end-to-end-metadata-management": "Enables end-to-end metadata management with data discovery, data quality, observability, and people collaboration",
"endpoint-should-be-valid": "Endpoint should be valid URL.",
"ensure-airflow-set-up-correctly-before-heading-to-ingest-metadata": "Ensure that you have Airflow set up correctly before heading to ingest metadata.",
"enter-a-field": "Enter a {{field}}",
"enter-column-description": "Enter column description",
"enter-comma-separated-field": "Enter comma(,) separated {{field}}",
"enter-comma-separated-keywords": "Enter comma separated keywords",
"enter-comma-separated-term": "Enter comma separated term",
"enter-display-name": "Enter display name",
"enter-feature-description": "Enter feature description",
"enter-interval": "Enter interval",
"enter-test-case-name": "Enter test case name",
"enter-test-suite-name": "Enter test suite name",
"enter-your-registered-email": "Enter your registered email to receive password reset link",
"entity-already-exists": "{{entity}} already exists.",
"entity-is-not-valid": "{{entity}} is not valid",
@ -979,10 +995,12 @@
"profile-sample-row-count-message": " Set the Profiler value as row count",
"profiler-ingestion-description": "A profiler workflow can be configured and deployed after a metadata ingestion has been set up. Multiple profiler pipelines can be set up for the same database service. The pipeline feeds the Profiler tab of the Table entity, and also runs the tests configured for that entity. Add a Name, FQN, and define the filter pattern to start.",
"profiler-timeout-seconds-message": "For the Profiler, add the duration in seconds for timeout (optional). The profiler will wait for any pending queries to be executed, or will terminate them once it reaches the timeout.",
"queries-result-test": "Queries returning 1 or more rows will result in the test failing.",
"query-log-duration-message": "Configuration to tune how far we want to look back in query logs to process usage data.",
"reacted-with-emoji": "reacted with {{type}} emoji",
"redirecting-to-home-page": "Redirecting to the home page",
"remove-edge-between-source-and-target": "Are you sure you want to remove the edge between \"{{sourceDisplayName}} and {{targetDisplayName}}\"?.",
"remove-lineage-edge": "Remove lineage edge",
"request-description": "Request description",
"request-update-description": "Request update description",
"reset-link-has-been-sent": "Reset link has been sent to your email",
@ -1038,6 +1056,7 @@
"view-deleted-teams": "View All the Deleted Teams, which come under this Team.",
"view-sample-data": "To view Sample Data, run the Profiler Ingestion. Please refer to this doc to schedule the",
"view-sample-data-message": "To view Sample Data, run the MetaData Ingestion. Please refer to this doc to schedule the",
"view-test-suite": "View test suite",
"viewing-older-version": "Viewing older version \n Go to latest to update details",
"webhook-listing-message": "The webhook allows external services to be notified of the metadata change events happening in your organization through APIs. Register callback URLs with webhook integration to receive metadata event notifications. You can add, list, update, and delete webhooks.",
"webhook-type-listing-message": "Provide timely updates to the producers and consumers of metadata via {{webhookType}} notifications. Use {{webhookType}} webhooks to send notifications regarding the metadata change events in your organization through APIs. You can add, list, update, and delete these webhooks.",
@ -1062,6 +1081,7 @@
"entity-updating-error": "Error while updating {{entity}}",
"feed-post-error": "Error while posting the message!",
"fetch-entity-permissions-error": "Unable to get permission for {{entity}}.",
"fetch-suggestions-error": "Error while fetching suggestions!",
"fetch-tags-category-error": "Error while fetching tags category!",
"fetch-updated-conversation-error": "Error while fetching updated conversation!",
"ingestion-workflow-operation-error": "Error while {{operation}} ingestion workflow {{displayName}}",

View File

@ -109,7 +109,7 @@ const GlossaryLeftPanel = ({ glossaries }: GlossaryLeftPanelProps) => {
<Tooltip
title={
createGlossaryPermission
? t('label.add-glossary')
? t('label.add-entity', { entity: t('label.glossary') })
: t('message.no-permission-for-action')
}>
<Button
@ -119,7 +119,7 @@ const GlossaryLeftPanel = ({ glossaries }: GlossaryLeftPanelProps) => {
disabled={!createGlossaryPermission}
icon={<PlusIcon className="anticon" />}
onClick={handleAddGlossaryClick}>
{t('label.add-glossary')}
{t('label.add-entity', { entity: t('label.glossary') })}
</Button>
</Tooltip>
</Col>