From 018c5f1009e98e8688c8f06c8778c34c3583a9bb Mon Sep 17 00:00:00 2001 From: MartinSchoeler Date: Tue, 26 Aug 2025 14:04:40 -0300 Subject: [PATCH 1/3] fix: missing room type translation on useEncryptedRoomDescription --- .../actions/useEncryptedRoomDescription.tsx | 6 +++--- .../sidebar/header/hooks/useEncryptedRoomDescription.tsx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.tsx b/apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.tsx index 0cef06d391737..55f47e6acd8a9 100644 --- a/apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.tsx +++ b/apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.tsx @@ -11,13 +11,13 @@ export const useEncryptedRoomDescription = (roomType: 'channel' | 'team') => { return t('Not_available_for_this_workspace'); } if (!isPrivate) { - return t('Encrypted_not_available', { roomType }); + return t('Encrypted_not_available', { roomType: t(roomType) }); } if (broadcast) { - return t('Not_available_for_broadcast', { roomType }); + return t('Not_available_for_broadcast', { roomType: t(roomType) }); } if (e2eEnabledForPrivateByDefault || encrypted) { - return t('Encrypted_messages', { roomType }); + return t('Encrypted_messages', { roomType: t(roomType) }); } return t('Encrypted_messages_false'); }; diff --git a/apps/meteor/client/sidebar/header/hooks/useEncryptedRoomDescription.tsx b/apps/meteor/client/sidebar/header/hooks/useEncryptedRoomDescription.tsx index 0cef06d391737..55f47e6acd8a9 100644 --- a/apps/meteor/client/sidebar/header/hooks/useEncryptedRoomDescription.tsx +++ b/apps/meteor/client/sidebar/header/hooks/useEncryptedRoomDescription.tsx @@ -11,13 +11,13 @@ export const useEncryptedRoomDescription = (roomType: 'channel' | 'team') => { return t('Not_available_for_this_workspace'); } if (!isPrivate) { - return t('Encrypted_not_available', { roomType }); + return t('Encrypted_not_available', { roomType: t(roomType) }); } if (broadcast) { - return t('Not_available_for_broadcast', { roomType }); + return t('Not_available_for_broadcast', { roomType: t(roomType) }); } if (e2eEnabledForPrivateByDefault || encrypted) { - return t('Encrypted_messages', { roomType }); + return t('Encrypted_messages', { roomType: t(roomType) }); } return t('Encrypted_messages_false'); }; From 79634cb38f15dd17e2b96d112807fa7f9c4b39d0 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Tue, 26 Aug 2025 14:08:22 -0300 Subject: [PATCH 2/3] Create new-poems-compare.md --- .changeset/new-poems-compare.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/new-poems-compare.md diff --git a/.changeset/new-poems-compare.md b/.changeset/new-poems-compare.md new file mode 100644 index 0000000000000..84a83bc6e5cff --- /dev/null +++ b/.changeset/new-poems-compare.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixes a missing translation on the create channel/team modal From b21126fff4fada77680646160844791889b04cfd Mon Sep 17 00:00:00 2001 From: MartinSchoeler Date: Tue, 26 Aug 2025 16:37:07 -0300 Subject: [PATCH 3/3] test: add test --- .../useEncryptedRoomDescription.spec.tsx | 118 ++++++++++++++++++ .../src/MockedAppRootBuilder.tsx | 14 +++ 2 files changed, 132 insertions(+) create mode 100644 apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.spec.tsx diff --git a/apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.spec.tsx b/apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.spec.tsx new file mode 100644 index 0000000000000..1e70402c6552e --- /dev/null +++ b/apps/meteor/client/NavBarV2/NavBarPagesGroup/actions/useEncryptedRoomDescription.spec.tsx @@ -0,0 +1,118 @@ +import { mockAppRoot } from '@rocket.chat/mock-providers'; +import { renderHook } from '@testing-library/react'; + +import { useEncryptedRoomDescription } from './useEncryptedRoomDescription'; + +describe('useEncryptedRoomDescription', () => { + describe('actual translation values comparison', () => { + describe('Portuguese translations', () => { + it('should return correct Portuguese translations for channel type', () => { + const { result } = renderHook(() => useEncryptedRoomDescription('channel'), { + wrapper: mockAppRoot() + .withSetting('E2E_Enable', true) + .withSetting('E2E_Enabled_Default_PrivateRooms', false) + .withSetting('language', 'pt-BR') + .withUserPreference('language', 'pt-BR') + .withTranslationLanguage('pt-BR') + .withTranslations('pt-BR', 'core', { + Encrypted_not_available: 'Indisponível para {{roomType}} públicos', + Not_available_for_broadcast: 'Não disponível para transmissão {{roomType}}', + Encrypted_messages: + 'Criptografado de ponta a ponta {{roomType}}. A pesquisa não funcionará com {{roomType}} criptografado e as notificações podem não mostrar o conteúdo das mensagens.', + channel: 'canal', + team: 'Equipe', + }) + .build(), + }); + + // Test all scenarios with Portuguese translations + expect(result.current({ isPrivate: false, broadcast: false, encrypted: false })).toBe('Indisponível para canal públicos'); + expect(result.current({ isPrivate: true, broadcast: true, encrypted: false })).toBe('Não disponível para transmissão canal'); + expect(result.current({ isPrivate: true, broadcast: false, encrypted: true })).toBe( + 'Criptografado de ponta a ponta canal. A pesquisa não funcionará com canal criptografado e as notificações podem não mostrar o conteúdo das mensagens.', + ); + }); + + it('should return correct Portuguese translations for team type', () => { + const { result } = renderHook(() => useEncryptedRoomDescription('team'), { + wrapper: mockAppRoot() + .withSetting('E2E_Enable', true) + .withSetting('E2E_Enabled_Default_PrivateRooms', false) + .withTranslationLanguage('pt-BR') + .withTranslations('pt-BR', 'core', { + Encrypted_not_available: 'Indisponível para {{roomType}} públicos', + Not_available_for_broadcast: 'Não disponível para transmissão {{roomType}}', + Encrypted_messages: + 'Criptografado de ponta a ponta {{roomType}}. A pesquisa não funcionará com {{roomType}} criptografado e as notificações podem não mostrar o conteúdo das mensagens.', + channel: 'canal', + team: 'Equipe', + }) + .build(), + }); + + // Test all scenarios with Portuguese translations + expect(result.current({ isPrivate: false, broadcast: false, encrypted: false })).toBe('Indisponível para Equipe públicos'); + expect(result.current({ isPrivate: true, broadcast: true, encrypted: false })).toBe('Não disponível para transmissão Equipe'); + expect(result.current({ isPrivate: true, broadcast: false, encrypted: true })).toBe( + 'Criptografado de ponta a ponta Equipe. A pesquisa não funcionará com Equipe criptografado e as notificações podem não mostrar o conteúdo das mensagens.', + ); + }); + }); + + describe('English translations', () => { + it('should return correct English translations for channel type', () => { + const { result } = renderHook(() => useEncryptedRoomDescription('channel'), { + wrapper: mockAppRoot() + .withSetting('E2E_Enable', true) + .withSetting('E2E_Enabled_Default_PrivateRooms', false) + .withTranslations('en', 'core', { + Not_available_for_this_workspace: 'Not available for this workspace', + Encrypted_not_available: 'Not available for public {{roomType}}', + Not_available_for_broadcast: 'Not available for broadcast {{roomType}}', + Encrypted_messages: + 'End-to-end encrypted {{roomType}}. Search will not work with encrypted {{roomType}} and notifications may not show the messages content.', + Encrypted_messages_false: 'Messages are not encrypted', + channel: 'Channel', + team: 'Team', + }) + .build(), + }); + + // Test all scenarios with English translations + expect(result.current({ isPrivate: false, broadcast: false, encrypted: false })).toBe('Not available for public Channel'); + expect(result.current({ isPrivate: true, broadcast: true, encrypted: false })).toBe('Not available for broadcast Channel'); + expect(result.current({ isPrivate: true, broadcast: false, encrypted: true })).toBe( + 'End-to-end encrypted Channel. Search will not work with encrypted Channel and notifications may not show the messages content.', + ); + expect(result.current({ isPrivate: true, broadcast: false, encrypted: false })).toBe('Messages are not encrypted'); + }); + + it('should return correct English translations for team type', () => { + const { result } = renderHook(() => useEncryptedRoomDescription('team'), { + wrapper: mockAppRoot() + .withSetting('E2E_Enable', true) + .withSetting('E2E_Enabled_Default_PrivateRooms', false) + .withTranslations('en', 'core', { + Not_available_for_this_workspace: 'Not available for this workspace', + Encrypted_not_available: 'Not available for public {{roomType}}', + Not_available_for_broadcast: 'Not available for broadcast {{roomType}}', + Encrypted_messages: + 'End-to-end encrypted {{roomType}}. Search will not work with encrypted {{roomType}} and notifications may not show the messages content.', + Encrypted_messages_false: 'Messages are not encrypted', + channel: 'Channel', + team: 'Team', + }) + .build(), + }); + + // Test all scenarios with English translations + expect(result.current({ isPrivate: false, broadcast: false, encrypted: false })).toBe('Not available for public Team'); + expect(result.current({ isPrivate: true, broadcast: true, encrypted: false })).toBe('Not available for broadcast Team'); + expect(result.current({ isPrivate: true, broadcast: false, encrypted: true })).toBe( + 'End-to-end encrypted Team. Search will not work with encrypted Team and notifications may not show the messages content.', + ); + expect(result.current({ isPrivate: true, broadcast: false, encrypted: false })).toBe('Messages are not encrypted'); + }); + }); + }); +}); diff --git a/packages/mock-providers/src/MockedAppRootBuilder.tsx b/packages/mock-providers/src/MockedAppRootBuilder.tsx index 7f1b1150a493c..ea3ef7f9a771d 100644 --- a/packages/mock-providers/src/MockedAppRootBuilder.tsx +++ b/packages/mock-providers/src/MockedAppRootBuilder.tsx @@ -554,6 +554,20 @@ export class MockedAppRootBuilder { return this; } + // Manually changes the language in the i18next instance + // To be used with languages other than the default one + withTranslationLanguage(lng: string): this { + if (this.i18n.isInitialized) { + this.i18n.changeLanguage(lng); + } else { + this.i18n.on('initialized', () => { + this.i18n.changeLanguage(lng); + }); + } + + return this; + } + withServerContext(partial: Partial): this { this.server = { ...this.server, ...partial }; return this;