Skip to content

Commit 42dc838

Browse files
refactor(i18n): do not translate ingestion source/connector display names
Source/connector display names (Athena, BigQuery, Confluence, …) are proper nouns and must stay identical across all languages, so they should not be extracted for translation. Revert the displayName i18n extraction while keeping descriptions and category labels translatable: - Drop all sources.*.displayName keys from ingest.sources.json - Stop calling t() for displayName in useIngestionSources (v2) and IngestionSourceBuilderModal (v1); display names pass through raw from sources.json - Add a .*[Dd]isplayName$ exclusion to the i18next/no-literal-string enforcement so connector display names are never flagged for translation - Remove the sources.json entries from translated-files.txt - Update tests/comments to reflect displayName passthrough Co-authored-by: Ben Blazke <benjiaming@users.noreply.github.com>
1 parent 6bcf3e8 commit 42dc838

7 files changed

Lines changed: 26 additions & 84 deletions

File tree

datahub-web-react/.eslintrc.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ const PATTERNS_TO_EXCLUDE_UNTRANSLATABLE_ATTRIBUTES = [
9898
'rel',
9999
'href',
100100
'name',
101+
// Source/connector display names are proper nouns (Athena, BigQuery, Confluence, …) and
102+
// must never be translated. Exempt any `displayName`/`*DisplayName` property or attribute.
103+
'.*[Dd]isplayName$',
101104
'form',
102105
'entityTypeName',
103106
'autoComplete',

datahub-web-react/src/app/ingest/source/builder/IngestionSourceBuilderModal.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ function resolveSource(source: SourceConfig): SourceConfig {
1818
const ns = 'ingest.sources';
1919
return {
2020
...source,
21-
displayName: i18next.t(`sources.${key}.displayName`, { ns, defaultValue: source.displayName }),
21+
// displayName intentionally NOT translated — source/connector display names are proper
22+
// nouns (Athena, BigQuery, Confluence, …) and must stay identical across all languages.
2223
description: source.description
2324
? i18next.t(`sources.${key}.description`, { ns, defaultValue: source.description })
2425
: source.description,

datahub-web-react/src/app/ingestV2/source/builder/__tests__/useIngestionSources.test.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,25 @@ import i18n from 'i18next';
44
import { useIngestionSources } from '@app/ingestV2/source/builder/useIngestionSources';
55

66
describe('useIngestionSources', () => {
7-
describe('toSourceKey transform (via hook output)', () => {
8-
it('converts simple names unchanged', () => {
7+
describe('displayName field', () => {
8+
// Display names are proper nouns (Athena, BigQuery, …) and must NOT be translated —
9+
// they always pass through unchanged from sources.json.
10+
it('passes simple display names through unchanged', () => {
911
const { result } = renderHook(() => useIngestionSources());
1012
const bigquery = result.current.ingestionSources.find((s) => s.name === 'bigquery');
1113
expect(bigquery).toBeDefined();
1214
expect(bigquery!.displayName).toBe('BigQuery');
1315
});
1416

15-
it('converts kebab-case names to camelCase for key lookup', () => {
17+
it('passes display names of kebab-case sources through unchanged', () => {
1618
const { result } = renderHook(() => useIngestionSources());
17-
// dbt-cloud → dbtCloud; the translation key sources.dbtCloud.displayName must resolve
1819
const dbtCloud = result.current.ingestionSources.find((s) => s.name === 'dbt-cloud');
1920
expect(dbtCloud).toBeDefined();
2021
expect(dbtCloud!.displayName).toBe('dbt Cloud');
2122
});
2223

23-
it('converts multi-segment kebab names correctly', () => {
24+
it('passes display names of multi-segment kebab sources through unchanged', () => {
2425
const { result } = renderHook(() => useIngestionSources());
25-
// matillion-dpc → matillionDpc
2626
const matillion = result.current.ingestionSources.find((s) => s.name === 'matillion-dpc');
2727
expect(matillion).toBeDefined();
2828
expect(matillion!.displayName).toBe('Matillion');
@@ -36,9 +36,16 @@ describe('useIngestionSources', () => {
3636
expect(snowflake!.description).toContain('Snowflake');
3737
});
3838

39+
it('resolves description for kebab-case sources via camelCase key lookup', () => {
40+
const { result } = renderHook(() => useIngestionSources());
41+
// dbt-cloud → dbtCloud; the translation key sources.dbtCloud.description must resolve
42+
const dbtCloud = result.current.ingestionSources.find((s) => s.name === 'dbt-cloud');
43+
expect(dbtCloud!.description).toContain('dbt cloud');
44+
});
45+
3946
it('resolves description for all sources that have one', () => {
4047
const { result } = renderHook(() => useIngestionSources());
41-
// Every source in the v2 sources.json has a description — none should be lost
48+
// No source that has a description should lose it during resolution
4249
const missing = result.current.ingestionSources.filter((s) => s.description === null);
4350
expect(missing).toHaveLength(0);
4451
});
@@ -80,15 +87,15 @@ describe('useIngestionSources', () => {
8087
describe('language reactivity', () => {
8188
it('re-computes when i18n language changes', async () => {
8289
const { result, rerender } = renderHook(() => useIngestionSources());
83-
const initialDisplayName = result.current.ingestionSources.find((s) => s.name === 'bigquery')!.displayName;
90+
const initialDescription = result.current.ingestionSources.find((s) => s.name === 'bigquery')!.description;
8491

8592
await i18n.changeLanguage('de');
8693
rerender();
8794

8895
// After language change the hook should re-run. In tests the DE locale isn't
8996
// loaded so it falls back to EN — but the memo must have re-evaluated.
90-
const afterDisplayName = result.current.ingestionSources.find((s) => s.name === 'bigquery')!.displayName;
91-
expect(afterDisplayName).toBe(initialDisplayName);
97+
const afterDescription = result.current.ingestionSources.find((s) => s.name === 'bigquery')!.description;
98+
expect(afterDescription).toBe(initialDescription);
9299

93100
// Restore
94101
await i18n.changeLanguage('en');

datahub-web-react/src/app/ingestV2/source/builder/useIngestionSources.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ function resolveSource(source: SourceConfig, t: TFunction<'ingest.sources'>): So
1313
const key = toSourceKey(source.name);
1414
return {
1515
...source,
16-
displayName: t(`sources.${key}.displayName`, { defaultValue: source.displayName }),
16+
// displayName intentionally NOT translated — source/connector display names are proper
17+
// nouns (Athena, BigQuery, Confluence, …) and must stay identical across all languages.
1718
description: source.description
1819
? t(`sources.${key}.description`, { defaultValue: source.description })
1920
: source.description,

datahub-web-react/src/app/ingestV2/source/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import {
3636

3737
const CUSTOM_SOURCE_NAME = 'custom';
3838
/* untranslated-text -- used programmatically as a source-type discriminator, not rendered as UI copy.
39-
Must match the resolved displayName of the custom source (sources.custom.displayName in ingest.sources.json). */
39+
Must match the displayName of the custom source in sources.json. */
4040
export const CUSTOM_SOURCE_DISPLAY_NAME = 'Other';
4141

4242
export const getSourceConfigs = (ingestionSources: SourceConfig[], sourceType: string) => {

datahub-web-react/src/i18n/locales/en/ingest.sources.json

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -11,139 +11,71 @@
1111
"category.mlPlatforms": "ML Platforms",
1212
"category.orchestration": "Orchestration",
1313
"category.queryEngine": "Query Engine",
14-
"sources.aerospike.displayName": "Aerospike",
1514
"sources.airbyte.description": "Import Connections, Sources, Destinations, and lineage from Airbyte (OSS and Cloud).",
16-
"sources.airbyte.displayName": "Airbyte",
1715
"sources.airflow.description": "Import DAGs, Tasks, and lineage from Airflow.",
18-
"sources.airflow.displayName": "Airflow",
1916
"sources.athena.description": "Import Schemas, Tables, Views, and lineage to S3 from Athena.",
20-
"sources.athena.displayName": "Athena",
2117
"sources.azureAd.description": "Import Users and Groups from Azure Active Directory.",
22-
"sources.azureAd.displayName": "Azure AD",
2318
"sources.bigquery.description": "Import Projects, Datasets, Tables, Views, lineage, queries, and statistics from BigQuery.",
24-
"sources.bigquery.displayName": "BigQuery",
2519
"sources.cassandra.description": "Import Tables, Keyspaces, and column schemas from Cassandra.",
26-
"sources.cassandra.displayName": "CassandraDB",
2720
"sources.clickhouse.description": "Import Tables, Views, Materialized Views, Dictionaries, statistics, queries, and lineage from ClickHouse.",
28-
"sources.clickhouse.displayName": "ClickHouse",
2921
"sources.cockroachdb.description": "Import Databases, Schemas, Tables, Views, statistics and lineage from CockroachDB.",
30-
"sources.cockroachdb.displayName": "CockroachDb",
3122
"sources.confluence.description": "Import pages and spaces from Confluence as Documents with semantic search support.",
32-
"sources.confluence.displayName": "Confluence",
3323
"sources.csvEnricher.description": "Import metadata from a formatted CSV.",
34-
"sources.csvEnricher.displayName": "CSV",
3524
"sources.custom.description": "Configure a custom recipe using YAML.",
36-
"sources.custom.displayName": "Other",
3725
"sources.dagster.description": "Import Pipelines, Jobs, Assets, and lineage from Dagster.",
38-
"sources.dagster.displayName": "Dagster",
3926
"sources.databricks.description": "Import Metastores, Schemas, Tables, lineage, queries, and statistics from Databricks Unity Catalog.",
40-
"sources.databricks.displayName": "Databricks",
4127
"sources.dbt.description": "Import Sources, Seeds, Models, Snapshots, Tests, and lineage from dbt.",
42-
"sources.dbt.displayName": "dbt",
4328
"sources.dbtCloud.description": "Import Sources, Seeds, Models, Snapshots, Tests, and lineage from dbt cloud.",
44-
"sources.dbtCloud.displayName": "dbt Cloud",
4529
"sources.doris.description": "Import Tables, Views, Databases, Schemas, and statistics from Apache Doris.",
46-
"sources.doris.displayName": "Apache Doris",
4730
"sources.dremio.description": "Import Spaces, Sources, Tables and statistics from Dremio.",
48-
"sources.dremio.displayName": "Dremio",
4931
"sources.druid.description": "Import Databases, Schemas, Tables, statistics, and lineage from Druid.",
50-
"sources.druid.displayName": "Druid",
5132
"sources.dynamodb.description": "Import Tables from DynamoDB.",
52-
"sources.dynamodb.displayName": "DynamoDB",
5333
"sources.feast.description": "Import Feature Tables, Features, Entities, and Data Sources from Feast.",
54-
"sources.feast.displayName": "Feast",
5534
"sources.fivetran.description": "Import Connectors, Destinations, Sync History, Users, and lineage from FiveTran.",
56-
"sources.fivetran.displayName": "Fivetran",
5735
"sources.flink.description": "Import jobs, lineage, and run history from Flink.",
58-
"sources.flink.displayName": "Flink",
5936
"sources.glue.description": "Import Tables, Databases, Jobs, statistics, and lineage to S3 from AWS Glue.",
60-
"sources.glue.displayName": "Glue",
6137
"sources.grafana.description": "Import Dashboards, Charts, and Data sources from Grafana.",
62-
"sources.grafana.displayName": "Grafana",
6338
"sources.hex.description": "Import Projects, Components, lineage, run history, and AI context documents from Hex.",
64-
"sources.hex.displayName": "Hex",
6539
"sources.hive.description": "Import Tables, Views, Databases, Schemas, and statistics from Hive.",
66-
"sources.hive.displayName": "Hive",
6740
"sources.iceberg.description": "Ingest databases and tables from any Iceberg catalog implementation.",
68-
"sources.iceberg.displayName": "Iceberg",
6941
"sources.informatica.description": "Import Mappings, Taskflows, lineage, ownership, and tags from Informatica Intelligent Data Management Cloud (IDMC).",
70-
"sources.informatica.displayName": "Informatica",
7142
"sources.kafka.description": "Import streaming topics from Kafka.",
72-
"sources.kafka.displayName": "Kafka",
7343
"sources.looker.description": "Import Models, Explores, Views, Looks, Dashboards, and lineage from Looker.",
74-
"sources.looker.displayName": "Looker",
7544
"sources.lookml.description": "Import Models, Explores, Views, Looks, Dashboards, and lineage from LookML files.",
76-
"sources.lookml.displayName": "LookML",
7745
"sources.mariadb.description": "Import Tables, Views, Databases, Schemas, and statistics from MariaDB.",
78-
"sources.mariadb.displayName": "MariaDB",
7946
"sources.matillionDpc.description": "Import Pipelines, Streaming Pipelines, Projects, Environments, and lineage from Matillion Data Productivity Cloud.",
80-
"sources.matillionDpc.displayName": "Matillion",
8147
"sources.metabase.description": "Import Collections, Dashboards, and Charts from Metabase.",
82-
"sources.metabase.displayName": "Metabase",
8348
"sources.mlflow.description": "Import Registered Models, Model Versions, and Model Stages from MLflow.",
84-
"sources.mlflow.displayName": "MLflow",
8549
"sources.mode.description": "Import Reports, Charts, and lineage from Mode.",
86-
"sources.mode.displayName": "Mode",
8750
"sources.mongodb.description": "Import Databases and Collections from MongoDB.",
88-
"sources.mongodb.displayName": "MongoDB",
8951
"sources.mssql.description": "Import Tables, Views, Databases, Schemas, and statistics from SQL Server.",
90-
"sources.mssql.displayName": "Microsoft SQL Server",
9152
"sources.mysql.description": "Import Tables, Views, Databases, Schemas, and statistics from MySQL.",
92-
"sources.mysql.displayName": "MySQL",
9353
"sources.neo4j.description": "Import Nodes and Relationships from Neo4j.",
94-
"sources.neo4j.displayName": "Neo4j",
9554
"sources.notion.description": "Import pages from Notion as Documents.",
96-
"sources.notion.displayName": "Notion",
9755
"sources.okta.description": "Import Users and Groups from Okta.",
98-
"sources.okta.displayName": "Okta",
9956
"sources.omni.description": "Import Dashboards, Charts, and lineage from Omni.",
100-
"sources.omni.displayName": "Omni",
10157
"sources.oracle.description": "Import Databases, Schemas, Tables, Views, statistics, and lineage from Oracle.",
102-
"sources.oracle.displayName": "Oracle",
10358
"sources.postgres.description": "Import Tables, Views, Databases, Schemas, and statistics from Postgres.",
104-
"sources.postgres.displayName": "Postgres",
10559
"sources.powerbi.description": "Import Dashboards, Tiles, Datasets, and lineage from PowerBI.",
106-
"sources.powerbi.displayName": "PowerBI",
10760
"sources.preset.description": "Import Charts and Dashboards from Preset.",
108-
"sources.preset.displayName": "Preset",
10961
"sources.presto.description": "Import Tables, Databases, Schemas, and statistics from Presto.",
110-
"sources.presto.displayName": "Presto",
11162
"sources.qlikSense.description": "Import Spaces, Apps, Sheets, Charts, and Datasets from Qlik Sense.",
112-
"sources.qlikSense.displayName": "Qlik Sense",
11363
"sources.rdf.description": "Import glossary terms, term groups, and relationships from RDF/OWL ontologies (SKOS, Turtle, RDF/XML).",
114-
"sources.rdf.displayName": "RDF",
11564
"sources.redshift.description": "Import Tables, Views, Databases, Schemas, lineage, queries, and statistics from Redshift.",
116-
"sources.redshift.displayName": "Redshift",
11765
"sources.s3.description": "Import Datasets, Folders, S3 Buckets, and inferred schemas from S3.",
118-
"sources.s3.displayName": "S3",
11966
"sources.sac.description": "Import Stories, Applications and Models from SAP Analytics Cloud.",
120-
"sources.sac.displayName": "SAP Analytics Cloud",
12167
"sources.sagemaker.description": "Import Feature Groups, Models, Jobs, and lineage from SageMaker.",
122-
"sources.sagemaker.displayName": "SageMaker",
12368
"sources.sigma.description": "Import Workspaces, Workbooks, Pages, Elements, and lineage from Sigma Computing.",
124-
"sources.sigma.displayName": "Sigma",
12569
"sources.snaplogic.description": "Import lineage from SnapLogic.",
126-
"sources.snaplogic.displayName": "SnapLogic",
12770
"sources.snowflake.description": "Import Tables, Views, Databases, Schemas, lineage, queries, and statistics from Snowflake.",
128-
"sources.snowflake.displayName": "Snowflake",
12971
"sources.snowplow.description": "Import Schemas, Event Specifications, Tracking Plans, Pipelines, and Enrichments from Snowplow BDP.",
130-
"sources.snowplow.displayName": "Snowplow",
13172
"sources.spark.description": "Import Pipelines, Jobs, and column-level lineage from Spark.",
132-
"sources.spark.displayName": "Spark",
13373
"sources.starrocks.description": "Import Tables, Views, Databases, Schemas, and statistics from StarRocks.",
134-
"sources.starrocks.displayName": "StarRocks",
13574
"sources.superset.description": "Import Charts and Dashboards from Superset.",
136-
"sources.superset.displayName": "Superset",
13775
"sources.tableau.description": "Import Data Sources, Workbooks, Worksheets, Tags, Dashboards, and lineage from Tableau.",
138-
"sources.tableau.displayName": "Tableau",
13976
"sources.thoughtspot.description": "Import Liveboards, Answers, Visualizations, Worksheets, Tags, and column-level lineage from ThoughtSpot.",
140-
"sources.thoughtspot.displayName": "ThoughtSpot",
14177
"sources.timescaledb.description": "Import Tables, Views, Hypertables, Continuous Aggregates, and Background Jobs from TimescaleDB.",
142-
"sources.timescaledb.displayName": "TimescaleDB",
14378
"sources.trino.description": "Import Tables, Databases, Schemas, and statistics from Trino.",
144-
"sources.trino.displayName": "Trino",
14579
"sources.vertexai.description": "Import ML Models and lineage from Google Vertex AI.",
146-
"sources.vertexai.displayName": "Vertex AI",
147-
"sources.vertica.description": "Import Databases, Schemas, Tables, Views, Projections, statistics, and lineage from Vertica.",
148-
"sources.vertica.displayName": "Vertica"
80+
"sources.vertica.description": "Import Databases, Schemas, Tables, Views, Projections, statistics, and lineage from Vertica."
14981
}

datahub-web-react/translated-files.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,6 @@ src/app/identity/user/cacheUtils.ts
105105
src/app/identity/user/recommendedUsersLocalStorage.ts
106106
src/app/identity/user/useRoleSelector.ts
107107
src/app/identity/user/useUserTitle.ts
108-
src/app/ingest/source/builder/sources.json
109-
src/app/ingestV2/source/builder/sources.json
110108
src/app/ingestV2/*.{ts,tsx}
111109
src/app/ingestV2/executions/**/*.{ts,tsx}
112110
src/app/ingestV2/hooks/**/*.{ts,tsx}

0 commit comments

Comments
 (0)