Skip to content

Commit 8baf489

Browse files
Shrabanti PaulShrabanti Paul
authored andcommitted
cherry pick user dropdown translation issue
1 parent 1044f08 commit 8baf489

10 files changed

Lines changed: 176 additions & 18 deletions

File tree

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright 2024 Collate.
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
import { Browser, expect, Page, test as base } from '@playwright/test';
14+
import { redirectToHomePage } from '../../utils/common';
15+
16+
const test = base.extend<{ germanLocalePage: Page }>({
17+
germanLocalePage: async ({ browser }: { browser: Browser }, use) => {
18+
const context = await browser.newContext({
19+
locale: 'de-DE',
20+
storageState: 'playwright/.auth/admin.json',
21+
});
22+
const page = await context.newPage();
23+
await use(page);
24+
await context.close();
25+
},
26+
});
27+
28+
test.describe('Language Override Tests', () => {
29+
test('App language should override browser language on landing page and user dropdown', async ({
30+
germanLocalePage,
31+
}) => {
32+
test.slow(true);
33+
34+
await redirectToHomePage(germanLocalePage);
35+
36+
await germanLocalePage
37+
.getByTestId('language-selector-button')
38+
.waitFor({ state: 'visible' });
39+
await germanLocalePage.getByTestId('language-selector-button').click();
40+
await germanLocalePage.waitForSelector('.ant-dropdown', {
41+
state: 'visible',
42+
});
43+
await germanLocalePage.getByText('EN', { exact: true }).click();
44+
await germanLocalePage.waitForLoadState('networkidle');
45+
46+
await germanLocalePage.locator('[data-testid="dropdown-profile"]').click();
47+
await germanLocalePage.waitForSelector('[role="menu"].profile-dropdown', {
48+
state: 'visible',
49+
});
50+
51+
const profileDropdown = germanLocalePage.locator(
52+
'[role="menu"].profile-dropdown'
53+
);
54+
55+
await expect(
56+
profileDropdown.getByText('View Profile', { exact: true })
57+
).toBeVisible();
58+
await expect(
59+
profileDropdown.getByText('Switch Persona', { exact: true })
60+
).toBeVisible();
61+
await expect(
62+
profileDropdown.getByText('Roles', { exact: true })
63+
).toBeVisible();
64+
await expect(
65+
profileDropdown.getByText('Inherited Roles', { exact: true })
66+
).toBeVisible();
67+
await expect(
68+
profileDropdown.getByText('Logout', { exact: true })
69+
).toBeVisible();
70+
71+
await expect(
72+
profileDropdown.getByText('Profil anzeigen', { exact: true })
73+
).not.toBeVisible();
74+
await expect(
75+
profileDropdown.getByText('Persona wechseln', { exact: true })
76+
).not.toBeVisible();
77+
await expect(
78+
profileDropdown.getByText('Rollen', { exact: true })
79+
).not.toBeVisible();
80+
await expect(
81+
profileDropdown.getByText('Geerbte Rollen', { exact: true })
82+
).not.toBeVisible();
83+
await expect(
84+
profileDropdown.getByText('Abmelden', { exact: true })
85+
).not.toBeVisible();
86+
});
87+
});

openmetadata-ui/src/main/resources/ui/src/components/NavBar/NavBar.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,18 +175,20 @@ const NavBar = () => {
175175
if (visible) {
176176
switch (activeTab) {
177177
case 'Task':
178-
hasTaskNotification &&
178+
if (hasTaskNotification) {
179179
setTimeout(() => {
180180
handleTaskNotificationRead();
181181
}, NOTIFICATION_READ_TIMER);
182+
}
182183

183184
break;
184185

185186
case 'Conversation':
186-
hasMentionNotification &&
187+
if (hasMentionNotification) {
187188
setTimeout(() => {
188189
handleMentionsNotificationRead();
189190
}, NOTIFICATION_READ_TIMER);
191+
}
190192

191193
break;
192194
}
@@ -518,6 +520,7 @@ const NavBar = () => {
518520
trigger={['click']}>
519521
<Button
520522
className="flex-center gap-2 p-x-xs font-medium"
523+
data-testid="language-selector-button"
521524
type="text">
522525
{language ? upperCase(language.split('-')[0]) : ''}{' '}
523526
<DropDownIcon width={12} />

openmetadata-ui/src/main/resources/ui/src/components/NotificationBox/NotificationBox.component.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,11 @@ const NotificationBox = ({
151151

152152
if (hasTaskNotification || hasMentionNotification) {
153153
setTimeout(() => {
154-
key === NotificationTabsKey.TASK
155-
? onMarkTaskNotificationRead()
156-
: onMarkMentionsNotificationRead();
154+
if (key === NotificationTabsKey.TASK) {
155+
onMarkTaskNotificationRead();
156+
} else {
157+
onMarkMentionsNotificationRead();
158+
}
157159
}, NOTIFICATION_READ_TIMER);
158160
}
159161
},
@@ -212,7 +214,7 @@ const NotificationBox = ({
212214
size="small"
213215
/>
214216
),
215-
[notifications, notificationDropDownList, viewAllPath]
217+
[notifications, notificationDropDownList, viewAllPath, t]
216218
);
217219

218220
return (

openmetadata-ui/src/main/resources/ui/src/components/NotificationBox/NotificationFeedCard.component.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ const NotificationFeedCard: FC<NotificationFeedProp> = ({
8484
</Link>
8585
</>
8686
);
87-
}, [entityType, task, taskDetails]);
87+
}, [entityType, task, taskDetails, t]);
8888

8989
const entityName = useMemo(() => {
9090
return task?.entityRef

openmetadata-ui/src/main/resources/ui/src/components/Settings/CustomProperty/CustomPropertyTable.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ export const CustomPropertyTable: FC<CustomPropertyTableProp> = ({
263263
),
264264
},
265265
],
266-
[hasAccess]
266+
[hasAccess, t]
267267
);
268268

269269
return (

openmetadata-ui/src/main/resources/ui/src/components/Settings/Team/TeamDetails/UserTab/UserTab.component.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ export const UserTab = ({
245245
return tabColumns.filter((column) =>
246246
column.key === 'actions' ? !isTeamDeleted : true
247247
);
248-
}, [handleRemoveClick, editUserPermission, isTeamDeleted]);
248+
}, [handleRemoveClick, editUserPermission, isTeamDeleted, t]);
249249

250250
const sortedUser = useMemo(() => orderBy(users, ['name'], 'asc'), [users]);
251251

@@ -307,7 +307,7 @@ export const UserTab = ({
307307
}
308308

309309
return option;
310-
}, [handleUserExportClick, handleImportClick, permission]);
310+
}, [handleUserExportClick, handleImportClick, permission, t]);
311311

312312
const handleRemoveUser = () => {
313313
if (deletingUser?.id) {
@@ -325,7 +325,7 @@ export const UserTab = ({
325325
return permission.EditAll
326326
? t('label.add-new-entity', { entity: t('label.user') })
327327
: t('message.no-permission-for-action');
328-
}, [permission, isTeamDeleted]);
328+
}, [permission, isTeamDeleted, t]);
329329

330330
if (isEmpty(users) && !searchText && !isLoading) {
331331
return isGroupType ? (

openmetadata-ui/src/main/resources/ui/src/components/Settings/Team/TeamImportResult/TeamImportResult.component.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ export const TeamImportResult = ({
187187
];
188188

189189
return data;
190-
}, [parsedRecords]);
190+
}, [parsedRecords, t]);
191191

192192
const parseCsvFile = () => {
193193
if (csvImportResult.importResultsCsv) {

openmetadata-ui/src/main/resources/ui/src/components/Settings/Team/UserImportResult/UserImportResult.component.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ export const UserImportResult = ({
171171
];
172172

173173
return data;
174-
}, [parsedRecords]);
174+
}, [parsedRecords, t]);
175175

176176
const parseCsvFile = () => {
177177
if (csvImportResult.importResultsCsv) {

openmetadata-ui/src/main/resources/ui/src/components/Settings/Users/UserProfileIcon/UserProfileIcon.component.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ export const UserProfileIcon = () => {
165165
</div>
166166
);
167167
},
168-
[handleSelectedPersonaChange, selectedPersona, defaultPersona]
168+
[handleSelectedPersonaChange, selectedPersona, defaultPersona, t]
169169
);
170170

171171
const teamLabelRenderer = useCallback(
@@ -197,7 +197,7 @@ export const UserProfileIcon = () => {
197197
{count} {t('label.more')}
198198
</Link>
199199
),
200-
[currentUser]
200+
[currentUser, t]
201201
);
202202

203203
const handleCloseDropdown = useCallback(() => {
@@ -377,6 +377,9 @@ export const UserProfileIcon = () => {
377377
roles,
378378
personas,
379379
showAllPersona,
380+
sortedPersonas,
381+
inheritedRoles,
382+
t,
380383
]
381384
);
382385

openmetadata-ui/src/main/resources/ui/src/components/Settings/Users/UserProfileIcon/UserProfileIcon.test.tsx

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,45 @@ jest.mock('../../../../hooks/authHooks', () => ({
2626
onLogoutHandler: jest.fn(),
2727
}),
2828
}));
29+
const translationState = {
30+
language: 'en',
31+
};
32+
33+
const germanTranslations: Record<string, string> = {
34+
'label.role-plural': 'Rollen',
35+
'label.team-plural': 'Teams',
36+
'label.logout': 'Abmelden',
37+
'label.switch-persona': 'Persona wechseln',
38+
'label.inherited-role-plural': 'Geerbte Rollen',
39+
'label.default': 'Standard',
40+
'label.more': 'mehr',
41+
};
42+
43+
const mockChangeLanguage = jest.fn((lng: string) => {
44+
translationState.language = lng;
45+
});
46+
47+
const mockI18n = {
48+
changeLanguage: mockChangeLanguage,
49+
language: translationState.language,
50+
};
51+
2952
jest.mock('react-i18next', () => ({
30-
useTranslation: () => ({
31-
t: (key: string) => key,
32-
}),
53+
useTranslation: () => {
54+
const currentLanguage = translationState.language;
55+
const getTranslation = (key: string) => {
56+
if (currentLanguage === 'de') {
57+
return germanTranslations[key] || key;
58+
}
59+
60+
return key;
61+
};
62+
63+
return {
64+
t: getTranslation,
65+
i18n: mockI18n,
66+
};
67+
},
3368
}));
3469

3570
const mockPersonas: EntityReference[] = [
@@ -95,6 +130,7 @@ describe('UserProfileIcon', () => {
95130
beforeEach(() => {
96131
jest.clearAllMocks();
97132
mockUseApplicationStore.mockReturnValue(createMockStoreData());
133+
translationState.language = 'en';
98134
});
99135

100136
const openDropdown = () => {
@@ -196,4 +232,31 @@ describe('UserProfileIcon', () => {
196232
expect(screen.queryByTestId('default-persona-tag')).not.toBeInTheDocument();
197233
expect(screen.getAllByRole('radio').length).toBeGreaterThan(0);
198234
});
235+
236+
it('should update dropdown labels when language changes', async () => {
237+
const { rerender } = render(
238+
<MockWrapper>
239+
<UserProfileIcon />
240+
</MockWrapper>
241+
);
242+
243+
openDropdown();
244+
await screen.findByText('label.switch-persona');
245+
246+
expect(screen.getByText('label.role-plural')).toBeInTheDocument();
247+
expect(screen.getByText('label.team-plural')).toBeInTheDocument();
248+
expect(screen.getByText('label.logout')).toBeInTheDocument();
249+
250+
mockChangeLanguage('de');
251+
rerender(
252+
<MockWrapper>
253+
<UserProfileIcon />
254+
</MockWrapper>
255+
);
256+
257+
expect(screen.getByText('Persona wechseln')).toBeInTheDocument();
258+
expect(screen.getByText('Rollen')).toBeInTheDocument();
259+
expect(screen.getByText('Teams')).toBeInTheDocument();
260+
expect(screen.getByText('Abmelden')).toBeInTheDocument();
261+
});
199262
});

0 commit comments

Comments
 (0)